Initial import from FreeBSD RELENG_4:
[games.git] / crypto / heimdal / lib / kadm5 / set_keys.c
1 /*
2  * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden). 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions 
8  * are met: 
9  *
10  * 1. Redistributions of source code must retain the above copyright 
11  *    notice, this list of conditions and the following disclaimer. 
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright 
14  *    notice, this list of conditions and the following disclaimer in the 
15  *    documentation and/or other materials provided with the distribution. 
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors 
18  *    may be used to endorse or promote products derived from this software 
19  *    without specific prior written permission. 
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
31  * SUCH DAMAGE. 
32  */
33
34 #include "kadm5_locl.h"
35
36 RCSID("$Id: set_keys.c,v 1.25 2001/08/13 15:12:16 joda Exp $");
37
38 /*
39  * the known and used DES enctypes
40  */
41
42 static krb5_enctype des_types[] = { ETYPE_DES_CBC_CRC,
43                                     ETYPE_DES_CBC_MD4,
44                                     ETYPE_DES_CBC_MD5 };
45 static unsigned n_des_types = sizeof(des_types) / sizeof(des_types[0]);
46
47 static krb5_error_code
48 make_keys(krb5_context context, krb5_principal principal, const char *password,
49           Key **keys_ret, size_t *num_keys_ret)
50 {
51     krb5_enctype all_etypes[] = { ETYPE_DES3_CBC_SHA1,
52                                   ETYPE_DES_CBC_MD5,
53                                   ETYPE_DES_CBC_MD4,
54                                   ETYPE_DES_CBC_CRC };
55
56
57     krb5_enctype e;
58
59     krb5_error_code ret = 0;
60     char **ktypes, **kp;
61
62     Key *keys = NULL, *tmp;
63     int num_keys = 0;
64     Key key;
65
66     int i;
67     char *v4_ktypes[] = {"des3:pw-salt", "v4", NULL};
68
69     ktypes = krb5_config_get_strings(context, NULL, "kadmin", 
70                                      "default_keys", NULL);
71
72     /* for each entry in `default_keys' try to parse it as a sequence
73        of etype:salttype:salt, syntax of this if something like:
74        [(des|des3|etype):](pw|afs3)[:string], if etype is omitted it
75        means all etypes, and if string is omitted is means the default
76        string (for that principal). Additional special values:
77        v5 == pw-salt, and
78        v4 == des:pw-salt:
79        afs or afs3 == des:afs3-salt
80     */
81
82     if (ktypes == NULL
83         && krb5_config_get_bool (context, NULL, "kadmin",
84                                  "use_v4_salt", NULL))
85         ktypes = v4_ktypes;
86
87     for(kp = ktypes; kp && *kp; kp++) {
88         krb5_enctype *etypes;
89         int num_etypes;
90         krb5_salt salt;
91         krb5_boolean salt_set;
92
93         const char *p;
94         char buf[3][256];
95         int num_buf = 0;
96
97         p = *kp;
98         if(strcmp(p, "v5") == 0)
99             p = "pw-salt";
100         else if(strcmp(p, "v4") == 0)
101             p = "des:pw-salt:";
102         else if(strcmp(p, "afs") == 0 || strcmp(p, "afs3") == 0)
103             p = "des:afs3-salt";
104         
105         /* split p in a list of :-separated strings */
106         for(num_buf = 0; num_buf < 3; num_buf++)
107             if(strsep_copy(&p, ":", buf[num_buf], sizeof(buf[num_buf])) == -1)
108                 break;
109
110         etypes = NULL;
111         num_etypes = 0;
112         memset(&salt, 0, sizeof(salt));
113         salt_set = FALSE;
114
115         for(i = 0; i < num_buf; i++) {
116             if(etypes == NULL) {
117                 /* this might be a etype specifier */
118                 /* XXX there should be a string_to_etypes handling
119                    special cases like `des' and `all' */
120                 if(strcmp(buf[i], "des") == 0) {
121                     etypes = all_etypes + 1;
122                     num_etypes = 3;
123                     continue;
124                 } else if(strcmp(buf[i], "des3") == 0) {
125                     e = ETYPE_DES3_CBC_SHA1;
126                     etypes = &e;
127                     num_etypes = 1;
128                     continue;
129                 } else {
130                     ret = krb5_string_to_enctype(context, buf[i], &e);
131                     if(ret == 0) {
132                         etypes = &e;
133                         num_etypes = 1;
134                         continue;
135                     }
136                 }
137             }
138             if(salt.salttype == 0) {
139                 /* interpret string as a salt specifier, if no etype
140                    is set, this sets default values */
141                 /* XXX should perhaps use string_to_salttype, but that
142                    interface sucks */
143                 if(strcmp(buf[i], "pw-salt") == 0) {
144                     if(etypes == NULL) {
145                         etypes = all_etypes;
146                         num_etypes = 4;
147                     }
148                     salt.salttype = KRB5_PW_SALT;
149                 } else if(strcmp(buf[i], "afs3-salt") == 0) {
150                     if(etypes == NULL) {
151                         etypes = all_etypes + 1;
152                         num_etypes = 3;
153                     }
154                     salt.salttype = KRB5_AFS3_SALT;
155                 }
156             } else {
157                 /* if there is a final string, use it as the string to
158                    salt with, this is mostly useful with null salt for
159                    v4 compat, and a cell name for afs compat */
160                 salt.saltvalue.data = buf[i];
161                 salt.saltvalue.length = strlen(buf[i]);
162                 salt_set = TRUE;
163             }
164         }
165
166         if(etypes == NULL || salt.salttype == 0) {          
167             krb5_warnx(context, "bad value for default_keys `%s'", *kp);
168             continue;
169         }
170
171         if(!salt_set) {
172             /* make up default salt */
173             if(salt.salttype == KRB5_PW_SALT)
174                 ret = krb5_get_pw_salt(context, principal, &salt);
175             else if(salt.salttype == KRB5_AFS3_SALT) {
176                 krb5_realm *realm = krb5_princ_realm(context, principal);
177                 salt.saltvalue.data = strdup(*realm);
178                 if(salt.saltvalue.data == NULL) {
179                     krb5_set_error_string(context, "out of memory while "
180                                           "parsinig salt specifiers");
181                     ret = ENOMEM;
182                     goto out;
183                 }
184                 strlwr(salt.saltvalue.data);
185                 salt.saltvalue.length = strlen(*realm);
186                 salt_set = 1;
187             }
188         }
189         memset(&key, 0, sizeof(key));
190         for(i = 0; i < num_etypes; i++) {
191             Key *k;
192             for(k = keys; k < keys + num_keys; k++) {
193                 if(k->key.keytype == etypes[i] &&
194                    ((k->salt != NULL && 
195                      k->salt->type == salt.salttype &&
196                      k->salt->salt.length == salt.saltvalue.length &&
197                      memcmp(k->salt->salt.data, salt.saltvalue.data, 
198                             salt.saltvalue.length) == 0) ||
199                     (k->salt == NULL && 
200                      salt.salttype == KRB5_PW_SALT && 
201                      !salt_set)))
202                     goto next_etype;
203             }
204                        
205             ret = krb5_string_to_key_salt (context,
206                                            etypes[i],
207                                            password,
208                                            salt,
209                                            &key.key);
210
211             if(ret)
212                 goto out;
213
214             if (salt.salttype != KRB5_PW_SALT || salt_set) {
215                 key.salt = malloc (sizeof(*key.salt));
216                 if (key.salt == NULL) {
217                     free_Key(&key);
218                     ret = ENOMEM;
219                     goto out;
220                 }
221                 key.salt->type = salt.salttype;
222                 krb5_data_zero (&key.salt->salt);
223
224                 /* is the salt has not been set explicitly, it will be
225                    the default salt, so there's no need to explicitly
226                    copy it */
227                 if (salt_set) {
228                     ret = krb5_data_copy(&key.salt->salt, 
229                                          salt.saltvalue.data, 
230                                          salt.saltvalue.length);
231                     if (ret) {
232                         free_Key(&key);
233                         goto out;
234                     }
235                 }
236             }
237             tmp = realloc(keys, (num_keys + 1) * sizeof(*keys));
238             if(tmp == NULL) {
239                 free_Key(&key);
240                 ret = ENOMEM;
241                 goto out;
242             }
243             keys = tmp;
244             keys[num_keys++] = key;
245           next_etype:;
246         }
247     }
248
249     if(num_keys == 0) {
250         /* if we didn't manage to find a single valid key, create a
251            default set */
252         /* XXX only do this is there is no `default_keys'? */
253         krb5_salt v5_salt;
254         tmp = realloc(keys, (num_keys + 4) * sizeof(*keys));
255         if(tmp == NULL) {
256             ret = ENOMEM;
257             goto out;
258         }
259         keys = tmp;
260         ret = krb5_get_pw_salt(context, principal, &v5_salt);
261         if(ret)
262             goto out;
263         for(i = 0; i < 4; i++) {
264             memset(&key, 0, sizeof(key));
265             ret = krb5_string_to_key_salt(context, all_etypes[i], password, 
266                                           v5_salt, &key.key);
267             if(ret) {
268                 krb5_free_salt(context, v5_salt);
269                 goto out;
270             }
271             keys[num_keys++] = key;
272         }
273         krb5_free_salt(context, v5_salt);
274     }
275
276   out:
277     if(ret == 0) {
278         *keys_ret = keys;
279         *num_keys_ret = num_keys;
280     } else {
281         for(i = 0; i < num_keys; i++) {
282             free_Key(&keys[i]);
283         }
284         free(keys);
285     }
286     return ret;
287 }
288
289 /*
290  * Set the keys of `ent' to the string-to-key of `password'
291  */
292
293 kadm5_ret_t
294 _kadm5_set_keys(kadm5_server_context *context,
295                 hdb_entry *ent, 
296                 const char *password)
297 {
298     kadm5_ret_t ret;
299     Key *keys;
300     size_t num_keys;
301
302     ret = make_keys(context->context, ent->principal, password, 
303                     &keys, &num_keys);
304
305     if(ret)
306         return ret;
307     
308     _kadm5_free_keys (context, ent->keys.len, ent->keys.val);
309     ent->keys.val = keys;
310     ent->keys.len = num_keys;
311     ent->kvno++;
312     return 0;
313 }
314
315 /*
316  * Set the keys of `ent' to (`n_key_data', `key_data')
317  */
318
319 kadm5_ret_t
320 _kadm5_set_keys2(kadm5_server_context *context,
321                  hdb_entry *ent, 
322                  int16_t n_key_data, 
323                  krb5_key_data *key_data)
324 {
325     krb5_error_code ret;
326     int i;
327     unsigned len;
328     Key *keys;
329
330     len  = n_key_data;
331     keys = malloc (len * sizeof(*keys));
332     if (keys == NULL)
333         return ENOMEM;
334
335     _kadm5_init_keys (keys, len);
336
337     for(i = 0; i < n_key_data; i++) {
338         keys[i].mkvno = NULL;
339         keys[i].key.keytype = key_data[i].key_data_type[0];
340         ret = krb5_data_copy(&keys[i].key.keyvalue,
341                              key_data[i].key_data_contents[0],
342                              key_data[i].key_data_length[0]);
343         if(ret)
344             goto out;
345         if(key_data[i].key_data_ver == 2) {
346             Salt *salt;
347
348             salt = malloc(sizeof(*salt));
349             if(salt == NULL) {
350                 ret = ENOMEM;
351                 goto out;
352             }
353             keys[i].salt = salt;
354             salt->type = key_data[i].key_data_type[1];
355             krb5_data_copy(&salt->salt, 
356                            key_data[i].key_data_contents[1],
357                            key_data[i].key_data_length[1]);
358         } else
359             keys[i].salt = NULL;
360     }
361     _kadm5_free_keys (context, ent->keys.len, ent->keys.val);
362     ent->keys.len = len;
363     ent->keys.val = keys;
364     ent->kvno++;
365     return 0;
366  out:
367     _kadm5_free_keys (context, len, keys);
368     return ret;
369 }
370
371 /*
372  * Set the keys of `ent' to `n_keys, keys'
373  */
374
375 kadm5_ret_t
376 _kadm5_set_keys3(kadm5_server_context *context,
377                  hdb_entry *ent,
378                  int n_keys,
379                  krb5_keyblock *keyblocks)
380 {
381     krb5_error_code ret;
382     int i;
383     unsigned len;
384     Key *keys;
385
386     len  = n_keys;
387     keys = malloc (len * sizeof(*keys));
388     if (keys == NULL)
389         return ENOMEM;
390
391     _kadm5_init_keys (keys, len);
392
393     for(i = 0; i < n_keys; i++) {
394         keys[i].mkvno = NULL;
395         ret = krb5_copy_keyblock_contents (context->context,
396                                            &keyblocks[i],
397                                            &keys[i].key);
398         if(ret)
399             goto out;
400         keys[i].salt = NULL;
401     }
402     _kadm5_free_keys (context, ent->keys.len, ent->keys.val);
403     ent->keys.len = len;
404     ent->keys.val = keys;
405     ent->kvno++;
406     return 0;
407  out:
408     _kadm5_free_keys (context, len, keys);
409     return ret;
410 }
411
412 /*
413  * Set the keys of `ent' to random keys and return them in `n_keys'
414  * and `new_keys'.
415  */
416
417 kadm5_ret_t
418 _kadm5_set_keys_randomly (kadm5_server_context *context,
419                           hdb_entry *ent,
420                           krb5_keyblock **new_keys,
421                           int *n_keys)
422 {
423     kadm5_ret_t ret = 0;
424     int i;
425     unsigned len;
426     krb5_keyblock *keys;
427     Key *hkeys;
428
429     len  = n_des_types + 1;
430     keys = malloc (len * sizeof(*keys));
431     if (keys == NULL)
432         return ENOMEM;
433
434     for (i = 0; i < len; ++i) {
435         keys[i].keyvalue.length = 0;
436         keys[i].keyvalue.data   = NULL;
437     }
438
439     hkeys = malloc (len * sizeof(*hkeys));
440     if (hkeys == NULL) {
441         free (keys);
442         return ENOMEM;
443     }
444
445     _kadm5_init_keys (hkeys, len);
446
447     ret = krb5_generate_random_keyblock (context->context,
448                                          des_types[0],
449                                          &keys[0]);
450     if (ret)
451         goto out;
452
453     ret = krb5_copy_keyblock_contents (context->context,
454                                        &keys[0],
455                                        &hkeys[0].key);
456     if (ret)
457         goto out;
458
459     for (i = 1; i < n_des_types; ++i) {
460         ret = krb5_copy_keyblock_contents (context->context,
461                                            &keys[0],
462                                            &keys[i]);
463         if (ret)
464             goto out;
465         keys[i].keytype = des_types[i];
466         ret = krb5_copy_keyblock_contents (context->context,
467                                            &keys[0],
468                                            &hkeys[i].key);
469         if (ret)
470             goto out;
471         hkeys[i].key.keytype = des_types[i];
472     }
473
474     ret = krb5_generate_random_keyblock (context->context,
475                                          ETYPE_DES3_CBC_SHA1,
476                                          &keys[n_des_types]);
477     if (ret)
478         goto out;
479
480     ret = krb5_copy_keyblock_contents (context->context,
481                                        &keys[n_des_types],
482                                        &hkeys[n_des_types].key);
483     if (ret)
484         goto out;
485
486     _kadm5_free_keys (context, ent->keys.len, ent->keys.val);
487     ent->keys.len = len;
488     ent->keys.val = hkeys;
489     ent->kvno++;
490     *new_keys     = keys;
491     *n_keys       = len;
492     return ret;
493 out:
494     for (i = 0; i < len; ++i)
495         krb5_free_keyblock_contents (context->context, &keys[i]);
496     free (keys);
497     _kadm5_free_keys (context, len, hkeys);
498     return ret;
499 }