aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/cvs/src/login.c
diff options
context:
space:
mode:
authorPeter Wemm <peter@FreeBSD.org>1996-08-20 23:46:10 +0000
committerPeter Wemm <peter@FreeBSD.org>1996-08-20 23:46:10 +0000
commit18576028af9c8455e19c9f51d94b87e08d1e6bd7 (patch)
tree70187fdf5be4cbefd0baf46bddac7e5e32c13c24 /contrib/cvs/src/login.c
parentbd3a9cd23c621022280b2b8d4e66a5141b4e88e0 (diff)
downloadsrc-18576028af9c8455e19c9f51d94b87e08d1e6bd7.tar.gz
src-18576028af9c8455e19c9f51d94b87e08d1e6bd7.zip
Import of slightly trimmed cvs-1.8 distribution. Generated files
and non-unix code has been left out.
Notes
Notes: svn path=/vendor/cvs/dist/; revision=17721
Diffstat (limited to 'contrib/cvs/src/login.c')
-rw-r--r--contrib/cvs/src/login.c392
1 files changed, 392 insertions, 0 deletions
diff --git a/contrib/cvs/src/login.c b/contrib/cvs/src/login.c
new file mode 100644
index 000000000000..fc3a1783665b
--- /dev/null
+++ b/contrib/cvs/src/login.c
@@ -0,0 +1,392 @@
+/*
+ * Copyright (c) 1995, Cyclic Software, Bloomington, IN, USA
+ *
+ * You may distribute under the terms of the GNU General Public License as
+ * specified in the README file that comes with CVS.
+ *
+ * Allow user to log in for an authenticating server.
+ */
+
+#include "cvs.h"
+#include "getline.h"
+
+#ifdef AUTH_CLIENT_SUPPORT /* This covers the rest of the file. */
+
+extern char *getpass ();
+
+#ifndef CVS_PASSWORD_FILE
+#define CVS_PASSWORD_FILE ".cvspass"
+#endif
+
+/* If non-NULL, get_cvs_password() will just return this. */
+static char *cvs_password = NULL;
+
+/* The return value will need to be freed. */
+char *
+construct_cvspass_filename ()
+{
+ char *homedir;
+ char *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)
+ {
+ 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;
+}
+
+
+/* Prompt for a password, and store it in the file "CVS/.cvspass".
+ *
+ * Because the user might be accessing multiple repositories, with
+ * different passwords for each one, the format of ~/.cvspass is:
+ *
+ * user@host:/path Acleartext_password
+ * user@host:/path Acleartext_password
+ * ...
+ *
+ * Of course, the "user@" might be left off -- it's just based on the
+ * value of CVSroot.
+ *
+ * The "A" before "cleartext_password" is a literal capital A. It's a
+ * version number indicating which form of scrambling we're doing on
+ * the password -- someday we might provide something more secure than
+ * the trivial encoding we do now, and when that day comes, it would
+ * be nice to remain backward-compatible.
+ *
+ * Like .netrc, the file's permissions are the only thing preventing
+ * it from being read by others. Unlike .netrc, we will not be
+ * fascist about it, at most issuing a warning, and never refusing to
+ * work.
+ */
+int
+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;
+
+ printf ("Repository \"%s\" not fully-qualified.\n", CVSroot);
+ printf ("Please enter \"user@host:/path\": ");
+ fflush (stdout);
+ getline (&linebuf, &linebuf_len, stdin);
+
+ 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[0] != ':')
+ {
+ /* Then we need to prepend ":pserver:". */
+ char *tmp;
+
+ tmp = xmalloc (strlen (":pserver:") + strlen (CVSroot) + 1);
+ strcpy (tmp, ":pserver:");
+ strcat (tmp, CVSroot);
+ CVSroot = tmp;
+ }
+
+ /* 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);
+ fflush (stdout);
+ }
+
+ 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);
+
+ if (connect_to_pserver (NULL, NULL, 1) == 0)
+ {
+ /* 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)
+ {
+ /* 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
+ {
+ free (linebuf);
+ linebuf = (char *) NULL;
+ }
+ }
+ fclose (fp);
+ }
+
+ if (already_entered)
+ {
+ /* This user/host has a password in the file already. */
+
+ 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)
+ {
+ error (1, errno, "unable to open temp file %s", tmp_name);
+ return 1;
+ }
+ chmod (tmp_name, 0600);
+
+ fp = fopen (passfile, "r");
+ if (fp == NULL)
+ {
+ error (1, errno, "unable to open %s", passfile);
+ return 1;
+ }
+ /* 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)
+ {
+ if (strncmp (CVSroot, linebuf, root_len))
+ fprintf (tmp_fp, "%s", linebuf);
+ else
+ fprintf (tmp_fp, "%s %s\n", CVSroot, typed_password);
+
+ free (linebuf);
+ linebuf = (char *) NULL;
+ }
+ fclose (tmp_fp);
+ fclose (fp);
+ rename_file (tmp_name, passfile);
+ chmod (passfile, 0600);
+ }
+ }
+ else
+ {
+ if ((fp = fopen (passfile, "a")) == NULL)
+ {
+ error (1, errno, "could not open %s", passfile);
+ free (passfile);
+ return 1;
+ }
+
+ fprintf (fp, "%s %s\n", CVSroot, typed_password);
+ fclose (fp);
+ }
+
+ /* 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;
+}
+
+/* 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)
+ {
+ 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;
+ }
+
+ /* Else get it from the file. */
+ passfile = construct_cvspass_filename ();
+ fp = 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");
+ }
+
+ root_len = strlen (CVSroot);
+
+ /* 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
+ {
+ free (linebuf);
+ linebuf = (char *) NULL;
+ }
+ }
+
+ 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;
+ }
+ 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");
+ }
+ /* NOTREACHED */
+ return NULL;
+}
+
+#endif /* AUTH_CLIENT_SUPPORT from beginning of file. */
+