int write_heimdal_enc_key(char **p, char *end, gss_ctx_id_t ctx)
{
	krb5_keyblock enc_key, *key;
	krb5_context context;
	krb5_error_code ret;
	int i;
	char *skd, *dkd, *k5err = NULL;
	int code = -1;

	if ((ret = krb5_init_context(&context))) {
		k5err = gssd_k5_err_msg(NULL, ret);
		printerr(0, "ERROR: initializing krb5_context: %s\n", k5err);
		goto out_err;
	}

	if ((ret = krb5_auth_con_getlocalsubkey(context,
						ctx->auth_context, &key))){
		k5err = gssd_k5_err_msg(context, ret);
		printerr(0, "ERROR: getting auth_context key: %s\n", k5err);
		goto out_err_free_context;
	}

	memset(&enc_key, 0, sizeof(enc_key));
	enc_key.keytype = key->keytype;
	/* XXX current kernel code only handles des-cbc-raw  (4) */
	if (enc_key.keytype != 4) {
		printerr(1, "WARN: write_heimdal_enc_key: "
			    "overriding heimdal keytype (%d => %d)\n",
			 enc_key.keytype, 4);
		enc_key.keytype = 4;
	}
	enc_key.keyvalue.length = key->keyvalue.length;
	if ((enc_key.keyvalue.data =
				calloc(1, enc_key.keyvalue.length)) == NULL) {
		k5err = gssd_k5_err_msg(context, ENOMEM);
		printerr(0, "ERROR: allocating memory for enc key: %s\n",
			 k5err);
		goto out_err_free_key;
	}
	skd = (char *) key->keyvalue.data;
	dkd = (char *) enc_key.keyvalue.data;
	for (i = 0; i < enc_key.keyvalue.length; i++)
		dkd[i] = skd[i] ^ 0xf0;
	if (write_heimdal_keyblock(p, end, &enc_key)) {
		goto out_err_free_enckey;
	}

	code = 0;

    out_err_free_enckey:
	krb5_free_keyblock_contents(context, &enc_key);
    out_err_free_key:
	krb5_free_keyblock(context, key);
    out_err_free_context:
	krb5_free_context(context);
    out_err:
	free(k5err);
	printerr(2, "write_heimdal_enc_key: %s\n", code ? "FAILED" : "SUCCESS");
	return(code);
}
int write_heimdal_seq_key(char **p, char *end, gss_ctx_id_t ctx)
{
	krb5_keyblock *key;
	krb5_context context;
	krb5_error_code ret;
	char *k5err = NULL;
	int code = -1;

	if ((ret = krb5_init_context(&context))) {
		k5err = gssd_k5_err_msg(NULL, ret);
		printerr(0, "ERROR: initializing krb5_context: %s\n", k5err);
		goto out_err;
	}

	if ((ret = krb5_auth_con_getlocalsubkey(context,
						ctx->auth_context, &key))){
		k5err = gssd_k5_err_msg(context, ret);
		printerr(0, "ERROR: getting auth_context key: %s\n", k5err);
		goto out_err_free_context;
	}

	/* XXX current kernel code only handles des-cbc-raw  (4) */
	if (key->keytype != 4) {
		printerr(1, "WARN: write_heimdal_seq_key: "
			    "overriding heimdal keytype (%d => %d)\n",
			 key->keytype, 4);
		key->keytype = 4;
	}

	if (write_heimdal_keyblock(p, end, key)) {
		goto out_err_free_key;
	}

	code = 0;

    out_err_free_key:
	krb5_free_keyblock(context, key);
    out_err_free_context:
	krb5_free_context(context);
    out_err:
	free(k5err);
	printerr(2, "write_heimdal_seq_key: %s\n", code ? "FAILED" : "SUCCESS");
	return(code);
}
Exemple #3
0
/*
 * Called upon exit.  Destroys machine credentials.
 */
void
gssd_destroy_krb5_machine_creds(void)
{
	krb5_context context;
	krb5_error_code code = 0;
	krb5_ccache ccache;
	struct gssd_k5_kt_princ *ple;
	char *k5err = NULL;

	code = krb5_init_context(&context);
	if (code) {
		k5err = gssd_k5_err_msg(NULL, code);
		printerr(0, "ERROR: %s while initializing krb5\n", k5err);
		goto out;
	}

	for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) {
		if (!ple->ccname)
			continue;
		if ((code = krb5_cc_resolve(context, ple->ccname, &ccache))) {
			k5err = gssd_k5_err_msg(context, code);
			printerr(0, "WARNING: %s while resolving credential "
				    "cache '%s' for destruction\n", k5err,
				    ple->ccname);
			continue;
		}

		if ((code = krb5_cc_destroy(context, ccache))) {
			k5err = gssd_k5_err_msg(context, code);
			printerr(0, "WARNING: %s while destroying credential "
				    "cache '%s'\n", k5err, ple->ccname);
		}
	}
  out:
	free(k5err);
	krb5_free_context(context);
}
Exemple #4
0
/*
 * Obtain (or refresh if necessary) Kerberos machine credentials
 */
int gssd_refresh_krb5_machine_credential(char *hostname,
					 struct gssd_k5_kt_princ *ple,
					 char *service)
{
	krb5_error_code code = 0;
	krb5_context context;
	krb5_keytab kt = NULL;
	int retval = 0;
	char *k5err = NULL;
	const char *svcnames[5] = { "$", "root", "nfs", "host", NULL };

	/*
	 * If a specific service name was specified, use it.
	 * Otherwise, use the default list.
	 */
	if (service != NULL && strcmp(service, "*") != 0) {
		svcnames[0] = service;
		svcnames[1] = NULL;
	}
	if (hostname == NULL && ple == NULL)
		return EINVAL;

	code = krb5_init_context(&context);
	if (code) {
		k5err = gssd_k5_err_msg(NULL, code);
		printerr(0, "ERROR: %s: %s while initializing krb5 context\n",
			 __func__, k5err);
		retval = code;
		gsh_free(k5err);
		goto out_wo_context;
	}

	code = krb5_kt_resolve(context, keytabfile, &kt);
	if (code != 0) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(0, "ERROR: %s: %s while resolving keytab '%s'\n",
			 __func__, k5err, keytabfile);
		gsh_free(k5err);
		goto out;
	}

	if (ple == NULL) {
		krb5_keytab_entry kte;

		code = find_keytab_entry(context, kt, hostname, &kte,
					 svcnames);
		if (code) {
			printerr(0,
				 "ERROR: %s: no usable keytab entry found "
				 "in keytab %s for connection with host %s\n",
				 __func__, keytabfile, hostname);
			retval = code;
			goto out;
		}

		ple = get_ple_by_princ(context, kte.principal);
		k5_free_kt_entry(context, &kte);
		if (ple == NULL) {
			char *pname;
			if ((krb5_unparse_name(context, kte.principal,
					       &pname))) {
				pname = NULL;
			}
			printerr(0,
				 "ERROR: %s: Could not locate or create ple struct for principal %s for connection with host %s\n",
				 __func__,
				 pname ? pname : "<unparsable>", hostname);
			if (pname)
				k5_free_unparsed_name(context, pname);
			goto out;
		}
	}
	retval = gssd_get_single_krb5_cred(context, kt, ple, 0);
 out:
	if (kt)
		krb5_kt_close(context, kt);
	krb5_free_context(context);
 out_wo_context:
	return retval;
}
Exemple #5
0
/*
 * Find a keytab entry to use for a given target hostname.
 * Tries to find the most appropriate keytab to use given the
 * name of the host we are trying to connect with.
 */
static int find_keytab_entry(krb5_context context, krb5_keytab kt,
			     const char *hostname, krb5_keytab_entry *kte,
			     const char **svcnames)
{
	krb5_error_code code;
	char **realmnames = NULL;
	char myhostname[NI_MAXHOST], targethostname[NI_MAXHOST];
	char myhostad[NI_MAXHOST + 1];
	int i, j, retval;
	char *default_realm = NULL;
	char *realm;
	char *k5err = NULL;
	int tried_all = 0, tried_default = 0;
	krb5_principal princ;

	/* Get full target hostname */
	retval =
	    get_full_hostname(hostname, targethostname, sizeof(targethostname));
	if (retval)
		goto out;

	/* Get full local hostname */
	retval = gethostname(myhostname, sizeof(myhostname));
	if (retval) {
		k5err = gssd_k5_err_msg(context, retval);
		printerr(1, "%s while getting local hostname\n", k5err);
		gsh_free(k5err);
		goto out;
	}

	/* Compute the active directory machine name HOST$ */
	strcpy(myhostad, myhostname);
	for (i = 0; myhostad[i] != 0; ++i)
		myhostad[i] = toupper(myhostad[i]);
	myhostad[i] = '$';
	myhostad[i + 1] = 0;

	retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname));
	if (retval)
		goto out;

	code = krb5_get_default_realm(context, &default_realm);
	if (code) {
		retval = code;
		k5err = gssd_k5_err_msg(context, code);
		printerr(1, "%s while getting default realm name\n", k5err);
		gsh_free(k5err);
		goto out;
	}

	/*
	 * Get the realm name(s) for the target hostname.
	 * In reality, this function currently only returns a
	 * single realm, but we code with the assumption that
	 * someday it may actually return a list.
	 */
	code = krb5_get_host_realm(context, targethostname, &realmnames);
	if (code) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(0, "ERROR: %s while getting realm(s) for host '%s'\n",
			 k5err, targethostname);
		gsh_free(k5err);
		retval = code;
		goto out;
	}

	/*
	 * Try the "appropriate" realm first, and if nothing found for that
	 * realm, try the default realm (if it hasn't already been tried).
	 */
	i = 0;
	realm = realmnames[i];
	while (1) {
		if (realm == NULL) {
			tried_all = 1;
			if (!tried_default)
				realm = default_realm;
		}
		if (tried_all && tried_default)
			break;
		if (strcmp(realm, default_realm) == 0)
			tried_default = 1;
		for (j = 0; svcnames[j] != NULL; j++) {
			char spn[300];

			/*
			 * The special svcname "$" means 'try the active
			 * directory machine account'
			 */
			if (strcmp(svcnames[j], "$") == 0) {
				snprintf(spn, sizeof(spn), "%s@%s", myhostad,
					 realm);
				code =
				    krb5_build_principal_ext(context, &princ,
							     strlen(realm),
							     realm,
							     strlen(myhostad),
							     myhostad, NULL);
			} else {
				snprintf(spn, sizeof(spn), "%s/%s@%s",
					 svcnames[j], myhostname, realm);
				code =
				    krb5_build_principal_ext(context, &princ,
							     strlen(realm),
							     realm,
							     strlen(svcnames
								    [j]),
							     svcnames[j],
							     strlen(myhostname),
							     myhostname, NULL);
			}

			if (code) {
				k5err = gssd_k5_err_msg(context, code);
				printerr(1,
					 "%s while building principal for '%s'\n",
					 k5err, spn);
				gsh_free(k5err);
				continue;
			}
			code = krb5_kt_get_entry(context, kt, princ, 0, 0, kte);
			krb5_free_principal(context, princ);
			if (code) {
				k5err = gssd_k5_err_msg(context, code);
				printerr(3,
					 "%s while getting keytab entry for '%s'\n",
					 k5err, spn);
				gsh_free(k5err);
			} else {
				printerr(3,
					 "Success getting keytab entry for '%s'\n",
					 spn);
				retval = 0;
				goto out;
			}
			retval = code;
		}
		/*
		 * Nothing found with our hostname instance, now look for
		 * names with any instance (they must have an instance)
		 */
		for (j = 0; svcnames[j] != NULL; j++) {
			int found = 0;
			if (strcmp(svcnames[j], "$") == 0)
				continue;
			code =
			    gssd_search_krb5_keytab(context, kt, realm,
						    svcnames[j], &found, kte);
			if (!code && found) {
				printerr(3,
					 "Success getting keytab entry for "
					 "%s/*@%s\n", svcnames[j], realm);
				retval = 0;
				goto out;
			}
		}
		if (!tried_all) {
			i++;
			realm = realmnames[i];
		}
	}
 out:
	if (default_realm)
		k5_free_default_realm(context, default_realm);
	if (realmnames)
		krb5_free_host_realm(context, realmnames);

	return retval;
}
Exemple #6
0
/*
 * Search the given keytab file looking for an entry with the given
 * service name and realm, ignoring hostname (instance).
 *
 * Returns:
 *	0 => No error
 *	non-zero => An error occurred
 *
 * If a keytab entry is found, "found" is set to one, and the keytab
 * entry is returned in "kte".  Otherwise, "found" is zero, and the
 * value of "kte" is unpredictable.
 */
static int gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt,
				   const char *realm, const char *service,
				   int *found, krb5_keytab_entry *kte)
{
	krb5_kt_cursor cursor;
	krb5_error_code code;
	struct gssd_k5_kt_princ *ple;
	int retval = -1, status;
	char kt_name[BUFSIZ];
	char *pname;
	char *k5err = NULL;

	if (found == NULL) {
		retval = EINVAL;
		goto out;
	}
	*found = 0;

	/*
	 * Look through each entry in the keytab file and determine
	 * if we might want to use it as machine credentials.  If so,
	 * save info in the global principal list (gssd_k5_kt_princ_list).
	 */
	code = krb5_kt_get_name(context, kt, kt_name, BUFSIZ);
	if (code != 0) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(0, "ERROR: %s attempting to get keytab name\n",
			 k5err);
		gsh_free(k5err);
		retval = code;
		goto out;
	}
	code = krb5_kt_start_seq_get(context, kt, &cursor);
	if (code != 0) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(0,
			 "ERROR: %s while beginning keytab scan "
			 "for keytab '%s'\n", k5err, kt_name);
		gsh_free(k5err);
		retval = code;
		goto out;
	}

	while ((code = krb5_kt_next_entry(context, kt, kte, &cursor)) == 0) {
		code = krb5_unparse_name(context, kte->principal, &pname);
		if (code != 0) {
			k5err = gssd_k5_err_msg(context, code);
			printerr(0,
				 "WARNING: Skipping keytab entry because "
				 "we failed to unparse principal name: %s\n",
				 k5err);
			k5_free_kt_entry(context, kte);
			gsh_free(k5err);
			continue;
		}
		printerr(4, "Processing keytab entry for principal '%s'\n",
			 pname);
		/* Use the first matching keytab entry found */
#ifdef HAVE_KRB5
		status =
		    realm_and_service_match(kte->principal, realm, service);
#else
		status =
		    realm_and_service_match(context, kte->principal, realm,
					    service);
#endif
		if (status) {
			printerr(4, "We WILL use this entry (%s)\n", pname);
			ple = get_ple_by_princ(context, kte->principal);
			/*
			 * Return, don't free, keytab entry if
			 * we were successful!
			 */
			if (ple == NULL) {
				retval = ENOMEM;
				k5_free_kt_entry(context, kte);
			} else {
				retval = 0;
				*found = 1;
			}
			k5_free_unparsed_name(context, pname);
			break;
		} else {
			printerr(4, "We will NOT use this entry (%s)\n", pname);
		}
		k5_free_unparsed_name(context, pname);
		k5_free_kt_entry(context, kte);
	}

	code = krb5_kt_end_seq_get(context, kt, &cursor);
	if (code != 0) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(0,
			 "WARNING: %s while ending keytab scan for "
			 "keytab '%s'\n", k5err, kt_name);
		gsh_free(k5err);
	}

	retval = 0;
 out:
	return retval;
}
Exemple #7
0
/*
 * Obtain credentials via a key in the keytab given
 * a keytab handle and a gssd_k5_kt_princ structure.
 * Checks to see if current credentials are expired,
 * if not, uses the keytab to obtain new credentials.
 *
 * Returns:
 *	0 => success (or credentials have not expired)
 *	nonzero => error
 */
static int gssd_get_single_krb5_cred(krb5_context context, krb5_keytab kt,
				     struct gssd_k5_kt_princ *ple, int nocache)
{
#if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS
	krb5_get_init_creds_opt *init_opts = NULL;
#else
	krb5_get_init_creds_opt options;
#endif
	krb5_get_init_creds_opt *opts;
	krb5_creds my_creds;
	krb5_ccache ccache = NULL;
	char kt_name[BUFSIZ];
	char cc_name[BUFSIZ];
	int code;
	time_t now = time(0);
	char *cache_type;
	char *pname = NULL;
	char *k5err = NULL;

	memset(&my_creds, 0, sizeof(my_creds));

	if (ple->ccname && ple->endtime > now && !nocache) {
		printerr(2, "INFO: Credentials in CC '%s' are good until %d\n",
			 ple->ccname, ple->endtime);
		code = 0;
		goto out;
	}

	code = krb5_kt_get_name(context, kt, kt_name, BUFSIZ);
	if (code != 0) {
		printerr(0,
			 "ERROR: Unable to get keytab name in "
			 "gssd_get_single_krb5_cred\n");
		goto out;
	}

	if ((krb5_unparse_name(context, ple->princ, &pname)))
		pname = NULL;

#if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS
	code = krb5_get_init_creds_opt_alloc(context, &init_opts);
	if (code) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(0, "ERROR: %s allocating gic options\n", k5err);
		goto out;
	}
	if (krb5_get_init_creds_opt_set_addressless(context, init_opts, 1))
		printerr(1,
			 "WARNING: Unable to set option for addressless "
			 "tickets.  May have problems behind a NAT.\n");
#ifdef TEST_SHORT_LIFETIME
	/* set a short lifetime (for debugging only!) */
	printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n");
	krb5_get_init_creds_opt_set_tkt_life(init_opts, 5 * 60);
#endif
	opts = init_opts;

#else /* HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS */

	krb5_get_init_creds_opt_init(&options);
	krb5_get_init_creds_opt_set_address_list(&options, NULL);
#ifdef TEST_SHORT_LIFETIME
	/* set a short lifetime (for debugging only!) */
	printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n");
	krb5_get_init_creds_opt_set_tkt_life(&options, 5 * 60);
#endif
	opts = &options;
#endif

	code = krb5_get_init_creds_keytab(context, &my_creds,
					  ple->princ, kt, 0,
					  NULL, opts);
	if (code != 0) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(1,
			 "WARNING: %s while getting initial ticket for "
			 "principal '%s' using keytab '%s'\n", k5err,
			 pname ? pname : "<unparsable>", kt_name);
		goto out;
	}

	/*
	 * Initialize cache file which we're going to be using
	 */

	if (use_memcache)
		cache_type = "MEMORY";
	else
		cache_type = "FILE";
	snprintf(cc_name, sizeof(cc_name), "%s:%s/%s%s_%s", cache_type,
		 ccachesearch[0], GSSD_DEFAULT_CRED_PREFIX,
		 GSSD_DEFAULT_MACHINE_CRED_SUFFIX, ple->realm);
	ple->endtime = my_creds.times.endtime;
	if (ple->ccname != NULL)
		gsh_free(ple->ccname);
	ple->ccname = gsh_strdup(cc_name);
	if (ple->ccname == NULL) {
		printerr(0,
			 "ERROR: no storage to duplicate credentials "
			 "cache name '%s'\n", cc_name);
		code = ENOMEM;
		goto out;
	}
	code = krb5_cc_resolve(context, cc_name, &ccache);
	if (code != 0) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(0, "ERROR: %s while opening credential cache '%s'\n",
			 k5err, cc_name);
		goto out;
	}
	code = krb5_cc_initialize(context, ccache, ple->princ);
	if (code != 0) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(0,
			 "ERROR: %s while initializing credential "
			 "cache '%s'\n", k5err, cc_name);
	}
	code = krb5_cc_store_cred(context, ccache, &my_creds);
	if (code != 0) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(0, "ERROR: %s while storing credentials in '%s'\n",
			 k5err, cc_name);
		goto out;
	}
	/* if we get this far, let gss mech know */
	gssd_set_krb5_ccache_name(cc_name);
	code = 0;
	printerr(2,
		 "Successfully obtained machine credentials for "
		 "principal '%s' stored in ccache '%s'\n", pname, cc_name);
 out:
#if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS
	if (init_opts)
		krb5_get_init_creds_opt_free(context, init_opts);
#endif
	if (pname)
		k5_free_unparsed_name(context, pname);
	if (ccache)
		krb5_cc_close(context, ccache);
	krb5_free_cred_contents(context, &my_creds);
	gsh_free(k5err);
	return code;
}
Exemple #8
0
/*
 * Obtain (or refresh if necessary) Kerberos machine credentials
 */
int
gssd_refresh_krb5_machine_credential(char *hostname,
				     struct gssd_k5_kt_princ *ple)
{
	krb5_error_code code = 0;
	krb5_context context;
	krb5_keytab kt = NULL;;
	int retval = 0;
	char *k5err = NULL;

	if (hostname == NULL && ple == NULL)
		return EINVAL;

	code = krb5_init_context(&context);
	if (code) {
		k5err = gssd_k5_err_msg(NULL, code);
		printerr(0, "ERROR: %s: %s while initializing krb5 context\n",
			 __func__, k5err);
		retval = code;
		goto out;
	}

	if ((code = krb5_kt_resolve(context, keytabfile, &kt))) {
		k5err = gssd_k5_err_msg(context, code);
		printerr(0, "ERROR: %s: %s while resolving keytab '%s'\n",
			 __func__, k5err, keytabfile);
		goto out;
	}

	if (ple == NULL) {
		krb5_keytab_entry kte;

		code = find_keytab_entry(context, kt, hostname, &kte);
		if (code) {
			printerr(0, "ERROR: %s: no usable keytab entry found "
				 "in keytab %s for connection with host %s\n",
				 __FUNCTION__, keytabfile, hostname);
			retval = code;
			goto out;
		}

		ple = get_ple_by_princ(context, kte.principal);
		k5_free_kt_entry(context, &kte);
		if (ple == NULL) {
			char *pname;
			if ((krb5_unparse_name(context, kte.principal, &pname))) {
				pname = NULL;
			}
			printerr(0, "ERROR: %s: Could not locate or create "
				 "ple struct for principal %s for connection "
				 "with host %s\n",
				 __FUNCTION__, pname ? pname : "<unparsable>",
				 hostname);
			if (pname) k5_free_unparsed_name(context, pname);
			goto out;
		}
	}
	retval = gssd_get_single_krb5_cred(context, kt, ple);
out:
	if (kt)
		krb5_kt_close(context, kt);
	krb5_free_context(context);
	free(k5err);
	return retval;
}