]> arthur.barton.de Git - netatalk.git/blobdiff - bin/afppasswd/afppasswd.c
Include path fixes.
[netatalk.git] / bin / afppasswd / afppasswd.c
index f5d7110aa18e3338404f18cc2b6edb297a70d119..eb138c4f47f5c044df812d4657b38ac451707707 100644 (file)
@@ -1,5 +1,5 @@
 /* 
- * $Id: afppasswd.c,v 1.8 2001-09-06 20:00:59 rufustfirefly Exp $
+ * $Id: afppasswd.c,v 1.18 2003-06-09 02:55:25 srittau Exp $
  *
  * Copyright 1999 (c) Adrian Sun (asun@u.washington.edu)
  * All Rights Reserved. See COPYRIGHT.
  */
 
 #ifdef HAVE_CONFIG_H
-#include "config.h"
+#include <config.h>
 #endif /* HAVE_CONFIG_H */
 
-/* STDC check */
-#if STDC_HEADERS
-#include <string.h>
-#else /* STDC_HEADERS */
-#ifndef HAVE_STRCHR
-#define strchr index
-#define strrchr index
-#endif /* HAVE_STRCHR */
-char *strchr (), *strrchr ();
-#ifndef HAVE_MEMCPY
-#define memcpy(d,s,n) bcopy ((s), (d), (n))
-#define memmove(d,s,n) bcopy ((s), (d), (n))
-#endif /* ! HAVE_MEMCPY */
-#endif /* STDC_HEADERS */
-
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <errno.h>
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif /* HAVE_UNISTD_H */
@@ -55,8 +43,12 @@ char *strchr (), *strrchr ();
 
 #include <netatalk/endian.h>
 
-#ifdef UAM_RNDNUM
+#if HAVE_GCRYPT
+#include <gcrypt.h>
+#define DES_KEY_SZ 8
+#else
 #include <des.h>
+#endif
 
 #ifdef USE_CRACKLIB
 #include <crack.h>
@@ -75,57 +67,142 @@ char *strchr (), *strrchr ();
 #define OPTIONS "cafnu:p:"
 #define UID_START 100
 
-#define HEXPASSWDLEN 16
-#define PASSWDLEN 8
+#define PASSWDLEN DES_KEY_SZ
+#define HEXPASSWDLEN (PASSWDLEN * 2)
 
 static char buf[MAXPATHLEN + 1];
 
-/* if newpwd is null, convert buf from hex to binary. if newpwd isn't
- * null, convert newpwd to hex and save it in buf. */
-#define unhex(x)  (isdigit(x) ? (x) - '0' : toupper(x) + 10 - 'A')
-static void convert_passwd(char *buf, char *newpwd, const int keyfd)
+/* FIXME: preparation for i18n */
+#ifndef _
+#define _(x) (x)
+#endif
+
+/* SRC and DST must not overlap. */
+static void hexify(u_int8_t *dst, const u_int8_t *src)
 {
-  u_int8_t key[HEXPASSWDLEN];
-  Key_schedule schedule;
   int i, j;
 
-  if (!newpwd) {
-    /* convert to binary */
-    for (i = j = 0; i < sizeof(key); i += 2, j++)
-      buf[j] = (unhex(buf[i]) << 4) | unhex(buf[i + 1]);
-    if (j <= DES_KEY_SZ)
-      memset(buf + j, 0, sizeof(key) - j);
+  for (i = j = 0; i < DES_KEY_SZ; i++, j += 2) {
+    static const unsigned char hextable[] = "0123456789ABCDEF";
+
+    dst[j]     = hextable[(src[i] & 0xF0) >> 4];
+    dst[j + 1] = hextable[(src[i] & 0x0F)];
   }
+}
+
+/* SRC and DST can overlap. */
+#define unhex(x)  (isdigit(x) ? (x) - '0' : toupper(x) + 10 - 'A')
+static void unhexify(u_int8_t *dst, const u_int8_t *src)
+{
+  int i, j;
+
+  /* convert to binary */
+  for (i = j = 0; i < HEXPASSWDLEN; i += 2, j++)
+    dst[j] = (unhex(src[i]) << 4) | unhex(src[i + 1]);
+  if (j <= DES_KEY_SZ)
+    memset(dst + j, 0, HEXPASSWDLEN - j);
+}
+
+static u_int8_t *retrieve_key(int keyfd)
+{
+  static u_int8_t key[HEXPASSWDLEN];
+
+  if (lseek(keyfd, 0, SEEK_SET) == -1)
+    return NULL;
+  if (read(keyfd, key, sizeof(key)) < sizeof(key))
+    return NULL;
+
+  unhexify(key, key);
 
-  if (keyfd > -1) {
-    lseek(keyfd, 0, SEEK_SET);
-    read(keyfd, key, sizeof(key));
-    /* convert to binary */
-    for (i = j = 0; i < sizeof(key); i += 2, j++)
-      key[j] = (unhex(key[i]) << 4) | unhex(key[i + 1]);
-    if (j <= DES_KEY_SZ)
-      memset(key + j, 0, sizeof(key) - j);
-    key_sched((C_Block *) key, schedule);
-    memset(key, 0, sizeof(key));   
-    if (newpwd) {
-       ecb_encrypt((C_Block *) newpwd, (C_Block *) newpwd, schedule,
-                   DES_ENCRYPT);
+  return key;
+}
+
+static int decrypt_passwd(u_int8_t *dst, const u_int8_t *src, int keyfd)
+{
+  u_int8_t *key;
+  int err = 0;
+
+  key = retrieve_key(keyfd);
+  if (!key)
+    return 0;
+
+  {
+#if HAVE_GCRYPT
+    GcryCipherHd handle;
+
+    handle = gcry_cipher_open(GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+    if (handle) {
+      int ret;
+
+      ret = gcry_cipher_setkey(handle, key, DES_KEY_SZ);
+      if (!ret)
+        ret = gcry_cipher_decrypt(handle, dst, 8, src, 8);
+      gcry_cipher_close(handle);
+      if (ret) {
+        fprintf(stderr, _("Decryption error: %s\n"), gcry_strerror(ret));
+        err = 1;
+      }
+      printf("pw: %s\n", buf); /* FIXME */
     } else {
-      /* decrypt the password */
-      ecb_encrypt((C_Block *) buf, (C_Block *) buf, schedule, DES_DECRYPT);
+      fprintf(stderr, _("Could not create crypt handle.\n"));
+      err = 1;
     }
-    memset(schedule, 0, sizeof(schedule));      
+#else
+    DES_key_schedule schedule;
+
+    DES_set_key_unchecked((DES_cblock *) key, &schedule);
+    DES_ecb_encrypt((DES_cblock *) src, (DES_cblock *) dst,
+                    &schedule, DES_DECRYPT);
+
+    memset(&schedule, 0, sizeof(schedule));
+#endif
   }
 
-  if (newpwd) {
-    const unsigned char hextable[] = "0123456789ABCDEF";
+  memset(key, 0, HEXPASSWDLEN);
+
+  return err;
+}
 
-    /* convert to hex */
-    for (i = j = 0; i < DES_KEY_SZ; i++, j += 2) {
-      buf[j] = hextable[(newpwd[i] & 0xF0) >> 4];
-      buf[j + 1] = hextable[newpwd[i] & 0x0F];
+static int encrypt_passwd(u_int8_t *dst, const u_int8_t *src, int keyfd)
+{
+  const u_int8_t *key;
+  int err = 0;
+
+  key = retrieve_key(keyfd);
+  if (!key)
+    return 0;
+
+  {
+#if HAVE_GCRYPT
+    GcryCipherHd handle;
+    int ret;
+                                                                                
+    handle = gcry_cipher_open(GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+    if (handle) {
+      ret = gcry_cipher_setkey(handle, key, DES_KEY_SZ);
+      if (!ret)
+        ret = gcry_cipher_encrypt(handle, dst, 8, src, 0);
+      gcry_cipher_close(handle);
+      if (ret) {
+        fprintf(stderr, _("Encryption error: %s\n"), gcry_strerror(ret));
+        err = 1;
+      }
+    } else {
+      fprintf(stderr, _("Could not create crypt handle.\n"));
+      err = 1;
     }
+#else
+    DES_key_schedule schedule;
+
+    DES_set_key_unchecked((DES_cblock *) key, &schedule);
+    DES_ecb_encrypt((DES_cblock *) src, (DES_cblock *) dst,
+                    &schedule, DES_ENCRYPT);
+
+    memset(&schedule, 0, sizeof(schedule));      
+#endif
   }
+
+  return err;
 }
 
 /* this matches the code in uam_randnum.c */
@@ -134,11 +211,12 @@ static int update_passwd(const char *path, const char *name, int flags)
   char password[PASSWDLEN + 1], *p, *passwd;
   FILE *fp;
   off_t pos;
+  int found = 0;
   int keyfd = -1, err = 0;
 
   if ((fp = fopen(path, "r+")) == NULL) {
-    fprintf(stderr, "afppasswd: can't open %s\n", path);
-    return -1;
+    fprintf(stderr, _("Can't open password file %s: %s.\n"), path, strerror(errno));
+    return 1;
   }
 
   /* open the key file if it exists */
@@ -146,6 +224,11 @@ static int update_passwd(const char *path, const char *name, int flags)
   if (strlen(path) < sizeof(buf) - 5) {
     strcat(buf, ".key");
     keyfd = open(buf, O_RDONLY);
+    if (keyfd == -1 && errno != ENOENT) {
+      fprintf(stderr, _("Can't open key file %s: %s\n"), buf, strerror(errno));
+      err = 1;
+      goto update_done;
+    }
   } 
 
   pos = ftell(fp);
@@ -156,73 +239,94 @@ static int update_passwd(const char *path, const char *name, int flags)
       if (strncmp(buf, name, p - buf) == 0) {
        p++;
        if (!(flags & OPT_ISROOT) && (*p == PASSWD_ILLEGAL)) {
-         fprintf(stderr, "Your password is disabled. Please see your administrator.\n");
+         fprintf(stderr, _("Your password is disabled. Please see your administrator.\n"));
          break;
        }
-       goto found_entry;
+       found = 1;
+       break;
       }
     }
     pos = ftell(fp);
     memset(buf, 0, sizeof(buf));
   }
 
-  if (flags & OPT_ADDUSER) {
-    strcpy(buf, name);
-    strcat(buf, FORMAT);
-    p = strchr(buf, ':') + 1;
-    fwrite(buf, strlen(buf), 1, fp);
-  } else {
-    fprintf(stderr, "afppasswd: can't find %s in %s\n", name, path);
-    err = -1;
-    goto update_done;
+  if (!found) {
+    if ((flags & OPT_ISROOT) && (flags & OPT_ADDUSER)) {
+      strcpy(buf, name);
+      strcat(buf, FORMAT);
+      p = strchr(buf, ':') + 1;
+      fwrite(buf, strlen(buf), 1, fp);
+    } else {
+      fprintf(stderr, _("Can't find user %s in %s\n"), name, path);
+      err = 1;
+      goto update_done;
+    }
   }
 
-found_entry:
   /* need to verify against old password */
   if ((flags & OPT_ISROOT) == 0) {
-    passwd = getpass("Enter OLD AFP password: ");
-    convert_passwd(p, NULL, keyfd);
+    passwd = getpass(_("Enter OLD AFP password: "));
+    unhexify(p, p);
+    err = decrypt_passwd(p, p, keyfd);
+    if (err) {
+      memset(passwd, 0, strlen(passwd));
+      goto update_done;
+    }
     if (strncmp(passwd, p, PASSWDLEN)) {
-      fprintf(stderr, "afppasswd: invalid password.\n");
-      err = -1;
+      memset(passwd, 0, strlen(passwd));
+      fprintf(stderr, _("Wrong password.\n"));
+      err = 1;
       goto update_done;
     }
+    memset(passwd, 0, strlen(passwd));
   }
 
   /* new password */
-  passwd = getpass("Enter NEW AFP password: ");
+  passwd = getpass(_("Enter NEW AFP password: "));
   memcpy(password, passwd, sizeof(password));
+  memset(passwd, 0, strlen(passwd));
   password[PASSWDLEN] = '\0';
 #ifdef USE_CRACKLIB
   if (!(flags & OPT_NOCRACK)) {
-    if (passwd = FascistCheck(password, _PATH_CRACKLIB)) { 
-        fprintf(stderr, "Error: %s\n", passwd);
-        err = -1;
-        goto update_done;
+    char *str;
+    if (str = FascistCheck(password, _PATH_CRACKLIB)) { 
+      memset(password, 0, PASSWDLEN);
+      fprintf(stderr, _("Error: %s\n"), str);
+      err = 1;
+      goto update_done;
     } 
   }
 #endif /* USE_CRACKLIB */
 
-  passwd = getpass("Enter NEW AFP password again: ");
+  passwd = getpass(_("Enter NEW AFP password again: "));
   if (strcmp(passwd, password) == 0) {
-     struct flock lock;
-     int fd = fileno(fp);
-
-     convert_passwd(p, password, keyfd);
-     lock.l_type = F_WRLCK;
-     lock.l_start = pos;
-     lock.l_len = 1;
-     lock.l_whence = SEEK_SET;
-     fseek(fp, pos, SEEK_SET);
-     fcntl(fd, F_SETLKW, &lock);
-     fwrite(buf, p - buf + HEXPASSWDLEN, 1, fp);
-     lock.l_type = F_UNLCK;
-     fcntl(fd, F_SETLK, &lock);
-     printf("afppasswd: updated password.\n");
+    struct flock lock;
+    int fd = fileno(fp);
+
+    memset(passwd, 0, strlen(passwd));
+
+    err = encrypt_passwd(password, password, keyfd);
+    if (err)
+      goto update_done;
+    hexify(p, password);
+
+    lock.l_type = F_WRLCK;
+    lock.l_start = pos;
+    lock.l_len = 1;
+    lock.l_whence = SEEK_SET;
+    fseek(fp, pos, SEEK_SET);
+    fcntl(fd, F_SETLKW, &lock);
+    fwrite(buf, p - buf + HEXPASSWDLEN, 1, fp);
+    lock.l_type = F_UNLCK;
+    fcntl(fd, F_SETLK, &lock);
+    printf(_("Updated password.\n"));
+    memset(password, 0, PASSWDLEN);
 
   } else {
-    fprintf(stderr, "afppasswd: passwords don't match!\n");
-    err = -1;
+    memset(passwd, 0, strlen(passwd));
+    memset(password, 0, PASSWDLEN);
+    fprintf(stderr, _("Passwords don't match!\n"));
+    err = 1;
   }
 
 update_done:
@@ -241,8 +345,8 @@ static int create_file(const char *path, uid_t minuid)
 
   
   if ((fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600)) < 0) {
-    fprintf(stderr, "afppasswd: can't create %s\n", path);
-    return -1;
+    fprintf(stderr, _("Can't create password file %s: %s\n"), path, strerror(errno));
+    return 1;
   }
 
   setpwent();
@@ -256,8 +360,9 @@ static int create_file(const char *path, uid_t minuid)
     strcat(buf, FORMAT);
     len = strlen(buf);
     if (write(fd, buf, len) != len) {
-      fprintf(stderr, "afppasswd: problem writing to %s: %m\n", path);
-      err = -1;
+      fprintf(stderr, _("Problem writing to password file %s: %s\n"),
+             path, strerror(errno));
+      err = 1;
       break;
     }
   }
@@ -268,6 +373,24 @@ static int create_file(const char *path, uid_t minuid)
 }
 
 
+static void usage(void)
+{
+#ifdef USE_CRACKLIB
+    fprintf(stderr, _("Usage: afppasswd [-acfn] [-u minuid] [-p path] [username]\n"));
+#else /* USE_CRACKLIB */
+    fprintf(stderr, _("Usage: afppasswd [-acf] [-u minuid] [-p path] [username]\n"));
+#endif /* USE_CRACKLIB */
+    fprintf(stderr, _("  -a        add a new user\n"));
+    fprintf(stderr, _("  -c        create and initialize password file or specific user\n"));
+    fprintf(stderr, _("  -f        force an action\n"));
+#ifdef USE_CRACKLIB
+    fprintf(stderr, _("  -n        disable cracklib checking of passwords\n"));
+#endif /* USE_CRACKLIB */
+    fprintf(stderr, _("  -u uid    minimum uid to use, defaults to 100\n"));
+    fprintf(stderr, _("  -p path   path to afppasswd file\n"));
+}
+
+
 int main(int argc, char **argv)
 {
   struct stat st;
@@ -282,16 +405,8 @@ int main(int argc, char **argv)
   flags = ((uid = getuid()) == 0) ? OPT_ISROOT : 0;
 
   if (((flags & OPT_ISROOT) == 0) && (argc > 1)) {
-    fprintf(stderr, "Usage: afppasswd [-acfn] [-u minuid] [-p path] [username]\n");
-    fprintf(stderr, "  -a        add a new user\n");
-    fprintf(stderr, "  -c        create and initialize password file or specific user\n");
-    fprintf(stderr, "  -f        force an action\n");
-#ifdef USE_CRACKLIB
-    fprintf(stderr, "  -n        disable cracklib checking of passwords\n");
-#endif /* USE_CRACKLIB */
-    fprintf(stderr, "  -u uid    minimum uid to use, defaults to 100\n");
-    fprintf(stderr, "  -p path   path to afppasswd file\n");
-    return -1;
+    usage();
+    return 1;
   }
 
   while ((i = getopt(argc, argv, OPTIONS)) != EOF) {
@@ -324,41 +439,28 @@ int main(int argc, char **argv)
   
   if (err || (optind + ((flags & OPT_CREATE) ? 0 : 
                        (flags & OPT_ISROOT)) != argc)) {
-#ifdef USE_CRACKLIB
-    fprintf(stderr, "Usage: afppasswd [-acfn] [-u minuid] [-p path] [username]\n");
-#else /* USE_CRACKLIB */
-    fprintf(stderr, "Usage: afppasswd [-acf] [-u minuid] [-p path] [username]\n");
-#endif /* USE_CRACKLIB */
-    fprintf(stderr, "  -a        add a new user\n");
-    fprintf(stderr, "  -c        create and initialize password file or specific user\n");
-    fprintf(stderr, "  -f        force an action\n");
-#ifdef USE_CRACKLIB
-    fprintf(stderr, "  -n        disable cracklib checking of passwords\n");
-#endif /* USE_CRACKLIB */
-    fprintf(stderr, "  -u uid    minimum uid to use, defaults to 100\n");
-    fprintf(stderr, "  -p path   path to afppasswd file\n");
-    return -1;
+    usage();
+    return 1;
   }
 
-  i = stat(path, &st);
   if (flags & OPT_CREATE) {
     if ((flags & OPT_ISROOT) == 0) {
-      fprintf(stderr, "afppasswd: only root can create the password file.\n");
-      return -1;
+      fprintf(stderr, _("Only root can create the password file.\n"));
+      return 1;
     }
 
-    if (!i && ((flags & OPT_FORCE) == 0)) {
-      fprintf(stderr, "afppasswd: password file already exists.\n");
-      return -1;
+    if (!stat(path, &st) && ((flags & OPT_FORCE) == 0)) {
+      fprintf(stderr, _("Password file already exists.\n"));
+      return 1;
     }
     return create_file(path, uid_min);
 
   } else {
     struct passwd *pwd = NULL;
 
-    if (i < 0) {
-      fprintf(stderr, "afppasswd: %s doesn't exist.\n", path);
-      return -1;
+    if (stat(path, &st) < 0) {
+      fprintf(stderr, _("Password file %s doesn't exist.\n"), path);
+      return 1;
     }
     
     /* if we're root, we need to specify the username */
@@ -366,17 +468,7 @@ int main(int argc, char **argv)
     if (pwd)
       return update_passwd(path, pwd->pw_name, flags);
 
-    fprintf(stderr, "afppasswd: can't get password entry.\n");
-    return -1;
+    fprintf(stderr, _("Can't get password entry.\n"));
+    return 1;
   }
 }
-#else /* UAM_RNDNUM */
-
-main(int argc, char **argv)
-{
-  fprintf(stderr, "afppasswd is only useful if you're using centralized passwords\n");
-  fprintf(stderr, "for the Random Number authentication methods.\n");
-  return -1;
-}
-
-#endif /* UAM_RNDNUM */