pam_krb5.c revision 147810
181477Smarkm/*-
2109069Snectar * This pam_krb5 module contains code that is:
3109069Snectar *   Copyright (c) Derrick J. Brashear, 1996. All rights reserved.
4109069Snectar *   Copyright (c) Frank Cusack, 1999-2001. All rights reserved.
5109069Snectar *   Copyright (c) Jacques A. Vidrine, 2000-2001. All rights reserved.
6109069Snectar *   Copyright (c) Nicolas Williams, 2001. All rights reserved.
7109069Snectar *   Copyright (c) Perot Systems Corporation, 2001. All rights reserved.
8109069Snectar *   Copyright (c) Mark R V Murray, 2001.  All rights reserved.
9140667Srwatson *   Copyright (c) Networks Associates Technology, Inc., 2002-2005.
10109069Snectar *       All rights reserved.
1194564Sdes *
1293984Sdes * Portions of this software were developed for the FreeBSD Project by
1393984Sdes * ThinkSec AS and NAI Labs, the Security Research Division of Network
1493984Sdes * Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
1593984Sdes * ("CBOSS"), as part of the DARPA CHATS research program.
16110274Sdes *
1781477Smarkm * Redistribution and use in source and binary forms, with or without
1881477Smarkm * modification, are permitted provided that the following conditions
1981477Smarkm * are met:
2081477Smarkm * 1. Redistributions of source code must retain the above copyright
21109069Snectar *    notices, and the entire permission notice in its entirety,
2281477Smarkm *    including the disclaimer of warranties.
2381477Smarkm * 2. Redistributions in binary form must reproduce the above copyright
2481477Smarkm *    notice, this list of conditions and the following disclaimer in the
2581477Smarkm *    documentation and/or other materials provided with the distribution.
2681477Smarkm * 3. The name of the author may not be used to endorse or promote
2781477Smarkm *    products derived from this software without specific prior
2881477Smarkm *    written permission.
29110274Sdes *
3081477Smarkm * ALTERNATIVELY, this product may be distributed under the terms of
3181477Smarkm * the GNU Public License, in which case the provisions of the GPL are
3281477Smarkm * required INSTEAD OF the above restrictions.  (This clause is
3381477Smarkm * necessary due to a potential bad interaction between the GPL and
3481477Smarkm * the restrictions contained in a BSD-style copyright.)
35110274Sdes *
3681477Smarkm * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
3781477Smarkm * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
3881477Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3981477Smarkm * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
4081477Smarkm * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
4181477Smarkm * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
4281477Smarkm * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4381477Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
4481477Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
4581477Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
4681477Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE.
4794564Sdes *
4881477Smarkm */
4981477Smarkm
5084218Sdillon#include <sys/cdefs.h>
5184218Sdillon__FBSDID("$FreeBSD: head/lib/libpam/modules/pam_krb5/pam_krb5.c 147810 2005-07-07 14:16:38Z kensmith $");
5284218Sdillon
5381477Smarkm#include <sys/types.h>
5481477Smarkm#include <sys/stat.h>
5581477Smarkm#include <errno.h>
5681477Smarkm#include <limits.h>
5781477Smarkm#include <pwd.h>
5881477Smarkm#include <stdio.h>
5981477Smarkm#include <stdlib.h>
6093984Sdes#include <string.h>
6181477Smarkm#include <syslog.h>
6281477Smarkm#include <unistd.h>
6381477Smarkm
6481477Smarkm#include <krb5.h>
6581477Smarkm#include <com_err.h>
6681477Smarkm
6781477Smarkm#define	PAM_SM_AUTH
6881477Smarkm#define	PAM_SM_ACCOUNT
6981477Smarkm#define	PAM_SM_PASSWORD
7081477Smarkm
7181477Smarkm#include <security/pam_appl.h>
7281477Smarkm#include <security/pam_modules.h>
7390229Sdes#include <security/pam_mod_misc.h>
74115465Sdes#include <security/openpam.h>
7581477Smarkm
7681477Smarkm#define	COMPAT_HEIMDAL
7781477Smarkm/* #define	COMPAT_MIT */
7881477Smarkm
7981477Smarkmstatic int	verify_krb_v5_tgt(krb5_context, krb5_ccache, char *, int);
8081477Smarkmstatic void	cleanup_cache(pam_handle_t *, void *, int);
8181477Smarkmstatic const	char *compat_princ_component(krb5_context, krb5_principal, int);
8281477Smarkmstatic void	compat_free_data_contents(krb5_context, krb5_data *);
8381477Smarkm
8481477Smarkm#define USER_PROMPT		"Username: "
8585485Ssobomax#define PASSWORD_PROMPT		"Password:"
8685485Ssobomax#define NEW_PASSWORD_PROMPT	"New Password:"
8781477Smarkm
88115465Sdes#define PAM_OPT_CCACHE		"ccache"
89140667Srwatson#define PAM_OPT_DEBUG		"debug"
90115465Sdes#define PAM_OPT_FORWARDABLE	"forwardable"
91115465Sdes#define PAM_OPT_NO_CCACHE	"no_ccache"
92115465Sdes#define PAM_OPT_REUSE_CCACHE	"reuse_ccache"
9381477Smarkm
9481477Smarkm/*
9581477Smarkm * authentication management
9681477Smarkm */
9781477SmarkmPAM_EXTERN int
9894564Sdespam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
99115465Sdes    int argc __unused, const char *argv[] __unused)
10081477Smarkm{
10181477Smarkm	krb5_error_code krbret;
10281477Smarkm	krb5_context pam_context;
10381477Smarkm	krb5_creds creds;
10481477Smarkm	krb5_principal princ;
105106864Snectar	krb5_ccache ccache;
10681477Smarkm	krb5_get_init_creds_opt opts;
10781477Smarkm	struct passwd *pwd;
10881477Smarkm	int retval;
109125650Sdes	void *ccache_data;
110123454Sdes	const char *user, *pass;
111125650Sdes	const void *sourceuser, *service;
112106864Snectar	char *principal, *princ_name, *ccache_name, luser[32], *srvdup;
11381477Smarkm
11481477Smarkm	retval = pam_get_user(pamh, &user, USER_PROMPT);
11581477Smarkm	if (retval != PAM_SUCCESS)
11694564Sdes		return (retval);
11781477Smarkm
11881477Smarkm	PAM_LOG("Got user: %s", user);
11981477Smarkm
120123454Sdes	retval = pam_get_item(pamh, PAM_RUSER, &sourceuser);
12181477Smarkm	if (retval != PAM_SUCCESS)
12294564Sdes		return (retval);
12381477Smarkm
124123454Sdes	PAM_LOG("Got ruser: %s", (const char *)sourceuser);
12581477Smarkm
12681477Smarkm	service = NULL;
127123454Sdes	pam_get_item(pamh, PAM_SERVICE, &service);
12881477Smarkm	if (service == NULL)
12981477Smarkm		service = "unknown";
13081477Smarkm
131123454Sdes	PAM_LOG("Got service: %s", (const char *)service);
13281477Smarkm
13381477Smarkm	krbret = krb5_init_context(&pam_context);
13481477Smarkm	if (krbret != 0) {
13581477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
13694564Sdes		return (PAM_SERVICE_ERR);
13781477Smarkm	}
13881477Smarkm
13981477Smarkm	PAM_LOG("Context initialised");
14081477Smarkm
14181477Smarkm	krb5_get_init_creds_opt_init(&opts);
14281477Smarkm
143115465Sdes	if (openpam_get_option(pamh, PAM_OPT_FORWARDABLE))
14481477Smarkm		krb5_get_init_creds_opt_set_forwardable(&opts, 1);
14581477Smarkm
14681477Smarkm	PAM_LOG("Credentials initialised");
14781477Smarkm
14881477Smarkm	krbret = krb5_cc_register(pam_context, &krb5_mcc_ops, FALSE);
14981477Smarkm	if (krbret != 0 && krbret != KRB5_CC_TYPE_EXISTS) {
15081477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
15181477Smarkm		retval = PAM_SERVICE_ERR;
15281477Smarkm		goto cleanup3;
15381477Smarkm	}
15481477Smarkm
15581477Smarkm	PAM_LOG("Done krb5_cc_register()");
15681477Smarkm
15781477Smarkm	/* Get principal name */
158115465Sdes	if (openpam_get_option(pamh, PAM_OPT_AUTH_AS_SELF))
159123454Sdes		asprintf(&principal, "%s/%s", (const char *)sourceuser, user);
16081477Smarkm	else
16181477Smarkm		principal = strdup(user);
16281477Smarkm
16381477Smarkm	PAM_LOG("Created principal: %s", principal);
16481477Smarkm
16581477Smarkm	krbret = krb5_parse_name(pam_context, principal, &princ);
16681477Smarkm	free(principal);
16781477Smarkm	if (krbret != 0) {
168106862Snectar		PAM_LOG("Error krb5_parse_name(): %s",
169106862Snectar		    krb5_get_err_text(pam_context, krbret));
17081477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
17181477Smarkm		retval = PAM_SERVICE_ERR;
17281477Smarkm		goto cleanup3;
17381477Smarkm	}
17481477Smarkm
17581477Smarkm	PAM_LOG("Done krb5_parse_name()");
17681477Smarkm
17781477Smarkm	/* Now convert the principal name into something human readable */
17881477Smarkm	princ_name = NULL;
17981477Smarkm	krbret = krb5_unparse_name(pam_context, princ, &princ_name);
18081477Smarkm	if (krbret != 0) {
181106862Snectar		PAM_LOG("Error krb5_unparse_name(): %s",
182106862Snectar		    krb5_get_err_text(pam_context, krbret));
18381477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
18481477Smarkm		retval = PAM_SERVICE_ERR;
18581477Smarkm		goto cleanup2;
18681477Smarkm	}
18781477Smarkm
18881477Smarkm	PAM_LOG("Got principal: %s", princ_name);
18981477Smarkm
19081477Smarkm	/* Get password */
19193984Sdes	retval = pam_get_authtok(pamh, PAM_AUTHTOK, &pass, PASSWORD_PROMPT);
19281477Smarkm	if (retval != PAM_SUCCESS)
19381477Smarkm		goto cleanup2;
19481477Smarkm
19581477Smarkm	PAM_LOG("Got password");
19681477Smarkm
19781477Smarkm	/* Verify the local user exists (AFTER getting the password) */
19881477Smarkm	if (strchr(user, '@')) {
19981477Smarkm		/* get a local account name for this principal */
20081477Smarkm		krbret = krb5_aname_to_localname(pam_context, princ,
20181477Smarkm		    sizeof(luser), luser);
20281477Smarkm		if (krbret != 0) {
20381477Smarkm			PAM_VERBOSE_ERROR("Kerberos 5 error");
20481477Smarkm			PAM_LOG("Error krb5_aname_to_localname(): %s",
205106862Snectar			    krb5_get_err_text(pam_context, krbret));
20681477Smarkm			retval = PAM_USER_UNKNOWN;
20781477Smarkm			goto cleanup2;
20881477Smarkm		}
20981477Smarkm
21081477Smarkm		retval = pam_set_item(pamh, PAM_USER, luser);
21181477Smarkm		if (retval != PAM_SUCCESS)
21281477Smarkm			goto cleanup2;
21381477Smarkm
21481477Smarkm		PAM_LOG("PAM_USER Redone");
21581477Smarkm	}
21681477Smarkm
21781477Smarkm	pwd = getpwnam(user);
21881477Smarkm	if (pwd == NULL) {
21981477Smarkm		retval = PAM_USER_UNKNOWN;
22081477Smarkm		goto cleanup2;
22181477Smarkm	}
22281477Smarkm
22381477Smarkm	PAM_LOG("Done getpwnam()");
22481477Smarkm
22581477Smarkm	/* Get a TGT */
22681477Smarkm	memset(&creds, 0, sizeof(krb5_creds));
22781477Smarkm	krbret = krb5_get_init_creds_password(pam_context, &creds, princ,
22881477Smarkm	    pass, NULL, pamh, 0, NULL, &opts);
22981477Smarkm	if (krbret != 0) {
23081477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
23181477Smarkm		PAM_LOG("Error krb5_get_init_creds_password(): %s",
232106862Snectar		    krb5_get_err_text(pam_context, krbret));
23381477Smarkm		retval = PAM_AUTH_ERR;
23481477Smarkm		goto cleanup2;
23581477Smarkm	}
23681477Smarkm
23781477Smarkm	PAM_LOG("Got TGT");
23881477Smarkm
239106864Snectar	/* Generate a temporary cache */
240106864Snectar	krbret = krb5_cc_gen_new(pam_context, &krb5_mcc_ops, &ccache);
24181477Smarkm	if (krbret != 0) {
24281477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
243106864Snectar		PAM_LOG("Error krb5_cc_gen_new(): %s",
244106862Snectar		    krb5_get_err_text(pam_context, krbret));
24581477Smarkm		retval = PAM_SERVICE_ERR;
24681477Smarkm		goto cleanup;
24781477Smarkm	}
24881477Smarkm	krbret = krb5_cc_initialize(pam_context, ccache, princ);
24981477Smarkm	if (krbret != 0) {
25081477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
251106862Snectar		PAM_LOG("Error krb5_cc_initialize(): %s",
252106862Snectar		    krb5_get_err_text(pam_context, krbret));
25381477Smarkm		retval = PAM_SERVICE_ERR;
25481477Smarkm		goto cleanup;
25581477Smarkm	}
25681477Smarkm	krbret = krb5_cc_store_cred(pam_context, ccache, &creds);
25781477Smarkm	if (krbret != 0) {
25881477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
259106862Snectar		PAM_LOG("Error krb5_cc_store_cred(): %s",
260106862Snectar		    krb5_get_err_text(pam_context, krbret));
26181477Smarkm		krb5_cc_destroy(pam_context, ccache);
26281477Smarkm		retval = PAM_SERVICE_ERR;
26381477Smarkm		goto cleanup;
26481477Smarkm	}
26581477Smarkm
26681477Smarkm	PAM_LOG("Credentials stashed");
26781477Smarkm
26881477Smarkm	/* Verify them */
26993984Sdes	if ((srvdup = strdup(service)) == NULL) {
27093984Sdes		retval = PAM_BUF_ERR;
27193984Sdes		goto cleanup;
27293984Sdes	}
27393984Sdes	krbret = verify_krb_v5_tgt(pam_context, ccache, srvdup,
274140667Srwatson	    openpam_get_option(pamh, PAM_OPT_DEBUG) ? 1 : 0);
27593984Sdes	free(srvdup);
27693984Sdes	if (krbret == -1) {
27781477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
27881477Smarkm		krb5_cc_destroy(pam_context, ccache);
27981477Smarkm		retval = PAM_AUTH_ERR;
28081477Smarkm		goto cleanup;
28181477Smarkm	}
28281477Smarkm
28381477Smarkm	PAM_LOG("Credentials stash verified");
28481477Smarkm
285125650Sdes	retval = pam_get_data(pamh, "ccache", &ccache_data);
28681477Smarkm	if (retval == PAM_SUCCESS) {
28781477Smarkm		krb5_cc_destroy(pam_context, ccache);
28881477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
28981477Smarkm		retval = PAM_AUTH_ERR;
29081477Smarkm		goto cleanup;
29181477Smarkm	}
29281477Smarkm
29381477Smarkm	PAM_LOG("Credentials stash not pre-existing");
29481477Smarkm
295106864Snectar	asprintf(&ccache_name, "%s:%s", krb5_cc_get_type(pam_context,
296106864Snectar		ccache), krb5_cc_get_name(pam_context, ccache));
297106864Snectar	if (ccache_name == NULL) {
298106864Snectar		PAM_VERBOSE_ERROR("Kerberos 5 error");
299106864Snectar		retval = PAM_BUF_ERR;
300106864Snectar		goto cleanup;
301106864Snectar	}
302106864Snectar	retval = pam_set_data(pamh, "ccache", ccache_name, cleanup_cache);
30381477Smarkm	if (retval != 0) {
30481477Smarkm		krb5_cc_destroy(pam_context, ccache);
30581477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
30681477Smarkm		retval = PAM_SERVICE_ERR;
30781477Smarkm		goto cleanup;
30881477Smarkm	}
30981477Smarkm
31081477Smarkm	PAM_LOG("Credentials stash saved");
31181477Smarkm
31281477Smarkmcleanup:
31381477Smarkm	krb5_free_cred_contents(pam_context, &creds);
31481477Smarkm	PAM_LOG("Done cleanup");
31581477Smarkmcleanup2:
31681477Smarkm	krb5_free_principal(pam_context, princ);
31781477Smarkm	PAM_LOG("Done cleanup2");
31881477Smarkmcleanup3:
31981477Smarkm	if (princ_name)
32081477Smarkm		free(princ_name);
32181477Smarkm
32281477Smarkm	krb5_free_context(pam_context);
32381477Smarkm
32481477Smarkm	PAM_LOG("Done cleanup3");
32581477Smarkm
32681477Smarkm	if (retval != PAM_SUCCESS)
32781477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 refuses you");
32881477Smarkm
32994564Sdes	return (retval);
33081477Smarkm}
33181477Smarkm
33281477SmarkmPAM_EXTERN int
33394564Sdespam_sm_setcred(pam_handle_t *pamh, int flags,
334115465Sdes    int argc __unused, const char *argv[] __unused)
33581477Smarkm{
336147810Skensmith#ifdef _FREEFALL_CONFIG
337147810Skensmith	return (PAM_SUCCESS);
338147810Skensmith#else
33981477Smarkm
34081477Smarkm	krb5_error_code krbret;
34181477Smarkm	krb5_context pam_context;
34281477Smarkm	krb5_principal princ;
34381477Smarkm	krb5_creds creds;
34481477Smarkm	krb5_ccache ccache_temp, ccache_perm;
34581477Smarkm	krb5_cc_cursor cursor;
34681477Smarkm	struct passwd *pwd = NULL;
34781477Smarkm	int retval;
348123454Sdes	const char *cache_name, *q;
349125650Sdes	const void *user;
350125650Sdes	void *cache_data;
351115465Sdes	char *cache_name_buf = NULL, *p;
35281477Smarkm
35381477Smarkm	uid_t euid;
35481477Smarkm	gid_t egid;
35581477Smarkm
35681477Smarkm	if (flags & PAM_DELETE_CRED)
35794564Sdes		return (PAM_SUCCESS);
35881477Smarkm
35981477Smarkm	if (flags & PAM_REFRESH_CRED)
36094564Sdes		return (PAM_SUCCESS);
36181477Smarkm
36281477Smarkm	if (flags & PAM_REINITIALIZE_CRED)
36394564Sdes		return (PAM_SUCCESS);
36481477Smarkm
36581477Smarkm	if (!(flags & PAM_ESTABLISH_CRED))
36694564Sdes		return (PAM_SERVICE_ERR);
36781477Smarkm
368140747Srwatson	/* If a persistent cache isn't desired, stop now. */
369140747Srwatson	if (openpam_get_option(pamh, PAM_OPT_NO_CCACHE))
370140747Srwatson		return (PAM_SUCCESS);
371140747Srwatson
37281477Smarkm	PAM_LOG("Establishing credentials");
37381477Smarkm
37481477Smarkm	/* Get username */
375123454Sdes	retval = pam_get_item(pamh, PAM_USER, &user);
37681477Smarkm	if (retval != PAM_SUCCESS)
37794564Sdes		return (retval);
37881477Smarkm
379123454Sdes	PAM_LOG("Got user: %s", (const char *)user);
38081477Smarkm
38181477Smarkm	krbret = krb5_init_context(&pam_context);
38281477Smarkm	if (krbret != 0) {
383106862Snectar		PAM_LOG("Error krb5_init_context() failed");
38494564Sdes		return (PAM_SERVICE_ERR);
38581477Smarkm	}
38681477Smarkm
38781477Smarkm	PAM_LOG("Context initialised");
38881477Smarkm
38981477Smarkm	euid = geteuid();	/* Usually 0 */
39081477Smarkm	egid = getegid();
39181477Smarkm
39281477Smarkm	PAM_LOG("Got euid, egid: %d %d", euid, egid);
39381477Smarkm
394106864Snectar	/* Retrieve the temporary cache */
395123454Sdes	retval = pam_get_data(pamh, "ccache", &cache_data);
396110056Snectar	if (retval != PAM_SUCCESS) {
397110056Snectar		retval = PAM_CRED_UNAVAIL;
39881477Smarkm		goto cleanup3;
399110056Snectar	}
400123454Sdes	krbret = krb5_cc_resolve(pam_context, cache_data, &ccache_temp);
401106864Snectar	if (krbret != 0) {
402123454Sdes		PAM_LOG("Error krb5_cc_resolve(\"%s\"): %s", (const char *)cache_data,
403106864Snectar		    krb5_get_err_text(pam_context, krbret));
404110056Snectar		retval = PAM_SERVICE_ERR;
405106864Snectar		goto cleanup3;
406106864Snectar	}
40781477Smarkm
40881477Smarkm	/* Get the uid. This should exist. */
40981477Smarkm	pwd = getpwnam(user);
41081477Smarkm	if (pwd == NULL) {
41181477Smarkm		retval = PAM_USER_UNKNOWN;
41281477Smarkm		goto cleanup3;
41381477Smarkm	}
41481477Smarkm
41581477Smarkm	PAM_LOG("Done getpwnam()");
41681477Smarkm
41781477Smarkm	/* Avoid following a symlink as root */
41881477Smarkm	if (setegid(pwd->pw_gid)) {
41981477Smarkm		retval = PAM_SERVICE_ERR;
42081477Smarkm		goto cleanup3;
42181477Smarkm	}
42281477Smarkm	if (seteuid(pwd->pw_uid)) {
42381477Smarkm		retval = PAM_SERVICE_ERR;
42481477Smarkm		goto cleanup3;
42581477Smarkm	}
42681477Smarkm
42781477Smarkm	PAM_LOG("Done setegid() & seteuid()");
42881477Smarkm
42981477Smarkm	/* Get the cache name */
430115465Sdes	cache_name = openpam_get_option(pamh, PAM_OPT_CCACHE);
431115465Sdes	if (cache_name == NULL) {
432115465Sdes		asprintf(&cache_name_buf, "FILE:/tmp/krb5cc_%d", pwd->pw_uid);
433115465Sdes		cache_name = cache_name_buf;
434115465Sdes	}
43581477Smarkm
43681477Smarkm	p = calloc(PATH_MAX + 16, sizeof(char));
43781477Smarkm	q = cache_name;
43881477Smarkm
43981477Smarkm	if (p == NULL) {
44081477Smarkm		PAM_LOG("Error malloc(): failure");
44181477Smarkm		retval = PAM_BUF_ERR;
44281477Smarkm		goto cleanup3;
44381477Smarkm	}
44481477Smarkm	cache_name = p;
44581477Smarkm
44681477Smarkm	/* convert %u and %p */
44781477Smarkm	while (*q) {
44881477Smarkm		if (*q == '%') {
44981477Smarkm			q++;
45081477Smarkm			if (*q == 'u') {
45181477Smarkm				sprintf(p, "%d", pwd->pw_uid);
45281477Smarkm				p += strlen(p);
45381477Smarkm			}
45481477Smarkm			else if (*q == 'p') {
45581477Smarkm				sprintf(p, "%d", getpid());
45681477Smarkm				p += strlen(p);
45781477Smarkm			}
45881477Smarkm			else {
45981477Smarkm				/* Not a special token */
46081477Smarkm				*p++ = '%';
46181477Smarkm				q--;
46281477Smarkm			}
46381477Smarkm			q++;
46481477Smarkm		}
46581477Smarkm		else {
46681477Smarkm			*p++ = *q++;
46781477Smarkm		}
46881477Smarkm	}
46981477Smarkm
47081477Smarkm	PAM_LOG("Got cache_name: %s", cache_name);
47181477Smarkm
47281477Smarkm	/* Initialize the new ccache */
47381477Smarkm	krbret = krb5_cc_get_principal(pam_context, ccache_temp, &princ);
47481477Smarkm	if (krbret != 0) {
47581477Smarkm		PAM_LOG("Error krb5_cc_get_principal(): %s",
476106862Snectar		    krb5_get_err_text(pam_context, krbret));
47781477Smarkm		retval = PAM_SERVICE_ERR;
47881477Smarkm		goto cleanup3;
47981477Smarkm	}
48081477Smarkm	krbret = krb5_cc_resolve(pam_context, cache_name, &ccache_perm);
48181477Smarkm	if (krbret != 0) {
482106862Snectar		PAM_LOG("Error krb5_cc_resolve(): %s",
483106862Snectar		    krb5_get_err_text(pam_context, krbret));
48481477Smarkm		retval = PAM_SERVICE_ERR;
48581477Smarkm		goto cleanup2;
48681477Smarkm	}
48781477Smarkm	krbret = krb5_cc_initialize(pam_context, ccache_perm, princ);
48881477Smarkm	if (krbret != 0) {
489106862Snectar		PAM_LOG("Error krb5_cc_initialize(): %s",
490106862Snectar		    krb5_get_err_text(pam_context, krbret));
49181477Smarkm		retval = PAM_SERVICE_ERR;
49281477Smarkm		goto cleanup2;
49381477Smarkm	}
49481477Smarkm
49581477Smarkm	PAM_LOG("Cache initialised");
49681477Smarkm
49781477Smarkm	/* Prepare for iteration over creds */
49881477Smarkm	krbret = krb5_cc_start_seq_get(pam_context, ccache_temp, &cursor);
49981477Smarkm	if (krbret != 0) {
500106862Snectar		PAM_LOG("Error krb5_cc_start_seq_get(): %s",
501106862Snectar		    krb5_get_err_text(pam_context, krbret));
50281477Smarkm		krb5_cc_destroy(pam_context, ccache_perm);
50381477Smarkm		retval = PAM_SERVICE_ERR;
50481477Smarkm		goto cleanup2;
50581477Smarkm	}
50681477Smarkm
50781477Smarkm	PAM_LOG("Prepared for iteration");
50881477Smarkm
50981477Smarkm	/* Copy the creds (should be two of them) */
51081477Smarkm	while ((krbret = krb5_cc_next_cred(pam_context, ccache_temp,
51181477Smarkm				&cursor, &creds) == 0)) {
51281477Smarkm		krbret = krb5_cc_store_cred(pam_context, ccache_perm, &creds);
51381477Smarkm		if (krbret != 0) {
51481477Smarkm			PAM_LOG("Error krb5_cc_store_cred(): %s",
515106862Snectar			    krb5_get_err_text(pam_context, krbret));
51681477Smarkm			krb5_cc_destroy(pam_context, ccache_perm);
51781477Smarkm			krb5_free_cred_contents(pam_context, &creds);
51881477Smarkm			retval = PAM_SERVICE_ERR;
51981477Smarkm			goto cleanup2;
52081477Smarkm		}
52181477Smarkm		krb5_free_cred_contents(pam_context, &creds);
52281477Smarkm		PAM_LOG("Iteration");
52381477Smarkm	}
52481477Smarkm	krb5_cc_end_seq_get(pam_context, ccache_temp, &cursor);
52581477Smarkm
52681477Smarkm	PAM_LOG("Done iterating");
52781477Smarkm
52881477Smarkm	if (strstr(cache_name, "FILE:") == cache_name) {
52981477Smarkm		if (chown(&cache_name[5], pwd->pw_uid, pwd->pw_gid) == -1) {
53081477Smarkm			PAM_LOG("Error chown(): %s", strerror(errno));
53181477Smarkm			krb5_cc_destroy(pam_context, ccache_perm);
53281477Smarkm			retval = PAM_SERVICE_ERR;
53381477Smarkm			goto cleanup2;
53481477Smarkm		}
53581477Smarkm		PAM_LOG("Done chown()");
53681477Smarkm
53781477Smarkm		if (chmod(&cache_name[5], (S_IRUSR | S_IWUSR)) == -1) {
53881477Smarkm			PAM_LOG("Error chmod(): %s", strerror(errno));
53981477Smarkm			krb5_cc_destroy(pam_context, ccache_perm);
54081477Smarkm			retval = PAM_SERVICE_ERR;
54181477Smarkm			goto cleanup2;
54281477Smarkm		}
54381477Smarkm		PAM_LOG("Done chmod()");
54481477Smarkm	}
54581477Smarkm
54681477Smarkm	krb5_cc_close(pam_context, ccache_perm);
54781477Smarkm
54881477Smarkm	PAM_LOG("Cache closed");
54981477Smarkm
550115465Sdes	retval = pam_setenv(pamh, "KRB5CCNAME", cache_name, 1);
551115465Sdes	if (retval != PAM_SUCCESS) {
552115465Sdes		PAM_LOG("Error pam_setenv(): %s", pam_strerror(pamh, retval));
55381477Smarkm		krb5_cc_destroy(pam_context, ccache_perm);
55481477Smarkm		retval = PAM_SERVICE_ERR;
55581477Smarkm		goto cleanup2;
55681477Smarkm	}
55781477Smarkm
55881477Smarkm	PAM_LOG("Environment done: KRB5CCNAME=%s", cache_name);
55981477Smarkm
56081477Smarkmcleanup2:
56181477Smarkm	krb5_free_principal(pam_context, princ);
56281477Smarkm	PAM_LOG("Done cleanup2");
56381477Smarkmcleanup3:
56481477Smarkm	krb5_free_context(pam_context);
56581477Smarkm	PAM_LOG("Done cleanup3");
56681477Smarkm
56781477Smarkm	seteuid(euid);
56881477Smarkm	setegid(egid);
56981477Smarkm
57081477Smarkm	PAM_LOG("Done seteuid() & setegid()");
57194564Sdes
572115465Sdes	if (cache_name_buf != NULL)
573115465Sdes		free(cache_name_buf);
574115465Sdes
57594564Sdes	return (retval);
576147810Skensmith#endif
57781477Smarkm}
57881477Smarkm
57994564Sdes/*
58081477Smarkm * account management
58181477Smarkm */
58281477SmarkmPAM_EXTERN int
58394564Sdespam_sm_acct_mgmt(pam_handle_t *pamh, int flags __unused,
584115465Sdes    int argc __unused, const char *argv[] __unused)
58581477Smarkm{
58681477Smarkm	krb5_error_code krbret;
58781477Smarkm	krb5_context pam_context;
58881477Smarkm	krb5_ccache ccache;
58981477Smarkm	krb5_principal princ;
59081477Smarkm	int retval;
591125650Sdes	const void *user;
592125650Sdes	void *ccache_name;
59381477Smarkm
594123454Sdes	retval = pam_get_item(pamh, PAM_USER, &user);
59581477Smarkm	if (retval != PAM_SUCCESS)
59694564Sdes		return (retval);
59781477Smarkm
598123454Sdes	PAM_LOG("Got user: %s", (const char *)user);
59981477Smarkm
600123454Sdes	retval = pam_get_data(pamh, "ccache", &ccache_name);
601110275Sdes	if (retval != PAM_SUCCESS)
602110275Sdes		return (PAM_SUCCESS);
603110275Sdes
604110275Sdes	PAM_LOG("Got credentials");
605110275Sdes
60681477Smarkm	krbret = krb5_init_context(&pam_context);
60781477Smarkm	if (krbret != 0) {
608106862Snectar		PAM_LOG("Error krb5_init_context() failed");
60994564Sdes		return (PAM_PERM_DENIED);
61081477Smarkm	}
61181477Smarkm
61281477Smarkm	PAM_LOG("Context initialised");
61381477Smarkm
614123454Sdes	krbret = krb5_cc_resolve(pam_context, (const char *)ccache_name, &ccache);
615106864Snectar	if (krbret != 0) {
616123454Sdes		PAM_LOG("Error krb5_cc_resolve(\"%s\"): %s", (const char *)ccache_name,
617106864Snectar		    krb5_get_err_text(pam_context, krbret));
618106864Snectar		krb5_free_context(pam_context);
619106864Snectar		return (PAM_PERM_DENIED);
620106864Snectar	}
621106864Snectar
622123454Sdes	PAM_LOG("Got ccache %s", (const char *)ccache_name);
623106864Snectar
624106864Snectar
62581477Smarkm	krbret = krb5_cc_get_principal(pam_context, ccache, &princ);
62681477Smarkm	if (krbret != 0) {
627106862Snectar		PAM_LOG("Error krb5_cc_get_principal(): %s",
628106862Snectar		    krb5_get_err_text(pam_context, krbret));
62981477Smarkm		retval = PAM_PERM_DENIED;;
63081477Smarkm		goto cleanup;
63181477Smarkm	}
63281477Smarkm
63381477Smarkm	PAM_LOG("Got principal");
63481477Smarkm
635123454Sdes	if (krb5_kuserok(pam_context, princ, (const char *)user))
63681477Smarkm		retval = PAM_SUCCESS;
63781477Smarkm	else
63881477Smarkm		retval = PAM_PERM_DENIED;
63981477Smarkm	krb5_free_principal(pam_context, princ);
64081477Smarkm
64181477Smarkm	PAM_LOG("Done kuserok()");
64281477Smarkm
64381477Smarkmcleanup:
64481477Smarkm	krb5_free_context(pam_context);
64581477Smarkm	PAM_LOG("Done cleanup");
64681477Smarkm
64794564Sdes	return (retval);
64881477Smarkm
64981477Smarkm}
65081477Smarkm
65194564Sdes/*
65281477Smarkm * password management
65381477Smarkm */
65481477SmarkmPAM_EXTERN int
65594564Sdespam_sm_chauthtok(pam_handle_t *pamh, int flags,
656115465Sdes    int argc __unused, const char *argv[] __unused)
65781477Smarkm{
65881477Smarkm	krb5_error_code krbret;
65981477Smarkm	krb5_context pam_context;
66081477Smarkm	krb5_creds creds;
66181477Smarkm	krb5_principal princ;
66281477Smarkm	krb5_get_init_creds_opt opts;
66381477Smarkm	krb5_data result_code_string, result_string;
66481477Smarkm	int result_code, retval;
665123454Sdes	const char *pass;
666123454Sdes	const void *user;
66793984Sdes	char *princ_name, *passdup;
66881477Smarkm
66981477Smarkm	if (!(flags & PAM_UPDATE_AUTHTOK))
67094564Sdes		return (PAM_AUTHTOK_ERR);
67181477Smarkm
672123454Sdes	retval = pam_get_item(pamh, PAM_USER, &user);
67381477Smarkm	if (retval != PAM_SUCCESS)
67494564Sdes		return (retval);
67581477Smarkm
676123454Sdes	PAM_LOG("Got user: %s", (const char *)user);
67781477Smarkm
67881477Smarkm	krbret = krb5_init_context(&pam_context);
67981477Smarkm	if (krbret != 0) {
680106862Snectar		PAM_LOG("Error krb5_init_context() failed");
68194564Sdes		return (PAM_SERVICE_ERR);
68281477Smarkm	}
68381477Smarkm
68481477Smarkm	PAM_LOG("Context initialised");
68581477Smarkm
68681477Smarkm	krb5_get_init_creds_opt_init(&opts);
68781477Smarkm
68881477Smarkm	PAM_LOG("Credentials options initialised");
68981477Smarkm
69081477Smarkm	/* Get principal name */
691123454Sdes	krbret = krb5_parse_name(pam_context, (const char *)user, &princ);
69281477Smarkm	if (krbret != 0) {
693106862Snectar		PAM_LOG("Error krb5_parse_name(): %s",
694106862Snectar		    krb5_get_err_text(pam_context, krbret));
69581477Smarkm		retval = PAM_USER_UNKNOWN;
69681477Smarkm		goto cleanup3;
69781477Smarkm	}
69881477Smarkm
69981477Smarkm	/* Now convert the principal name into something human readable */
70081477Smarkm	princ_name = NULL;
70181477Smarkm	krbret = krb5_unparse_name(pam_context, princ, &princ_name);
70281477Smarkm	if (krbret != 0) {
703106862Snectar		PAM_LOG("Error krb5_unparse_name(): %s",
704106862Snectar		    krb5_get_err_text(pam_context, krbret));
70581477Smarkm		retval = PAM_SERVICE_ERR;
70681477Smarkm		goto cleanup2;
70781477Smarkm	}
70881477Smarkm
70981477Smarkm	PAM_LOG("Got principal: %s", princ_name);
71081477Smarkm
71181477Smarkm	/* Get password */
71293984Sdes	retval = pam_get_authtok(pamh, PAM_OLDAUTHTOK, &pass, PASSWORD_PROMPT);
71381477Smarkm	if (retval != PAM_SUCCESS)
71481477Smarkm		goto cleanup2;
71581477Smarkm
71681477Smarkm	PAM_LOG("Got password");
71781477Smarkm
71881477Smarkm	memset(&creds, 0, sizeof(krb5_creds));
71981477Smarkm	krbret = krb5_get_init_creds_password(pam_context, &creds, princ,
72081477Smarkm	    pass, NULL, pamh, 0, "kadmin/changepw", &opts);
72181477Smarkm	if (krbret != 0) {
722125650Sdes		PAM_LOG("Error krb5_get_init_creds_password(): %s",
723106862Snectar		    krb5_get_err_text(pam_context, krbret));
72481477Smarkm		retval = PAM_AUTH_ERR;
72581477Smarkm		goto cleanup2;
72681477Smarkm	}
72781477Smarkm
72881477Smarkm	PAM_LOG("Credentials established");
72981477Smarkm
73081477Smarkm	/* Now get the new password */
73193984Sdes	for (;;) {
73293984Sdes		retval = pam_get_authtok(pamh,
73393984Sdes		    PAM_AUTHTOK, &pass, NEW_PASSWORD_PROMPT);
73493984Sdes		if (retval != PAM_TRY_AGAIN)
73593984Sdes			break;
73693984Sdes		pam_error(pamh, "Mismatch; try again, EOF to quit.");
73793984Sdes	}
73881477Smarkm	if (retval != PAM_SUCCESS)
73981477Smarkm		goto cleanup;
74081477Smarkm
74193984Sdes	PAM_LOG("Got new password");
74281477Smarkm
74393984Sdes	/* Change it */
74493984Sdes	if ((passdup = strdup(pass)) == NULL) {
74593984Sdes		retval = PAM_BUF_ERR;
74681477Smarkm		goto cleanup;
74781477Smarkm	}
74893984Sdes	krbret = krb5_change_password(pam_context, &creds, passdup,
74981477Smarkm	    &result_code, &result_code_string, &result_string);
75093984Sdes	free(passdup);
75181477Smarkm	if (krbret != 0) {
75281477Smarkm		PAM_LOG("Error krb5_change_password(): %s",
753106862Snectar		    krb5_get_err_text(pam_context, krbret));
75481477Smarkm		retval = PAM_AUTHTOK_ERR;
75581477Smarkm		goto cleanup;
75681477Smarkm	}
75781477Smarkm	if (result_code) {
75881477Smarkm		PAM_LOG("Error krb5_change_password(): (result_code)");
75981477Smarkm		retval = PAM_AUTHTOK_ERR;
76081477Smarkm		goto cleanup;
76181477Smarkm	}
76281477Smarkm
76381477Smarkm	PAM_LOG("Password changed");
76481477Smarkm
76581477Smarkm	if (result_string.data)
76681477Smarkm		free(result_string.data);
76781477Smarkm	if (result_code_string.data)
76881477Smarkm		free(result_code_string.data);
76981477Smarkm
77081477Smarkmcleanup:
77181477Smarkm	krb5_free_cred_contents(pam_context, &creds);
77281477Smarkm	PAM_LOG("Done cleanup");
77381477Smarkmcleanup2:
77481477Smarkm	krb5_free_principal(pam_context, princ);
77581477Smarkm	PAM_LOG("Done cleanup2");
77681477Smarkmcleanup3:
77781477Smarkm	if (princ_name)
77881477Smarkm		free(princ_name);
77981477Smarkm
78081477Smarkm	krb5_free_context(pam_context);
78181477Smarkm
78281477Smarkm	PAM_LOG("Done cleanup3");
78381477Smarkm
78494564Sdes	return (retval);
78581477Smarkm}
78681477Smarkm
78781477SmarkmPAM_MODULE_ENTRY("pam_krb5");
78881477Smarkm
78981477Smarkm/*
79081477Smarkm * This routine with some modification is from the MIT V5B6 appl/bsd/login.c
79181477Smarkm * Modified by Sam Hartman <hartmans@mit.edu> to support PAM services
79281477Smarkm * for Debian.
79381477Smarkm *
79481477Smarkm * Verify the Kerberos ticket-granting ticket just retrieved for the
79581477Smarkm * user.  If the Kerberos server doesn't respond, assume the user is
79681477Smarkm * trying to fake us out (since we DID just get a TGT from what is
79781477Smarkm * supposedly our KDC).  If the host/<host> service is unknown (i.e.,
79881477Smarkm * the local keytab doesn't have it), and we cannot find another
79981477Smarkm * service we do have, let her in.
80081477Smarkm *
80181477Smarkm * Returns 1 for confirmation, -1 for failure, 0 for uncertainty.
80281477Smarkm */
803111985Smarkm/* ARGSUSED */
80481477Smarkmstatic int
80581477Smarkmverify_krb_v5_tgt(krb5_context context, krb5_ccache ccache,
80681477Smarkm    char *pam_service, int debug)
80781477Smarkm{
80881477Smarkm	krb5_error_code retval;
80981477Smarkm	krb5_principal princ;
81081477Smarkm	krb5_keyblock *keyblock;
81181477Smarkm	krb5_data packet;
81281477Smarkm	krb5_auth_context auth_context;
81389760Smarkm	char phost[BUFSIZ];
81489760Smarkm	const char *services[3], **service;
81581477Smarkm
81681477Smarkm	packet.data = 0;
81781477Smarkm
81881477Smarkm	/* If possible we want to try and verify the ticket we have
81981477Smarkm	 * received against a keytab.  We will try multiple service
82081477Smarkm	 * principals, including at least the host principal and the PAM
82181477Smarkm	 * service principal.  The host principal is preferred because access
82281477Smarkm	 * to that key is generally sufficient to compromise root, while the
82381477Smarkm	 * service key for this PAM service may be less carefully guarded.
82481477Smarkm	 * It is important to check the keytab first before the KDC so we do
82581477Smarkm	 * not get spoofed by a fake KDC.
82681477Smarkm	 */
82781477Smarkm	services[0] = "host";
82881477Smarkm	services[1] = pam_service;
82981477Smarkm	services[2] = NULL;
83081477Smarkm	keyblock = 0;
83181477Smarkm	retval = -1;
83281477Smarkm	for (service = &services[0]; *service != NULL; service++) {
83381477Smarkm		retval = krb5_sname_to_principal(context, NULL, *service,
83481477Smarkm		    KRB5_NT_SRV_HST, &princ);
83581477Smarkm		if (retval != 0) {
83681477Smarkm			if (debug)
837106862Snectar				syslog(LOG_DEBUG,
838106862Snectar				    "pam_krb5: verify_krb_v5_tgt(): %s: %s",
839106862Snectar				    "krb5_sname_to_principal()",
840106862Snectar				    krb5_get_err_text(context, retval));
84181477Smarkm			return -1;
84281477Smarkm		}
84381477Smarkm
84481477Smarkm		/* Extract the name directly. */
84581477Smarkm		strncpy(phost, compat_princ_component(context, princ, 1),
84681477Smarkm		    BUFSIZ);
84781477Smarkm		phost[BUFSIZ - 1] = '\0';
84881477Smarkm
84981477Smarkm		/*
85094564Sdes		 * Do we have service/<host> keys?
85194564Sdes		 * (use default/configured keytab, kvno IGNORE_VNO to get the
85294564Sdes		 * first match, and ignore enctype.)
85394564Sdes		 */
85481477Smarkm		retval = krb5_kt_read_service_key(context, NULL, princ, 0, 0,
85581477Smarkm		    &keyblock);
85681477Smarkm		if (retval != 0)
85781477Smarkm			continue;
85881477Smarkm		break;
85981477Smarkm	}
86081477Smarkm	if (retval != 0) {	/* failed to find key */
86181477Smarkm		/* Keytab or service key does not exist */
86281477Smarkm		if (debug)
863106862Snectar			syslog(LOG_DEBUG,
864106862Snectar			    "pam_krb5: verify_krb_v5_tgt(): %s: %s",
865106862Snectar			    "krb5_kt_read_service_key()",
866106862Snectar			    krb5_get_err_text(context, retval));
86781477Smarkm		retval = 0;
86881477Smarkm		goto cleanup;
86981477Smarkm	}
87081477Smarkm	if (keyblock)
87181477Smarkm		krb5_free_keyblock(context, keyblock);
87281477Smarkm
87381477Smarkm	/* Talk to the kdc and construct the ticket. */
87481477Smarkm	auth_context = NULL;
87581477Smarkm	retval = krb5_mk_req(context, &auth_context, 0, *service, phost,
87681477Smarkm		NULL, ccache, &packet);
87781477Smarkm	if (auth_context) {
87881477Smarkm		krb5_auth_con_free(context, auth_context);
87981477Smarkm		auth_context = NULL;	/* setup for rd_req */
88081477Smarkm	}
88181477Smarkm	if (retval) {
88281477Smarkm		if (debug)
883106862Snectar			syslog(LOG_DEBUG,
884106862Snectar			    "pam_krb5: verify_krb_v5_tgt(): %s: %s",
885106862Snectar			    "krb5_mk_req()",
886106862Snectar			    krb5_get_err_text(context, retval));
88781477Smarkm		retval = -1;
88881477Smarkm		goto cleanup;
88981477Smarkm	}
89081477Smarkm
89181477Smarkm	/* Try to use the ticket. */
89281477Smarkm	retval = krb5_rd_req(context, &auth_context, &packet, princ, NULL,
89381477Smarkm	    NULL, NULL);
89481477Smarkm	if (retval) {
89581477Smarkm		if (debug)
896106862Snectar			syslog(LOG_DEBUG,
897106862Snectar			    "pam_krb5: verify_krb_v5_tgt(): %s: %s",
898106862Snectar			    "krb5_rd_req()",
899106862Snectar			    krb5_get_err_text(context, retval));
90081477Smarkm		retval = -1;
90181477Smarkm	}
90281477Smarkm	else
90381477Smarkm		retval = 1;
90481477Smarkm
90581477Smarkmcleanup:
90681477Smarkm	if (packet.data)
90781477Smarkm		compat_free_data_contents(context, &packet);
90881477Smarkm	krb5_free_principal(context, princ);
90981477Smarkm	return retval;
91081477Smarkm}
91181477Smarkm
91281477Smarkm/* Free the memory for cache_name. Called by pam_end() */
913111985Smarkm/* ARGSUSED */
91481477Smarkmstatic void
91589760Smarkmcleanup_cache(pam_handle_t *pamh __unused, void *data, int pam_end_status __unused)
91681477Smarkm{
91781477Smarkm	krb5_context pam_context;
91881477Smarkm	krb5_ccache ccache;
919106864Snectar	krb5_error_code krbret;
92081477Smarkm
92181477Smarkm	if (krb5_init_context(&pam_context))
92281477Smarkm		return;
92381477Smarkm
924106864Snectar	krbret = krb5_cc_resolve(pam_context, data, &ccache);
925106864Snectar	if (krbret == 0)
926106864Snectar		krb5_cc_destroy(pam_context, ccache);
92781477Smarkm	krb5_free_context(pam_context);
928106864Snectar	free(data);
92981477Smarkm}
93081477Smarkm
93181477Smarkm#ifdef COMPAT_HEIMDAL
93281477Smarkm#ifdef COMPAT_MIT
93381477Smarkm#error This cannot be MIT and Heimdal compatible!
93481477Smarkm#endif
93581477Smarkm#endif
93681477Smarkm
93781477Smarkm#ifndef COMPAT_HEIMDAL
93881477Smarkm#ifndef COMPAT_MIT
93981477Smarkm#error One of COMPAT_MIT and COMPAT_HEIMDAL must be specified!
94081477Smarkm#endif
94181477Smarkm#endif
94281477Smarkm
94381477Smarkm#ifdef COMPAT_HEIMDAL
944111985Smarkm/* ARGSUSED */
94581477Smarkmstatic const char *
94689760Smarkmcompat_princ_component(krb5_context context __unused, krb5_principal princ, int n)
94781477Smarkm{
94881477Smarkm	return princ->name.name_string.val[n];
94981477Smarkm}
95081477Smarkm
951111985Smarkm/* ARGSUSED */
95281477Smarkmstatic void
95389760Smarkmcompat_free_data_contents(krb5_context context __unused, krb5_data * data)
95481477Smarkm{
95581477Smarkm	krb5_xfree(data->data);
95681477Smarkm}
95781477Smarkm#endif
95881477Smarkm
95981477Smarkm#ifdef COMPAT_MIT
96081477Smarkmstatic const char *
96181477Smarkmcompat_princ_component(krb5_context context, krb5_principal princ, int n)
96281477Smarkm{
96381477Smarkm	return krb5_princ_component(context, princ, n)->data;
96481477Smarkm}
96581477Smarkm
96681477Smarkmstatic void
96781477Smarkmcompat_free_data_contents(krb5_context context, krb5_data * data)
96881477Smarkm{
96981477Smarkm	krb5_free_data_contents(context, data);
97081477Smarkm}
97181477Smarkm#endif
972