diff options
Diffstat (limited to 'Linux-PAM/libpam_misc')
-rw-r--r-- | Linux-PAM/libpam_misc/Makefile | 120 | ||||
-rw-r--r-- | Linux-PAM/libpam_misc/help_env.c | 105 | ||||
-rw-r--r-- | Linux-PAM/libpam_misc/include/security/pam_misc.h | 62 | ||||
-rw-r--r-- | Linux-PAM/libpam_misc/misc_conv.c | 386 | ||||
-rw-r--r-- | Linux-PAM/libpam_misc/xstrdup.c | 31 |
5 files changed, 704 insertions, 0 deletions
diff --git a/Linux-PAM/libpam_misc/Makefile b/Linux-PAM/libpam_misc/Makefile new file mode 100644 index 00000000..97166668 --- /dev/null +++ b/Linux-PAM/libpam_misc/Makefile @@ -0,0 +1,120 @@ +# +# $Id: Makefile,v 1.9 2005/03/29 20:41:20 toady Exp $ +# + +# lots of debugging information goes to /tmp/pam-debug.log +#MOREFLAGS += -D"DEBUG" + +include ../Make.Rules + +ifeq ($(WITH_LIBDEBUG),yes) + LIBNAME=libpam_miscd +else + LIBNAME=libpam_misc +endif +ifeq ($(WITH_PRELUDE),yes) + CFLAGS += -DPRELUDE -DLIBPRELUDE_CONFIG_PREFIX=\"`libprelude-config --prefix`\" +endif +VERSION=.$(MAJOR_REL) +MODIFICATION=.$(MINOR_REL) + +CFLAGS += $(MOREFLAGS) $(DYNAMIC) $(STATIC) +LINKLIBS += -L$(absolute_objdir)/libpam -lpam + +# dynamic library names + +LIBNAMED = $(LIBNAME).$(DYNTYPE) +LIBNAMEDNAME = $(LIBNAMED)$(VERSION) +LIBNAMEDFULL = $(LIBNAMEDNAME)$(MODIFICATION) + +# static library name + +LIBNAMEDSTATIC = $(LIBNAME).a + +LIBOBJECTS = help_env.o misc_conv.o + +ifeq ($(DYNAMIC_LIBPAM),yes) +DLIBOBJECTS = $(addprefix dynamic/,$(LIBOBJECTS)) +endif + +ifeq ($(STATIC_LIBPAM),yes) +SLIBOBJECTS = $(addprefix static/,$(LIBOBJECTS)) +endif + +# --------------------------------------------- +## rules + +all: dirs $(LIBNAMED) $(LIBNAMEDSTATIC) + +dirs: +ifeq ($(DYNAMIC_LIBPAM),yes) + $(MKDIR) dynamic +endif +ifeq ($(STATIC_LIBPAM),yes) + $(MKDIR) static +endif + +dynamic/%.o : %.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +static/%.o : %.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +$(LIBNAMED): $(DLIBOBJECTS) +ifeq ($(DYNAMIC_LIBPAM),yes) + ifeq ($(USESONAME),yes) + $(LD_L) $(SOSWITCH)$(LIBNAMEDNAME) -o $@ $(DLIBOBJECTS) $(MODULES) $(LINKLIBS) + else + $(LD_L) -o $@ $(DLIBOBJECTS) $(MODULES) $(LINKLIBS) + endif + ifeq ($(NEEDSONAME),yes) + rm -f $(LIBNAMEDFULL) + ln -s $(LIBNAMED) $(LIBNAMEDFULL) + rm -f $(LIBNAMEDNAME) + ln -s $(LIBNAMED) $(LIBNAMEDNAME) + endif +endif + +$(LIBNAMEDSTATIC): $(SLIBOBJECTS) +ifeq ($(STATIC_LIBPAM),yes) + $(AR) rcu $@ $(SLIBOBJECTS) $(MODULES) +ifdef RANLIB + $(AR) rc $@ $(SLIBOBJECTS) $(MODULES) + $(RANLIB) $@ +endif +endif + +install: all + $(MKDIR) $(FAKEROOT)$(INCLUDED) + $(INSTALL) -m 644 include/security/pam_misc.h $(FAKEROOT)$(INCLUDED) +ifeq ($(DYNAMIC_LIBPAM),yes) + $(MKDIR) $(FAKEROOT)$(libdir) + $(INSTALL) -m $(SHLIBMODE) $(LIBNAMED) $(FAKEROOT)$(libdir)/$(LIBNAMEDFULL) +ifndef FAKEROOT + $(LDCONFIG) +else + $(LDCONFIG) -n $(FAKEROOT)$(libdir) +endif + ifneq ($(DYNTYPE),"sl") + ( cd $(FAKEROOT)$(libdir) ; rm -f $(LIBNAMED) ; ln -s $(LIBNAMEDNAME) $(LIBNAMED) ) + endif +endif +ifeq ($(STATIC_LIBPAM),yes) + $(INSTALL) -m 644 $(LIBNAMEDSTATIC) $(FAKEROOT)$(libdir) +endif + +remove: + rm -f $(FAKEROOT)$(INCLUDED)/pam_misc.h + rm -f $(FAKEROOT)$(libdir)/$(LIBNAMEDFULL) + rm -f $(FAKEROOT)$(libdir)/$(LIBNAMED) +ifndef FAKEROOT + $(LDCONFIG) +endif + rm -f $(FAKEROOT)$(libdir)/$(LIBNAMEDSTATIC) + +clean: + rm -f a.out core *~ static/*.o dynamic/*.o + rm -f *.a *.out *.o *.so ./include/security/*~ + rm -f *.orig $(LIBNAMEDNAME) $(LIBNAMEDFULL) + if [ -d dynamic ]; then rmdir dynamic ; fi + if [ -d static ]; then rmdir static ; fi diff --git a/Linux-PAM/libpam_misc/help_env.c b/Linux-PAM/libpam_misc/help_env.c new file mode 100644 index 00000000..e1390984 --- /dev/null +++ b/Linux-PAM/libpam_misc/help_env.c @@ -0,0 +1,105 @@ +/* + * $Id: help_env.c,v 1.2 2000/12/04 19:02:34 baggins Exp $ + * + * This file was written by Andrew G. Morgan <morgan@parc.power.net> + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <security/pam_misc.h> + +/* + * This is a useful function for dumping the Linux-PAM environment + * into some local memory, prior to it all getting lost when pam_end() + * is called. + * + * Initially it was assumed that libpam did not do this part correctly + * (based on a loose email definition). The X/Open XSSO spec makes it + * clear that this function is a duplicate of the one already in + * libpam and therefore unnecessary. IT WILL BE COMPLETELY REMOVED + * IN libpam_misc 1.0 */ + +char **pam_misc_copy_env(pam_handle_t *pamh); +char **pam_misc_copy_env(pam_handle_t *pamh) +{ + return pam_getenvlist(pamh); +} + +/* + * This function should be used to carefully dispose of the copied + * environment. + * + * usage: env = pam_misc_drop_env(env); + */ + +char **pam_misc_drop_env(char **dump) +{ + int i; + + for (i=0; dump[i] != NULL; ++i) { + D(("dump[%d]=`%s'", i, dump[i])); + _pam_overwrite(dump[i]); + _pam_drop(dump[i]); + } + _pam_drop(dump); + + return NULL; +} + +/* + * This function takes the supplied environment and uploads it to be + * the PAM one. + */ + +int pam_misc_paste_env(pam_handle_t *pamh, const char * const * user_env) +{ + for (; user_env && *user_env; ++user_env) { + int retval; + + D(("uploading: %s", *user_env)); + retval = pam_putenv(pamh, *user_env); + if (retval != PAM_SUCCESS) { + D(("error setting %s: %s", *user_env, pam_strerror(pamh,retval))); + return retval; + } + } + D(("done.")); + return PAM_SUCCESS; +} + +/* + * This is a wrapper to make pam behave in the way that setenv() does. + */ + +int pam_misc_setenv(pam_handle_t *pamh, const char *name + , const char *value, int readonly) +{ + char *tmp; + int retval; + + if (readonly) { + const char *etmp; + + /* we check if the variable is there already */ + etmp = pam_getenv(pamh, name); + if (etmp != NULL) { + D(("failed to set readonly variable: %s", name)); + return PAM_PERM_DENIED; /* not allowed to overwrite */ + } + } + tmp = malloc(2+strlen(name)+strlen(value)); + if (tmp != NULL) { + sprintf(tmp,"%s=%s",name,value); + D(("pam_putt()ing: %s", tmp)); + retval = pam_putenv(pamh, tmp); + _pam_overwrite(tmp); /* purge */ + _pam_drop(tmp); /* forget */ + } else { + D(("malloc failure")); + retval = PAM_BUF_ERR; + } + + return retval; +} diff --git a/Linux-PAM/libpam_misc/include/security/pam_misc.h b/Linux-PAM/libpam_misc/include/security/pam_misc.h new file mode 100644 index 00000000..66c7ab4a --- /dev/null +++ b/Linux-PAM/libpam_misc/include/security/pam_misc.h @@ -0,0 +1,62 @@ +/* $Id: pam_misc.h,v 1.4 2001/05/01 04:27:37 agmorgan Exp $ */ + +#ifndef __PAMMISC_H +#define __PAMMISC_H + +#include <security/pam_appl.h> +#include <security/pam_client.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* include some useful macros */ + +#include <security/_pam_macros.h> + +/* functions defined in pam_misc.* libraries */ + +extern int misc_conv(int num_msg, const struct pam_message **msgm, + struct pam_response **response, void *appdata_ptr); + +#include <time.h> + +extern time_t pam_misc_conv_warn_time; /* time that we should warn user */ +extern time_t pam_misc_conv_die_time; /* cut-off time for input */ +extern const char *pam_misc_conv_warn_line; /* warning notice */ +extern const char *pam_misc_conv_die_line; /* cut-off remark */ +extern int pam_misc_conv_died; /* 1 = cut-off time reached (0 not) */ +extern int (*pam_binary_handler_fn)(void *appdata, pamc_bp_t *prompt_p); +extern void (*pam_binary_handler_free)(void *appdata, pamc_bp_t *prompt_p); +/* + * Environment helper functions + */ + +/* transcribe given environment (to pam) */ +extern int pam_misc_paste_env(pam_handle_t *pamh + , const char * const * user_env); + +/* char **pam_misc_copy_env(pam_handle_t *pamh); + + This is no longer defined as a prototype because the X/Open XSSO + spec makes it clear that PAM's pam_getenvlist() does exactly + what this was needed for. + + A wrapper is still provided in the pam_misc library - so that + legacy applications will still work. But _BE_WARNED_ it will + disappear by the release of libpam 1.0 . */ + +/* delete environment as obtained from (pam_getenvlist) */ +extern char **pam_misc_drop_env(char **env); + +/* provide something like the POSIX setenv function for the (Linux-)PAM + * environment. */ + +extern int pam_misc_setenv(pam_handle_t *pamh, const char *name + , const char *value, int readonly); + +#ifdef __cplusplus +} +#endif /* def __cplusplus */ + +#endif /* ndef __PAMMISC_H */ diff --git a/Linux-PAM/libpam_misc/misc_conv.c b/Linux-PAM/libpam_misc/misc_conv.c new file mode 100644 index 00000000..1c66f96c --- /dev/null +++ b/Linux-PAM/libpam_misc/misc_conv.c @@ -0,0 +1,386 @@ +/* + * $Id: misc_conv.c,v 1.6 2004/09/22 12:51:20 kukuk Exp $ + * + * A generic conversation function for text based applications + * + * Written by Andrew Morgan <morgan@linux.kernel.org> + */ + +#include <security/_pam_aconf.h> + +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <termios.h> +#include <time.h> +#include <unistd.h> + +#include <security/pam_appl.h> +#include <security/pam_misc.h> + +#define INPUTSIZE PAM_MAX_MSG_SIZE /* maximum length of input+1 */ +#define CONV_ECHO_ON 1 /* types of echo state */ +#define CONV_ECHO_OFF 0 + +/* + * external timeout definitions - these can be overriden by the + * application. + */ + +time_t pam_misc_conv_warn_time = 0; /* time when we warn */ +time_t pam_misc_conv_die_time = 0; /* time when we timeout */ + +const char *pam_misc_conv_warn_line = "..\a.Time is running out...\n"; +const char *pam_misc_conv_die_line = "..\a.Sorry, your time is up!\n"; + +int pam_misc_conv_died=0; /* application can probe this for timeout */ + +/* + * These functions are for binary prompt manipulation. + * The manner in which a binary prompt is processed is application + * specific, so these function pointers are provided and can be + * initialized by the application prior to the conversation function + * being used. + */ + +static void pam_misc_conv_delete_binary(void *appdata, + pamc_bp_t *delete_me) +{ + PAM_BP_RENEW(delete_me, 0, 0); +} + +int (*pam_binary_handler_fn)(void *appdata, pamc_bp_t *prompt_p) = NULL; +void (*pam_binary_handler_free)(void *appdata, pamc_bp_t *prompt_p) + = pam_misc_conv_delete_binary; + +/* the following code is used to get text input */ + +static volatile int expired=0; + +/* return to the previous signal handling */ +static void reset_alarm(struct sigaction *o_ptr) +{ + (void) alarm(0); /* stop alarm clock - if still ticking */ + (void) sigaction(SIGALRM, o_ptr, NULL); +} + +/* this is where we intercept the alarm signal */ +static void time_is_up(int ignore) +{ + expired = 1; +} + +/* set the new alarm to hit the time_is_up() function */ +static int set_alarm(int delay, struct sigaction *o_ptr) +{ + struct sigaction new_sig; + + sigemptyset(&new_sig.sa_mask); + new_sig.sa_flags = 0; + new_sig.sa_handler = time_is_up; + if ( sigaction(SIGALRM, &new_sig, o_ptr) ) { + return 1; /* setting signal failed */ + } + if ( alarm(delay) ) { + (void) sigaction(SIGALRM, o_ptr, NULL); + return 1; /* failed to set alarm */ + } + return 0; /* all seems to have worked */ +} + +/* return the number of seconds to next alarm. 0 = no delay, -1 = expired */ +static int get_delay(void) +{ + time_t now; + + expired = 0; /* reset flag */ + (void) time(&now); + + /* has the quit time past? */ + if (pam_misc_conv_die_time && now >= pam_misc_conv_die_time) { + fprintf(stderr,"%s",pam_misc_conv_die_line); + + pam_misc_conv_died = 1; /* note we do not reset the die_time */ + return -1; /* time is up */ + } + + /* has the warning time past? */ + if (pam_misc_conv_warn_time && now >= pam_misc_conv_warn_time) { + fprintf(stderr, "%s", pam_misc_conv_warn_line); + pam_misc_conv_warn_time = 0; /* reset warn_time */ + + /* indicate remaining delay - if any */ + + return (pam_misc_conv_die_time ? pam_misc_conv_die_time - now:0 ); + } + + /* indicate possible warning delay */ + + if (pam_misc_conv_warn_time) + return (pam_misc_conv_warn_time - now); + else if (pam_misc_conv_die_time) + return (pam_misc_conv_die_time - now); + else + return 0; +} + +/* read a line of input string, giving prompt when appropriate */ +static int read_string(int echo, const char *prompt, char **retstr) +{ + struct termios term_before, term_tmp; + char line[INPUTSIZE]; + struct sigaction old_sig; + int delay, nc = -1, have_term = 0; + sigset_t oset, nset; + + D(("called with echo='%s', prompt='%s'.", echo ? "ON":"OFF" , prompt)); + + if (isatty(STDIN_FILENO)) { /* terminal state */ + + /* is a terminal so record settings and flush it */ + if ( tcgetattr(STDIN_FILENO, &term_before) != 0 ) { + D(("<error: failed to get terminal settings>")); + *retstr = NULL; + return -1; + } + memcpy(&term_tmp, &term_before, sizeof(term_tmp)); + if (!echo) { + term_tmp.c_lflag &= ~(ECHO); + } + have_term = 1; + + /* + * We make a simple attempt to block TTY signals from terminating + * the conversation without giving PAM a chance to clean up. + */ + + sigemptyset(&nset); + sigaddset(&nset, SIGINT); + sigaddset(&nset, SIGTSTP); + (void) sigprocmask(SIG_BLOCK, &nset, &oset); + + } else if (!echo) { + D(("<warning: cannot turn echo off>")); + } + + /* set up the signal handling */ + delay = get_delay(); + + /* reading the line */ + while (delay >= 0) { + + fprintf(stderr, "%s", prompt); + /* this may, or may not set echo off -- drop pending input */ + if (have_term) + (void) tcsetattr(STDIN_FILENO, TCSAFLUSH, &term_tmp); + + if ( delay > 0 && set_alarm(delay, &old_sig) ) { + D(("<failed to set alarm>")); + break; + } else { + nc = read(STDIN_FILENO, line, INPUTSIZE-1); + if (have_term) { + (void) tcsetattr(STDIN_FILENO, TCSADRAIN, &term_before); + if (!echo || expired) /* do we need a newline? */ + fprintf(stderr,"\n"); + } + if ( delay > 0 ) { + reset_alarm(&old_sig); + } + if (expired) { + delay = get_delay(); + } else if (nc > 0) { /* we got some user input */ + D(("we got some user input")); + + if (nc > 0 && line[nc-1] == '\n') { /* <NUL> terminate */ + line[--nc] = '\0'; + } else { + if (echo) { + fprintf(stderr, "\n"); + } + line[nc] = '\0'; + } + *retstr = x_strdup(line); + _pam_overwrite(line); + + goto cleanexit; /* return malloc()ed string */ + + } else if (nc == 0) { /* Ctrl-D */ + D(("user did not want to type anything")); + + *retstr = NULL; + if (echo) { + fprintf(stderr, "\n"); + } + goto cleanexit; /* return malloc()ed "" */ + } else if (nc == -1) { + /* Don't loop forever if read() returns -1. */ + D(("error reading input from the user: %s", strerror(errno))); + if (echo) { + fprintf(stderr, "\n"); + } + *retstr = NULL; + goto cleanexit; /* return NULL */ + } + } + } + + /* getting here implies that the timer expired */ + + D(("the timer appears to have expired")); + + *retstr = NULL; + _pam_overwrite(line); + + cleanexit: + + if (have_term) { + (void) sigprocmask(SIG_SETMASK, &oset, NULL); + (void) tcsetattr(STDIN_FILENO, TCSADRAIN, &term_before); + } + + return nc; +} + +/* end of read_string functions */ + +/* + * This conversation function is supposed to be a generic PAM one. + * Unfortunately, it is _not_ completely compatible with the Solaris PAM + * codebase. + * + * Namely, for msgm's that contain multiple prompts, this function + * interprets "const struct pam_message **msgm" as equivalent to + * "const struct pam_message *msgm[]". The Solaris module + * implementation interprets the **msgm object as a pointer to a + * pointer to an array of "struct pam_message" objects (that is, a + * confusing amount of pointer indirection). + */ + +int misc_conv(int num_msg, const struct pam_message **msgm, + struct pam_response **response, void *appdata_ptr) +{ + int count=0; + struct pam_response *reply; + + if (num_msg <= 0) + return PAM_CONV_ERR; + + D(("allocating empty response structure array.")); + + reply = (struct pam_response *) calloc(num_msg, + sizeof(struct pam_response)); + if (reply == NULL) { + D(("no memory for responses")); + return PAM_CONV_ERR; + } + + D(("entering conversation function.")); + + for (count=0; count < num_msg; ++count) { + char *string=NULL; + int nc; + + switch (msgm[count]->msg_style) { + case PAM_PROMPT_ECHO_OFF: + nc = read_string(CONV_ECHO_OFF,msgm[count]->msg, &string); + if (nc < 0) { + goto failed_conversation; + } + break; + case PAM_PROMPT_ECHO_ON: + nc = read_string(CONV_ECHO_ON,msgm[count]->msg, &string); + if (nc < 0) { + goto failed_conversation; + } + break; + case PAM_ERROR_MSG: + if (fprintf(stderr,"%s\n",msgm[count]->msg) < 0) { + goto failed_conversation; + } + break; + case PAM_TEXT_INFO: + if (fprintf(stdout,"%s\n",msgm[count]->msg) < 0) { + goto failed_conversation; + } + break; + case PAM_BINARY_PROMPT: + { + pamc_bp_t binary_prompt = NULL; + + if (!msgm[count]->msg || !pam_binary_handler_fn) { + goto failed_conversation; + } + + PAM_BP_RENEW(&binary_prompt, + PAM_BP_RCONTROL(msgm[count]->msg), + PAM_BP_LENGTH(msgm[count]->msg)); + PAM_BP_FILL(binary_prompt, 0, PAM_BP_LENGTH(msgm[count]->msg), + PAM_BP_RDATA(msgm[count]->msg)); + + if (pam_binary_handler_fn(appdata_ptr, + &binary_prompt) != PAM_SUCCESS + || (binary_prompt == NULL)) { + goto failed_conversation; + } + string = (char *) binary_prompt; + binary_prompt = NULL; + + break; + } + default: + fprintf(stderr, "erroneous conversation (%d)\n" + ,msgm[count]->msg_style); + goto failed_conversation; + } + + if (string) { /* must add to reply array */ + /* add string to list of responses */ + + reply[count].resp_retcode = 0; + reply[count].resp = string; + string = NULL; + } + } + + *response = reply; + reply = NULL; + + return PAM_SUCCESS; + +failed_conversation: + + D(("the conversation failed")); + + if (reply) { + for (count=0; count<num_msg; ++count) { + if (reply[count].resp == NULL) { + continue; + } + switch (msgm[count]->msg_style) { + case PAM_PROMPT_ECHO_ON: + case PAM_PROMPT_ECHO_OFF: + _pam_overwrite(reply[count].resp); + free(reply[count].resp); + break; + case PAM_BINARY_PROMPT: + pam_binary_handler_free(appdata_ptr, + (pamc_bp_t *) &reply[count].resp); + break; + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + /* should not actually be able to get here... */ + free(reply[count].resp); + } + reply[count].resp = NULL; + } + /* forget reply too */ + free(reply); + reply = NULL; + } + + return PAM_CONV_ERR; +} + diff --git a/Linux-PAM/libpam_misc/xstrdup.c b/Linux-PAM/libpam_misc/xstrdup.c new file mode 100644 index 00000000..cce476e8 --- /dev/null +++ b/Linux-PAM/libpam_misc/xstrdup.c @@ -0,0 +1,31 @@ +/* $Id: xstrdup.c,v 1.1.1.1 2000/06/20 22:11:25 agmorgan Exp $ */ + +#include <malloc.h> +#include <string.h> +#include <security/pam_misc.h> + +/* + * Safe duplication of character strings. "Paranoid"; don't leave + * evidence of old token around for later stack analysis. + */ + +char *xstrdup(const char *x) +{ + register char *new=NULL; + + if (x != NULL) { + register int i; + + for (i=0; x[i]; ++i); /* length of string */ + if ((new = malloc(++i)) == NULL) { + i = 0; + } else { + while (i-- > 0) { + new[i] = x[i]; + } + } + x = NULL; + } + + return new; /* return the duplicate or NULL on error */ +} |