• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500v2-V1.0.0.60_1.0.38/ap/gpl/timemachine/netatalk-2.2.0/bin/afppasswd/
1/*
2 * $Id: afppasswd.c,v 1.19 2005-04-28 20:49:19 bfernhomberg Exp $
3 *
4 * Copyright 1999 (c) Adrian Sun (asun@u.washington.edu)
5 * All Rights Reserved. See COPYRIGHT.
6 *
7 * format of the password file:
8 * name:****************:****************:********
9 *      password         last login date  failed usage count
10 *
11 * ***'s are illegal. they're just place holders for hex values. hex
12 * values that represent actual numbers are in network byte order.
13 *
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.
16 *
17 * the last two fields aren't currently used by the randnum uams.
18 *
19 * root syntax: afppasswd [-c] [-a] [-p path] [-f] [username]
20 * user syntax: afppasswd
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif /* HAVE_CONFIG_H */
26
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <errno.h>
31#ifdef HAVE_UNISTD_H
32#include <unistd.h>
33#endif /* HAVE_UNISTD_H */
34#include <ctype.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <sys/param.h>
38#ifdef HAVE_FCNTL_H
39#include <fcntl.h>
40#endif /* HAVE_FCNTL_H */
41#include <pwd.h>
42
43#include <netatalk/endian.h>
44
45#include <des.h>
46
47#ifdef USE_CRACKLIB
48#include <crack.h>
49#endif /* USE_CRACKLIB */
50
51#define OPT_ISROOT  (1 << 0)
52#define OPT_CREATE  (1 << 1)
53#define OPT_FORCE   (1 << 2)
54#define OPT_ADDUSER (1 << 3)
55#define OPT_NOCRACK (1 << 4)
56
57#define PASSWD_ILLEGAL '*'
58
59#define FORMAT  ":****************:****************:********\n"
60#define FORMAT_LEN 44
61#define OPTIONS "cafnu:p:"
62#define UID_START 100
63
64#define HEXPASSWDLEN 16
65#define PASSWDLEN 8
66
67static char buf[MAXPATHLEN + 1];
68
69/* if newpwd is null, convert buf from hex to binary. if newpwd isn't
70 * null, convert newpwd to hex and save it in buf. */
71#define unhex(x)  (isdigit(x) ? (x) - '0' : toupper(x) + 10 - 'A')
72static void convert_passwd(char *buf, char *newpwd, const int keyfd)
73{
74  u_int8_t key[HEXPASSWDLEN];
75  Key_schedule schedule;
76  unsigned int i, j;
77
78  if (!newpwd) {
79    /* convert to binary */
80    for (i = j = 0; i < sizeof(key); i += 2, j++)
81      buf[j] = (unhex(buf[i]) << 4) | unhex(buf[i + 1]);
82    if (j <= DES_KEY_SZ)
83      memset(buf + j, 0, sizeof(key) - j);
84  }
85
86  if (keyfd > -1) {
87    lseek(keyfd, 0, SEEK_SET);
88    read(keyfd, key, sizeof(key));
89    /* convert to binary */
90    for (i = j = 0; i < sizeof(key); i += 2, j++)
91      key[j] = (unhex(key[i]) << 4) | unhex(key[i + 1]);
92    if (j <= DES_KEY_SZ)
93      memset(key + j, 0, sizeof(key) - j);
94    key_sched((C_Block *) key, schedule);
95    memset(key, 0, sizeof(key));
96    if (newpwd) {
97	ecb_encrypt((C_Block *) newpwd, (C_Block *) newpwd, schedule,
98		    DES_ENCRYPT);
99    } else {
100      /* decrypt the password */
101      ecb_encrypt((C_Block *) buf, (C_Block *) buf, schedule, DES_DECRYPT);
102    }
103    memset(&schedule, 0, sizeof(schedule));
104  }
105
106  if (newpwd) {
107    const unsigned char hextable[] = "0123456789ABCDEF";
108
109    /* convert to hex */
110    for (i = j = 0; i < DES_KEY_SZ; i++, j += 2) {
111      buf[j] = hextable[(newpwd[i] & 0xF0) >> 4];
112      buf[j + 1] = hextable[newpwd[i] & 0x0F];
113    }
114  }
115}
116
117/* this matches the code in uam_randnum.c */
118static int update_passwd(const char *path, const char *name, int flags)
119{
120  char password[PASSWDLEN + 1], *p, *passwd;
121  FILE *fp;
122  off_t pos;
123  int keyfd = -1, err = 0;
124
125  if ((fp = fopen(path, "r+")) == NULL) {
126    fprintf(stderr, "afppasswd: can't open %s\n", path);
127    return -1;
128  }
129
130  /* open the key file if it exists */
131  strcpy(buf, path);
132  if (strlen(path) < sizeof(buf) - 5) {
133    strcat(buf, ".key");
134    keyfd = open(buf, O_RDONLY);
135  }
136
137  pos = ftell(fp);
138  memset(buf, 0, sizeof(buf));
139  while (fgets(buf, sizeof(buf), fp)) {
140    if ((p = strchr(buf, ':'))) {
141      /* check for a match */
142      if (strlen(name) == (p - buf) &&
143          strncmp(buf, name, p - buf) == 0) {
144	p++;
145	if (!(flags & OPT_ISROOT) && (*p == PASSWD_ILLEGAL)) {
146	  fprintf(stderr, "Your password is disabled. Please see your administrator.\n");
147	  break;
148	}
149	goto found_entry;
150      }
151    }
152    pos = ftell(fp);
153    memset(buf, 0, sizeof(buf));
154  }
155
156  if (flags & OPT_ADDUSER) {
157    strcpy(buf, name);
158    strcat(buf, FORMAT);
159    p = strchr(buf, ':') + 1;
160    fwrite(buf, strlen(buf), 1, fp);
161  } else {
162    fprintf(stderr, "afppasswd: can't find %s in %s\n", name, path);
163    err = -1;
164    goto update_done;
165  }
166
167found_entry:
168  /* need to verify against old password */
169  if ((flags & OPT_ISROOT) == 0) {
170    passwd = getpass("Enter OLD AFP password: ");
171    convert_passwd(p, NULL, keyfd);
172    if (strncmp(passwd, p, PASSWDLEN)) {
173      fprintf(stderr, "afppasswd: invalid password.\n");
174      err = -1;
175      goto update_done;
176    }
177  }
178
179  /* new password */
180  passwd = getpass("Enter NEW AFP password: ");
181  memcpy(password, passwd, sizeof(password));
182  password[PASSWDLEN] = '\0';
183#ifdef USE_CRACKLIB
184  if (!(flags & OPT_NOCRACK)) {
185    if (passwd = FascistCheck(password, _PATH_CRACKLIB)) {
186        fprintf(stderr, "Error: %s\n", passwd);
187        err = -1;
188        goto update_done;
189    }
190  }
191#endif /* USE_CRACKLIB */
192
193  passwd = getpass("Enter NEW AFP password again: ");
194  if (strcmp(passwd, password) == 0) {
195     struct flock lock;
196     int fd = fileno(fp);
197
198     convert_passwd(p, password, keyfd);
199     lock.l_type = F_WRLCK;
200     lock.l_start = pos;
201     lock.l_len = 1;
202     lock.l_whence = SEEK_SET;
203     fseek(fp, pos, SEEK_SET);
204     fcntl(fd, F_SETLKW, &lock);
205     fwrite(buf, p - buf + HEXPASSWDLEN, 1, fp);
206     lock.l_type = F_UNLCK;
207     fcntl(fd, F_SETLK, &lock);
208     printf("afppasswd: updated password.\n");
209
210  } else {
211    fprintf(stderr, "afppasswd: passwords don't match!\n");
212    err = -1;
213  }
214
215update_done:
216  if (keyfd > -1)
217    close(keyfd);
218  fclose(fp);
219  return err;
220}
221
222
223/* creates a file with all the password entries */
224static int create_file(const char *path, uid_t minuid)
225{
226  struct passwd *pwd;
227  int fd, len, err = 0;
228
229
230  if ((fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600)) < 0) {
231    fprintf(stderr, "afppasswd: can't create %s\n", path);
232    return -1;
233  }
234
235  setpwent();
236  while ((pwd = getpwent())) {
237    if (pwd->pw_uid < minuid)
238      continue;
239    /* a little paranoia */
240    if (strlen(pwd->pw_name) + FORMAT_LEN > sizeof(buf) - 1)
241      continue;
242    strcpy(buf, pwd->pw_name);
243    strcat(buf, FORMAT);
244    len = strlen(buf);
245    if (write(fd, buf, len) != len) {
246      fprintf(stderr, "afppasswd: problem writing to %s: %s\n", path,
247	      strerror(errno));
248      err = -1;
249      break;
250    }
251  }
252  endpwent();
253  close(fd);
254
255  return err;
256}
257
258
259int main(int argc, char **argv)
260{
261  struct stat st;
262  int flags;
263  uid_t uid_min = UID_START, uid;
264  char *path = _PATH_AFPDPWFILE;
265  int i, err = 0;
266
267  extern char *optarg;
268  extern int optind;
269
270  flags = ((uid = getuid()) == 0) ? OPT_ISROOT : 0;
271
272  if (((flags & OPT_ISROOT) == 0) && (argc > 1)) {
273    fprintf(stderr, "Usage: afppasswd [-acfn] [-u minuid] [-p path] [username]\n");
274    fprintf(stderr, "  -a        add a new user\n");
275    fprintf(stderr, "  -c        create and initialize password file or specific user\n");
276    fprintf(stderr, "  -f        force an action\n");
277#ifdef USE_CRACKLIB
278    fprintf(stderr, "  -n        disable cracklib checking of passwords\n");
279#endif /* USE_CRACKLIB */
280    fprintf(stderr, "  -u uid    minimum uid to use, defaults to 100\n");
281    fprintf(stderr, "  -p path   path to afppasswd file\n");
282    return -1;
283  }
284
285  while ((i = getopt(argc, argv, OPTIONS)) != EOF) {
286    switch (i) {
287    case 'c': /* create and initialize password file or specific user */
288      flags |= OPT_CREATE;
289      break;
290    case 'a': /* add a new user */
291      flags |= OPT_ADDUSER;
292      break;
293    case 'f': /* force an action */
294      flags |= OPT_FORCE;
295      break;
296    case 'u':  /* minimum uid to use. default is 100 */
297      uid_min = atoi(optarg);
298      break;
299#ifdef USE_CRACKLIB
300    case 'n': /* disable CRACKLIB check */
301      flags |= OPT_NOCRACK;
302      break;
303#endif /* USE_CRACKLIB */
304    case 'p': /* path to afppasswd file */
305      path = optarg;
306      break;
307    default:
308      err++;
309      break;
310    }
311  }
312
313  if (err || (optind + ((flags & OPT_CREATE) ? 0 :
314			(flags & OPT_ISROOT)) != argc)) {
315#ifdef USE_CRACKLIB
316    fprintf(stderr, "Usage: afppasswd [-acfn] [-u minuid] [-p path] [username]\n");
317#else /* USE_CRACKLIB */
318    fprintf(stderr, "Usage: afppasswd [-acf] [-u minuid] [-p path] [username]\n");
319#endif /* USE_CRACKLIB */
320    fprintf(stderr, "  -a        add a new user\n");
321    fprintf(stderr, "  -c        create and initialize password file or specific user\n");
322    fprintf(stderr, "  -f        force an action\n");
323#ifdef USE_CRACKLIB
324    fprintf(stderr, "  -n        disable cracklib checking of passwords\n");
325#endif /* USE_CRACKLIB */
326    fprintf(stderr, "  -u uid    minimum uid to use, defaults to 100\n");
327    fprintf(stderr, "  -p path   path to afppasswd file\n");
328    return -1;
329  }
330
331  i = stat(path, &st);
332  if (flags & OPT_CREATE) {
333    if ((flags & OPT_ISROOT) == 0) {
334      fprintf(stderr, "afppasswd: only root can create the password file.\n");
335      return -1;
336    }
337
338    if (!i && ((flags & OPT_FORCE) == 0)) {
339      fprintf(stderr, "afppasswd: password file already exists.\n");
340      return -1;
341    }
342    return create_file(path, uid_min);
343
344  } else {
345    struct passwd *pwd = NULL;
346
347    if (i < 0) {
348      fprintf(stderr, "afppasswd: %s doesn't exist.\n", path);
349      return -1;
350    }
351
352    /* if we're root, we need to specify the username */
353    pwd = (flags & OPT_ISROOT) ? getpwnam(argv[optind]) : getpwuid(uid);
354    if (pwd)
355      return update_passwd(path, pwd->pw_name, flags);
356
357    fprintf(stderr, "afppasswd: can't get password entry.\n");
358    return -1;
359  }
360}
361