2 * $Id: afppasswd.c,v 1.8 2001-09-06 20:00:59 rufustfirefly 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 */
30 #else /* STDC_HEADERS */
34 #endif /* HAVE_STRCHR */
35 char *strchr (), *strrchr ();
37 #define memcpy(d,s,n) bcopy ((s), (d), (n))
38 #define memmove(d,s,n) bcopy ((s), (d), (n))
39 #endif /* ! HAVE_MEMCPY */
40 #endif /* STDC_HEADERS */
46 #endif /* HAVE_UNISTD_H */
48 #include <sys/types.h>
50 #include <sys/param.h>
53 #endif /* HAVE_FCNTL_H */
56 #include <netatalk/endian.h>
63 #endif /* USE_CRACKLIB */
65 #define OPT_ISROOT (1 << 0)
66 #define OPT_CREATE (1 << 1)
67 #define OPT_FORCE (1 << 2)
68 #define OPT_ADDUSER (1 << 3)
69 #define OPT_NOCRACK (1 << 4)
71 #define PASSWD_ILLEGAL '*'
73 #define FORMAT ":****************:****************:********\n"
75 #define OPTIONS "cafnu:p:"
78 #define HEXPASSWDLEN 16
81 static char buf[MAXPATHLEN + 1];
83 /* if newpwd is null, convert buf from hex to binary. if newpwd isn't
84 * null, convert newpwd to hex and save it in buf. */
85 #define unhex(x) (isdigit(x) ? (x) - '0' : toupper(x) + 10 - 'A')
86 static void convert_passwd(char *buf, char *newpwd, const int keyfd)
88 u_int8_t key[HEXPASSWDLEN];
89 Key_schedule schedule;
93 /* convert to binary */
94 for (i = j = 0; i < sizeof(key); i += 2, j++)
95 buf[j] = (unhex(buf[i]) << 4) | unhex(buf[i + 1]);
97 memset(buf + j, 0, sizeof(key) - j);
101 lseek(keyfd, 0, SEEK_SET);
102 read(keyfd, key, sizeof(key));
103 /* convert to binary */
104 for (i = j = 0; i < sizeof(key); i += 2, j++)
105 key[j] = (unhex(key[i]) << 4) | unhex(key[i + 1]);
107 memset(key + j, 0, sizeof(key) - j);
108 key_sched((C_Block *) key, schedule);
109 memset(key, 0, sizeof(key));
111 ecb_encrypt((C_Block *) newpwd, (C_Block *) newpwd, schedule,
114 /* decrypt the password */
115 ecb_encrypt((C_Block *) buf, (C_Block *) buf, schedule, DES_DECRYPT);
117 memset(schedule, 0, sizeof(schedule));
121 const unsigned char hextable[] = "0123456789ABCDEF";
124 for (i = j = 0; i < DES_KEY_SZ; i++, j += 2) {
125 buf[j] = hextable[(newpwd[i] & 0xF0) >> 4];
126 buf[j + 1] = hextable[newpwd[i] & 0x0F];
131 /* this matches the code in uam_randnum.c */
132 static int update_passwd(const char *path, const char *name, int flags)
134 char password[PASSWDLEN + 1], *p, *passwd;
137 int keyfd = -1, err = 0;
139 if ((fp = fopen(path, "r+")) == NULL) {
140 fprintf(stderr, "afppasswd: can't open %s\n", path);
144 /* open the key file if it exists */
146 if (strlen(path) < sizeof(buf) - 5) {
148 keyfd = open(buf, O_RDONLY);
152 memset(buf, 0, sizeof(buf));
153 while (fgets(buf, sizeof(buf), fp)) {
154 if ((p = strchr(buf, ':'))) {
155 /* check for a match */
156 if (strncmp(buf, name, p - buf) == 0) {
158 if (!(flags & OPT_ISROOT) && (*p == PASSWD_ILLEGAL)) {
159 fprintf(stderr, "Your password is disabled. Please see your administrator.\n");
166 memset(buf, 0, sizeof(buf));
169 if (flags & OPT_ADDUSER) {
172 p = strchr(buf, ':') + 1;
173 fwrite(buf, strlen(buf), 1, fp);
175 fprintf(stderr, "afppasswd: can't find %s in %s\n", name, path);
181 /* need to verify against old password */
182 if ((flags & OPT_ISROOT) == 0) {
183 passwd = getpass("Enter OLD AFP password: ");
184 convert_passwd(p, NULL, keyfd);
185 if (strncmp(passwd, p, PASSWDLEN)) {
186 fprintf(stderr, "afppasswd: invalid password.\n");
193 passwd = getpass("Enter NEW AFP password: ");
194 memcpy(password, passwd, sizeof(password));
195 password[PASSWDLEN] = '\0';
197 if (!(flags & OPT_NOCRACK)) {
198 if (passwd = FascistCheck(password, _PATH_CRACKLIB)) {
199 fprintf(stderr, "Error: %s\n", passwd);
204 #endif /* USE_CRACKLIB */
206 passwd = getpass("Enter NEW AFP password again: ");
207 if (strcmp(passwd, password) == 0) {
211 convert_passwd(p, password, keyfd);
212 lock.l_type = F_WRLCK;
215 lock.l_whence = SEEK_SET;
216 fseek(fp, pos, SEEK_SET);
217 fcntl(fd, F_SETLKW, &lock);
218 fwrite(buf, p - buf + HEXPASSWDLEN, 1, fp);
219 lock.l_type = F_UNLCK;
220 fcntl(fd, F_SETLK, &lock);
221 printf("afppasswd: updated password.\n");
224 fprintf(stderr, "afppasswd: passwords don't match!\n");
236 /* creates a file with all the password entries */
237 static int create_file(const char *path, uid_t minuid)
240 int fd, len, err = 0;
243 if ((fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600)) < 0) {
244 fprintf(stderr, "afppasswd: can't create %s\n", path);
249 while ((pwd = getpwent())) {
250 if (pwd->pw_uid < minuid)
252 /* a little paranoia */
253 if (strlen(pwd->pw_name) + FORMAT_LEN > sizeof(buf) - 1)
255 strcpy(buf, pwd->pw_name);
258 if (write(fd, buf, len) != len) {
259 fprintf(stderr, "afppasswd: problem writing to %s: %m\n", path);
271 int main(int argc, char **argv)
275 uid_t uid_min = UID_START, uid;
276 char *path = _PATH_AFPDPWFILE;
282 flags = ((uid = getuid()) == 0) ? OPT_ISROOT : 0;
284 if (((flags & OPT_ISROOT) == 0) && (argc > 1)) {
285 fprintf(stderr, "Usage: afppasswd [-acfn] [-u minuid] [-p path] [username]\n");
286 fprintf(stderr, " -a add a new user\n");
287 fprintf(stderr, " -c create and initialize password file or specific user\n");
288 fprintf(stderr, " -f force an action\n");
290 fprintf(stderr, " -n disable cracklib checking of passwords\n");
291 #endif /* USE_CRACKLIB */
292 fprintf(stderr, " -u uid minimum uid to use, defaults to 100\n");
293 fprintf(stderr, " -p path path to afppasswd file\n");
297 while ((i = getopt(argc, argv, OPTIONS)) != EOF) {
299 case 'c': /* create and initialize password file or specific user */
302 case 'a': /* add a new user */
303 flags |= OPT_ADDUSER;
305 case 'f': /* force an action */
308 case 'u': /* minimum uid to use. default is 100 */
309 uid_min = atoi(optarg);
312 case 'n': /* disable CRACKLIB check */
313 flags |= OPT_NOCRACK;
315 #endif /* USE_CRACKLIB */
316 case 'p': /* path to afppasswd file */
325 if (err || (optind + ((flags & OPT_CREATE) ? 0 :
326 (flags & OPT_ISROOT)) != argc)) {
328 fprintf(stderr, "Usage: afppasswd [-acfn] [-u minuid] [-p path] [username]\n");
329 #else /* USE_CRACKLIB */
330 fprintf(stderr, "Usage: afppasswd [-acf] [-u minuid] [-p path] [username]\n");
331 #endif /* USE_CRACKLIB */
332 fprintf(stderr, " -a add a new user\n");
333 fprintf(stderr, " -c create and initialize password file or specific user\n");
334 fprintf(stderr, " -f force an action\n");
336 fprintf(stderr, " -n disable cracklib checking of passwords\n");
337 #endif /* USE_CRACKLIB */
338 fprintf(stderr, " -u uid minimum uid to use, defaults to 100\n");
339 fprintf(stderr, " -p path path to afppasswd file\n");
344 if (flags & OPT_CREATE) {
345 if ((flags & OPT_ISROOT) == 0) {
346 fprintf(stderr, "afppasswd: only root can create the password file.\n");
350 if (!i && ((flags & OPT_FORCE) == 0)) {
351 fprintf(stderr, "afppasswd: password file already exists.\n");
354 return create_file(path, uid_min);
357 struct passwd *pwd = NULL;
360 fprintf(stderr, "afppasswd: %s doesn't exist.\n", path);
364 /* if we're root, we need to specify the username */
365 pwd = (flags & OPT_ISROOT) ? getpwnam(argv[optind]) : getpwuid(uid);
367 return update_passwd(path, pwd->pw_name, flags);
369 fprintf(stderr, "afppasswd: can't get password entry.\n");
373 #else /* UAM_RNDNUM */
375 main(int argc, char **argv)
377 fprintf(stderr, "afppasswd is only useful if you're using centralized passwords\n");
378 fprintf(stderr, "for the Random Number authentication methods.\n");
382 #endif /* UAM_RNDNUM */