Manually initialize krbtgt_princ.data
[krb5.git] / src / lib / kdb / kdb_cpw.c
1 /*
2  * lib/kdb/kdb_cpw.c
3  *
4  * Copyright 1995 by the Massachusetts Institute of Technology. 
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  * 
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  M.I.T. makes no representations about the suitability of
20  * this software for any purpose.  It is provided "as is" without express
21  * or implied warranty.
22  * 
23  */
24
25 #include "k5-int.h"
26 #include "krb5/adm.h"
27 #include <stdio.h>
28 #include <errno.h>
29
30 static int
31 get_key_data_kvno(context, count, data)
32     krb5_context          context;
33     int                   count;
34     krb5_key_data       * data;
35 {
36     int i, kvno;
37     /* Find last key version number */
38     for (kvno = i = 0; i < count; i++) {
39         if (kvno < data[i].key_data_kvno) {
40             kvno = data[i].key_data_kvno;
41         }
42     }
43     return(kvno);
44 }
45
46 static void
47 cleanup_key_data(context, count, data)
48     krb5_context          context;
49     int                   count;
50     krb5_key_data       * data;
51 {
52     int i, j;
53
54     for (i = 0; i < count; i++) {
55         for (j = 0; j < data[i].key_data_ver; j++) {
56             if (data[i].key_data_length[j]) {
57                 free(data[i].key_data_contents[j]);
58             }
59         }
60     }
61 }
62
63 /*
64  * Currently we can only generate random keys for preinitialized
65  * krb5_encrypt_block with a seed. This is bogus but currently
66  * necessary to insure that we don't generate two keys with the 
67  * same data.
68  */
69 static krb5_error_code
70 add_key_rnd(context, master_eblock, ks_tuple, ks_tuple_count, db_entry, kvno)
71     krb5_context          context;
72     krb5_encrypt_block  * master_eblock;
73     krb5_key_salt_tuple * ks_tuple;
74     int                   ks_tuple_count;
75     krb5_db_entry       * db_entry;
76     int                   kvno;
77 {
78     krb5_data             krbtgt_princ_entries[] = {
79         { 0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME },
80         { 0, 0, 0 }, 
81     };
82     krb5_principal_data   krbtgt_princ = {
83         0,                                      /* magic number */
84         {0, 0, 0},                              /* krb5_data realm */
85         (krb5_data *) NULL,                     /* krb5_data *data */
86         2,                                      /* int length */
87         KRB5_NT_SRV_INST                        /* int type */
88     };
89     krb5_keyblock         krbtgt_keyblock, * key;
90     krb5_pointer          krbtgt_seed;  
91     krb5_encrypt_block    krbtgt_eblock;
92     krb5_db_entry         krbtgt_entry;
93     krb5_boolean          more;
94     int                   max_kvno, one, i, j;
95     krb5_error_code       retval;
96
97     krbtgt_princ.data = krbtgt_princ_entries;
98     krb5_princ_set_realm_length(context, &krbtgt_princ, 
99                                 db_entry->princ->realm.length);
100     krb5_princ_set_realm_data(context, &krbtgt_princ, 
101                               db_entry->princ->realm.data);
102     krb5_princ_component(context, &krbtgt_princ, 1)->length = 
103                         db_entry->princ->realm.length;
104     krb5_princ_component(context, &krbtgt_princ, 1)->data = 
105                         db_entry->princ->realm.data;
106
107     /* Get tgt from database */
108     if (retval = krb5_db_get_principal(context, &krbtgt_princ, &krbtgt_entry,
109                                        &one, &more))
110         return(retval);
111     if ((one > 1) || (more)) {
112         krb5_db_free_principal(context, &krbtgt_entry, one);
113         return KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE;
114     }
115     if (!one) 
116         return KRB5_KDB_NOENTRY;
117
118     /* Get max kvno */
119     for (max_kvno = j = 0; j < krbtgt_entry.n_key_data; j++) {
120          if (max_kvno < krbtgt_entry.key_data[j].key_data_kvno) {
121              max_kvno = krbtgt_entry.key_data[j].key_data_kvno;
122         }
123     }
124
125     for (i = 0; i < ks_tuple_count; i++) {
126         if (retval = krb5_dbe_create_key_data(context, db_entry)) 
127             goto add_key_rnd_err;
128
129         for (j = 0; j < krbtgt_entry.n_key_data; j++) {
130              if ((krbtgt_entry.key_data[j].key_data_kvno == max_kvno) &&
131                  (krbtgt_entry.key_data[j].key_data_type[0] == 
132                   ks_tuple[i].ks_keytype)) {
133                 break;
134             }
135         }
136
137         if (j == krbtgt_entry.n_key_data) {
138             retval = KRB5_KDB_BAD_KEYTYPE;
139             goto add_key_rnd_err;
140         }
141
142         /* Decrypt key */
143         if (retval = krb5_dbekd_decrypt_key_data(context, master_eblock, 
144                                                  &krbtgt_entry.key_data[j],
145                                                  &krbtgt_keyblock, NULL)) {
146             goto add_key_rnd_err;
147         }
148
149         /* Init key */
150         krb5_use_keytype(context, &krbtgt_eblock, ks_tuple[i].ks_keytype);
151         if (retval = krb5_process_key(context,&krbtgt_eblock,&krbtgt_keyblock)){
152             goto add_key_rnd_err;
153         }
154
155         /* Init random generator */
156         if (retval = krb5_init_random_key(context, &krbtgt_eblock,
157                                           &krbtgt_keyblock, &krbtgt_seed)) {
158             krb5_finish_key(context, &krbtgt_eblock);
159             goto add_key_rnd_err;
160         }
161
162         if (retval = krb5_random_key(context,&krbtgt_eblock,krbtgt_seed,&key)) {
163             krb5_finish_random_key(context, &krbtgt_eblock, &krbtgt_seed);
164             krb5_finish_key(context, &krbtgt_eblock);
165             goto add_key_rnd_err;
166         }
167
168         krb5_finish_random_key(context, &krbtgt_eblock, &krbtgt_seed);
169         krb5_finish_key(context, &krbtgt_eblock);
170
171         if (retval = krb5_dbekd_encrypt_key_data(context, master_eblock, 
172                                                  key, NULL, kvno + 1, 
173                                                  db_entry->key_data)) {
174             krb5_free_keyblock(context, key);
175             goto add_key_rnd_err;
176         }
177
178         /* Finish random key */
179         krb5_free_keyblock(context, key);
180     }
181
182 add_key_rnd_err:;
183     krb5_db_free_principal(context, &krbtgt_entry, one);
184     return(retval);
185 }
186
187 /*
188  * Change random key for a krb5_db_entry 
189  * Assumes the max kvno
190  *
191  * As a side effect all old keys are nuked.
192  */
193 krb5_error_code
194 krb5_dbe_crk(context, master_eblock, ks_tuple, ks_tuple_count, db_entry)
195     krb5_context          context;
196     krb5_encrypt_block  * master_eblock;
197     krb5_key_salt_tuple * ks_tuple;
198     int                   ks_tuple_count;
199     krb5_db_entry       * db_entry;
200 {
201     int                   key_data_count;
202     krb5_key_data       * key_data;
203     krb5_error_code       retval;
204     int                   kvno;
205
206     /* First save the old keydata */
207     kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
208     key_data_count = db_entry->n_key_data;
209     key_data = db_entry->key_data;
210     db_entry->key_data = NULL;
211     db_entry->n_key_data = 0;
212
213     if (retval = add_key_rnd(context, master_eblock, ks_tuple, 
214                              ks_tuple_count, db_entry, kvno)) {
215         cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
216         db_entry->n_key_data = key_data_count;
217         db_entry->key_data = key_data;
218     } else {
219         cleanup_key_data(context, key_data_count, key_data);
220     }
221     return(retval);
222 }
223
224 /*
225  * Add random key for a krb5_db_entry 
226  * Assumes the max kvno
227  *
228  * As a side effect all old keys older than the max kvno are nuked.
229  */
230 krb5_error_code
231 krb5_dbe_ark(context, master_eblock, ks_tuple, ks_tuple_count, db_entry)
232     krb5_context          context;
233     krb5_encrypt_block  * master_eblock;
234     krb5_key_salt_tuple * ks_tuple;
235     int                   ks_tuple_count;
236     krb5_db_entry       * db_entry;
237 {
238     int                   key_data_count;
239     krb5_key_data       * key_data;
240     krb5_error_code       retval;
241     int                   kvno;
242     int                   i;
243
244     /* First save the old keydata */
245     kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
246     key_data_count = db_entry->n_key_data;
247     key_data = db_entry->key_data;
248     db_entry->key_data = NULL;
249     db_entry->n_key_data = 0;
250
251     if (retval = add_key_rnd(context, master_eblock, ks_tuple, 
252                              ks_tuple_count, db_entry, kvno)) {
253         cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
254         db_entry->n_key_data = key_data_count;
255         db_entry->key_data = key_data;
256     } else {
257         /* Copy keys with key_data_kvno = kvno */
258         for (i = 0; i < key_data_count; i++) {
259             if (key_data[i].key_data_kvno = kvno) {
260                 if (retval = krb5_dbe_create_key_data(context, db_entry)) {
261                     cleanup_key_data(context, db_entry->n_key_data,
262                                      db_entry->key_data);
263                     break;
264                 }
265                 /* We should decrypt/re-encrypt the data to use the same mkvno*/
266                 db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
267                 memset(&key_data[i], 0, sizeof(krb5_key_data));
268             }
269         }
270         cleanup_key_data(context, key_data_count, key_data);
271     }
272     return(retval);
273 }
274
275 /*
276  * Add key_data for a krb5_db_entry 
277  * If passwd is NULL the assumes that the caller wants a random password.
278  */
279 static krb5_error_code
280 add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count, passwd, 
281             db_entry, kvno)
282     krb5_context          context;
283     krb5_encrypt_block  * master_eblock;
284     krb5_key_salt_tuple * ks_tuple;
285     int                   ks_tuple_count;
286     char                * passwd;
287     krb5_db_entry       * db_entry;
288     int                   kvno;
289 {
290     krb5_error_code       retval;
291     krb5_encrypt_block    key_eblock;
292     krb5_keysalt          key_salt;
293     krb5_keyblock         key;
294     krb5_data             pwd;
295     int                   i;
296
297     for (i = 0; i < ks_tuple_count; i++) {
298         krb5_use_keytype(context, &key_eblock, ks_tuple[i].ks_keytype);
299         if (retval = krb5_dbe_create_key_data(context, db_entry)) 
300             return(retval);
301
302         /* Convert password string to key using appropriate salt */
303         switch (key_salt.type = ks_tuple[i].ks_salttype) {
304         case KRB5_KDB_SALTTYPE_ONLYREALM: {
305             krb5_data * saltdata;
306             if (retval = krb5_copy_data(context, krb5_princ_realm(context,
307                                         db_entry->princ), &saltdata))
308                 return(retval);
309
310             key_salt.data = *saltdata;
311             krb5_xfree(saltdata);
312         }
313         case KRB5_KDB_SALTTYPE_NOREALM:
314             if (retval=krb5_principal2salt_norealm(context, db_entry->princ,
315                                                          &key_salt.data)) 
316                 return(retval);
317             break;
318         case KRB5_KDB_SALTTYPE_NORMAL:
319             if (retval = krb5_principal2salt(context, db_entry->princ,
320                                                  &key_salt.data)) 
321                 return(retval);
322             break;
323         case KRB5_KDB_SALTTYPE_V4:
324             key_salt.data.length = 0;
325             key_salt.data.data = 0;
326             break;
327         default:
328             return(KRB5_KDB_BAD_SALTTYPE);
329         }
330
331         pwd.data = passwd;
332         pwd.length = strlen(passwd);
333         if (retval = krb5_string_to_key(context, &key_eblock, 
334                                         ks_tuple[i].ks_keytype, &key,
335                                         &pwd, &key_salt.data))
336             return(retval);
337
338         if (retval = krb5_dbekd_encrypt_key_data(context, master_eblock, &key,
339                      key_salt.type ? (const krb5_keysalt *)&key_salt : NULL,
340                      kvno + 1, &db_entry->key_data[i])) {
341             krb5_xfree(key.contents);
342             return(retval);
343         }
344         krb5_xfree(key.contents);
345     }
346     return(retval);
347 }
348
349 /*
350  * Change password for a krb5_db_entry 
351  * Assumes the max kvno
352  *
353  * As a side effect all old keys are nuked.
354  */
355 krb5_error_code
356 krb5_dbe_cpw(context, master_eblock, ks_tuple, ks_tuple_count, passwd, db_entry)
357     krb5_context          context;
358     krb5_encrypt_block  * master_eblock;
359     krb5_key_salt_tuple * ks_tuple;
360     int                   ks_tuple_count;
361     char                * passwd;
362     krb5_db_entry       * db_entry;
363 {
364     int                   key_data_count;
365     krb5_key_data       * key_data;
366     krb5_error_code       retval;
367     int                   kvno;
368
369     /* First save the old keydata */
370     kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
371     key_data_count = db_entry->n_key_data;
372     key_data = db_entry->key_data;
373     db_entry->key_data = NULL;
374     db_entry->n_key_data = 0;
375
376     if (retval = add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count,
377                              passwd, db_entry, kvno)) {
378         cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
379         db_entry->n_key_data = key_data_count;
380         db_entry->key_data = key_data;
381     } else {
382         cleanup_key_data(context, key_data_count, key_data);
383     }
384     return(retval);
385 }
386
387 /*
388  * Add password for a krb5_db_entry 
389  * Assumes the max kvno
390  *
391  * As a side effect all old keys older than the max kvno are nuked.
392  */
393 krb5_error_code
394 krb5_dbe_apw(context, master_eblock, ks_tuple, ks_tuple_count, passwd, db_entry)
395     krb5_context          context;
396     krb5_encrypt_block  * master_eblock;
397     krb5_key_salt_tuple * ks_tuple;
398     int                   ks_tuple_count;
399     char                * passwd;
400     krb5_db_entry       * db_entry;
401 {
402     int                   key_data_count;
403     krb5_key_data       * key_data;
404     krb5_error_code       retval;
405     int                   kvno;
406     int                   i;
407
408     /* First save the old keydata */
409     kvno = get_key_data_kvno(context, db_entry->n_key_data, db_entry->key_data);
410     key_data_count = db_entry->n_key_data;
411     key_data = db_entry->key_data;
412     db_entry->key_data = NULL;
413     db_entry->n_key_data = 0;
414
415     if (retval = add_key_pwd(context, master_eblock, ks_tuple, ks_tuple_count,
416                              passwd, db_entry, kvno)) {
417         cleanup_key_data(context, db_entry->n_key_data, db_entry->key_data);
418         db_entry->n_key_data = key_data_count;
419         db_entry->key_data = key_data;
420     } else {
421         /* Copy keys with key_data_kvno = kvno */
422         for (i = 0; i < key_data_count; i++) {
423             if (key_data[i].key_data_kvno = kvno) {
424                 if (retval = krb5_dbe_create_key_data(context, db_entry)) {
425                     cleanup_key_data(context, db_entry->n_key_data,
426                                      db_entry->key_data);
427                     break;
428                 }
429                 /* We should decrypt/re-encrypt the data to use the same mkvno*/
430                 db_entry->key_data[db_entry->n_key_data - 1] = key_data[i];
431                 memset(&key_data[i], 0, sizeof(krb5_key_data));
432             }
433         }
434         cleanup_key_data(context, key_data_count, key_data);
435     }
436     return(retval);
437 }