diff --git a/lib/auth/pam/Makefile.in b/lib/auth/pam/Makefile.in new file mode 100644 index 000000000..3f24732f3 --- /dev/null +++ b/lib/auth/pam/Makefile.in @@ -0,0 +1,75 @@ +# +# $Id$ +# + +SHELL = /bin/sh + +srcdir = @srcdir@ +VPATH = @srcdir@ + +CC = @CC@ +AR = ar +RANLIB = @RANLIB@ +DEFS = @DEFS@ +CFLAGS = @CFLAGS@ + +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +MKINSTALLDIRS = @top_srcdir@/mkinstalldirs + +prefix = @prefix@ +exec_prefix = $(prefix) +libdir = $(exec_prefix)/lib + +PICFLAGS = @PICFLAGS@ + +LIB = @PAM_LIB@ + +SOURCES = pam.c + +OBJECTS = pam.o + +all: $(LIB) + +Wall: + make CFLAGS="-g -Wall -Wmissing-prototypes -Wmissing-declarations -D__USE_FIXED_PROTOTYPES__" + +.c.o: + $(CC) -c $(CPPFLAGS) $(DEFS) -I../../.. -I../../../include -I$(srcdir) $(CFLAGS) $(PICFLAGS) $< + +install: all + $(MKINSTALLDIRS) $(libdir) + -if test "$(LIB)" != ""; then \ + $(INSTALL) -m 0555 $(LIB) $(libdir) ; \ + fi + +uninstall: + +TAGS: $(SOURCES) + etags $(SOURCES) + +check: + +clean: + rm -f $(LIB) *.o + +mostlyclean: clean + +distclean: clean + rm -f Makefile *.tab.c *~ + rm -rf CVS + +realclean: distclean + rm -f TAGS + +dist: $(DISTFILES) + for file in $(DISTFILES); do \ + ln $$file ../`cat ../.fname`/lib \ + || cp -p $$file ../`cat ../.fname`/lib; \ + done + + +$(OBJECTS): ../../../config.h + +$(LIB): $(OBJECTS) + $(CC) -shared -Wl,-x -o $(LIB) $(OBJECTS) ../../kafs/libkafs.a ../../krb/libkrb.a ../../des/libdes.a diff --git a/lib/auth/pam/README b/lib/auth/pam/README new file mode 100644 index 000000000..292c0a0ba --- /dev/null +++ b/lib/auth/pam/README @@ -0,0 +1,17 @@ + ------------------------------------------------------------ + | NOTE: This is currently just experimental code, it might | + | not work as expected. You have been warned. | + ------------------------------------------------------------ + +This is a quick attempt at a PAM module for Kerberos. You don't really +want to use this, but if you feel suicidal you will have to do the +following: + +* Make sure pam_krb4.so is available in /usr/athena/lib. You might + actually want it on local disk, so /lib/security might be a better + place if /usr/athena is not local. + +* Look at pam.conf.add for examples of what to add to /etc/pam.conf + +There is currently no support for changing kerberos passwords. Use +kpasswd instead. diff --git a/lib/auth/pam/pam.c b/lib/auth/pam/pam.c new file mode 100644 index 000000000..fe29c2790 --- /dev/null +++ b/lib/auth/pam/pam.c @@ -0,0 +1,226 @@ +/* + * Copyright (c) 1995, 1996 Kungliga Tekniska Högskolan (Royal Institute + * of Technology, Stockholm, Sweden). + * 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. + * + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the Kungliga Tekniska + * Högskolan and its contributors. + * + * 4. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE 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 INSTITUTE 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. + */ + +/* This code is extremely ugly, and would probably be better off + beeing completely rewritten */ + + +#ifdef HAVE_CONFIG_H +#include +RCSID("$Id$"); +#endif + +#include +#include +#include +#include +#include + +#define PAM_SM_AUTH +#define PAM_SM_SESSION +#include + +#include +#include +#include + +static int +cleanup(pam_handle_t *pamh, void *data, int error_code) +{ + if(error_code != PAM_SUCCESS) + dest_tkt(); + free(data); + return PAM_SUCCESS; +} + +static int +doit(pam_handle_t *pamh, char *name, char *inst, char *pwd, char *tkt) +{ + char realm[REALM_SZ]; + 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, 1, NULL); + memset(pwd, 0, strlen(pwd)); + 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 +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]; + + pmsg = &msg; + msg.msg_style = PAM_PROMPT_ECHO_OFF; + sprintf(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){ + sprintf(tkt, "%s%d", TKT_ROOT, pw->pw_uid); + ret = doit(pamh, user, "", resp->resp, tkt); + if(ret == PAM_SUCCESS) + chown(tkt, pw->pw_uid, pw->pw_uid); + }else + ret = PAM_USER_UNKNOWN; + memset(resp->resp, 0, strlen(resp->resp)); + free(resp->resp); + free(resp); + } + 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]; + char name[ANAME_SZ], inst[INST_SZ]; + + ret = pam_get_user(pamh, &user, "login: "); + if(ret != PAM_SUCCESS) + return ret; + + pw = getpwuid(getuid()); + if(strcmp(user, "root") == 0){ + strcpy(name, pw->pw_name); + strcpy(inst, "root"); + }else{ + strcpy(name, user); + inst[0] = 0; + } + pmsg = &msg; + msg.msg_style = PAM_PROMPT_ECHO_OFF; + sprintf(prompt, "%s%s%s's Password: ", name, inst[0]?".":"", inst); + 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]; + sprintf(tkt, "%s_%s_to_%s", TKT_ROOT, pw->pw_name, user); + ret = doit(pamh, name, inst, resp->resp, tkt); + if(ret == PAM_SUCCESS) + chown(tkt, pw->pw_uid, pw->pw_uid); + memset(resp->resp, 0, strlen(resp->resp)); + free(resp->resp); + free(resp); + } + return ret; +} + +int +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; + + ret = pam_get_item(pamh, PAM_CONV, (void*)&conv); + if(ret != PAM_SUCCESS) + return ret; + + + if(getuid() != geteuid()) + return auth_su(pamh, flags, user, conv); + else + return auth_login(pamh, flags, user, conv); +} + +int +pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + return PAM_SUCCESS; +} + + +int +pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + char *tkt; + pam_get_data(pamh, "KRBTKFILE", (const void**)&tkt); + setenv("KRBTKFILE", tkt, 1); + if(k_hasafs()){ + k_setpag(); + k_afsklog(0, 0); + } + return PAM_SUCCESS; +} + + +int +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; +} diff --git a/lib/auth/pam/pam.conf.add b/lib/auth/pam/pam.conf.add new file mode 100644 index 000000000..1bfb30eb9 --- /dev/null +++ b/lib/auth/pam/pam.conf.add @@ -0,0 +1,13 @@ +# To get this to work, you will have to add entries to /etc/pam.conf +# +# To make login kerberos-aware, you might change pam.conf to look +# like: + +# login authorization +login auth sufficient /lib/security/pam_krb4.so +login auth required /lib/security/pam_securetty.so +login auth required /lib/security/pam_unix_auth.so +login account required /lib/security/pam_unix_acct.so +login password required /lib/security/pam_unix_passwd.so +login session required /lib/security/pam_krb4.so +login session required /lib/security/pam_unix_session.so