/*
- * $Id: afppasswd.c,v 1.17 2003-06-09 02:51:34 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 */
-#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 */
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
-#ifdef HAVE_FCNTL_H
#include <fcntl.h>
-#endif /* HAVE_FCNTL_H */
#include <pwd.h>
-
-#include <netatalk/endian.h>
+#include <arpa/inet.h>
#include <des.h>
#define OPTIONS "cafnu:p:"
#define UID_START 100
-#define PASSWDLEN DES_KEY_SZ
-#define HEXPASSWDLEN (PASSWDLEN * 2)
+#define HEXPASSWDLEN 16
+#define PASSWDLEN 8
static char buf[MAXPATHLEN + 1];
-/* 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)
-{
- int i, 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. */
+/* 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 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);
-
- return key;
-}
-
-static int decrypt_passwd(u_int8_t *dst, const u_int8_t *src, int keyfd)
+static void convert_passwd(char *buf, char *newpwd, const int keyfd)
{
- u_int8_t *key;
- int err = 0;
-
- key = retrieve_key(keyfd);
- if (!key)
- return 0;
-
- {
- 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));
+ uint8_t key[HEXPASSWDLEN];
+ Key_schedule schedule;
+ unsigned 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);
}
- memset(key, 0, HEXPASSWDLEN);
-
- return err;
-}
-
-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;
-
- {
- DES_key_schedule schedule;
-
- DES_set_key_unchecked((DES_cblock *) key, &schedule);
- DES_ecb_encrypt((DES_cblock *) src, (DES_cblock *) dst,
- &schedule, DES_ENCRYPT);
-
+ 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);
+ } else {
+ /* decrypt the password */
+ ecb_encrypt((C_Block *) buf, (C_Block *) buf, schedule, DES_DECRYPT);
+ }
memset(&schedule, 0, sizeof(schedule));
}
- return err;
+ if (newpwd) {
+ const unsigned char hextable[] = "0123456789ABCDEF";
+
+ /* 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];
+ }
+ }
}
/* this matches the code in uam_randnum.c */
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, _("Can't open password file %s: %s.\n"), path, strerror(errno));
- return 1;
+ fprintf(stderr, "afppasswd: can't open %s\n", path);
+ return -1;
}
/* open the key file if it exists */
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);
while (fgets(buf, sizeof(buf), fp)) {
if ((p = strchr(buf, ':'))) {
/* check for a match */
- if (strncmp(buf, name, p - buf) == 0) {
+ if (strlen(name) == (p - buf) &&
+ 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;
}
- found = 1;
- break;
+ goto found_entry;
}
}
pos = ftell(fp);
memset(buf, 0, sizeof(buf));
}
- 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;
- }
+ 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;
}
+found_entry:
/* need to verify against old password */
if ((flags & OPT_ISROOT) == 0) {
- 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;
- }
+ passwd = getpass("Enter OLD AFP password: ");
+ convert_passwd(p, NULL, keyfd);
if (strncmp(passwd, p, PASSWDLEN)) {
- memset(passwd, 0, strlen(passwd));
- fprintf(stderr, _("Wrong password.\n"));
- err = 1;
+ fprintf(stderr, "afppasswd: invalid 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)) {
- char *str;
- if (str = FascistCheck(password, _PATH_CRACKLIB)) {
- memset(password, 0, PASSWDLEN);
- fprintf(stderr, _("Error: %s\n"), str);
- err = 1;
- goto update_done;
+ if (passwd = FascistCheck(password, _PATH_CRACKLIB)) {
+ fprintf(stderr, "Error: %s\n", passwd);
+ 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);
-
- 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);
+ 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");
} else {
- memset(passwd, 0, strlen(passwd));
- memset(password, 0, PASSWDLEN);
- fprintf(stderr, _("Passwords don't match!\n"));
- err = 1;
+ fprintf(stderr, "afppasswd: passwords don't match!\n");
+ err = -1;
}
update_done:
if ((fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600)) < 0) {
- fprintf(stderr, _("Can't create password file %s: %s\n"), path, strerror(errno));
- return 1;
+ fprintf(stderr, "afppasswd: can't create %s\n", path);
+ return -1;
}
setpwent();
strcat(buf, FORMAT);
len = strlen(buf);
if (write(fd, buf, len) != len) {
- fprintf(stderr, _("Problem writing to password file %s: %s\n"),
- path, strerror(errno));
- err = 1;
+ fprintf(stderr, "afppasswd: problem writing to %s: %s\n", path,
+ strerror(errno));
+ err = -1;
break;
}
}
}
-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;
flags = ((uid = getuid()) == 0) ? OPT_ISROOT : 0;
if (((flags & OPT_ISROOT) == 0) && (argc > 1)) {
- usage();
- return 1;
+ fprintf(stderr, "afppasswd (Netatalk %s)\n", VERSION);
+ 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;
}
while ((i = getopt(argc, argv, OPTIONS)) != EOF) {
if (err || (optind + ((flags & OPT_CREATE) ? 0 :
(flags & OPT_ISROOT)) != argc)) {
- usage();
- return 1;
+#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;
}
+ i = stat(path, &st);
if (flags & OPT_CREATE) {
if ((flags & OPT_ISROOT) == 0) {
- fprintf(stderr, _("Only root can create the password file.\n"));
- return 1;
+ fprintf(stderr, "afppasswd: only root can create the password file.\n");
+ return -1;
}
- if (!stat(path, &st) && ((flags & OPT_FORCE) == 0)) {
- fprintf(stderr, _("Password file already exists.\n"));
- return 1;
+ if (!i && ((flags & OPT_FORCE) == 0)) {
+ fprintf(stderr, "afppasswd: password file already exists.\n");
+ return -1;
}
return create_file(path, uid_min);
} else {
struct passwd *pwd = NULL;
- if (stat(path, &st) < 0) {
- fprintf(stderr, _("Password file %s doesn't exist.\n"), path);
- return 1;
+ if (i < 0) {
+ fprintf(stderr, "afppasswd: %s doesn't exist.\n", path);
+ return -1;
}
/* if we're root, we need to specify the username */
if (pwd)
return update_passwd(path, pwd->pw_name, flags);
- fprintf(stderr, _("Can't get password entry.\n"));
- return 1;
+ fprintf(stderr, "afppasswd: can't get password entry.\n");
+ return -1;
}
}