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