#ifdef __GNUC__
#ident "$Id: auth_krb5.c,v 1.1 2004/03/31 18:08:42 dasenbro Exp $"
#endif
#include "mechanisms.h"
#ifdef AUTH_KRB5
# include <krb5.h>
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/stat.h>
#include "auth_krb5.h"
#define TF_DIR "/.tf"
char *tf_dir = NULL;
int
auth_krb5_init (
void
)
{
#ifdef AUTH_KRB5
int rc;
struct stat sb;
tf_dir = malloc(strlen(PATH_SASLAUTHD_RUNDIR) + strlen(TF_DIR)
+ 1024 + 2);
if (tf_dir == NULL) {
syslog(LOG_ERR, "auth_krb5_init malloc(tf_dir) failed");
return -1;
}
strcpy(tf_dir, PATH_SASLAUTHD_RUNDIR);
strcat(tf_dir, TF_DIR);
rc = lstat(tf_dir, &sb);
if (rc == -1) {
if (errno == ENOENT) {
rc = mkdir(tf_dir, 0700);
if (rc == -1) {
syslog(LOG_ERR, "auth_krb5_init mkdir(%s): %m",
tf_dir);
free(tf_dir);
tf_dir = NULL;
return -1;
}
} else {
rc = errno;
syslog(LOG_ERR, "auth_krb5_init: %s: %m", tf_dir);
free(tf_dir);
tf_dir = NULL;
return -1;
}
}
if (S_ISLNK(sb.st_mode)) {
syslog(LOG_ERR, "auth_krb5_init: %s: is a symbolic link", tf_dir);
free(tf_dir);
tf_dir = NULL;
return -1;
}
return 0;
#else
return -1;
#endif
}
#ifdef AUTH_KRB5
#ifdef KRB5_HEIMDAL
char *
auth_krb5 (
const char *user,
const char *password,
const char *service __attribute__((unused)),
const char *realm __attribute__((unused))
)
{
krb5_context context;
krb5_ccache ccache = NULL;
krb5_principal auth_user;
char * result;
char tfname[2048];
if (!user|| !password) {
syslog(LOG_ERR, "auth_krb5: NULL password or username?");
return strdup("NO saslauthd internal NULL password or username");
}
if (krb5_init_context(&context)) {
syslog(LOG_ERR, "auth_krb5: krb5_init_context");
return strdup("NO saslauthd internal krb5_init_context error");
}
if (krb5_parse_name (context, user, &auth_user)) {
krb5_free_context(context);
syslog(LOG_ERR, "auth_krb5: krb5_parse_name");
return strdup("NO saslauthd internal krb5_parse_name error");
}
#ifdef SASLAUTHD_THREADED
snprintf(tfname,sizeof(tfname), "%s/k5cc_%d_%d", tf_dir,
getpid(), pthread_self());
#else
snprintf(tfname,sizeof(tfname), "%s/k5cc_%d", tf_dir, getpid());
#endif
if (krb5_cc_resolve(context, tfname, &ccache)) {
krb5_free_principal(context, auth_user);
krb5_free_context(context);
syslog(LOG_ERR, "auth_krb5: krb5_cc_resolve");
return strdup("NO saslauthd internal error");
}
if (krb5_cc_initialize (context, ccache, auth_user)) {
krb5_free_principal(context, auth_user);
krb5_cc_destroy(context, ccache);
krb5_free_context(context);
syslog(LOG_ERR, "auth_krb5: krb5_cc_initialize");
return strdup("NO saslauthd internal error");
}
if (krb5_verify_user(context, auth_user, ccache, password, 1, NULL)) {
result = strdup("NO krb5_verify_user failed");
} else {
result = strdup("OK");
}
krb5_free_principal(context, auth_user);
krb5_cc_destroy(context, ccache);
krb5_free_context(context);
return result;
}
#else
static int k5support_verify_tgt(krb5_context context,
krb5_ccache ccache)
{
krb5_principal server;
krb5_data packet;
krb5_keyblock *keyblock = NULL;
krb5_auth_context auth_context = NULL;
krb5_error_code k5_retcode;
char thishost[BUFSIZ];
int result = 0;
if (krb5_sname_to_principal(context, NULL, NULL,
KRB5_NT_SRV_HST, &server)) {
return 0;
}
if (krb5_kt_read_service_key(context, NULL, server, 0,
0, &keyblock)) {
goto fini;
}
if (keyblock) {
krb5_free_keyblock(context, keyblock);
}
if (gethostname(thishost, BUFSIZ) < 0) {
goto fini;
}
thishost[BUFSIZ-1] = '\0';
#ifdef KRB5_HEIMDAL
krb5_data_zero(&packet);
#endif
k5_retcode = krb5_mk_req(context, &auth_context, 0, "host",
thishost, NULL, ccache, &packet);
if (auth_context) {
krb5_auth_con_free(context, auth_context);
auth_context = NULL;
}
if (k5_retcode) {
goto fini;
}
if (krb5_rd_req(context, &auth_context, &packet,
server, NULL, NULL, NULL)) {
goto fini;
}
if (auth_context) {
krb5_auth_con_free(context, auth_context);
auth_context = NULL;
}
result = 1;
fini:
#ifndef KRB5_HEIMDAL
krb5_free_data_contents(context, &packet);
#endif
krb5_free_principal(context, server);
return result;
}
char *
auth_krb5 (
const char *user,
const char *password,
const char *service __attribute__((unused)),
const char *realm __attribute__((unused))
)
{
krb5_context context;
krb5_ccache ccache = NULL;
krb5_principal auth_user;
krb5_creds creds;
krb5_get_init_creds_opt opts;
char * result;
char tfname[40];
if (!user|| !password) {
syslog(LOG_ERR, "auth_krb5: NULL password or username?");
return strdup("NO saslauthd internal error");
}
if (krb5_init_context(&context)) {
syslog(LOG_ERR, "auth_krb5: krb5_init_context");
return strdup("NO saslauthd internal error");
}
if (krb5_parse_name (context, user, &auth_user)) {
krb5_free_context(context);
syslog(LOG_ERR, "auth_krb5: krb5_parse_name");
return strdup("NO saslauthd internal error");
}
snprintf(tfname,sizeof(tfname), "/tmp/k5cc_%d", getpid());
if (krb5_cc_resolve(context, tfname, &ccache)) {
krb5_free_principal(context, auth_user);
krb5_free_context(context);
syslog(LOG_ERR, "auth_krb5: krb5_cc_resolve");
return strdup("NO saslauthd internal error");
}
if (krb5_cc_initialize (context, ccache, auth_user)) {
krb5_free_principal(context, auth_user);
krb5_free_context(context);
syslog(LOG_ERR, "auth_krb5: krb5_cc_initialize");
return strdup("NO saslauthd internal error");
}
krb5_get_init_creds_opt_init(&opts);
krb5_get_init_creds_opt_set_tkt_life(&opts, 900);
if (krb5_get_init_creds_password(context, &creds,
auth_user, password, NULL, NULL,
0, NULL, &opts)) {
krb5_cc_destroy(context, ccache);
krb5_free_principal(context, auth_user);
krb5_free_context(context);
syslog(LOG_ERR, "auth_krb5: krb5_get_init_creds_password");
return strdup("NO saslauthd internal error");
}
if (krb5_cc_store_cred(context, ccache, &creds)) {
krb5_free_principal(context, auth_user);
krb5_cc_destroy(context, ccache);
krb5_free_context(context);
syslog(LOG_ERR, "auth_krb5: krb5_cc_store_cred");
return strdup("NO saslauthd internal error");
}
if (!k5support_verify_tgt(context, ccache)) {
syslog(LOG_ERR, "auth_krb5: k5support_verify_tgt");
result = strdup("NO saslauthd internal error");
goto fini;
}
result = strdup("OK");
fini:
krb5_free_cred_contents(context, &creds);
krb5_free_principal(context, auth_user);
krb5_cc_destroy(context, ccache);
krb5_free_context(context);
return result;
}
#endif
#else
char *
auth_krb5 (
const char *login __attribute__((unused)),
const char *password __attribute__((unused)),
const char *service __attribute__((unused)),
const char *realm __attribute__((unused))
)
{
return NULL;
}
#endif