diff options
Diffstat (limited to 'contrib/cvs/src/login.c')
-rw-r--r-- | contrib/cvs/src/login.c | 595 |
1 files changed, 331 insertions, 264 deletions
diff --git a/contrib/cvs/src/login.c b/contrib/cvs/src/login.c index fc3a178..cc277a6 100644 --- a/contrib/cvs/src/login.c +++ b/contrib/cvs/src/login.c @@ -12,7 +12,16 @@ #ifdef AUTH_CLIENT_SUPPORT /* This covers the rest of the file. */ +/* There seems to be very little agreement on which system header + getpass is declared in. With a lot of fancy autoconfiscation, + we could perhaps detect this, but for now we'll just rely on + _CRAY, since Cray is perhaps the only system on which our own + declaration won't work (some Crays declare the 2#$@% thing as + varadic, believe it or not). On Cray, getpass will be declared + in either stdlib.h or unistd.h. */ +#ifndef _CRAY extern char *getpass (); +#endif #ifndef CVS_PASSWORD_FILE #define CVS_PASSWORD_FILE ".cvspass" @@ -21,40 +30,53 @@ extern char *getpass (); /* If non-NULL, get_cvs_password() will just return this. */ static char *cvs_password = NULL; +static char *construct_cvspass_filename PROTO ((void)); + /* The return value will need to be freed. */ -char * +static char * construct_cvspass_filename () { - char *homedir; - char *passfile; + char *homedir; + char *passfile; - /* Environment should override file. */ - if ((passfile = getenv ("CVS_PASSFILE")) != NULL) - return xstrdup (passfile); + /* Environment should override file. */ + if ((passfile = getenv ("CVS_PASSFILE")) != NULL) + return xstrdup (passfile); - /* Construct absolute pathname to user's password file. */ - /* todo: does this work under OS/2 ? */ - homedir = get_homedir (); - if (! homedir) + /* Construct absolute pathname to user's password file. */ + /* todo: does this work under OS/2 ? */ + homedir = get_homedir (); + if (! homedir) { - error (1, errno, "could not find out home directory"); - return (char *) NULL; + error (1, errno, "could not find out home directory"); + return (char *) NULL; } - - passfile = - (char *) xmalloc (strlen (homedir) + strlen (CVS_PASSWORD_FILE) + 3); - strcpy (passfile, homedir); - strcat (passfile, "/"); - strcat (passfile, CVS_PASSWORD_FILE); - - /* Safety first and last, Scouts. */ - if (isfile (passfile)) - /* xchmod() is too polite. */ - chmod (passfile, 0600); - return passfile; + passfile = + (char *) xmalloc (strlen (homedir) + strlen (CVS_PASSWORD_FILE) + 3); + strcpy (passfile, homedir); +#ifndef NO_SLASH_AFTER_HOME + /* NO_SLASH_AFTER_HOME is defined for VMS, where foo:[bar]/.cvspass is not + a legal filename but foo:[bar].cvspass is. A more clean solution would + be something more along the lines of a "join a directory to a filename" + kind of thing.... */ + strcat (passfile, "/"); +#endif + strcat (passfile, CVS_PASSWORD_FILE); + + /* Safety first and last, Scouts. */ + if (isfile (passfile)) + /* xchmod() is too polite. */ + chmod (passfile, 0600); + + return passfile; } +static const char *const login_usage[] = +{ + "Usage: %s %s\n", + NULL +}; /* Prompt for a password, and store it in the file "CVS/.cvspass". * @@ -84,309 +106,354 @@ login (argc, argv) int argc; char **argv; { - char *passfile; - FILE *fp; - char *typed_password, *found_password; - char *linebuf = (char *) NULL; - size_t linebuf_len; - int root_len, already_entered = 0; - - /* Make this a "fully-qualified" CVSroot if necessary. */ - if (! strchr (CVSroot, '@')) - { - /* We need to prepend "user@host:". */ - char *tmp; + char *passfile; + FILE *fp; + char *typed_password, *found_password; + char *linebuf = (char *) NULL; + size_t linebuf_len; + int root_len, already_entered = 0; - printf ("Repository \"%s\" not fully-qualified.\n", CVSroot); - printf ("Please enter \"user@host:/path\": "); - fflush (stdout); - getline (&linebuf, &linebuf_len, stdin); + if (argc < 0) + usage (login_usage); - tmp = xmalloc (strlen (linebuf) + 1); - - /* Give it some permanent storage. */ - strcpy (tmp, linebuf); - tmp[strlen (linebuf) - 1] = '\0'; - CVSroot = tmp; - - /* Reset. */ - free (linebuf); - linebuf = (char *) NULL; + if (CVSroot_method != pserver_method) + { + error (0, 0, "can only use pserver method with `login' command"); + error (1, 0, "CVSROOT: %s", CVSroot_original); } - - if (CVSroot[0] != ':') + + if (! CVSroot_username) { - /* Then we need to prepend ":pserver:". */ - char *tmp; - - tmp = xmalloc (strlen (":pserver:") + strlen (CVSroot) + 1); - strcpy (tmp, ":pserver:"); - strcat (tmp, CVSroot); - CVSroot = tmp; + error (0, 0, "CVSROOT \"%s\" is not fully-qualified.", + CVSroot_original); + error (1, 0, "Please make sure to specify \"user@host\"!"); } - /* Check to make sure it's fully-qualified before going on. - * Fully qualified in this context means it has both a user and a - * host:repos portion. - */ - { - char *r; - - /* After confirming that CVSroot is non-NULL, we skip past the - initial ":pserver:" to test the rest of it. */ - - if (! CVSroot) - error (1, 0, "CVSroot is NULL"); - else if (! strchr ((r = (CVSroot + strlen (":pserver:"))), '@')) - goto not_fqrn; - else if (! strchr (r, ':')) - goto not_fqrn; - - if (0) /* Lovely. */ - { - not_fqrn: - error (0, 0, "CVSroot not fully-qualified: %s", CVSroot); - error (1, 0, "should be format user@host:/path/to/repository"); - } - } - - /* CVSroot is now fully qualified and has ":pserver:" prepended. - We'll print out most of it so user knows exactly what is being - dealt with here. */ - { - char *s; - s = strchr (CVSroot, ':'); - s++; - s = strchr (s, ':'); - s++; - - if (s == NULL) - error (1, 0, "NULL CVSroot"); - - printf ("(Logging in to %s)\n", s); + printf ("(Logging in to %s@%s)\n", CVSroot_username, CVSroot_hostname); fflush (stdout); - } - passfile = construct_cvspass_filename (); - typed_password = getpass ("CVS password: "); - typed_password = scramble (typed_password); + passfile = construct_cvspass_filename (); + typed_password = getpass ("CVS password: "); + typed_password = scramble (typed_password); - /* Force get_cvs_password() to use this one (when the client - * confirms the new password with the server), instead of consulting - * the file. We make a new copy because cvs_password will get - * zeroed by connect_to_server(). - */ - cvs_password = xstrdup (typed_password); + /* Force get_cvs_password() to use this one (when the client + * confirms the new password with the server), instead of + * consulting the file. We make a new copy because cvs_password + * will get zeroed by connect_to_server(). */ - if (connect_to_pserver (NULL, NULL, 1) == 0) + cvs_password = xstrdup (typed_password); + + if (connect_to_pserver (NULL, NULL, 1) == 0) { - /* The password is wrong, according to the server. */ - error (1, 0, "incorrect password"); + /* The password is wrong, according to the server. */ + error (1, 0, "incorrect password"); } - /* IF we have a password for this "[user@]host:/path" already - * THEN - * IF it's the same as the password we read from the prompt - * THEN - * do nothing - * ELSE - * replace the old password with the new one - * ELSE - * append new entry to the end of the file. - */ - - root_len = strlen (CVSroot); - - /* Yes, the method below reads the user's password file twice. It's - inefficient, but we're not talking about a gig of data here. */ - - fp = fopen (passfile, "r"); - /* FIXME: should be printing a message if fp == NULL and not - existence_error (errno). */ - if (fp != NULL) + /* IF we have a password for this "[user@]host:/path" already + * THEN + * IF it's the same as the password we read from the prompt + * THEN + * do nothing + * ELSE + * replace the old password with the new one + * ELSE + * append new entry to the end of the file. + */ + + root_len = strlen (CVSroot_original); + + /* Yes, the method below reads the user's password file twice. It's + inefficient, but we're not talking about a gig of data here. */ + + fp = CVS_FOPEN (passfile, "r"); + /* FIXME: should be printing a message if fp == NULL and not + existence_error (errno). */ + if (fp != NULL) { - /* Check each line to see if we have this entry already. */ - while (getline (&linebuf, &linebuf_len, fp) >= 0) + /* Check each line to see if we have this entry already. */ + while (getline (&linebuf, &linebuf_len, fp) >= 0) { - if (strncmp (CVSroot, linebuf, root_len) == 0) - { - already_entered = 1; - break; - } - else + if (strncmp (CVSroot_original, linebuf, root_len) == 0) { - free (linebuf); - linebuf = (char *) NULL; + already_entered = 1; + break; } } - fclose (fp); + fclose (fp); } - - if (already_entered) + + if (already_entered) { - /* This user/host has a password in the file already. */ + /* This user/host has a password in the file already. */ - strtok (linebuf, " "); - found_password = strtok (NULL, "\n"); - if (strcmp (found_password, typed_password)) + strtok (linebuf, " "); + found_password = strtok (NULL, "\n"); + if (strcmp (found_password, typed_password)) { - /* typed_password and found_password don't match, so we'll - * have to update passfile. We replace the old password - * with the new one by writing a tmp file whose contents are - * exactly the same as passfile except that this one entry - * gets typed_password instead of found_password. Then we - * rename the tmp file on top of passfile. - */ - char *tmp_name; - FILE *tmp_fp; - - tmp_name = tmpnam (NULL); - if ((tmp_fp = fopen (tmp_name, "w")) == NULL) + /* typed_password and found_password don't match, so we'll + * have to update passfile. We replace the old password + * with the new one by writing a tmp file whose contents are + * exactly the same as passfile except that this one entry + * gets typed_password instead of found_password. Then we + * rename the tmp file on top of passfile. + */ + char *tmp_name; + FILE *tmp_fp; + + tmp_name = cvs_temp_name (); + if ((tmp_fp = CVS_FOPEN (tmp_name, "w")) == NULL) { - error (1, errno, "unable to open temp file %s", tmp_name); - return 1; + error (1, errno, "unable to open temp file %s", tmp_name); + return 1; } - chmod (tmp_name, 0600); + chmod (tmp_name, 0600); - fp = fopen (passfile, "r"); - if (fp == NULL) + fp = CVS_FOPEN (passfile, "r"); + if (fp == NULL) { - error (1, errno, "unable to open %s", passfile); - return 1; + error (1, errno, "unable to open %s", passfile); + if (linebuf) + free (linebuf); + return 1; } - /* I'm not paranoid, they really ARE out to get me: */ - chmod (passfile, 0600); + /* I'm not paranoid, they really ARE out to get me: */ + chmod (passfile, 0600); - free (linebuf); - linebuf = (char *) NULL; - while (getline (&linebuf, &linebuf_len, fp) >= 0) + while (getline (&linebuf, &linebuf_len, fp) >= 0) { - if (strncmp (CVSroot, linebuf, root_len)) - fprintf (tmp_fp, "%s", linebuf); - else - fprintf (tmp_fp, "%s %s\n", CVSroot, typed_password); + if (strncmp (CVSroot_original, linebuf, root_len)) + fprintf (tmp_fp, "%s", linebuf); + else + fprintf (tmp_fp, "%s %s\n", CVSroot_original, + typed_password); - free (linebuf); - linebuf = (char *) NULL; } - fclose (tmp_fp); - fclose (fp); - rename_file (tmp_name, passfile); - chmod (passfile, 0600); + if (linebuf) + free (linebuf); + fclose (tmp_fp); + fclose (fp); + copy_file (tmp_name, passfile); + unlink_file (tmp_name); + chmod (passfile, 0600); + free (tmp_name); } } - else + else { - if ((fp = fopen (passfile, "a")) == NULL) + if (linebuf) + free (linebuf); + if ((fp = CVS_FOPEN (passfile, "a")) == NULL) { - error (1, errno, "could not open %s", passfile); - free (passfile); - return 1; + error (1, errno, "could not open %s", passfile); + free (passfile); + return 1; } - fprintf (fp, "%s %s\n", CVSroot, typed_password); - fclose (fp); + fprintf (fp, "%s %s\n", CVSroot_original, typed_password); + fclose (fp); } - /* Utter, total, raving paranoia, I know. */ - chmod (passfile, 0600); - memset (typed_password, 0, strlen (typed_password)); - free (typed_password); + /* Utter, total, raving paranoia, I know. */ + chmod (passfile, 0600); + memset (typed_password, 0, strlen (typed_password)); + free (typed_password); - free (passfile); - free (cvs_password); - cvs_password = NULL; - return 0; + free (passfile); + free (cvs_password); + cvs_password = NULL; + return 0; } -/* todo: "cvs logout" could erase an entry from the file. - * But to what purpose? - */ - /* Returns the _scrambled_ password. The server must descramble before hashing and comparing. */ char * get_cvs_password () { - int found_it = 0; - int root_len; - char *password; - char *linebuf = (char *) NULL; - size_t linebuf_len; - FILE *fp; - char *passfile; - - /* If someone (i.e., login()) is calling connect_to_pserver() out of - context, then assume they have supplied the correct, scrambled - password. */ - if (cvs_password) - return cvs_password; - - /* Environment should override file. */ - if ((password = getenv ("CVS_PASSWORD")) != NULL) + int found_it = 0; + int root_len; + char *password; + char *linebuf = (char *) NULL; + size_t linebuf_len; + FILE *fp; + char *passfile; + + /* If someone (i.e., login()) is calling connect_to_pserver() out of + context, then assume they have supplied the correct, scrambled + password. */ + if (cvs_password) + return cvs_password; + + if (getenv ("CVS_PASSWORD") != NULL) + { + /* In previous versions of CVS one could specify a password in + CVS_PASSWORD. This is a bad idea, because in BSD variants + of unix anyone can see the environment variable with 'ps'. + But for users who were using that feature we want to at + least let them know what is going on. After printing this + warning, we should fall through to the regular error where + we tell them to run "cvs login" (unless they already ran + it, of course). */ + error (0, 0, "CVS_PASSWORD is no longer supported; ignored"); + } + + /* Else get it from the file. First make sure that the CVSROOT + variable has the appropriate fields filled in. */ + + if (CVSroot_method != pserver_method) + { + error (0, 0, "can only call GET_CVS_PASSWORD with pserver method"); + error (1, 0, "CVSROOT: %s", CVSroot_original); + } + + if (! CVSroot_username) { - char *p; - p = xstrdup (password); - /* If we got it from the environment, then it wasn't properly - scrambled. Since unscrambling is done on the server side, we - need to transmit it scrambled. */ - p = scramble (p); - return p; + error (0, 0, "CVSROOT \"%s\" is not fully-qualified.", + CVSroot_original); + error (1, 0, "Please make sure to specify \"user@host\"!"); } - /* Else get it from the file. */ - passfile = construct_cvspass_filename (); - fp = fopen (passfile, "r"); - if (fp == NULL) + passfile = construct_cvspass_filename (); + fp = CVS_FOPEN (passfile, "r"); + if (fp == NULL) { - error (0, errno, "could not open %s", passfile); - free (passfile); - error (1, 0, "use \"cvs login\" to log in first"); + error (0, errno, "could not open %s", passfile); + free (passfile); + error (1, 0, "use \"cvs login\" to log in first"); } - root_len = strlen (CVSroot); + root_len = strlen (CVSroot_original); - /* Check each line to see if we have this entry already. */ - while (getline (&linebuf, &linebuf_len, fp) >= 0) + /* Check each line to see if we have this entry already. */ + while (getline (&linebuf, &linebuf_len, fp) >= 0) { - if (strncmp (CVSroot, linebuf, root_len) == 0) - { - /* This is it! So break out and deal with linebuf. */ - found_it = 1; - break; - } - else + if (strncmp (CVSroot_original, linebuf, root_len) == 0) { - free (linebuf); - linebuf = (char *) NULL; + /* This is it! So break out and deal with linebuf. */ + found_it = 1; + break; } } - if (found_it) + if (found_it) { - /* linebuf now contains the line with the password. */ - char *tmp; - - strtok (linebuf, " "); - password = strtok (NULL, "\n"); - - /* Give it permanent storage. */ - tmp = xmalloc (strlen (password) + 1); - strcpy (tmp, password); - tmp[strlen (password)] = '\0'; - memset (password, 0, strlen (password)); - free (linebuf); - return tmp; + /* linebuf now contains the line with the password. */ + char *tmp; + + strtok (linebuf, " "); + password = strtok (NULL, "\n"); + + /* Give it permanent storage. */ + tmp = xstrdup (password); + memset (password, 0, strlen (password)); + free (linebuf); + return tmp; } - else + else { - error (0, 0, "cannot find password"); - error (0, 0, "use \"cvs login\" to log in first"); - error (1, 0, "or set the CVS_PASSWORD environment variable"); + if (linebuf) + free (linebuf); + error (0, 0, "cannot find password"); + error (1, 0, "use \"cvs login\" to log in first"); } - /* NOTREACHED */ - return NULL; + /* NOTREACHED */ + return NULL; } -#endif /* AUTH_CLIENT_SUPPORT from beginning of file. */ +static const char *const logout_usage[] = +{ + "Usage: %s %s\n", + NULL +}; + +/* Remove any entry for the CVSRoot repository found in "CVS/.cvspass". */ +int +logout (argc, argv) + int argc; + char **argv; +{ + char *passfile; + FILE *fp; + char *tmp_name; + FILE *tmp_fp; + char *linebuf = (char *) NULL; + size_t linebuf_len; + int root_len, found = 0; + + if (argc < 0) + usage (logout_usage); + + if (CVSroot_method != pserver_method) + { + error (0, 0, "can only use pserver method with `logout' command"); + error (1, 0, "CVSROOT: %s", CVSroot_original); + } + + if (! CVSroot_username) + { + error (0, 0, "CVSROOT \"%s\" is not fully-qualified.", + CVSroot_original); + error (1, 0, "Please make sure to specify \"user@host\"!"); + } + + /* Hmm. Do we want a variant of this command which deletes _all_ + the entries from the current .cvspass? Might be easier to + remember than "rm ~/.cvspass" but then again if people are + mucking with HOME (common in Win95 as the system doesn't set + it), then this variant of "cvs logout" might give a false sense + of security, in that it wouldn't delete entries from any + .cvspass files but the current one. */ + + printf ("(Logging out of %s@%s)\n", CVSroot_username, CVSroot_hostname); + fflush (stdout); + /* IF we have a password for this "[user@]host:/path" already + * THEN + * drop the entry + * ELSE + * do nothing + */ + + passfile = construct_cvspass_filename (); + tmp_name = cvs_temp_name (); + if ((tmp_fp = CVS_FOPEN (tmp_name, "w")) == NULL) + { + error (1, errno, "unable to open temp file %s", tmp_name); + return 1; + } + chmod (tmp_name, 0600); + + root_len = strlen (CVSroot_original); + + fp = CVS_FOPEN (passfile, "r"); + if (fp == NULL) + error (1, errno, "Error opening %s", passfile); + + /* Check each line to see if we have this entry. */ + /* Copy only those lines that do not match this entry */ + while (getline (&linebuf, &linebuf_len, fp) >= 0) + { + if (strncmp (CVSroot_original, linebuf, root_len)) + fprintf (tmp_fp, "%s", linebuf); + else + found = TRUE; + } + if (linebuf) + free (linebuf); + fclose (fp); + fclose (tmp_fp); + + if (! found) + { + printf ("Entry not found for %s\n", CVSroot_original); + unlink_file (tmp_name); + } + else + { + copy_file (tmp_name, passfile); + unlink_file (tmp_name); + chmod (passfile, 0600); + } + return 0; +} + +#endif /* AUTH_CLIENT_SUPPORT from beginning of file. */ |