Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / crypto / kerberosIV / kadmin / ksrvutil.c
1 /* 
2   Copyright (C) 1989 by the Massachusetts Institute of Technology
3
4    Export of this software from the United States of America is assumed
5    to require a specific license from the United States Government.
6    It is the responsibility of any person or organization contemplating
7    export to obtain such a license before exporting.
8
9 WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
10 distribute this software and its documentation for any purpose and
11 without fee is hereby granted, provided that the above copyright
12 notice appear in all copies and that both that copyright notice and
13 this permission notice appear in supporting documentation, and that
14 the name of M.I.T. not be used in advertising or publicity pertaining
15 to distribution of the software without specific, written prior
16 permission.  M.I.T. makes no representations about the suitability of
17 this software for any purpose.  It is provided "as is" without express
18 or implied warranty.
19
20   */
21 /* $FreeBSD: src/crypto/kerberosIV/kadmin/ksrvutil.c,v 1.1.1.3.2.1 2003/02/14 22:37:37 nectar Exp $ */
22 /* $DragonFly: src/crypto/kerberosIV/kadmin/Attic/ksrvutil.c,v 1.2 2003/06/17 04:24:36 dillon Exp $ */
23
24 /*
25  * list and update contents of srvtab files
26  */
27
28 /*
29  * ksrvutil
30  * list and update the contents of srvtab files
31  */
32
33 #include "kadm_locl.h"
34
35 RCSID("$Id: ksrvutil.c,v 1.50 1999/11/13 06:33:59 assar Exp $");
36
37 #include "ksrvutil.h"
38
39 #ifdef NOENCRYPTION
40 #define read_long_pw_string placebo_read_pw_string
41 #else /* NOENCRYPTION */
42 #define read_long_pw_string des_read_pw_string
43 #endif /* NOENCRYPTION */
44
45 #define SRVTAB_MODE 0600        /* rw------- */
46 #define PAD "  "
47 #define VNO_HEADER "Version"
48 #define VNO_FORMAT "%4d   "
49 #define KEY_HEADER "       Key       " /* 17 characters long */
50 #define PRINC_HEADER "  Principal\n"
51 #define PRINC_FORMAT "%s"
52
53 char u_name[ANAME_SZ];
54 char u_inst[INST_SZ];
55 char u_realm[REALM_SZ];
56
57 int destroyp = FALSE;           /* Should the ticket file be destroyed? */
58
59 static unsigned short
60 get_mode(char *filename)
61 {
62     struct stat statbuf;
63     unsigned short mode;
64
65     memset(&statbuf, 0, sizeof(statbuf));
66     
67     if (stat(filename, &statbuf) < 0) 
68         mode = SRVTAB_MODE;
69     else
70         mode = statbuf.st_mode;
71
72     return(mode);
73 }
74
75 static void
76 copy_keyfile(char *keyfile, char *backup_keyfile)
77 {
78     int keyfile_fd;
79     int backup_keyfile_fd;
80     int keyfile_mode;
81     char buf[BUFSIZ];           /* for copying keyfiles */
82     int rcount;                 /* for copying keyfiles */
83     int try_again;
84     
85     memset(buf, 0, sizeof(buf));
86     
87     do {
88         try_again = FALSE;
89         if ((keyfile_fd = open(keyfile, O_RDONLY, 0)) < 0) {
90             if (errno != ENOENT)
91               err (1, "open %s", keyfile);
92             else {
93                 try_again = TRUE;
94                 if ((keyfile_fd = 
95                      open(keyfile, 
96                           O_WRONLY | O_TRUNC | O_CREAT, SRVTAB_MODE)) < 0)
97                   err(1, "create %s", keyfile);
98                 else
99                     if (close(keyfile_fd) < 0)
100                       err (1, "close %s", keyfile);
101             }
102         }
103     } while(try_again);
104
105     keyfile_mode = get_mode(keyfile);
106
107     if ((backup_keyfile_fd = 
108          open(backup_keyfile, O_WRONLY | O_TRUNC | O_CREAT, 
109               keyfile_mode)) < 0)
110         err (1, "open %s", backup_keyfile);
111     do {
112         if ((rcount = read(keyfile_fd, buf, sizeof(buf))) < 0)
113             err (1, "read %s", keyfile);
114         if (rcount && (write(backup_keyfile_fd, buf, rcount) != rcount))
115             err (1, "write %s", backup_keyfile);
116     } while (rcount);
117     if (close(backup_keyfile_fd) < 0)
118         err(1, "close %s", backup_keyfile);
119     if (close(keyfile_fd) < 0)
120         err(1, "close %s", keyfile);
121 }
122
123 void
124 leave(char *str, int x)
125 {
126     if (str)
127         fprintf(stderr, "%s\n", str);
128     if (destroyp)
129          dest_tkt();
130     exit(x);
131 }
132
133 void
134 safe_read_stdin(char *prompt, char *buf, size_t size)
135 {
136     printf("%s", prompt);
137     fflush(stdout);
138     memset(buf, 0, size);
139     if (read(0, buf, size - 1) < 0) {
140         warn("read stdin");
141         leave(NULL, 1);
142     }
143     buf[strlen(buf)-1] = 0;
144 }
145
146 void
147 safe_write(char *filename, int fd, void *buf, size_t len)
148 {
149     if (write(fd, buf, len) != len) {
150         warn("write %s", filename);
151         close(fd);
152         leave("In progress srvtab in this file.", 1);
153     }
154 }
155
156 static int
157 yes_no(char *string, int dflt)
158 {
159   char ynbuf[5];
160   
161   printf("%s (y,n) [%c]", string, dflt?'y':'n');
162   for (;;) {
163     safe_read_stdin("", ynbuf, sizeof(ynbuf));
164     
165     if ((ynbuf[0] == 'n') || (ynbuf[0] == 'N'))
166       return(0);
167     else if ((ynbuf[0] == 'y') || (ynbuf[0] == 'Y'))
168       return(1);
169     else if(ynbuf[0] == 0)
170       return dflt;
171     else {
172       printf("Please enter 'y' or 'n': ");
173       fflush(stdout);
174     }
175   }
176 }
177
178 int yn(char *string)
179 {
180   return yes_no(string, 1);
181 }
182
183 int ny(char *string)
184 {
185   return yes_no(string, 0);
186 }
187
188 static void
189 append_srvtab(char *filename, int fd, char *sname, char *sinst, char *srealm,
190               unsigned char key_vno, unsigned char *key)
191 {
192   /* Add one to append null */
193     safe_write(filename, fd, sname, strlen(sname) + 1);
194     safe_write(filename, fd, sinst, strlen(sinst) + 1);
195     safe_write(filename, fd, srealm, strlen(srealm) + 1);
196     safe_write(filename, fd, &key_vno, 1);
197     safe_write(filename, fd, key, sizeof(des_cblock));
198     fsync(fd);
199 }    
200
201 static void
202 print_key(unsigned char *key)
203 {
204     int i;
205
206     for (i = 0; i < 4; i++)
207         printf("%02x", key[i]);
208     printf(" ");
209     for (i = 4; i < 8; i++)
210         printf("%02x", key[i]);
211 }
212
213 static void
214 print_name(char *name, char *inst, char *realm)
215 {
216     printf("%s", krb_unparse_name_long(name, inst, realm));
217 }
218
219 static int
220 get_svc_new_key(des_cblock *new_key, char *sname, char *sinst,
221                 char *srealm, char *keyfile)
222 {
223     int status = KADM_SUCCESS;
224
225     if (((status = krb_get_svc_in_tkt(sname, sinst, srealm, PWSERV_NAME,
226                                       KADM_SINST, 1, keyfile)) == KSUCCESS) &&
227         ((status = kadm_init_link(PWSERV_NAME, KRB_MASTER, srealm)) == 
228          KADM_SUCCESS)) {
229 #ifdef NOENCRYPTION
230         memset(new_key, 0, sizeof(des_cblock));
231         (*new_key)[0] = (unsigned char) 1;
232 #else /* NOENCRYPTION */
233         des_random_key(*new_key);
234 #endif /* NOENCRYPTION */
235         return(KADM_SUCCESS);
236     }
237     
238     return(status);
239 }
240
241 static void
242 get_key_from_password(des_cblock (*key), char *cellname)
243 {
244     char password[MAX_KPW_LEN]; /* storage for the password */
245
246     if (read_long_pw_string(password, sizeof(password)-1, "Password: ", 1))
247         leave("Error reading password.", 1);
248
249 #ifdef NOENCRYPTION
250     memset(key, 0, sizeof(des_cblock));
251     (*key)[0] = (unsigned char) 1;
252 #else /* NOENCRYPTION */
253     if (strlen(cellname) == 0)
254       des_string_to_key(password, key);
255     else
256       afs_string_to_key(password, cellname, key);
257 #endif /* NOENCRYPTION */
258     memset(password, 0, sizeof(password));
259 }    
260
261 static void
262 usage(void)
263 {
264     fprintf(stderr, "Usage: ksrvutil [-f keyfile] [-i] [-k] ");
265     fprintf(stderr, "[-p principal] [-r realm] [-u]");
266     fprintf(stderr, "[-c AFS cellname] ");
267     fprintf(stderr, "{list | change | add | get | delete}\n");
268     fprintf(stderr, "   -i causes the program to ask for "
269             "confirmation before changing keys.\n");
270     fprintf(stderr, "   -k causes the key to printed for list or change.\n");
271     fprintf(stderr, "   -u creates one keyfile for each principal "
272             "(only used with `get')\n");
273     exit(1);
274 }
275
276 int
277 main(int argc, char **argv)
278 {
279     char sname[ANAME_SZ];       /* name of service */
280     char sinst[INST_SZ];        /* instance of service */
281     char srealm[REALM_SZ];      /* realm of service */
282     unsigned char key_vno;      /* key version number */
283     int status;                 /* general purpose error status */
284     des_cblock new_key;
285     des_cblock old_key;
286     char change_tkt[MaxPathLen]; /* Ticket to use for key change */
287     char keyfile[MaxPathLen];   /* Original keyfile */
288     char work_keyfile[MaxPathLen]; /* Working copy of keyfile */
289     char backup_keyfile[MaxPathLen]; /* Backup copy of keyfile */
290     unsigned short keyfile_mode; /* Protections on keyfile */
291     int work_keyfile_fd = -1;   /* Initialize so that */
292     int backup_keyfile_fd = -1; /* compiler doesn't complain */
293     char local_realm[REALM_SZ]; /* local kerberos realm */
294     char cellname[1024];         /* AFS cell name */
295     int c;
296     int interactive = FALSE;
297     int list = FALSE;
298     int change = FALSE;
299     int unique_filename = FALSE;
300     int add = FALSE;
301     int delete = FALSE;
302     int get = FALSE;
303     int key = FALSE;            /* do we show keys? */
304     int arg_entered = FALSE;
305     int change_this_key = FALSE;
306     char databuf[BUFSIZ];
307     int first_printed = FALSE;  /* have we printed the first item? */
308     
309     memset(sname, 0, sizeof(sname));
310     memset(sinst, 0, sizeof(sinst));
311     memset(srealm, 0, sizeof(srealm));
312           
313     memset(change_tkt, 0, sizeof(change_tkt));
314     memset(keyfile, 0, sizeof(keyfile));
315     memset(work_keyfile, 0, sizeof(work_keyfile));
316     memset(backup_keyfile, 0, sizeof(backup_keyfile));
317     memset(local_realm, 0, sizeof(local_realm));
318     memset(cellname, 0, sizeof(cellname));
319     
320     set_progname (argv[0]);
321
322     if (krb_get_default_principal(u_name, u_inst, u_realm) < 0)
323         errx (1, "could not get default principal");
324
325     /* This is used only as a default for adding keys */
326     if (krb_get_lrealm(local_realm, 1) != KSUCCESS)
327         strlcpy(local_realm,
328                         KRB_REALM,
329                         sizeof(local_realm));
330     
331     while((c = getopt(argc, argv, "ikc:f:p:r:u")) != -1) {
332         switch (c) {
333         case 'i':
334             interactive++;
335             break;
336         case 'k':
337             key++;
338             break;
339         case 'c':
340             strlcpy(cellname, optarg, sizeof(cellname));
341             break;
342         case 'f':
343             strlcpy(keyfile, optarg, sizeof(keyfile));
344             break;
345         case 'p':
346             if((status = kname_parse (u_name, u_inst, u_realm, optarg)) !=
347                KSUCCESS)
348                 errx (1, "principal %s: %s", optarg,
349                       krb_get_err_text(status));
350             break;
351         case 'r':
352             strlcpy(u_realm, optarg, sizeof(u_realm));
353             break;
354         case 'u':
355             unique_filename = 1;
356             break;
357         case '?':
358             usage();
359         }
360     }
361     if (optind >= argc)
362         usage();
363     if (*u_realm == '\0')
364          strlcpy (u_realm, local_realm, sizeof(u_realm));
365     if (strcmp(argv[optind], "list") == 0) {
366         if (arg_entered)
367             usage();
368         else {
369             arg_entered++;
370             list++;
371         }
372     }
373     else if (strcmp(argv[optind], "change") == 0) {
374         if (arg_entered)
375             usage();
376         else {
377             arg_entered++;
378             change++;
379         }
380     }
381     else if (strcmp(argv[optind], "add") == 0) {
382         if (arg_entered)
383             usage();
384         else {
385             arg_entered++;
386             add++;
387         }
388     }
389     else if (strcmp(argv[optind], "get") == 0) {
390         if (arg_entered)
391             usage();
392         else {
393             arg_entered++;
394             get++;
395         }
396     }
397     else if (strcmp(argv[optind], "delete") == 0) {
398         if (arg_entered)
399             usage();
400         else {
401             arg_entered++;
402             delete++;
403         }
404     }
405     else
406         usage();
407     ++optind;
408     
409     if (!arg_entered)
410         usage();
411
412     if(unique_filename && !get)
413         warnx("`-u' flag is only used with `get'");
414
415     if (!keyfile[0])
416         strlcpy(keyfile, KEYFILE, sizeof(keyfile));
417
418     strlcpy(work_keyfile, keyfile, sizeof(work_keyfile));
419     strlcpy(backup_keyfile, keyfile, sizeof(backup_keyfile));
420     
421     if (change || add || (get && !unique_filename) || delete) {
422         snprintf(work_keyfile, sizeof(work_keyfile), "%s.work", keyfile);
423         snprintf(backup_keyfile, sizeof(backup_keyfile), "%s.old", keyfile);
424         copy_keyfile(keyfile, backup_keyfile);
425     }
426     
427     if (add || (get && !unique_filename))
428         copy_keyfile(backup_keyfile, work_keyfile);
429
430     keyfile_mode = get_mode(keyfile);
431
432     if (change || list || delete)
433         if ((backup_keyfile_fd = open(backup_keyfile, O_RDONLY, 0)) < 0)
434             err (1, "open %s", backup_keyfile);
435
436     if (change || delete) {
437         if ((work_keyfile_fd = 
438              open(work_keyfile, O_WRONLY | O_CREAT | O_TRUNC, 
439                   SRVTAB_MODE)) < 0)
440             err (1, "creat %s", work_keyfile);
441     }
442     else if (add) {
443         if ((work_keyfile_fd =
444              open(work_keyfile, O_APPEND | O_WRONLY, SRVTAB_MODE)) < 0)
445             err (1, "open with append %s", work_keyfile );
446     }
447     else if (get && !unique_filename) {
448         if ((work_keyfile_fd =
449              open(work_keyfile, O_RDWR | O_CREAT, SRVTAB_MODE)) < 0)
450             err (1, "open for writing %s", work_keyfile);
451     }
452     
453     if (change || list || delete) {
454         while ((getst(backup_keyfile_fd, sname, SNAME_SZ) > 0) &&
455                (getst(backup_keyfile_fd, sinst, INST_SZ) > 0) &&
456                (getst(backup_keyfile_fd, srealm, REALM_SZ) > 0) &&
457                (read(backup_keyfile_fd, &key_vno, 1) > 0) &&
458                (read(backup_keyfile_fd, old_key, sizeof(old_key)) > 0)) {
459             if (list) {
460                 if (!first_printed) {
461                     printf(VNO_HEADER);
462                     printf(PAD);
463                     if (key) {
464                         printf(KEY_HEADER);
465                         printf(PAD);
466                     }
467                     printf(PRINC_HEADER);
468                     first_printed = 1;
469                 }
470                 printf(VNO_FORMAT, key_vno);
471                 printf(PAD);
472                 if (key) {
473                     print_key(old_key);
474                     printf(PAD);
475                 }
476                 print_name(sname, sinst, srealm);
477                 printf("\n");
478             }
479             else if (change) {
480                 snprintf(change_tkt, sizeof(change_tkt), "%s_ksrvutil.%u",
481                          TKT_ROOT, (unsigned)getpid());
482                 krb_set_tkt_string(change_tkt);
483                 destroyp = TRUE;
484
485                 printf("\nPrincipal: ");
486                 print_name(sname, sinst, srealm);
487                 printf("; version %d\n", key_vno);
488                 if (interactive)
489                     change_this_key = yn("Change this key?");
490                 else
491                     change_this_key = 1;
492                 
493                 if (change_this_key)
494                     printf("Changing to version %d.\n", key_vno + 1);
495                 else if (change)
496                     printf("Not changing this key.\n");
497                 
498                 if (change_this_key) {
499                     /* 
500                      * Pick a new key and determine whether or not
501                      * it is safe to change
502                      */
503                     if ((status = 
504                          get_svc_new_key(&new_key, sname, sinst, 
505                                          srealm, keyfile)) == KADM_SUCCESS)
506                         key_vno++;
507                     else {
508                         memcpy(new_key, old_key, sizeof(new_key));
509                         warnx ("Key NOT changed: %s\n",
510                                krb_get_err_text(status));
511                         change_this_key = FALSE;
512                     }
513                 }
514                 else 
515                     memcpy(new_key, old_key, sizeof(new_key));
516                 append_srvtab(work_keyfile, work_keyfile_fd, 
517                               sname, sinst, srealm, key_vno, new_key);
518                 if (key && change_this_key) {
519                     printf("Old key: ");
520                     print_key(old_key);
521                     printf("; new key: ");
522                     print_key(new_key);
523                     printf("\n");
524                 }
525                 if (change_this_key) {
526                     if ((status = kadm_change_pw(new_key)) == KADM_SUCCESS) {
527                         printf("Key changed.\n");
528                         dest_tkt();
529                     }
530                     else {
531                         com_err(__progname, status, 
532                                 " attempting to change password.");
533                         dest_tkt();
534                         /* XXX This knows the format of a keyfile */
535                         if (lseek(work_keyfile_fd, -9, SEEK_CUR) >= 0) {
536                             key_vno--;
537                             safe_write(work_keyfile,
538                                        work_keyfile_fd, &key_vno, 1);
539                             safe_write(work_keyfile, work_keyfile_fd,
540                                        old_key, sizeof(des_cblock));
541                             fsync(work_keyfile_fd);
542                             fprintf(stderr,"Key NOT changed.\n");
543                         } else {
544                             warn ("Unable to revert keyfile");
545                             leave("", 1);
546                         }
547                     }
548                 }
549             } else if(delete) {
550                 int delete_this_key;
551                 printf("\nPrincipal: ");
552                 print_name(sname, sinst, srealm);
553                 printf("; version %d\n", key_vno);
554                 delete_this_key = yn("Delete this key?");
555                 
556                 if (delete_this_key)
557                     printf("Deleting this key.\n");
558                 
559                 if (!delete_this_key) {
560                     append_srvtab(work_keyfile, work_keyfile_fd, 
561                                   sname, sinst, srealm, key_vno, old_key);
562                 }
563             }
564             memset(old_key, 0, sizeof(des_cblock));
565             memset(new_key, 0, sizeof(des_cblock));
566         }
567     }
568     else if (add) {
569         do {
570             do {
571                 char *p;
572
573                 safe_read_stdin("Name: ", databuf, sizeof(databuf));
574                 p = strchr(databuf, '.');
575                 if (p != NULL) {
576                     *p++ = '\0';
577                     strlcpy (sname, databuf, sizeof(sname));
578                     strlcpy (sinst, p, sizeof(sinst));
579                 } else {
580                     strlcpy (sname, databuf, sizeof(sname));
581                     safe_read_stdin("Instance: ", databuf, sizeof(databuf));
582                     strlcpy (sinst, databuf, sizeof(databuf));
583                 }
584
585                 safe_read_stdin("Realm: ", databuf, sizeof(databuf));
586                 if (databuf[0] != '\0')
587                     strlcpy (srealm, databuf, sizeof(srealm));
588                 else
589                     strlcpy (srealm, local_realm, sizeof(srealm));
590
591                 safe_read_stdin("Version number: ", databuf, sizeof(databuf));
592                 key_vno = atoi(databuf);
593                 if (!srealm[0])
594                     strlcpy(srealm, local_realm, sizeof(srealm));
595                 printf("New principal: ");
596                 print_name(sname, sinst, srealm);
597                 printf("; version %d\n", key_vno);
598             } while (!yn("Is this correct?"));
599             get_key_from_password(&new_key, cellname);
600             if (key) {
601                 printf("Key: ");
602                 print_key(new_key);
603                 printf("\n");
604             }
605             append_srvtab(work_keyfile, work_keyfile_fd, 
606                           sname, sinst, srealm, key_vno, new_key);
607             printf("Key successfully added.\n");
608         } while (yn("Would you like to add another key?"));
609     }
610     else if (get) {
611         ksrvutil_get(unique_filename, work_keyfile_fd, work_keyfile,
612                      argc - optind, argv + optind);
613     }
614
615     if (change || list || delete) 
616         if (close(backup_keyfile_fd) < 0)
617             warn ("close %s", backup_keyfile);
618     
619     if (change || add || (get && !unique_filename) || delete) {
620         if (close(work_keyfile_fd) < 0)
621             err (1, "close %s", work_keyfile);
622         if (rename(work_keyfile, keyfile) < 0)
623             err (1, "rename(%s, %s)", work_keyfile, keyfile);
624         chmod(backup_keyfile, keyfile_mode);
625         chmod(keyfile, keyfile_mode);
626         printf("Old keyfile in %s.\n", backup_keyfile);
627     }
628     return 0;
629 }