1/* Add passphrases to the tpasswd file.  Use the last entry in the config
2file by default or a particular one specified by index. */
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <unistd.h>
8#include <sys/types.h>
9#include <sys/stat.h>
10#include "config.h"
11#include "t_pwd.h"
12#include "t_read.h"
13#include "t_sha.h"
14#include "t_defines.h"
15
16char *Progname;
17char Usage[] = "usage: %s [-n configindex] [-p passfile] user\n";
18#define USAGE() fprintf(stderr, Usage, Progname)
19
20void doit(char *);
21
22int Configindex = -1;
23char *Passfile = DEFAULT_PASSWD;
24
25int main(int argc, char **argv)
26{
27	int c;
28
29	Progname = *argv;
30
31	/* Parse option arguments. */
32
33	while ((c = getopt(argc, argv, "n:p:")) != EOF) {
34		switch (c) {
35
36		case 'n':
37			Configindex = atoi(optarg);
38			break;
39
40		case 'p':
41			Passfile = optarg;
42			break;
43
44		default:
45			USAGE();
46			exit(1);
47		}
48	}
49	argc -= optind;
50	argv += optind;
51
52	if (argc != 1) {
53		USAGE();
54		exit(1);
55	}
56	doit(argv[0]);
57
58	return 0;
59}
60
61void doit(char *name)
62{
63	char passphrase[128], passphrase1[128];
64	FILE *f;
65	struct t_confent *tcent;
66	struct t_pw eps_passwd;
67
68	/* Get the config entry. */
69
70	if (Configindex <= 0) {
71		Configindex = t_getprecount();
72	}
73	tcent = gettcid(Configindex);
74	if (tcent == NULL) {
75		fprintf(stderr, "Invalid configuration file entry.\n");
76		exit(1);
77	}
78
79	/* Ask for the passphrase twice. */
80
81	printf("Setting passphrase for %s\n", name);
82
83	if (t_getpass(passphrase, sizeof(passphrase), "Enter passphrase: ") < 0) {
84		exit(1);
85	}
86	if (t_getpass(passphrase1, sizeof(passphrase1), "Verify: ") < 0) {
87		exit(1);
88	}
89	if (strcmp(passphrase, passphrase1) != 0) {
90		fprintf(stderr, "mismatch\n");
91		exit(1);
92	}
93
94	/* Create the passphrase verifier. */
95
96	t_makepwent(&eps_passwd, name, passphrase, NULL, tcent);
97
98	/* Don't need these anymore. */
99
100	memset(passphrase, 0, sizeof(passphrase));
101	memset(passphrase1, 0, sizeof(passphrase1));
102
103	/* See if the passphrase file is there; create it if not. */
104
105	if ((f = fopen(Passfile, "r+")) == NULL) {
106		creat(Passfile, 0400);
107	} else {
108		fclose(f);
109	}
110
111	/* Change the passphrase. */
112
113	if (t_changepw(Passfile, &eps_passwd.pebuf) < 0) {
114		fprintf(stderr, "Error changing passphrase\n");
115		exit(1);
116	}
117}
118
119/* TODO: Implement a more general method to handle delete/change */
120
121_TYPE( int )
122t_changepw(pwname, diff)
123     const char * pwname;
124     const struct t_pwent * diff;
125{
126  char * bakfile;
127  char * bakfile2;
128  struct stat st;
129  FILE * passfp;
130  FILE * bakfp;
131
132  if(pwname == NULL)
133    pwname = DEFAULT_PASSWD;
134
135  if((passfp = fopen(pwname, "rb")) == NULL || fstat(fileno(passfp), &st) < 0)
136    return -1;
137
138  if((bakfile = malloc(strlen(pwname) + 5)) == NULL) {
139    fclose(passfp);
140    return -1;
141  }
142  else if((bakfile2 = malloc(strlen(pwname) + 5)) == NULL) {
143    fclose(passfp);
144    free(bakfile);
145    return -1;
146  }
147
148  sprintf(bakfile, "%s.bak", pwname);
149  sprintf(bakfile2, "%s.sav", pwname);
150
151  if((bakfp = fopen(bakfile2, "wb")) == NULL &&
152     (unlink(bakfile2) < 0 || (bakfp = fopen(bakfile2, "wb")) == NULL)) {
153    fclose(passfp);
154    free(bakfile);
155    free(bakfile2);
156    return -1;
157  }
158
159#ifdef NO_FCHMOD
160  chmod(bakfile2, st.st_mode & 0777);
161#else
162  fchmod(fileno(bakfp), st.st_mode & 0777);
163#endif
164
165  t_pwcopy(bakfp, passfp, diff);
166
167  fclose(bakfp);
168  fclose(passfp);
169
170#ifdef USE_RENAME
171  unlink(bakfile);
172  if(rename(pwname, bakfile) < 0) {
173    free(bakfile);
174    free(bakfile2);
175    return -1;
176  }
177  if(rename(bakfile2, pwname) < 0) {
178    free(bakfile);
179    free(bakfile2);
180    return -1;
181  }
182#else
183  unlink(bakfile);
184  link(pwname, bakfile);
185  unlink(pwname);
186  link(bakfile2, pwname);
187  unlink(bakfile2);
188#endif
189  free(bakfile);
190  free(bakfile2);
191
192  return 0;
193}
194
195_TYPE( struct t_pwent * )
196t_makepwent(tpw, user, pass, salt, confent)
197     struct t_pw * tpw;
198     const char * user;
199     const char * pass;
200     const struct t_num * salt;
201     const struct t_confent * confent;
202{
203  BigInteger x, v, n, g;
204  unsigned char dig[SHA_DIGESTSIZE];
205  SHA1_CTX ctxt;
206
207  tpw->pebuf.name = tpw->userbuf;
208  tpw->pebuf.password.data = tpw->pwbuf;
209  tpw->pebuf.salt.data = tpw->saltbuf;
210
211  strncpy(tpw->pebuf.name, user, MAXUSERLEN);
212  tpw->pebuf.index = confent->index;
213
214  if(salt) {
215    tpw->pebuf.salt.len = salt->len;
216    memcpy(tpw->pebuf.salt.data, salt->data, salt->len);
217  }
218  else {
219    memset(dig, 0, SALTLEN);            /* salt is 80 bits */
220    tpw->pebuf.salt.len = SALTLEN;
221    do {
222      t_random(tpw->pebuf.salt.data, SALTLEN);
223    } while(memcmp(tpw->pebuf.salt.data, dig, SALTLEN) == 0);
224    if(tpw->pebuf.salt.data[0] == 0)
225      tpw->pebuf.salt.data[0] = 0xff;
226  }
227
228  n = BigIntegerFromBytes(confent->modulus.data, confent->modulus.len);
229  g = BigIntegerFromBytes(confent->generator.data, confent->generator.len);
230  v = BigIntegerFromInt(0);
231
232  SHA1Init(&ctxt);
233  SHA1Update(&ctxt, user, strlen(user));
234  SHA1Update(&ctxt, ":", 1);
235  SHA1Update(&ctxt, pass, strlen(pass));
236  SHA1Final(dig, &ctxt);
237
238  SHA1Init(&ctxt);
239  SHA1Update(&ctxt, tpw->pebuf.salt.data, tpw->pebuf.salt.len);
240  SHA1Update(&ctxt, dig, sizeof(dig));
241  SHA1Final(dig, &ctxt);
242
243  /* x = H(s, H(u, ':', p)) */
244  x = BigIntegerFromBytes(dig, sizeof(dig));
245
246  BigIntegerModExp(v, g, x, n);
247  tpw->pebuf.password.len = BigIntegerToBytes(v, tpw->pebuf.password.data);
248
249  BigIntegerFree(v);
250  BigIntegerFree(x);
251  BigIntegerFree(g);
252  BigIntegerFree(n);
253
254  return &tpw->pebuf;
255}
256
257int
258t_pwcopy(pwdest, pwsrc, diff)
259     FILE * pwdest;
260     FILE * pwsrc;
261     struct t_pwent * diff;
262{
263  struct t_pw * src;
264  struct t_pwent * ent;
265
266  if((src = t_openpw(pwsrc)) == NULL)
267    return -1;
268
269  while((ent = t_getpwent(src)) != NULL)
270    if(diff && strcmp(diff->name, ent->name) == 0) {
271      t_putpwent(diff, pwdest);
272      diff = NULL;
273    }
274    else
275      t_putpwent(ent, pwdest);
276
277  if(diff)
278    t_putpwent(diff, pwdest);
279
280  return 0;
281}
282
283_TYPE( struct t_pwent * )
284t_getpwent(tpw)
285     struct t_pw * tpw;
286{
287  char indexbuf[16];
288  char passbuf[MAXB64PARAMLEN];
289  char saltstr[MAXB64SALTLEN];
290
291#ifdef ENABLE_YP
292  struct t_passwd * nisent;
293  /* FIXME: should tell caller to get conf entry from NIS also */
294
295  if(tpw->state == IN_NIS) {
296    nisent = _yp_gettpent();
297    if(nisent != NULL) {
298      savepwent(tpw, &nisent->tp);
299      return &tpw->pebuf;
300    }
301    tpw->state = FILE_NIS;
302  }
303#endif
304
305  while(1) {
306    if(t_nextfield(tpw->instream, tpw->userbuf, MAXUSERLEN) > 0) {
307#ifdef ENABLE_YP
308      if(tpw->state == FILE_NIS && *tpw->userbuf == '+') {
309	t_nextline(tpw->instream);
310	if(strlen(tpw->userbuf) > 1) {  /* +name:... */
311	  nisent = _yp_gettpnam(tpw->userbuf + 1);
312	  if(nisent != NULL) {
313	    savepwent(tpw, nisent);
314	    return &tpw->pebuf;
315	  }
316	}
317	else {  /* +:... */
318	  tpw->state = IN_NIS;
319	  _yp_settpent();
320	  return t_getpwent(tpw);
321	}
322      }
323#endif
324      if(t_nextfield(tpw->instream, passbuf, MAXB64PARAMLEN) > 0 &&
325	 (tpw->pebuf.password.len = t_fromb64(tpw->pwbuf, passbuf)) > 0 &&
326	 t_nextfield(tpw->instream, saltstr, MAXB64SALTLEN) > 0 &&
327	 (tpw->pebuf.salt.len = t_fromb64(tpw->saltbuf, saltstr)) > 0 &&
328	 t_nextfield(tpw->instream, indexbuf, 16) > 0 &&
329	 (tpw->pebuf.index = atoi(indexbuf)) > 0) {
330	tpw->pebuf.name = tpw->userbuf;
331	tpw->pebuf.password.data = tpw->pwbuf;
332	tpw->pebuf.salt.data = tpw->saltbuf;
333	t_nextline(tpw->instream);
334	return &tpw->pebuf;
335      }
336    }
337    if(t_nextline(tpw->instream) < 0)
338      return NULL;
339  }
340}
341
342_TYPE( void )
343t_putpwent(ent, fp)
344     const struct t_pwent * ent;
345     FILE * fp;
346{
347  char strbuf[MAXB64PARAMLEN];
348  char saltbuf[MAXB64SALTLEN];
349
350  fprintf(fp, "%s:%s:%s:%d\n", ent->name,
351	  t_tob64(strbuf, ent->password.data, ent->password.len),
352	  t_tob64(saltbuf, ent->salt.data, ent->salt.len), ent->index);
353}
354
355