static void set_tkt_string(uid_t uid) { char buf[128]; snprintf(buf, sizeof(buf), "%s%u", TKT_ROOT, (unsigned)uid); krb_set_tkt_string(buf); #if 0 /* pam_set_data+pam_get_data are not guaranteed to work, grr. */ pam_set_data(pamh, "KRBTKFILE", strdup(t), cleanup); if (pam_get_data(pamh, "KRBTKFILE", (const void**)&tkt) == PAM_SUCCESS) { pam_putenv(pamh, var); } #endif /* We don't want to inherit this variable. * If we still do, it must have a sane value. */ if (getenv("KRBTKFILE") != 0) { char *var = malloc(sizeof(buf)); snprintf(var, sizeof(buf), "KRBTKFILE=%s", tkt_string()); putenv(var); /* free(var); XXX */ } }
static void test_pam_env_functions(void **state) { int rv; const char *v; char **vlist; struct pwrap_test_ctx *test_ctx; test_ctx = (struct pwrap_test_ctx *) *state; rv = pam_putenv(test_ctx->ph, "KEY=value"); assert_int_equal(rv, PAM_SUCCESS); rv = pam_putenv(test_ctx->ph, "KEY2=value2"); assert_int_equal(rv, PAM_SUCCESS); v = pam_getenv(test_ctx->ph, "KEY"); assert_non_null(v); assert_string_equal(v, "value"); v = pam_getenv(test_ctx->ph, "KEY2"); assert_non_null(v); assert_string_equal(v, "value2"); vlist = pam_getenvlist(test_ctx->ph); assert_non_null(vlist); assert_non_null(vlist[0]); assert_string_equal(vlist[0], "KEY=value"); assert_non_null(vlist[1]); assert_string_equal(vlist[1], "KEY2=value2"); assert_null(vlist[2]); free_vlist(vlist); rv = pam_putenv(test_ctx->ph, "KEY2="); assert_int_equal(rv, PAM_SUCCESS); vlist = pam_getenvlist(test_ctx->ph); assert_non_null(vlist); assert_non_null(vlist[0]); assert_string_equal(vlist[0], "KEY=value"); assert_non_null(vlist[1]); assert_string_equal(vlist[1], "KEY2="); assert_null(vlist[2]); free_vlist(vlist); #ifndef HAVE_OPENPAM /* OpenPAM does not support this feature */ rv = pam_putenv(test_ctx->ph, "KEY2"); assert_int_equal(rv, PAM_SUCCESS); vlist = pam_getenvlist(test_ctx->ph); assert_non_null(vlist); assert_non_null(vlist[0]); assert_string_equal(vlist[0], "KEY=value"); assert_null(vlist[1]); free_vlist(vlist); #endif }
// This method is the method that execute the authentication procedure int authenticate() { pam_handle_t *pamh = NULL; int retval = 0; int ritorno = 1; char path_script[1024]; // The service to be authenticated against is defined by *service retval = pam_start(service, username, &conv, &pamh); if (retval != PAM_SUCCESS) { return 1; } // Call the addmessage.pl script that adds a message to the spool of the sms daemon sprintf(path_script, "PATH_ADD_MSG=%s/addmessage.pl", PATH_SCRIPT); retval = pam_putenv(pamh, path_script); if (retval != PAM_SUCCESS) { return 1; } // Execute the real authentication retval = pam_authenticate(pamh, 0); if (retval == PAM_SUCCESS) { ritorno = 0; } if (pam_end(pamh, retval) != PAM_SUCCESS) pamh = NULL; return ritorno; }
int pam_setenv(pam_handle_t *pamh, const char *name, const char *value, int overwrite) { char *env; int r; ENTER(); if (pamh == NULL) RETURNC(PAM_SYSTEM_ERR); /* sanity checks */ if (name == NULL || value == NULL || strchr(name, '=') != NULL) RETURNC(PAM_SYSTEM_ERR); /* is it already there? */ if (!overwrite && openpam_findenv(pamh, name, strlen(name)) >= 0) RETURNC(PAM_SUCCESS); /* set it... */ if (asprintf(&env, "%s=%s", name, value) < 0) RETURNC(PAM_BUF_ERR); r = pam_putenv(pamh, env); FREE(env); RETURNC(r); }
static void transfer_pam_env (pam_handle_t *pamh, ...) { const char *name; const char *value; char *nameval; va_list va; va_start (va, pamh); for (;;) { name = va_arg (va, const char *); if (!name) break; value = getenv (name); if (value) { if (asprintf (&nameval, "%s=%s", name, value) < 0) errx (42, "couldn't allocate environment"); pam_putenv (pamh, nameval); } } va_end (va); }
static void modify_environment_putenv (pam_handle_t *pam_handle, poldi_ctx_t ctx, const char *name, const char *value) { char *str; int ret; str = NULL; ret = asprintf (&str, "%s=%s", name, value); if (ret < 0) { log_msg_error (ctx->loghandle, _("asprintf() failed in modify_environment_putenv(): %s"), errno); return; } ret = pam_putenv (pam_handle, str); if (ret != PAM_SUCCESS) { log_msg_error (ctx->loghandle, _("pam_putenv() failed in modify_environment_putenv(): %s"), pam_strerror (pam_handle, ret)); } free (str); }
static int setup_environment (char *line, void *arg) { pam_handle_t *ph = (pam_handle_t*)arg; char *x; int ret; /* * Called for each stdout output line from the daemon * presumably environment variables. */ assert (line); assert (arg); /* Make sure it is in fact an environment variable */ if (!strchr (line, '=')) return PAM_SUCCESS; line = strbtrim (line); ret = pam_putenv (ph, line); /* If it's the PID line then we're interested in it */ if (strncmp (line, ENV_PID, strlen (ENV_PID)) == 0) { x = line + strlen (ENV_PID); if (x[0] == '=') pam_set_data (ph, "gkr-pam-pid", strdup (x + 1), cleanup_free); } return ret; }
/** * create a key value pair from the given key and value string */ static void set_to_pam_env(pam_handle_t *pamh, ngx_http_request_t *r, char *key, char *value) { if (key != NULL && value != NULL) { size_t size = strlen(key) + strlen(value) + 1 * sizeof(char); char *key_value_pair = ngx_palloc(r->pool, size); sprintf(key_value_pair, "%s=%s", key, value); pam_putenv(pamh, key_value_pair); } }
/* Import regular and PAM environment from subprocess */ static void import_environments(struct sshbuf *b) { char *env; u_int n, i, num_env; int r; debug3("PAM: %s entering", __func__); #ifndef UNSUPPORTED_POSIX_THREADS_HACK /* Import variables set by do_pam_account */ if ((r = sshbuf_get_u32(b, &n)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (n > INT_MAX) fatal("%s: invalid PAM account status %u", __func__, n); sshpam_account_status = (int)n; if ((r = sshbuf_get_u32(b, &n)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); sshpam_password_change_required(n != 0); /* Import environment from subprocess */ if ((r = sshbuf_get_u32(b, &num_env)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); if (num_env > 1024) fatal("%s: received %u environment variables, expected <= 1024", __func__, num_env); sshpam_env = xcalloc(num_env + 1, sizeof(*sshpam_env)); debug3("PAM: num env strings %d", num_env); for(i = 0; i < num_env; i++) { if ((r = sshbuf_get_cstring(b, &(sshpam_env[i]), NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); } sshpam_env[num_env] = NULL; /* Import PAM environment from subprocess */ if ((r = sshbuf_get_u32(b, &num_env)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); debug("PAM: num PAM env strings %d", num_env); for (i = 0; i < num_env; i++) { if ((r = sshbuf_get_cstring(b, &env, NULL)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); #ifdef HAVE_PAM_PUTENV /* Errors are not fatal here */ if ((r = pam_putenv(sshpam_handle, env)) != PAM_SUCCESS) { error("PAM: pam_putenv: %s", pam_strerror(sshpam_handle, r)); } #endif /* XXX leak env? */ } #endif }
static _printf_(2, 3) int pam_setenv(pam_handle_t *ph, const char *fmt, ...) { va_list ap; int nbytes; _cleanup_free_ char *line = NULL; va_start(ap, fmt); nbytes = vasprintf(&line, fmt, ap); va_end(ap); if (nbytes < 0) return -1; pam_putenv(ph, line); return 0; }
static int __attribute__((format (printf, 2, 3))) pam_setenv(pam_handle_t *ph, const char *fmt, ...) { va_list ap; int nbytes; char *line = NULL; va_start(ap, fmt); nbytes = vasprintf(&line, fmt, ap); va_end(ap); if (nbytes < 0) return -1; pam_putenv(ph, line); free(line); return 0; }
void Authenticator::delenv(const std::string& key) { switch((last_result=pam_putenv(pam_handle, key.c_str()))) { default: case PAM_PERM_DENIED: case PAM_ABORT: case PAM_BUF_ERR: #ifdef __LIBPAM_VERSION case PAM_BAD_ITEM: #endif _end(); throw Exception(pam_handle, "pam_putenv()", last_result); case PAM_SUCCESS: break; }; return; }
void ssh_gssapi_rekey_creds() { int ok; int ret; #ifdef USE_PAM pam_handle_t *pamh = NULL; struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; char *envstr; #endif if (gssapi_client.store.filename == NULL && gssapi_client.store.envval == NULL && gssapi_client.store.envvar == NULL) return; ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); if (!ok) return; debug("Rekeyed credentials stored successfully"); /* Actually managing to play with the ssh pam stack from here will * be next to impossible. In any case, we may want different options * for rekeying. So, use our own :) */ #ifdef USE_PAM if (!use_privsep) { debug("Not even going to try and do PAM with privsep disabled"); return; } ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name, &pamconv, &pamh); if (ret) return; xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, gssapi_client.store.envval); ret = pam_putenv(pamh, envstr); if (!ret) pam_setcred(pamh, PAM_REINITIALIZE_CRED); pam_end(pamh, PAM_SUCCESS); #endif }
/* * Set a PAM environment string. We need to do this so that the session * modules can handle things like Kerberos/GSI credentials that appear * during the ssh authentication process. */ int do_pam_putenv(char *name, char *value) { int ret = 1; #ifdef HAVE_PAM_PUTENV char *compound; size_t len; len = strlen(name) + strlen(value) + 2; compound = xmalloc(len); snprintf(compound, len, "%s=%s", name, value); ret = pam_putenv(sshpam_handle, compound); free(compound); #endif return (ret); }
static int set_env(pam_handle_t *pamh, const char *name, const char *value) { if (setenv(name, value, 1) < 0) { pam_syslog(pamh, LOG_WARNING, "pam_kwallet: Couldn't setenv %s = %s", name, value); //We do not return because pam_putenv might work } char *pamEnv = malloc(strlen(name) + strlen(value) + 2); //2 is for = and \0 if (!pamEnv) { pam_syslog(pamh, LOG_WARNING, "pam_kwallet: Impossible to allocate memory for pamEnv"); return -1; } sprintf (pamEnv, "%s=%s", name, value); int ret = pam_putenv(pamh, pamEnv); free(pamEnv); return ret; }
/** * EscalateUtilPamEnvFromVariant: * @pamh: PAM handle where environment variables should be written. * @iter: Iterator over environment key/value pairs to write. * @error: (out)(allow-none): Error return location or #NULL. * * Returns: #TRUE if all variables from @iter were written to @pamh. */ gboolean EscalateUtilPamEnvFromVariant(pam_handle_t *pamh, GVariantIter *iter, GError **error) { const gchar *key = NULL; const gchar *value = NULL; gboolean result = TRUE; while (result && g_variant_iter_next(iter, "{&s&s}", &key, &value)) { gchar *key_and_value = g_strjoin("=", key, value, NULL); int pam_result = pam_putenv(pamh, key_and_value); if (pam_result != PAM_SUCCESS) { g_set_error(error, ESCALATE_UTIL_ERROR, ESCALATE_UTIL_ERROR_ENVIRONMENT, "Failed to set environment variable '%s'", key_and_value); result = FALSE; } g_free(key_and_value); } return result; }
/* * set_ccname() * * set KRB5CCNAME shell var */ static void set_ccname( pam_handle_t *pamh, krb5_module_data_t *kmd, int login_result, int debug) { int result; if (debug) syslog(LOG_DEBUG, "PAM-KRB5 (password): password: finalize" " ccname env, login_result =%d, env ='%s'", login_result, kmd->env ? kmd->env : "<null>"); if (kmd->env) { if (login_result == PAM_SUCCESS) { /* * Put ccname into the pamh so that login * apps can pick this up when they run * pam_getenvlist(). */ if ((result = pam_putenv(pamh, kmd->env)) != PAM_SUCCESS) { /* should not happen but... */ syslog(LOG_ERR, dgettext(TEXT_DOMAIN, "PAM-KRB5 (password):" " pam_putenv failed: result: %d"), result); goto cleanupccname; } } else { cleanupccname: /* for lack of a Solaris unputenv() */ krb5_unsetenv(KRB5_ENV_CCNAME); free(kmd->env); kmd->env = NULL; } } }
/* Import regular and PAM environment from subprocess */ static void import_environments(Buffer *b) { char *env; u_int i, num_env; int err; debug3("PAM: %s entering", __func__); #ifndef UNSUPPORTED_POSIX_THREADS_HACK /* Import variables set by do_pam_account */ sshpam_account_status = buffer_get_int(b); sshpam_password_change_required(buffer_get_int(b)); /* Import environment from subprocess */ num_env = buffer_get_int(b); if (num_env > 1024) fatal("%s: received %u environment variables, expected <= 1024", __func__, num_env); sshpam_env = xcalloc(num_env + 1, sizeof(*sshpam_env)); debug3("PAM: num env strings %d", num_env); for(i = 0; i < num_env; i++) sshpam_env[i] = buffer_get_string(b, NULL); sshpam_env[num_env] = NULL; /* Import PAM environment from subprocess */ num_env = buffer_get_int(b); debug("PAM: num PAM env strings %d", num_env); for(i = 0; i < num_env; i++) { env = buffer_get_string(b, NULL); #ifdef HAVE_PAM_PUTENV /* Errors are not fatal here */ if ((err = pam_putenv(sshpam_handle, env)) != PAM_SUCCESS) { error("PAM: pam_putenv: %s", pam_strerror(sshpam_handle, sshpam_err)); } #endif } #endif }
static int setup_pam_env (pam_handle_t *ph, const char *name, const char *val) { int ret; char *var; assert (name); assert (val); var = malloc (strlen (name) + strlen (val) + 2); if (!var) { syslog (GKR_LOG_ERR, "gkr-pam: out of memory"); return PAM_SYSTEM_ERR; } sprintf (var, "%s=%s", name, val); ret = pam_putenv (ph, var); free (var); return ret; }
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; }
/* * Put the ticket cache information into the environment. Takes the path and * the environment variable to set, since this is used both for the permanent * cache (KRB5CCNAME) and the temporary cache (PAM_KRB5CCNAME). Returns a PAM * status code. */ int pamk5_set_krb5ccname(struct pam_args *args, const char *name, const char *key) { char *env_name = NULL; int pamret; if (asprintf(&env_name, "%s=%s", key, name) < 0) { putil_crit(args, "asprintf failed: %s", strerror(errno)); pamret = PAM_BUF_ERR; goto done; } pamret = pam_putenv(args->pamh, env_name); if (pamret != PAM_SUCCESS) { putil_err_pam(args, pamret, "pam_putenv failed"); pamret = PAM_SERVICE_ERR; goto done; } pamret = PAM_SUCCESS; done: if (env_name != NULL) free(env_name); return pamret; }
/* authenticates user on remote TACACS+ server * returns PAM_SUCCESS if the supplied username and password * pair is valid */ PAM_EXTERN int pam_sm_authenticate (pam_handle_t * pamh, int flags, int argc, const char **argv) { int ctrl, retval; char *user; char *pass; char *tty; char *r_addr; int srv_i; int tac_fd, status, msg, communicating; user = pass = tty = r_addr = NULL; ctrl = _pam_parse(argc, argv); if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)", __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT); if ((user = _pam_get_user(pamh)) == NULL) return PAM_USER_UNKNOWN; if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "%s: user [%s] obtained", __FUNCTION__, user); // read config file _read_config(ctrl); retval = tacacs_get_password (pamh, flags, ctrl, &pass); if (retval != PAM_SUCCESS || pass == NULL || *pass == '\0') { _pam_log(LOG_ERR, "unable to obtain password"); xfree(pass); return PAM_CRED_INSUFFICIENT; } retval = pam_set_item (pamh, PAM_AUTHTOK, pass); if (retval != PAM_SUCCESS) { _pam_log(LOG_ERR, "unable to set password"); xfree(pass); return PAM_CRED_INSUFFICIENT; } if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "%s: password obtained", __FUNCTION__); tty = _pam_get_terminal(pamh); if (!strncmp(tty, "/dev/", 5)) tty += 5; if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "%s: tty [%s] obtained", __FUNCTION__, tty); r_addr = _pam_get_rhost(pamh); if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "%s: rhost [%s] obtained", __FUNCTION__, r_addr); status = PAM_AUTHINFO_UNAVAIL; for (srv_i = 0; srv_i < tac_srv_no; srv_i++) { if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "%s: trying srv %d", __FUNCTION__, srv_i ); tac_fd = tac_connect_single(tac_srv[srv_i].addr, tac_srv[srv_i].key, NULL, tac_timeout); if (tac_fd < 0) { _pam_log(LOG_ERR, "connection failed srv %d: %m", srv_i); continue; } if (tac_authen_send(tac_fd, user, pass, tty, r_addr, TAC_PLUS_AUTHEN_LOGIN) < 0) { close(tac_fd); _pam_log(LOG_ERR, "error sending auth req to TACACS+ server"); continue; } communicating = 1; while (communicating) { struct areply re = { .attr = NULL, .msg = NULL, status = 0, flags = 0 }; struct pam_message conv_msg = { .msg_style = 0, .msg = NULL }; struct pam_response *resp = NULL; msg = tac_authen_read(tac_fd, &re); if (NULL != re.msg) { conv_msg.msg = re.msg; } /* talk the protocol */ switch (msg) { case TAC_PLUS_AUTHEN_STATUS_PASS: /* success */ if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_PASS"); if (NULL != conv_msg.msg) { int retval = -1; conv_msg.msg_style = PAM_TEXT_INFO; retval = converse(pamh, 1, &conv_msg, &resp); if (PAM_SUCCESS == retval) { if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG)) syslog(LOG_DEBUG, "send msg=\"%s\"", conv_msg.msg); } else { _pam_log(LOG_WARNING, "%s: error sending msg=\"%s\", retval=%d", __FUNCTION__, conv_msg.msg, retval); } } status = PAM_SUCCESS; communicating = 0; if (active_server.addr != NULL) { xfree(active_server.addr); } active_server.addr = (struct addrinfo*)xcalloc(1, sizeof(struct addrinfo)); bcopy(tac_srv[srv_i].addr, active_server.addr, sizeof(struct addrinfo)); if (active_server.key != NULL) { xfree(active_server.key); } active_server.key = xstrdup(tac_srv[srv_i].key); if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "%s: active srv %d", __FUNCTION__, srv_i); break; case TAC_PLUS_AUTHEN_STATUS_FAIL: if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_FAIL"); if (NULL != conv_msg.msg) { int retval = -1; conv_msg.msg_style = PAM_ERROR_MSG; retval = converse(pamh, 1, &conv_msg, &resp); if (PAM_SUCCESS == retval) { if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG)) syslog(LOG_DEBUG, "send msg=\"%s\"", conv_msg.msg); } else { _pam_log(LOG_WARNING, "%s: error sending msg=\"%s\", retval=%d", __FUNCTION__, conv_msg.msg, retval); } } status = PAM_AUTH_ERR; communicating = 0; _pam_log(LOG_ERR, "auth failed: %d", msg); break; case TAC_PLUS_AUTHEN_STATUS_GETDATA: if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG)) syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETDATA"); if (NULL != conv_msg.msg) { int retval = -1; int echo_off = (0x1 == (re.flags & 0x1)); conv_msg.msg_style = echo_off ? PAM_PROMPT_ECHO_OFF : PAM_PROMPT_ECHO_ON; retval = converse(pamh, 1, &conv_msg, &resp); if (PAM_SUCCESS == retval) { if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG)) syslog(LOG_DEBUG, "sent msg=\"%s\", resp=\"%s\"", conv_msg.msg, resp->resp); if (PAM_TAC_DEBUG == (ctrl & PAM_TAC_DEBUG)) syslog(LOG_DEBUG, "%s: calling tac_cont_send", __FUNCTION__); if (0 > tac_cont_send_seq(tac_fd, resp->resp, re.seq_no + 1)) { _pam_log(LOG_ERR, "error sending continue req to TACACS+ server"); status = PAM_AUTH_ERR; communicating = 0; } } else { _pam_log(LOG_WARNING, "%s: error sending msg=\"%s\", retval=%d (%s)", __FUNCTION__, conv_msg.msg, retval, pam_strerror(pamh, retval)); status = PAM_AUTH_ERR; communicating = 0; } } else { syslog(LOG_ERR, "GETDATA response with no message, returning PAM_AUTH_ERR"); status = PAM_AUTH_ERR; communicating = 0; } break; case TAC_PLUS_AUTHEN_STATUS_GETUSER: /* not implemented */ if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETUSER"); communicating = 0; break; case TAC_PLUS_AUTHEN_STATUS_GETPASS: if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_GETPASS"); if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "%s: tac_cont_send called", __FUNCTION__); if (tac_cont_send(tac_fd, pass) < 0) { _pam_log (LOG_ERR, "error sending continue req to TACACS+ server"); communicating = 0; } /* continue the while loop; go read tac response */ break; case TAC_PLUS_AUTHEN_STATUS_RESTART: /* try it again */ if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_RESTART"); /* * not implemented * WdJ: I *think* you can just do tac_authen_send(user, pass) again * but I'm not sure */ communicating = 0; break; case TAC_PLUS_AUTHEN_STATUS_ERROR: /* server has problems */ if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_ERROR"); communicating = 0; break; case TAC_PLUS_AUTHEN_STATUS_FOLLOW: /* server tells to try a different server address */ /* not implemented */ if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "tacacs status: TAC_PLUS_AUTHEN_STATUS_FOLLOW"); communicating = 0; break; default: if (msg < 0) { /* connection error */ communicating = 0; if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "error communicating with tacacs server"); break; } /* unknown response code */ communicating = 0; if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "tacacs status: unknown response 0x%02x", msg); } if (NULL != resp) { if (resp->resp != NULL) { xfree(resp->resp); } xfree(resp); } if (re.msg != NULL) { xfree(re.msg); } } /* end while(communicating) */ close(tac_fd); if (status == PAM_SUCCESS || status == PAM_AUTH_ERR) break; } if (status != PAM_SUCCESS && status != PAM_AUTH_ERR) _pam_log(LOG_ERR, "no more servers to connect"); if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "%s: exit with pam status: %d", __FUNCTION__, status); if (NULL != pass) { bzero(pass, strlen (pass)); xfree(pass); pass = NULL; } return status; } /* pam_sm_authenticate */ /* no-op function to satisfy PAM authentication module */ PAM_EXTERN int pam_sm_setcred (pam_handle_t * pamh, int flags, int argc, const char **argv) { int ctrl = _pam_parse (argc, argv); if (ctrl & PAM_TAC_DEBUG) syslog (LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)" , __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT); return PAM_SUCCESS; } /* pam_sm_setcred */ /* authorizes user on remote TACACS+ server, i.e. checks * his permission to access requested service * returns PAM_SUCCESS if the service is allowed */ PAM_EXTERN int pam_sm_acct_mgmt (pam_handle_t * pamh, int flags, int argc, const char **argv) { int retval, ctrl, status=PAM_AUTH_ERR; char *user; char *tty; char *r_addr; struct areply arep; struct tac_attrib *attr = NULL; int tac_fd; user = tty = r_addr = NULL; memset(&arep, 0, sizeof(arep)); /* this also obtains service name for authorization this should be normally performed by pam_get_item(PAM_SERVICE) but since PAM service names are incompatible TACACS+ we have to pass it via command line argument until a better solution is found ;) */ ctrl = _pam_parse (argc, argv); if (ctrl & PAM_TAC_DEBUG) syslog (LOG_DEBUG, "%s: called (pam_tacplus v%u.%u.%u)" , __FUNCTION__, PAM_TAC_VMAJ, PAM_TAC_VMIN, PAM_TAC_VPAT); if ((user = _pam_get_user(pamh)) == NULL) return PAM_USER_UNKNOWN; if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "%s: username obtained [%s]", __FUNCTION__, user); // read config file _read_config(ctrl); tty = _pam_get_terminal(pamh); if(!strncmp(tty, "/dev/", 5)) tty += 5; if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "%s: tty obtained [%s]", __FUNCTION__, tty); r_addr = _pam_get_rhost(pamh); if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "%s: rhost obtained [%s]", __FUNCTION__, r_addr); /* checks if user has been successfully authenticated by TACACS+; we cannot solely authorize user if it hasn't been authenticated or has been authenticated by method other than TACACS+ */ if(active_server.addr == NULL) { _pam_log (LOG_ERR, "user not authenticated by TACACS+"); return PAM_AUTH_ERR; } if (ctrl & PAM_TAC_DEBUG) syslog (LOG_DEBUG, "%s: active server is [%s]", __FUNCTION__, tac_ntop(active_server.addr->ai_addr)); /* checks for specific data required by TACACS+, which should be supplied in command line */ if(!*tac_service) { _pam_log (LOG_ERR, "SM: TACACS+ service type not configured"); return PAM_AUTH_ERR; } if(!*tac_protocol) { _pam_log (LOG_ERR, "SM: TACACS+ protocol type not configured (IGNORED)"); } tac_add_attrib(&attr, "service", tac_service); if(tac_protocol[0] != '\0') tac_add_attrib(&attr, "protocol", tac_protocol); tac_fd = tac_connect_single(active_server.addr, active_server.key, NULL, tac_timeout); if(tac_fd < 0) { _pam_log (LOG_ERR, "TACACS+ server unavailable"); if(arep.msg != NULL) xfree (arep.msg); return PAM_AUTH_ERR; } retval = tac_author_send(tac_fd, user, tty, r_addr, attr); tac_free_attrib(&attr); if(retval < 0) { _pam_log (LOG_ERR, "error getting authorization"); if(arep.msg != NULL) xfree (arep.msg); close(tac_fd); return PAM_AUTH_ERR; } if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "%s: sent authorization request", __FUNCTION__); tac_author_read(tac_fd, &arep); if(arep.status != AUTHOR_STATUS_PASS_ADD && arep.status != AUTHOR_STATUS_PASS_REPL) { _pam_log (LOG_ERR, "TACACS+ authorisation failed for [%s]", user); if(arep.msg != NULL) xfree (arep.msg); close(tac_fd); return PAM_PERM_DENIED; } if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "%s: user [%s] successfully authorized", __FUNCTION__, user); status = PAM_SUCCESS; attr = arep.attr; while (attr != NULL) { char attribute[attr->attr_len]; char value[attr->attr_len]; char *sep; sep = index(attr->attr, '='); if(sep == NULL) sep = index(attr->attr, '*'); if(sep != NULL) { bcopy(attr->attr, attribute, attr->attr_len-strlen(sep)); attribute[attr->attr_len-strlen(sep)] = '\0'; bcopy(sep, value, strlen(sep)); value[strlen(sep)] = '\0'; size_t i; for (i = 0; attribute[i] != '\0'; i++) { attribute[i] = toupper(attribute[i]); if (attribute[i] == '-') attribute[i] = '_'; } if (ctrl & PAM_TAC_DEBUG) syslog(LOG_DEBUG, "%s: returned attribute `%s%s' from server", __FUNCTION__, attribute, value); /* make returned attributes available for other PAM modules via PAM environment */ if (pam_putenv(pamh, strncat(attribute, value, strlen(value))) != PAM_SUCCESS) syslog(LOG_WARNING, "%s: unable to set PAM environment", __FUNCTION__); } else { syslog(LOG_WARNING, "%s: invalid attribute `%s', no separator", __FUNCTION__, attr->attr); } attr = attr->next; } /* free returned attributes */ if(arep.attr != NULL) tac_free_attrib(&arep.attr); if(arep.msg != NULL) xfree (arep.msg); close(tac_fd); return status; } /* pam_sm_acct_mgmt */
int main(int argc, char **argv) { pam_handle_t *pamh=NULL; char *username=NULL; int retcode; /* did the user call with a username as an argument ? */ if (argc > 2) { fprintf(stderr,"usage: %s [username]\n",argv[0]); } else if (argc == 2) { username = argv[1]; } /* initialize the Linux-PAM library */ retcode = pam_start("blank", username, &conv, &pamh); bail_out(pamh,1,retcode,"pam_start"); /* test the environment stuff */ { #define MAXENV 15 const char *greek[MAXENV] = { "a=alpha", "b=beta", "c=gamma", "d=delta", "e=epsilon", "f=phi", "g=psi", "h=eta", "i=iota", "j=mu", "k=nu", "l=zeta", "h=", "d", "k=xi" }; char **env; int i; for (i=0; i<MAXENV; ++i) { retcode = pam_putenv(pamh,greek[i]); bail_out(pamh,0,retcode,"pam_putenv"); } env = pam_getenvlist(pamh); if (env) env = pam_misc_drop_env(env); else fprintf(stderr,"???\n"); fprintf(stderr,"a test: c=[%s], j=[%s]\n" , pam_getenv(pamh, "c"), pam_getenv(pamh, "j")); } /* to avoid using goto we abuse a loop here */ for (;;) { /* authenticate the user --- `0' here, could have been PAM_SILENT * | PAM_DISALLOW_NULL_AUTHTOK */ retcode = pam_authenticate(pamh, 0); bail_out(pamh,0,retcode,"pam_authenticate"); /* has the user proved themself valid? */ if (retcode != PAM_SUCCESS) { fprintf(stderr,"%s: invalid request\n",argv[0]); break; } /* the user is valid, but should they have access at this time? */ retcode = pam_acct_mgmt(pamh, 0); /* `0' could be as above */ bail_out(pamh,0,retcode,"pam_acct_mgmt"); if (retcode == PAM_NEW_AUTHTOK_REQD) { fprintf(stderr,"Application must request new password...\n"); retcode = pam_chauthtok(pamh,PAM_CHANGE_EXPIRED_AUTHTOK); bail_out(pamh,0,retcode,"pam_chauthtok"); } if (retcode != PAM_SUCCESS) { fprintf(stderr,"%s: invalid request\n",argv[0]); break; } /* `0' could be as above */ retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED); bail_out(pamh,0,retcode,"pam_setcred1"); if (retcode != PAM_SUCCESS) { fprintf(stderr,"%s: problem setting user credentials\n" ,argv[0]); break; } /* open a session for the user --- `0' could be PAM_SILENT */ retcode = pam_open_session(pamh,0); bail_out(pamh,0,retcode,"pam_open_session"); if (retcode != PAM_SUCCESS) { fprintf(stderr,"%s: problem opening a session\n",argv[0]); break; } fprintf(stderr,"The user has been authenticated and `logged in'\n"); /* close a session for the user --- `0' could be PAM_SILENT * it is possible that this pam_close_call is in another program.. */ retcode = pam_close_session(pamh,0); bail_out(pamh,0,retcode,"pam_close_session"); if (retcode != PAM_SUCCESS) { fprintf(stderr,"%s: problem closing a session\n",argv[0]); break; } retcode = pam_setcred(pamh, PAM_DELETE_CRED); bail_out(pamh,0,retcode,"pam_setcred2"); break; /* don't go on for ever! */ } /* close the Linux-PAM library */ retcode = pam_end(pamh, PAM_SUCCESS); pamh = NULL; bail_out(pamh,1,retcode,"pam_end"); exit(0); }
static int _do_mail(pam_handle_t *pamh, int flags, int argc, const char **argv, int est) { int retval, ctrl, hashcount; char *path_mail=NULL, *folder; const char *type; /* * this module (un)sets the MAIL environment variable, and checks if * the user has any new mail. */ ctrl = _pam_parse(flags, argc, argv, &path_mail, &hashcount); /* Do we have anything to do? */ if (flags & PAM_SILENT) return PAM_SUCCESS; /* which folder? */ retval = get_folder(pamh, ctrl, &path_mail, &folder, hashcount); if (retval != PAM_SUCCESS) { D(("failed to find folder")); return retval; } /* set the MAIL variable? */ if (!(ctrl & PAM_NO_ENV) && est) { char *tmp; tmp = malloc(strlen(folder)+sizeof(MAIL_ENV_FORMAT)); if (tmp != NULL) { sprintf(tmp, MAIL_ENV_FORMAT, folder); D(("setting env: %s", tmp)); retval = pam_putenv(pamh, tmp); _pam_overwrite(tmp); _pam_drop(tmp); if (retval != PAM_SUCCESS) { _pam_overwrite(folder); _pam_drop(folder); _log_err(LOG_CRIT, "unable to set " MAIL_ENV_NAME " variable"); return retval; } } else { _log_err(LOG_CRIT, "no memory for " MAIL_ENV_NAME " variable"); _pam_overwrite(folder); _pam_drop(folder); return retval; } } else { D(("not setting " MAIL_ENV_NAME " variable")); } /* * OK. we've got the mail folder... what about its status? */ if ((est && !(ctrl & PAM_NO_LOGIN)) || (!est && (ctrl & PAM_LOGOUT_TOO))) { type = get_mail_status(ctrl, folder); if (type != NULL) { retval = report_mail(pamh, ctrl, type, folder); type = NULL; } } /* Delete environment variable? */ if (!est) (void) pam_putenv(pamh, MAIL_ENV_NAME); _pam_overwrite(folder); /* clean up */ _pam_drop(folder); /* indicate success or failure */ return retval; }
/* Initiate session management by creating temporary file. */ int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { int i; int debug = 0; int pamret; int n; const char *user; struct passwd *pw; char mktemp_buf[MAXBUF]; char envput[MAXBUF]; const char *prefix = "/tmp/tempfile"; const char *var = NULL; int fd; int dir = 0; for (i = 0; i < argc; i++) { if (strcmp(argv[i], "debug") == 0) debug = 1; else if (strncmp(argv[i], "prefix=", 7) == 0) prefix = argv[i] + 7; else if (strncmp(argv[i], "var=", 4) == 0) var = argv[i] + 4; else if (strcmp(argv[i], "dir") == 0) dir = 1; } if (var == NULL) { syslog(LOG_ERR, "pam_mktemp: No variable to set"); return PAM_SESSION_ERR; } if ((pamret = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) { syslog(LOG_ERR, "pam_mktemp: pam_get_user: %s", pam_strerror(pamh, pamret)); return PAM_SESSION_ERR; } errno = 0; pw = getpwnam(user); if (pw == NULL) { if (errno != 0) syslog(LOG_ERR, "pam_mktemp: getpwnam: %m"); else syslog(LOG_ERR, "pam_mktemp: no such user: %s", user); return PAM_SESSION_ERR; } n = snprintf(mktemp_buf, MAXBUF, "%s-%d-XXXXXX", prefix, pw->pw_uid); if (n < 0 || n >= MAXBUF) { syslog(LOG_ERR, "pam_mktemp: snprintf failed"); return PAM_SESSION_ERR; } if (dir) { if (mkdtemp(mktemp_buf) == NULL) { syslog(LOG_ERR, "pam_mktemp: mkdtemp: %m"); return PAM_SESSION_ERR; } } else { fd = mkstemp(mktemp_buf); if (fd == -1) { syslog(LOG_ERR, "pam_mktemp: mkstemp: %m"); return PAM_SESSION_ERR; } if (close(fd) != 0) { syslog(LOG_ERR, "pam_mktemp: close: %m"); return PAM_SESSION_ERR; } } if (chown(mktemp_buf, pw->pw_uid, -1) != 0) { syslog(LOG_ERR, "pam_mktemp: chown: %m"); return PAM_SESSION_ERR; } if (debug) syslog(LOG_DEBUG, "pam_mktemp: using temporary file %s", mktemp_buf); n = snprintf(envput, MAXBUF, "%s=%s", var, mktemp_buf); if (n < 0 || n >= MAXBUF) { syslog(LOG_ERR, "pam_mktemp: snprintf failed"); return PAM_SESSION_ERR; } pamret = pam_putenv(pamh, envput); if (pamret != PAM_SUCCESS) { syslog(LOG_ERR, "pam_mktemp: pam_putenv: %s", pam_strerror(pamh, pamret)); return PAM_SESSION_ERR; } pamret = pam_set_data(pamh, var, mktemp_buf, mktemp_cleanup); if (pamret != PAM_SUCCESS) { syslog(LOG_ERR, "pam_mktemp: pam_set_data: %s", pam_strerror(pamh, pamret)); return PAM_SESSION_ERR; } return PAM_SUCCESS; }
/* Initiate session management by creating Xauthority file. */ int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv) { int i; int debug = 0; int pamret; int n; const char *user; struct passwd *pw; char xauth[MAXBUF]; char envput[MAXBUF]; const char *dir = "/tmp"; int xauth_fd; for (i = 0; i < argc; i++) { if (strcmp(argv[i], "debug") == 0) debug = 1; else if (strncmp(argv[i], "dir=", 4) == 0) dir = argv[i] + 4; } if ((pamret = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS) { syslog(LOG_ERR, "pam_athena-locker: pam_get_user: %s", pam_strerror(pamh, pamret)); return PAM_SESSION_ERR; } errno = 0; pw = getpwnam(user); if (pw == NULL) { if (errno != 0) syslog(LOG_ERR, "pam_xauthority: getpwnam: %s", strerror(errno)); else syslog(LOG_ERR, "pam_xauthority: no such user: %s", user); return PAM_SESSION_ERR; } n = snprintf(xauth, MAXBUF, "%s/xauth-%d-XXXXXX", dir, pw->pw_uid); if (n < 0 || n >= MAXBUF) { syslog(LOG_ERR, "pam_xauthority: snprintf failed"); return PAM_SESSION_ERR; } xauth_fd = mkstemp(xauth); if (xauth_fd == -1) { syslog(LOG_ERR, "pam_xauthority: mkstemp: %s", strerror(errno)); return PAM_SESSION_ERR; } if (fchown(xauth_fd, pw->pw_uid, -1) != 0) { syslog(LOG_ERR, "pam_xauthority: fchown: %s", strerror(errno)); return PAM_SESSION_ERR; } if (close(xauth_fd) != 0) { syslog(LOG_ERR, "pam_xauthority: close: %s", strerror(errno)); return PAM_SESSION_ERR; } if (debug) syslog(LOG_DEBUG, "pam_xauthority: using Xauthority file %s", xauth); n = snprintf(envput, MAXBUF, "%s=%s", XAUTH, xauth); if (n < 0 || n >= MAXBUF) { syslog(LOG_ERR, "pam_xauthority: snprintf failed"); return PAM_SESSION_ERR; } pamret = pam_putenv(pamh, envput); if (pamret != PAM_SUCCESS) { syslog(LOG_ERR, "pam_xauthority: pam_putenv: %s", pam_strerror(pamh, pamret)); return PAM_SESSION_ERR; } pamret = pam_set_data(pamh, XAUTH, xauth, xauth_cleanup); if (pamret != PAM_SUCCESS) { syslog(LOG_ERR, "pam_xauthority: pam_set_data: %s", pam_strerror(pamh, pamret)); return PAM_SESSION_ERR; } return PAM_SUCCESS; }
int main (int argc, char *argv[]) { int retcode; int ret; pam_handle_t *pamh; char *username; char *hostname; char *tty_name; char *ttyn; struct pam_conv conv = { misc_conv, NULL }; int failcount; ret = 1; username = NULL; hostname = NULL; tty_name = NULL; retcode = pam_start ("login", username, &conv, &pamh); if (retcode != PAM_SUCCESS) { fprintf (stderr, "login: PAM Failure, aborting: %s\n", pam_strerror (pamh, retcode)); exit (99); } ttyn = ttyname (0); if (strncmp (ttyn, _PATH_DEV, 5) == 0) { tty_name = ttyn + 5; } else { tty_name = ttyn; } retcode = pam_set_item (pamh, PAM_RHOST, hostname); PAM_FAIL_CHECK; retcode = pam_set_item (pamh, PAM_TTY, tty_name); PAM_FAIL_CHECK; pam_set_item (pamh, PAM_USER, NULL); retcode = pam_set_item (pamh, PAM_USER_PROMPT, "Username: "******"Login incorrect\n\n"); pam_set_item (pamh, PAM_USER, NULL); retcode = pam_authenticate (pamh, 0); } if (retcode != PAM_SUCCESS) { fprintf (stderr, "\nLogin incorrect\n"); pam_end (pamh, retcode); exit (0); } retcode = pam_acct_mgmt (pamh, 0); if (retcode == PAM_NEW_AUTHTOK_REQD) { retcode = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK); } PAM_FAIL_CHECK; pam_putenv (pamh, "CKCON_TTY=/dev/tty55"); pam_putenv (pamh, "CKCON_X11_DISPLAY=:50"); retcode = pam_open_session (pamh, 0); PAM_FAIL_CHECK; retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED); PAM_FAIL_CHECK; pam_get_item (pamh, PAM_USER, (const void **) &username); printf ("Session opened for %s\n", username); printf ("sleeping for 20 seconds..."); sleep (20); PAM_END; printf ("\nSession closed\n"); return ret; }
int main(void) { pam_handle_t *pamh; struct pam_conv conv = { NULL, NULL }; char **env; size_t i; /* * Skip this test if the native PAM library doesn't support a PAM * environment, since we "break" pam_putenv to mirror the native behavior * in that case. */ #ifndef HAVE_PAM_GETENV skip_all("system doesn't support PAM environment"); #endif plan(33); /* Basic environment manipulation. */ if (pam_start("test", NULL, &conv, &pamh) != PAM_SUCCESS) sysbail("Fake PAM initialization failed"); is_int(PAM_BAD_ITEM, pam_putenv(pamh, "TEST"), "delete when NULL"); ok(pam_getenv(pamh, "TEST") == NULL, "getenv when NULL"); env = pam_getenvlist(pamh); ok(env != NULL, "getenvlist when NULL returns non-NULL"); is_string(NULL, env[0], "...but first element is NULL"); for (i = 0; env[i] != NULL; i++) free(env[i]); free(env); /* putenv and getenv. */ is_int(PAM_SUCCESS, pam_putenv(pamh, "TEST=foo"), "putenv TEST"); is_string("foo", pam_getenv(pamh, "TEST"), "getenv TEST"); is_int(PAM_SUCCESS, pam_putenv(pamh, "FOO=bar"), "putenv FOO"); is_int(PAM_SUCCESS, pam_putenv(pamh, "BAR=baz"), "putenv BAR"); is_string("foo", pam_getenv(pamh, "TEST"), "getenv TEST"); is_string("bar", pam_getenv(pamh, "FOO"), "getenv FOO"); is_string("baz", pam_getenv(pamh, "BAR"), "getenv BAR"); ok(pam_getenv(pamh, "BAZ") == NULL, "getenv BAZ is NULL"); /* Replacing and deleting environment variables. */ is_int(PAM_BAD_ITEM, pam_putenv(pamh, "BAZ"), "putenv nonexistent delete"); is_int(PAM_SUCCESS, pam_putenv(pamh, "FOO=foo"), "putenv replace"); is_int(PAM_SUCCESS, pam_putenv(pamh, "FOON=bar=n"), "putenv prefix"); is_string("foo", pam_getenv(pamh, "FOO"), "getenv FOO"); is_string("bar=n", pam_getenv(pamh, "FOON"), "getenv FOON"); is_int(PAM_BAD_ITEM, pam_putenv(pamh, "FO"), "putenv delete FO"); is_int(PAM_SUCCESS, pam_putenv(pamh, "FOO"), "putenv delete FOO"); ok(pam_getenv(pamh, "FOO") == NULL, "getenv FOO is NULL"); is_string("bar=n", pam_getenv(pamh, "FOON"), "getenv FOON"); is_string("baz", pam_getenv(pamh, "BAR"), "getenv BAR"); /* pam_getenvlist. */ env = pam_getenvlist(pamh); ok(env != NULL, "getenvlist not NULL"); is_string("TEST=foo", env[0], "getenvlist TEST"); is_string("BAR=baz", env[1], "getenvlist BAR"); is_string("FOON=bar=n", env[2], "getenvlist FOON"); ok(env[3] == NULL, "getenvlist length"); for (i = 0; env[i] != NULL; i++) free(env[i]); free(env); is_int(PAM_SUCCESS, pam_putenv(pamh, "FOO=foo"), "putenv FOO"); is_string("TEST=foo", pamh->environ[0], "pamh environ TEST"); is_string("BAR=baz", pamh->environ[1], "pamh environ BAR"); is_string("FOON=bar=n", pamh->environ[2], "pamh environ FOON"); is_string("FOO=foo", pamh->environ[3], "pamh environ FOO"); ok(pamh->environ[4] == NULL, "pamh environ length"); pam_end(pamh, 0); return 0; }
int pam_sm_open_session( pam_handle_t* pamh, int flags, int argc, const char** argv ) { DWORD dwError = 0; PPAMCONTEXT pPamContext = NULL; HANDLE hLsaConnection = (HANDLE)NULL; PSTR pszLoginId = NULL; PLSA_PAM_CONFIG pConfig = NULL; #ifdef HAVE_PAM_PUTENV PSTR pszSmartCardReader = NULL; PSTR pszSmartCardReaderEnv = NULL; #endif /* HAVE_PAM_PUTENV */ LSA_LOG_PAM_DEBUG("pam_sm_open_session::begin"); dwError = LsaPamGetConfig(&pConfig); BAIL_ON_LSA_ERROR(dwError); LsaPamSetLogLevel(pConfig->dwLogLevel); dwError = LsaPamGetContext( pamh, flags, argc, argv, &pPamContext); BAIL_ON_LSA_ERROR(dwError); dwError = LsaPamGetLoginId( pamh, pPamContext, &pszLoginId, TRUE); BAIL_ON_LSA_ERROR(dwError); #ifdef HAVE_PAM_PUTENV dwError = pam_get_data( pamh, PAM_LSASS_SMART_CARD_READER, (PAM_GET_DATA_TYPE)&pszSmartCardReader); /* pszSmartCardReader will be freed when the module is closed. */ if (dwError == PAM_SUCCESS && pszSmartCardReader != NULL) { dwError = LwAllocateStringPrintf( &pszSmartCardReaderEnv, "LW_SMART_CARD_READER=%s", pszSmartCardReader); BAIL_ON_LSA_ERROR(dwError); dwError = pam_putenv( pamh, pszSmartCardReaderEnv); BAIL_ON_LSA_ERROR(dwError); } #endif /* HAVE_PAM_PUTENV */ if (LsaShouldIgnoreUser(pszLoginId)) { LSA_LOG_PAM_DEBUG("By passing lsassd for local account"); dwError = LW_ERROR_NOT_HANDLED; BAIL_ON_LSA_ERROR(dwError); } dwError = LsaOpenServer(&hLsaConnection); BAIL_ON_LSA_ERROR(dwError); dwError = LsaOpenSession( hLsaConnection, pszLoginId); BAIL_ON_LSA_ERROR(dwError); if (pPamContext && pConfig->bLsaPamDisplayMOTD) { dwError = LsaPamDisplayMOTD( pamh, pPamContext); BAIL_ON_LSA_ERROR(dwError); } if (pPamContext && pPamContext->bOnlineLogon) { dwError = LsaPamNotifyUserLogon( pszLoginId); if (dwError == LW_ERROR_LOAD_LIBRARY_FAILED || dwError == LW_ERROR_LOOKUP_SYMBOL_FAILED ) { dwError = 0; } BAIL_ON_LSA_ERROR(dwError); } cleanup: if (hLsaConnection != (HANDLE)NULL) { LsaCloseServer(hLsaConnection); } if (pConfig) { LsaPamFreeConfig(pConfig); } LW_SAFE_FREE_STRING(pszLoginId); #ifdef HAVE_PAM_PUTENV LW_SAFE_FREE_STRING(pszSmartCardReaderEnv); #endif /* HAVE_PAM_PUTENV */ LSA_LOG_PAM_DEBUG("pam_sm_open_session::end"); return LsaPamOpenPamFilterOpenSession( LsaPamMapErrorCode(dwError, pPamContext)); error: if ((dwError == LW_ERROR_NO_SUCH_USER) || (dwError == LW_ERROR_NOT_HANDLED)) { LSA_LOG_PAM_WARNING("pam_sm_open_session failed [login:%s][error code: %u]", LSA_SAFE_LOG_STRING(pszLoginId), dwError); } else { LSA_LOG_PAM_ERROR("pam_sm_open_session failed [login:%s][error code: %u]", LSA_SAFE_LOG_STRING(pszLoginId), dwError); } goto cleanup; }
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv) { int i, rv; const char *user = NULL; char *password; unsigned int slot_num = 0; int is_a_screen_saver = 0; struct configuration_st *configuration; int pkcs11_pam_fail = PAM_AUTHINFO_UNAVAIL; pkcs11_handle_t *ph; cert_object_t *chosen_cert = NULL; cert_object_t **cert_list; int ncert; unsigned char random_value[128]; unsigned char *signature; unsigned long signature_length; /* enough space to hold an issuer DN */ char env_temp[256] = ""; char **issuer, **serial; const char *login_token_name = NULL; pam_prompt(pamh, PAM_TEXT_INFO , NULL, _("Smartcard authentication starts")); /* first of all check whether debugging should be enabled */ for (i = 0; i < argc; i++) if (strcmp("debug", argv[i]) == 0) { set_debug_level(1); } /* call configure routines */ configuration = pk_configure(argc,argv); if (!configuration ) { ERR("Error setting configuration parameters"); return PAM_AUTHINFO_UNAVAIL; } /* Either slot_description or slot_num, but not both, needs to be used */ if ((configuration->slot_description != NULL && configuration->slot_num != -1) || (configuration->slot_description == NULL && configuration->slot_num == -1)) { ERR("Error setting configuration parameters"); return PAM_AUTHINFO_UNAVAIL; } /* fail if we are using a remote server * local login: DISPLAY=:0 * XDMCP login: DISPLAY=host:0 */ { char *display = getenv("DISPLAY"); if (display) { if (strncmp(display, "localhost:", 10) != 0 && (display[0] != ':') && (display[0] != '\0')) { ERR1("Remote login (from %s) is not (yet) supported", display); pam_syslog(pamh, LOG_ERR, "Remote login (from %s) is not (yet) supported", display); return PAM_AUTHINFO_UNAVAIL; } } } #ifdef ENABLE_NLS setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, "/usr/share/locale"); textdomain(PACKAGE); #endif /* init openssl */ rv = crypto_init(&configuration->policy); if (rv != 0) { ERR("Failed to initialize crypto"); if (!configuration->quiet) pam_syslog(pamh,LOG_ERR, "Failed to initialize crypto"); return PAM_AUTHINFO_UNAVAIL; } /* * card_only means: * 1) always get the userid from the certificate. * 2) don't prompt for the user name if the card is present. * 3) if the token is present, then we must use the cardAuth mechanism. * * wait_for_card means: * 1) nothing if card_only isn't set * 2) if logged in, block in pam conversation until the token used for login * is inserted * 3) if not logged in, block until a token that could be used for logging in * is inserted * right now, logged in means PKC11_LOGIN_TOKEN_NAME is set, * but we could something else later (like set some per-user state in * a pam session module keyed off uid) */ if (configuration->card_only) { char *service; if (configuration->screen_savers) { DBG("Is it a screen saver?"); pam_get_item(pamh, PAM_SERVICE, &service); for (i=0; configuration->screen_savers[i]; i++) { if (strcmp(configuration->screen_savers[i], service) == 0) { is_a_screen_saver = 1; break; } } } pkcs11_pam_fail = PAM_CRED_INSUFFICIENT; /* look to see if username is already set */ pam_get_item(pamh, PAM_USER, &user); if (user) { DBG1("explicit username = [%s]", user); } } else { rv = pam_get_item(pamh, PAM_USER, &user); if (rv != PAM_SUCCESS || user == NULL || user[0] == '\0') { pam_prompt(pamh, PAM_TEXT_INFO, NULL, _("Please insert your %s or enter your username."), _(configuration->token_type)); /* get user name */ rv = pam_get_user(pamh, &user, NULL); if (rv != PAM_SUCCESS) { pam_syslog(pamh, LOG_ERR, "pam_get_user() failed %s", pam_strerror(pamh, rv)); return PAM_USER_UNKNOWN; } } DBG1("username = [%s]", user); } login_token_name = getenv("PKCS11_LOGIN_TOKEN_NAME"); /* if we are using a screen saver, and we didn't log in using the smart card * drop to the next pam module. */ if (is_a_screen_saver && !login_token_name) { return PAM_IGNORE; } /* load pkcs #11 module */ DBG("loading pkcs #11 module..."); rv = load_pkcs11_module(configuration->pkcs11_modulepath, &ph); if (rv != 0) { ERR2("load_pkcs11_module() failed loading %s: %s", configuration->pkcs11_modulepath, get_error()); if (!configuration->quiet) { pam_syslog(pamh, LOG_ERR, "load_pkcs11_module() failed loading %s: %s", configuration->pkcs11_modulepath, get_error()); pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2302: PKCS#11 module failed loading")); sleep(configuration->err_display_time); } return PAM_AUTHINFO_UNAVAIL; } /* initialise pkcs #11 module */ DBG("initialising pkcs #11 module..."); rv = init_pkcs11_module(ph,configuration->support_threads); if (rv != 0) { release_pkcs11_module(ph); ERR1("init_pkcs11_module() failed: %s", get_error()); if (!configuration->quiet) { pam_syslog(pamh, LOG_ERR, "init_pkcs11_module() failed: %s", get_error()); pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2304: PKCS#11 module could not be initialized")); sleep(configuration->err_display_time); } return PAM_AUTHINFO_UNAVAIL; } /* open pkcs #11 session */ if (configuration->slot_description != NULL) { rv = find_slot_by_slotlabel_and_tokenlabel(ph, configuration->slot_description, login_token_name, &slot_num); } else if (configuration->slot_num != -1) { rv = find_slot_by_number_and_label(ph, configuration->slot_num, login_token_name, &slot_num); } if (rv != 0) { ERR("no suitable token available"); if (!configuration->quiet) { pam_syslog(pamh, LOG_ERR, "no suitable token available"); pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2306: No suitable token available")); sleep(configuration->err_display_time); } if (!configuration->card_only) { release_pkcs11_module(ph); return PAM_AUTHINFO_UNAVAIL; } /* we must have a smart card, either because we've configured it as such, * or because we used one to log in */ if (login_token_name || configuration->wait_for_card) { if (login_token_name) { pam_prompt(pamh, PAM_TEXT_INFO, NULL, _("Please insert your smart card called \"%.32s\"."), login_token_name); } else { pam_prompt(pamh, PAM_TEXT_INFO, NULL, _("Please insert your smart card.")); } if (configuration->slot_description != NULL) { rv = wait_for_token_by_slotlabel(ph, configuration->slot_description, login_token_name, &slot_num); } else if (configuration->slot_num != -1) { rv = wait_for_token(ph, configuration->slot_num, login_token_name, &slot_num); } if (rv != 0) { release_pkcs11_module(ph); return pkcs11_pam_fail; } } else if (user) { if (!configuration->quiet) { pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2308: No smartcard found")); sleep(configuration->err_display_time); } /* we have a user and no smart card, go to the next pam module */ release_pkcs11_module(ph); return PAM_AUTHINFO_UNAVAIL; } else { /* we haven't prompted for the user yet, get the user and see if * the smart card has been inserted in the mean time */ pam_prompt(pamh, PAM_TEXT_INFO, NULL, _("Please insert your %s or enter your username."), _(configuration->token_type)); rv = pam_get_user(pamh, &user, NULL); /* check one last time for the smart card before bouncing to the next * module */ if (configuration->slot_description != NULL) { rv = find_slot_by_slotlabel(ph, configuration->slot_description, &slot_num); } else if (configuration->slot_num != -1) { rv = find_slot_by_number(ph, configuration->slot_num, &slot_num); } if (rv != 0) { /* user gave us a user id and no smart card go to next module */ if (!configuration->quiet) { pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2310: No smartcard found")); sleep(configuration->err_display_time); } release_pkcs11_module(ph); return PAM_AUTHINFO_UNAVAIL; } } } else { pam_prompt(pamh, PAM_TEXT_INFO, NULL, _("%s found."), _(configuration->token_type)); } rv = open_pkcs11_session(ph, slot_num); if (rv != 0) { ERR1("open_pkcs11_session() failed: %s", get_error()); if (!configuration->quiet) { pam_syslog(pamh, LOG_ERR, "open_pkcs11_session() failed: %s", get_error()); pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2312: open PKCS#11 session failed")); sleep(configuration->err_display_time); } release_pkcs11_module(ph); return pkcs11_pam_fail; } rv = get_slot_login_required(ph); if (rv == -1) { ERR1("get_slot_login_required() failed: %s", get_error()); if (!configuration->quiet) { pam_syslog(pamh, LOG_ERR, "get_slot_login_required() failed: %s", get_error()); pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2314: Slot login failed")); sleep(configuration->err_display_time); } release_pkcs11_module(ph); return pkcs11_pam_fail; } else if (rv) { /* get password */ pam_prompt(pamh, PAM_TEXT_INFO, NULL, _("Welcome %.32s!"), get_slot_tokenlabel(ph)); /* no CKF_PROTECTED_AUTHENTICATION_PATH */ rv = get_slot_protected_authentication_path(ph); if ((-1 == rv) || (0 == rv)) { char password_prompt[128]; snprintf(password_prompt, sizeof(password_prompt), _("%s PIN: "), _(configuration->token_type)); if (configuration->use_first_pass) { rv = pam_get_pwd(pamh, &password, NULL, PAM_AUTHTOK, 0); } else if (configuration->try_first_pass) { rv = pam_get_pwd(pamh, &password, password_prompt, PAM_AUTHTOK, PAM_AUTHTOK); } else { rv = pam_get_pwd(pamh, &password, password_prompt, 0, PAM_AUTHTOK); } if (rv != PAM_SUCCESS) { if (!configuration->quiet) { pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2316: password could not be read")); sleep(configuration->err_display_time); } release_pkcs11_module(ph); pam_syslog(pamh, LOG_ERR, "pam_get_pwd() failed: %s", pam_strerror(pamh, rv)); return pkcs11_pam_fail; } #ifdef DEBUG_SHOW_PASSWORD DBG1("password = [%s]", password); #endif /* check password length */ if (!configuration->nullok && strlen(password) == 0) { release_pkcs11_module(ph); memset(password, 0, strlen(password)); free(password); pam_syslog(pamh, LOG_ERR, "password length is zero but the 'nullok' argument was not defined."); if (!configuration->quiet) { pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2318: Empty smartcard PIN not allowed.")); sleep(configuration->err_display_time); } return PAM_AUTH_ERR; } } else { pam_prompt(pamh, PAM_TEXT_INFO, NULL, _("Enter your %s PIN on the pinpad"), _(configuration->token_type)); /* use pin pad */ password = NULL; } /* call pkcs#11 login to ensure that the user is the real owner of the card * we need to do thise before get_certificate_list because some tokens * can not read their certificates until the token is authenticated */ rv = pkcs11_login(ph, password); /* erase and free in-memory password data asap */ if (password) { memset(password, 0, strlen(password)); free(password); } if (rv != 0) { ERR1("open_pkcs11_login() failed: %s", get_error()); if (!configuration->quiet) { pam_syslog(pamh, LOG_ERR, "open_pkcs11_login() failed: %s", get_error()); pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2320: Wrong smartcard PIN")); sleep(configuration->err_display_time); } goto auth_failed_nopw; } } cert_list = get_certificate_list(ph, &ncert); if (rv<0) { ERR1("get_certificate_list() failed: %s", get_error()); if (!configuration->quiet) { pam_syslog(pamh, LOG_ERR, "get_certificate_list() failed: %s", get_error()); pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2322: No certificate found")); sleep(configuration->err_display_time); } goto auth_failed_nopw; } /* load mapper modules */ load_mappers(configuration->ctx); /* find a valid and matching certificates */ for (i = 0; i < ncert; i++) { X509 *x509 = (X509 *)get_X509_certificate(cert_list[i]); if (!x509 ) continue; /* sanity check */ DBG1("verifying the certificate #%d", i + 1); if (!configuration->quiet) { pam_prompt(pamh, PAM_TEXT_INFO, NULL, _("verifying certificate")); } /* verify certificate (date, signature, CRL, ...) */ rv = verify_certificate(x509,&configuration->policy); if (rv < 0) { ERR1("verify_certificate() failed: %s", get_error()); if (!configuration->quiet) { pam_syslog(pamh, LOG_ERR, "verify_certificate() failed: %s", get_error()); switch (rv) { case -2: // X509_V_ERR_CERT_HAS_EXPIRED: pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2324: Certificate has expired")); break; case -3: // X509_V_ERR_CERT_NOT_YET_VALID: pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2326: Certificate not yet valid")); break; case -4: // X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2328: Certificate signature invalid")); break; default: pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2330: Certificate invalid")); break; } sleep(configuration->err_display_time); } continue; /* try next certificate */ } else if (rv != 1) { ERR1("verify_certificate() failed: %s", get_error()); continue; /* try next certificate */ } /* CA and CRL verified, now check/find user */ if ( is_spaced_str(user) ) { /* if provided user is null or empty extract and set user name from certificate */ DBG("Empty login: try to deduce from certificate"); user=find_user(x509); if (!user) { ERR2("find_user() failed: %s on cert #%d", get_error(),i+1); if (!configuration->quiet) pam_syslog(pamh, LOG_ERR, "find_user() failed: %s on cert #%d",get_error(),i+1); continue; /* try on next certificate */ } else { DBG1("certificate is valid and matches user %s",user); /* try to set up PAM user entry with evaluated value */ rv = pam_set_item(pamh, PAM_USER,(const void *)user); if (rv != PAM_SUCCESS) { ERR1("pam_set_item() failed %s", pam_strerror(pamh, rv)); if (!configuration->quiet) { pam_syslog(pamh, LOG_ERR, "pam_set_item() failed %s", pam_strerror(pamh, rv)); pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2332: setting PAM userentry failed")); sleep(configuration->err_display_time); } goto auth_failed_nopw; } chosen_cert = cert_list[i]; break; /* end loop, as find user success */ } } else { /* User provided: check whether the certificate matches the user */ rv = match_user(x509, user); if (rv < 0) { /* match error; abort and return */ ERR1("match_user() failed: %s", get_error()); if (!configuration->quiet) { pam_syslog(pamh, LOG_ERR, "match_user() failed: %s", get_error()); pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2334: No matching user")); sleep(configuration->err_display_time); } goto auth_failed_nopw; } else if (rv == 0) { /* match didn't success */ DBG("certificate is valid but does not match the user"); continue; /* try next certificate */ } else { /* match success */ DBG("certificate is valid and matches the user"); chosen_cert = cert_list[i]; break; } } /* if is_spaced string */ } /* for (i=0; i<ncerts; i++) */ /* now myCert points to our found certificate or null if no user found */ if (!chosen_cert) { ERR("no valid certificate which meets all requirements found"); if (!configuration->quiet) { pam_syslog(pamh, LOG_ERR, "no valid certificate which meets all requirements found"); pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2336: No matching certificate found")); sleep(configuration->err_display_time); } goto auth_failed_nopw; } /* if signature check is enforced, generate random data, sign and verify */ if (configuration->policy.signature_policy) { pam_prompt(pamh, PAM_TEXT_INFO, NULL, _("Checking signature")); #ifdef notdef rv = get_private_key(ph); if (rv != 0) { ERR1("get_private_key() failed: %s", get_error()); if (!configuration->quiet) pam_syslog(pamh, LOG_ERR, "get_private_key() failed: %s", get_error()); goto auth_failed_nopw; } #endif /* read random value */ rv = get_random_value(random_value, sizeof(random_value)); if (rv != 0) { ERR1("get_random_value() failed: %s", get_error()); if (!configuration->quiet){ pam_syslog(pamh, LOG_ERR, "get_random_value() failed: %s", get_error()); pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2338: Getting random value failed")); sleep(configuration->err_display_time); } goto auth_failed_nopw; } /* sign random value */ signature = NULL; rv = sign_value(ph, chosen_cert, random_value, sizeof(random_value), &signature, &signature_length); if (rv != 0) { ERR1("sign_value() failed: %s", get_error()); if (!configuration->quiet) { pam_syslog(pamh, LOG_ERR, "sign_value() failed: %s", get_error()); pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2340: Signing failed")); sleep(configuration->err_display_time); } goto auth_failed_nopw; } /* verify the signature */ DBG("verifying signature..."); rv = verify_signature((X509 *)get_X509_certificate(chosen_cert), random_value, sizeof(random_value), signature, signature_length); if (signature != NULL) { free(signature); } if (rv != 0) { close_pkcs11_session(ph); release_pkcs11_module(ph); ERR1("verify_signature() failed: %s", get_error()); if (!configuration->quiet) { pam_syslog(pamh, LOG_ERR, "verify_signature() failed: %s", get_error()); pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2342: Verifying signature failed")); sleep(configuration->err_display_time); } return PAM_AUTH_ERR; } } else { DBG("Skipping signature check"); } /* * fill in the environment variables. */ snprintf(env_temp, sizeof(env_temp) - 1, "PKCS11_LOGIN_TOKEN_NAME=%.*s", (int)((sizeof(env_temp) - 1) - strlen("PKCS11_LOGIN_TOKEN_NAME=")), get_slot_tokenlabel(ph)); rv = pam_putenv(pamh, env_temp); if (rv != PAM_SUCCESS) { ERR1("could not put token name in environment: %s", pam_strerror(pamh, rv)); if (!configuration->quiet) pam_syslog(pamh, LOG_ERR, "could not put token name in environment: %s", pam_strerror(pamh, rv)); } issuer = cert_info((X509 *)get_X509_certificate(chosen_cert), CERT_ISSUER, ALGORITHM_NULL); if (issuer) { snprintf(env_temp, sizeof(env_temp) - 1, "PKCS11_LOGIN_CERT_ISSUER=%.*s", (int)((sizeof(env_temp) - 1) - strlen("PKCS11_LOGIN_CERT_ISSUER=")), issuer[0]); rv = pam_putenv(pamh, env_temp); } else { ERR("couldn't get certificate issuer."); if (!configuration->quiet) pam_syslog(pamh, LOG_ERR, "couldn't get certificate issuer."); } if (rv != PAM_SUCCESS) { ERR1("could not put cert issuer in environment: %s", pam_strerror(pamh, rv)); if (!configuration->quiet) pam_syslog(pamh, LOG_ERR, "could not put cert issuer in environment: %s", pam_strerror(pamh, rv)); } serial = cert_info((X509 *)get_X509_certificate(chosen_cert), CERT_SERIAL, ALGORITHM_NULL); if (serial) { snprintf(env_temp, sizeof(env_temp) - 1, "PKCS11_LOGIN_CERT_SERIAL=%.*s", (int)((sizeof(env_temp) - 1) - strlen("PKCS11_LOGIN_CERT_SERIAL=")), serial[0]); rv = pam_putenv(pamh, env_temp); } else { ERR("couldn't get certificate serial number."); if (!configuration->quiet) pam_syslog(pamh, LOG_ERR, "couldn't get certificate serial number."); } if (rv != PAM_SUCCESS) { ERR1("could not put cert serial in environment: %s", pam_strerror(pamh, rv)); if (!configuration->quiet) pam_syslog(pamh, LOG_ERR, "could not put cert serial in environment: %s", pam_strerror(pamh, rv)); } /* unload mapper modules */ unload_mappers(); /* close pkcs #11 session */ rv = close_pkcs11_session(ph); if (rv != 0) { release_pkcs11_module(ph); ERR1("close_pkcs11_session() failed: %s", get_error()); if (!configuration->quiet) { pam_syslog(pamh, LOG_ERR, "close_pkcs11_module() failed: %s", get_error()); pam_prompt(pamh, PAM_ERROR_MSG , NULL, ("Error 2344: Closing PKCS#11 session failed")); sleep(configuration->err_display_time); } return pkcs11_pam_fail; } /* release pkcs #11 module */ DBG("releasing pkcs #11 module..."); release_pkcs11_module(ph); DBG("authentication succeeded"); return PAM_SUCCESS; /* quick and dirty fail exit point */ memset(password, 0, strlen(password)); free(password); /* erase and free in-memory password data */ auth_failed_nopw: unload_mappers(); close_pkcs11_session(ph); release_pkcs11_module(ph); return pkcs11_pam_fail; }