[BACK]Return to skeyinit.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / skeyinit

Diff for /src/usr.bin/skeyinit/skeyinit.c between version 1.27 and 1.28

version 1.27, 2001/01/26 16:27:04 version 1.28, 2001/06/20 22:25:08
Line 1 
Line 1 
 /*      $OpenBSD$       */  /*      $OpenBSD$       */
   
 /* S/KEY v1.1b (skeyinit.c)  /* OpenBSD S/Key (skeyinit.c)
  *   *
  * Authors:   * Authors:
  *          Neil M. Haller <nmh@thumper.bellcore.com>   *          Neil M. Haller <nmh@thumper.bellcore.com>
  *          Philip R. Karn <karn@chicago.qualcomm.com>   *          Philip R. Karn <karn@chicago.qualcomm.com>
  *          John S. Walden <jsw@thumper.bellcore.com>   *          John S. Walden <jsw@thumper.bellcore.com>
  *          Scott Chasin <chasin@crimelab.com>   *          Scott Chasin <chasin@crimelab.com>
  *  
  * Modifications:  
  *          Todd C. Miller <Todd.Miller@courtesan.com>   *          Todd C. Miller <Todd.Miller@courtesan.com>
  *   *
  * S/KEY initialization and seed update   * S/Key initialization and seed update
  */   */
   
 #include <sys/param.h>  #include <sys/param.h>
Line 23 
Line 21 
 #include <errno.h>  #include <errno.h>
 #include <ctype.h>  #include <ctype.h>
 #include <pwd.h>  #include <pwd.h>
   #include <readpassphrase.h>
 #include <stdio.h>  #include <stdio.h>
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
Line 37 
Line 36 
 #define SKEY_NAMELEN    4  #define SKEY_NAMELEN    4
 #endif  #endif
   
   void    lockeof __P((struct skey *, char *));
 void    usage __P((char *));  void    usage __P((char *));
   void    secure_mode __P((int *, char *, char *, char *, char *, size_t));
   void    normal_mode __P((char *, int, char *, char *, char *));
   void    timedout __P((int));
   
 int  int
 main(argc, argv)  main(argc, argv)
         int     argc;          int     argc;
         char   *argv[];          char   *argv[];
 {  {
         int     rval, nn, i, l, n=0, defaultsetup=1, zerokey=0, hexmode=0;          int     rval, i, l, n=0, defaultsetup=1, zerokey=0, hexmode=0;
           int     oldmd4=0;
         time_t  now;          time_t  now;
           size_t  seedlen;
         char    hostname[MAXHOSTNAMELEN];          char    hostname[MAXHOSTNAMELEN];
         char    passwd[SKEY_MAX_PW_LEN+2], passwd2[SKEY_MAX_PW_LEN+2];          char    passwd[SKEY_MAX_PW_LEN+2];
         char    seed[SKEY_MAX_SEED_LEN+2], defaultseed[SKEY_MAX_SEED_LEN+1];          char    seed[SKEY_MAX_SEED_LEN+2], defaultseed[SKEY_MAX_SEED_LEN+1];
         char    tbuf[27], buf[80], key[SKEY_BINKEY_SIZE];          char    tbuf[27], buf[256], key[SKEY_BINKEY_SIZE];
         char    lastc, me[UT_NAMESIZE+1], *salt, *p, *pw, *ht=NULL;          char    lastc, me[UT_NAMESIZE+1], *salt, *p, *ht=NULL;
         struct skey skey;          struct skey skey;
         struct passwd *pp;          struct passwd *pp;
         struct tm *tm;          struct tm *tm;
Line 58 
Line 63 
         if (geteuid() != 0)          if (geteuid() != 0)
                 errx(1, "must be setuid root.");                  errx(1, "must be setuid root.");
   
           /* Build up a default seed based on the hostname and time */
         if (gethostname(hostname, sizeof(hostname)) < 0)          if (gethostname(hostname, sizeof(hostname)) < 0)
                 err(1, "gethostname");                  err(1, "gethostname");
         for (i = 0, p = defaultseed; hostname[i] && i < SKEY_NAMELEN; i++) {          for (i = 0, p = defaultseed; hostname[i] && i < SKEY_NAMELEN; i++) {
Line 136 
Line 142 
                 }                  }
         }          }
   
           if (defaultsetup)
                   fputs("Reminder - Only use this method if you are directly connected\n           or have an encrypted channel.  If you are using telnet\n           or rlogin, hit return now and use skeyinit -s.\n", stderr);
   
         if (getuid() != 0) {          if (getuid() != 0) {
                 pw = getpass("Password (or `s/key'):");                  /* XXX - use BSD auth */
                 if (strcasecmp(pw, "s/key") == 0) {                  passwd[0] = '\0';
                         if (skey_haskey(me))                  if (!defaultsetup && skeychallenge(&skey, me, buf) == 0) {
                                 exit(1);                          printf("Enter S/Key password below or hit return twice "
                         if (skey_authenticate(me))                              "to enter standard password.\n%s\n", buf);
                           fflush(stdout);
                           if (!readpassphrase("S/Key Password: ", passwd,
                               sizeof(passwd), 0) || passwd[0] == '\0') {
                                   readpassphrase("S/Key Password: [echo on] ",
                                       passwd, sizeof(passwd), RPP_ECHO_ON);
                           }
                   }
                   if (passwd[0]) {
                           if (skeyverify(&skey, passwd) != 0)
                                 errx(1, "Password incorrect.");                                  errx(1, "Password incorrect.");
                 } else {                  } else {
                         p = crypt(pw, salt);                          fflush(stdout);
                         if (strcmp(p, pp->pw_passwd))                          readpassphrase("Password: ", passwd, sizeof(passwd), 0);
                                 errx(1, "Password incorrect.");                          if (strcmp(crypt(passwd, salt), pp->pw_passwd)) {
                                   if (passwd[0])
                                           warnx("Password incorrect.");
                                   exit(1);
                           }
                 }                  }
         }          }
   
           /*
            * Lookup and lock the record we are about to modify.
            * If this is a new entry this will prevent other users
            * from appending new entries (and clobbering ours).
            */
         rval = skeylookup(&skey, pp->pw_name);          rval = skeylookup(&skey, pp->pw_name);
         switch (rval) {          switch (rval) {
                 case -1:                  case -1:
Line 163 
Line 190 
                         if (zerokey)                          if (zerokey)
                                 exit(skeyzero(&skey, pp->pw_name));                                  exit(skeyzero(&skey, pp->pw_name));
   
                         (void)printf("[Updating %s]\n", pp->pw_name);                          (void)printf("[Updating %s with %s]\n", pp->pw_name,
                         (void)printf("Old key: [%s] %s\n", skey_get_algorithm(),                              ht ? ht : skey_get_algorithm());
                                      skey.seed);                          (void)printf("Old seed: [%s] %s\n",
                                        skey_get_algorithm(), skey.seed);
   
                         /*                          /*
                          * Sanity check old seed.                           * Sanity check old seed.
Line 181 
Line 209 
                                 }                                  }
                         }                          }
   
                         /*                          /* If the seed ends in 0-8 just add one.  */
                          * Let's be nice if they have an skey.seed that  
                          * ends in 0-8 just add one  
                          */  
                         if (l > 0) {                          if (l > 0) {
                                 lastc = skey.seed[l - 1];                                  lastc = skey.seed[l - 1];
                                 if (isdigit(lastc) && lastc != '9') {                                  if (isdigit(lastc) && lastc != '9') {
Line 202 
Line 227 
                 case 1:                  case 1:
                         if (zerokey)                          if (zerokey)
                                 errx(1, "You have no entry to zero.");                                  errx(1, "You have no entry to zero.");
                         (void)printf("[Adding %s]\n", pp->pw_name);                          (void)printf("[Adding %s with %s]\n", pp->pw_name,
                               ht ? ht : skey_get_algorithm());
                           lockeof(&skey, pp->pw_name);
                         break;                          break;
         }          }
         if (n == 0)          if (n == 0)
                 n = 99;                  n = 99;
   
           /* Do we have an old-style md4 entry? */
           if (rval == 0 && strcmp("md4", skey_get_algorithm()) == 0 &&
               strcmp("md4", skey.logname + strlen(skey.logname) + 1) != 0)
                   oldmd4 = 1;
   
         /* Set hash type if asked to */          /* Set hash type if asked to */
         if (ht) {          if (ht && strcmp(ht, skey_get_algorithm()) != 0)
                 /* Need to zero out old key when changing algorithm */                  skey_set_algorithm(ht);
                 if (strcmp(ht, skey_get_algorithm()) && skey_set_algorithm(ht))  
                         zerokey = 1;  
         }  
   
         if (!defaultsetup) {          alarm(180);
                 (void)printf("You need the 6 english words generated from the \"skey\" command.\n");          if (!defaultsetup)
                 for (i = 0; ; i++) {                  secure_mode(&n, key, seed, defaultseed, buf, sizeof(buf));
                         if (i >= 2)          else
                                 exit(1);                  normal_mode(pp->pw_name, n, key, seed, defaultseed);
           alarm(0);
   
                         (void)printf("Enter sequence count from 1 to %d: ",          (void)time(&now);
                                      SKEY_MAX_SEQ);          tm = localtime(&now);
                         (void)fgets(buf, sizeof(buf), stdin);          (void)strftime(tbuf, sizeof(tbuf), " %b %d,%Y %T", tm);
                         n = atoi(buf);  
                         if (n > 0 && n < SKEY_MAX_SEQ)  
                                 break;  /* Valid range */  
                         (void)printf("Error: Count must be > 0 and < %d\n",  
                                      SKEY_MAX_SEQ);  
                 }  
   
                 for (i = 0;; i++) {          /* If this is an exiting entry, compute the line length and seed pad */
                         if (i >= 2)          seedlen = SKEY_MAX_SEED_LEN;
                                 exit(1);          if (rval == 0) {
                   int nlen;
   
                         (void)printf("Enter new key [default %s]: ",                  nlen = strlen(pp->pw_name) + 1 + strlen(skey_get_algorithm()) +
                                      defaultseed);                      1 + 4 + 1 + strlen(seed) + 1 + 16 + 1 + strlen(tbuf) + 1;
                         (void)fgets(seed, sizeof(seed), stdin);  
                         rip(seed);                  /*
                         if (seed[0] == '\0')                   * If there was no hash type (md4) add one unless we
                                 (void)strcpy(seed, defaultseed);                   * are short on space.
                         for (p = seed; *p; p++) {                   */
                                 if (isalpha(*p)) {                  if (oldmd4) {
                                         if (isupper(*p))                          if (nlen > skey.len)
                                                 *p = tolower(*p);                                  nlen -= 4;
                                 } else if (!isdigit(*p)) {                          else
                                         (void)puts("Error: seed may only contain alpha numeric characters");                                  oldmd4 = 0;
                                         break;  
                                 }  
                         }  
                         if (*p == '\0')  
                                 break;  /* Valid seed */  
                 }                  }
                 if (strlen(seed) > SKEY_MAX_SEED_LEN) {  
                         (void)printf("Notice: Seed truncated to %d characters.\n",                  /* If new entry is longer than the old, comment out the old. */
                                      SKEY_MAX_SEED_LEN);                  if (nlen > skey.len) {
                         seed[SKEY_MAX_SEED_LEN] = '\0';                          (void)skeyzero(&skey, pp->pw_name);
                           /* Re-open keys file and seek to the end */
                           if (skeylookup(&skey, pp->pw_name) == -1)
                                   err(1, "cannot reopen database");
                           lockeof(&skey, pp->pw_name);
                   } else {
                           /* Compute how much to space-pad the seed */
                           seedlen = strlen(seed) + (skey.len - nlen);
                 }                  }
           }
   
                 for (i = 0;; i++) {          if ((skey.val = (char *)malloc(16 + 1)) == NULL)
                         if (i >= 2)                  err(1, "Can't allocate memory");
                                 exit(1);          btoa8(skey.val, key);
   
                         (void)printf("otp-%s %d %s\nS/Key access password: ",          /* Don't save algorithm type for md4 (maintain record length) */
                                      skey_get_algorithm(), n, seed);          /* XXX - should check return values of fprintf + fclose */
                         (void)fgets(buf, sizeof(buf), stdin);          if (oldmd4)
                         rip(buf);                  (void)fprintf(skey.keyfile, "%s %04d %-* %s %-21s\n",
                         backspace(buf);                      pp->pw_name, n, seedlen, seed, skey.val, tbuf);
           else
                   (void)fprintf(skey.keyfile, "%s %s %04d %-*s %s %-21s\n",
                       pp->pw_name, skey_get_algorithm(), n, seedlen, seed,
                       skey.val, tbuf);
           (void)fclose(skey.keyfile);
   
                         if (buf[0] == '?') {          (void)printf("\nID %s skey is otp-%s %d %s\n", pp->pw_name,
                                 (void)puts("Enter 6 English words from secure S/Key calculation.");                       skey_get_algorithm(), n, seed);
                                 continue;          (void)printf("Next login password: %s\n\n",
                         } else if (buf[0] == '\0')              hexmode ? put8(buf, key) : btoe(buf, key));
                                 exit(1);          exit(0);
                         if (etob(key, buf) == 1 || atob8(key, buf) == 0)  }
                                 break;  /* Valid format */  
                         (void)puts("Invalid format - try again with 6 English words.");  
                 }  
         } else {  
                 /* Get user's secret password */  
                 fputs("Reminder - Only use this method if you are directly connected\n           or have an encrypted channel.  If you are using telnet\n           or rlogin, exit with no password and use skeyinit -s.\n", stderr);  
   
                 for (i = 0;; i++) {  void
                         if (i > 2)  lockeof(mp, user)
                                 exit(1);          struct skey *mp;
           char *user;
   {
           struct flock fl;
   
                         (void)fputs("Enter secret password: ", stderr);          fseek(mp->keyfile, 0, SEEK_END);
                         readpass(passwd, sizeof(passwd));  dolock:
                         if (passwd[0] == '\0')          fl.l_start = ftell(mp->keyfile);
                                 exit(1);          fl.l_len = mp->len;
           fl.l_pid = getpid();
           fl.l_type = F_WRLCK;
           fl.l_whence = SEEK_SET;
   
                         if (strlen(passwd) < SKEY_MIN_PW_LEN) {          if (fcntl(fileno(mp->keyfile), F_SETLKW, &fl) == -1)
                                 (void)fprintf(stderr,                  err(1, "Can't lock database");
                                     "Your password must be at least %d characters long.\n", SKEY_MIN_PW_LEN);  
                                 continue;  
                         } else if (strcmp(passwd, pp->pw_name) == 0) {  
                                 (void)fputs("Your password may not be the same as your user name.\n", stderr);  
                                 continue;  
                         } else if (strspn(passwd, "abcdefghijklmnopqrstuvwxyz") == strlen(passwd)) {  
                                 (void)fputs("Your password must contain more than just lower case letters.\nWhitespace, numbers, and puctuation are suggested.\n", stderr);  
                                 continue;  
                         }  
   
                         (void)fputs("Again secret password: ", stderr);          /* Make sure we are still at the end. */
                         readpass(passwd2, sizeof(passwd));          fseek(mp->keyfile, 0, SEEK_END);
           if (fl.l_start == ftell(mp->keyfile))
                   return;         /* still at EOF */
   
                         if (strcmp(passwd, passwd2) == 0)          fclose(mp->keyfile);
                                 break;          if (skeylookup(mp, user) != 1)
                   errx(1, "user %s already added", user);
           goto dolock;
   }
   
                         (void)fputs("Passwords do not match.\n", stderr);  void
                 }  secure_mode(count, key, seed, defaultseed, buf, bufsiz)
           int *count;
           char *key;
           char *seed;
           char *defaultseed;
           char *buf;
           size_t bufsiz;
   {
           int i, n;
           char *p;
   
                 /* Crunch seed and password into starting key */          (void)puts("You need the 6 words generated from the \"skey\" command.");
                 (void)strcpy(seed, defaultseed);          for (i = 0; ; i++) {
                 if (keycrunch(key, seed, passwd) != 0)                  if (i >= 2)
                         err(2, "key crunch failed");                          exit(1);
   
                 nn = n;                  (void)printf("Enter sequence count from 1 to %d: ",
                 while (nn-- != 0)                      SKEY_MAX_SEQ);
                         f(key);                  (void)fgets(buf, bufsiz, stdin);
                   clearerr(stdin);
                   n = atoi(buf);
                   if (n > 0 && n < SKEY_MAX_SEQ)
                           break;  /* Valid range */
                   (void)fprintf(stderr, "ERROR: Count must be between 1 and %d\n",
                                SKEY_MAX_SEQ);
         }          }
         (void)time(&now);  
         tm = localtime(&now);  
         (void)strftime(tbuf, sizeof(tbuf), " %b %d,%Y %T", tm);  
   
         if ((skey.val = (char *)malloc(16 + 1)) == NULL)          for (i = 0; ; i++) {
                 err(1, "Can't allocate memory");                  if (i >= 2)
                           exit(1);
   
         /* Zero out old key if necesary (entry would change size) */                  (void)printf("Enter new seed [default %s]: ",
         if (zerokey) {                               defaultseed);
                 (void)skeyzero(&skey, pp->pw_name);                  (void)fgets(seed, SKEY_MAX_SEED_LEN+2, stdin); /* XXX */
                 /* Re-open keys file and seek to the end */                  clearerr(stdin);
                 if (skeylookup(&skey, pp->pw_name) == -1)                  rip(seed);
                         err(1, "cannot open database");                  if (strlen(seed) > SKEY_MAX_SEED_LEN) {
                           (void)fprintf(stderr, "ERROR: Seed must be between 1 "
                               "and %d characters in length\n", SKEY_MAX_SEED_LEN);
                           continue;
                   }
                   if (seed[0] == '\0')
                           (void)strcpy(seed, defaultseed);
                   for (p = seed; *p; p++) {
                           if (isspace(*p)) {
                                   (void)fputs("ERROR: Seed must not contain "
                                       "any spaces\n", stderr);
                                   break;
                           } else if (isalpha(*p)) {
                                   if (isupper(*p))
                                           *p = tolower(*p);
                           } else if (!isdigit(*p)) {
                                   (void)fputs("ERROR: Seed must be purely "
                                       "alphanumeric\n", stderr);
                                   break;
                           }
                   }
                   if (*p == '\0')
                           break;  /* Valid seed */
         }          }
   
         btoa8(skey.val, key);          for (i = 0; ; i++) {
                   if (i >= 2)
                           exit(1);
   
         /*                  (void)printf("otp-%s %d %s\nS/Key access password: ",
          * Obtain an exclusive lock on the key file so we don't                               skey_get_algorithm(), n, seed);
          * clobber someone authenticating themselves at the same time.                  (void)fgets(buf, bufsiz, stdin);
          */                  clearerr(stdin);
         for (i = 0; i < 300; i++) {                  rip(buf);
                 if ((rval = flock(fileno(skey.keyfile), LOCK_EX|LOCK_NB)) == 0                  backspace(buf);
                     || errno != EWOULDBLOCK)  
                   if (buf[0] == '?') {
                           (void)puts("Enter 6 words from secure S/Key calculation.");
                           continue;
                   } else if (buf[0] == '\0')
                           exit(1);
   
                   if (etob(key, buf) == 1 || atob8(key, buf) == 0)
                           break;  /* Valid format */
                   (void)fputs("ERROR: Invalid format - try again with the 6 words.\n",
                       stderr);
           }
           *count= n;
   }
   
   void
   normal_mode(username, n, key, seed, defaultseed)
           char *username;
           int n;
           char *key;
           char *seed;
           char *defaultseed;
   {
           int i, nn;
           char passwd[SKEY_MAX_PW_LEN+2], passwd2[SKEY_MAX_PW_LEN+2];
   
           /* Get user's secret passphrase */
           for (i = 0; ; i++) {
                   if (i > 2)
                           exit(1);
   
                   if (readpassphrase("Enter secret passphrase: ", passwd,
                       sizeof(passwd), 0) == NULL || passwd[0] == '\0')
                           exit(1);
   
                   if (strlen(passwd) < SKEY_MIN_PW_LEN) {
                           (void)fprintf(stderr,
                               "ERROR: Your passphrase must be at least %d "
                               "characters long.\n", SKEY_MIN_PW_LEN);
                           continue;
                   } else if (strcmp(passwd, username) == 0) {
                           (void)fputs("ERROR: Your passphrase may not be the "
                               "same as your user name.\n", stderr);
                           continue;
                   } else if (strspn(passwd, "abcdefghijklmnopqrstuvwxyz") ==
                       strlen(passwd)) {
                           (void)fputs("ERROR: Your passphrase must contain more "
                               "than just lower case letters.\nWhitespace, "
                               "numbers, and puctuation are suggested.\n", stderr);
                           continue;
                   } else if (strlen(passwd) > 63) {
                           (void)fprintf(stderr, "WARNING: Your passphrase is "
                               "longer than the recommended maximum length of 63\n");
                   }
                   /* XXX - should check for passphrase that is really too long */
   
                   if (readpassphrase("Again secret passphrase: ", passwd2,
                       sizeof(passwd2), 0) && strcmp(passwd, passwd2) == 0)
                         break;                          break;
                 usleep(100000);                 /* Sleep for 0.1 seconds */  
                   (void)fputs("Passphrases do not match.\n", stderr);
         }          }
         if (rval == -1) {                       /* Can't get exclusive lock */  
                 errno = EAGAIN;  
                 err(1, "cannot open database");  
         }  
   
         /* Don't save algorithm type for md4 (keep record length same) */          /* Crunch seed and passphrase into starting key */
         if (strcmp(skey_get_algorithm(), "md4") == 0)          (void)strcpy(seed, defaultseed);
                 (void)fprintf(skey.keyfile, "%s %04d %-16s %s %-21s\n",          if (keycrunch(key, seed, passwd) != 0)
                     pp->pw_name, n, seed, skey.val, tbuf);                  err(2, "key crunch failed");
         else  
                 (void)fprintf(skey.keyfile, "%s %s %04d %-16s %s %-21s\n",  
                     pp->pw_name, skey_get_algorithm(), n, seed, skey.val, tbuf);  
   
         (void)fclose(skey.keyfile);          nn = n;
           while (nn-- != 0)
                   f(key);
   }
   
         (void)printf("\nID %s skey is otp-%s %d %s\n", pp->pw_name,  #define TIMEOUT_MSG     "Timed out waiting for input.\n"
                      skey_get_algorithm(), n, seed);  void
         (void)printf("Next login password: %s\n\n",  timedout(signo)
                      hexmode ? put8(buf, key) : btoe(buf, key));          int signo;
         exit(0);  {
   
           write(STDERR_FILENO, TIMEOUT_MSG, sizeof(TIMEOUT_MSG) - 1);
           _exit(1);
 }  }
   
 void  void

Legend:
Removed from v.1.27  
changed lines
  Added in v.1.28