From 7bc3242654983427b2195a4f54f731c4676fb0b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Fri, 23 Oct 2009 10:40:30 +0200 Subject: [PATCH] Use pam --- Makefile | 5 ++- README | 2 +- debian/control | 2 +- execwrap.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 96 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index c82948a..681ed32 100644 --- a/Makefile +++ b/Makefile @@ -25,11 +25,14 @@ DIET+=-Os endif endif -CC:=$(DIET) $(CC) +# CC:=$(DIET) $(CC) .PHONY: all install clean all: execwrap +execwrap: execwrap.o + $(CC) -o $@ $< -lpam + install: execwrap install -d $(DESTDIR)/usr/sbin/ $(DESTDIR)/usr/share/man/man8/ install -s -m 755 execwrap $(DESTDIR)/usr/sbin/ diff --git a/README b/README index 6d320de..5e312f7 100644 --- a/README +++ b/README @@ -110,7 +110,7 @@ ENV_DEBUG Controls the name of environment variable used to enable d There is no Makefile right now, but compile is as simple as: -> gcc -W -Wall -O2 -o execwrap execwrap.c && strip execwrap +> gcc -W -Wall -O2 -o execwrap execwrap.c -lpam && strip execwrap Or similar, depending on taste. You need something other than an ancient compiler to make it work, preferably C99. To install, make sure the file is owned by the super user and has diff --git a/debian/control b/debian/control index 7b6e87a..84a72e6 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: execwrap Section: net Priority: extra Maintainer: Stefan Bühler -Build-Depends: cdbs, debhelper (>= 5) +Build-Depends: cdbs, debhelper (>= 5), libpam-dev Standards-Version: 3.8.0 Homepage: http://cyanite.org/projects/execwrap/ Vcs-Git: git://cyanite.org/execwrap diff --git a/execwrap.c b/execwrap.c index b56eba1..f814df6 100644 --- a/execwrap.c +++ b/execwrap.c @@ -1,4 +1,4 @@ -/* +// /* Superuser-exec wrapper for HTTP serves and other needs (made especially for lighttpd). Allows programs to be run with configurable uid/gid. @@ -84,7 +84,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define RC_BAD_OPTION 24 #define RC_CHILD_ABNORMAL_EXIT 25 #define RC_MISSING_PWENT 26 - +#define RC_PAM_FAILED 27 /* User configuration. */ #include "execwrap_config.h" @@ -127,6 +127,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include +#include +#include + #if USE_SYSLOG # include @@ -147,6 +151,83 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif /* USE_SYSLOG */ +#define UNUSED(x) ((void)(x)) +static int execwrap_conv(int num_msg, const struct pam_message **msg, struct pam_response **response, void *appdata_ptr) { + struct pam_response *pr; + const struct pam_message *pm; + int n; + + UNUSED(appdata_ptr); + + if ((*response = calloc(num_msg, sizeof(struct pam_response))) == NULL) + return(PAM_CONV_ERR); + + for (pr = *response, pm = *msg, n = num_msg; n--; pr++, pm++) { + switch (pm->msg_style) { + case PAM_PROMPT_ECHO_ON: + case PAM_PROMPT_ECHO_OFF: + // No input available! + goto err; + case PAM_TEXT_INFO: + if (pm->msg) + puts(pm->msg); + break; + case PAM_ERROR_MSG: + if (pm->msg) { + fputs(pm->msg, stderr); + fputc('\n', stderr); + } + break; + default: + goto err; + } + } + + return PAM_SUCCESS; + +err: + free(*response); + *response = NULL; + return(PAM_CONV_ERR); +} + + +static pam_handle_t *pamh; +// return 0 on success +int setup_pam_session(const char *username) { + static struct pam_conv pam_conv; + int pam_status; + + pam_conv.conv = execwrap_conv; + + pam_status = pam_start("execwrap", username, &pam_conv, &pamh); + if (pam_status != PAM_SUCCESS) { + puts("unable to initialize PAM"); + return 1; + } + + (void) pam_set_item(pamh, PAM_USER, username); + (void) pam_set_item(pamh, PAM_RUSER, "www-data"); + + (void) pam_setcred(pamh, PAM_ESTABLISH_CRED); + + if ((pam_status = pam_open_session(pamh, 0)) != PAM_SUCCESS) { + (void) pam_end(pamh, pam_status | PAM_DATA_SILENT); + pamh = NULL; + puts("unable to open PAM session"); + return 2; + } + return 0; +} + +void close_pam_session() { + (void) pam_close_session(pamh, 0); + if (pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT) != PAM_SUCCESS) { + puts("unable to close PAM session"); + } + pamh = NULL; +} + /* The global child PID and previous SIGTERM handler. */ int pid; void (*oldHandler)(int); @@ -296,6 +377,10 @@ int main(int argc, char* argv[], char* envp[]) if(oldHandler == SIG_ERR) return RC_SIGNAL_HANDLER; } + /* setup pam session for limits */ + if (setup_pam_session(pwent->pw_name)) return RC_PAM_FAILED; + if (non_resident) close_pam_session(); + /* Fork off (or, if we are a non-resident wrapper, just carry on). */ if(non_resident || !(pid = fork())) { @@ -363,6 +448,9 @@ int main(int argc, char* argv[], char* envp[]) /* Here we're in the parent. Wait for the child to be done, and return. */ int status; wait(&status); + + close_pam_session(); + if(WIFEXITED(status)) return WEXITSTATUS(status); return RC_CHILD_ABNORMAL_EXIT; }