2 * $Id: afppasswd.c,v 1.18 2003-06-09 02:55:25 srittau Exp $
4 * Copyright 1999 (c) Adrian Sun (asun@u.washington.edu)
5 * All Rights Reserved. See COPYRIGHT.
7 * format of the password file:
8 * name:****************:****************:********
9 * password last login date failed usage count
11 * ***'s are illegal. they're just place holders for hex values. hex
12 * values that represent actual numbers are in network byte order.
14 * last login date is currently a 4-byte number representing seconds
15 * since 1970 (UTC). there's enough space to extend it to 8 bytes.
17 * the last two fields aren't currently used by the randnum uams.
19 * root syntax: afppasswd [-c] [-a] [-p path] [-f] [username]
20 * user syntax: afppasswd
25 #endif /* HAVE_CONFIG_H */
34 #endif /* HAVE_UNISTD_H */
36 #include <sys/types.h>
38 #include <sys/param.h>
41 #endif /* HAVE_FCNTL_H */
44 #include <netatalk/endian.h>
55 #endif /* USE_CRACKLIB */
57 #define OPT_ISROOT (1 << 0)
58 #define OPT_CREATE (1 << 1)
59 #define OPT_FORCE (1 << 2)
60 #define OPT_ADDUSER (1 << 3)
61 #define OPT_NOCRACK (1 << 4)
63 #define PASSWD_ILLEGAL '*'
65 #define FORMAT ":****************:****************:********\n"
67 #define OPTIONS "cafnu:p:"
70 #define PASSWDLEN DES_KEY_SZ
71 #define HEXPASSWDLEN (PASSWDLEN * 2)
73 static char buf[MAXPATHLEN + 1];
75 /* FIXME: preparation for i18n */
80 /* SRC and DST must not overlap. */
81 static void hexify(u_int8_t *dst, const u_int8_t *src)
85 for (i = j = 0; i < DES_KEY_SZ; i++, j += 2) {
86 static const unsigned char hextable[] = "0123456789ABCDEF";
88 dst[j] = hextable[(src[i] & 0xF0) >> 4];
89 dst[j + 1] = hextable[(src[i] & 0x0F)];
93 /* SRC and DST can overlap. */
94 #define unhex(x) (isdigit(x) ? (x) - '0' : toupper(x) + 10 - 'A')
95 static void unhexify(u_int8_t *dst, const u_int8_t *src)
99 /* convert to binary */
100 for (i = j = 0; i < HEXPASSWDLEN; i += 2, j++)
101 dst[j] = (unhex(src[i]) << 4) | unhex(src[i + 1]);
103 memset(dst + j, 0, HEXPASSWDLEN - j);
106 static u_int8_t *retrieve_key(int keyfd)
108 static u_int8_t key[HEXPASSWDLEN];
110 if (lseek(keyfd, 0, SEEK_SET) == -1)
112 if (read(keyfd, key, sizeof(key)) < sizeof(key))
120 static int decrypt_passwd(u_int8_t *dst, const u_int8_t *src, int keyfd)
125 key = retrieve_key(keyfd);
133 handle = gcry_cipher_open(GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
137 ret = gcry_cipher_setkey(handle, key, DES_KEY_SZ);
139 ret = gcry_cipher_decrypt(handle, dst, 8, src, 8);
140 gcry_cipher_close(handle);
142 fprintf(stderr, _("Decryption error: %s\n"), gcry_strerror(ret));
145 printf("pw: %s\n", buf); /* FIXME */
147 fprintf(stderr, _("Could not create crypt handle.\n"));
151 DES_key_schedule schedule;
153 DES_set_key_unchecked((DES_cblock *) key, &schedule);
154 DES_ecb_encrypt((DES_cblock *) src, (DES_cblock *) dst,
155 &schedule, DES_DECRYPT);
157 memset(&schedule, 0, sizeof(schedule));
161 memset(key, 0, HEXPASSWDLEN);
166 static int encrypt_passwd(u_int8_t *dst, const u_int8_t *src, int keyfd)
171 key = retrieve_key(keyfd);
180 handle = gcry_cipher_open(GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
182 ret = gcry_cipher_setkey(handle, key, DES_KEY_SZ);
184 ret = gcry_cipher_encrypt(handle, dst, 8, src, 0);
185 gcry_cipher_close(handle);
187 fprintf(stderr, _("Encryption error: %s\n"), gcry_strerror(ret));
191 fprintf(stderr, _("Could not create crypt handle.\n"));
195 DES_key_schedule schedule;
197 DES_set_key_unchecked((DES_cblock *) key, &schedule);
198 DES_ecb_encrypt((DES_cblock *) src, (DES_cblock *) dst,
199 &schedule, DES_ENCRYPT);
201 memset(&schedule, 0, sizeof(schedule));
208 /* this matches the code in uam_randnum.c */
209 static int update_passwd(const char *path, const char *name, int flags)
211 char password[PASSWDLEN + 1], *p, *passwd;
215 int keyfd = -1, err = 0;
217 if ((fp = fopen(path, "r+")) == NULL) {
218 fprintf(stderr, _("Can't open password file %s: %s.\n"), path, strerror(errno));
222 /* open the key file if it exists */
224 if (strlen(path) < sizeof(buf) - 5) {
226 keyfd = open(buf, O_RDONLY);
227 if (keyfd == -1 && errno != ENOENT) {
228 fprintf(stderr, _("Can't open key file %s: %s\n"), buf, strerror(errno));
235 memset(buf, 0, sizeof(buf));
236 while (fgets(buf, sizeof(buf), fp)) {
237 if ((p = strchr(buf, ':'))) {
238 /* check for a match */
239 if (strncmp(buf, name, p - buf) == 0) {
241 if (!(flags & OPT_ISROOT) && (*p == PASSWD_ILLEGAL)) {
242 fprintf(stderr, _("Your password is disabled. Please see your administrator.\n"));
250 memset(buf, 0, sizeof(buf));
254 if ((flags & OPT_ISROOT) && (flags & OPT_ADDUSER)) {
257 p = strchr(buf, ':') + 1;
258 fwrite(buf, strlen(buf), 1, fp);
260 fprintf(stderr, _("Can't find user %s in %s\n"), name, path);
266 /* need to verify against old password */
267 if ((flags & OPT_ISROOT) == 0) {
268 passwd = getpass(_("Enter OLD AFP password: "));
270 err = decrypt_passwd(p, p, keyfd);
272 memset(passwd, 0, strlen(passwd));
275 if (strncmp(passwd, p, PASSWDLEN)) {
276 memset(passwd, 0, strlen(passwd));
277 fprintf(stderr, _("Wrong password.\n"));
281 memset(passwd, 0, strlen(passwd));
285 passwd = getpass(_("Enter NEW AFP password: "));
286 memcpy(password, passwd, sizeof(password));
287 memset(passwd, 0, strlen(passwd));
288 password[PASSWDLEN] = '\0';
290 if (!(flags & OPT_NOCRACK)) {
292 if (str = FascistCheck(password, _PATH_CRACKLIB)) {
293 memset(password, 0, PASSWDLEN);
294 fprintf(stderr, _("Error: %s\n"), str);
299 #endif /* USE_CRACKLIB */
301 passwd = getpass(_("Enter NEW AFP password again: "));
302 if (strcmp(passwd, password) == 0) {
306 memset(passwd, 0, strlen(passwd));
308 err = encrypt_passwd(password, password, keyfd);
313 lock.l_type = F_WRLCK;
316 lock.l_whence = SEEK_SET;
317 fseek(fp, pos, SEEK_SET);
318 fcntl(fd, F_SETLKW, &lock);
319 fwrite(buf, p - buf + HEXPASSWDLEN, 1, fp);
320 lock.l_type = F_UNLCK;
321 fcntl(fd, F_SETLK, &lock);
322 printf(_("Updated password.\n"));
323 memset(password, 0, PASSWDLEN);
326 memset(passwd, 0, strlen(passwd));
327 memset(password, 0, PASSWDLEN);
328 fprintf(stderr, _("Passwords don't match!\n"));
340 /* creates a file with all the password entries */
341 static int create_file(const char *path, uid_t minuid)
344 int fd, len, err = 0;
347 if ((fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600)) < 0) {
348 fprintf(stderr, _("Can't create password file %s: %s\n"), path, strerror(errno));
353 while ((pwd = getpwent())) {
354 if (pwd->pw_uid < minuid)
356 /* a little paranoia */
357 if (strlen(pwd->pw_name) + FORMAT_LEN > sizeof(buf) - 1)
359 strcpy(buf, pwd->pw_name);
362 if (write(fd, buf, len) != len) {
363 fprintf(stderr, _("Problem writing to password file %s: %s\n"),
364 path, strerror(errno));
376 static void usage(void)
379 fprintf(stderr, _("Usage: afppasswd [-acfn] [-u minuid] [-p path] [username]\n"));
380 #else /* USE_CRACKLIB */
381 fprintf(stderr, _("Usage: afppasswd [-acf] [-u minuid] [-p path] [username]\n"));
382 #endif /* USE_CRACKLIB */
383 fprintf(stderr, _(" -a add a new user\n"));
384 fprintf(stderr, _(" -c create and initialize password file or specific user\n"));
385 fprintf(stderr, _(" -f force an action\n"));
387 fprintf(stderr, _(" -n disable cracklib checking of passwords\n"));
388 #endif /* USE_CRACKLIB */
389 fprintf(stderr, _(" -u uid minimum uid to use, defaults to 100\n"));
390 fprintf(stderr, _(" -p path path to afppasswd file\n"));
394 int main(int argc, char **argv)
398 uid_t uid_min = UID_START, uid;
399 char *path = _PATH_AFPDPWFILE;
405 flags = ((uid = getuid()) == 0) ? OPT_ISROOT : 0;
407 if (((flags & OPT_ISROOT) == 0) && (argc > 1)) {
412 while ((i = getopt(argc, argv, OPTIONS)) != EOF) {
414 case 'c': /* create and initialize password file or specific user */
417 case 'a': /* add a new user */
418 flags |= OPT_ADDUSER;
420 case 'f': /* force an action */
423 case 'u': /* minimum uid to use. default is 100 */
424 uid_min = atoi(optarg);
427 case 'n': /* disable CRACKLIB check */
428 flags |= OPT_NOCRACK;
430 #endif /* USE_CRACKLIB */
431 case 'p': /* path to afppasswd file */
440 if (err || (optind + ((flags & OPT_CREATE) ? 0 :
441 (flags & OPT_ISROOT)) != argc)) {
446 if (flags & OPT_CREATE) {
447 if ((flags & OPT_ISROOT) == 0) {
448 fprintf(stderr, _("Only root can create the password file.\n"));
452 if (!stat(path, &st) && ((flags & OPT_FORCE) == 0)) {
453 fprintf(stderr, _("Password file already exists.\n"));
456 return create_file(path, uid_min);
459 struct passwd *pwd = NULL;
461 if (stat(path, &st) < 0) {
462 fprintf(stderr, _("Password file %s doesn't exist.\n"), path);
466 /* if we're root, we need to specify the username */
467 pwd = (flags & OPT_ISROOT) ? getpwnam(argv[optind]) : getpwuid(uid);
469 return update_passwd(path, pwd->pw_name, flags);
471 fprintf(stderr, _("Can't get password entry.\n"));