00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 #include "includes.h"
00050 RCSID("$Id: auth-pam.c,v 1.128 2006/01/29 05:46:13 dtucker Exp $");
00051
00052 #ifdef USE_PAM
00053 #if defined(HAVE_SECURITY_PAM_APPL_H)
00054 #include <security/pam_appl.h>
00055 #elif defined (HAVE_PAM_PAM_APPL_H)
00056 #include <pam/pam_appl.h>
00057 #endif
00058
00059
00060 #ifdef PAM_SUN_CODEBASE
00061 # define sshpam_const
00062 #else
00063 # define sshpam_const const
00064 #endif
00065
00066 #include "auth.h"
00067 #include "auth-pam.h"
00068 #include "buffer.h"
00069 #include "bufaux.h"
00070 #include "canohost.h"
00071 #include "log.h"
00072 #include "monitor_wrap.h"
00073 #include "msg.h"
00074 #include "packet.h"
00075 #include "misc.h"
00076 #include "servconf.h"
00077 #include "ssh2.h"
00078 #include "xmalloc.h"
00079 #include "auth-options.h"
00080
00081 extern ServerOptions options;
00082 extern Buffer loginmsg;
00083 extern int compat20;
00084 extern u_int utmp_len;
00085
00086
00087 #ifdef USE_POSIX_THREADS
00088 # error "USE_POSIX_THREADS replaced by UNSUPPORTED_POSIX_THREADS_HACK"
00089 #endif
00090
00091
00092
00093
00094
00095
00096 #ifdef UNSUPPORTED_POSIX_THREADS_HACK
00097 #include <pthread.h>
00098
00099
00100
00101
00102
00103 typedef pthread_t sp_pthread_t;
00104 #else
00105 typedef pid_t sp_pthread_t;
00106 #endif
00107
00108 struct pam_ctxt {
00109 sp_pthread_t pam_thread;
00110 int pam_psock;
00111 int pam_csock;
00112 int pam_done;
00113 };
00114
00115 static void sshpam_free_ctx(void *);
00116 static struct pam_ctxt *cleanup_ctxt;
00117
00118 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
00119
00120
00121
00122
00123 static int sshpam_thread_status = -1;
00124 static mysig_t sshpam_oldsig;
00125
00126 static void
00127 sshpam_sigchld_handler(int sig)
00128 {
00129 signal(SIGCHLD, SIG_DFL);
00130 if (cleanup_ctxt == NULL)
00131 return;
00132 if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, WNOHANG)
00133 <= 0) {
00134
00135 kill(cleanup_ctxt->pam_thread, SIGTERM);
00136 if (waitpid(cleanup_ctxt->pam_thread, &sshpam_thread_status, 0)
00137 <= 0)
00138 return;
00139 }
00140 if (WIFSIGNALED(sshpam_thread_status) &&
00141 WTERMSIG(sshpam_thread_status) == SIGTERM)
00142 return;
00143 if (!WIFEXITED(sshpam_thread_status))
00144 fatal("PAM: authentication thread exited unexpectedly");
00145 if (WEXITSTATUS(sshpam_thread_status) != 0)
00146 fatal("PAM: authentication thread exited uncleanly");
00147 }
00148
00149 static void
00150 pthread_exit(void *value __unused)
00151 {
00152 _exit(0);
00153 }
00154
00155 static int
00156 pthread_create(sp_pthread_t *thread, const void *attr __unused,
00157 void *(*thread_start)(void *), void *arg)
00158 {
00159 pid_t pid;
00160 struct pam_ctxt *ctx = arg;
00161
00162 sshpam_thread_status = -1;
00163 switch ((pid = fork())) {
00164 case -1:
00165 error("fork(): %s", strerror(errno));
00166 return (-1);
00167 case 0:
00168 close(ctx->pam_psock);
00169 ctx->pam_psock = -1;
00170 thread_start(arg);
00171 _exit(1);
00172 default:
00173 *thread = pid;
00174 close(ctx->pam_csock);
00175 ctx->pam_csock = -1;
00176 sshpam_oldsig = signal(SIGCHLD, sshpam_sigchld_handler);
00177 return (0);
00178 }
00179 }
00180
00181 static int
00182 pthread_cancel(sp_pthread_t thread)
00183 {
00184 signal(SIGCHLD, sshpam_oldsig);
00185 return (kill(thread, SIGTERM));
00186 }
00187
00188 static int
00189 pthread_join(sp_pthread_t thread, void **value __unused)
00190 {
00191 int status;
00192
00193 if (sshpam_thread_status != -1)
00194 return (sshpam_thread_status);
00195 signal(SIGCHLD, sshpam_oldsig);
00196 waitpid(thread, &status, 0);
00197 return (status);
00198 }
00199 #endif
00200
00201
00202 static pam_handle_t *sshpam_handle = NULL;
00203 static int sshpam_err = 0;
00204 static int sshpam_authenticated = 0;
00205 static int sshpam_session_open = 0;
00206 static int sshpam_cred_established = 0;
00207 static int sshpam_account_status = -1;
00208 static char **sshpam_env = NULL;
00209 static Authctxt *sshpam_authctxt = NULL;
00210 static const char *sshpam_password = NULL;
00211 static char badpw[] = "\b\n\r\177INCORRECT";
00212
00213
00214 #ifndef HAVE_PAM_GETENVLIST
00215 static char **
00216 pam_getenvlist(pam_handle_t *pamh)
00217 {
00218
00219
00220
00221
00222
00223 return NULL;
00224 }
00225 #endif
00226
00227
00228
00229
00230
00231
00232
00233
00234 #ifdef SSHPAM_CHAUTHTOK_NEEDS_RUID
00235 static int
00236 sshpam_chauthtok_ruid(pam_handle_t *pamh, int flags)
00237 {
00238 int result;
00239
00240 if (sshpam_authctxt == NULL)
00241 fatal("PAM: sshpam_authctxt not initialized");
00242 if (setreuid(sshpam_authctxt->pw->pw_uid, -1) == -1)
00243 fatal("%s: setreuid failed: %s", __func__, strerror(errno));
00244 result = pam_chauthtok(pamh, flags);
00245 if (setreuid(0, -1) == -1)
00246 fatal("%s: setreuid failed: %s", __func__, strerror(errno));
00247 return result;
00248 }
00249 # define pam_chauthtok(a,b) (sshpam_chauthtok_ruid((a), (b)))
00250 #endif
00251
00252 void
00253 sshpam_password_change_required(int reqd)
00254 {
00255 debug3("%s %d", __func__, reqd);
00256 if (sshpam_authctxt == NULL)
00257 fatal("%s: PAM authctxt not initialized", __func__);
00258 sshpam_authctxt->force_pwchange = reqd;
00259 if (reqd) {
00260 no_port_forwarding_flag |= 2;
00261 no_agent_forwarding_flag |= 2;
00262 no_x11_forwarding_flag |= 2;
00263 } else {
00264 no_port_forwarding_flag &= ~2;
00265 no_agent_forwarding_flag &= ~2;
00266 no_x11_forwarding_flag &= ~2;
00267 }
00268 }
00269
00270
00271 static void
00272 import_environments(Buffer *b)
00273 {
00274 char *env;
00275 u_int i, num_env;
00276 int err;
00277
00278 debug3("PAM: %s entering", __func__);
00279
00280 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
00281
00282 sshpam_account_status = buffer_get_int(b);
00283 sshpam_password_change_required(buffer_get_int(b));
00284
00285
00286 num_env = buffer_get_int(b);
00287 sshpam_env = xmalloc((num_env + 1) * sizeof(*sshpam_env));
00288 debug3("PAM: num env strings %d", num_env);
00289 for(i = 0; i < num_env; i++)
00290 sshpam_env[i] = buffer_get_string(b, NULL);
00291
00292 sshpam_env[num_env] = NULL;
00293
00294
00295 num_env = buffer_get_int(b);
00296 debug("PAM: num PAM env strings %d", num_env);
00297 for(i = 0; i < num_env; i++) {
00298 env = buffer_get_string(b, NULL);
00299
00300 #ifdef HAVE_PAM_PUTENV
00301
00302 if ((err = pam_putenv(sshpam_handle, env)) != PAM_SUCCESS) {
00303 error("PAM: pam_putenv: %s",
00304 pam_strerror(sshpam_handle, sshpam_err));
00305 }
00306 #endif
00307 }
00308 #endif
00309 }
00310
00311
00312
00313
00314 static int
00315 sshpam_thread_conv(int n, sshpam_const struct pam_message **msg,
00316 struct pam_response **resp, void *data)
00317 {
00318 Buffer buffer;
00319 struct pam_ctxt *ctxt;
00320 struct pam_response *reply;
00321 int i;
00322
00323 debug3("PAM: %s entering, %d messages", __func__, n);
00324 *resp = NULL;
00325
00326 if (data == NULL) {
00327 error("PAM: conversation function passed a null context");
00328 return (PAM_CONV_ERR);
00329 }
00330 ctxt = data;
00331 if (n <= 0 || n > PAM_MAX_NUM_MSG)
00332 return (PAM_CONV_ERR);
00333
00334 if ((reply = malloc(n * sizeof(*reply))) == NULL)
00335 return (PAM_CONV_ERR);
00336 memset(reply, 0, n * sizeof(*reply));
00337
00338 buffer_init(&buffer);
00339 for (i = 0; i < n; ++i) {
00340 switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
00341 case PAM_PROMPT_ECHO_OFF:
00342 buffer_put_cstring(&buffer,
00343 PAM_MSG_MEMBER(msg, i, msg));
00344 if (ssh_msg_send(ctxt->pam_csock,
00345 PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
00346 goto fail;
00347 if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1)
00348 goto fail;
00349 if (buffer_get_char(&buffer) != PAM_AUTHTOK)
00350 goto fail;
00351 reply[i].resp = buffer_get_string(&buffer, NULL);
00352 break;
00353 case PAM_PROMPT_ECHO_ON:
00354 buffer_put_cstring(&buffer,
00355 PAM_MSG_MEMBER(msg, i, msg));
00356 if (ssh_msg_send(ctxt->pam_csock,
00357 PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
00358 goto fail;
00359 if (ssh_msg_recv(ctxt->pam_csock, &buffer) == -1)
00360 goto fail;
00361 if (buffer_get_char(&buffer) != PAM_AUTHTOK)
00362 goto fail;
00363 reply[i].resp = buffer_get_string(&buffer, NULL);
00364 break;
00365 case PAM_ERROR_MSG:
00366 buffer_put_cstring(&buffer,
00367 PAM_MSG_MEMBER(msg, i, msg));
00368 if (ssh_msg_send(ctxt->pam_csock,
00369 PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
00370 goto fail;
00371 break;
00372 case PAM_TEXT_INFO:
00373 buffer_put_cstring(&buffer,
00374 PAM_MSG_MEMBER(msg, i, msg));
00375 if (ssh_msg_send(ctxt->pam_csock,
00376 PAM_MSG_MEMBER(msg, i, msg_style), &buffer) == -1)
00377 goto fail;
00378 break;
00379 default:
00380 goto fail;
00381 }
00382 buffer_clear(&buffer);
00383 }
00384 buffer_free(&buffer);
00385 *resp = reply;
00386 return (PAM_SUCCESS);
00387
00388 fail:
00389 for(i = 0; i < n; i++) {
00390 if (reply[i].resp != NULL)
00391 xfree(reply[i].resp);
00392 }
00393 xfree(reply);
00394 buffer_free(&buffer);
00395 return (PAM_CONV_ERR);
00396 }
00397
00398
00399
00400
00401 static void *
00402 sshpam_thread(void *ctxtp)
00403 {
00404 struct pam_ctxt *ctxt = ctxtp;
00405 Buffer buffer;
00406 struct pam_conv sshpam_conv;
00407 int flags = (options.permit_empty_passwd == 0 ?
00408 PAM_DISALLOW_NULL_AUTHTOK : 0);
00409 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
00410 extern char **environ;
00411 char **env_from_pam;
00412 u_int i;
00413 const char *pam_user;
00414 const char **ptr_pam_user = &pam_user;
00415
00416 pam_get_item(sshpam_handle, PAM_USER,
00417 (sshpam_const void **)ptr_pam_user);
00418 environ[0] = NULL;
00419
00420 if (sshpam_authctxt != NULL) {
00421 setproctitle("%s [pam]",
00422 sshpam_authctxt->valid ? pam_user : "unknown");
00423 }
00424 #endif
00425
00426 sshpam_conv.conv = sshpam_thread_conv;
00427 sshpam_conv.appdata_ptr = ctxt;
00428
00429 if (sshpam_authctxt == NULL)
00430 fatal("%s: PAM authctxt not initialized", __func__);
00431
00432 buffer_init(&buffer);
00433 sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
00434 (const void *)&sshpam_conv);
00435 if (sshpam_err != PAM_SUCCESS)
00436 goto auth_fail;
00437 sshpam_err = pam_authenticate(sshpam_handle, flags);
00438 if (sshpam_err != PAM_SUCCESS)
00439 goto auth_fail;
00440
00441 if (compat20) {
00442 if (!do_pam_account())
00443 goto auth_fail;
00444 if (sshpam_authctxt->force_pwchange) {
00445 sshpam_err = pam_chauthtok(sshpam_handle,
00446 PAM_CHANGE_EXPIRED_AUTHTOK);
00447 if (sshpam_err != PAM_SUCCESS)
00448 goto auth_fail;
00449 sshpam_password_change_required(0);
00450 }
00451 }
00452
00453 buffer_put_cstring(&buffer, "OK");
00454
00455 #ifndef UNSUPPORTED_POSIX_THREADS_HACK
00456
00457 buffer_put_int(&buffer, sshpam_account_status);
00458 buffer_put_int(&buffer, sshpam_authctxt->force_pwchange);
00459
00460
00461 for(i = 0; environ[i] != NULL; i++)
00462 ;
00463 buffer_put_int(&buffer, i);
00464 for(i = 0; environ[i] != NULL; i++)
00465 buffer_put_cstring(&buffer, environ[i]);
00466
00467
00468 env_from_pam = pam_getenvlist(sshpam_handle);
00469 for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++)
00470 ;
00471 buffer_put_int(&buffer, i);
00472 for(i = 0; env_from_pam != NULL && env_from_pam[i] != NULL; i++)
00473 buffer_put_cstring(&buffer, env_from_pam[i]);
00474 #endif
00475
00476
00477 ssh_msg_send(ctxt->pam_csock, sshpam_err, &buffer);
00478 buffer_free(&buffer);
00479 pthread_exit(NULL);
00480
00481 auth_fail:
00482 buffer_put_cstring(&buffer,
00483 pam_strerror(sshpam_handle, sshpam_err));
00484
00485 ssh_msg_send(ctxt->pam_csock, PAM_AUTH_ERR, &buffer);
00486 buffer_free(&buffer);
00487 pthread_exit(NULL);
00488
00489 return (NULL);
00490 }
00491
00492 void
00493 sshpam_thread_cleanup(void)
00494 {
00495 struct pam_ctxt *ctxt = cleanup_ctxt;
00496
00497 debug3("PAM: %s entering", __func__);
00498 if (ctxt != NULL && ctxt->pam_thread != 0) {
00499 pthread_cancel(ctxt->pam_thread);
00500 pthread_join(ctxt->pam_thread, NULL);
00501 close(ctxt->pam_psock);
00502 close(ctxt->pam_csock);
00503 memset(ctxt, 0, sizeof(*ctxt));
00504 cleanup_ctxt = NULL;
00505 }
00506 }
00507
00508 static int
00509 sshpam_null_conv(int n, sshpam_const struct pam_message **msg,
00510 struct pam_response **resp, void *data)
00511 {
00512 debug3("PAM: %s entering, %d messages", __func__, n);
00513 return (PAM_CONV_ERR);
00514 }
00515
00516 static struct pam_conv null_conv = { sshpam_null_conv, NULL };
00517
00518 static int
00519 sshpam_store_conv(int n, sshpam_const struct pam_message **msg,
00520 struct pam_response **resp, void *data)
00521 {
00522 struct pam_response *reply;
00523 int i;
00524 size_t len;
00525
00526 debug3("PAM: %s called with %d messages", __func__, n);
00527 *resp = NULL;
00528
00529 if (n <= 0 || n > PAM_MAX_NUM_MSG)
00530 return (PAM_CONV_ERR);
00531
00532 if ((reply = malloc(n * sizeof(*reply))) == NULL)
00533 return (PAM_CONV_ERR);
00534 memset(reply, 0, n * sizeof(*reply));
00535
00536 for (i = 0; i < n; ++i) {
00537 switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
00538 case PAM_ERROR_MSG:
00539 case PAM_TEXT_INFO:
00540 len = strlen(PAM_MSG_MEMBER(msg, i, msg));
00541 buffer_append(&loginmsg, PAM_MSG_MEMBER(msg, i, msg), len);
00542 buffer_append(&loginmsg, "\n", 1 );
00543 reply[i].resp_retcode = PAM_SUCCESS;
00544 break;
00545 default:
00546 goto fail;
00547 }
00548 }
00549 *resp = reply;
00550 return (PAM_SUCCESS);
00551
00552 fail:
00553 for(i = 0; i < n; i++) {
00554 if (reply[i].resp != NULL)
00555 xfree(reply[i].resp);
00556 }
00557 xfree(reply);
00558 return (PAM_CONV_ERR);
00559 }
00560
00561 static struct pam_conv store_conv = { sshpam_store_conv, NULL };
00562
00563 void
00564 sshpam_cleanup(void)
00565 {
00566 debug("PAM: cleanup");
00567 if (sshpam_handle == NULL)
00568 return;
00569 pam_set_item(sshpam_handle, PAM_CONV, (const void *)&null_conv);
00570 if (sshpam_cred_established) {
00571 pam_setcred(sshpam_handle, PAM_DELETE_CRED);
00572 sshpam_cred_established = 0;
00573 }
00574 if (sshpam_session_open) {
00575 pam_close_session(sshpam_handle, PAM_SILENT);
00576 sshpam_session_open = 0;
00577 }
00578 sshpam_authenticated = 0;
00579 pam_end(sshpam_handle, sshpam_err);
00580 sshpam_handle = NULL;
00581 }
00582
00583 static int
00584 sshpam_init(Authctxt *authctxt)
00585 {
00586 extern char *__progname;
00587 const char *pam_rhost, *pam_user, *user = authctxt->user;
00588 const char **ptr_pam_user = &pam_user;
00589
00590 if (sshpam_handle != NULL) {
00591
00592 sshpam_err = pam_get_item(sshpam_handle,
00593 PAM_USER, (sshpam_const void **)ptr_pam_user);
00594 if (sshpam_err == PAM_SUCCESS && strcmp(user, pam_user) == 0)
00595 return (0);
00596 pam_end(sshpam_handle, sshpam_err);
00597 sshpam_handle = NULL;
00598 }
00599 debug("PAM: initializing for \"%s\"", user);
00600 sshpam_err =
00601 pam_start(SSHD_PAM_SERVICE, user, &store_conv, &sshpam_handle);
00602 sshpam_authctxt = authctxt;
00603
00604 if (sshpam_err != PAM_SUCCESS) {
00605 pam_end(sshpam_handle, sshpam_err);
00606 sshpam_handle = NULL;
00607 return (-1);
00608 }
00609 pam_rhost = get_remote_name_or_ip(utmp_len, options.use_dns);
00610 debug("PAM: setting PAM_RHOST to \"%s\"", pam_rhost);
00611 sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST, pam_rhost);
00612 if (sshpam_err != PAM_SUCCESS) {
00613 pam_end(sshpam_handle, sshpam_err);
00614 sshpam_handle = NULL;
00615 return (-1);
00616 }
00617 #ifdef PAM_TTY_KLUDGE
00618
00619
00620
00621
00622
00623 debug("PAM: setting PAM_TTY to \"ssh\"");
00624 sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, "ssh");
00625 if (sshpam_err != PAM_SUCCESS) {
00626 pam_end(sshpam_handle, sshpam_err);
00627 sshpam_handle = NULL;
00628 return (-1);
00629 }
00630 #endif
00631 return (0);
00632 }
00633
00634 static void *
00635 sshpam_init_ctx(Authctxt *authctxt)
00636 {
00637 struct pam_ctxt *ctxt;
00638 int socks[2];
00639
00640 debug3("PAM: %s entering", __func__);
00641
00642 if (!options.use_pam)
00643 return NULL;
00644
00645
00646 if (sshpam_init(authctxt) == -1) {
00647 error("PAM: initialization failed");
00648 return (NULL);
00649 }
00650
00651 ctxt = xmalloc(sizeof *ctxt);
00652 memset(ctxt, 0, sizeof(*ctxt));
00653
00654
00655 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, socks) == -1) {
00656 error("PAM: failed create sockets: %s", strerror(errno));
00657 xfree(ctxt);
00658 return (NULL);
00659 }
00660 ctxt->pam_psock = socks[0];
00661 ctxt->pam_csock = socks[1];
00662 if (pthread_create(&ctxt->pam_thread, NULL, sshpam_thread, ctxt) == -1) {
00663 error("PAM: failed to start authentication thread: %s",
00664 strerror(errno));
00665 close(socks[0]);
00666 close(socks[1]);
00667 xfree(ctxt);
00668 return (NULL);
00669 }
00670 cleanup_ctxt = ctxt;
00671 return (ctxt);
00672 }
00673
00674 static int
00675 sshpam_query(void *ctx, char **name, char **info,
00676 u_int *num, char ***prompts, u_int **echo_on)
00677 {
00678 Buffer buffer;
00679 struct pam_ctxt *ctxt = ctx;
00680 size_t plen;
00681 u_char type;
00682 char *msg;
00683 size_t len, mlen;
00684
00685 debug3("PAM: %s entering", __func__);
00686 buffer_init(&buffer);
00687 *name = xstrdup("");
00688 *info = xstrdup("");
00689 *prompts = xmalloc(sizeof(char *));
00690 **prompts = NULL;
00691 plen = 0;
00692 *echo_on = xmalloc(sizeof(u_int));
00693 while (ssh_msg_recv(ctxt->pam_psock, &buffer) == 0) {
00694 type = buffer_get_char(&buffer);
00695 msg = buffer_get_string(&buffer, NULL);
00696 mlen = strlen(msg);
00697 switch (type) {
00698 case PAM_PROMPT_ECHO_ON:
00699 case PAM_PROMPT_ECHO_OFF:
00700 *num = 1;
00701 len = plen + mlen + 1;
00702 **prompts = xrealloc(**prompts, len);
00703 strlcpy(**prompts + plen, msg, len - plen);
00704 plen += mlen;
00705 **echo_on = (type == PAM_PROMPT_ECHO_ON);
00706 xfree(msg);
00707 return (0);
00708 case PAM_ERROR_MSG:
00709 case PAM_TEXT_INFO:
00710
00711 len = plen + mlen + 2;
00712 **prompts = xrealloc(**prompts, len);
00713 strlcpy(**prompts + plen, msg, len - plen);
00714 plen += mlen;
00715 strlcat(**prompts + plen, "\n", len - plen);
00716 plen++;
00717 xfree(msg);
00718 break;
00719 case PAM_AUTH_ERR:
00720 debug3("PAM: PAM_AUTH_ERR");
00721 if (**prompts != NULL && strlen(**prompts) != 0) {
00722 *info = **prompts;
00723 **prompts = NULL;
00724 *num = 0;
00725 **echo_on = 0;
00726 ctxt->pam_done = -1;
00727 return 0;
00728 }
00729
00730 case PAM_SUCCESS:
00731 if (**prompts != NULL) {
00732
00733 debug("PAM: %s", **prompts);
00734 buffer_append(&loginmsg, **prompts,
00735 strlen(**prompts));
00736 xfree(**prompts);
00737 **prompts = NULL;
00738 }
00739 if (type == PAM_SUCCESS) {
00740 if (!sshpam_authctxt->valid ||
00741 (sshpam_authctxt->pw->pw_uid == 0 &&
00742 options.permit_root_login != PERMIT_YES))
00743 fatal("Internal error: PAM auth "
00744 "succeeded when it should have "
00745 "failed");
00746 import_environments(&buffer);
00747 *num = 0;
00748 **echo_on = 0;
00749 ctxt->pam_done = 1;
00750 xfree(msg);
00751 return (0);
00752 }
00753 error("PAM: %s for %s%.100s from %.100s", msg,
00754 sshpam_authctxt->valid ? "" : "illegal user ",
00755 sshpam_authctxt->user,
00756 get_remote_name_or_ip(utmp_len, options.use_dns));
00757
00758 default:
00759 *num = 0;
00760 **echo_on = 0;
00761 xfree(msg);
00762 ctxt->pam_done = -1;
00763 return (-1);
00764 }
00765 }
00766 return (-1);
00767 }
00768
00769
00770 static int
00771 sshpam_respond(void *ctx, u_int num, char **resp)
00772 {
00773 Buffer buffer;
00774 struct pam_ctxt *ctxt = ctx;
00775
00776 debug2("PAM: %s entering, %u responses", __func__, num);
00777 switch (ctxt->pam_done) {
00778 case 1:
00779 sshpam_authenticated = 1;
00780 return (0);
00781 case 0:
00782 break;
00783 default:
00784 return (-1);
00785 }
00786 if (num != 1) {
00787 error("PAM: expected one response, got %u", num);
00788 return (-1);
00789 }
00790 buffer_init(&buffer);
00791 if (sshpam_authctxt->valid &&
00792 (sshpam_authctxt->pw->pw_uid != 0 ||
00793 options.permit_root_login == PERMIT_YES))
00794 buffer_put_cstring(&buffer, *resp);
00795 else
00796 buffer_put_cstring(&buffer, badpw);
00797 if (ssh_msg_send(ctxt->pam_psock, PAM_AUTHTOK, &buffer) == -1) {
00798 buffer_free(&buffer);
00799 return (-1);
00800 }
00801 buffer_free(&buffer);
00802 return (1);
00803 }
00804
00805 static void
00806 sshpam_free_ctx(void *ctxtp)
00807 {
00808 struct pam_ctxt *ctxt = ctxtp;
00809
00810 debug3("PAM: %s entering", __func__);
00811 sshpam_thread_cleanup();
00812 xfree(ctxt);
00813
00814
00815
00816
00817
00818
00819 }
00820
00821 KbdintDevice sshpam_device = {
00822 "pam",
00823 sshpam_init_ctx,
00824 sshpam_query,
00825 sshpam_respond,
00826 sshpam_free_ctx
00827 };
00828
00829 KbdintDevice mm_sshpam_device = {
00830 "pam",
00831 mm_sshpam_init_ctx,
00832 mm_sshpam_query,
00833 mm_sshpam_respond,
00834 mm_sshpam_free_ctx
00835 };
00836
00837
00838
00839
00840 void
00841 start_pam(Authctxt *authctxt)
00842 {
00843 if (!options.use_pam)
00844 fatal("PAM: initialisation requested when UsePAM=no");
00845
00846 if (sshpam_init(authctxt) == -1)
00847 fatal("PAM: initialisation failed");
00848 }
00849
00850 void
00851 finish_pam(void)
00852 {
00853 sshpam_cleanup();
00854 }
00855
00856 u_int
00857 do_pam_account(void)
00858 {
00859 debug("%s: called", __func__);
00860 if (sshpam_account_status != -1)
00861 return (sshpam_account_status);
00862
00863 sshpam_err = pam_acct_mgmt(sshpam_handle, 0);
00864 debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err,
00865 pam_strerror(sshpam_handle, sshpam_err));
00866
00867 if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) {
00868 sshpam_account_status = 0;
00869 return (sshpam_account_status);
00870 }
00871
00872 if (sshpam_err == PAM_NEW_AUTHTOK_REQD)
00873 sshpam_password_change_required(1);
00874
00875 sshpam_account_status = 1;
00876 return (sshpam_account_status);
00877 }
00878
00879 void
00880 do_pam_set_tty(const char *tty)
00881 {
00882 if (tty != NULL) {
00883 debug("PAM: setting PAM_TTY to \"%s\"", tty);
00884 sshpam_err = pam_set_item(sshpam_handle, PAM_TTY, tty);
00885 if (sshpam_err != PAM_SUCCESS)
00886 fatal("PAM: failed to set PAM_TTY: %s",
00887 pam_strerror(sshpam_handle, sshpam_err));
00888 }
00889 }
00890
00891 void
00892 do_pam_setcred(int init)
00893 {
00894 sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
00895 (const void *)&store_conv);
00896 if (sshpam_err != PAM_SUCCESS)
00897 fatal("PAM: failed to set PAM_CONV: %s",
00898 pam_strerror(sshpam_handle, sshpam_err));
00899 if (init) {
00900 debug("PAM: establishing credentials");
00901 sshpam_err = pam_setcred(sshpam_handle, PAM_ESTABLISH_CRED);
00902 } else {
00903 debug("PAM: reinitializing credentials");
00904 sshpam_err = pam_setcred(sshpam_handle, PAM_REINITIALIZE_CRED);
00905 }
00906 if (sshpam_err == PAM_SUCCESS) {
00907 sshpam_cred_established = 1;
00908 return;
00909 }
00910 if (sshpam_authenticated)
00911 fatal("PAM: pam_setcred(): %s",
00912 pam_strerror(sshpam_handle, sshpam_err));
00913 else
00914 debug("PAM: pam_setcred(): %s",
00915 pam_strerror(sshpam_handle, sshpam_err));
00916 }
00917
00918 static int
00919 sshpam_tty_conv(int n, sshpam_const struct pam_message **msg,
00920 struct pam_response **resp, void *data)
00921 {
00922 char input[PAM_MAX_MSG_SIZE];
00923 struct pam_response *reply;
00924 int i;
00925
00926 debug3("PAM: %s called with %d messages", __func__, n);
00927
00928 *resp = NULL;
00929
00930 if (n <= 0 || n > PAM_MAX_NUM_MSG || !isatty(STDIN_FILENO))
00931 return (PAM_CONV_ERR);
00932
00933 if ((reply = malloc(n * sizeof(*reply))) == NULL)
00934 return (PAM_CONV_ERR);
00935 memset(reply, 0, n * sizeof(*reply));
00936
00937 for (i = 0; i < n; ++i) {
00938 switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
00939 case PAM_PROMPT_ECHO_OFF:
00940 reply[i].resp =
00941 read_passphrase(PAM_MSG_MEMBER(msg, i, msg),
00942 RP_ALLOW_STDIN);
00943 reply[i].resp_retcode = PAM_SUCCESS;
00944 break;
00945 case PAM_PROMPT_ECHO_ON:
00946 fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));
00947 fgets(input, sizeof input, stdin);
00948 if ((reply[i].resp = strdup(input)) == NULL)
00949 goto fail;
00950 reply[i].resp_retcode = PAM_SUCCESS;
00951 break;
00952 case PAM_ERROR_MSG:
00953 case PAM_TEXT_INFO:
00954 fprintf(stderr, "%s\n", PAM_MSG_MEMBER(msg, i, msg));
00955 reply[i].resp_retcode = PAM_SUCCESS;
00956 break;
00957 default:
00958 goto fail;
00959 }
00960 }
00961 *resp = reply;
00962 return (PAM_SUCCESS);
00963
00964 fail:
00965 for(i = 0; i < n; i++) {
00966 if (reply[i].resp != NULL)
00967 xfree(reply[i].resp);
00968 }
00969 xfree(reply);
00970 return (PAM_CONV_ERR);
00971 }
00972
00973 static struct pam_conv tty_conv = { sshpam_tty_conv, NULL };
00974
00975
00976
00977
00978
00979 void
00980 do_pam_chauthtok(void)
00981 {
00982 if (use_privsep)
00983 fatal("Password expired (unable to change with privsep)");
00984 sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
00985 (const void *)&tty_conv);
00986 if (sshpam_err != PAM_SUCCESS)
00987 fatal("PAM: failed to set PAM_CONV: %s",
00988 pam_strerror(sshpam_handle, sshpam_err));
00989 debug("PAM: changing password");
00990 sshpam_err = pam_chauthtok(sshpam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);
00991 if (sshpam_err != PAM_SUCCESS)
00992 fatal("PAM: pam_chauthtok(): %s",
00993 pam_strerror(sshpam_handle, sshpam_err));
00994 }
00995
00996 void
00997 do_pam_session(void)
00998 {
00999 debug3("PAM: opening session");
01000 sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
01001 (const void *)&store_conv);
01002 if (sshpam_err != PAM_SUCCESS)
01003 fatal("PAM: failed to set PAM_CONV: %s",
01004 pam_strerror(sshpam_handle, sshpam_err));
01005 sshpam_err = pam_open_session(sshpam_handle, 0);
01006 if (sshpam_err == PAM_SUCCESS)
01007 sshpam_session_open = 1;
01008 else {
01009 sshpam_session_open = 0;
01010 disable_forwarding();
01011 error("PAM: pam_open_session(): %s",
01012 pam_strerror(sshpam_handle, sshpam_err));
01013 }
01014
01015 }
01016
01017 int
01018 is_pam_session_open(void)
01019 {
01020 return sshpam_session_open;
01021 }
01022
01023
01024
01025
01026
01027
01028 int
01029 do_pam_putenv(char *name, char *value)
01030 {
01031 int ret = 1;
01032 #ifdef HAVE_PAM_PUTENV
01033 char *compound;
01034 size_t len;
01035
01036 len = strlen(name) + strlen(value) + 2;
01037 compound = xmalloc(len);
01038
01039 snprintf(compound, len, "%s=%s", name, value);
01040 ret = pam_putenv(sshpam_handle, compound);
01041 xfree(compound);
01042 #endif
01043
01044 return (ret);
01045 }
01046
01047 char **
01048 fetch_pam_child_environment(void)
01049 {
01050 return sshpam_env;
01051 }
01052
01053 char **
01054 fetch_pam_environment(void)
01055 {
01056 return (pam_getenvlist(sshpam_handle));
01057 }
01058
01059 void
01060 free_pam_environment(char **env)
01061 {
01062 char **envp;
01063
01064 if (env == NULL)
01065 return;
01066
01067 for (envp = env; *envp; envp++)
01068 xfree(*envp);
01069 xfree(env);
01070 }
01071
01072
01073
01074
01075
01076
01077 static int
01078 sshpam_passwd_conv(int n, sshpam_const struct pam_message **msg,
01079 struct pam_response **resp, void *data)
01080 {
01081 struct pam_response *reply;
01082 int i;
01083 size_t len;
01084
01085 debug3("PAM: %s called with %d messages", __func__, n);
01086
01087 *resp = NULL;
01088
01089 if (n <= 0 || n > PAM_MAX_NUM_MSG)
01090 return (PAM_CONV_ERR);
01091
01092 if ((reply = malloc(n * sizeof(*reply))) == NULL)
01093 return (PAM_CONV_ERR);
01094 memset(reply, 0, n * sizeof(*reply));
01095
01096 for (i = 0; i < n; ++i) {
01097 switch (PAM_MSG_MEMBER(msg, i, msg_style)) {
01098 case PAM_PROMPT_ECHO_OFF:
01099 if (sshpam_password == NULL)
01100 goto fail;
01101 if ((reply[i].resp = strdup(sshpam_password)) == NULL)
01102 goto fail;
01103 reply[i].resp_retcode = PAM_SUCCESS;
01104 break;
01105 case PAM_ERROR_MSG:
01106 case PAM_TEXT_INFO:
01107 len = strlen(PAM_MSG_MEMBER(msg, i, msg));
01108 if (len > 0) {
01109 buffer_append(&loginmsg,
01110 PAM_MSG_MEMBER(msg, i, msg), len);
01111 buffer_append(&loginmsg, "\n", 1);
01112 }
01113 if ((reply[i].resp = strdup("")) == NULL)
01114 goto fail;
01115 reply[i].resp_retcode = PAM_SUCCESS;
01116 break;
01117 default:
01118 goto fail;
01119 }
01120 }
01121 *resp = reply;
01122 return (PAM_SUCCESS);
01123
01124 fail:
01125 for(i = 0; i < n; i++) {
01126 if (reply[i].resp != NULL)
01127 xfree(reply[i].resp);
01128 }
01129 xfree(reply);
01130 return (PAM_CONV_ERR);
01131 }
01132
01133 static struct pam_conv passwd_conv = { sshpam_passwd_conv, NULL };
01134
01135
01136
01137
01138 int
01139 sshpam_auth_passwd(Authctxt *authctxt, const char *password)
01140 {
01141 int flags = (options.permit_empty_passwd == 0 ?
01142 PAM_DISALLOW_NULL_AUTHTOK : 0);
01143
01144 if (!options.use_pam || sshpam_handle == NULL)
01145 fatal("PAM: %s called when PAM disabled or failed to "
01146 "initialise.", __func__);
01147
01148 sshpam_password = password;
01149 sshpam_authctxt = authctxt;
01150
01151
01152
01153
01154
01155
01156 if (!authctxt->valid || (authctxt->pw->pw_uid == 0 &&
01157 options.permit_root_login != PERMIT_YES))
01158 sshpam_password = badpw;
01159
01160 sshpam_err = pam_set_item(sshpam_handle, PAM_CONV,
01161 (const void *)&passwd_conv);
01162 if (sshpam_err != PAM_SUCCESS)
01163 fatal("PAM: %s: failed to set PAM_CONV: %s", __func__,
01164 pam_strerror(sshpam_handle, sshpam_err));
01165
01166 sshpam_err = pam_authenticate(sshpam_handle, flags);
01167 sshpam_password = NULL;
01168 if (sshpam_err == PAM_SUCCESS && authctxt->valid) {
01169 debug("PAM: password authentication accepted for %.100s",
01170 authctxt->user);
01171 return 1;
01172 } else {
01173 debug("PAM: password authentication failed for %.100s: %s",
01174 authctxt->valid ? authctxt->user : "an illegal user",
01175 pam_strerror(sshpam_handle, sshpam_err));
01176 return 0;
01177 }
01178 }
01179 #endif