Initial import from FreeBSD RELENG_4:
[dragonfly.git] / crypto / kerberosIV / lib / kdb / krb_kdb_utils.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
22 /*
23  * Utility routines for Kerberos programs which directly access
24  * the database.  This code was duplicated in too many places
25  * before I gathered it here.
26  *
27  * Jon Rochlis, MIT Telecom, March 1988
28  */
29
30 #include "kdb_locl.h"
31
32 #include <kdc.h>
33
34 RCSID("$Id: krb_kdb_utils.c,v 1.25 1999/03/13 21:24:21 assar Exp $");
35
36 /* always try /.k for backwards compatibility */
37 static char *master_key_files[] = { MKEYFILE, "/.k", NULL };
38
39 #ifdef HAVE_STRERROR
40 #define k_strerror(e) strerror(e)
41 #else
42 static
43 char *
44 k_strerror(int eno)
45 {
46   extern int sys_nerr;
47   extern char *sys_errlist[];
48
49   static char emsg[128];
50
51   if (eno < 0 || eno >= sys_nerr)
52     snprintf(emsg, sizeof(emsg), "Error %d occurred.", eno);
53   else
54     return sys_errlist[eno];
55
56   return emsg;
57 }
58 #endif
59
60 int
61 kdb_new_get_master_key(des_cblock *key, des_key_schedule schedule)
62 {
63   int kfile = -1;
64   int i;
65   char buf[1024];
66
67   char **mkey;
68
69   for(mkey = master_key_files; *mkey; mkey++){
70       kfile = open(*mkey, O_RDONLY);
71       if(kfile < 0 && errno != ENOENT)
72           fprintf(stderr, "Failed to open master key file \"%s\": %s\n", 
73                   *mkey,
74                   k_strerror(errno));
75       if(kfile >= 0)
76           break;
77   }
78   if(*mkey){
79       int bytes;
80       bytes = read(kfile, (char*)key, sizeof(des_cblock));
81       close(kfile);
82       if(bytes == sizeof(des_cblock)){
83           des_key_sched(key, schedule);
84           return 0;
85       }
86       fprintf(stderr, "Could only read %d bytes from master key file %s\n", 
87               bytes, *mkey);
88   }else{
89       fprintf(stderr, "No master key file found.\n");
90   }
91
92   
93   i=0;
94   while(i < 3){
95       if(des_read_pw_string(buf, sizeof(buf), "Enter master password: ", 0))
96           break;
97
98       /* buffer now contains either an old format master key password or a
99        * new format base64 encoded master key
100        */
101       
102       /* try to verify as old password */
103       des_string_to_key(buf, key);
104       des_key_sched(key, schedule);
105       
106       if(kdb_verify_master_key(key, schedule, NULL) != -1){
107           memset(buf, 0, sizeof(buf));
108           return 0;
109       }
110       
111       /* failed test, so must be base64 encoded */
112       
113       if(base64_decode(buf, key) == 8){
114           des_key_sched(key, schedule);
115           if(kdb_verify_master_key(key, schedule, NULL) != -1){
116               memset(buf, 0, sizeof(buf));
117               return 0;
118           }
119       }
120       
121       memset(buf, 0, sizeof(buf));
122       fprintf(stderr, "Failed to verify master key.\n");
123       i++;
124   }
125   
126   /* life sucks */
127   fprintf(stderr, "You loose.\n");
128   exit(1);
129 }
130
131 int
132 kdb_new_get_new_master_key(des_cblock *key,
133                            des_key_schedule schedule, 
134                            int verify)
135 {
136 #ifndef RANDOM_MKEY
137   des_read_password(key, "\nEnter Kerberos master password: ", verify);
138   printf ("\n");
139 #else
140   char buf[1024];
141   des_generate_random_block (key);
142   des_key_sched(key, schedule);
143   
144   des_read_pw_string(buf, sizeof(buf), "Enter master key seed: ", 0);
145   des_cbc_cksum((des_cblock*)buf, key, sizeof(buf), schedule, key);
146   memset(buf, 0, sizeof(buf));
147 #endif
148   des_key_sched(key, schedule);
149   return 0;
150 }
151
152 int
153 kdb_get_master_key(int prompt,
154                    des_cblock *master_key, 
155                    des_key_schedule master_key_sched)
156 {
157   int ask = (prompt == KDB_GET_TWICE);
158 #ifndef RANDOM_MKEY
159   ask |= (prompt == KDB_GET_PROMPT);
160 #endif
161   
162   if(ask)
163     kdb_new_get_new_master_key(master_key, master_key_sched, 
164                                prompt == KDB_GET_TWICE);
165   else
166     kdb_new_get_master_key(master_key, master_key_sched);
167   return 0;
168 }
169
170 int
171 kdb_kstash(des_cblock *master_key, char *file)
172 {
173   int kfile;
174
175   kfile = open(file, O_TRUNC | O_RDWR | O_CREAT, 0600);
176   if (kfile < 0) {
177     return -1;
178   }
179   if (write(kfile, master_key, sizeof(des_cblock)) != sizeof(des_cblock)) {
180     close(kfile);
181     return -1;
182   }
183   close(kfile);
184   return 0;
185 }
186
187 /* The old algorithm used the key schedule as the initial vector which
188    was byte order depedent ... */
189
190 void
191 kdb_encrypt_key (des_cblock (*in), des_cblock (*out),
192                  des_cblock (*master_key),
193                  des_key_schedule master_key_sched, int e_d_flag)
194 {
195
196 #ifdef NOENCRYPTION
197   memcpy(out, in, sizeof(des_cblock));
198 #else
199   des_pcbc_encrypt(in,out,(long)sizeof(des_cblock),master_key_sched,master_key,
200                    e_d_flag);
201 #endif
202 }
203
204 /* The caller is reasponsible for cleaning up the master key and sched,
205    even if we can't verify the master key */
206
207 /* Returns master key version if successful, otherwise -1 */
208
209 long 
210 kdb_verify_master_key (des_cblock *master_key,
211                        des_key_schedule master_key_sched,
212                        FILE *out) /* NULL -> no output */
213 {
214   des_cblock key_from_db;
215   Principal principal_data[1];
216   int n, more = 0;
217   long master_key_version;
218
219   /* lookup the master key version */
220   n = kerb_get_principal(KERB_M_NAME, KERB_M_INST, principal_data,
221                          1 /* only one please */, &more);
222   if ((n != 1) || more) {
223     if (out != NULL) 
224       fprintf(out,
225               "verify_master_key: %s, %d found.\n",
226               "Kerberos error on master key version lookup",
227               n);
228     return (-1);
229   }
230
231   master_key_version = (long) principal_data[0].key_version;
232
233   /* set up the master key */
234   if (out != NULL)  /* should we punt this? */
235     fprintf(out, "Current Kerberos master key version is %d.\n",
236             principal_data[0].kdc_key_ver);
237
238   /*
239    * now use the master key to decrypt the key in the db, had better
240    * be the same! 
241    */
242   copy_to_key(&principal_data[0].key_low,
243               &principal_data[0].key_high,
244               key_from_db);
245   kdb_encrypt_key (&key_from_db, &key_from_db, 
246                    master_key, master_key_sched, DES_DECRYPT);
247
248   /* the decrypted database key had better equal the master key */
249   n = memcmp(master_key, key_from_db, sizeof(master_key));
250   /* this used to zero the master key here! */
251   memset(key_from_db, 0, sizeof(key_from_db));
252   memset(principal_data, 0, sizeof (principal_data));
253
254   if (n && (out != NULL)) {
255     fprintf(out, "\n\07\07verify_master_key: Invalid master key; ");
256     fprintf(out, "does not match database.\n");
257   }
258   if(n)
259     return (-1);
260
261   if (out != (FILE *) NULL) {
262     fprintf(out, "\nMaster key entered.  BEWARE!\07\07\n");
263     fflush(out);
264   }
265
266   return (master_key_version);
267 }