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$");
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"
92207553Smm#define PAM_OPT_NO_USER_CHECK	"no_user_check"
93115465Sdes#define PAM_OPT_REUSE_CCACHE	"reuse_ccache"
9481477Smarkm
9581477Smarkm/*
9681477Smarkm * authentication management
9781477Smarkm */
9881477SmarkmPAM_EXTERN int
9994564Sdespam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
100115465Sdes    int argc __unused, const char *argv[] __unused)
10181477Smarkm{
10281477Smarkm	krb5_error_code krbret;
10381477Smarkm	krb5_context pam_context;
10481477Smarkm	krb5_creds creds;
10581477Smarkm	krb5_principal princ;
106106864Snectar	krb5_ccache ccache;
10781477Smarkm	krb5_get_init_creds_opt opts;
10881477Smarkm	struct passwd *pwd;
10981477Smarkm	int retval;
110174837Sdes	const void *ccache_data;
111123454Sdes	const char *user, *pass;
112125650Sdes	const void *sourceuser, *service;
113106864Snectar	char *principal, *princ_name, *ccache_name, luser[32], *srvdup;
11481477Smarkm
11581477Smarkm	retval = pam_get_user(pamh, &user, USER_PROMPT);
11681477Smarkm	if (retval != PAM_SUCCESS)
11794564Sdes		return (retval);
11881477Smarkm
11981477Smarkm	PAM_LOG("Got user: %s", user);
12081477Smarkm
121123454Sdes	retval = pam_get_item(pamh, PAM_RUSER, &sourceuser);
12281477Smarkm	if (retval != PAM_SUCCESS)
12394564Sdes		return (retval);
12481477Smarkm
125123454Sdes	PAM_LOG("Got ruser: %s", (const char *)sourceuser);
12681477Smarkm
12781477Smarkm	service = NULL;
128123454Sdes	pam_get_item(pamh, PAM_SERVICE, &service);
12981477Smarkm	if (service == NULL)
13081477Smarkm		service = "unknown";
13181477Smarkm
132123454Sdes	PAM_LOG("Got service: %s", (const char *)service);
13381477Smarkm
13481477Smarkm	krbret = krb5_init_context(&pam_context);
13581477Smarkm	if (krbret != 0) {
13681477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
13794564Sdes		return (PAM_SERVICE_ERR);
13881477Smarkm	}
13981477Smarkm
14081477Smarkm	PAM_LOG("Context initialised");
14181477Smarkm
14281477Smarkm	krb5_get_init_creds_opt_init(&opts);
14381477Smarkm
144115465Sdes	if (openpam_get_option(pamh, PAM_OPT_FORWARDABLE))
14581477Smarkm		krb5_get_init_creds_opt_set_forwardable(&opts, 1);
14681477Smarkm
14781477Smarkm	PAM_LOG("Credentials initialised");
14881477Smarkm
14981477Smarkm	krbret = krb5_cc_register(pam_context, &krb5_mcc_ops, FALSE);
15081477Smarkm	if (krbret != 0 && krbret != KRB5_CC_TYPE_EXISTS) {
15181477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
15281477Smarkm		retval = PAM_SERVICE_ERR;
15381477Smarkm		goto cleanup3;
15481477Smarkm	}
15581477Smarkm
15681477Smarkm	PAM_LOG("Done krb5_cc_register()");
15781477Smarkm
15881477Smarkm	/* Get principal name */
159115465Sdes	if (openpam_get_option(pamh, PAM_OPT_AUTH_AS_SELF))
160123454Sdes		asprintf(&principal, "%s/%s", (const char *)sourceuser, user);
16181477Smarkm	else
16281477Smarkm		principal = strdup(user);
16381477Smarkm
16481477Smarkm	PAM_LOG("Created principal: %s", principal);
16581477Smarkm
16681477Smarkm	krbret = krb5_parse_name(pam_context, principal, &princ);
16781477Smarkm	free(principal);
16881477Smarkm	if (krbret != 0) {
169106862Snectar		PAM_LOG("Error krb5_parse_name(): %s",
170106862Snectar		    krb5_get_err_text(pam_context, krbret));
17181477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
17281477Smarkm		retval = PAM_SERVICE_ERR;
17381477Smarkm		goto cleanup3;
17481477Smarkm	}
17581477Smarkm
17681477Smarkm	PAM_LOG("Done krb5_parse_name()");
17781477Smarkm
17881477Smarkm	/* Now convert the principal name into something human readable */
17981477Smarkm	princ_name = NULL;
18081477Smarkm	krbret = krb5_unparse_name(pam_context, princ, &princ_name);
18181477Smarkm	if (krbret != 0) {
182106862Snectar		PAM_LOG("Error krb5_unparse_name(): %s",
183106862Snectar		    krb5_get_err_text(pam_context, krbret));
18481477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
18581477Smarkm		retval = PAM_SERVICE_ERR;
18681477Smarkm		goto cleanup2;
18781477Smarkm	}
18881477Smarkm
18981477Smarkm	PAM_LOG("Got principal: %s", princ_name);
19081477Smarkm
19181477Smarkm	/* Get password */
19293984Sdes	retval = pam_get_authtok(pamh, PAM_AUTHTOK, &pass, PASSWORD_PROMPT);
19381477Smarkm	if (retval != PAM_SUCCESS)
19481477Smarkm		goto cleanup2;
19581477Smarkm
19681477Smarkm	PAM_LOG("Got password");
19781477Smarkm
198207553Smm	if (openpam_get_option(pamh, PAM_OPT_NO_USER_CHECK))
199207553Smm		PAM_LOG("Skipping local user check");
200207553Smm	else {
201207553Smm
202207555Smm		/* Verify the local user exists (AFTER getting the password) */
203207555Smm		if (strchr(user, '@')) {
204207555Smm			/* get a local account name for this principal */
205207555Smm			krbret = krb5_aname_to_localname(pam_context, princ,
206207555Smm			    sizeof(luser), luser);
207207555Smm			if (krbret != 0) {
208207555Smm				PAM_VERBOSE_ERROR("Kerberos 5 error");
209207555Smm				PAM_LOG("Error krb5_aname_to_localname(): %s",
210207555Smm				    krb5_get_err_text(pam_context, krbret));
211207555Smm				retval = PAM_USER_UNKNOWN;
212207555Smm				goto cleanup2;
213207555Smm			}
214207555Smm
215207555Smm			retval = pam_set_item(pamh, PAM_USER, luser);
216207555Smm			if (retval != PAM_SUCCESS)
217207555Smm				goto cleanup2;
218207555Smm
219207555Smm			PAM_LOG("PAM_USER Redone");
220207555Smm		}
221207555Smm
222207555Smm		pwd = getpwnam(user);
223207555Smm		if (pwd == NULL) {
22481477Smarkm			retval = PAM_USER_UNKNOWN;
22581477Smarkm			goto cleanup2;
22681477Smarkm		}
22781477Smarkm
228207555Smm		PAM_LOG("Done getpwnam()");
22981477Smarkm	}
23081477Smarkm
23181477Smarkm	/* Get a TGT */
23281477Smarkm	memset(&creds, 0, sizeof(krb5_creds));
23381477Smarkm	krbret = krb5_get_init_creds_password(pam_context, &creds, princ,
23481477Smarkm	    pass, NULL, pamh, 0, NULL, &opts);
23581477Smarkm	if (krbret != 0) {
23681477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
23781477Smarkm		PAM_LOG("Error krb5_get_init_creds_password(): %s",
238106862Snectar		    krb5_get_err_text(pam_context, krbret));
23981477Smarkm		retval = PAM_AUTH_ERR;
24081477Smarkm		goto cleanup2;
24181477Smarkm	}
24281477Smarkm
24381477Smarkm	PAM_LOG("Got TGT");
24481477Smarkm
245106864Snectar	/* Generate a temporary cache */
246106864Snectar	krbret = krb5_cc_gen_new(pam_context, &krb5_mcc_ops, &ccache);
24781477Smarkm	if (krbret != 0) {
24881477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
249106864Snectar		PAM_LOG("Error krb5_cc_gen_new(): %s",
250106862Snectar		    krb5_get_err_text(pam_context, krbret));
25181477Smarkm		retval = PAM_SERVICE_ERR;
25281477Smarkm		goto cleanup;
25381477Smarkm	}
25481477Smarkm	krbret = krb5_cc_initialize(pam_context, ccache, princ);
25581477Smarkm	if (krbret != 0) {
25681477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
257106862Snectar		PAM_LOG("Error krb5_cc_initialize(): %s",
258106862Snectar		    krb5_get_err_text(pam_context, krbret));
25981477Smarkm		retval = PAM_SERVICE_ERR;
26081477Smarkm		goto cleanup;
26181477Smarkm	}
26281477Smarkm	krbret = krb5_cc_store_cred(pam_context, ccache, &creds);
26381477Smarkm	if (krbret != 0) {
26481477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
265106862Snectar		PAM_LOG("Error krb5_cc_store_cred(): %s",
266106862Snectar		    krb5_get_err_text(pam_context, krbret));
26781477Smarkm		krb5_cc_destroy(pam_context, ccache);
26881477Smarkm		retval = PAM_SERVICE_ERR;
26981477Smarkm		goto cleanup;
27081477Smarkm	}
27181477Smarkm
27281477Smarkm	PAM_LOG("Credentials stashed");
27381477Smarkm
27481477Smarkm	/* Verify them */
27593984Sdes	if ((srvdup = strdup(service)) == NULL) {
27693984Sdes		retval = PAM_BUF_ERR;
27793984Sdes		goto cleanup;
27893984Sdes	}
27993984Sdes	krbret = verify_krb_v5_tgt(pam_context, ccache, srvdup,
280140667Srwatson	    openpam_get_option(pamh, PAM_OPT_DEBUG) ? 1 : 0);
28193984Sdes	free(srvdup);
28293984Sdes	if (krbret == -1) {
28381477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
28481477Smarkm		krb5_cc_destroy(pam_context, ccache);
28581477Smarkm		retval = PAM_AUTH_ERR;
28681477Smarkm		goto cleanup;
28781477Smarkm	}
28881477Smarkm
28981477Smarkm	PAM_LOG("Credentials stash verified");
29081477Smarkm
291125650Sdes	retval = pam_get_data(pamh, "ccache", &ccache_data);
29281477Smarkm	if (retval == PAM_SUCCESS) {
29381477Smarkm		krb5_cc_destroy(pam_context, ccache);
29481477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
29581477Smarkm		retval = PAM_AUTH_ERR;
29681477Smarkm		goto cleanup;
29781477Smarkm	}
29881477Smarkm
29981477Smarkm	PAM_LOG("Credentials stash not pre-existing");
30081477Smarkm
301106864Snectar	asprintf(&ccache_name, "%s:%s", krb5_cc_get_type(pam_context,
302106864Snectar		ccache), krb5_cc_get_name(pam_context, ccache));
303106864Snectar	if (ccache_name == NULL) {
304106864Snectar		PAM_VERBOSE_ERROR("Kerberos 5 error");
305106864Snectar		retval = PAM_BUF_ERR;
306106864Snectar		goto cleanup;
307106864Snectar	}
308106864Snectar	retval = pam_set_data(pamh, "ccache", ccache_name, cleanup_cache);
30981477Smarkm	if (retval != 0) {
31081477Smarkm		krb5_cc_destroy(pam_context, ccache);
31181477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 error");
31281477Smarkm		retval = PAM_SERVICE_ERR;
31381477Smarkm		goto cleanup;
31481477Smarkm	}
31581477Smarkm
31681477Smarkm	PAM_LOG("Credentials stash saved");
31781477Smarkm
31881477Smarkmcleanup:
31981477Smarkm	krb5_free_cred_contents(pam_context, &creds);
32081477Smarkm	PAM_LOG("Done cleanup");
32181477Smarkmcleanup2:
32281477Smarkm	krb5_free_principal(pam_context, princ);
32381477Smarkm	if (princ_name)
32481477Smarkm		free(princ_name);
325239520Sdim	PAM_LOG("Done cleanup2");
32681477Smarkm
327239520Sdimcleanup3:
32881477Smarkm	krb5_free_context(pam_context);
32981477Smarkm
33081477Smarkm	PAM_LOG("Done cleanup3");
33181477Smarkm
33281477Smarkm	if (retval != PAM_SUCCESS)
33381477Smarkm		PAM_VERBOSE_ERROR("Kerberos 5 refuses you");
33481477Smarkm
33594564Sdes	return (retval);
33681477Smarkm}
33781477Smarkm
33881477SmarkmPAM_EXTERN int
33994564Sdespam_sm_setcred(pam_handle_t *pamh, int flags,
340115465Sdes    int argc __unused, const char *argv[] __unused)
34181477Smarkm{
342147810Skensmith#ifdef _FREEFALL_CONFIG
343147810Skensmith	return (PAM_SUCCESS);
344147810Skensmith#else
34581477Smarkm
34681477Smarkm	krb5_error_code krbret;
34781477Smarkm	krb5_context pam_context;
34881477Smarkm	krb5_principal princ;
34981477Smarkm	krb5_creds creds;
35081477Smarkm	krb5_ccache ccache_temp, ccache_perm;
35181477Smarkm	krb5_cc_cursor cursor;
35281477Smarkm	struct passwd *pwd = NULL;
35381477Smarkm	int retval;
354123454Sdes	const char *cache_name, *q;
355125650Sdes	const void *user;
356174837Sdes	const void *cache_data;
357115465Sdes	char *cache_name_buf = NULL, *p;
35881477Smarkm
35981477Smarkm	uid_t euid;
36081477Smarkm	gid_t egid;
36181477Smarkm
36281477Smarkm	if (flags & PAM_DELETE_CRED)
36394564Sdes		return (PAM_SUCCESS);
36481477Smarkm
36581477Smarkm	if (flags & PAM_REFRESH_CRED)
36694564Sdes		return (PAM_SUCCESS);
36781477Smarkm
36881477Smarkm	if (flags & PAM_REINITIALIZE_CRED)
36994564Sdes		return (PAM_SUCCESS);
37081477Smarkm
37181477Smarkm	if (!(flags & PAM_ESTABLISH_CRED))
37294564Sdes		return (PAM_SERVICE_ERR);
37381477Smarkm
374140747Srwatson	/* If a persistent cache isn't desired, stop now. */
375207553Smm	if (openpam_get_option(pamh, PAM_OPT_NO_CCACHE) ||
376207553Smm		openpam_get_option(pamh, PAM_OPT_NO_USER_CHECK))
377140747Srwatson		return (PAM_SUCCESS);
378140747Srwatson
37981477Smarkm	PAM_LOG("Establishing credentials");
38081477Smarkm
38181477Smarkm	/* Get username */
382123454Sdes	retval = pam_get_item(pamh, PAM_USER, &user);
38381477Smarkm	if (retval != PAM_SUCCESS)
38494564Sdes		return (retval);
38581477Smarkm
386123454Sdes	PAM_LOG("Got user: %s", (const char *)user);
38781477Smarkm
38881477Smarkm	krbret = krb5_init_context(&pam_context);
38981477Smarkm	if (krbret != 0) {
390106862Snectar		PAM_LOG("Error krb5_init_context() failed");
39194564Sdes		return (PAM_SERVICE_ERR);
39281477Smarkm	}
39381477Smarkm
39481477Smarkm	PAM_LOG("Context initialised");
39581477Smarkm
39681477Smarkm	euid = geteuid();	/* Usually 0 */
39781477Smarkm	egid = getegid();
39881477Smarkm
39981477Smarkm	PAM_LOG("Got euid, egid: %d %d", euid, egid);
40081477Smarkm
401106864Snectar	/* Retrieve the temporary cache */
402123454Sdes	retval = pam_get_data(pamh, "ccache", &cache_data);
403110056Snectar	if (retval != PAM_SUCCESS) {
404110056Snectar		retval = PAM_CRED_UNAVAIL;
40581477Smarkm		goto cleanup3;
406110056Snectar	}
407123454Sdes	krbret = krb5_cc_resolve(pam_context, cache_data, &ccache_temp);
408106864Snectar	if (krbret != 0) {
409123454Sdes		PAM_LOG("Error krb5_cc_resolve(\"%s\"): %s", (const char *)cache_data,
410106864Snectar		    krb5_get_err_text(pam_context, krbret));
411110056Snectar		retval = PAM_SERVICE_ERR;
412106864Snectar		goto cleanup3;
413106864Snectar	}
41481477Smarkm
41581477Smarkm	/* Get the uid. This should exist. */
41681477Smarkm	pwd = getpwnam(user);
41781477Smarkm	if (pwd == NULL) {
41881477Smarkm		retval = PAM_USER_UNKNOWN;
41981477Smarkm		goto cleanup3;
42081477Smarkm	}
42181477Smarkm
42281477Smarkm	PAM_LOG("Done getpwnam()");
42381477Smarkm
42481477Smarkm	/* Avoid following a symlink as root */
42581477Smarkm	if (setegid(pwd->pw_gid)) {
42681477Smarkm		retval = PAM_SERVICE_ERR;
42781477Smarkm		goto cleanup3;
42881477Smarkm	}
42981477Smarkm	if (seteuid(pwd->pw_uid)) {
43081477Smarkm		retval = PAM_SERVICE_ERR;
43181477Smarkm		goto cleanup3;
43281477Smarkm	}
43381477Smarkm
43481477Smarkm	PAM_LOG("Done setegid() & seteuid()");
43581477Smarkm
43681477Smarkm	/* Get the cache name */
437115465Sdes	cache_name = openpam_get_option(pamh, PAM_OPT_CCACHE);
438115465Sdes	if (cache_name == NULL) {
439115465Sdes		asprintf(&cache_name_buf, "FILE:/tmp/krb5cc_%d", pwd->pw_uid);
440115465Sdes		cache_name = cache_name_buf;
441115465Sdes	}
44281477Smarkm
44381477Smarkm	p = calloc(PATH_MAX + 16, sizeof(char));
44481477Smarkm	q = cache_name;
44581477Smarkm
44681477Smarkm	if (p == NULL) {
44781477Smarkm		PAM_LOG("Error malloc(): failure");
44881477Smarkm		retval = PAM_BUF_ERR;
44981477Smarkm		goto cleanup3;
45081477Smarkm	}
45181477Smarkm	cache_name = p;
45281477Smarkm
45381477Smarkm	/* convert %u and %p */
45481477Smarkm	while (*q) {
45581477Smarkm		if (*q == '%') {
45681477Smarkm			q++;
45781477Smarkm			if (*q == 'u') {
45881477Smarkm				sprintf(p, "%d", pwd->pw_uid);
45981477Smarkm				p += strlen(p);
46081477Smarkm			}
46181477Smarkm			else if (*q == 'p') {
46281477Smarkm				sprintf(p, "%d", getpid());
46381477Smarkm				p += strlen(p);
46481477Smarkm			}
46581477Smarkm			else {
46681477Smarkm				/* Not a special token */
46781477Smarkm				*p++ = '%';
46881477Smarkm				q--;
46981477Smarkm			}
47081477Smarkm			q++;
47181477Smarkm		}
47281477Smarkm		else {
47381477Smarkm			*p++ = *q++;
47481477Smarkm		}
47581477Smarkm	}
47681477Smarkm
47781477Smarkm	PAM_LOG("Got cache_name: %s", cache_name);
47881477Smarkm
47981477Smarkm	/* Initialize the new ccache */
48081477Smarkm	krbret = krb5_cc_get_principal(pam_context, ccache_temp, &princ);
48181477Smarkm	if (krbret != 0) {
48281477Smarkm		PAM_LOG("Error krb5_cc_get_principal(): %s",
483106862Snectar		    krb5_get_err_text(pam_context, krbret));
48481477Smarkm		retval = PAM_SERVICE_ERR;
48581477Smarkm		goto cleanup3;
48681477Smarkm	}
48781477Smarkm	krbret = krb5_cc_resolve(pam_context, cache_name, &ccache_perm);
48881477Smarkm	if (krbret != 0) {
489106862Snectar		PAM_LOG("Error krb5_cc_resolve(): %s",
490106862Snectar		    krb5_get_err_text(pam_context, krbret));
49181477Smarkm		retval = PAM_SERVICE_ERR;
49281477Smarkm		goto cleanup2;
49381477Smarkm	}
49481477Smarkm	krbret = krb5_cc_initialize(pam_context, ccache_perm, princ);
49581477Smarkm	if (krbret != 0) {
496106862Snectar		PAM_LOG("Error krb5_cc_initialize(): %s",
497106862Snectar		    krb5_get_err_text(pam_context, krbret));
49881477Smarkm		retval = PAM_SERVICE_ERR;
49981477Smarkm		goto cleanup2;
50081477Smarkm	}
50181477Smarkm
50281477Smarkm	PAM_LOG("Cache initialised");
50381477Smarkm
50481477Smarkm	/* Prepare for iteration over creds */
50581477Smarkm	krbret = krb5_cc_start_seq_get(pam_context, ccache_temp, &cursor);
50681477Smarkm	if (krbret != 0) {
507106862Snectar		PAM_LOG("Error krb5_cc_start_seq_get(): %s",
508106862Snectar		    krb5_get_err_text(pam_context, krbret));
50981477Smarkm		krb5_cc_destroy(pam_context, ccache_perm);
51081477Smarkm		retval = PAM_SERVICE_ERR;
51181477Smarkm		goto cleanup2;
51281477Smarkm	}
51381477Smarkm
51481477Smarkm	PAM_LOG("Prepared for iteration");
51581477Smarkm
51681477Smarkm	/* Copy the creds (should be two of them) */
51781477Smarkm	while ((krbret = krb5_cc_next_cred(pam_context, ccache_temp,
51881477Smarkm				&cursor, &creds) == 0)) {
51981477Smarkm		krbret = krb5_cc_store_cred(pam_context, ccache_perm, &creds);
52081477Smarkm		if (krbret != 0) {
52181477Smarkm			PAM_LOG("Error krb5_cc_store_cred(): %s",
522106862Snectar			    krb5_get_err_text(pam_context, krbret));
52381477Smarkm			krb5_cc_destroy(pam_context, ccache_perm);
52481477Smarkm			krb5_free_cred_contents(pam_context, &creds);
52581477Smarkm			retval = PAM_SERVICE_ERR;
52681477Smarkm			goto cleanup2;
52781477Smarkm		}
52881477Smarkm		krb5_free_cred_contents(pam_context, &creds);
52981477Smarkm		PAM_LOG("Iteration");
53081477Smarkm	}
53181477Smarkm	krb5_cc_end_seq_get(pam_context, ccache_temp, &cursor);
53281477Smarkm
53381477Smarkm	PAM_LOG("Done iterating");
53481477Smarkm
53581477Smarkm	if (strstr(cache_name, "FILE:") == cache_name) {
53681477Smarkm		if (chown(&cache_name[5], pwd->pw_uid, pwd->pw_gid) == -1) {
53781477Smarkm			PAM_LOG("Error chown(): %s", strerror(errno));
53881477Smarkm			krb5_cc_destroy(pam_context, ccache_perm);
53981477Smarkm			retval = PAM_SERVICE_ERR;
54081477Smarkm			goto cleanup2;
54181477Smarkm		}
54281477Smarkm		PAM_LOG("Done chown()");
54381477Smarkm
54481477Smarkm		if (chmod(&cache_name[5], (S_IRUSR | S_IWUSR)) == -1) {
54581477Smarkm			PAM_LOG("Error chmod(): %s", strerror(errno));
54681477Smarkm			krb5_cc_destroy(pam_context, ccache_perm);
54781477Smarkm			retval = PAM_SERVICE_ERR;
54881477Smarkm			goto cleanup2;
54981477Smarkm		}
55081477Smarkm		PAM_LOG("Done chmod()");
55181477Smarkm	}
55281477Smarkm
55381477Smarkm	krb5_cc_close(pam_context, ccache_perm);
55481477Smarkm
55581477Smarkm	PAM_LOG("Cache closed");
55681477Smarkm
557115465Sdes	retval = pam_setenv(pamh, "KRB5CCNAME", cache_name, 1);
558115465Sdes	if (retval != PAM_SUCCESS) {
559115465Sdes		PAM_LOG("Error pam_setenv(): %s", pam_strerror(pamh, retval));
56081477Smarkm		krb5_cc_destroy(pam_context, ccache_perm);
56181477Smarkm		retval = PAM_SERVICE_ERR;
56281477Smarkm		goto cleanup2;
56381477Smarkm	}
56481477Smarkm
56581477Smarkm	PAM_LOG("Environment done: KRB5CCNAME=%s", cache_name);
56681477Smarkm
56781477Smarkmcleanup2:
56881477Smarkm	krb5_free_principal(pam_context, princ);
56981477Smarkm	PAM_LOG("Done cleanup2");
57081477Smarkmcleanup3:
57181477Smarkm	krb5_free_context(pam_context);
57281477Smarkm	PAM_LOG("Done cleanup3");
57381477Smarkm
57481477Smarkm	seteuid(euid);
57581477Smarkm	setegid(egid);
57681477Smarkm
57781477Smarkm	PAM_LOG("Done seteuid() & setegid()");
57894564Sdes
579115465Sdes	if (cache_name_buf != NULL)
580115465Sdes		free(cache_name_buf);
581115465Sdes
58294564Sdes	return (retval);
583147810Skensmith#endif
58481477Smarkm}
58581477Smarkm
58694564Sdes/*
58781477Smarkm * account management
58881477Smarkm */
58981477SmarkmPAM_EXTERN int
59094564Sdespam_sm_acct_mgmt(pam_handle_t *pamh, int flags __unused,
591115465Sdes    int argc __unused, const char *argv[] __unused)
59281477Smarkm{
59381477Smarkm	krb5_error_code krbret;
59481477Smarkm	krb5_context pam_context;
59581477Smarkm	krb5_ccache ccache;
59681477Smarkm	krb5_principal princ;
59781477Smarkm	int retval;
598125650Sdes	const void *user;
599174837Sdes	const void *ccache_name;
60081477Smarkm
601123454Sdes	retval = pam_get_item(pamh, PAM_USER, &user);
60281477Smarkm	if (retval != PAM_SUCCESS)
60394564Sdes		return (retval);
60481477Smarkm
605123454Sdes	PAM_LOG("Got user: %s", (const char *)user);
60681477Smarkm
607123454Sdes	retval = pam_get_data(pamh, "ccache", &ccache_name);
608110275Sdes	if (retval != PAM_SUCCESS)
609110275Sdes		return (PAM_SUCCESS);
610110275Sdes
611110275Sdes	PAM_LOG("Got credentials");
612110275Sdes
61381477Smarkm	krbret = krb5_init_context(&pam_context);
61481477Smarkm	if (krbret != 0) {
615106862Snectar		PAM_LOG("Error krb5_init_context() failed");
61694564Sdes		return (PAM_PERM_DENIED);
61781477Smarkm	}
61881477Smarkm
61981477Smarkm	PAM_LOG("Context initialised");
62081477Smarkm
621123454Sdes	krbret = krb5_cc_resolve(pam_context, (const char *)ccache_name, &ccache);
622106864Snectar	if (krbret != 0) {
623123454Sdes		PAM_LOG("Error krb5_cc_resolve(\"%s\"): %s", (const char *)ccache_name,
624106864Snectar		    krb5_get_err_text(pam_context, krbret));
625106864Snectar		krb5_free_context(pam_context);
626106864Snectar		return (PAM_PERM_DENIED);
627106864Snectar	}
628106864Snectar
629123454Sdes	PAM_LOG("Got ccache %s", (const char *)ccache_name);
630106864Snectar
631106864Snectar
63281477Smarkm	krbret = krb5_cc_get_principal(pam_context, ccache, &princ);
63381477Smarkm	if (krbret != 0) {
634106862Snectar		PAM_LOG("Error krb5_cc_get_principal(): %s",
635106862Snectar		    krb5_get_err_text(pam_context, krbret));
636242544Seadler		retval = PAM_PERM_DENIED;
63781477Smarkm		goto cleanup;
63881477Smarkm	}
63981477Smarkm
64081477Smarkm	PAM_LOG("Got principal");
64181477Smarkm
642123454Sdes	if (krb5_kuserok(pam_context, princ, (const char *)user))
64381477Smarkm		retval = PAM_SUCCESS;
64481477Smarkm	else
64581477Smarkm		retval = PAM_PERM_DENIED;
64681477Smarkm	krb5_free_principal(pam_context, princ);
64781477Smarkm
64881477Smarkm	PAM_LOG("Done kuserok()");
64981477Smarkm
65081477Smarkmcleanup:
65181477Smarkm	krb5_free_context(pam_context);
65281477Smarkm	PAM_LOG("Done cleanup");
65381477Smarkm
65494564Sdes	return (retval);
65581477Smarkm
65681477Smarkm}
65781477Smarkm
65894564Sdes/*
65981477Smarkm * password management
66081477Smarkm */
66181477SmarkmPAM_EXTERN int
66294564Sdespam_sm_chauthtok(pam_handle_t *pamh, int flags,
663115465Sdes    int argc __unused, const char *argv[] __unused)
66481477Smarkm{
66581477Smarkm	krb5_error_code krbret;
66681477Smarkm	krb5_context pam_context;
66781477Smarkm	krb5_creds creds;
66881477Smarkm	krb5_principal princ;
66981477Smarkm	krb5_get_init_creds_opt opts;
67081477Smarkm	krb5_data result_code_string, result_string;
67181477Smarkm	int result_code, retval;
672123454Sdes	const char *pass;
673123454Sdes	const void *user;
67493984Sdes	char *princ_name, *passdup;
67581477Smarkm
67681477Smarkm	if (!(flags & PAM_UPDATE_AUTHTOK))
67794564Sdes		return (PAM_AUTHTOK_ERR);
67881477Smarkm
679123454Sdes	retval = pam_get_item(pamh, PAM_USER, &user);
68081477Smarkm	if (retval != PAM_SUCCESS)
68194564Sdes		return (retval);
68281477Smarkm
683123454Sdes	PAM_LOG("Got user: %s", (const char *)user);
68481477Smarkm
68581477Smarkm	krbret = krb5_init_context(&pam_context);
68681477Smarkm	if (krbret != 0) {
687106862Snectar		PAM_LOG("Error krb5_init_context() failed");
68894564Sdes		return (PAM_SERVICE_ERR);
68981477Smarkm	}
69081477Smarkm
69181477Smarkm	PAM_LOG("Context initialised");
69281477Smarkm
69381477Smarkm	krb5_get_init_creds_opt_init(&opts);
69481477Smarkm
69581477Smarkm	PAM_LOG("Credentials options initialised");
69681477Smarkm
69781477Smarkm	/* Get principal name */
698123454Sdes	krbret = krb5_parse_name(pam_context, (const char *)user, &princ);
69981477Smarkm	if (krbret != 0) {
700106862Snectar		PAM_LOG("Error krb5_parse_name(): %s",
701106862Snectar		    krb5_get_err_text(pam_context, krbret));
70281477Smarkm		retval = PAM_USER_UNKNOWN;
70381477Smarkm		goto cleanup3;
70481477Smarkm	}
70581477Smarkm
70681477Smarkm	/* Now convert the principal name into something human readable */
70781477Smarkm	princ_name = NULL;
70881477Smarkm	krbret = krb5_unparse_name(pam_context, princ, &princ_name);
70981477Smarkm	if (krbret != 0) {
710106862Snectar		PAM_LOG("Error krb5_unparse_name(): %s",
711106862Snectar		    krb5_get_err_text(pam_context, krbret));
71281477Smarkm		retval = PAM_SERVICE_ERR;
71381477Smarkm		goto cleanup2;
71481477Smarkm	}
71581477Smarkm
71681477Smarkm	PAM_LOG("Got principal: %s", princ_name);
71781477Smarkm
71881477Smarkm	/* Get password */
71993984Sdes	retval = pam_get_authtok(pamh, PAM_OLDAUTHTOK, &pass, PASSWORD_PROMPT);
72081477Smarkm	if (retval != PAM_SUCCESS)
72181477Smarkm		goto cleanup2;
72281477Smarkm
72381477Smarkm	PAM_LOG("Got password");
72481477Smarkm
72581477Smarkm	memset(&creds, 0, sizeof(krb5_creds));
72681477Smarkm	krbret = krb5_get_init_creds_password(pam_context, &creds, princ,
72781477Smarkm	    pass, NULL, pamh, 0, "kadmin/changepw", &opts);
72881477Smarkm	if (krbret != 0) {
729125650Sdes		PAM_LOG("Error krb5_get_init_creds_password(): %s",
730106862Snectar		    krb5_get_err_text(pam_context, krbret));
73181477Smarkm		retval = PAM_AUTH_ERR;
73281477Smarkm		goto cleanup2;
73381477Smarkm	}
73481477Smarkm
73581477Smarkm	PAM_LOG("Credentials established");
73681477Smarkm
73781477Smarkm	/* Now get the new password */
73893984Sdes	for (;;) {
73993984Sdes		retval = pam_get_authtok(pamh,
74093984Sdes		    PAM_AUTHTOK, &pass, NEW_PASSWORD_PROMPT);
74193984Sdes		if (retval != PAM_TRY_AGAIN)
74293984Sdes			break;
74393984Sdes		pam_error(pamh, "Mismatch; try again, EOF to quit.");
74493984Sdes	}
74581477Smarkm	if (retval != PAM_SUCCESS)
74681477Smarkm		goto cleanup;
74781477Smarkm
74893984Sdes	PAM_LOG("Got new password");
74981477Smarkm
75093984Sdes	/* Change it */
75193984Sdes	if ((passdup = strdup(pass)) == NULL) {
75293984Sdes		retval = PAM_BUF_ERR;
75381477Smarkm		goto cleanup;
75481477Smarkm	}
75593984Sdes	krbret = krb5_change_password(pam_context, &creds, passdup,
75681477Smarkm	    &result_code, &result_code_string, &result_string);
75793984Sdes	free(passdup);
75881477Smarkm	if (krbret != 0) {
75981477Smarkm		PAM_LOG("Error krb5_change_password(): %s",
760106862Snectar		    krb5_get_err_text(pam_context, krbret));
76181477Smarkm		retval = PAM_AUTHTOK_ERR;
76281477Smarkm		goto cleanup;
76381477Smarkm	}
76481477Smarkm	if (result_code) {
76581477Smarkm		PAM_LOG("Error krb5_change_password(): (result_code)");
76681477Smarkm		retval = PAM_AUTHTOK_ERR;
76781477Smarkm		goto cleanup;
76881477Smarkm	}
76981477Smarkm
77081477Smarkm	PAM_LOG("Password changed");
77181477Smarkm
77281477Smarkm	if (result_string.data)
77381477Smarkm		free(result_string.data);
77481477Smarkm	if (result_code_string.data)
77581477Smarkm		free(result_code_string.data);
77681477Smarkm
77781477Smarkmcleanup:
77881477Smarkm	krb5_free_cred_contents(pam_context, &creds);
77981477Smarkm	PAM_LOG("Done cleanup");
78081477Smarkmcleanup2:
78181477Smarkm	krb5_free_principal(pam_context, princ);
78281477Smarkm	if (princ_name)
78381477Smarkm		free(princ_name);
784239520Sdim	PAM_LOG("Done cleanup2");
78581477Smarkm
786239520Sdimcleanup3:
78781477Smarkm	krb5_free_context(pam_context);
78881477Smarkm
78981477Smarkm	PAM_LOG("Done cleanup3");
79081477Smarkm
79194564Sdes	return (retval);
79281477Smarkm}
79381477Smarkm
79481477SmarkmPAM_MODULE_ENTRY("pam_krb5");
79581477Smarkm
79681477Smarkm/*
79781477Smarkm * This routine with some modification is from the MIT V5B6 appl/bsd/login.c
79881477Smarkm * Modified by Sam Hartman <hartmans@mit.edu> to support PAM services
79981477Smarkm * for Debian.
80081477Smarkm *
80181477Smarkm * Verify the Kerberos ticket-granting ticket just retrieved for the
80281477Smarkm * user.  If the Kerberos server doesn't respond, assume the user is
80381477Smarkm * trying to fake us out (since we DID just get a TGT from what is
80481477Smarkm * supposedly our KDC).  If the host/<host> service is unknown (i.e.,
80581477Smarkm * the local keytab doesn't have it), and we cannot find another
80681477Smarkm * service we do have, let her in.
80781477Smarkm *
80881477Smarkm * Returns 1 for confirmation, -1 for failure, 0 for uncertainty.
80981477Smarkm */
810111985Smarkm/* ARGSUSED */
81181477Smarkmstatic int
81281477Smarkmverify_krb_v5_tgt(krb5_context context, krb5_ccache ccache,
81381477Smarkm    char *pam_service, int debug)
81481477Smarkm{
81581477Smarkm	krb5_error_code retval;
81681477Smarkm	krb5_principal princ;
81781477Smarkm	krb5_keyblock *keyblock;
81881477Smarkm	krb5_data packet;
81981477Smarkm	krb5_auth_context auth_context;
82089760Smarkm	char phost[BUFSIZ];
82189760Smarkm	const char *services[3], **service;
82281477Smarkm
82381477Smarkm	packet.data = 0;
82481477Smarkm
82581477Smarkm	/* If possible we want to try and verify the ticket we have
82681477Smarkm	 * received against a keytab.  We will try multiple service
82781477Smarkm	 * principals, including at least the host principal and the PAM
82881477Smarkm	 * service principal.  The host principal is preferred because access
82981477Smarkm	 * to that key is generally sufficient to compromise root, while the
83081477Smarkm	 * service key for this PAM service may be less carefully guarded.
83181477Smarkm	 * It is important to check the keytab first before the KDC so we do
83281477Smarkm	 * not get spoofed by a fake KDC.
83381477Smarkm	 */
83481477Smarkm	services[0] = "host";
83581477Smarkm	services[1] = pam_service;
83681477Smarkm	services[2] = NULL;
83781477Smarkm	keyblock = 0;
83881477Smarkm	retval = -1;
83981477Smarkm	for (service = &services[0]; *service != NULL; service++) {
84081477Smarkm		retval = krb5_sname_to_principal(context, NULL, *service,
84181477Smarkm		    KRB5_NT_SRV_HST, &princ);
84281477Smarkm		if (retval != 0) {
84381477Smarkm			if (debug)
844106862Snectar				syslog(LOG_DEBUG,
845106862Snectar				    "pam_krb5: verify_krb_v5_tgt(): %s: %s",
846106862Snectar				    "krb5_sname_to_principal()",
847106862Snectar				    krb5_get_err_text(context, retval));
84881477Smarkm			return -1;
84981477Smarkm		}
85081477Smarkm
85181477Smarkm		/* Extract the name directly. */
85281477Smarkm		strncpy(phost, compat_princ_component(context, princ, 1),
85381477Smarkm		    BUFSIZ);
85481477Smarkm		phost[BUFSIZ - 1] = '\0';
85581477Smarkm
85681477Smarkm		/*
85794564Sdes		 * Do we have service/<host> keys?
85894564Sdes		 * (use default/configured keytab, kvno IGNORE_VNO to get the
85994564Sdes		 * first match, and ignore enctype.)
86094564Sdes		 */
86181477Smarkm		retval = krb5_kt_read_service_key(context, NULL, princ, 0, 0,
86281477Smarkm		    &keyblock);
86381477Smarkm		if (retval != 0)
86481477Smarkm			continue;
86581477Smarkm		break;
86681477Smarkm	}
86781477Smarkm	if (retval != 0) {	/* failed to find key */
86881477Smarkm		/* Keytab or service key does not exist */
86981477Smarkm		if (debug)
870106862Snectar			syslog(LOG_DEBUG,
871106862Snectar			    "pam_krb5: verify_krb_v5_tgt(): %s: %s",
872106862Snectar			    "krb5_kt_read_service_key()",
873106862Snectar			    krb5_get_err_text(context, retval));
87481477Smarkm		retval = 0;
87581477Smarkm		goto cleanup;
87681477Smarkm	}
87781477Smarkm	if (keyblock)
87881477Smarkm		krb5_free_keyblock(context, keyblock);
87981477Smarkm
88081477Smarkm	/* Talk to the kdc and construct the ticket. */
88181477Smarkm	auth_context = NULL;
88281477Smarkm	retval = krb5_mk_req(context, &auth_context, 0, *service, phost,
88381477Smarkm		NULL, ccache, &packet);
88481477Smarkm	if (auth_context) {
88581477Smarkm		krb5_auth_con_free(context, auth_context);
88681477Smarkm		auth_context = NULL;	/* setup for rd_req */
88781477Smarkm	}
88881477Smarkm	if (retval) {
88981477Smarkm		if (debug)
890106862Snectar			syslog(LOG_DEBUG,
891106862Snectar			    "pam_krb5: verify_krb_v5_tgt(): %s: %s",
892106862Snectar			    "krb5_mk_req()",
893106862Snectar			    krb5_get_err_text(context, retval));
89481477Smarkm		retval = -1;
89581477Smarkm		goto cleanup;
89681477Smarkm	}
89781477Smarkm
89881477Smarkm	/* Try to use the ticket. */
89981477Smarkm	retval = krb5_rd_req(context, &auth_context, &packet, princ, NULL,
90081477Smarkm	    NULL, NULL);
90181477Smarkm	if (retval) {
90281477Smarkm		if (debug)
903106862Snectar			syslog(LOG_DEBUG,
904106862Snectar			    "pam_krb5: verify_krb_v5_tgt(): %s: %s",
905106862Snectar			    "krb5_rd_req()",
906106862Snectar			    krb5_get_err_text(context, retval));
90781477Smarkm		retval = -1;
90881477Smarkm	}
90981477Smarkm	else
91081477Smarkm		retval = 1;
91181477Smarkm
91281477Smarkmcleanup:
91381477Smarkm	if (packet.data)
91481477Smarkm		compat_free_data_contents(context, &packet);
91581477Smarkm	krb5_free_principal(context, princ);
91681477Smarkm	return retval;
91781477Smarkm}
91881477Smarkm
91981477Smarkm/* Free the memory for cache_name. Called by pam_end() */
920111985Smarkm/* ARGSUSED */
92181477Smarkmstatic void
92289760Smarkmcleanup_cache(pam_handle_t *pamh __unused, void *data, int pam_end_status __unused)
92381477Smarkm{
92481477Smarkm	krb5_context pam_context;
92581477Smarkm	krb5_ccache ccache;
926106864Snectar	krb5_error_code krbret;
92781477Smarkm
92881477Smarkm	if (krb5_init_context(&pam_context))
92981477Smarkm		return;
93081477Smarkm
931106864Snectar	krbret = krb5_cc_resolve(pam_context, data, &ccache);
932106864Snectar	if (krbret == 0)
933106864Snectar		krb5_cc_destroy(pam_context, ccache);
93481477Smarkm	krb5_free_context(pam_context);
935106864Snectar	free(data);
93681477Smarkm}
93781477Smarkm
93881477Smarkm#ifdef COMPAT_HEIMDAL
93981477Smarkm#ifdef COMPAT_MIT
94081477Smarkm#error This cannot be MIT and Heimdal compatible!
94181477Smarkm#endif
94281477Smarkm#endif
94381477Smarkm
94481477Smarkm#ifndef COMPAT_HEIMDAL
94581477Smarkm#ifndef COMPAT_MIT
94681477Smarkm#error One of COMPAT_MIT and COMPAT_HEIMDAL must be specified!
94781477Smarkm#endif
94881477Smarkm#endif
94981477Smarkm
95081477Smarkm#ifdef COMPAT_HEIMDAL
951111985Smarkm/* ARGSUSED */
95281477Smarkmstatic const char *
95389760Smarkmcompat_princ_component(krb5_context context __unused, krb5_principal princ, int n)
95481477Smarkm{
95581477Smarkm	return princ->name.name_string.val[n];
95681477Smarkm}
95781477Smarkm
958111985Smarkm/* ARGSUSED */
95981477Smarkmstatic void
96089760Smarkmcompat_free_data_contents(krb5_context context __unused, krb5_data * data)
96181477Smarkm{
96281477Smarkm	krb5_xfree(data->data);
96381477Smarkm}
96481477Smarkm#endif
96581477Smarkm
96681477Smarkm#ifdef COMPAT_MIT
96781477Smarkmstatic const char *
96881477Smarkmcompat_princ_component(krb5_context context, krb5_principal princ, int n)
96981477Smarkm{
97081477Smarkm	return krb5_princ_component(context, princ, n)->data;
97181477Smarkm}
97281477Smarkm
97381477Smarkmstatic void
97481477Smarkmcompat_free_data_contents(krb5_context context, krb5_data * data)
97581477Smarkm{
97681477Smarkm	krb5_free_data_contents(context, data);
97781477Smarkm}
97881477Smarkm#endif
979