bool PamHandle::openSession() { m_result = pam_open_session(m_handle, m_silent); if (m_result != PAM_SUCCESS) { qWarning() << "[PAM] openSession:" << pam_strerror(m_handle, m_result); } return m_result == PAM_SUCCESS; }
void Authenticator::open_session(void) { switch((last_result=pam_setcred(pam_handle, PAM_ESTABLISH_CRED))) { default: case PAM_CRED_ERR: case PAM_CRED_UNAVAIL: _end(); throw Exception(pam_handle, "pam_setcred()", last_result); case PAM_CRED_EXPIRED: case PAM_USER_UNKNOWN: throw Cred_Exception(pam_handle, "pam_setcred()", last_result); case PAM_SUCCESS: break; } switch((last_result=pam_open_session(pam_handle, 0))) { // The documentation and implementation of Linux PAM differs: // PAM_SESSION_ERROR is described in the documentation but // don't exists in the actual implementation. This issue needs // to be fixes at some point. default: //case PAM_SESSION_ERROR: pam_setcred(pam_handle, PAM_DELETE_CRED); _end(); throw Exception(pam_handle, "pam_open_session()", last_result); case PAM_SUCCESS: break; }; return; }
int xlsh_session_open(const char* service, const char* user, pam_handle_t** handle) { struct pam_conv conv = { xlsh_session_conv, NULL }; pam_handle_t* pam_handle; if(pam_start(service, user, &conv, &pam_handle) != PAM_SUCCESS) return XLSH_ERROR; if(xlsh_X) pam_set_item(pam_handle, PAM_TTY, XLSH_XTTY); else pam_set_item(pam_handle, PAM_TTY, ttyname(0)); if(pam_authenticate(pam_handle, 0) != PAM_SUCCESS) { pam_end(pam_handle, 0); return XLSH_ERROR; } if(pam_acct_mgmt(pam_handle, 0) != PAM_SUCCESS) { pam_end(pam_handle, 0); return XLSH_ERROR; } if(pam_setcred(pam_handle, PAM_ESTABLISH_CRED) != PAM_SUCCESS) { pam_end(pam_handle, 0); return XLSH_ERROR; } if(pam_open_session(pam_handle, 0) != PAM_SUCCESS) { pam_setcred(pam_handle, PAM_DELETE_CRED); pam_end(pam_handle, 0); return XLSH_ERROR; } *handle = pam_handle; return XLSH_EOK; }
static enum pamtest_err run_test_case(pam_handle_t *ph, struct pam_testcase *tc) { switch (tc->pam_operation) { case PAMTEST_AUTHENTICATE: tc->op_rv = pam_authenticate(ph, tc->flags); return PAMTEST_ERR_OK; case PAMTEST_SETCRED: tc->op_rv = pam_setcred(ph, tc->flags); return PAMTEST_ERR_OK; case PAMTEST_ACCOUNT: tc->op_rv = pam_acct_mgmt(ph, tc->flags); return PAMTEST_ERR_OK; case PAMTEST_OPEN_SESSION: tc->op_rv = pam_open_session(ph, tc->flags); return PAMTEST_ERR_OK; case PAMTEST_CLOSE_SESSION: tc->op_rv = pam_close_session(ph, tc->flags); return PAMTEST_ERR_OK; case PAMTEST_CHAUTHTOK: tc->op_rv = pam_chauthtok(ph, tc->flags); return PAMTEST_ERR_OK; case PAMTEST_GETENVLIST: tc->case_out.envlist = pam_getenvlist(ph); return PAMTEST_ERR_OK; case PAMTEST_KEEPHANDLE: tc->case_out.ph = ph; return PAMTEST_ERR_KEEPHANDLE; default: return PAMTEST_ERR_OP; } return PAMTEST_ERR_OP; }
static int setup_pam(struct weston_launch *wl) { int err; wl->pc.conv = pam_conversation_fn; wl->pc.appdata_ptr = wl; err = pam_start("login", wl->pw->pw_name, &wl->pc, &wl->ph); if (err != PAM_SUCCESS) { fprintf(stderr, "failed to start pam transaction: %d: %s\n", err, pam_strerror(wl->ph, err)); return -1; } err = pam_set_item(wl->ph, PAM_TTY, ttyname(wl->tty)); if (err != PAM_SUCCESS) { fprintf(stderr, "failed to set PAM_TTY item: %d: %s\n", err, pam_strerror(wl->ph, err)); return -1; } err = pam_open_session(wl->ph, 0); if (err != PAM_SUCCESS) { fprintf(stderr, "failed to open pam session: %d: %s\n", err, pam_strerror(wl->ph, err)); return -1; } return 0; }
bool XProcess::pam_startSession(){ //This should only be run if pam_checkPW was successful int ret = pam_open_session(pamh,0); bool ok = FALSE; if(ret == PAM_SUCCESS){ ok = TRUE; } else{ pam_logFailure(ret); } return ok; }
bool PAMAuthenticator::authenticate(void) { pam_conv c; c.conv = PAMAuthenticator::conv; c.appdata_ptr = this; int res = pam_start("repwatchproxy", 0, &c, &this->m_ph); if (res == PAM_SUCCESS) { res = pam_set_item(this->m_ph, PAM_RUSER, this->m_user.constData()); if (res != PAM_SUCCESS) { goto getout; } res = pam_set_item(this->m_ph, PAM_RHOST, this->m_host.constData()); if (res != PAM_SUCCESS) { goto getout; } res = pam_authenticate(this->m_ph, 0); if (res != PAM_SUCCESS) { goto getout; } res = pam_acct_mgmt(this->m_ph, 0); if (PAM_NEW_AUTHTOK_REQD == res) { res = pam_chauthtok(this->m_ph, PAM_CHANGE_EXPIRED_AUTHTOK); } if (res != PAM_SUCCESS) { goto getout; } res = pam_setcred(this->m_ph, PAM_ESTABLISH_CRED); if (res != PAM_SUCCESS) { goto getout; } res = pam_open_session(this->m_ph, 0); if (res != PAM_SUCCESS) { goto getout; } return true; getout: qWarning("%s: %s", Q_FUNC_INFO, pam_strerror(this->m_ph, res)); pam_end(this->m_ph, res); } else { qCritical("PAM initialization failed"); } this->m_ph = 0; return false; }
int main(int argc, char *argv[]) { char **args; pam_handle_t *pamh=NULL; int retval; struct passwd *pw; if (argc==1){ return -1; } pw=getpwuid(getuid()); retval = pam_start(PAM_NAME, pw->pw_name, &conv, &pamh); if (retval == PAM_SUCCESS) retval = pam_acct_mgmt(pamh, 0); /* permitted access? */ else fprintf(stderr,"%s: pam_start failed\n",PAM_NAME); if (retval == PAM_SUCCESS) retval = pam_open_session(pamh, 0); else fprintf(stderr,"%s: pam_acct failed\n",PAM_NAME); if (retval != PAM_SUCCESS) fprintf(stderr,"%s: pam_acct failed\n",PAM_NAME); if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */ pamh = NULL; fprintf(stderr, "check_user: failed to release authenticator\n"); exit(1); } if (retval != PAM_SUCCESS) return 99; #ifdef LOG log=fopen(LOG,"a"); if (log!=NULL){ for (i=0;i<argc;i++){ fprintf(log,"%s ",argv[i]); } fprintf(log,"\n"); fclose(log); } #endif args = &argv[1]; execvp(args[0], args); }
void context::open_session() { _M_code = setcred(); if(errc(_M_code) != errc::success) throw cred_error(_M_pamh, _M_code); _M_code = pam_open_session(_M_pamh, 0); if(errc(_M_code) != errc::success) { rmcred(); throw session_error(_M_pamh, _M_code); } }
int pam_setup (char *user, char *host) { /* * Any application using PAM must provide a conversion function, which * is used for direct communication between a loaded module and the * application. In this case, SLURM does need a communication mechanism, * so the default (or null) conversation function may be used. */ struct pam_conv conv = {misc_conv, NULL}; int rc = 0; if (!conf->use_pam) return SLURM_SUCCESS; /* * SLURM uses PAM to obtain resource limits established by the system * administrator. PAM's session management library is responsible for * handling resource limits. When a PAM session is opened on behalf of * a user, the limits imposed by the sys admin are picked up. Opening * a PAM session requires a PAM handle, which is obtained when the PAM * interface is initialized. (PAM handles are required with essentially * all PAM calls.) It's also necessary to have the users PAM credentials * to open a user session. */ if ((rc = pam_start (SLURM_SERVICE_PAM, user, &conv, &pam_h)) != PAM_SUCCESS) { error ("pam_start: %s", pam_strerror(pam_h, rc)); return SLURM_ERROR; } else if ((rc = pam_set_item (pam_h, PAM_USER, user)) != PAM_SUCCESS) { error ("pam_set_item USER: %s", pam_strerror(pam_h, rc)); return SLURM_ERROR; } else if ((rc = pam_set_item (pam_h, PAM_RUSER, user)) != PAM_SUCCESS) { error ("pam_set_item RUSER: %s", pam_strerror(pam_h, rc)); return SLURM_ERROR; } else if ((rc = pam_set_item (pam_h, PAM_RHOST, host)) != PAM_SUCCESS) { error ("pam_set_item HOST: %s", pam_strerror(pam_h, rc)); return SLURM_ERROR; } else if ((rc = pam_setcred (pam_h, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) { error ("pam_setcred: %s", pam_strerror(pam_h, rc)); return SLURM_ERROR; } else if ((rc = pam_open_session (pam_h, 0)) != PAM_SUCCESS) { error("pam_open_session: %s", pam_strerror(pam_h, rc)); return SLURM_ERROR; } return SLURM_SUCCESS; }
static void do_auth(char *service, char*user, char*pwd, char* mode, int sid) { pam_handle_t *pamh=NULL; int retval; struct session *sessp; conv.appdata_ptr = (void*)strdup(pwd); retval = pam_start(service, user, &conv, &pamh); if (retval != PAM_SUCCESS) { werr(pamh, sid, retval, "start"); return; } pam_set_item(pamh, PAM_RUSER, user); retval = pam_authenticate(pamh, 0); if (retval != PAM_SUCCESS) { werr(pamh, sid, retval, "auth"); return; } if (mode[0] == 'A') { retval = pam_acct_mgmt(pamh, 0); if (retval != PAM_SUCCESS) { werr(pamh, sid, retval, "accounting"); return; } /*fprintf(stderr, "did ok acct \n\r");*/ } if (mode[1] == 'S') { retval = pam_open_session(pamh, 0); if (retval != PAM_SUCCESS) { werr(pamh, sid, retval, "session"); return; } /*fprintf(stderr, "did ok open sess \n\r"); */ } if ((sessp = malloc(sizeof(struct session))) == NULL) { werr(pamh, sid, -1, "malloc"); return; } if (mode[1] == 'S') sessp->session_mode = 1; else sessp->session_mode = 0; sessp->sid = sid; sessp->pamh = pamh; sessp->next = sessions; sessions = sessp; wok(sid); }
int AuthPAMCheckSession(TSession *Session) { if (! pamh) { if (! PAMStart(Session, Session->RealUser)) return(FALSE); } if (pam_acct_mgmt(pamh, 0)==PAM_SUCCESS) { pam_open_session(pamh, 0); return(TRUE); } return(FALSE); }
int pam_begin_session(struct passwd *pw, sudo_auth *auth) { int status = PAM_SUCCESS; /* * If there is no valid user we cannot open a PAM session. * This is not an error as sudo can run commands with arbitrary * uids, it just means we are done from a session management standpoint. */ if (pw == NULL) { if (pamh != NULL) { (void) pam_end(pamh, PAM_SUCCESS | PAM_DATA_SILENT); pamh = NULL; } goto done; } /* If the user did not have to authenticate there is no pam handle yet. */ if (pamh == NULL) pam_init(pw, NULL, NULL); /* * Update PAM_USER to reference the user we are running the command * as, as opposed to the user we authenticated as. */ (void) pam_set_item(pamh, PAM_USER, pw->pw_name); /* * Set credentials (may include resource limits, device ownership, etc). * We don't check the return value here because in Linux-PAM 0.75 * it returns the last saved return code, not the return code * for the setcred module. Because we haven't called pam_authenticate(), * this is not set and so pam_setcred() returns PAM_PERM_DENIED. * We can't call pam_acct_mgmt() with Linux-PAM for a similar reason. */ (void) pam_setcred(pamh, PAM_ESTABLISH_CRED); #ifndef NO_PAM_SESSION status = pam_open_session(pamh, 0); if (status != PAM_SUCCESS) { (void) pam_end(pamh, status | PAM_DATA_SILENT); pamh = NULL; } #endif done: return status == PAM_SUCCESS ? AUTH_SUCCESS : AUTH_FAILURE; }
int pam_begin_session(const char* username, int fd) { int rv, i; if (!pam_h && (rv = pam_start(PAM_APPL_NAME, username, &conv, &pam_h)) != PAM_SUCCESS) fatal("pam_start() failure: %d", rv); #ifdef SUN_PAM_TTY_BUG if ((rv = pam_set_item(pam_h, PAM_TTY, "/dev/nld")) != PAM_SUCCESS) fatal("pam_set_item(PAM_TTY,/dev/nld"); #endif conv_reject_prompts = 1; pam_conv_fd = fd; /* On Solaris and HP-UX, the docs say we can't call setcred first, and the * modules actually enforce that. LinuxPAM says we must call setcred first, * and that's preferable, so we do it in all other cases. */ #ifdef SUN_PAM int setcred_first = 0; #else int setcred_first = 1; #endif for (i = 0; i < 2; ++i) { if (i != setcred_first) { if ((rv = pam_setcred(pam_h, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) { debug("pam_setcred(PAM_ESTABLISH_CRED): %s", pam_strerror(pam_h, rv)); if (authenticated) { pam_conv_fd = -1; return -1; } } else { setcred = 1; } } else { if ((rv = pam_open_session(pam_h, 0)) != PAM_SUCCESS) { debug("pam_open_session(): %s", pam_strerror(pam_h, rv)); if (authenticated) { pam_conv_fd = -1; return -1; } } else { opened_session = 1; } } } pam_conv_fd = -1; return 0; }
int main (void) { int retval; /* 1: Call with NULL as pam handle */ retval = pam_open_session (NULL, 0); if (retval == PAM_SUCCESS) { fprintf (stderr, "pam_open_session (NULL, 0) returned PAM_SUCCESS\n"); return 1; } return 0; }
int main(int argc, char *argv[]) { char *user = (argc > 1) ? argv[1] : getlogin(); char *service = (argc > 2) ? argv[2] : "pamtest"; struct pam_conv conv; int rc; pam_handle_t *pamh = NULL; conv.conv = pamtestConv; conv.appdata_ptr = NULL; fprintf(stderr, "%s:%d Starting with user=%s service=%s\n", __FILE__, __LINE__, user, service); rc = pam_start(service, user, &conv, &pamh); CHECK_STATUS(pamh, "pam_start", rc); rc = pam_authenticate(pamh, 0); CHECK_STATUS(pamh, "pam_authenticate", rc); rc = pam_acct_mgmt(pamh, 0); CHECK_STATUS(pamh, "pam_acct_mgmt", rc); if (rc == PAM_SUCCESS) { rc = pam_open_session(pamh, 0); CHECK_STATUS(pamh, "pam_open_session", rc); rc = pam_close_session(pamh, 0); CHECK_STATUS(pamh, "pam_close_session", rc); } if (rc != PAM_SUCCESS) { return rc; } if (pamh != NULL) { rc = pam_end(pamh, PAM_SUCCESS); CHECK_STATUS(pamh, "pam_end", rc); } return rc; }
void do_pam_session(void) { debug3("PAM: opening session"); sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, (const void *)&store_conv); if (sshpam_err != PAM_SUCCESS) fatal("PAM: failed to set PAM_CONV: %s", pam_strerror(sshpam_handle, sshpam_err)); sshpam_err = pam_open_session(sshpam_handle, 0); if (sshpam_err == PAM_SUCCESS) sshpam_session_open = 1; else { sshpam_session_open = 0; disable_forwarding(); error("PAM: pam_open_session(): %s", pam_strerror(sshpam_handle, sshpam_err)); } }
int checkpass_pam(char *password) { struct pam_conv conv = { conv_func, password }; int retval = pam_start("bftpd", user, (struct pam_conv *) &conv, (pam_handle_t **) & pamh); if (retval != PAM_SUCCESS) { printf("Error while initializing PAM: %s\n", pam_strerror(pamh, retval)); return 1; } pam_fail_delay(pamh, 0); retval = pam_authenticate(pamh, 0); if (retval == PAM_SUCCESS) retval = pam_acct_mgmt(pamh, 0); if (retval == PAM_SUCCESS) pam_open_session(pamh, 0); if (retval != PAM_SUCCESS) return 1; else return 0; }
gboolean pam_session_open(void) { g_pamLastStatus = pam_setcred(g_pamHandle, PAM_ESTABLISH_CRED); if (g_pamLastStatus != PAM_SUCCESS) { fprintf(stderr, "Jolicloud-DisplayManager: Unable to define pam credentials. Error %d\n", g_pamLastStatus); return FALSE; } g_pamLastStatus = pam_open_session(g_pamHandle, 0); if (g_pamLastStatus != PAM_SUCCESS) { fprintf(stderr, "Jolicloud-DisplayManager: Unable to open session with pan. Error %d\n", g_pamLastStatus); pam_setcred(g_pamHandle, PAM_DELETE_CRED); return FALSE; } return TRUE; }
/* * Note that the position of the pam_setcred() call is discussable: * * - the PAM docs recommend pam_setcred() before pam_open_session() * - but the original RFC http://www.opengroup.org/rfc/mirror-rfc/rfc86.0.txt * uses pam_setcred() after pam_open_session() * * The old login versions (before year 2011) followed the RFC. This is probably * not optimal, because there could be a dependence between some session modules * and the user's credentials. * * The best is probably to follow openssh and call pam_setcred() before and * after pam_open_session(). -- [email protected] (18-Nov-2011) * */ static void loginpam_session(struct login_context *cxt) { int rc; pam_handle_t *pamh = cxt->pamh; rc = pam_setcred(pamh, PAM_ESTABLISH_CRED); if (is_pam_failure(rc)) loginpam_err(pamh, rc); rc = pam_open_session(pamh, 0); if (is_pam_failure(rc)) { pam_setcred(cxt->pamh, PAM_DELETE_CRED); loginpam_err(pamh, rc); } rc = pam_setcred(pamh, PAM_REINITIALIZE_CRED); if (is_pam_failure(rc)) { pam_close_session(pamh, 0); loginpam_err(pamh, rc); } }
struct passwd *checkpw (struct passwd *pw,char *pass,int argc,char *argv[]) { pam_handle_t *hdl; struct pam_conv conv; struct checkpw_cred cred; conv.conv = &checkpw_conv; conv.appdata_ptr = &cred; cred.uname = pw->pw_name; cred.pass = pass; if ((pam_start ((char *) mail_parameters (NIL,GET_SERVICENAME,NIL), pw->pw_name,&conv,&hdl) != PAM_SUCCESS) || (pam_set_item (hdl,PAM_RHOST,tcp_clientaddr ()) != PAM_SUCCESS) || (pam_authenticate (hdl,NIL) != PAM_SUCCESS) || (pam_acct_mgmt (hdl,NIL) != PAM_SUCCESS) || (pam_setcred (hdl,PAM_ESTABLISH_CRED) != PAM_SUCCESS)) { /* clean up */ pam_setcred (hdl,PAM_DELETE_CRED); pam_end (hdl,PAM_AUTH_ERR); /* failed */ return NIL; } #if 0 /* * Some people have reported that this causes a SEGV in strncpy() from * pam_unix.so.1 */ /* * This pam_open_session() call is inconsistant with how we handle other * platforms, where we don't write [uw]tmp records. However, unlike our * code on other platforms, pam_acct_mgmt() will check those records for * inactivity and deny the authentication. */ pam_open_session (hdl,NIL); /* make sure account doesn't go inactive */ #endif /* arm hook to delete credentials */ mail_parameters (NIL,SET_LOGOUTHOOK,(void *) checkpw_cleanup); mail_parameters (NIL,SET_LOGOUTDATA,(void *) hdl); return pw; }
void do_pam_session(struct ssh *ssh) { debug3("PAM: opening session"); expose_authinfo(__func__); sshpam_err = pam_set_item(sshpam_handle, PAM_CONV, (const void *)&store_conv); if (sshpam_err != PAM_SUCCESS) fatal("PAM: failed to set PAM_CONV: %s", pam_strerror(sshpam_handle, sshpam_err)); sshpam_err = pam_open_session(sshpam_handle, 0); if (sshpam_err == PAM_SUCCESS) sshpam_session_open = 1; else { sshpam_session_open = 0; auth_restrict_session(ssh); error("PAM: pam_open_session(): %s", pam_strerror(sshpam_handle, sshpam_err)); } }
int lxdm_auth_session_begin(LXDM_AUTH *a,const char *name,int tty,int display,char mcookie[16]) { int err; char x[256]; if(!a->handle) { return -1; } sprintf(x, "tty%d", tty); pam_set_item(a->handle, PAM_TTY, x); #ifdef PAM_XDISPLAY sprintf(x,":%d",display); pam_set_item(a->handle, PAM_XDISPLAY, x); #endif #if !defined(DISABLE_XAUTH) && defined(PAM_XAUTHDATA) struct pam_xauth_data value; value.name="MIT-MAGIC-COOKIE-1"; value.namelen=18; value.data=mcookie; value.datalen=16; pam_set_item (a->handle, PAM_XAUTHDATA, &value); #endif if(name && name[0]) { char *env; env = g_strdup_printf ("DESKTOP_SESSION=%s", name); pam_putenv (a->handle, env); g_free (env); } err = pam_open_session(a->handle, 0); /* FIXME pam session failed */ if( err != PAM_SUCCESS ) g_warning( "pam open session error \"%s\"\n", pam_strerror(a->handle, err)); else a->in_session=1; return 0; }
static int open_session (pam_handle_t *pamh, const char *user) { char login[256]; int res; /* * If we're already in the right session, then skip cockpit-session. * This is used when testing, or running as your own user. * * This doesn't apply if this code is running as a service, or otherwise * unassociated from a terminal, we get a non-zero return value from * getlogin_r() in that case. */ want_session = (getlogin_r (login, sizeof (login)) != 0 || strcmp (login, user) != 0); if (want_session) { debug ("checking access for %s", user); res = pam_acct_mgmt (pamh, 0); if (res != PAM_SUCCESS) { warnx ("user account access failed: %s: %s", user, pam_strerror (pamh, res)); /* We change PAM_AUTH_ERR to PAM_PERM_DENIED so that we can * distinguish between failures here and in * * pam_authenticate. */ if (res == PAM_AUTH_ERR) res = PAM_PERM_DENIED; return res; } debug ("opening pam session for %s", user); res = pam_set_item (pamh, PAM_TTY, line); if (res != PAM_SUCCESS) { warnx ("couldn't set tty: %s", pam_strerror (pamh, res)); return res; } res = pam_setcred (pamh, PAM_ESTABLISH_CRED); if (res != PAM_SUCCESS) { warnx ("establishing credentials failed: %s: %s", user, pam_strerror (pamh, res)); return res; } res = pam_open_session (pamh, 0); if (res != PAM_SUCCESS) { warnx ("couldn't open session: %s: %s", user, pam_strerror (pamh, res)); return res; } res = pam_setcred (pamh, PAM_REINITIALIZE_CRED); if (res != PAM_SUCCESS) { warnx ("reinitializing credentials failed: %s: %s", user, pam_strerror (pamh, res)); return res; } } return PAM_SUCCESS; }
static void create_watching_parent (void) { pid_t child; sigset_t ourset; struct sigaction oldact[3]; int status = 0; int retval; retval = pam_open_session (pamh, 0); if (is_pam_failure(retval)) { cleanup_pam (retval); errx (EXIT_FAILURE, _("cannot open session: %s"), pam_strerror (pamh, retval)); } else { _pam_session_opened = 1; } memset(oldact, 0, sizeof(oldact)); child = fork (); if (child == (pid_t) - 1) { cleanup_pam (PAM_ABORT); err (EXIT_FAILURE, _("cannot create child process")); } /* the child proceeds to run the shell */ if (child == 0) { return; } /* In the parent watch the child. */ /* su without pam support does not have a helper that keeps sitting on any directory so let's go to /. */ if (chdir ("/") != 0) { warn (_("cannot change directory to %s"), "/"); } sigfillset (&ourset); if (sigprocmask (SIG_BLOCK, &ourset, NULL)) { warn (_("cannot block signals")); caught_signal = true; } if (!caught_signal) { struct sigaction action; action.sa_handler = su_catch_sig; sigemptyset (&action.sa_mask); action.sa_flags = 0; sigemptyset (&ourset); if (!same_session) { if (sigaddset(&ourset, SIGINT) || sigaddset(&ourset, SIGQUIT)) { warn (_("cannot set signal handler")); caught_signal = true; } } if (!caught_signal && (sigaddset(&ourset, SIGTERM) || sigaddset(&ourset, SIGALRM) || sigaction(SIGTERM, &action, &oldact[0]) || sigprocmask(SIG_UNBLOCK, &ourset, NULL))) { warn (_("cannot set signal handler")); caught_signal = true; } if (!caught_signal && !same_session && (sigaction(SIGINT, &action, &oldact[1]) || sigaction(SIGQUIT, &action, &oldact[2]))) { warn (_("cannot set signal handler")); caught_signal = true; } } if (!caught_signal) { pid_t pid; for (;;) { pid = waitpid (child, &status, WUNTRACED); if (pid != (pid_t) - 1 && WIFSTOPPED (status)) { kill (getpid (), SIGSTOP); /* once we get here, we must have resumed */ kill (pid, SIGCONT); } else { break; } } if (pid != (pid_t) - 1) { if (WIFSIGNALED (status)) { fprintf (stderr, "%s%s\n", strsignal (WTERMSIG (status)), WCOREDUMP (status) ? _(" (core dumped)") : ""); status = WTERMSIG (status) + 128; } else { status = WEXITSTATUS (status); } } else if (caught_signal) { status = caught_signal + 128; } else { status = 1; } } else { status = 1; } if (caught_signal) { fprintf (stderr, _("\nSession terminated, killing shell...")); kill (child, SIGTERM); } cleanup_pam (PAM_SUCCESS); if (caught_signal) { sleep (2); kill (child, SIGKILL); fprintf (stderr, _(" ...killed.\n")); /* Let's terminate itself with the received signal. * * It seems that shells use WIFSIGNALED() rather than our exit status * value to detect situations when is necessary to cleanup (reset) * terminal settings (kzak -- Jun 2013). */ switch (caught_signal) { case SIGTERM: sigaction(SIGTERM, &oldact[0], NULL); break; case SIGINT: sigaction(SIGINT, &oldact[1], NULL); break; case SIGQUIT: sigaction(SIGQUIT, &oldact[2], NULL); break; default: /* just in case that signal stuff initialization failed and * caught_signal = true */ caught_signal = SIGKILL; break; } kill(getpid(), caught_signal); } exit (status); }
gchar * mdm_verify_user (MdmDisplay *d, const char *username, gboolean allow_retry) { gint pamerr = 0; struct passwd *pwent = NULL; char *login, *passreq; char *pam_stack = NULL; MDM_PAM_QUAL void *p; int null_tok = 0; gboolean credentials_set = FALSE; gboolean error_msg_given = FALSE; gboolean started_timer = FALSE; verify_user_again: pamerr = 0; login = NULL; error_msg_given = FALSE; credentials_set = FALSE; started_timer = FALSE; null_tok = 0; /* Don't start a timed login if we've already entered a username */ if (username != NULL) { login = g_strdup (username); mdm_slave_greeter_ctl_no_ret (MDM_SETLOGIN, login); } else { /* start the timer for timed logins */ if ( ! ve_string_empty (mdm_daemon_config_get_value_string (MDM_KEY_TIMED_LOGIN)) && d->timed_login_ok && (d->attached)) { mdm_slave_greeter_ctl_no_ret (MDM_STARTTIMER, ""); started_timer = TRUE; } } cur_mdm_disp = d; authenticate_again: if (prev_user && !login) { login = g_strdup (prev_user); } else if (login && !prev_user) { prev_user = g_strdup (login); auth_retries = 0; } else if (login && prev_user && strcmp (login, prev_user)) { g_free (prev_user); prev_user = g_strdup (login); auth_retries = 0; } /* * Initialize a PAM session for the user... * Get value per-display so different displays can use different * PAM Stacks, in case one display should use a different * authentication mechanism than another display. */ pam_stack = mdm_daemon_config_get_value_string_per_display (MDM_KEY_PAM_STACK, (char *)d->name); if ( ! create_pamh (d, pam_stack, login, &pamc, d->name, &pamerr)) { if (started_timer) mdm_slave_greeter_ctl_no_ret (MDM_STOPTIMER, ""); g_free (pam_stack); goto pamerr; } g_free (pam_stack); /* * have to unset login otherwise there is no chance to ever enter * a different user */ g_free (login); login = NULL; pam_set_item (pamh, PAM_USER_PROMPT, _("Username:"******"PASSREQ="); if (mdm_daemon_config_get_value_bool (MDM_KEY_PASSWORD_REQUIRED) || ((passreq != NULL) && g_ascii_strcasecmp (passreq, "YES") == 0)) null_tok |= PAM_DISALLOW_NULL_AUTHTOK; mdm_verify_select_user (NULL); /* Start authentication session */ did_we_ask_for_password = FALSE; if ((pamerr = pam_authenticate (pamh, null_tok)) != PAM_SUCCESS) { if ( ! ve_string_empty (selected_user)) { pam_handle_t *tmp_pamh; /* Face browser was used to select a user, just completely rewhack everything since it seems various PAM implementations are having goats with just setting PAM_USER and trying to pam_authenticate again */ g_free (login); login = selected_user; selected_user = NULL; mdm_sigterm_block_push (); mdm_sigchld_block_push (); tmp_pamh = pamh; pamh = NULL; mdm_sigchld_block_pop (); mdm_sigterm_block_pop (); /* FIXME: what about errors */ /* really this has been a sucess, not a failure */ pam_end (tmp_pamh, pamerr); g_free (prev_user); prev_user = NULL; auth_retries = 0; mdm_slave_greeter_ctl_no_ret (MDM_SETLOGIN, login); goto authenticate_again; } if (started_timer) mdm_slave_greeter_ctl_no_ret (MDM_STOPTIMER, ""); if (mdm_slave_action_pending ()) { /* FIXME: see note above about PAM_FAIL_DELAY */ /* #ifndef PAM_FAIL_DELAY */ mdm_sleep_no_signal (mdm_daemon_config_get_value_int (MDM_KEY_RETRY_DELAY)); /* wait up to 100ms randomly */ usleep (g_random_int_range (0, 100000)); /* #endif */ /* PAM_FAIL_DELAY */ mdm_error ("Couldn't authenticate user"); if (prev_user) { unsigned max_auth_retries = 3; char *val = mdm_read_default ("LOGIN_RETRIES="); if (val) { max_auth_retries = atoi (val); g_free (val); } if (allow_retry == FALSE || pamerr == PAM_MAXTRIES || ++auth_retries >= max_auth_retries) { g_free (prev_user); prev_user = NULL; auth_retries = 0; } } } else { /* cancel, configurator etc pressed */ g_free (prev_user); prev_user = NULL; auth_retries = 0; } goto pamerr; } /* stop the timer for timed logins */ if (started_timer) mdm_slave_greeter_ctl_no_ret (MDM_STOPTIMER, ""); g_free (login); login = NULL; g_free (prev_user); prev_user = NULL; if ((pamerr = pam_get_item (pamh, PAM_USER, &p)) != PAM_SUCCESS) { login = NULL; /* is not really an auth problem, but it will pretty much look as such, it shouldn't really happen */ if (mdm_slave_action_pending ()) mdm_error ("Couldn't authenticate user"); goto pamerr; } login = g_strdup ((const char *)p); /* kind of anal, the greeter likely already knows, but it could have been changed */ mdm_slave_greeter_ctl_no_ret (MDM_SETLOGIN, login); if ( ! mdm_slave_check_user_wants_to_log_in (login)) { /* cleanup stuff */ mdm_slave_greeter_ctl_no_ret (MDM_SETLOGIN, ""); g_free (login); login = NULL; mdm_slave_greeter_ctl_no_ret (MDM_RESETOK, ""); mdm_verify_cleanup (d); goto verify_user_again; } /* Check if user is root and is allowed to log in */ pwent = getpwnam (login); if (( ! mdm_daemon_config_get_value_bool (MDM_KEY_ALLOW_ROOT) || ( ! d->attached )) && (pwent != NULL && pwent->pw_uid == 0)) { mdm_error ("Root login disallowed on display '%s'", d->name); mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, _("\nThe system administrator " "is not allowed to login " "from this screen")); /*mdm_slave_greeter_ctl_no_ret (MDM_ERRDLG, _("Root login disallowed"));*/ error_msg_given = TRUE; goto pamerr; } if (mdm_daemon_config_get_value_bool (MDM_KEY_DISPLAY_LAST_LOGIN)) { char *info = mdm_get_last_info (login); mdm_slave_greeter_ctl_no_ret (MDM_MSG, info); g_free (info); } /* Check if the user's account is healthy. */ pamerr = pam_acct_mgmt (pamh, null_tok); switch (pamerr) { case PAM_SUCCESS : break; case PAM_NEW_AUTHTOK_REQD : if ((pamerr = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK)) != PAM_SUCCESS) { mdm_error ("Authentication token change failed for user %s", login); mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, _("\nThe change of the authentication token failed. " "Please try again later or contact the system administrator.")); error_msg_given = TRUE; goto pamerr; } break; case PAM_ACCT_EXPIRED : mdm_error ("User %s no longer permitted to access the system", login); mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, _("\nThe system administrator has disabled your account.")); error_msg_given = TRUE; goto pamerr; case PAM_PERM_DENIED : mdm_error ("User %s not permitted to gain access at this time", login); mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, _("\nThe system administrator has disabled access to the system temporarily.")); error_msg_given = TRUE; goto pamerr; default : if (mdm_slave_action_pending ()) mdm_error ("Couldn't set acct. mgmt for %s", login); goto pamerr; } pwent = getpwnam (login); if (/* paranoia */ pwent == NULL || ! mdm_setup_gids (login, pwent->pw_gid)) { mdm_error ("Cannot set user group for %s", login); mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, _("\nCannot set your user group; " "you will not be able to log in. " "Please contact your system administrator.")); goto pamerr; } did_setcred = TRUE; /* Set credentials */ pamerr = pam_setcred (pamh, PAM_ESTABLISH_CRED); if (pamerr != PAM_SUCCESS) { did_setcred = FALSE; if (mdm_slave_action_pending ()) mdm_error ("Couldn't set credentials for %s", login); goto pamerr; } credentials_set = TRUE; opened_session = TRUE; /* Register the session */ pamerr = pam_open_session (pamh, 0); if (pamerr != PAM_SUCCESS) { opened_session = FALSE; /* we handle this above */ did_setcred = FALSE; if (mdm_slave_action_pending ()) mdm_error ("Couldn't open session for %s", login); goto pamerr; } /* Workaround to avoid mdm messages being logged as PAM_pwdb */ mdm_log_shutdown (); mdm_log_init (); cur_mdm_disp = NULL; /* * Login succeeded. * This function is a no-op if libaudit is not present. */ log_to_audit_system(login, d->hostname, d->name, AU_SUCCESS); return login; pamerr: /* * Take care of situation where we get here before setting pwent. * Since login can be passed in as NULL, get the actual value if * possible. */ if ((pam_get_item (pamh, PAM_USER, &p)) == PAM_SUCCESS) { g_free (login); login = g_strdup ((const char *)p); } if (pwent == NULL && login != NULL) { pwent = getpwnam (login); } /* * Log the failed login attempt. * This function is a no-op if libaudit is not present. */ log_to_audit_system(login, d->hostname, d->name, AU_FAILED); /* The verbose authentication is turned on, output the error * message from the PAM subsystem */ if ( ! error_msg_given && mdm_slave_action_pending ()) { mdm_slave_write_utmp_wtmp_record (d, MDM_SESSION_RECORD_TYPE_FAILED_ATTEMPT, login, getpid ()); /* * I'm not sure yet if I should display this message for any * other issues - heeten * Adding AUTHINFO_UNAVAIL to the list - its what an unknown * user is. */ if (pamerr == PAM_AUTH_ERR || pamerr == PAM_USER_UNKNOWN || pamerr == PAM_AUTHINFO_UNAVAIL) { gboolean is_capslock = FALSE; const char *basemsg; char *msg; char *ret; ret = mdm_slave_greeter_ctl (MDM_QUERY_CAPSLOCK, ""); if ( ! ve_string_empty (ret)) is_capslock = TRUE; g_free (ret); /* Only give this message if we actually asked for password, otherwise it would be silly to say that the password may have been wrong */ if (did_we_ask_for_password) { basemsg = _("\nIncorrect username or password. " "Letters must be typed in the correct " "case."); } else { basemsg = _("\nAuthentication failed. " "Letters must be typed in the correct " "case."); } if (is_capslock) { msg = g_strconcat (basemsg, " ", _("Caps Lock is on."), NULL); } else { msg = g_strdup (basemsg); } mdm_slave_greeter_ctl_no_ret (MDM_ERRBOX, msg); g_free (msg); } else { mdm_slave_greeter_ctl_no_ret (MDM_ERRDLG, _("Authentication failed")); } } did_setcred = FALSE; opened_session = FALSE; if (pamh != NULL) { pam_handle_t *tmp_pamh; mdm_sigterm_block_push (); mdm_sigchld_block_push (); tmp_pamh = pamh; pamh = NULL; mdm_sigchld_block_pop (); mdm_sigterm_block_pop (); /* Throw away the credentials */ if (credentials_set) pam_setcred (tmp_pamh, PAM_DELETE_CRED); pam_end (tmp_pamh, pamerr); } pamh = NULL; /* Workaround to avoid mdm messages being logged as PAM_pwdb */ mdm_log_shutdown (); mdm_log_init (); g_free (login); cur_mdm_disp = NULL; return NULL; }
int main(int argc, char **argv) { int devnull_fd = -1; #ifdef TIOCNOTTY int tty_fd = -1; #endif #ifdef HAVE_PAM pam_handle_t *pamh = NULL; int pamr; const char *const *pamenv = NULL; #endif int opt; bool start = false; bool stop = false; bool oknodo = false; bool test = false; char *exec = NULL; char *startas = NULL; char *name = NULL; char *pidfile = NULL; char *retry = NULL; int sig = -1; int nicelevel = 0, ionicec = -1, ioniced = 0; bool background = false; bool makepidfile = false; bool interpreted = false; bool progress = false; uid_t uid = 0; gid_t gid = 0; char *home = NULL; int tid = 0; char *redirect_stderr = NULL; char *redirect_stdout = NULL; int stdin_fd; int stdout_fd; int stderr_fd; pid_t pid, spid; int i; char *svcname = getenv("RC_SVCNAME"); RC_STRINGLIST *env_list; RC_STRING *env; char *tmp, *newpath, *np; char *p; char *token; char exec_file[PATH_MAX]; struct passwd *pw; struct group *gr; char line[130]; FILE *fp; size_t len; mode_t numask = 022; char **margv; unsigned int start_wait = 0; applet = basename_c(argv[0]); TAILQ_INIT(&schedule); #ifdef DEBUG_MEMORY atexit(cleanup); #endif signal_setup(SIGINT, handle_signal); signal_setup(SIGQUIT, handle_signal); signal_setup(SIGTERM, handle_signal); if ((tmp = getenv("SSD_NICELEVEL"))) if (sscanf(tmp, "%d", &nicelevel) != 1) eerror("%s: invalid nice level `%s' (SSD_NICELEVEL)", applet, tmp); /* Get our user name and initial dir */ p = getenv("USER"); home = getenv("HOME"); if (home == NULL || p == NULL) { pw = getpwuid(getuid()); if (pw != NULL) { if (p == NULL) setenv("USER", pw->pw_name, 1); if (home == NULL) { setenv("HOME", pw->pw_dir, 1); home = pw->pw_dir; } } } while ((opt = getopt_long(argc, argv, getoptstring, longopts, (int *) 0)) != -1) switch (opt) { case 'I': /* --ionice */ if (sscanf(optarg, "%d:%d", &ionicec, &ioniced) == 0) eerrorx("%s: invalid ionice `%s'", applet, optarg); if (ionicec == 0) ioniced = 0; else if (ionicec == 3) ioniced = 7; ionicec <<= 13; /* class shift */ break; case 'K': /* --stop */ stop = true; break; case 'N': /* --nice */ if (sscanf(optarg, "%d", &nicelevel) != 1) eerrorx("%s: invalid nice level `%s'", applet, optarg); break; case 'P': /* --progress */ progress = true; break; case 'R': /* --retry <schedule>|<timeout> */ retry = optarg; break; case 'S': /* --start */ start = true; break; case 'b': /* --background */ background = true; break; case 'c': /* --chuid <username>|<uid> */ /* DEPRECATED */ ewarn("WARNING: -c/--chuid is deprecated and will be removed in the future, please use -u/--user instead"); case 'u': /* --user <username>|<uid> */ { p = optarg; tmp = strsep(&p, ":"); changeuser = xstrdup(tmp); if (sscanf(tmp, "%d", &tid) != 1) pw = getpwnam(tmp); else pw = getpwuid((uid_t)tid); if (pw == NULL) eerrorx("%s: user `%s' not found", applet, tmp); uid = pw->pw_uid; home = pw->pw_dir; unsetenv("HOME"); if (pw->pw_dir) setenv("HOME", pw->pw_dir, 1); unsetenv("USER"); if (pw->pw_name) setenv("USER", pw->pw_name, 1); if (gid == 0) gid = pw->pw_gid; if (p) { tmp = strsep (&p, ":"); if (sscanf(tmp, "%d", &tid) != 1) gr = getgrnam(tmp); else gr = getgrgid((gid_t) tid); if (gr == NULL) eerrorx("%s: group `%s'" " not found", applet, tmp); gid = gr->gr_gid; } } break; case 'd': /* --chdir /new/dir */ ch_dir = optarg; break; case 'e': /* --env */ putenv(optarg); break; case 'g': /* --group <group>|<gid> */ if (sscanf(optarg, "%d", &tid) != 1) gr = getgrnam(optarg); else gr = getgrgid((gid_t)tid); if (gr == NULL) eerrorx("%s: group `%s' not found", applet, optarg); gid = gr->gr_gid; break; case 'i': /* --interpreted */ interpreted = true; break; case 'k': if (parse_mode(&numask, optarg)) eerrorx("%s: invalid mode `%s'", applet, optarg); break; case 'm': /* --make-pidfile */ makepidfile = true; break; case 'n': /* --name <process-name> */ name = optarg; break; case 'o': /* --oknodo */ /* DEPRECATED */ ewarn("WARNING: -o/--oknodo is deprecated and will be removed in the future"); oknodo = true; break; case 'p': /* --pidfile <pid-file> */ pidfile = optarg; break; case 's': /* --signal <signal> */ sig = parse_signal(optarg); break; case 't': /* --test */ test = true; break; case 'r': /* --chroot /new/root */ ch_root = optarg; break; case 'a': /* --startas <name> */ /* DEPRECATED */ ewarn("WARNING: -a/--startas is deprecated and will be removed in the future, please use -x/--exec or -n/--name instead"); startas = optarg; break; case 'w': if (sscanf(optarg, "%d", &start_wait) != 1) eerrorx("%s: `%s' not a number", applet, optarg); break; case 'x': /* --exec <executable> */ exec = optarg; break; case '1': /* --stdout /path/to/stdout.lgfile */ redirect_stdout = optarg; break; case '2': /* --stderr /path/to/stderr.logfile */ redirect_stderr = optarg; break; case_RC_COMMON_GETOPT } endpwent(); argc -= optind; argv += optind; /* Allow start-stop-daemon --signal HUP --exec /usr/sbin/dnsmasq * instead of forcing --stop --oknodo as well */ if (!start && !stop && sig != SIGINT && sig != SIGTERM && sig != SIGQUIT && sig != SIGKILL) oknodo = true; if (!exec) exec = startas; else if (!name) name = startas; if (!exec) { exec = *argv; if (!exec) exec = name; if (name && start) *argv = name; } else if (name) { *--argv = name; ++argc; } else if (exec) { *--argv = exec; ++argc; }; if (stop || sig != -1) { if (sig == -1) sig = SIGTERM; if (!*argv && !pidfile && !name && !uid) eerrorx("%s: --stop needs --exec, --pidfile," " --name or --user", applet); if (background) eerrorx("%s: --background is only relevant with" " --start", applet); if (makepidfile) eerrorx("%s: --make-pidfile is only relevant with" " --start", applet); if (redirect_stdout || redirect_stderr) eerrorx("%s: --stdout and --stderr are only relevant" " with --start", applet); } else { if (!exec) eerrorx("%s: nothing to start", applet); if (makepidfile && !pidfile) eerrorx("%s: --make-pidfile is only relevant with" " --pidfile", applet); if ((redirect_stdout || redirect_stderr) && !background) eerrorx("%s: --stdout and --stderr are only relevant" " with --background", applet); } /* Expand ~ */ if (ch_dir && *ch_dir == '~') ch_dir = expand_home(home, ch_dir); if (ch_root && *ch_root == '~') ch_root = expand_home(home, ch_root); if (exec) { if (*exec == '~') exec = expand_home(home, exec); /* Validate that the binary exists if we are starting */ if (*exec == '/' || *exec == '.') { /* Full or relative path */ if (ch_root) snprintf(exec_file, sizeof(exec_file), "%s/%s", ch_root, exec); else snprintf(exec_file, sizeof(exec_file), "%s", exec); } else { /* Something in $PATH */ p = tmp = xstrdup(getenv("PATH")); *exec_file = '\0'; while ((token = strsep(&p, ":"))) { if (ch_root) snprintf(exec_file, sizeof(exec_file), "%s/%s/%s", ch_root, token, exec); else snprintf(exec_file, sizeof(exec_file), "%s/%s", token, exec); if (exists(exec_file)) break; *exec_file = '\0'; } free(tmp); } } if (start && !exists(exec_file)) { eerror("%s: %s does not exist", applet, *exec_file ? exec_file : exec); exit(EXIT_FAILURE); } /* If we don't have a pidfile we should check if it's interpreted * or not. If it we, we need to pass the interpreter through * to our daemon calls to find it correctly. */ if (interpreted && !pidfile) { fp = fopen(exec_file, "r"); if (fp) { p = fgets(line, sizeof(line), fp); fclose(fp); if (p != NULL && line[0] == '#' && line[1] == '!') { p = line + 2; /* Strip leading spaces */ while (*p == ' ' || *p == '\t') p++; /* Remove the trailing newline */ len = strlen(p) - 1; if (p[len] == '\n') p[len] = '\0'; token = strsep(&p, " "); strncpy(exec_file, token, sizeof(exec_file)); opt = 0; for (nav = argv; *nav; nav++) opt++; nav = xmalloc(sizeof(char *) * (opt + 3)); nav[0] = exec_file; len = 1; if (p) nav[len++] = p; for (i = 0; i < opt; i++) nav[i + len] = argv[i]; nav[i + len] = '\0'; } } } margv = nav ? nav : argv; if (stop || sig != -1) { if (sig == -1) sig = SIGTERM; if (!stop) oknodo = true; if (retry) parse_schedule(retry, sig); else if (test || oknodo) parse_schedule("0", sig); else parse_schedule(NULL, sig); i = run_stop_schedule(exec, (const char *const *)margv, pidfile, uid, test, progress); if (i < 0) /* We failed to stop something */ exit(EXIT_FAILURE); if (test || oknodo) return i > 0 ? EXIT_SUCCESS : EXIT_FAILURE; /* Even if we have not actually killed anything, we should * remove information about it as it may have unexpectedly * crashed out. We should also return success as the end * result would be the same. */ if (pidfile && exists(pidfile)) unlink(pidfile); if (svcname) rc_service_daemon_set(svcname, exec, (const char *const *)argv, pidfile, false); exit(EXIT_SUCCESS); } if (pidfile) pid = get_pid(pidfile); else pid = 0; if (do_stop(exec, (const char * const *)margv, pid, uid, 0, test) > 0) eerrorx("%s: %s is already running", applet, exec); if (test) { if (rc_yesno(getenv("EINFO_QUIET"))) exit (EXIT_SUCCESS); einfon("Would start"); while (argc-- > 0) printf(" %s", *argv++); printf("\n"); eindent(); if (uid != 0) einfo("as user id %d", uid); if (gid != 0) einfo("as group id %d", gid); if (ch_root) einfo("in root `%s'", ch_root); if (ch_dir) einfo("in dir `%s'", ch_dir); if (nicelevel != 0) einfo("with a priority of %d", nicelevel); if (name) einfo ("with a process name of %s", name); eoutdent(); exit(EXIT_SUCCESS); } ebeginv("Detaching to start `%s'", exec); eindentv(); /* Remove existing pidfile */ if (pidfile) unlink(pidfile); if (background) signal_setup(SIGCHLD, handle_signal); if ((pid = fork()) == -1) eerrorx("%s: fork: %s", applet, strerror(errno)); /* Child process - lets go! */ if (pid == 0) { pid_t mypid = getpid(); umask(numask); #ifdef TIOCNOTTY tty_fd = open("/dev/tty", O_RDWR); #endif devnull_fd = open("/dev/null", O_RDWR); if (nicelevel) { if (setpriority(PRIO_PROCESS, mypid, nicelevel) == -1) eerrorx("%s: setpritory %d: %s", applet, nicelevel, strerror(errno)); } if (ionicec != -1 && ioprio_set(1, mypid, ionicec | ioniced) == -1) eerrorx("%s: ioprio_set %d %d: %s", applet, ionicec, ioniced, strerror(errno)); if (ch_root && chroot(ch_root) < 0) eerrorx("%s: chroot `%s': %s", applet, ch_root, strerror(errno)); if (ch_dir && chdir(ch_dir) < 0) eerrorx("%s: chdir `%s': %s", applet, ch_dir, strerror(errno)); if (makepidfile && pidfile) { fp = fopen(pidfile, "w"); if (! fp) eerrorx("%s: fopen `%s': %s", applet, pidfile, strerror(errno)); fprintf(fp, "%d\n", mypid); fclose(fp); } #ifdef HAVE_PAM if (changeuser != NULL) { pamr = pam_start("start-stop-daemon", changeuser, &conv, &pamh); if (pamr == PAM_SUCCESS) pamr = pam_acct_mgmt(pamh, PAM_SILENT); if (pamr == PAM_SUCCESS) pamr = pam_open_session(pamh, PAM_SILENT); if (pamr != PAM_SUCCESS) eerrorx("%s: pam error: %s", applet, pam_strerror(pamh, pamr)); } #endif if (gid && setgid(gid)) eerrorx("%s: unable to set groupid to %d", applet, gid); if (changeuser && initgroups(changeuser, gid)) eerrorx("%s: initgroups (%s, %d)", applet, changeuser, gid); if (uid && setuid(uid)) eerrorx ("%s: unable to set userid to %d", applet, uid); /* Close any fd's to the passwd database */ endpwent(); #ifdef TIOCNOTTY ioctl(tty_fd, TIOCNOTTY, 0); close(tty_fd); #endif /* Clean the environment of any RC_ variables */ env_list = rc_stringlist_new(); i = 0; while (environ[i]) rc_stringlist_add(env_list, environ[i++]); #ifdef HAVE_PAM if (changeuser != NULL) { pamenv = (const char *const *)pam_getenvlist(pamh); if (pamenv) { while (*pamenv) { /* Don't add strings unless they set a var */ if (strchr(*pamenv, '=')) putenv(xstrdup(*pamenv)); else unsetenv(*pamenv); pamenv++; } } } #endif TAILQ_FOREACH(env, env_list, entries) { if ((strncmp(env->value, "RC_", 3) == 0 && strncmp(env->value, "RC_SERVICE=", 10) != 0 && strncmp(env->value, "RC_SVCNAME=", 10) != 0) || strncmp(env->value, "SSD_NICELEVEL=", 14) == 0) { p = strchr(env->value, '='); *p = '\0'; unsetenv(env->value); continue; } } rc_stringlist_free(env_list); /* For the path, remove the rcscript bin dir from it */ if ((token = getenv("PATH"))) { len = strlen(token); newpath = np = xmalloc(len + 1); while (token && *token) { p = strchr(token, ':'); if (p) { *p++ = '\0'; while (*p == ':') p++; } if (strcmp(token, RC_LIBEXECDIR "/bin") != 0 && strcmp(token, RC_LIBEXECDIR "/sbin") != 0) { len = strlen(token); if (np != newpath) *np++ = ':'; memcpy(np, token, len); np += len; } token = p; } *np = '\0'; unsetenv("PATH"); setenv("PATH", newpath, 1); } stdin_fd = devnull_fd; stdout_fd = devnull_fd; stderr_fd = devnull_fd; if (redirect_stdout) { if ((stdout_fd = open(redirect_stdout, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR)) == -1) eerrorx("%s: unable to open the logfile" " for stdout `%s': %s", applet, redirect_stdout, strerror(errno)); } if (redirect_stderr) { if ((stderr_fd = open(redirect_stderr, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR)) == -1) eerrorx("%s: unable to open the logfile" " for stderr `%s': %s", applet, redirect_stderr, strerror(errno)); } if (background) dup2(stdin_fd, STDIN_FILENO); if (background || redirect_stdout || rc_yesno(getenv("EINFO_QUIET"))) dup2(stdout_fd, STDOUT_FILENO); if (background || redirect_stderr || rc_yesno(getenv("EINFO_QUIET"))) dup2(stderr_fd, STDERR_FILENO); for (i = getdtablesize() - 1; i >= 3; --i) close(i); setsid(); execvp(exec, argv); #ifdef HAVE_PAM if (changeuser != NULL && pamr == PAM_SUCCESS) pam_close_session(pamh, PAM_SILENT); #endif eerrorx("%s: failed to exec `%s': %s", applet, exec,strerror(errno)); }
int main(int argc, char **argv) { hardened_shadow_openlog("su"); if (!hardened_shadow_get_current_username(¤t_username)) errx(EXIT_FAILURE, "Cannot determine your user name."); parse_args(argc, argv); uid_t my_uid = getuid(); bool is_root = (my_uid == 0); if (!is_root && (!isatty(STDIN_FILENO) || !ttyname(STDIN_FILENO))) errx(EXIT_FAILURE, "must be run from a terminal"); const struct pam_conv pam_conversation = { misc_conv, NULL }; pam_handle_t *pam_handle = NULL; int pam_rv = pam_start("su", target_username, &pam_conversation, &pam_handle); if (pam_rv != PAM_SUCCESS) { hardened_shadow_syslog(LOG_ERR, "pam_start: error %d", pam_rv); su_fatal(); } pam_rv = pam_set_item(pam_handle, PAM_TTY, ttyname(STDIN_FILENO)); if (pam_rv != PAM_SUCCESS) { hardened_shadow_syslog(LOG_ERR, "pam_set_item: %s", pam_strerror(pam_handle, pam_rv)); goto pam_cleanup; } pam_rv = pam_set_item(pam_handle, PAM_RUSER, current_username); if (pam_rv != PAM_SUCCESS) { hardened_shadow_syslog(LOG_ERR, "pam_set_item: %s", pam_strerror(pam_handle, pam_rv)); goto pam_cleanup; } pam_rv = pam_fail_delay(pam_handle, 1000000); if (pam_rv != PAM_SUCCESS) { hardened_shadow_syslog(LOG_ERR, "pam_fail_delay: %s", pam_strerror(pam_handle, pam_rv)); goto pam_cleanup; } pam_rv = pam_authenticate(pam_handle, 0); if (pam_rv != PAM_SUCCESS) { hardened_shadow_syslog(LOG_ERR, "pam_authenticate: %s", pam_strerror(pam_handle, pam_rv)); goto pam_cleanup; } pam_rv = pam_acct_mgmt(pam_handle, 0); if (pam_rv != PAM_SUCCESS) { if (is_root) { warnx("%s (ignored)", pam_strerror(pam_handle, pam_rv)); } else if (pam_rv == PAM_NEW_AUTHTOK_REQD) { pam_rv = pam_chauthtok(pam_handle, PAM_CHANGE_EXPIRED_AUTHTOK); if (pam_rv != PAM_SUCCESS) { hardened_shadow_syslog(LOG_ERR, "pam_chauthtok: %s", pam_strerror(pam_handle, pam_rv)); goto pam_cleanup; } } else { hardened_shadow_syslog(LOG_ERR, "pam_acct_mgmt: %s", pam_strerror(pam_handle, pam_rv)); goto pam_cleanup; } } if (setgid(target_gid) != 0) { hardened_shadow_syslog(LOG_ERR, "bad group ID `%d' for user `%s': %s", target_gid, target_username, strerror(errno)); pam_rv = PAM_ABORT; goto pam_cleanup; } if (initgroups(target_username, target_gid) != 0) { hardened_shadow_syslog(LOG_ERR, "initgroups failed for user `%s': %s", target_username, strerror(errno)); pam_rv = PAM_ABORT; goto pam_cleanup; } pam_rv = pam_setcred(pam_handle, PAM_ESTABLISH_CRED); if (pam_rv != PAM_SUCCESS) { hardened_shadow_syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pam_handle, pam_rv)); goto pam_cleanup; } pam_rv = pam_open_session(pam_handle, 0); if (pam_rv != PAM_SUCCESS) { hardened_shadow_syslog(LOG_ERR, "pam_open_session: %s", pam_strerror(pam_handle, pam_rv)); goto pam_cred_cleanup; } char **pam_env = pam_getenvlist(pam_handle); if (!pam_env) errx(EXIT_FAILURE, "pam_getenvlist returned NULL"); struct environment_options environment_options = { .pam_environment = pam_env, .preserve_environment = preserve_environment, .login_shell = login_shell, .target_username = target_username, .target_homedir = target_homedir, .target_shell = shell, }; if (!hardened_shadow_prepare_environment(&environment_options)) { pam_rv = PAM_ABORT; goto pam_session_cleanup; } if (setuid(target_uid) != 0) { hardened_shadow_syslog(LOG_ERR, "bad user ID `%d' for user `%s': %s", target_uid, target_username, strerror(errno)); goto pam_session_cleanup; } int shell_argc = command ? 4 : 2; char **shell_argv = calloc(shell_argc, sizeof(*shell_argv)); if (!shell_argv) { hardened_shadow_syslog(LOG_ERR, "memory allocation failure"); goto pam_session_cleanup; } /* When argv[0] starts with a dash ("-"), bash will recognize * it as a login shell. This is what shadow-utils does. */ shell_argv[0] = login_shell ? "-su" : shell; if (command) { shell_argv[1] = "-c"; shell_argv[2] = command; } shell_argv[shell_argc - 1] = NULL; int status; if (!run_shell(shell, shell_argv, &status)) { pam_rv = PAM_ABORT; goto pam_session_cleanup; } free(shell_argv); pam_rv = pam_setcred(pam_handle, PAM_DELETE_CRED); if (pam_rv != PAM_SUCCESS) { hardened_shadow_syslog(LOG_ERR, "pam_setcred: %s", pam_strerror(pam_handle, pam_rv)); pam_close_session(pam_handle, 0); pam_end(pam_handle, pam_rv); errx(EXIT_FAILURE, "pam_setcred"); } pam_rv = pam_close_session(pam_handle, 0); if (pam_rv != PAM_SUCCESS) { hardened_shadow_syslog(LOG_ERR, "pam_close_session: %s", pam_strerror(pam_handle, pam_rv)); pam_end(pam_handle, pam_rv); errx(EXIT_FAILURE, "pam_close_session"); } pam_end(pam_handle, pam_rv); free(shell); free(current_username); free(target_username); free(target_homedir); hardened_shadow_closelog(); if (WIFEXITED(status)) return WEXITSTATUS(status); return WTERMSIG(status) + 128; pam_session_cleanup: pam_close_session(pam_handle, 0); pam_cred_cleanup: pam_setcred(pam_handle, PAM_DELETE_CRED); pam_cleanup: pam_end(pam_handle, pam_rv); su_fatal(); }
/** * Switch the process's effective and real user IDs to the ID associated with * the specified user name. Also switches to that user's group ID to the * primary group associated with the user. * * This function calls die() if anything fails. * * Parameters: * user_name - name of user to which to switch * uid - current process user ID * pid_file - if non-NULL, specifies PID file path, ownership of which * should be changed to the user */ static void switch_user(const char *user_name, uid_t uid, const char *pid_file) { struct passwd *pw; #if WITH_PAM int pamret; pam_handle_t *pamh; const char *pamuser; const char *failed_msg; struct passwd pwdstruct; char pwdbuf[256]; #endif /* WITH_PAM */ if (uid != 0) die("Must be root to specify a different user.\n"); if ( (pw = getpwnam(user_name)) == NULL ) die("Can't find user \"%s\" in password file.\n", user_name); #if WITH_PAM pamret = pam_start("daemonize", user, &conv, &pamh); if (pamret != PAM_SUCCESS) { syslog(LOG_WARNING, "pam_%s call failed: %s (%d)", "start", pam_strerror(pamh, pamret), pamret); } pamret = pam_authenticate(pamh, 0); if (pamret != PAM_SUCCESS) { syslog(LOG_WARNING, "pam_%s call failed: %s (%d)", "authenticate", pam_strerror(pamh, pamret), pamret); } /* check that the account is healthy */ pamret = pam_acct_mgmt(pamh, 0); if (pamret != PAM_SUCCESS) { syslog(LOG_WARNING, "pam_%s call failed: %s (%d)", "acct_mgmt", pam_strerror(pamh, pamret), pamret); } pamret = pam_open_session(pamh, 0); if (pamret != PAM_SUCCESS) { syslog(LOG_WARNING, "pam_%s call failed: %s (%d)", "open_session", pam_strerror(pamh, pamret), pamret); } if (pamret == PAM_SUCCESS) { /* success */ syslog(LOG_INFO, "pam_limits call success: %s (%d)", pam_strerror(pamh, pamret), pamret); } #endif /* WITH_PAM */ if (setgid(pw->pw_gid) != 0) die("Can't set gid to %d: %s\n", pw->pw_gid, strerror (errno)); /* For systems supporting multiple group memberships, make sure ALL groups are added to the process, just in case someone depends on them. Patch by Ken Farnen <*****@*****.**>, 18 February 2010. Modified to put the #ifdef in the config.h header, rather than in here. */ if (initgroups(pw->pw_name, pw->pw_gid) == -1) die("Can't initialize secondary groups for \"%s\": %s\n", pw->pw_name, strerror (errno)); if (pid_file != NULL) { verbose("Changing ownership of PID file to \"%s\" (%d)\n", user, pw->pw_uid); if (chown(pid_file, pw->pw_uid, pw->pw_gid) == -1) { die("Can't change owner of PID file \"%s\" to \"%s\" (%d): %s\n", pid_file, user, pw->pw_uid, strerror (errno)); } } if (setegid(pw->pw_gid) != 0) die("Can't set egid to %d: %s\n", pw->pw_gid, strerror (errno)); if (setuid(pw->pw_uid) != 0) die("Can't set uid to %d: %s\n", pw->pw_uid, strerror (errno)); if (seteuid(pw->pw_uid) != 0) die("Can't set euid to %d: %s\n", pw->pw_uid, strerror (errno)); /* Initialize environment to match new username. Patch by Ken Farnen <*****@*****.**>, 18 February 2010. */ setenv("USER", pw->pw_name,1); setenv("LOGNAME", pw->pw_name,1); setenv("HOME", pw->pw_dir,1); }
static Bool StartClient ( struct verify_info *verify, struct display *d, int *pidp, char *name, char *passwd) { char **f, *home; char *failsafeArgv[2]; int pid; #ifdef HAS_SETUSERCONTEXT struct passwd* pwd; #endif #ifdef USE_PAM pam_handle_t *pamh = thepamh(); #endif if (verify->argv) { Debug ("StartSession %s: ", verify->argv[0]); for (f = verify->argv; *f; f++) Debug ("%s ", *f); Debug ("; "); } if (verify->userEnviron) { for (f = verify->userEnviron; *f; f++) Debug ("%s ", *f); Debug ("\n"); } #ifdef USE_PAM if (pamh) pam_open_session(pamh, 0); #endif switch (pid = fork ()) { case 0: CleanUpChild (); #ifdef XDMCP /* The chooser socket is not closed by CleanUpChild() */ DestroyWellKnownSockets(); #endif /* Do system-dependent login setup here */ #ifdef USE_PAM /* pass in environment variables set by libpam and modules it called */ if (pamh) { long i; char **pam_env = pam_getenvlist(pamh); for(i = 0; pam_env && pam_env[i]; i++) { verify->userEnviron = putEnv(pam_env[i], verify->userEnviron); } } #endif #ifndef AIXV3 #ifndef HAS_SETUSERCONTEXT if (setgid(verify->gid) < 0) { LogError("setgid %d (user \"%s\") failed, errno=%d\n", verify->gid, name, errno); return (0); } #if defined(BSD) && (BSD >= 199103) if (setlogin(name) < 0) { LogError("setlogin for \"%s\" failed, errno=%d", name, errno); return(0); } #endif #ifndef QNX4 if (initgroups(name, verify->gid) < 0) { LogError("initgroups for \"%s\" failed, errno=%d\n", name, errno); return (0); } #endif /* QNX4 doesn't support multi-groups, no initgroups() */ #ifdef USE_PAM if (thepamh()) { pam_setcred(thepamh(), PAM_ESTABLISH_CRED); } #endif if (setuid(verify->uid) < 0) { LogError("setuid %d (user \"%s\") failed, errno=%d\n", verify->uid, name, errno); return (0); } #else /* HAS_SETUSERCONTEXT */ /* * Set the user's credentials: uid, gid, groups, * environment variables, resource limits, and umask. */ pwd = getpwnam(name); if (pwd) { if (setusercontext(NULL, pwd, pwd->pw_uid, LOGIN_SETALL) < 0) { LogError("setusercontext for \"%s\" failed, errno=%d\n", name, errno); return (0); } endpwent(); } else { LogError("getpwnam for \"%s\" failed, errno=%d\n", name, errno); return (0); } #endif /* HAS_SETUSERCONTEXT */ #else /* AIXV3 */ /* * Set the user's credentials: uid, gid, groups, * audit classes, user limits, and umask. */ if (setpcred(name, NULL) == -1) { LogError("setpcred for \"%s\" failed, errno=%d\n", name, errno); return (0); } #endif /* AIXV3 */ /* * for user-based authorization schemes, * use the password to get the user's credentials. */ #ifdef SECURE_RPC /* do like "keylogin" program */ { char netname[MAXNETNAMELEN+1], secretkey[HEXKEYBYTES+1]; int nameret, keyret; int len; int key_set_ok = 0; nameret = getnetname (netname); Debug ("User netname: %s\n", netname); len = strlen (passwd); if (len > 8) bzero (passwd + 8, len - 8); keyret = getsecretkey(netname,secretkey,passwd); Debug ("getsecretkey returns %d, key length %d\n", keyret, strlen (secretkey)); /* is there a key, and do we have the right password? */ if (keyret == 1) { if (*secretkey) { keyret = key_setsecret(secretkey); Debug ("key_setsecret returns %d\n", keyret); if (keyret == -1) LogError ("failed to set NIS secret key\n"); else key_set_ok = 1; } else { /* found a key, but couldn't interpret it */ LogError ("password incorrect for NIS principal \"%s\"\n", nameret ? netname : name); } } if (!key_set_ok) { /* remove SUN-DES-1 from authorizations list */ int i, j; for (i = 0; i < d->authNum; i++) { if (d->authorizations[i]->name_length == 9 && memcmp(d->authorizations[i]->name, "SUN-DES-1", 9) == 0) { for (j = i+1; j < d->authNum; j++) d->authorizations[j-1] = d->authorizations[j]; d->authNum--; break; } } } bzero(secretkey, strlen(secretkey)); } #endif #ifdef K5AUTH /* do like "kinit" program */ { int i, j; int result; extern char *Krb5CCacheName(); result = Krb5Init(name, passwd, d); if (result == 0) { /* point session clients at the Kerberos credentials cache */ verify->userEnviron = setEnv(verify->userEnviron, "KRB5CCNAME", Krb5CCacheName(d->name)); } else { for (i = 0; i < d->authNum; i++) { if (d->authorizations[i]->name_length == 14 && memcmp(d->authorizations[i]->name, "MIT-KERBEROS-5", 14) == 0) { /* remove Kerberos from authorizations list */ for (j = i+1; j < d->authNum; j++) d->authorizations[j-1] = d->authorizations[j]; d->authNum--; break; } } } } #endif /* K5AUTH */ bzero(passwd, strlen(passwd)); SetUserAuthorization (d, verify); home = getEnv (verify->userEnviron, "HOME"); if (home) if (chdir (home) == -1) { LogError ("user \"%s\": cannot chdir to home \"%s\" (err %d), using \"/\"\n", getEnv (verify->userEnviron, "USER"), home, errno); chdir ("/"); verify->userEnviron = setEnv(verify->userEnviron, "HOME", "/"); } if (verify->argv) { Debug ("executing session %s\n", verify->argv[0]); execute (verify->argv, verify->userEnviron); LogError ("Session \"%s\" execution failed (err %d)\n", verify->argv[0], errno); } else { LogError ("Session has no command/arguments\n"); } failsafeArgv[0] = d->failsafeClient; failsafeArgv[1] = 0; execute (failsafeArgv, verify->userEnviron); exit (1); case -1: bzero(passwd, strlen(passwd)); Debug ("StartSession, fork failed\n"); LogError ("can't start session on \"%s\", fork failed, errno=%d\n", d->name, errno); return 0; default: bzero(passwd, strlen(passwd)); Debug ("StartSession, fork succeeded %d\n", pid); *pidp = pid; return 1; } }