bug-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] One time password


From: Brian Murphy
Subject: [PATCH] One time password
Date: Mon, 18 Aug 2003 21:09:21 +0200

Hi,
        herewith ChangeLog and patch for one time password support.

/Brian

doc/cvsclient.texi:

added items to document the new protocol to prompt the user directly 
for a password and the new -p global option sending a NULL password
to the server.

src/client.c:

auth_server: allowing the -p option to set a NULL password. 
Added support for the "prompt-secret" method allowing the server 
to get a password reply in response to its query when no password
is sent in the pserver request.

src/cvs.h

password_prompt: new global variable reflecting the state of the -p command
line flag.

PROMPT_SECRET: defined to "prompt-secret ", part of the client-server
protocol to allow the server to interact with the user, prompt for a
password, and get a reply in return from the client.

NULL_PASSWORD: an addition to the scrambling method "A" which stands for 
a NULL password. Used to indicate to the server that no password is sent with
the request and it may send a prompt request if required.

src/login.c:

login: allow "cvs login" to save the NULL password in ~/.cvsrc so
that the server will always prompt for passwords.

src/main.c:

password_prompt: a new global to reflect the state of the -p command line
option.

main: added the -p option to the list of global options.

src/scramble.c:

descramble: adds a new scrambling method "N" which always descrambles to the 
NULL password.

src/server.c:

check_repository_password: Handle the possibility of NULL passwords sanely.

cvs_pam_conv: allow passwords to be NULL. If a NULL password is received
then prompt the client using the prompt-secret method for the user to 
enter a password if required by the PAM module doing the authentication.

check_system_password: a NULL password is denied authentication. There is no
point in standard system authentication using this method. It might as well
use the standard pserver method of passing the password with the request.

Index: doc/cvsclient.texi
===================================================================
RCS file: /cvs/ccvs/doc/cvsclient.texi,v
retrieving revision 1.130
diff -u -r1.130 cvsclient.texi
--- doc/cvsclient.texi  5 Sep 2001 21:26:49 -0000       1.130
+++ doc/cvsclient.texi  18 Aug 2003 18:02:43 -0000
@@ -212,6 +212,12 @@
 @code{unrecognized auth response} and @var{text}, and then exit, upon
 receiving this response.
 
+@item prompt-secret @var{text}
+This causes enabled clients to prompt the user for a password and 
+then send the response back to the server. It is currently used in
+the PAM code to enable arbitrary PAM modules to prompt the user 
+for input.
+
 @item error @var{code} @var{text}
 The authentication fails.  After sending this response, the server may
 close the connection.  The @var{code} is a code describing why it
@@ -271,7 +277,10 @@
 Authentication (as described in RFC2068) uses BASE64 for a similar
 purpose.  CVS uses its own algorithm, described here.
 
-The scrambled password starts with @samp{A}, which serves to identify
+A null password starts with @samp{N}. This indicates the server should
+prompt the client for password information (if needed).
+
+A scrambled password starts with @samp{A}, which serves to identify
 the scrambling algorithm in use.  After that follows a single octet for
 each character in the password, according to a fixed encoding.  The
 values are shown here, with the encoded values in decimal.  Control
Index: src/client.c
===================================================================
RCS file: /cvs/ccvs/src/client.c,v
retrieving revision 1.347
diff -u -r1.347 client.c
--- src/client.c        23 Jul 2003 21:49:31 -0000      1.347
+++ src/client.c        18 Aug 2003 18:02:46 -0000
@@ -3225,8 +3225,12 @@
            end   = "END AUTH REQUEST";
        }
 
-       /* Get the password, probably from ~/.cvspass. */
-       password = get_cvs_password ();
+       if (password_prompt)
+           password = NULL_PASSWORD;
+       else
+           /* Get the password, probably from ~/.cvspass. */
+           password = get_cvs_password ();
+
        username = root->username ? root->username : getcaller();
 
        /* Send the empty string by default.  This is so anonymous CVS
@@ -3254,7 +3258,8 @@
        send_to_server_via(to_server, "\012", 1);
 
         /* Paranoia. */
-        memset (password, 0, strlen (password));
+       if (!password_prompt)
+           memset (password, 0, strlen (password));
 # else /* ! AUTH_CLIENT_SUPPORT */
        error (1, 0, "INTERNAL ERROR: This client does not support pserver 
authentication");
 # endif /* AUTH_CLIENT_SUPPORT */
@@ -3304,6 +3309,12 @@
                fprintf (stderr, "%s\n", read_buf + 2);
 
                /* Continue with the authentication protocol.  */
+           }
+           else if (strncmp (read_buf, PROMPT_SECRET, strlen(PROMPT_SECRET)) 
== 0)
+           {
+               char *response = getpass(read_buf + strlen(PROMPT_SECRET));
+               send_to_server_via(to_server, response, 0);
+               send_to_server_via(to_server, "\012", 1);
            }
            else if (strncmp (read_buf, "error ", 6) == 0)
            {
Index: src/cvs.h
===================================================================
RCS file: /cvs/ccvs/src/cvs.h,v
retrieving revision 1.269
diff -u -r1.269 cvs.h
--- src/cvs.h   25 Jul 2003 20:17:06 -0000      1.269
+++ src/cvs.h   18 Aug 2003 18:02:46 -0000
@@ -347,6 +347,7 @@
 extern char *Tmpdir, *Editor;
 extern int cvsadmin_root;
 extern char *CurDir;
+extern int password_prompt;
 extern int really_quiet, quiet;
 extern int use_editor;
 extern int cvswrite;
@@ -876,6 +877,9 @@
 char *scramble (char *str);
 char *descramble (char *str);
 #endif /* AUTH_CLIENT_SUPPORT || AUTH_SERVER_SUPPORT */
+
+#define PROMPT_SECRET "prompt-secret "
+#define NULL_PASSWORD "N"
 
 #ifdef AUTH_CLIENT_SUPPORT
 char *get_cvs_password (void);
Index: src/login.c
===================================================================
RCS file: /cvs/ccvs/src/login.c,v
retrieving revision 1.77
diff -u -r1.77 login.c
--- src/login.c 29 Jul 2003 14:00:10 -0000      1.77
+++ src/login.c 18 Aug 2003 18:02:46 -0000
@@ -508,6 +508,13 @@
     if (argc < 0)
        usage (login_usage);
 
+    if (password_prompt)
+    {
+       password_entry_operation (password_entry_add, current_parsed_root, 
NULL_PASSWORD);
+       printf ("Server always prompts for passwords\n");
+       return 0;
+    }
+
     if (current_parsed_root->method != pserver_method)
     {
        error (0, 0, "can only use `login' command with the 'pserver' method");
Index: src/main.c
===================================================================
RCS file: /cvs/ccvs/src/main.c,v
retrieving revision 1.189
diff -u -r1.189 main.c
--- src/main.c  24 Jul 2003 13:44:19 -0000      1.189
+++ src/main.c  18 Aug 2003 18:02:47 -0000
@@ -37,6 +37,7 @@
 int use_editor = 1;
 int use_cvsrc = 1;
 int cvswrite = !CVSREAD_DFLT;
+int password_prompt = 0;
 int really_quiet = 0;
 int quiet = 0;
 int trace = 0;
@@ -403,7 +404,7 @@
     int help = 0;              /* Has the user asked for help?  This
                                   lets us support the `cvs -H cmd'
                                   convention to give help for cmd. */
-    static const char short_options[] = "+QqrwtnRvb:T:e:d:Hfz:s:xa";
+    static const char short_options[] = "+pQqrwtnRvb:T:e:d:Hfz:s:xa";
     static struct option long_options[] =
     {
         {"help", 0, NULL, 'H'},
@@ -519,6 +520,9 @@
            case 3:
                /* --allow-root */
                root_allow_add (optarg);
+               break;
+           case 'p':
+               password_prompt = 1;
                break;
            case 'Q':
                really_quiet = 1;
Index: src/scramble.c
===================================================================
RCS file: /cvs/ccvs/src/scramble.c,v
retrieving revision 1.17
diff -u -r1.17 scramble.c
--- src/scramble.c      23 Jul 2003 20:42:26 -0000      1.17
+++ src/scramble.c      18 Aug 2003 18:02:47 -0000
@@ -111,28 +111,26 @@
     char *s;
     int i;
 
-    /* For now we can only handle one kind of scrambling.  In the future
-       there may be other kinds, and this `if' will become a `switch'.  */
-    if (str[0] != 'A')
+    switch (str[0]) {
+       case 'A':
+           /* Method `A' is symmetrical, so scramble again to decrypt. */
+           s = scramble (str + 1);
+
+           return s + 1;
+       case 'N':
+           /* NULL password sent */
+           return NULL;
+       default:
 #ifndef DIAGNOSTIC
-       error (1, 0, "descramble: unknown scrambling method");
+           error (1, 0, "descramble: unknown scrambling method");
 #else  /* DIAGNOSTIC */
-    {
-       fprintf (stderr, "descramble: unknown scrambling method\n", str);
-       fflush (stderr);
-       exit (EXIT_FAILURE);
-    }
+           fprintf (stderr, "descramble: unknown scrambling method\n", str);
+           fflush (stderr);
+           exit (EXIT_FAILURE);
 #endif  /* DIAGNOSTIC */
+           break;
+    }
 
-    /* Method `A' is symmetrical, so scramble again to decrypt. */
-    s = scramble (str + 1);
-
-    /* Shift the whole string one char to the left, pushing the unwanted
-       'A' off the left end.  Safe, because s is null-terminated. */
-    for (i = 0; s[i]; i++)
-       s[i] = s[i + 1];
-
-    return s;
 }
 
 #endif /* (AUTH_CLIENT_SUPPORT || AUTH_SERVER_SUPPORT) from top of file */
Index: src/server.c
===================================================================
RCS file: /cvs/ccvs/src/server.c,v
retrieving revision 1.310
diff -u -r1.310 server.c
--- src/server.c        13 Aug 2003 18:57:19 -0000      1.310
+++ src/server.c        18 Aug 2003 18:02:50 -0000
@@ -5233,7 +5233,8 @@
 
        /* Verify blank passwords directly, otherwise use crypt(). */
        if ((found_password == NULL)
-           || ((strcmp (found_password, crypt (password, found_password))
+           || (password && 
+               (strcmp (found_password, crypt (password, found_password))
                 == 0)))
        {
            /* Give host_user_ptr permanent storage. */
@@ -5280,8 +5281,11 @@
     int i;
     struct pam_response *response;
     struct cvs_pam_userinfo *ui = (struct cvs_pam_userinfo *)appdata_ptr;
+    char *tmp = NULL;
+    size_t tmp_allocated = 0;
+    int len;
 
-    assert (ui && ui->username && ui->password && msg && resp);
+    assert (ui && ui->username && msg && resp);
 
     response = xmalloc(num_msg * sizeof(struct pam_response));
     memset(response, 0, num_msg * sizeof(struct pam_response));
@@ -5296,11 +5300,21 @@
                break;
            /* PAM wants a password */
            case PAM_PROMPT_ECHO_OFF:
-               response[i].resp = xstrdup(ui->password);
+               if (ui->password)
+                   response[i].resp = xstrdup(ui->password);
+               else {
+                   printf(PROMPT_SECRET "%s\n", msg[i]->msg);
+                   fflush (stdout);
+                   getnline( &tmp, &tmp_allocated, PATH_MAX, stdin );
+                   len = strlen(tmp);
+                   if (len>1 && tmp[strlen(tmp)-1] == '\n')
+                       tmp[strlen(tmp)-1] = '\0';
+                   response[i].resp = tmp;
+               }
                break;
            case PAM_ERROR_MSG:
            case PAM_TEXT_INFO:
-               printf("E %s\n",msg[i]->msg);
+               printf("E %s\n", msg[i]->msg);
                break;
            /* PAM wants something we don't understand - bail out */
            default:
@@ -5374,6 +5388,13 @@
     }
 #endif
 
+    if (password == NULL) {
+       printf ("E Fatal error, aborting.\n"
+               "error 0 got NULL password. Try using cvs without the -p 
option\n");
+
+       error_exit ();
+    }
+
     if (found_passwd == NULL && (pw = getpwnam (username)) != NULL)
        found_passwd = pw->pw_passwd;
 
@@ -5646,13 +5667,15 @@
     /* We need the real cleartext before we hash it. */
     descrambled_password = descramble (password);
     host_user = check_password (username, descrambled_password, repository);
+    if (descrambled_password != NULL) {
+       memset (descrambled_password, 0, strlen (descrambled_password));
+       free (descrambled_password);
+    }
     if (host_user == NULL)
     {
 #ifdef HAVE_SYSLOG_H
        syslog (LOG_DAEMON | LOG_NOTICE, "login failure (for %s)", repository);
 #endif
-       memset (descrambled_password, 0, strlen (descrambled_password));
-       free (descrambled_password);
     i_hate_you:
        printf ("I HATE YOU\n");
        fflush (stdout);
@@ -5661,8 +5684,6 @@
           yet.  */
        error_exit ();
     }
-    memset (descrambled_password, 0, strlen (descrambled_password));
-    free (descrambled_password);
 
     /* Don't go any farther if we're just responding to "cvs login". */
     if (verify_and_exit)




reply via email to

[Prev in Thread] Current Thread [Next in Thread]