OpenBSD-4.6/libexec/login_krb5/login_krb5.c
/* $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);
}