diff -rup monit-4.10.1/configure monit-4.10.1-pam/configure --- monit-4.10.1/configure 2007-11-06 21:34:57.000000000 +0100 +++ monit-4.10.1-pam/configure 2008-04-01 20:56:18.000000000 +0200 @@ -3854,6 +3854,77 @@ _ACEOF fi +{ echo "$as_me:$LINENO: checking for pam_start in -lpam" >&5 +echo $ECHO_N "checking for pam_start in -lpam... $ECHO_C" >&6; } +if test "${ac_cv_lib_pam_pam_start+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpam $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pam_start (); +int +main () +{ +return pam_start (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_pam_pam_start=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_pam_pam_start=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_pam_pam_start" >&5 +echo "${ECHO_T}$ac_cv_lib_pam_pam_start" >&6; } +if test $ac_cv_lib_pam_pam_start = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBPAM 1 +_ACEOF + + LIBS="-lpam $LIBS" + +fi + + # Wacky pthread madness pthread_libs="" { echo "$as_me:$LINENO: checking for pthread_create in -lpthread" >&5 @@ -4501,6 +4572,9 @@ done + + + for ac_header in \ alloca.h \ arpa/inet.h \ @@ -4567,6 +4641,9 @@ for ac_header in \ uvm/uvm.h \ uvm/uvm_extern.h \ vm/vm.h \ + pwd.h \ + grp.h \ + security/pam_appl.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` diff -rup monit-4.10.1/configure.ac monit-4.10.1-pam/configure.ac --- monit-4.10.1/configure.ac 2007-11-06 21:32:30.000000000 +0100 +++ monit-4.10.1-pam/configure.ac 2008-04-01 20:44:03.000000000 +0200 @@ -40,6 +40,7 @@ AC_CHECK_LIB([inet], [socket]) AC_CHECK_LIB([nsl], [inet_addr]) AC_CHECK_LIB([resolv], [inet_aton]) AC_CHECK_LIB([crypt], [crypt]) +AC_CHECK_LIB([pam], [pam_start]) # Wacky pthread madness pthread_libs="" @@ -130,6 +131,9 @@ AC_CHECK_HEADERS([ \ uvm/uvm.h \ uvm/uvm_extern.h \ vm/vm.h \ + pwd.h \ + grp.h \ + security/pam_appl.h ]) AC_CHECK_HEADERS([ \ Only in monit-4.10.1-pam: monit.cnf Only in monit-4.10.1-pam: monit.pem diff -rup monit-4.10.1/monitor.h monit-4.10.1-pam/monitor.h --- monit-4.10.1/monitor.h 2007-10-16 21:10:43.000000000 +0200 +++ monit-4.10.1-pam/monitor.h 2008-03-28 12:58:43.000000000 +0100 @@ -160,6 +160,7 @@ #define DIGEST_CLEARTEXT 1 #define DIGEST_CRYPT 2 #define DIGEST_MD5 3 +#define DIGEST_PAM 4 #define UNIT_BYTE 1 #define UNIT_KILOBYTE 1024 @@ -346,7 +347,9 @@ typedef struct mymailserver { typedef struct myauthentication { char *uname; /**< User allowed to connect to monit httpd */ - char *passwd; /**< The users password data */ + char *passwd; /**< The users password + data */ + char* groupname; int digesttype; /**< How did we store the password */ int is_readonly; /**< TRUE if this is a read-only authenticated user*/ struct myauthentication *next; /**< Next credential or NULL if last */ diff -rup monit-4.10.1/monitrc monit-4.10.1-pam/monitrc --- monit-4.10.1/monitrc 2007-10-24 22:23:08.000000000 +0200 +++ monit-4.10.1-pam/monitrc 2008-04-01 20:52:19.000000000 +0200 @@ -89,6 +89,8 @@ # use address localhost # only accept connection from localhost # allow localhost # allow localhost to connect to the server and # allow admin:monit # require user 'admin' with password 'monit' +# allow @monit # allow users of group 'monit' to connect (rw) +# allow @users readonly # allow users of group 'users' to connect readonly # # ############################################################################### Only in monit-4.10.1-pam: openssl.rnd diff -rup monit-4.10.1/p.y monit-4.10.1-pam/p.y --- monit-4.10.1/p.y 2007-10-24 22:23:08.000000000 +0200 +++ monit-4.10.1-pam/p.y 2008-03-28 13:43:26.000000000 +0100 @@ -194,6 +194,7 @@ static void addcollector(URL_T, int, int, char *); static void addmailserver(MailServer_T); static int addcredentials(char *, char *, int, int); + static void addpamauth(char*, int); static void addhtpasswdentry(char *, char *, int); static uid_t get_uid(char *, uid_t); static gid_t get_gid(char *, gid_t); @@ -661,6 +662,10 @@ allowselfcert : /* EMPTY */ { allow : ALLOW STRING':'STRING readonly { addcredentials($2,$4, DIGEST_CLEARTEXT, $5); } + | ALLOW '@'STRING readonly { + printf("Group: %s readonly: %d\n", $3, $4); + addpamauth($3, $4); + } | ALLOW PATH { addhtpasswdentry($2, NULL, DIGEST_CLEARTEXT); FREE($2); @@ -2959,6 +2964,41 @@ static void addhtpasswdentry(char *filen } +static void addpamauth(char* groupname, int readonly) { + Auth_T c = NULL, prev = NULL; + ASSERT(groupname); + + if (Run.credentials == NULL) { + NEW(Run.credentials); + } + + c=Run.credentials; + do { + if (c->groupname != NULL && strcmp(c->groupname, groupname) == 0) { + yywarning2("groupname %s were already added, entry ignored", + groupname); + FREE(groupname); + return; + } + prev = c; + c=c->next; + } + while (c != NULL); + + NEW(prev->next); + c=prev->next; + + c->next=NULL; + c->uname=NULL; + c->passwd=NULL; + c->groupname=groupname; + c->digesttype=DIGEST_PAM; + c->is_readonly= readonly; + + DEBUG("%s: Debug: Adding pam-group '%s'.\n", prog, groupname); + + return; +} /* * Add Basic Authentication credentials @@ -3001,6 +3041,7 @@ static int addcredentials(char *uname, c } c->next=NULL; + c->groupname=NULL; c->uname=uname; c->passwd=passwd; c->digesttype=dtype; diff -rup monit-4.10.1/util.c monit-4.10.1-pam/util.c --- monit-4.10.1/util.c 2007-10-16 21:10:44.000000000 +0200 +++ monit-4.10.1-pam/util.c 2008-04-01 20:55:26.000000000 +0200 @@ -102,6 +102,9 @@ #include "process.h" #include "event.h" +#include +#include +#include /* Private prototypes */ static char x2c(char *hex); @@ -1595,15 +1598,73 @@ void Util_closeFds() { errno= 0; } +Auth_T Util_checkUserGroup(const char* uname) { + DEBUG("Util_checkUserGroup\n"); + + struct passwd* pwd = NULL; + ASSERT(uname); + if ((pwd = getpwnam(uname)) == NULL) { + return NULL; + } + + struct group* grp = NULL; + if ((grp = getgrgid(pwd->pw_gid)) == NULL) { + return NULL; + } + + DEBUG("Util_checkUserGroup: check groups for user: %s in group: %s\n", uname, grp->gr_name); + + Auth_T c= Run.credentials; + while (c != NULL) { + DEBUG("Util_checkUserGroup: iter \n"); + if (c->groupname != NULL) { + DEBUG("Util_checkUserGroup: check group %s \n", c->groupname); + if (strcmp(c->groupname, grp->gr_name) == 0) { + // primary group matches + DEBUG("Util_checkUserGroup: user: %s matches group: %s\n", + uname, c->groupname); + return c; + } + DEBUG("Util_checkUserGroup: check secondaries \n"); + struct group* sgrp = NULL; + if ((sgrp = getgrnam(c->groupname)) != NULL) { + DEBUG("Util_checkUserGroup: check secondary group: %s \n", c->groupname); + char** g = NULL; + for(g = sgrp->gr_mem; *g != NULL; g++) { + DEBUG("Util_checkUserGroup: check group member %s\n", *g); + if (strcmp(*g, uname) == 0) { + // secondary group matches + DEBUG("Util_checkUserGroup: user: %s matches group: %s\n", + uname, c->groupname); + return c; + } + } + } + + + } + c=c->next; + } + DEBUG("Util_checkUserGroup: user: %s no match\n", uname); + // no match + return NULL; +} /* * Check if monit does have credentials for this user. If successful * a pointer to the password is returned. */ Auth_T Util_getUserCredentials(char *uname) { + Auth_T lc = Util_checkUserGroup(uname); + // get group and check group and readonly + + if (lc != NULL) { // got a valid user + return lc; + } + Auth_T c= Run.credentials; while ( c != NULL ) { - if ( strcmp(c->uname, uname) == 0 ) { + if (c->uname != NULL && strcmp(c->uname, uname) == 0 ) { return c; } c=c->next; @@ -1611,6 +1672,90 @@ Auth_T Util_getUserCredentials(char *una return NULL; } +#define msgi(i) (*(msg[i])) + +struct ad_user { + const char* login; + const char* passwd; +}; + +// Linux-PAM conversation function +int Util_PAMconv (int num_msg, const struct pam_message **msg, + struct pam_response **resp, void *appdata_ptr) { + + struct ad_user *user= (struct ad_user *)appdata_ptr; + struct pam_response *response; + int i; + + /* Sanity checking */ + if (msg == NULL || resp == NULL || user == NULL) + return PAM_CONV_ERR; + + response= (struct pam_response *) + malloc(num_msg * sizeof(struct pam_response)); + + for (i= 0; i < num_msg; i++) { + response[i].resp_retcode= 0; + response[i].resp= NULL; + + switch (msgi(i).msg_style) { + case PAM_PROMPT_ECHO_ON: + /* Store the login as the response */ + /* This likely never gets called, since login was on pam_start() */ + response[i].resp= appdata_ptr ? (char *)strdup(user->login) : NULL; + break; + + case PAM_PROMPT_ECHO_OFF: + DEBUG("Util_PAMconv: echo off \n"); + /* Store the password as the response */ + response[i].resp= appdata_ptr ? (char *)strdup(user->passwd) : NULL; + break; + + case PAM_TEXT_INFO: + case PAM_ERROR_MSG: + /* Shouldn't happen since we have PAM_SILENT set. If it happens + * anyway, ignore it. */ + break; + + default: + /* Something strange... */ + if (response != NULL) free(response); + return PAM_CONV_ERR; + } + } + /* On success, return the response structure */ + *resp = response; + return PAM_SUCCESS; +} + +// validate login/passwd via pam-service "monit" +int Util_checkPamPasswd(const char* login, const char* passwd) { + struct ad_user user_info= {login, passwd}; + struct pam_conv conv = { Util_PAMconv, (void *)&user_info }; + pam_handle_t *pamh= NULL; + int retval; + + DEBUG("Util_checkPamPasswd: user: %s\n", login); + + retval= pam_start("monit", login, &conv, &pamh); + + if (retval == PAM_SUCCESS) + retval= pam_authenticate(pamh, PAM_SILENT); + + /* + if (retval == PAM_SUCCESS) + retval= pam_acct_mgmt(pamh, PAM_SILENT); + */ + + if (pam_end(pamh,retval) != PAM_SUCCESS) { + pamh= NULL; + } + + if (retval == PAM_SUCCESS) { + return TRUE; + } + return FALSE; +} /** * Check if the given password match the registred password for the @@ -1627,6 +1772,9 @@ int Util_checkCredentials(char *uname, c return FALSE; } switch (c->digesttype) { + case DIGEST_PAM: + return Util_checkPamPasswd(uname, outside); + break; case DIGEST_CLEARTEXT: { strncpy(outside_crypt, outside, STRLEN);