Home | History | Annotate | Download | only in srv
      1 /*
      2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 
      7 /*
      8  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
      9  *
     10  *	Openvision retains the copyright to derivative works of
     11  *	this source code.  Do *NOT* create a derivative of this
     12  *	source code before consulting with your legal department.
     13  *	Do *NOT* integrate *ANY* of this source code into another
     14  *	product before consulting with your legal department.
     15  *
     16  *	For further information, read the top-level Openvision
     17  *	copyright which is contained in the top-level MIT Kerberos
     18  *	copyright.
     19  *
     20  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
     21  *
     22  */
     23 
     24 
     25 /*
     26  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
     27  *
     28  * $Id: server_init.c 18584 2006-09-13 20:30:23Z raeburn $
     29  * $Source$
     30  */
     31 
     32 #if !defined(lint) && !defined(__CODECENTER__)
     33 static char *rcsid = "$Header: /cvs/krbdev/krb5/src/lib/kadm5/srv/server_init.c,v 1.8 2002/10/15 15:40:49 epeisach Exp $";
     34 #endif
     35 
     36 #include <stdio.h>
     37 #include <stdlib.h>
     38 #include <errno.h>
     39 #include <com_err.h>
     40 #include "k5-int.h"		/* needed for gssapiP_krb5.h */
     41 #include <kadm5/admin.h>
     42 #include <krb5.h>
     43 #include "server_internal.h"
     44 #include <kdb/kdb_log.h>
     45 
     46 /*
     47  * Function check_handle
     48  *
     49  * Purpose: Check a server handle and return a com_err code if it is
     50  * invalid or 0 if it is valid.
     51  *
     52  * Arguments:
     53  *
     54  * 	handle		The server handle.
     55  */
     56 
     57 static int check_handle(void *handle)
     58 {
     59      CHECK_HANDLE(handle);
     60      return 0;
     61 }
     62 
     63 static int dup_db_args(kadm5_server_handle_t handle, char **db_args)
     64 {
     65     int count  = 0;
     66     int ret = 0;
     67 
     68     for (count=0; db_args && db_args[count]; count++);
     69     if (count == 0) {
     70 	handle->db_args = NULL;
     71 	goto clean_n_exit;
     72     }
     73 
     74     handle->db_args = calloc(sizeof(char*), count+1);
     75     if (handle->db_args == NULL) {
     76 	ret=ENOMEM;
     77 	goto clean_n_exit;
     78     }
     79 
     80     for (count=0; db_args[count]; count++) {
     81 	handle->db_args[count] = strdup(db_args[count]);
     82 	if (handle->db_args[count] == NULL) {
     83 	    ret = ENOMEM;
     84 	    goto clean_n_exit;
     85 	}
     86     }
     87 
     88  clean_n_exit:
     89     if (ret && handle->db_args) {
     90 	for (count=0; handle->db_args[count]; count++)
     91 	    free(handle->db_args[count]);
     92 
     93 	free(handle->db_args), handle->db_args = NULL;
     94     }
     95 
     96     return ret;
     97 }
     98 
     99 static void free_db_args(kadm5_server_handle_t handle)
    100 {
    101     int count;
    102 
    103     if (handle->db_args) {
    104 	for (count=0; handle->db_args[count]; count++)
    105 	    free(handle->db_args[count]);
    106 
    107 	free(handle->db_args), handle->db_args = NULL;
    108     }
    109 }
    110 
    111 kadm5_ret_t kadm5_init_with_password(char *client_name, char *pass,
    112 				     char *service_name,
    113 				     kadm5_config_params *params,
    114 				     krb5_ui_4 struct_version,
    115 				     krb5_ui_4 api_version,
    116 				     char **db_args,
    117 				     void **server_handle)
    118 {
    119      return kadm5_init(client_name, pass, service_name, params,
    120 		       struct_version, api_version, db_args,
    121 		       server_handle);
    122 }
    123 
    124 kadm5_ret_t kadm5_init_with_creds(char *client_name,
    125 				  krb5_ccache ccache,
    126 				  char *service_name,
    127 				  kadm5_config_params *params,
    128 				  krb5_ui_4 struct_version,
    129 				  krb5_ui_4 api_version,
    130 				  char **db_args,
    131 				  void **server_handle)
    132 {
    133      /*
    134       * A program calling init_with_creds *never* expects to prompt the
    135       * user.  Therefore, always pass a dummy password in case this is
    136       * KADM5_API_VERSION_1.  If this is KADM5_API_VERSION_2 and
    137       * MKEY_FROM_KBD is non-zero, return an error.
    138       */
    139      if (api_version == KADM5_API_VERSION_2 && params &&
    140 	 (params->mask & KADM5_CONFIG_MKEY_FROM_KBD) &&
    141 	 params->mkey_from_kbd)
    142 	  return KADM5_BAD_SERVER_PARAMS;
    143      return kadm5_init(client_name, NULL, service_name, params,
    144 		       struct_version, api_version, db_args,
    145 		       server_handle);
    146 }
    147 
    148 
    149 kadm5_ret_t kadm5_init_with_skey(char *client_name, char *keytab,
    150 				 char *service_name,
    151 				 kadm5_config_params *params,
    152 				 krb5_ui_4 struct_version,
    153 				 krb5_ui_4 api_version,
    154 				 char **db_args,
    155 				 void **server_handle)
    156 {
    157      /*
    158       * A program calling init_with_skey *never* expects to prompt the
    159       * user.  Therefore, always pass a dummy password in case this is
    160       * KADM5_API_VERSION_1.  If this is KADM5_API_VERSION_2 and
    161       * MKEY_FROM_KBD is non-zero, return an error.
    162       */
    163      if (api_version == KADM5_API_VERSION_2 && params &&
    164 	 (params->mask & KADM5_CONFIG_MKEY_FROM_KBD) &&
    165 	 params->mkey_from_kbd)
    166 	  return KADM5_BAD_SERVER_PARAMS;
    167      return kadm5_init(client_name, NULL, service_name, params,
    168 		       struct_version, api_version, db_args,
    169 		       server_handle);
    170 }
    171 
    172 /*
    173  * Solaris Kerberos:
    174  * A private extended version of kadm5_init which potentially
    175  * returns more information in case of an error.
    176  */
    177 kadm5_ret_t kadm5_init2(char *client_name, char *pass,
    178 		       char *service_name,
    179 		       kadm5_config_params *params_in,
    180 		       krb5_ui_4 struct_version,
    181 		       krb5_ui_4 api_version,
    182 		       char **db_args,
    183 		       void **server_handle,
    184 		       char **emsg)
    185 {
    186      int ret;
    187      kadm5_server_handle_t handle;
    188      kadm5_config_params params_local; /* for v1 compat */
    189 
    190     if (emsg)
    191 	*emsg = NULL;
    192 
    193     if (! server_handle)
    194 	 return EINVAL;
    195 
    196     if (! client_name)
    197 	 return EINVAL;
    198 
    199     if (! (handle = (kadm5_server_handle_t) malloc(sizeof *handle)))
    200 	 return ENOMEM;
    201     memset(handle, 0, sizeof(*handle));
    202 
    203     ret = dup_db_args(handle, db_args);
    204     if (ret) {
    205 	free(handle);
    206 	return ret;
    207     }
    208 
    209     ret = (int) krb5int_init_context_kdc(&(handle->context));
    210     if (ret) {
    211 	 free_db_args(handle);
    212 	 free(handle);
    213 	 return(ret);
    214     }
    215 
    216     handle->magic_number = KADM5_SERVER_HANDLE_MAGIC;
    217     handle->struct_version = struct_version;
    218     handle->api_version = api_version;
    219 
    220      /*
    221       * Verify the version numbers before proceeding; we can't use
    222       * CHECK_HANDLE because not all fields are set yet.
    223       */
    224      GENERIC_CHECK_HANDLE(handle, KADM5_OLD_SERVER_API_VERSION,
    225 			  KADM5_NEW_SERVER_API_VERSION);
    226 
    227      /*
    228       * Acquire relevant profile entries.  In version 2, merge values
    229       * in params_in with values from profile, based on
    230       * params_in->mask.
    231       *
    232       * In version 1, we've given a realm (which may be NULL) instead
    233       * of params_in.  So use that realm, make params_in contain an
    234       * empty mask, and behave like version 2.
    235       */
    236      memset((char *) &params_local, 0, sizeof(params_local));
    237      if (api_version == KADM5_API_VERSION_1) {
    238 	  params_local.realm = (char *) params_in;
    239 	  if (params_in)
    240 	       params_local.mask = KADM5_CONFIG_REALM;
    241 	  params_in = &params_local;
    242      }
    243 
    244 #if 0 /* Now that we look at krb5.conf as well as kdc.conf, we can
    245 	 expect to see admin_server being set sometimes.  */
    246 #define ILLEGAL_PARAMS (KADM5_CONFIG_ADMIN_SERVER)
    247      if (params_in && (params_in->mask & ILLEGAL_PARAMS)) {
    248 	  krb5_free_context(handle->context);
    249 	  free_db_args(handle);
    250 	  free(handle);
    251 	  return KADM5_BAD_SERVER_PARAMS;
    252      }
    253 #endif
    254 
    255      ret = kadm5_get_config_params(handle->context, 1, params_in,
    256 				       &handle->params);
    257      if (ret) {
    258 	  krb5_free_context(handle->context);
    259 	  free_db_args(handle);
    260 	  free(handle);
    261 	  return(ret);
    262      }
    263 
    264 #define REQUIRED_PARAMS (KADM5_CONFIG_REALM | KADM5_CONFIG_DBNAME | \
    265 			 KADM5_CONFIG_ADBNAME | \
    266 			 KADM5_CONFIG_ADB_LOCKFILE | \
    267 			 KADM5_CONFIG_ENCTYPE | \
    268 			 KADM5_CONFIG_FLAGS | \
    269 			 KADM5_CONFIG_MAX_LIFE | KADM5_CONFIG_MAX_RLIFE | \
    270 			 KADM5_CONFIG_EXPIRATION | KADM5_CONFIG_ENCTYPES)
    271 
    272      if ((handle->params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) {
    273 	  kadm5_free_config_params(handle->context, &handle->params);
    274 	  krb5_free_context(handle->context);
    275 	  free_db_args(handle);
    276 	  free(handle);
    277 	  return KADM5_MISSING_CONF_PARAMS;
    278      }
    279 
    280      ret = krb5_set_default_realm(handle->context, handle->params.realm);
    281      if (ret) {
    282 	  kadm5_free_config_params(handle->context, &handle->params);
    283 	  krb5_free_context(handle->context);
    284 	  free_db_args(handle);
    285 	  free(handle);
    286 	  return ret;
    287      }
    288 
    289     ret = krb5_db_open(handle->context, db_args,
    290 		       KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN);
    291     if (ret) {
    292 	 if (emsg) {
    293 		 const char *m = krb5_get_error_message(handle->context, ret);
    294 		 *emsg = strdup(m);
    295 		 krb5_free_error_message(handle->context, m);
    296 	 }
    297 	 kadm5_free_config_params(handle->context, &handle->params);
    298 	 krb5_free_context(handle->context);
    299 	 free_db_args(handle);
    300 	 free(handle);
    301 	 return(ret);
    302     }
    303 
    304     if ((ret = krb5_parse_name(handle->context, client_name,
    305 			       &handle->current_caller))) {
    306 	 krb5_db_fini(handle->context);
    307 	 kadm5_free_config_params(handle->context, &handle->params);
    308 	 krb5_free_context(handle->context);
    309 	 free_db_args(handle);
    310 	 free(handle);
    311 	 return ret;
    312     }
    313 
    314     if (! (handle->lhandle = malloc(sizeof(*handle)))) {
    315 	 krb5_db_fini(handle->context);
    316 	 kadm5_free_config_params(handle->context, &handle->params);
    317 	 krb5_free_context(handle->context);
    318 	 free_db_args(handle);
    319 	 free(handle);
    320 	 return ENOMEM;
    321     }
    322     *handle->lhandle = *handle;
    323     handle->lhandle->api_version = KADM5_API_VERSION_2;
    324     handle->lhandle->struct_version = KADM5_STRUCT_VERSION;
    325     handle->lhandle->lhandle = handle->lhandle;
    326 
    327     /* can't check the handle until current_caller is set */
    328     ret = check_handle((void *) handle);
    329     if (ret) {
    330 	krb5_db_fini(handle->context);
    331 	kadm5_free_config_params(handle->context, &handle->params);
    332 	krb5_free_context(handle->context);
    333 	free_db_args(handle);
    334 	free(handle);
    335 	return ret;
    336     }
    337 
    338     /*
    339      * The KADM5_API_VERSION_1 spec said "If pass (or keytab) is NULL
    340      * or an empty string, reads the master password from [the stash
    341      * file].  Otherwise, the non-NULL password is ignored and the
    342      * user is prompted for it via the tty."  However, the code was
    343      * implemented the other way: when a non-NULL password was
    344      * provided, the stash file was used.  This is somewhat more
    345      * sensible, as then a local or remote client that provides a
    346      * password does not prompt the user.  This code maintains the
    347      * previous actual behavior, and not the old spec behavior,
    348      * because that is how the unit tests are written.
    349      *
    350      * In KADM5_API_VERSION_2, this decision is controlled by
    351      * params.
    352      *
    353      * kdb_init_master's third argument is "from_keyboard".
    354      */
    355     /*
    356      * Solaris Kerberos: Setting to an unknown enc type will make the function
    357      * read the encryption type in the stash file instead of assumming that it
    358      * is the default type.
    359      */
    360     if (handle->params.enctype == DEFAULT_KDC_ENCTYPE)
    361 	handle->params.enctype = ENCTYPE_UNKNOWN;
    362     ret = kdb_init_master(handle, handle->params.realm,
    363 			  (handle->api_version == KADM5_API_VERSION_1 ?
    364 			   ((pass == NULL) || !(strlen(pass))) :
    365 			   ((handle->params.mask & KADM5_CONFIG_MKEY_FROM_KBD)
    366 			    && handle->params.mkey_from_kbd)
    367 			));
    368     if (ret) {
    369 	krb5_db_fini(handle->context);
    370 	kadm5_free_config_params(handle->context, &handle->params);
    371 	krb5_free_context(handle->context);
    372 	free_db_args(handle);
    373 	free(handle);
    374 	return ret;
    375     }
    376     /*
    377      * Solaris Kerberos: We used the enc type that was discovered in the stash
    378      * file to associate with the other magic principals in the database.
    379      */
    380     handle->params.enctype = handle->master_keyblock.enctype;
    381 
    382     ret = kdb_init_hist(handle, handle->params.realm);
    383     if (ret) {
    384 	 krb5_db_fini(handle->context);
    385 	 kadm5_free_config_params(handle->context, &handle->params);
    386 	 krb5_free_context(handle->context);
    387 	 free_db_args(handle);
    388 	 free(handle);
    389 	 return ret;
    390     }
    391 
    392     ret = init_dict(&handle->params);
    393     if (ret) {
    394 	 krb5_db_fini(handle->context);
    395 	 krb5_free_principal(handle->context, handle->current_caller);
    396 	 kadm5_free_config_params(handle->context, &handle->params);
    397 	 krb5_free_context(handle->context);
    398 	 free_db_args(handle);
    399 	 free(handle);
    400 	 return ret;
    401     }
    402 
    403     *server_handle = (void *) handle;
    404 
    405     return KADM5_OK;
    406 }
    407 
    408 kadm5_ret_t kadm5_init(char *client_name, char *pass,
    409 		       char *service_name,
    410 		       kadm5_config_params *params_in,
    411 		       krb5_ui_4 struct_version,
    412 		       krb5_ui_4 api_version,
    413 		       char **db_args,
    414 		       void **server_handle) {
    415 	return (kadm5_init2(client_name, pass, service_name, params_in,
    416 	    struct_version, api_version, db_args, server_handle, NULL));
    417 
    418 }
    419 
    420 kadm5_ret_t kadm5_destroy(void *server_handle)
    421 {
    422     kadm5_server_handle_t handle = server_handle;
    423 
    424     CHECK_HANDLE(server_handle);
    425 
    426     destroy_dict();
    427 
    428     adb_policy_close(handle);
    429     krb5_db_fini(handle->context);
    430     krb5_free_principal(handle->context, handle->current_caller);
    431     kadm5_free_config_params(handle->context, &handle->params);
    432     krb5_free_context(handle->context);
    433     handle->magic_number = 0;
    434     free(handle->lhandle);
    435     free_db_args(handle);
    436     free(handle);
    437 
    438     return KADM5_OK;
    439 }
    440 
    441 kadm5_ret_t kadm5_lock(void *server_handle)
    442 {
    443     kadm5_server_handle_t handle = server_handle;
    444     kadm5_ret_t ret;
    445 
    446     CHECK_HANDLE(server_handle);
    447     ret = krb5_db_lock(handle->context, KRB5_DB_LOCKMODE_EXCLUSIVE);
    448     if (ret)
    449 	return ret;
    450 
    451     return KADM5_OK;
    452 }
    453 
    454 kadm5_ret_t kadm5_unlock(void *server_handle)
    455 {
    456     kadm5_server_handle_t handle = server_handle;
    457     kadm5_ret_t ret;
    458 
    459     CHECK_HANDLE(server_handle);
    460     ret = krb5_db_unlock(handle->context);
    461     if (ret)
    462 	return ret;
    463 
    464     return KADM5_OK;
    465 }
    466 
    467 kadm5_ret_t kadm5_flush(void *server_handle)
    468 {
    469      kadm5_server_handle_t handle = server_handle;
    470      kadm5_ret_t ret;
    471 
    472      CHECK_HANDLE(server_handle);
    473 
    474      if ((ret = krb5_db_fini(handle->context)) ||
    475 	 (ret = krb5_db_open(handle->context, handle->db_args,
    476 			     KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN)) ||
    477 	 (ret = adb_policy_close(handle)) ||
    478 	 (ret = adb_policy_init(handle))) {
    479 	  (void) kadm5_destroy(server_handle);
    480 	  return ret;
    481      }
    482      return KADM5_OK;
    483 }
    484 
    485 int _kadm5_check_handle(void *handle)
    486 {
    487      CHECK_HANDLE(handle);
    488      return 0;
    489 }
    490 
    491 #include "gssapiP_krb5.h"
    492 krb5_error_code kadm5_init_krb5_context (krb5_context *ctx)
    493 {
    494     /* Solaris Kerberos: not needed */
    495 #if 0 /************** Begin IFDEF'ed OUT *******************************/
    496     static int first_time = 1;
    497     if (first_time) {
    498 	krb5_error_code err;
    499 	err = krb5_gss_use_kdc_context();
    500 	if (err)
    501 	    return err;
    502 	first_time = 0;
    503     }
    504 #endif /**************** END IFDEF'ed OUT *******************************/
    505     return krb5int_init_context_kdc(ctx);
    506 }
    507 
    508 krb5_error_code
    509 kadm5_init_iprop(void *handle)
    510 {
    511 	kadm5_server_handle_t iprop_h;
    512 	krb5_error_code retval;
    513 
    514 	iprop_h = handle;
    515 	if (iprop_h->params.iprop_enabled) {
    516 		ulog_set_role(iprop_h->context, IPROP_MASTER);
    517 		if ((retval = ulog_map(iprop_h->context, &iprop_h->params,
    518 		    FKCOMMAND)) != 0)
    519 			return (retval);
    520 	}
    521 	return (0);
    522 }
    523