add chaos_calmer branch
[15.05/openwrt.git] / package / network / services / ead / src / tinysrp / tphrase.c
1 /* Add passphrases to the tpasswd file.  Use the last entry in the config
2 file 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
16 char *Progname;
17 char Usage[] = "usage: %s [-n configindex] [-p passfile] user\n";
18 #define USAGE() fprintf(stderr, Usage, Progname)
19
20 void doit(char *);
21
22 int Configindex = -1;
23 char *Passfile = DEFAULT_PASSWD;
24
25 int 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
61 void 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 )
122 t_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 * )
196 t_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
257 int
258 t_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 * )
284 t_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 )
343 t_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