OpenBSD-4.6/libexec/login_krb5/login_krb5.c

Compare this file to the similar file:
Show the results in this format:

/*	$OpenBSD: login_krb5.c,v 1.25 2009/01/14 14:53:44 jacekm Exp $	*/

/*-
 * Copyright (c) 2001, 2002 Hans Insulander <hin@openbsd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include "common.h"

#include <kerberosV/krb5.h>

krb5_error_code ret;
krb5_context context;
krb5_ccache ccache;
krb5_principal princ;

char *__progname;

static void
krb5_syslog(krb5_context context, int level, krb5_error_code code, char *fmt, ...)
{
	va_list ap;
	char buf[256];

	va_start(ap, fmt);
	vsnprintf(buf, sizeof(buf), fmt, ap);
	va_end(ap);
	syslog(level, "%s: %s", buf, krb5_get_err_text(context, code));
}

static void
store_tickets(struct passwd *pwd, int ticket_newfiles, int ticket_store,
    int token_install)
{
	char cc_file[MAXPATHLEN];
	krb5_ccache ccache_store;
#ifdef KRB524
	int get_krb4_ticket = 0;
	char krb4_ticket_file[MAXPATHLEN];
#endif

	if (ticket_newfiles)
		snprintf(cc_file, sizeof(cc_file), "FILE:/tmp/krb5cc_%d",
		    pwd->pw_uid);
	else
		snprintf(cc_file, sizeof(cc_file), "%s",
		    krb5_cc_default_name(context));

	if (ticket_store) {
		ret = krb5_cc_resolve(context, cc_file, &ccache_store);
		if (ret != 0) {
			krb5_syslog(context, LOG_ERR, ret,
			    "krb5_cc_gen_new");
			exit(1);
		}

		ret = krb5_cc_copy_cache(context, ccache, ccache_store);
		if (ret != 0)
			krb5_syslog(context, LOG_ERR, ret,
			    "krb5_cc_copy_cache");

		chown(krb5_cc_get_name(context, ccache_store),
		    pwd->pw_uid, pwd->pw_gid);

		fprintf(back, BI_SETENV " KRB5CCNAME %s:%s\n",
		    krb5_cc_get_type(context, ccache_store),
		    krb5_cc_get_name(context, ccache_store));

#ifdef KRB524
		get_krb4_ticket = krb5_config_get_bool_default (context,
		    NULL, get_krb4_ticket, "libdefaults",
		    "krb4_get_tickets", NULL);
		if (get_krb4_ticket) {
			CREDENTIALS c;
			krb5_creds cred;
			krb5_cc_cursor cursor;

			ret = krb5_cc_start_seq_get(context, ccache, &cursor);
			if (ret != 0) {
				krb5_syslog(context, LOG_ERR, ret,
				    "start seq");
				exit(1);
			}

			ret = krb5_cc_next_cred(context, ccache,
			    &cursor, &cred);
			if (ret != 0) {
				krb5_syslog(context, LOG_ERR, ret,
				    "next cred");
				exit(1);
			}

			ret = krb5_cc_end_seq_get(context, ccache,
			    &cursor);
			if (ret != 0) {
				krb5_syslog(context, LOG_ERR, ret,
				    "end seq");
				exit(1);
			}

			ret = krb524_convert_creds_kdc_ccache(context, ccache,
			    &cred, &c);
			if (ret != 0) {
				krb5_syslog(context, LOG_ERR, ret,
				    "convert");
			} else {
				snprintf(krb4_ticket_file,
				    sizeof(krb4_ticket_file),
				    "%s%d", TKT_ROOT, pwd->pw_uid);
				krb_set_tkt_string(krb4_ticket_file);
				tf_setup(&c, c.pname, c.pinst);
				chown(krb4_ticket_file,
				    pwd->pw_uid, pwd->pw_gid);
			}
		}
#endif
	}

	/* Need to chown the ticket file */
#ifdef KRB524
	if (get_krb4_ticket)
		fprintf(back, BI_SETENV " KRBTKFILE %s\n",
		    krb4_ticket_file);
#endif
}

int
krb5_login(char *username, char *invokinguser, char *password, int login,
    int tickets)
{
	int return_code = AUTH_FAILED;

	if (username == NULL || password == NULL)
		return (AUTH_FAILED);

	if (strcmp(__progname, "krb5-or-pwd") == 0 &&
	    strcmp(username,"root") == 0 && invokinguser[0] == '\0')
		return (AUTH_FAILED);

	ret = krb5_init_context(&context);
	if (ret != 0) {
		krb5_syslog(context, LOG_ERR, ret, "krb5_init_context");
		exit(1);
	}

	ret = krb5_cc_gen_new(context, &krb5_mcc_ops, &ccache);
	if (ret != 0) {
		krb5_syslog(context, LOG_ERR, ret, "krb5_cc_gen_new");
		exit(1);
	}

	if (strcmp(username, "root") == 0 && invokinguser[0] != '\0') {
		char *tmp;

		ret = asprintf(&tmp, "%s/root", invokinguser);
		if (ret == -1) {
			krb5_syslog(context, LOG_ERR, ret, "asprintf");
			exit(1);
		}
		ret = krb5_parse_name(context, tmp, &princ);
		free(tmp);
	} else
		ret = krb5_parse_name(context, username, &princ);
	if (ret != 0) {
		krb5_syslog(context, LOG_ERR, ret, "krb5_parse_name");
		exit(1);
	}

	ret = krb5_verify_user_lrealm(context, princ, ccache,
	    password, 1, NULL);

	switch (ret) {
	case 0: {
		struct passwd *pwd;

		pwd = getpwnam(username);
		if (pwd == NULL) {
			krb5_syslog(context, LOG_ERR, ret,
			    "%s: no such user", username);
			return (AUTH_FAILED);
		}
		fprintf(back, BI_AUTH "\n");
		store_tickets(pwd, login && tickets, login && tickets, login);
		return_code = AUTH_OK;
		break;
	}
	case KRB5KRB_AP_ERR_MODIFIED:
		/* XXX syslog here? */
	case KRB5KRB_AP_ERR_BAD_INTEGRITY:
		break;
	default:
		krb5_syslog(context, LOG_ERR, ret, "verify");
		break;
	}

	krb5_free_principal(context, princ);
	krb5_cc_close(context, ccache);
	krb5_free_context(context);

	return (return_code);
}