Beispiel #1
0
/*
 * Create, initialize, and add a new ple structure to the global list
 */
static struct gssd_k5_kt_princ *
new_ple(krb5_context context, krb5_principal princ)
{
	struct gssd_k5_kt_princ *ple = NULL, *p;
	krb5_error_code code;
	char *default_realm;
	int is_default_realm = 0;

	ple = malloc(sizeof(struct gssd_k5_kt_princ));
	if (ple == NULL)
		goto outerr;
	memset(ple, 0, sizeof(*ple));

#ifdef HAVE_KRB5
	ple->realm = strndup(princ->realm.data,
			     princ->realm.length);
#else
	ple->realm = strdup(princ->realm);
#endif
	if (ple->realm == NULL)
		goto outerr;
	code = krb5_copy_principal(context, princ, &ple->princ);
	if (code)
		goto outerr;

	/*
	 * Add new entry onto the list (if this is the default
	 * realm, always add to the front of the list)
	 */

	code = krb5_get_default_realm(context, &default_realm);
	if (code == 0) {
		if (strcmp(ple->realm, default_realm) == 0)
			is_default_realm = 1;
		k5_free_default_realm(context, default_realm);
	}

	if (is_default_realm) {
		ple->next = gssd_k5_kt_princ_list;
		gssd_k5_kt_princ_list = ple;
	} else {
		p = gssd_k5_kt_princ_list;
		while (p != NULL && p->next != NULL)
			p = p->next;
		if (p == NULL)
			gssd_k5_kt_princ_list = ple;
		else
			p->next = ple;
	}

	return ple;
outerr:
	if (ple) {
		if (ple->realm)
			free(ple->realm);
		free(ple);
	}
	return NULL;
}
Beispiel #2
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;
}