Lines Matching +full:pam +full:- +full:enabled
1 /*-
7 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
48 /* Based on FreeBSD: src/crypto/openssh/auth2-pam-freebsd.c,v 1.11 2003/03/31 13:48:18 des */
67 #include <pam/pam_appl.h>
72 # define sshpam_const /* Solaris, HP-UX, SunOS */
81 # define PAM_MSG_MEMBER(msg, n, member) ((msg)[(n)]->member)
89 #include "auth-pam.h"
97 #include "auth-options.h"
100 #include "ssh-gss.h"
151 static int sshpam_thread_status = -1;
159 return; /* handler called after PAM cleanup, shouldn't happen */ in sshpam_sigchld_handler()
160 if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, WNOHANG) in sshpam_sigchld_handler()
162 /* PAM thread has not exitted, privsep slave must have */ in sshpam_sigchld_handler()
163 kill(cleanup_ctxt->pam_thread, SIGTERM); in sshpam_sigchld_handler()
164 while (waitpid(cleanup_ctxt->pam_thread, in sshpam_sigchld_handler()
165 &sshpam_thread_status, 0) == -1) { in sshpam_sigchld_handler()
171 if (sshpam_thread_status == -1) in sshpam_sigchld_handler()
195 sshpam_thread_status = -1; in pthread_create()
197 case -1: in pthread_create()
201 close(ctx->pam_psock); in pthread_create()
202 ctx->pam_psock = -1; in pthread_create()
207 close(ctx->pam_csock); in pthread_create()
208 ctx->pam_csock = -1; in pthread_create()
227 if (sshpam_thread_status != -1) in pthread_join()
230 while (waitpid(thread, &status, 0) == -1) { in pthread_join()
245 static int sshpam_account_status = -1;
253 /* Some PAM implementations don't implement this */
259 * XXX - If necessary, we can still support environment passing in pam_getenvlist()
261 * env vars (e.g. KRB5CCNAME) from the PAM environment. in pam_getenvlist()
279 * This wraps pam_chauthtok and sets/restore the real uid so PAM will do
289 fatal("PAM: sshpam_authctxt not initialized"); in sshpam_chauthtok_ruid()
290 if (setreuid(sshpam_authctxt->pw->pw_uid, -1) == -1) in sshpam_chauthtok_ruid()
293 if (setreuid(0, -1) == -1) in sshpam_chauthtok_ruid()
308 fatal("%s: PAM authctxt not initialized", __func__); in sshpam_password_change_required()
309 sshpam_authctxt->force_pwchange = reqd; in sshpam_password_change_required()
311 saved_port = auth_opts->permit_port_forwarding_flag; in sshpam_password_change_required()
312 saved_agent = auth_opts->permit_agent_forwarding_flag; in sshpam_password_change_required()
313 saved_x11 = auth_opts->permit_x11_forwarding_flag; in sshpam_password_change_required()
314 auth_opts->permit_port_forwarding_flag = 0; in sshpam_password_change_required()
315 auth_opts->permit_agent_forwarding_flag = 0; in sshpam_password_change_required()
316 auth_opts->permit_x11_forwarding_flag = 0; in sshpam_password_change_required()
319 auth_opts->permit_port_forwarding_flag = saved_port; in sshpam_password_change_required()
321 auth_opts->permit_agent_forwarding_flag = saved_agent; in sshpam_password_change_required()
323 auth_opts->permit_x11_forwarding_flag = saved_x11; in sshpam_password_change_required()
327 /* Import regular and PAM environment from subprocess */
335 debug3("PAM: %s entering", __func__); in import_environments()
342 fatal("%s: invalid PAM account status %u", __func__, n); in import_environments()
356 debug3("PAM: num env strings %u", num_env); in import_environments()
363 /* Import PAM environment from subprocess */ in import_environments()
367 fatal_f("received %u PAM env variables, expected <= 1024", in import_environments()
370 debug("PAM: num PAM env strings %u", num_env); in import_environments()
376 error("PAM: pam_putenv: %s", in import_environments()
401 debug3("PAM: %s entering, %d messages", __func__, n); in sshpam_thread_conv()
405 error("PAM: conversation function passed a null context"); in sshpam_thread_conv()
427 if (ssh_msg_send(ctxt->pam_csock, in sshpam_thread_conv()
428 PAM_MSG_MEMBER(msg, i, msg_style), buffer) == -1) in sshpam_thread_conv()
431 if (ssh_msg_recv(ctxt->pam_csock, buffer) == -1) in sshpam_thread_conv()
449 if (ssh_msg_send(ctxt->pam_csock, in sshpam_thread_conv()
450 PAM_MSG_MEMBER(msg, i, msg_style), buffer) == -1) in sshpam_thread_conv()
497 if (setenv("TZ", tz, 1) == -1) in sshpam_thread()
498 error("PAM: could not set TZ environment: %s", in sshpam_thread()
502 setproctitle("%s [pam]", in sshpam_thread()
503 sshpam_authctxt->valid ? pam_user : "unknown"); in sshpam_thread()
511 fatal("%s: PAM authctxt not initialized", __func__); in sshpam_thread()
530 if (sshpam_authctxt->force_pwchange) { in sshpam_thread()
544 (r = sshbuf_put_u32(buffer, sshpam_authctxt->force_pwchange)) != 0) in sshpam_thread()
559 /* Export any environment strings set by PAM in child */ in sshpam_thread()
564 fatal("%s: too many PAM environment strings", __func__); in sshpam_thread()
574 /* XXX - can't do much about an error here */ in sshpam_thread()
575 ssh_msg_send(ctxt->pam_csock, sshpam_err, buffer); in sshpam_thread()
583 /* XXX - can't do much about an error here */ in sshpam_thread()
585 ssh_msg_send(ctxt->pam_csock, PAM_ACCT_EXPIRED, buffer); in sshpam_thread()
587 ssh_msg_send(ctxt->pam_csock, PAM_MAXTRIES, buffer); in sshpam_thread()
589 ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, buffer); in sshpam_thread()
593 return (NULL); /* Avoid warning for non-pthread case */ in sshpam_thread()
601 debug3("PAM: %s entering", __func__); in sshpam_thread_cleanup()
602 if (ctxt != NULL && ctxt->pam_thread != 0) { in sshpam_thread_cleanup()
603 pthread_cancel(ctxt->pam_thread); in sshpam_thread_cleanup()
604 pthread_join(ctxt->pam_thread, NULL); in sshpam_thread_cleanup()
605 close(ctxt->pam_psock); in sshpam_thread_cleanup()
606 close(ctxt->pam_csock); in sshpam_thread_cleanup()
616 debug3("PAM: %s entering, %d messages", __func__, n); in sshpam_null_conv()
629 debug3("PAM: %s called with %d messages", __func__, n); in sshpam_store_conv()
670 debug("PAM: cleanup"); in sshpam_cleanup()
673 debug("PAM: closing session"); in sshpam_cleanup()
678 debug("PAM: deleting credentials"); in sshpam_cleanup()
690 const char *pam_user, *user = authctxt->user; in sshpam_init()
695 fatal_f("internal error: NULL PAM service name"); in sshpam_init()
697 /* Protect buggy PAM implementations from excessively long usernames */ in sshpam_init()
709 /* We already have a PAM context; check if the user matches */ in sshpam_init()
717 debug("PAM: initializing for \"%s\" with service \"%s\"", user, in sshpam_init()
726 return (-1); in sshpam_init()
740 debug("PAM: setting PAM_RHOST to \"%s\"", sshpam_rhost); in sshpam_init()
746 return (-1); in sshpam_init()
752 /* Put SSH_CONNECTION in the PAM environment too */ in sshpam_init()
763 * Some silly PAM modules (e.g. pam_time) require a TTY to operate. in sshpam_init()
765 * may not even set one (for tty-less connections) in sshpam_init()
767 debug("PAM: setting PAM_TTY to \"ssh\""); in sshpam_init()
772 return (-1); in sshpam_init()
784 * Expose authentication information to PAM. in expose_authinfo()
788 if (sshpam_authctxt->session_info == NULL) in expose_authinfo()
791 sshpam_authctxt->session_info)) == NULL) in expose_authinfo()
805 debug3("PAM: %s entering", __func__); in sshpam_init_ctx()
807 * Refuse to start if we don't have PAM enabled or do_pam_account in sshpam_init_ctx()
813 /* Initialize PAM */ in sshpam_init_ctx()
814 if (sshpam_init(NULL, authctxt) == -1) { in sshpam_init_ctx()
815 error("PAM: initialization failed"); in sshpam_init_ctx()
823 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) { in sshpam_init_ctx()
824 error("PAM: failed create sockets: %s", strerror(errno)); in sshpam_init_ctx()
828 ctxt->pam_psock = socks[0]; in sshpam_init_ctx()
829 ctxt->pam_csock = socks[1]; in sshpam_init_ctx()
830 result = pthread_create(&ctxt->pam_thread, NULL, sshpam_thread, ctxt); in sshpam_init_ctx()
832 error("PAM: failed to start authentication thread: %s", in sshpam_init_ctx()
855 debug3("PAM: %s entering", __func__); in sshpam_query()
864 while (ssh_msg_recv(ctxt->pam_psock, buffer) == 0) { in sshpam_query()
876 strlcpy(**prompts + plen, msg, len - plen); in sshpam_query()
887 strlcpy(**prompts + plen, msg, len - plen); in sshpam_query()
889 strlcat(**prompts + plen, "\n", len - plen); in sshpam_query()
901 debug3("PAM: %s", pam_strerror(sshpam_handle, type)); in sshpam_query()
908 ctxt->pam_done = -1; in sshpam_query()
917 debug("PAM: %s", **prompts); in sshpam_query()
926 if (!sshpam_authctxt->valid || in sshpam_query()
927 (sshpam_authctxt->pw->pw_uid == 0 && in sshpam_query()
929 fatal("Internal error: PAM auth " in sshpam_query()
935 ctxt->pam_done = 1; in sshpam_query()
941 "PAM illegal user"); in sshpam_query()
942 error("PAM: %s for %s%.100s from %.100s", msg, in sshpam_query()
943 sshpam_authctxt->valid ? "" : "illegal user ", in sshpam_query()
944 sshpam_authctxt->user, sshpam_rhost); in sshpam_query()
950 ctxt->pam_done = -1; in sshpam_query()
952 return (-1); in sshpam_query()
956 return (-1); in sshpam_query()
961 * Used to mitigate timing attacks against crypt(3)/PAM stacks that
978 ret[i] = junk[i % (sizeof(junk) - 1)]; in fake_password()
983 /* XXX - see also comment in auth-chall.c:verify_response */
992 debug2("PAM: %s entering, %u responses", __func__, num); in sshpam_respond()
993 switch (ctxt->pam_done) { in sshpam_respond()
1000 return (-1); in sshpam_respond()
1003 error("PAM: expected one response, got %u", num); in sshpam_respond()
1004 return (-1); in sshpam_respond()
1008 if (sshpam_authctxt->valid && in sshpam_respond()
1009 (sshpam_authctxt->pw->pw_uid != 0 || in sshpam_respond()
1019 if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, buffer) == -1) { in sshpam_respond()
1021 return (-1); in sshpam_respond()
1032 debug3("PAM: %s entering", __func__); in sshpam_free_ctx()
1036 * We don't call sshpam_cleanup() here because we may need the PAM in sshpam_free_ctx()
1044 "pam",
1052 "pam",
1060 * This replaces auth-pam.c
1065 Authctxt *authctxt = (Authctxt *)ssh->authctxt; in start_pam()
1068 fatal("PAM: initialisation requested when UsePAM=no"); in start_pam()
1070 if (sshpam_init(ssh, authctxt) == -1) in start_pam()
1071 fatal("PAM: initialisation failed"); in start_pam()
1085 if (sshpam_account_status != -1) in do_pam_account()
1091 debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err, in do_pam_account()
1112 fatal("PAM: failed to set PAM_CONV: %s", in do_pam_setcred()
1114 debug("PAM: establishing credentials"); in do_pam_setcred()
1121 fatal("PAM: pam_setcred(): %s", in do_pam_setcred()
1124 debug("PAM: pam_setcred(): %s", in do_pam_setcred()
1137 debug3("PAM: %s called with %d messages", __func__, n);
1198 fatal("PAM: failed to set PAM_CONV: %s", in do_pam_chauthtok()
1200 debug("PAM: changing password"); in do_pam_chauthtok()
1203 fatal("PAM: pam_chauthtok(): %s", in do_pam_chauthtok()
1211 debug3("PAM: opening session"); in do_pam_session()
1218 fatal("PAM: failed to set PAM_CONV: %s", in do_pam_session()
1226 error("PAM: pam_open_session(): %s", in do_pam_session()
1239 * Set a PAM environment string. We need to do this so that the session
1287 * echo-off prompts are for the password and stores messages for later
1298 debug3("PAM: %s called with %d messages", __func__, n); in sshpam_passwd_conv()
1348 * Attempt password authentication via PAM
1358 fatal("PAM: %s called when PAM disabled or failed to " in sshpam_auth_passwd()
1367 * information via timing (eg if the PAM config has a delay on fail). in sshpam_auth_passwd()
1369 if (!authctxt->valid || (authctxt->pw->pw_uid == 0 && in sshpam_auth_passwd()
1376 fatal("PAM: %s: failed to set PAM_CONV: %s", __func__, in sshpam_auth_passwd()
1386 if (sshpam_err == PAM_SUCCESS && authctxt->valid) { in sshpam_auth_passwd()
1387 debug("PAM: password authentication accepted for %.100s", in sshpam_auth_passwd()
1388 authctxt->user); in sshpam_auth_passwd()
1391 debug("PAM: password authentication failed for %.100s: %s", in sshpam_auth_passwd()
1392 authctxt->valid ? authctxt->user : "an illegal user", in sshpam_auth_passwd()