Home | History | Annotate | Download | only in dbutil
      1 /*
      2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 /*
      7  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
      8  *
      9  * $Id: kadm5_create.c,v 1.6 1998/10/30 02:52:37 marc Exp $
     10  * $Source: /cvs/krbdev/krb5/src/kadmin/dbutil/kadm5_create.c,v $
     11  */
     12 
     13 /*
     14  * Copyright (C) 1998 by the FundsXpress, INC.
     15  *
     16  * All rights reserved.
     17  *
     18  * Export of this software from the United States of America may require
     19  * a specific license from the United States Government.  It is the
     20  * responsibility of any person or organization contemplating export to
     21  * obtain such a license before exporting.
     22  *
     23  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
     24  * distribute this software and its documentation for any purpose and
     25  * without fee is hereby granted, provided that the above copyright
     26  * notice appear in all copies and that both that copyright notice and
     27  * this permission notice appear in supporting documentation, and that
     28  * the name of FundsXpress. not be used in advertising or publicity pertaining
     29  * to distribution of the software without specific, written prior
     30  * permission.  FundsXpress makes no representations about the suitability of
     31  * this software for any purpose.  It is provided "as is" without express
     32  * or implied warranty.
     33  *
     34  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
     35  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
     36  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     37  */
     38 
     39 #include "string_table.h"
     40 
     41 #include <stdio.h>
     42 #include <stdlib.h>
     43 #include <string.h>
     44 #include <k5-int.h>
     45 #include <kdb.h>
     46 #include <kadm5/admin.h>
     47 #include <krb5/adm_proto.h>
     48 
     49 #include <krb5.h>
     50 #include <krb5/kdb.h>
     51 #include "kdb5_util.h"
     52 #include <libintl.h>
     53 
     54 int
     55 add_admin_old_princ(void *handle, krb5_context context,
     56 		    char *name, char *realm, int attrs, int lifetime);
     57 int
     58 add_admin_sname_princ(void *handle, krb5_context context,
     59     char *sname, int attrs, int lifetime);
     60 static int
     61 add_admin_princ(void *handle, krb5_context context,
     62     krb5_principal principal, int attrs, int lifetime);
     63 
     64 static int add_admin_princs(void *handle, krb5_context context, char *realm);
     65 
     66 #define ERR 1
     67 #define OK 0
     68 
     69 #define ADMIN_LIFETIME 60*60*3 /* 3 hours */
     70 #define CHANGEPW_LIFETIME 60*5 /* 5 minutes */
     71 
     72 extern char *progname;
     73 
     74 /*
     75  * Function: kadm5_create
     76  *
     77  * Purpose: create admin principals in KDC database
     78  *
     79  * Arguments:	params	(r) configuration parameters to use
     80  *
     81  * Effects:  Creates KADM5_ADMIN_SERVICE and KADM5_CHANGEPW_SERVICE
     82  * principals in the KDC database and sets their attributes
     83  * appropriately.
     84  */
     85 int kadm5_create(kadm5_config_params *params)
     86 {
     87      int retval;
     88      krb5_context context;
     89 
     90      kadm5_config_params lparams;
     91 
     92      if ((retval = kadm5_init_krb5_context(&context)))
     93 	  exit(ERR);
     94 
     95      (void) memset(&lparams, 0, sizeof (kadm5_config_params));
     96 
     97      /*
     98       * The lock file has to exist before calling kadm5_init, but
     99       * params->admin_lockfile may not be set yet...
    100       */
    101      if ((retval = kadm5_get_config_params(context, 1,
    102 					   params, &lparams))) {
    103 	com_err(progname, retval, gettext("while looking up the Kerberos configuration"));
    104 	  return 1;
    105      }
    106 
    107      retval = kadm5_create_magic_princs(&lparams, context);
    108 
    109      kadm5_free_config_params(context, &lparams);
    110      krb5_free_context(context);
    111 
    112      return retval;
    113 }
    114 
    115 int kadm5_create_magic_princs(kadm5_config_params *params,
    116 			      krb5_context context)
    117 {
    118      int retval;
    119      void *handle;
    120 
    121      retval = krb5_klog_init(context, "admin_server", progname, 0);
    122      if (retval)
    123 	  return retval;
    124      if ((retval = kadm5_init(progname, NULL, NULL, params,
    125 			      KADM5_STRUCT_VERSION,
    126 			      KADM5_API_VERSION_2,
    127 			      db5util_db_args,
    128 			      &handle))) {
    129 	com_err(progname, retval,  gettext("while initializing the Kerberos admin interface"));
    130 	  return retval;
    131      }
    132 
    133      retval = add_admin_princs(handle, context, params->realm);
    134 
    135      kadm5_destroy(handle);
    136 
    137      krb5_klog_close(context);
    138 
    139      return retval;
    140 }
    141 
    142 /*
    143  * Function: build_name_with_realm
    144  *
    145  * Purpose: concatenate a name and a realm to form a krb5 name
    146  *
    147  * Arguments:
    148  *
    149  * 	name	(input) the name
    150  * 	realm	(input) the realm
    151  *
    152  * Returns:
    153  *
    154  * 	pointer to name@realm, in allocated memory, or NULL if it
    155  * 	cannot be allocated
    156  *
    157  * Requires: both strings are null-terminated
    158  */
    159 static char *build_name_with_realm(char *name, char *realm)
    160 {
    161      char *n;
    162 
    163      n = (char *) malloc(strlen(name) + strlen(realm) + 2);
    164      sprintf(n, "%s@%s", name, realm);
    165      return n;
    166 }
    167 
    168 /*
    169  * Function: add_admin_princs
    170  *
    171  * Purpose: create admin principals
    172  *
    173  * Arguments:
    174  *
    175  * 	rseed		(input) random seed
    176  * 	realm		(input) realm, or NULL for default realm
    177  *      <return value>  (output) status, 0 for success, 1 for serious error
    178  *
    179  * Requires:
    180  *
    181  * Effects:
    182  *
    183  * add_admin_princs creates KADM5_ADMIN_SERVICE,
    184  * KADM5_CHANGEPW_SERVICE.  If any of these exist a message is
    185  * printed.  If any of these existing principal do not have the proper
    186  * attributes, a warning message is printed.
    187  */
    188 static int add_admin_princs(void *handle, krb5_context context, char *realm)
    189 {
    190   krb5_error_code ret = 0;
    191 
    192 /*
    193  * Solaris Kerberos:
    194  * The kadmin/admin principal is unused on Solaris. This principal is used
    195  * in AUTH_GSSAPI but Solaris doesn't support AUTH_GSSAPI. RPCSEC_GSS can only
    196  * be used with host-based principals.
    197  *
    198  */
    199 
    200 #if 0
    201   if ((ret = add_admin_old_princ(handle, context,
    202   		     KADM5_ADMIN_SERVICE, realm,
    203   		     KRB5_KDB_DISALLOW_TGT_BASED,
    204   		     ADMIN_LIFETIME)))
    205      goto clean_and_exit;
    206 #endif
    207 
    208 	if ((ret = add_admin_old_princ(handle, context,
    209 			     KADM5_CHANGEPW_SERVICE, realm,
    210 			     KRB5_KDB_DISALLOW_TGT_BASED |
    211 			     KRB5_KDB_PWCHANGE_SERVICE,
    212 			     CHANGEPW_LIFETIME)))
    213        goto clean_and_exit;
    214 
    215 	if ((ret = add_admin_sname_princ(handle, context,
    216 		    KADM5_ADMIN_HOST_SERVICE,
    217 		    KRB5_KDB_DISALLOW_TGT_BASED,
    218 		    ADMIN_LIFETIME)))
    219 		goto clean_and_exit;
    220 
    221 	if ((ret = add_admin_sname_princ(handle, context,
    222 		    KADM5_CHANGEPW_HOST_SERVICE,
    223 		    KRB5_KDB_DISALLOW_TGT_BASED |
    224 		    KRB5_KDB_PWCHANGE_SERVICE,
    225 		    ADMIN_LIFETIME)))
    226 		goto clean_and_exit;
    227 
    228 	if ((ret = add_admin_sname_princ(handle, context,
    229 		    KADM5_KIPROP_HOST_SERVICE,
    230 		    KRB5_KDB_DISALLOW_TGT_BASED,
    231 		    ADMIN_LIFETIME)))
    232 		goto clean_and_exit;
    233 
    234 clean_and_exit:
    235 
    236   return ret;
    237 }
    238 
    239 /*
    240  * Function: add_admin_princ
    241  *
    242  * Arguments:
    243  *
    244  * 	creator		(r) principal to use as "mod_by"
    245  * 	rseed		(r) seed for random key generator
    246  *	principal	(r) kerberos principal to add
    247  * 	attrs		(r) principal's attributes
    248  * 	lifetime	(r) principal's max life, or 0
    249  * 	not_unique	(r) error message for multiple entries, never used
    250  * 	exists		(r) warning message for principal exists
    251  * 	wrong_attrs	(r) warning message for wrong attributes
    252  *
    253  * Returns:
    254  *
    255  * 	OK on success
    256  * 	ERR on serious errors
    257  *
    258  * Effects:
    259  *
    260  * If the principal is not unique, not_unique is printed (but this
    261  * never happens).  If the principal exists, then exists is printed
    262  * and if the principals attributes != attrs, wrong_attrs is printed.
    263  * Otherwise, the principal is created with mod_by creator and
    264  * attributes attrs and max life of lifetime (if not zero).
    265  */
    266 
    267 static int add_admin_princ(void *handle, krb5_context context,
    268     krb5_principal principal, int attrs, int lifetime)
    269 {
    270      char *fullname;
    271      krb5_error_code ret;
    272      kadm5_principal_ent_rec ent;
    273 
    274      memset(&ent, 0, sizeof(ent));
    275 
    276 	if (krb5_unparse_name(context, principal, &fullname))
    277 		return ERR;
    278 
    279      ent.principal = principal;
    280      ent.max_life = lifetime;
    281      ent.attributes = attrs | KRB5_KDB_DISALLOW_ALL_TIX;
    282 
    283      ret = kadm5_create_principal(handle, &ent,
    284 				  (KADM5_PRINCIPAL | KADM5_MAX_LIFE |
    285 				   KADM5_ATTRIBUTES),
    286 				  "to-be-random");
    287      if (ret) {
    288 	  if (ret != KADM5_DUP) {
    289 	       com_err(progname, ret,
    290 			gettext(str_PUT_PRINC), fullname);
    291 	       krb5_free_principal(context, ent.principal);
    292 	       free(fullname);
    293 	       return ERR;
    294 	  }
    295      } else {
    296 	  /* only randomize key if we created the principal */
    297 
    298 	  /*
    299 	   * Solaris Kerberos:
    300 	   * Create kadmind principals with keys for all supported encryption types.
    301 	   * Follows a similar pattern to add_principal() in keytab.c.
    302 	   */
    303 	  krb5_enctype *tmpenc, *enctype = NULL;
    304 	  krb5_key_salt_tuple *keysalt;
    305 	  int num_ks, i;
    306 	  krb5_int32 normalsalttype;
    307 
    308 	  ret = krb5_get_permitted_enctypes(context, &enctype);
    309 	  if (ret || *enctype == NULL) {
    310 	       com_err(progname, ret,
    311 		   gettext("while getting list of permitted encryption types"));
    312 	       krb5_free_principal(context, ent.principal);
    313 	       free(fullname);
    314 	       return ERR;
    315 	  }
    316 
    317 	  /* Count the number of enc types */
    318 	  for (tmpenc = enctype, num_ks = 0; *tmpenc; tmpenc++)
    319 		num_ks++;
    320 
    321 	  keysalt = malloc (sizeof (krb5_key_salt_tuple) * num_ks);
    322 	  if (keysalt == NULL) {
    323 	       com_err(progname, ENOMEM,
    324 		   gettext("while generating list of key salt tuples"));
    325 	       krb5_free_ktypes(context, enctype);
    326 	       krb5_free_principal(context, ent.principal);
    327 	       free(fullname);
    328 	       return ERR;
    329 	  }
    330 
    331 	  ret = krb5_string_to_salttype("normal", &normalsalttype);
    332 	  if (ret) {
    333 	  	com_err(progname, ret,
    334 	  	 	gettext("while converting \"normal\" to a salttype"));
    335 		free(keysalt);
    336 		krb5_free_ktypes(context, enctype);
    337 	  	krb5_free_principal(context, ent.principal);
    338 	  	free(fullname);
    339 	  	return ERR;
    340 	  }
    341 
    342 	  /* Only create keys with "normal" salttype */
    343 	  for (i = 0; i < num_ks; i++) {
    344 		keysalt[i].ks_enctype = enctype[i];
    345 		keysalt[i].ks_salttype = normalsalttype;
    346 	  }
    347 
    348 	  ret = kadm5_randkey_principal_3(handle, ent.principal, FALSE, num_ks,
    349 	      keysalt, NULL, NULL);
    350 	  free(keysalt);
    351           krb5_free_ktypes (context, enctype);
    352 
    353 
    354 	  if (ret) {
    355 	       com_err(progname, ret,
    356 			gettext(str_RANDOM_KEY), fullname);
    357 	       krb5_free_principal(context, ent.principal);
    358 	       free(fullname);
    359 	       return ERR;
    360 	  }
    361 
    362 	  ent.attributes = attrs;
    363 	  ret = kadm5_modify_principal(handle, &ent, KADM5_ATTRIBUTES);
    364 	  if (ret) {
    365 	      com_err(progname, ret,
    366 	       gettext(str_PUT_PRINC), fullname);
    367 	       krb5_free_principal(context, ent.principal);
    368 	       free(fullname);
    369 	       return ERR;
    370 	  }
    371      }
    372 
    373      krb5_free_principal(context, ent.principal);
    374      free(fullname);
    375 
    376      return OK;
    377 }
    378 
    379 int
    380 add_admin_old_princ(void *handle, krb5_context context,
    381     char *name, char *realm, int attrs, int lifetime)
    382 {
    383 	char *fullname;
    384 	krb5_error_code ret;
    385 	krb5_principal principal;
    386 
    387 	fullname = build_name_with_realm(name, realm);
    388 	if (ret = krb5_parse_name(context, fullname, &principal)) {
    389 		com_err(progname, ret, gettext(str_PARSE_NAME));
    390 		return (ERR);
    391 	}
    392 
    393 	return (add_admin_princ(handle, context, principal, attrs, lifetime));
    394 }
    395 
    396 int
    397 add_admin_sname_princ(void *handle, krb5_context context,
    398 	     char *sname, int attrs, int lifetime)
    399 {
    400 	krb5_error_code ret;
    401 	krb5_principal principal;
    402 
    403 	if (ret = krb5_sname_to_principal(context, NULL, sname,
    404 					  KRB5_NT_SRV_HST, &principal)) {
    405 		com_err(progname, ret,
    406 			gettext("Could not get host based "
    407 				"service name for %s principal\n"), sname);
    408 		return (ERR);
    409 	}
    410 	return (add_admin_princ(handle, context, principal, attrs, lifetime));
    411 }
    412 
    413 
    414 
    415