]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - crypto/heimdal/kadmin/load.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / crypto / heimdal / kadmin / load.c
1 /*
2  * Copyright (c) 1997-2005 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 "kadmin_locl.h"
35 #include "kadmin-commands.h"
36 #include <kadm5/private.h>
37
38 RCSID("$Id: load.c 16658 2006-01-25 12:29:46Z lha $");
39
40 struct entry {
41     char *principal;
42     char *key;
43     char *max_life;
44     char *max_renew;
45     char *created;
46     char *modified;
47     char *valid_start;
48     char *valid_end;
49     char *pw_end;
50     char *flags;
51     char *generation;
52     char *extensions;
53 };
54
55 static char *
56 skip_next(char *p)
57 {
58     while(*p && !isspace((unsigned char)*p)) 
59         p++;
60     *p++ = 0;
61     while(*p && isspace((unsigned char)*p))
62         p++;
63     return p;
64 }
65
66 /*
67  * Parse the time in `s', returning:
68  * -1 if error parsing
69  * 0  if none  present
70  * 1  if parsed ok
71  */
72
73 static int
74 parse_time_string(time_t *t, const char *s)
75 {
76     int year, month, date, hour, minute, second;
77     struct tm tm;
78
79     if(strcmp(s, "-") == 0)
80         return 0;
81     if(sscanf(s, "%04d%02d%02d%02d%02d%02d", 
82               &year, &month, &date, &hour, &minute, &second) != 6)
83         return -1;
84     tm.tm_year  = year - 1900;
85     tm.tm_mon   = month - 1;
86     tm.tm_mday  = date;
87     tm.tm_hour  = hour;
88     tm.tm_min   = minute;
89     tm.tm_sec   = second;
90     tm.tm_isdst = 0;
91     *t = timegm(&tm);
92     return 1;
93 }
94
95 /*
96  * parse time, allocating space in *t if it's there
97  */
98
99 static int
100 parse_time_string_alloc (time_t **t, const char *s)
101 {
102     time_t tmp;
103     int ret;
104
105     *t = NULL;
106     ret = parse_time_string (&tmp, s);
107     if (ret == 1) {
108         *t = malloc (sizeof (**t));
109         if (*t == NULL)
110             krb5_errx (context, 1, "malloc: out of memory");
111         **t = tmp;
112     }
113     return ret;
114 }
115
116 /*
117  * see parse_time_string for calling convention
118  */
119
120 static int
121 parse_integer(unsigned int *u, const char *s)
122 {
123     if(strcmp(s, "-") == 0)
124         return 0;
125     if (sscanf(s, "%u", u) != 1)
126         return -1;
127     return 1;
128 }
129
130 static int
131 parse_integer_alloc (unsigned int **u, const char *s)
132 {
133     unsigned int tmp;
134     int ret;
135
136     *u = NULL;
137     ret = parse_integer (&tmp, s);
138     if (ret == 1) {
139         *u = malloc (sizeof (**u));
140         if (*u == NULL)
141             krb5_errx (context, 1, "malloc: out of memory");
142         **u = tmp;
143     }
144     return ret;
145 }
146
147 /*
148  * Parse dumped keys in `str' and store them in `ent'
149  * return -1 if parsing failed
150  */
151
152 static int
153 parse_keys(hdb_entry *ent, char *str)
154 {
155     krb5_error_code ret;
156     int tmp;
157     char *p;
158     int i;
159     
160     p = strsep(&str, ":");
161     if (sscanf(p, "%d", &tmp) != 1)
162         return 1;
163     ent->kvno = tmp;
164     p = strsep(&str, ":");
165     while(p){
166         Key *key;
167         key = realloc(ent->keys.val, 
168                       (ent->keys.len + 1) * sizeof(*ent->keys.val));
169         if(key == NULL)
170             krb5_errx (context, 1, "realloc: out of memory");
171         ent->keys.val = key;
172         key = ent->keys.val + ent->keys.len;
173         ent->keys.len++;
174         memset(key, 0, sizeof(*key));
175         if(sscanf(p, "%d", &tmp) == 1) {
176             key->mkvno = malloc(sizeof(*key->mkvno));
177             *key->mkvno = tmp;
178         } else
179             key->mkvno = NULL;
180         p = strsep(&str, ":");
181         if (sscanf(p, "%d", &tmp) != 1)
182             return 1;
183         key->key.keytype = tmp;
184         p = strsep(&str, ":");
185         ret = krb5_data_alloc(&key->key.keyvalue, (strlen(p) - 1) / 2 + 1);
186         if (ret)
187             krb5_err (context, 1, ret, "krb5_data_alloc");
188         for(i = 0; i < strlen(p); i += 2) {
189             if(sscanf(p + i, "%02x", &tmp) != 1)
190                 return 1;
191             ((u_char*)key->key.keyvalue.data)[i / 2] = tmp;
192         }
193         p = strsep(&str, ":");
194         if(strcmp(p, "-") != 0){
195             unsigned type;
196             size_t p_len;
197
198             if(sscanf(p, "%u/", &type) != 1)
199                 return 1;
200             p = strchr(p, '/');
201             if(p == NULL)
202                 return 1;
203             p++;
204             p_len = strlen(p);
205
206             key->salt = malloc(sizeof(*key->salt));
207             if (key->salt == NULL)
208                 krb5_errx (context, 1, "malloc: out of memory");
209             key->salt->type = type;
210                 
211             if (p_len) {
212                 if(*p == '\"') {
213                     ret = krb5_data_copy(&key->salt->salt, p + 1, p_len - 2);
214                     if (ret)
215                         krb5_err (context, 1, ret, "krb5_data_copy");
216                 } else {
217                     ret = krb5_data_alloc(&key->salt->salt,
218                                           (p_len - 1) / 2 + 1);
219                     if (ret)
220                         krb5_err (context, 1, ret, "krb5_data_alloc");
221                     for(i = 0; i < p_len; i += 2){
222                         if (sscanf(p + i, "%02x", &tmp) != 1)
223                             return 1;
224                         ((u_char*)key->salt->salt.data)[i / 2] = tmp;
225                     }
226                 }
227             } else
228                 krb5_data_zero (&key->salt->salt);
229         }
230         p = strsep(&str, ":");
231     }
232     return 0;
233 }
234
235 /*
236  * see parse_time_string for calling convention
237  */
238
239 static int
240 parse_event(Event *ev, char *s)
241 {
242     krb5_error_code ret;
243     char *p;
244
245     if(strcmp(s, "-") == 0)
246         return 0;
247     memset(ev, 0, sizeof(*ev));
248     p = strsep(&s, ":");
249     if(parse_time_string(&ev->time, p) != 1)
250         return -1;
251     p = strsep(&s, ":");
252     ret = krb5_parse_name(context, p, &ev->principal);
253     if (ret)
254         return -1;
255     return 1;
256 }
257
258 static int
259 parse_event_alloc (Event **ev, char *s)
260 {
261     Event tmp;
262     int ret;
263
264     *ev = NULL;
265     ret = parse_event (&tmp, s);
266     if (ret == 1) {
267         *ev = malloc (sizeof (**ev));
268         if (*ev == NULL)
269             krb5_errx (context, 1, "malloc: out of memory");
270         **ev = tmp;
271     }
272     return ret;
273 }
274
275 static int
276 parse_hdbflags2int(HDBFlags *f, const char *s)
277 {
278     int ret;
279     unsigned int tmp;
280
281     ret = parse_integer (&tmp, s);
282     if (ret == 1)
283         *f = int2HDBFlags (tmp);
284     return ret;
285 }
286
287 static int
288 parse_generation(char *str, GENERATION **gen)
289 {
290     char *p;
291     int v;
292
293     if(strcmp(str, "-") == 0 || *str == '\0') {
294         *gen = NULL;
295         return 0;
296     }
297     *gen = calloc(1, sizeof(**gen));
298
299     p = strsep(&str, ":");
300     if(parse_time_string(&(*gen)->time, p) != 1)
301         return -1;
302     p = strsep(&str, ":");
303     if(sscanf(p, "%d", &v) != 1)
304         return -1;
305     (*gen)->usec = v;
306     p = strsep(&str, ":");
307     if(sscanf(p, "%d", &v) != 1)
308         return -1;
309     (*gen)->gen = v - 1; /* XXX gets bumped in _hdb_store */
310     return 0;
311 }
312
313 static int
314 parse_extensions(char *str, HDB_extensions **e)
315 {
316     char *p;
317     int ret;
318
319     if(strcmp(str, "-") == 0 || *str == '\0') {
320         *e = NULL;
321         return 0;
322     }
323     *e = calloc(1, sizeof(**e));
324
325     p = strsep(&str, ":");
326
327     while (p) {
328         HDB_extension ext;
329         ssize_t len;
330         void *d;
331
332         len = strlen(p);
333         d = malloc(len);
334
335         len = hex_decode(p, d, len);
336         if (len < 0)
337             return -1;
338
339         ret = decode_HDB_extension(d, len, &ext, NULL);
340         free(d);
341         if (ret)
342             return -1;
343         d = realloc((*e)->val, ((*e)->len + 1) * sizeof((*e)->val[0]));
344         if (d == NULL)
345             abort();
346         (*e)->val = d;
347         (*e)->val[(*e)->len] = ext;
348         (*e)->len++;
349
350         p = strsep(&str, ":");
351     }
352
353     return 0;
354 }
355
356
357 /*
358  * Parse the dump file in `filename' and create the database (merging
359  * iff merge)
360  */
361
362 static int
363 doit(const char *filename, int mergep)
364 {
365     krb5_error_code ret;
366     FILE *f;
367     char s[8192]; /* XXX should fix this properly */
368     char *p;
369     int line;
370     int flags = O_RDWR;
371     struct entry e;
372     hdb_entry_ex ent;
373     HDB *db = _kadm5_s_get_db(kadm_handle);
374
375     f = fopen(filename, "r");
376     if(f == NULL){
377         krb5_warn(context, errno, "fopen(%s)", filename);
378         return 1;
379     }
380     ret = kadm5_log_truncate (kadm_handle);
381     if (ret) {
382         fclose (f);
383         krb5_warn(context, ret, "kadm5_log_truncate");
384         return 1;
385     }
386
387     if(!mergep)
388         flags |= O_CREAT | O_TRUNC;
389     ret = db->hdb_open(context, db, flags, 0600);
390     if(ret){
391         krb5_warn(context, ret, "hdb_open");
392         fclose(f);
393         return 1;
394     }
395     line = 0;
396     ret = 0;
397     while(fgets(s, sizeof(s), f) != NULL) {
398         ret = 0;
399         line++;
400
401         p = s;
402         while (isspace((unsigned char)*p))
403             p++;
404
405         e.principal = p;
406         for(p = s; *p; p++){
407             if(*p == '\\')
408                 p++;
409             else if(isspace((unsigned char)*p)) {
410                 *p = 0;
411                 break;
412             }
413         }
414         p = skip_next(p);
415         
416         e.key = p;
417         p = skip_next(p);
418
419         e.created = p;
420         p = skip_next(p);
421
422         e.modified = p;
423         p = skip_next(p);
424
425         e.valid_start = p;
426         p = skip_next(p);
427
428         e.valid_end = p;
429         p = skip_next(p);
430
431         e.pw_end = p;
432         p = skip_next(p);
433
434         e.max_life = p;
435         p = skip_next(p);
436
437         e.max_renew = p;
438         p = skip_next(p);
439
440         e.flags = p;
441         p = skip_next(p);
442
443         e.generation = p;
444         p = skip_next(p);
445
446         e.extensions = p;
447         p = skip_next(p);
448
449         memset(&ent, 0, sizeof(ent));
450         ret = krb5_parse_name(context, e.principal, &ent.entry.principal);
451         if(ret) {
452             fprintf(stderr, "%s:%d:%s (%s)\n", 
453                     filename, 
454                     line,
455                     krb5_get_err_text(context, ret),
456                     e.principal);
457             continue;
458         }
459         
460         if (parse_keys(&ent.entry, e.key)) {
461             fprintf (stderr, "%s:%d:error parsing keys (%s)\n",
462                      filename, line, e.key);
463             hdb_free_entry (context, &ent);
464             continue;
465         }
466         
467         if (parse_event(&ent.entry.created_by, e.created) == -1) {
468             fprintf (stderr, "%s:%d:error parsing created event (%s)\n",
469                      filename, line, e.created);
470             hdb_free_entry (context, &ent);
471             continue;
472         }
473         if (parse_event_alloc (&ent.entry.modified_by, e.modified) == -1) {
474             fprintf (stderr, "%s:%d:error parsing event (%s)\n",
475                      filename, line, e.modified);
476             hdb_free_entry (context, &ent);
477             continue;
478         }
479         if (parse_time_string_alloc (&ent.entry.valid_start, e.valid_start) == -1) {
480             fprintf (stderr, "%s:%d:error parsing time (%s)\n",
481                      filename, line, e.valid_start);
482             hdb_free_entry (context, &ent);
483             continue;
484         }
485         if (parse_time_string_alloc (&ent.entry.valid_end,   e.valid_end) == -1) {
486             fprintf (stderr, "%s:%d:error parsing time (%s)\n",
487                      filename, line, e.valid_end);
488             hdb_free_entry (context, &ent);
489             continue;
490         }
491         if (parse_time_string_alloc (&ent.entry.pw_end,      e.pw_end) == -1) {
492             fprintf (stderr, "%s:%d:error parsing time (%s)\n",
493                      filename, line, e.pw_end);
494             hdb_free_entry (context, &ent);
495             continue;
496         }
497
498         if (parse_integer_alloc (&ent.entry.max_life,  e.max_life) == -1) {
499             fprintf (stderr, "%s:%d:error parsing lifetime (%s)\n",
500                      filename, line, e.max_life);
501             hdb_free_entry (context, &ent);
502             continue;
503
504         }
505         if (parse_integer_alloc (&ent.entry.max_renew, e.max_renew) == -1) {
506             fprintf (stderr, "%s:%d:error parsing lifetime (%s)\n",
507                      filename, line, e.max_renew);
508             hdb_free_entry (context, &ent);
509             continue;
510         }
511
512         if (parse_hdbflags2int (&ent.entry.flags, e.flags) != 1) {
513             fprintf (stderr, "%s:%d:error parsing flags (%s)\n",
514                      filename, line, e.flags);
515             hdb_free_entry (context, &ent);
516             continue;
517         }
518
519         if(parse_generation(e.generation, &ent.entry.generation) == -1) {
520             fprintf (stderr, "%s:%d:error parsing generation (%s)\n",
521                      filename, line, e.generation);
522             hdb_free_entry (context, &ent);
523             continue;
524         }
525
526         if(parse_extensions(e.extensions, &ent.entry.extensions) == -1) {
527             fprintf (stderr, "%s:%d:error parsing extension (%s)\n",
528                      filename, line, e.extensions);
529             hdb_free_entry (context, &ent);
530             continue;
531         }
532
533         ret = db->hdb_store(context, db, HDB_F_REPLACE, &ent);
534         hdb_free_entry (context, &ent);
535         if (ret) {
536             krb5_warn(context, ret, "db_store");
537             break;
538         }
539     }
540     db->hdb_close(context, db);
541     fclose(f);
542     return ret != 0;
543 }
544
545
546 extern int local_flag;
547
548 static int
549 loadit(int mergep, const char *name, int argc, char **argv)
550 {
551     if(!local_flag) {
552         krb5_warnx(context, "%s is only available in local (-l) mode", name);
553         return 0;
554     }
555
556     return doit(argv[0], mergep);
557 }
558  
559 int
560 load(void *opt, int argc, char **argv)
561 {
562     return loadit(0, "load", argc, argv);
563 }
564  
565 int
566 merge(void *opt, int argc, char **argv)
567 {
568     return loadit(1, "merge", argc, argv);
569 }