Restructured and also seems to work!
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@7949 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska H<>gskolan
|
||||
* Copyright (c) 1995 - 2000 Kungliga Tekniska H<>gskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -31,10 +31,6 @@
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* This code is extremely ugly, and would probably be better off
|
||||
beeing completely rewritten */
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include<config.h>
|
||||
RCSID("$Id$");
|
||||
@@ -46,6 +42,7 @@ RCSID("$Id$");
|
||||
#include <pwd.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#define PAM_SM_AUTH
|
||||
#define PAM_SM_SESSION
|
||||
@@ -56,188 +53,366 @@ RCSID("$Id$");
|
||||
#include <krb.h>
|
||||
#include <kafs.h>
|
||||
|
||||
static int
|
||||
cleanup(pam_handle_t *pamh, void *data, int error_code)
|
||||
#if 0
|
||||
/* Debugging PAM modules is a royal pain, truss helps. */
|
||||
#define DEBUG(msg) (access(msg " at line", __LINE__))
|
||||
#endif
|
||||
|
||||
static void
|
||||
log_error(int level, const char *format, ...)
|
||||
{
|
||||
if(error_code != PAM_SUCCESS)
|
||||
dest_tkt();
|
||||
free(data);
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
openlog("pam_krb4", LOG_CONS|LOG_PID, LOG_AUTH);
|
||||
vsyslog(level | LOG_AUTH, format, args);
|
||||
va_end(args);
|
||||
closelog();
|
||||
}
|
||||
|
||||
enum {
|
||||
KRB4_DEBUG,
|
||||
KRB4_USE_FIRST_PASS,
|
||||
KRB4_TRY_FIRST_PASS,
|
||||
KRB4_IGNORE_ROOT,
|
||||
KRB4_NO_VERIFY,
|
||||
KRB4_REAFSLOG,
|
||||
KRB4_CTRLS /* Number of ctrl arguments defined. */
|
||||
};
|
||||
|
||||
#define KRB4_DEFAULTS 0
|
||||
|
||||
static int ctrl_flags = KRB4_DEFAULTS;
|
||||
#define ctrl_on(x) (krb4_args[x].flag & ctrl_flags)
|
||||
#define ctrl_off(x) (!ctrl_on(x))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *token;
|
||||
unsigned int flag;
|
||||
} krb4_ctrls_t;
|
||||
|
||||
static krb4_ctrls_t krb4_args[KRB4_CTRLS] =
|
||||
{
|
||||
/* KRB4_DEBUG */ { "debug", 0x01 },
|
||||
/* KRB4_USE_FIRST_PASS */ { "use_first_pass", 0x02 },
|
||||
/* KRB4_TRY_FIRST_PASS */ { "try_first_pass", 0x04 },
|
||||
/* KRB4_IGNORE_ROOT */ { "ignore_root", 0x08 },
|
||||
/* KRB4_NO_VERIFY */ { "no_verify", 0x10 },
|
||||
/* KRB4_REAFSLOG */ { "reafslog", 0x20 },
|
||||
};
|
||||
|
||||
static void
|
||||
parse_ctrl(int argc, const char **argv)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
ctrl_flags = KRB4_DEFAULTS;
|
||||
for (i = 0; i < argc; i++)
|
||||
{
|
||||
for (j = 0; j < KRB4_CTRLS; j++)
|
||||
if (strcmp(argv[i], krb4_args[j].token) == 0)
|
||||
break;
|
||||
|
||||
if (j >= KRB4_CTRLS)
|
||||
log_error(LOG_ALERT, "unrecognized option [%s]", *argv);
|
||||
else
|
||||
ctrl_flags |= krb4_args[j].flag;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pdeb(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
if (ctrl_off(KRB4_DEBUG))
|
||||
return;
|
||||
va_start(args, format);
|
||||
openlog("pam_krb4", LOG_PID, LOG_AUTH);
|
||||
vsyslog(LOG_DEBUG | LOG_AUTH, format, args);
|
||||
va_end(args);
|
||||
closelog();
|
||||
}
|
||||
|
||||
#define ENTRY(f) pdeb("%s() ruid = %d euid = %d", f, getuid(), geteuid())
|
||||
|
||||
static void
|
||||
set_tkt_string(uid_t uid)
|
||||
{
|
||||
char buf[128];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s%u", TKT_ROOT, (unsigned)uid);
|
||||
krb_set_tkt_string(buf);
|
||||
|
||||
#if 0
|
||||
/* pam_set_data+pam_get_data are not guaranteed to work, grr. */
|
||||
pam_set_data(pamh, "KRBTKFILE", strdup(t), cleanup);
|
||||
if (pam_get_data(pamh, "KRBTKFILE", (const void**)&tkt) == PAM_SUCCESS)
|
||||
{
|
||||
pam_putenv(pamh, var);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* We don't want to inherit this variable.
|
||||
* If we still do, it must have a sane value. */
|
||||
if (getenv("KRBTKFILE") != 0)
|
||||
{
|
||||
char *var = malloc(sizeof(buf));
|
||||
snprintf(var, sizeof(buf), "KRBTKFILE=%s", tkt_string());
|
||||
putenv(var);
|
||||
/* free(var); XXX */
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
verify_pass(pam_handle_t *pamh,
|
||||
const char *name,
|
||||
const char *inst,
|
||||
const char *pass)
|
||||
{
|
||||
char realm[REALM_SZ];
|
||||
int ret, krb_verify, old_euid, old_ruid;
|
||||
|
||||
krb_get_lrealm(realm, 1);
|
||||
if (ctrl_on(KRB4_NO_VERIFY))
|
||||
krb_verify = KRB_VERIFY_SECURE_FAIL;
|
||||
else
|
||||
krb_verify = KRB_VERIFY_SECURE;
|
||||
old_ruid = getuid();
|
||||
old_euid = geteuid();
|
||||
setreuid(0, 0);
|
||||
ret = krb_verify_user(name, inst, realm, pass, krb_verify, NULL);
|
||||
if (setreuid(old_ruid, old_euid) != 0)
|
||||
{
|
||||
log_error(LOG_ALERT , "setreuid(%d, %d) failed", old_ruid, old_euid);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
switch(ret) {
|
||||
case KSUCCESS:
|
||||
return PAM_SUCCESS;
|
||||
case KDC_PR_UNKNOWN:
|
||||
return PAM_USER_UNKNOWN;
|
||||
case SKDC_CANT:
|
||||
case SKDC_RETRY:
|
||||
case RD_AP_TIME:
|
||||
return PAM_AUTHINFO_UNAVAIL;
|
||||
default:
|
||||
return PAM_AUTH_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
doit(pam_handle_t *pamh, char *name, char *inst, char *pwd, char *tkt)
|
||||
krb4_auth(pam_handle_t *pamh,
|
||||
int flags,
|
||||
const char *name,
|
||||
const char *inst,
|
||||
struct pam_conv *conv)
|
||||
{
|
||||
char realm[REALM_SZ];
|
||||
int ret;
|
||||
struct pam_response *resp;
|
||||
char prompt[128];
|
||||
struct pam_message msg, *pmsg = &msg;
|
||||
int ret;
|
||||
|
||||
pam_set_data(pamh, "KRBTKFILE", strdup(tkt), cleanup);
|
||||
krb_set_tkt_string(tkt);
|
||||
|
||||
krb_get_lrealm(realm, 1);
|
||||
ret = krb_verify_user(name, inst, realm, pwd, KRB_VERIFY_SECURE, NULL);
|
||||
memset(pwd, 0, strlen(pwd));
|
||||
switch(ret){
|
||||
case KSUCCESS:
|
||||
if (ctrl_on(KRB4_TRY_FIRST_PASS) || ctrl_on(KRB4_USE_FIRST_PASS))
|
||||
{
|
||||
char *pass = 0;
|
||||
ret = pam_get_item(pamh, PAM_AUTHTOK, (void **) &pass);
|
||||
if (ret != PAM_SUCCESS)
|
||||
{
|
||||
log_error(LOG_ERR , "pam_get_item returned error to get-password");
|
||||
return ret;
|
||||
}
|
||||
else if (pass != 0 && verify_pass(pamh, name, inst, pass) ==PAM_SUCCESS)
|
||||
return PAM_SUCCESS;
|
||||
case KDC_PR_UNKNOWN:
|
||||
return PAM_USER_UNKNOWN;
|
||||
case SKDC_CANT:
|
||||
case SKDC_RETRY:
|
||||
case RD_AP_TIME:
|
||||
return PAM_AUTHINFO_UNAVAIL;
|
||||
default:
|
||||
return PAM_AUTH_ERR;
|
||||
else if (ctrl_on(KRB4_USE_FIRST_PASS))
|
||||
return PAM_AUTHTOK_RECOVERY_ERR; /* Wrong password! */
|
||||
else
|
||||
/* We tried the first password but it didn't work, cont. */;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
auth_login(pam_handle_t *pamh, int flags, char *user, struct pam_conv *conv)
|
||||
{
|
||||
int ret;
|
||||
struct pam_message msg, *pmsg;
|
||||
struct pam_response *resp;
|
||||
char prompt[128];
|
||||
msg.msg_style = PAM_PROMPT_ECHO_OFF;
|
||||
if (*inst == 0)
|
||||
snprintf(prompt, sizeof(prompt), "%s's Password: ", name);
|
||||
else
|
||||
snprintf(prompt, sizeof(prompt), "%s.%s's Password: ", name, inst);
|
||||
msg.msg = prompt;
|
||||
|
||||
pmsg = &msg;
|
||||
msg.msg_style = PAM_PROMPT_ECHO_OFF;
|
||||
snprintf(prompt, sizeof(prompt), "%s's Password: ", user);
|
||||
msg.msg = prompt;
|
||||
|
||||
ret = conv->conv(1, (const struct pam_message**)&pmsg,
|
||||
&resp, conv->appdata_ptr);
|
||||
if(ret != PAM_SUCCESS)
|
||||
return ret;
|
||||
|
||||
{
|
||||
char tkt[1024];
|
||||
struct passwd *pw = getpwnam(user);
|
||||
|
||||
if(pw){
|
||||
snprintf(tkt, sizeof(tkt),
|
||||
"%s%u", TKT_ROOT, (unsigned)pw->pw_uid);
|
||||
ret = doit(pamh, user, "", resp->resp, tkt);
|
||||
if(ret == PAM_SUCCESS)
|
||||
chown(tkt, pw->pw_uid, pw->pw_gid);
|
||||
}else
|
||||
ret = PAM_USER_UNKNOWN;
|
||||
memset(resp->resp, 0, strlen(resp->resp));
|
||||
free(resp->resp);
|
||||
free(resp);
|
||||
}
|
||||
ret = conv->conv(1, &pmsg, &resp, conv->appdata_ptr);
|
||||
if (ret != PAM_SUCCESS)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
auth_su(pam_handle_t *pamh, int flags, char *user, struct pam_conv *conv)
|
||||
{
|
||||
int ret;
|
||||
struct passwd *pw;
|
||||
struct pam_message msg, *pmsg;
|
||||
struct pam_response *resp;
|
||||
char prompt[128];
|
||||
krb_principal pr;
|
||||
|
||||
pr.realm[0] = 0;
|
||||
ret = pam_get_user(pamh, &user, "login: ");
|
||||
if(ret != PAM_SUCCESS)
|
||||
return ret;
|
||||
|
||||
pw = getpwuid(getuid());
|
||||
if(strcmp(user, "root") == 0){
|
||||
strlcpy(pr.name, pw->pw_name, sizeof(pr.name));
|
||||
strlcpy(pr.instance, "root", sizeof(pr.instance));
|
||||
}else{
|
||||
strlcpy(pr.name, user, sizeof(pr.name));
|
||||
pr.instance[0] = 0;
|
||||
}
|
||||
pmsg = &msg;
|
||||
msg.msg_style = PAM_PROMPT_ECHO_OFF;
|
||||
snprintf(prompt, sizeof(prompt), "%s's Password: ", krb_unparse_name(&pr));
|
||||
msg.msg = prompt;
|
||||
|
||||
ret = conv->conv(1, (const struct pam_message**)&pmsg,
|
||||
&resp, conv->appdata_ptr);
|
||||
if(ret != PAM_SUCCESS)
|
||||
return ret;
|
||||
|
||||
ret = verify_pass(pamh, name, inst, resp->resp);
|
||||
if (ret == PAM_SUCCESS)
|
||||
{
|
||||
char tkt[1024];
|
||||
|
||||
snprintf(tkt, sizeof(tkt),"%s_%s_to_%s",
|
||||
TKT_ROOT, pw->pw_name, user);
|
||||
ret = doit(pamh, pr.name, pr.instance, resp->resp, tkt);
|
||||
if(ret == PAM_SUCCESS)
|
||||
chown(tkt, pw->pw_uid, pw->pw_gid);
|
||||
memset(resp->resp, 0, strlen(resp->resp));
|
||||
free(resp->resp);
|
||||
free(resp);
|
||||
memset(resp->resp, 0, strlen(resp->resp)); /* Erase password! */
|
||||
free(resp->resp);
|
||||
free(resp);
|
||||
}
|
||||
return ret;
|
||||
else
|
||||
{
|
||||
pam_set_item(pamh, PAM_AUTHTOK, resp->resp); /* Save password. */
|
||||
/* free(resp->resp); XXX */
|
||||
/* free(resp); XXX */
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
|
||||
pam_sm_authenticate(pam_handle_t *pamh,
|
||||
int flags,
|
||||
int argc,
|
||||
const char **argv)
|
||||
{
|
||||
char *user;
|
||||
int ret;
|
||||
struct pam_conv *conv;
|
||||
ret = pam_get_user(pamh, &user, "login: ");
|
||||
if(ret != PAM_SUCCESS)
|
||||
return ret;
|
||||
char *user;
|
||||
int ret;
|
||||
struct pam_conv *conv;
|
||||
struct passwd *pw;
|
||||
uid_t uid = -1;
|
||||
const char *name, *inst;
|
||||
|
||||
ret = pam_get_item(pamh, PAM_CONV, (void*)&conv);
|
||||
if(ret != PAM_SUCCESS)
|
||||
return ret;
|
||||
parse_ctrl(argc, argv);
|
||||
ENTRY("pam_sm_authenticate");
|
||||
|
||||
ret = pam_get_user(pamh, &user, "login: ");
|
||||
if (ret != PAM_SUCCESS)
|
||||
return ret;
|
||||
|
||||
if (ctrl_on(KRB4_IGNORE_ROOT) && strcmp(user, "root") == 0)
|
||||
return PAM_AUTHINFO_UNAVAIL;
|
||||
|
||||
ret = pam_get_item(pamh, PAM_CONV, (void*)&conv);
|
||||
if (ret != PAM_SUCCESS)
|
||||
return ret;
|
||||
|
||||
pw = getpwnam(user);
|
||||
if (pw != 0)
|
||||
{
|
||||
uid = pw->pw_uid;
|
||||
set_tkt_string(uid);
|
||||
}
|
||||
|
||||
if(getuid() != geteuid())
|
||||
return auth_su(pamh, flags, user, conv);
|
||||
else
|
||||
return auth_login(pamh, flags, user, conv);
|
||||
if (strcmp(user, "root") == 0 && getuid() != 0)
|
||||
{
|
||||
pw = getpwuid(getuid());
|
||||
if (pw != 0)
|
||||
{
|
||||
name = strdup(pw->pw_name);
|
||||
inst = "root";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
name = user;
|
||||
inst = "";
|
||||
}
|
||||
|
||||
ret = krb4_auth(pamh, flags, name, inst, conv);
|
||||
|
||||
/*
|
||||
* The realm was lost inside krb_verify_user() so we can't simply do
|
||||
* a krb_kuserok() when inst != "".
|
||||
*/
|
||||
if (ret == PAM_SUCCESS && inst[0] != 0)
|
||||
{
|
||||
char realm[REALM_SZ];
|
||||
uid_t old_euid = geteuid();
|
||||
uid_t old_ruid = getuid();
|
||||
|
||||
realm[0] = 0;
|
||||
setreuid(0, 0); /* To read ticket file. */
|
||||
if (krb_get_tf_fullname(tkt_string(), 0, 0, realm) != KSUCCESS)
|
||||
ret = PAM_SERVICE_ERR;
|
||||
else if (krb_kuserok(name, inst, realm, user) != KSUCCESS)
|
||||
{
|
||||
setreuid(0, uid); /* To read ~/.klogin. */
|
||||
if (krb_kuserok(name, inst, realm, user) != KSUCCESS)
|
||||
ret = PAM_PERM_DENIED;
|
||||
}
|
||||
|
||||
if (ret != PAM_SUCCESS)
|
||||
{
|
||||
dest_tkt(); /* Passwd known, ok to kill ticket. */
|
||||
log_error(LOG_NOTICE,
|
||||
"%s.%s@%s is not allowed to log in as %s",
|
||||
name, inst, realm, user);
|
||||
}
|
||||
|
||||
if (setreuid(old_ruid, old_euid) != 0)
|
||||
{
|
||||
log_error(LOG_ALERT , "setreuid(%d, %d) failed", old_ruid, old_euid);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == PAM_SUCCESS)
|
||||
chown(tkt_string(), uid, -1);
|
||||
|
||||
/* Sun dtlogin unlock screen does not call any other pam_* funcs. */
|
||||
if (ret == PAM_SUCCESS
|
||||
&& ctrl_on(KRB4_REAFSLOG)
|
||||
&& k_hasafs()
|
||||
&& (pw = getpwnam(user)) != 0)
|
||||
krb_afslog_uid_home(/*cell*/ 0,/*realm_hint*/ 0, pw->pw_uid, pw->pw_dir);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
|
||||
{
|
||||
return PAM_SUCCESS;
|
||||
}
|
||||
parse_ctrl(argc, argv);
|
||||
ENTRY("pam_sm_setcred");
|
||||
|
||||
switch (flags & ~PAM_SILENT) {
|
||||
case 0:
|
||||
case PAM_ESTABLISH_CRED:
|
||||
if (k_hasafs())
|
||||
{
|
||||
void *user = 0;
|
||||
|
||||
k_setpag();
|
||||
if (pam_get_item(pamh, PAM_USER, &user) == PAM_SUCCESS)
|
||||
{
|
||||
struct passwd *pw = getpwnam((char *)user);
|
||||
if (pw != 0)
|
||||
krb_afslog_uid_home(/*cell*/ 0,/*realm_hint*/ 0,
|
||||
pw->pw_uid, pw->pw_dir);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PAM_REINITIALIZE_CRED:
|
||||
case PAM_REFRESH_CRED:
|
||||
case PAM_DELETE_CRED:
|
||||
break;
|
||||
default:
|
||||
log_error(LOG_ALERT , "pam_sm_setcred: unknown flags 0x%x", flags);
|
||||
break;
|
||||
}
|
||||
|
||||
return PAM_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
|
||||
{
|
||||
char *tkt, *var;
|
||||
void *user;
|
||||
const char *homedir = NULL;
|
||||
parse_ctrl(argc, argv);
|
||||
ENTRY("pam_sm_open_session");
|
||||
|
||||
if(pam_get_item (pamh, PAM_USER, &user) == PAM_SUCCESS) {
|
||||
struct passwd *pwd;
|
||||
|
||||
pwd = getpwnam ((char *)user);
|
||||
if (pwd != NULL)
|
||||
homedir = pwd->pw_dir;
|
||||
}
|
||||
|
||||
pam_get_data(pamh, "KRBTKFILE", (const void**)&tkt);
|
||||
var = malloc(strlen("KRBTKFILE=") + strlen(tkt) + 1);
|
||||
strcpy(var, "KRBTKFILE=");
|
||||
strcat(var, tkt);
|
||||
putenv(var);
|
||||
pam_putenv(pamh, var);
|
||||
if(k_hasafs()){
|
||||
k_setpag();
|
||||
krb_afslog_home(0, 0, homedir);
|
||||
}
|
||||
return PAM_SUCCESS;
|
||||
return PAM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
|
||||
pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char**argv)
|
||||
{
|
||||
dest_tkt();
|
||||
if(k_hasafs())
|
||||
k_unlog();
|
||||
return PAM_SUCCESS;
|
||||
parse_ctrl(argc, argv);
|
||||
ENTRY("pam_sm_close_session");
|
||||
|
||||
/* This isn't really kosher, but it's handy. */
|
||||
dest_tkt();
|
||||
if (k_hasafs())
|
||||
k_unlog();
|
||||
|
||||
return PAM_SUCCESS;
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
To enable PAM in dtlogin and /bin/login under SunOS 5.6 apply this patch:
|
||||
|
||||
--- /etc/pam.conf.DIST Mon Jul 20 15:37:46 1998
|
||||
+++ /etc/pam.conf Tue Nov 30 18:47:22 1999
|
||||
@@ -4,12 +4,14 @@
|
||||
+++ /etc/pam.conf Tue Feb 15 19:39:12 2000
|
||||
@@ -4,15 +4,19 @@
|
||||
#
|
||||
# Authentication management
|
||||
#
|
||||
@@ -17,12 +17,17 @@ To enable PAM in dtlogin and /bin/login under SunOS 5.6 apply this patch:
|
||||
dtlogin auth required /usr/lib/security/pam_unix.so.1
|
||||
#
|
||||
rsh auth required /usr/lib/security/pam_rhosts_auth.so.1
|
||||
@@ -24,6 +26,8 @@
|
||||
+# Reafslog is for dtlogin lock display
|
||||
+other auth sufficient /usr/athena/lib/pam_krb4.so reafslog
|
||||
other auth required /usr/lib/security/pam_unix.so.1
|
||||
#
|
||||
# Account management
|
||||
@@ -24,6 +28,8 @@
|
||||
#
|
||||
# Session management
|
||||
#
|
||||
+dtlogin session required /usr/athena/lib/pam_krb4.so
|
||||
+login session required /usr/athena/lib/pam_krb4.so
|
||||
+dtlogin session required /usr/athena/lib/pam_krb4.so
|
||||
+login session required /usr/athena/lib/pam_krb4.so
|
||||
other session required /usr/lib/security/pam_unix.so.1
|
||||
#
|
||||
# Password management
|
||||
|
Reference in New Issue
Block a user