/* * @(#)PAM.h * * This file is part of webCDwriter - Network CD/DVD Writing. * * webCDwriter is free software. See CDWserver.cpp for details. */ // some stuff for PAM by GSS // mostly ripped from mod_auth_pam for Apache 2.x #include #include static const char *pam_servicename = "cdwserver"; #ifndef CDWserver class Exception { private: const char *msg; public: Exception(const char *msg): msg(msg) { } public: const char *toString() { return msg; } }; #endif typedef struct { char *name, *pw; } auth_pam_userinfo; /* * * Solaris 2.6.x has a broken conversation function and needs this * * as a global variable * * I refused to pollute code for other platforms with this, * * so all Solaris 2.6 specific stuff is if'd like the following * */ #if SOLARIS2 == 260 auth_pam_userinfo *global_userinfo; #endif /* * auth_pam_talker: supply authentication information to PAM when asked * * Assumptions: * A password is asked for by requesting input without echoing * A username is asked for by requesting input _with_ echoing * */ static int auth_pam_talker(int num_msg, const struct pam_message ** msg, struct pam_response ** resp, void *appdata_ptr) { unsigned short i = 0; auth_pam_userinfo *userinfo = (auth_pam_userinfo *) appdata_ptr; struct pam_response *response = 0; #if SOLARIS2 == 260 if (!userinfo) userinfo = global_userinfo; /* fprintf(stderr,"%s : %s", userinfo->name, userinfo->pw); */ #endif /* parameter sanity checking */ if (!resp || !msg || !userinfo) return PAM_CONV_ERR; /* allocate memory to store response */ response = (struct pam_response *) malloc(num_msg * sizeof(struct pam_response)); if (!response) return PAM_CONV_ERR; /* copy values */ for (i = 0; i < num_msg; i++) { /* initialize to safe values */ response[i].resp_retcode = 0; response[i].resp = 0; /* select response based on requested output style */ switch (msg[i]->msg_style) { case PAM_PROMPT_ECHO_ON: /* on memory allocation failure, auth fails */ response[i].resp = strdup(userinfo->name); break; case PAM_PROMPT_ECHO_OFF: response[i].resp = strdup(userinfo->pw); break; default: if (response) free(response); return PAM_CONV_ERR; } } /* everything okay, set PAM response values */ *resp = response; return PAM_SUCCESS; } class PAM4CDWserver { #ifdef CDWserver private: static pthread_mutex_t mutex; #endif public: static void check(const char *ID, const char *passwd) { int res = 0; /* PAM specific */ auth_pam_userinfo userinfo = {NULL, NULL}; char ID2[strlen(ID)+1]; strcpy(ID2,ID); userinfo.name = ID2; char passwd2[strlen(passwd)+1]; strcpy(passwd2,passwd); userinfo.pw = passwd2; #ifdef CDWserver log.debug("PAM4CDWserver", S.e + "<" + userinfo.name + "> <" + userinfo.pw + ">"); if (true) { checkExternal(ID, passwd); return; } #endif struct pam_conv conv_info = {&auth_pam_talker, (void *) &userinfo}; pam_handle_t *pamh = NULL; #if SOLARIS2 == 260 global_userinfo = &userinfo; #endif try { #ifdef CDWserver pthread_mutex_lock(&mutex); #endif /* initialize pam */ if ((res = pam_start(pam_servicename, userinfo.name, &conv_info, &pamh)) != PAM_SUCCESS) { #ifdef CDWserver log.put(3, S.e + "PAM4CDWserver::check()" + " Error initializing the PAM subsysten!"); #endif throw new Exception("Cannot initialize PAM subsystem!"); } /* Authenticate to PAM, throw Exceptions on error */ if ((res = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK)) != PAM_SUCCESS) { #ifdef CDWserver log.put(3, S.e + "PAM4CDWserver::check() PAM Error: " + pam_strerror(pamh, res)); #endif pam_end(pamh, PAM_SUCCESS); throw new Exception("Could not authenticate with PAM"); } pam_end(pamh, PAM_SUCCESS); #ifdef CDWserver pthread_mutex_unlock(&mutex); #endif } catch (Exception *exception) { #ifdef CDWserver pthread_mutex_unlock(&mutex); #endif throw exception; } } #ifdef CDWserver public: static void checkExternal( const char *ID, const char *passwd) { Process p(config.getActiveValue("rootGatePath")); p.addArg("-pam"); p.show(); p.start(); String str = ""; str = str + ID + "\n" + passwd + "\n"; const char *outBuf = str.getBytes(); int out0 = 0, outN = str.length(); bool authenticated = false; while (true) { fd_set outFdSet; FD_ZERO(&outFdSet); FD_SET(p.getOutputStream(), &outFdSet); int n = ::select(FD_SETSIZE, NULL, &outFdSet, NULL, NULL); if (n <= 0) break; if (FD_ISSET(p.getOutputStream(), &outFdSet)) { int n = write(p.getOutputStream(), &outBuf[out0], outN - out0); if (n > 0) out0 += n; } const char *lineStr = p.readLine(30); if (lineStr == NULL) break; String line = lineStr; log.put(3, S.e + line); if (line.indexOf("authenticated") >= 0) authenticated = true; } if (p.getResult() != 0 || !authenticated) throw new Exception("Could not authenticate with PAM"); } #endif }; #ifdef CDWserver pthread_mutex_t PAM4CDWserver::mutex = PTHREAD_MUTEX_INITIALIZER; #endif