/ kadmin / load.c
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  struct entry {
 39      char *principal;
 40      char *key;
 41      char *max_life;
 42      char *max_renew;
 43      char *created;
 44      char *modified;
 45      char *valid_start;
 46      char *valid_end;
 47      char *pw_end;
 48      char *flags;
 49      char *generation;
 50      char *extensions;
 51  };
 52  
 53  static char *
 54  skip_next(char *p)
 55  {
 56      while(*p && !isspace((unsigned char)*p))
 57  	p++;
 58      *p++ = 0;
 59      while(*p && isspace((unsigned char)*p))
 60  	p++;
 61      return p;
 62  }
 63  
 64  /*
 65   * Parse the time in `s', returning:
 66   * -1 if error parsing
 67   * 0  if none  present
 68   * 1  if parsed ok
 69   */
 70  
 71  static int
 72  parse_time_string(time_t *t, const char *s)
 73  {
 74      int year, month, date, hour, minute, second;
 75      struct tm tm;
 76  
 77      if(strcmp(s, "-") == 0)
 78  	return 0;
 79      if(sscanf(s, "%04d%02d%02d%02d%02d%02d",
 80  	      &year, &month, &date, &hour, &minute, &second) != 6)
 81  	return -1;
 82      tm.tm_year  = year - 1900;
 83      tm.tm_mon   = month - 1;
 84      tm.tm_mday  = date;
 85      tm.tm_hour  = hour;
 86      tm.tm_min   = minute;
 87      tm.tm_sec   = second;
 88      tm.tm_isdst = 0;
 89      *t = timegm(&tm);
 90      return 1;
 91  }
 92  
 93  /*
 94   * parse time, allocating space in *t if it's there
 95   */
 96  
 97  static int
 98  parse_time_string_alloc (time_t **t, const char *s)
 99  {
100      time_t tmp;
101      int ret;
102  
103      *t = NULL;
104      ret = parse_time_string (&tmp, s);
105      if (ret == 1) {
106  	*t = malloc (sizeof (**t));
107  	if (*t == NULL)
108  	    krb5_errx (context, 1, "malloc: out of memory");
109  	**t = tmp;
110      }
111      return ret;
112  }
113  
114  /*
115   * see parse_time_string for calling convention
116   */
117  
118  static int
119  parse_integer(unsigned int *u, const char *s)
120  {
121      if(strcmp(s, "-") == 0)
122  	return 0;
123      if (sscanf(s, "%u", u) != 1)
124  	return -1;
125      return 1;
126  }
127  
128  static int
129  parse_integer_alloc (unsigned int **u, const char *s)
130  {
131      unsigned int tmp;
132      int ret;
133  
134      *u = NULL;
135      ret = parse_integer (&tmp, s);
136      if (ret == 1) {
137  	*u = malloc (sizeof (**u));
138  	if (*u == NULL)
139  	    krb5_errx (context, 1, "malloc: out of memory");
140  	**u = tmp;
141      }
142      return ret;
143  }
144  
145  /*
146   * Parse dumped keys in `str' and store them in `ent'
147   * return -1 if parsing failed
148   */
149  
150  static int
151  parse_keys(hdb_entry *ent, char *str)
152  {
153      krb5_error_code ret;
154      int tmp;
155      char *p;
156      size_t i;
157  
158      p = strsep(&str, ":");
159      if (sscanf(p, "%d", &tmp) != 1)
160  	return 1;
161      ent->kvno = tmp;
162      p = strsep(&str, ":");
163      while(p){
164  	Key *key;
165  	key = realloc(ent->keys.val,
166  		      (ent->keys.len + 1) * sizeof(*ent->keys.val));
167  	if(key == NULL)
168  	    krb5_errx (context, 1, "realloc: out of memory");
169  	ent->keys.val = key;
170  	key = ent->keys.val + ent->keys.len;
171  	ent->keys.len++;
172  	memset(key, 0, sizeof(*key));
173  	if(sscanf(p, "%d", &tmp) == 1) {
174  	    key->mkvno = malloc(sizeof(*key->mkvno));
175  	    *key->mkvno = tmp;
176  	} else
177  	    key->mkvno = NULL;
178  	p = strsep(&str, ":");
179  	if (sscanf(p, "%d", &tmp) != 1)
180  	    return 1;
181  	key->key.keytype = tmp;
182  	p = strsep(&str, ":");
183  	ret = krb5_data_alloc(&key->key.keyvalue, (strlen(p) - 1) / 2 + 1);
184  	if (ret)
185  	    krb5_err (context, 1, ret, "krb5_data_alloc");
186  	for(i = 0; i < strlen(p); i += 2) {
187  	    if(sscanf(p + i, "%02x", &tmp) != 1)
188  		return 1;
189  	    ((u_char*)key->key.keyvalue.data)[i / 2] = tmp;
190  	}
191  	p = strsep(&str, ":");
192  	if(strcmp(p, "-") != 0){
193  	    unsigned type;
194  	    size_t p_len;
195  
196  	    if(sscanf(p, "%u/", &type) != 1)
197  		return 1;
198  	    p = strchr(p, '/');
199  	    if(p == NULL)
200  		return 1;
201  	    p++;
202  	    p_len = strlen(p);
203  
204  	    key->salt = calloc(1, sizeof(*key->salt));
205  	    if (key->salt == NULL)
206  		krb5_errx (context, 1, "malloc: out of memory");
207  	    key->salt->type = type;
208  
209  	    if (p_len) {
210  		if(*p == '\"') {
211  		    ret = krb5_data_copy(&key->salt->salt, p + 1, p_len - 2);
212  		    if (ret)
213  			krb5_err (context, 1, ret, "krb5_data_copy");
214  		} else {
215  		    ret = krb5_data_alloc(&key->salt->salt,
216  					  (p_len - 1) / 2 + 1);
217  		    if (ret)
218  			krb5_err (context, 1, ret, "krb5_data_alloc");
219  		    for(i = 0; i < p_len; i += 2){
220  			if (sscanf(p + i, "%02x", &tmp) != 1)
221  			    return 1;
222  			((u_char*)key->salt->salt.data)[i / 2] = tmp;
223  		    }
224  		}
225  	    } else
226  		krb5_data_zero (&key->salt->salt);
227  	}
228  	p = strsep(&str, ":");
229      }
230      return 0;
231  }
232  
233  /*
234   * see parse_time_string for calling convention
235   */
236  
237  static int
238  parse_event(Event *ev, char *s)
239  {
240      krb5_error_code ret;
241      char *p;
242  
243      if(strcmp(s, "-") == 0)
244  	return 0;
245      memset(ev, 0, sizeof(*ev));
246      p = strsep(&s, ":");
247      if(parse_time_string(&ev->time, p) != 1)
248  	return -1;
249      p = strsep(&s, ":");
250      ret = krb5_parse_name(context, p, &ev->principal);
251      if (ret)
252  	return -1;
253      return 1;
254  }
255  
256  static int
257  parse_event_alloc (Event **ev, char *s)
258  {
259      Event tmp;
260      int ret;
261  
262      *ev = NULL;
263      ret = parse_event (&tmp, s);
264      if (ret == 1) {
265  	*ev = malloc (sizeof (**ev));
266  	if (*ev == NULL)
267  	    krb5_errx (context, 1, "malloc: out of memory");
268  	**ev = tmp;
269      }
270      return ret;
271  }
272  
273  static int
274  parse_hdbflags2int(HDBFlags *f, const char *s)
275  {
276      int ret;
277      unsigned int tmp;
278  
279      ret = parse_integer (&tmp, s);
280      if (ret == 1)
281  	*f = int2HDBFlags (tmp);
282      return ret;
283  }
284  
285  static int
286  parse_generation(char *str, GENERATION **gen)
287  {
288      char *p;
289      int v;
290  
291      if(strcmp(str, "-") == 0 || *str == '\0') {
292  	*gen = NULL;
293  	return 0;
294      }
295      *gen = calloc(1, sizeof(**gen));
296  
297      p = strsep(&str, ":");
298      if(parse_time_string(&(*gen)->time, p) != 1)
299  	return -1;
300      p = strsep(&str, ":");
301      if(sscanf(p, "%d", &v) != 1)
302  	return -1;
303      (*gen)->usec = v;
304      p = strsep(&str, ":");
305      if(sscanf(p, "%d", &v) != 1)
306  	return -1;
307      (*gen)->gen = v - 1; /* XXX gets bumped in _hdb_store */
308      return 0;
309  }
310  
311  static int
312  parse_extensions(char *str, HDB_extensions **e)
313  {
314      char *p;
315      int ret;
316  
317      if(strcmp(str, "-") == 0 || *str == '\0') {
318  	*e = NULL;
319  	return 0;
320      }
321      *e = calloc(1, sizeof(**e));
322  
323      p = strsep(&str, ":");
324  
325      while (p) {
326  	HDB_extension ext;
327  	ssize_t len;
328  	void *d;
329  
330  	len = strlen(p);
331  	d = malloc(len);
332  
333  	len = hex_decode(p, d, len);
334  	if (len < 0) {
335  	    free(d);
336  	    return -1;
337  	}
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, int new_realm_name)
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  	line++;
399  
400  	p = s;
401  	while (isspace((unsigned char)*p))
402  	    p++;
403  
404  	e.principal = p;
405  	for(p = s; *p; p++){
406  	    if(*p == '\\')
407  		p++;
408  	    else if(isspace((unsigned char)*p)) {
409  		*p = 0;
410  		break;
411  	    }
412  	}
413  	p = skip_next(p);
414  
415  	e.key = p;
416  	p = skip_next(p);
417  
418  	e.created = p;
419  	p = skip_next(p);
420  
421  	e.modified = p;
422  	p = skip_next(p);
423  
424  	e.valid_start = p;
425  	p = skip_next(p);
426  
427  	e.valid_end = p;
428  	p = skip_next(p);
429  
430  	e.pw_end = p;
431  	p = skip_next(p);
432  
433  	e.max_life = p;
434  	p = skip_next(p);
435  
436  	e.max_renew = p;
437  	p = skip_next(p);
438  
439  	e.flags = p;
440  	p = skip_next(p);
441  
442  	e.generation = p;
443  	p = skip_next(p);
444  
445  	e.extensions = p;
446  	skip_next(p);
447  
448  	memset(&ent, 0, sizeof(ent));
449  	ret = krb5_parse_name(context, e.principal, &ent.entry.principal);
450  	if(ret) {
451  	    const char *msg = krb5_get_error_message(context, ret);
452  	    fprintf(stderr, "%s:%d:%s (%s)\n",
453  		    filename, line, msg, e.principal);
454  	    krb5_free_error_message(context, msg);
455  	    continue;
456  	}
457  
458  	if (parse_keys(&ent.entry, e.key)) {
459  	    fprintf (stderr, "%s:%d:error parsing keys (%s)\n",
460  		     filename, line, e.key);
461  	    hdb_free_entry (context, &ent);
462  	    continue;
463  	}
464  
465  	if (parse_event(&ent.entry.created_by, e.created) == -1) {
466  	    fprintf (stderr, "%s:%d:error parsing created event (%s)\n",
467  		     filename, line, e.created);
468  	    hdb_free_entry (context, &ent);
469  	    continue;
470  	}
471  	if (parse_event_alloc (&ent.entry.modified_by, e.modified) == -1) {
472  	    fprintf (stderr, "%s:%d:error parsing event (%s)\n",
473  		     filename, line, e.modified);
474  	    hdb_free_entry (context, &ent);
475  	    continue;
476  	}
477  	if (parse_time_string_alloc (&ent.entry.valid_start, e.valid_start) == -1) {
478  	    fprintf (stderr, "%s:%d:error parsing time (%s)\n",
479  		     filename, line, e.valid_start);
480  	    hdb_free_entry (context, &ent);
481  	    continue;
482  	}
483  	if (parse_time_string_alloc (&ent.entry.valid_end,   e.valid_end) == -1) {
484  	    fprintf (stderr, "%s:%d:error parsing time (%s)\n",
485  		     filename, line, e.valid_end);
486  	    hdb_free_entry (context, &ent);
487  	    continue;
488  	}
489  	if (parse_time_string_alloc (&ent.entry.pw_end,      e.pw_end) == -1) {
490  	    fprintf (stderr, "%s:%d:error parsing time (%s)\n",
491  		     filename, line, e.pw_end);
492  	    hdb_free_entry (context, &ent);
493  	    continue;
494  	}
495  
496  	if (parse_integer_alloc (&ent.entry.max_life,  e.max_life) == -1) {
497  	    fprintf (stderr, "%s:%d:error parsing lifetime (%s)\n",
498  		     filename, line, e.max_life);
499  	    hdb_free_entry (context, &ent);
500  	    continue;
501  
502  	}
503  	if (parse_integer_alloc (&ent.entry.max_renew, e.max_renew) == -1) {
504  	    fprintf (stderr, "%s:%d:error parsing lifetime (%s)\n",
505  		     filename, line, e.max_renew);
506  	    hdb_free_entry (context, &ent);
507  	    continue;
508  	}
509  
510  	if (parse_hdbflags2int (&ent.entry.flags, e.flags) != 1) {
511  	    fprintf (stderr, "%s:%d:error parsing flags (%s)\n",
512  		     filename, line, e.flags);
513  	    hdb_free_entry (context, &ent);
514  	    continue;
515  	}
516  
517  	if(parse_generation(e.generation, &ent.entry.generation) == -1) {
518  	    fprintf (stderr, "%s:%d:error parsing generation (%s)\n",
519  		     filename, line, e.generation);
520  	    hdb_free_entry (context, &ent);
521  	    continue;
522  	}
523  
524  	if(parse_extensions(e.extensions, &ent.entry.extensions) == -1) {
525  	    fprintf (stderr, "%s:%d:error parsing extension (%s)\n",
526  		     filename, line, e.extensions);
527  	    hdb_free_entry (context, &ent);
528  	    continue;
529  	}
530  
531  	if (new_realm_name) {
532  	    /* fix salt */
533  	    unsigned i;
534  	    Salt salt;
535  	    krb5_salt salt2;
536  	    memset(&salt, 0, sizeof(salt));
537  	    krb5_get_pw_salt(context, ent.entry.principal, &salt2);
538  	    salt.type = hdb_pw_salt;
539  	    salt.salt = salt2.saltvalue;
540  	    for(i = 0; i < ent.entry.keys.len; i++){
541  		if(ent.entry.keys.val[i].salt == NULL){
542  		    ent.entry.keys.val[i].salt =
543  		    malloc(sizeof(*ent.entry.keys.val[i].salt));
544  		    if(ent.entry.keys.val[i].salt == NULL)
545  			return ENOMEM;
546  		    ret = copy_Salt(&salt, ent.entry.keys.val[i].salt);
547  		    if(ret)
548  			break;
549  		}
550  	    }
551  	    krb5_free_salt(context, salt2);
552  	}
553  	if(ret) {
554  	    fprintf (stderr, "%s:%d:error fixing salt\n",
555  		     filename, line);
556  	    hdb_free_entry (context, &ent);
557  	    continue;
558  	}
559  
560  	ret = db->hdb_store(context, db, HDB_F_REPLACE, &ent);
561  	hdb_free_entry (context, &ent);
562  	if (ret) {
563  	    krb5_warn(context, ret, "db_store");
564  	    break;
565  	}
566      }
567      db->hdb_close(context, db);
568      fclose(f);
569      return ret != 0;
570  }
571  
572  
573  extern int local_flag;
574  
575  static int
576  loadit(int mergep, int new_realm_name, const char *name, int argc, char **argv)
577  {
578      if(!local_flag) {
579  	krb5_warnx(context, "%s is only available in local (-l) mode", name);
580  	return 0;
581      }
582  
583      return doit(argv[0], mergep, new_realm_name);
584  }
585  
586  int
587  load(struct load_options *opt, int argc, char **argv)
588  {
589      return loadit(0, opt->fix_salts_flag, "load", argc, argv);
590  }
591  
592  int
593  merge(struct merge_options *opt, int argc, char **argv)
594  {
595      return loadit(1, opt->fix_salts_flag, "merge", argc, argv);
596  }