1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3*0Sstevel@tonic-gate * Use is subject to license terms. 4*0Sstevel@tonic-gate */ 5*0Sstevel@tonic-gate 6*0Sstevel@tonic-gate #include "includes.h" 7*0Sstevel@tonic-gate 8*0Sstevel@tonic-gate RCSID("$Id: auth2-pam.c,v 1.14 2002/06/28 16:48:12 mouring Exp $"); 9*0Sstevel@tonic-gate 10*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 11*0Sstevel@tonic-gate 12*0Sstevel@tonic-gate #ifdef USE_PAM 13*0Sstevel@tonic-gate #include <security/pam_appl.h> 14*0Sstevel@tonic-gate 15*0Sstevel@tonic-gate #include "ssh.h" 16*0Sstevel@tonic-gate #include "ssh2.h" 17*0Sstevel@tonic-gate #include "auth.h" 18*0Sstevel@tonic-gate #include "auth-pam.h" 19*0Sstevel@tonic-gate #include "auth-options.h" 20*0Sstevel@tonic-gate #include "packet.h" 21*0Sstevel@tonic-gate #include "xmalloc.h" 22*0Sstevel@tonic-gate #include "dispatch.h" 23*0Sstevel@tonic-gate #include "canohost.h" 24*0Sstevel@tonic-gate #include "log.h" 25*0Sstevel@tonic-gate #include "servconf.h" 26*0Sstevel@tonic-gate #include "monitor_wrap.h" 27*0Sstevel@tonic-gate #include "misc.h" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #ifdef HAVE_BSM 30*0Sstevel@tonic-gate #include "bsmaudit.h" 31*0Sstevel@tonic-gate #endif /* HAVE_BSM */ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate extern u_int utmp_len; 34*0Sstevel@tonic-gate extern ServerOptions options; 35*0Sstevel@tonic-gate 36*0Sstevel@tonic-gate extern Authmethod method_kbdint; 37*0Sstevel@tonic-gate extern Authmethod method_passwd; 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate #define SSHD_PAM_KBDINT_SVC "sshd-kbdint" 40*0Sstevel@tonic-gate 41*0Sstevel@tonic-gate static int do_pam_conv_kbd_int(int num_msg, 42*0Sstevel@tonic-gate struct pam_message **msg, struct pam_response **resp, 43*0Sstevel@tonic-gate void *appdata_ptr); 44*0Sstevel@tonic-gate static void input_userauth_info_response_pam(int type, 45*0Sstevel@tonic-gate u_int32_t seqnr, 46*0Sstevel@tonic-gate void *ctxt); 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate static struct pam_conv conv2 = { 49*0Sstevel@tonic-gate do_pam_conv_kbd_int, 50*0Sstevel@tonic-gate NULL, 51*0Sstevel@tonic-gate }; 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate static void do_pam_kbdint_cleanup(pam_handle_t *pamh); 54*0Sstevel@tonic-gate static void do_pam_kbdint(Authctxt *authctxt); 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate void 57*0Sstevel@tonic-gate auth2_pam(Authctxt *authctxt) 58*0Sstevel@tonic-gate { 59*0Sstevel@tonic-gate if (authctxt->user == NULL) 60*0Sstevel@tonic-gate fatal("auth2_pam: internal error: no user"); 61*0Sstevel@tonic-gate if (authctxt->method == NULL) 62*0Sstevel@tonic-gate fatal("auth2_pam: internal error: no method"); 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate conv2.appdata_ptr = authctxt; 65*0Sstevel@tonic-gate new_start_pam(authctxt, &conv2); 66*0Sstevel@tonic-gate 67*0Sstevel@tonic-gate authctxt->method->method_data = NULL; /* freed in the conv func */ 68*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, 69*0Sstevel@tonic-gate &input_userauth_info_response_pam); 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate /* 72*0Sstevel@tonic-gate * Since password userauth and keyboard-interactive userauth 73*0Sstevel@tonic-gate * both use PAM, and since keyboard-interactive is so much 74*0Sstevel@tonic-gate * better than password userauth, we should not allow the user 75*0Sstevel@tonic-gate * to try password userauth after trying keyboard-interactive. 76*0Sstevel@tonic-gate */ 77*0Sstevel@tonic-gate if (method_passwd.enabled) 78*0Sstevel@tonic-gate *method_passwd.enabled = 0; 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate do_pam_kbdint(authctxt); 81*0Sstevel@tonic-gate 82*0Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL); 83*0Sstevel@tonic-gate } 84*0Sstevel@tonic-gate 85*0Sstevel@tonic-gate static void 86*0Sstevel@tonic-gate do_pam_kbdint(Authctxt *authctxt) 87*0Sstevel@tonic-gate { 88*0Sstevel@tonic-gate int retval, retval2; 89*0Sstevel@tonic-gate pam_handle_t *pamh = authctxt->pam->h; 90*0Sstevel@tonic-gate const char *where = "authenticating"; 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate debug2("Calling pam_authenticate()"); 93*0Sstevel@tonic-gate if ((retval = pam_authenticate(pamh, 0)) != PAM_SUCCESS) 94*0Sstevel@tonic-gate goto cleanup; 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gate debug2("kbd-int: pam_authenticate() succeeded"); 97*0Sstevel@tonic-gate where = "authorizing"; 98*0Sstevel@tonic-gate retval = pam_acct_mgmt(pamh, 0); 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate if (retval == PAM_NEW_AUTHTOK_REQD) { 101*0Sstevel@tonic-gate if (authctxt->valid && authctxt->pw != NULL) { 102*0Sstevel@tonic-gate /* 103*0Sstevel@tonic-gate * Can't use temporarily_use_uid() and restore_uid() 104*0Sstevel@tonic-gate * here because we need (euid == 0 && ruid == pw_uid) 105*0Sstevel@tonic-gate * whereas temporarily_use_uid() arranges for 106*0Sstevel@tonic-gate * (suid = 0 && euid == pw_uid && ruid == pw_uid). 107*0Sstevel@tonic-gate */ 108*0Sstevel@tonic-gate (void) setreuid(authctxt->pw->pw_uid, -1); 109*0Sstevel@tonic-gate debug2("kbd-int: changing expired password"); 110*0Sstevel@tonic-gate where = "changing authentication tokens (password)"; 111*0Sstevel@tonic-gate retval = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK); 112*0Sstevel@tonic-gate audit_sshd_chauthtok(retval, authctxt->pw->pw_uid, 113*0Sstevel@tonic-gate authctxt->pw->pw_gid); 114*0Sstevel@tonic-gate (void) setreuid(0, -1); 115*0Sstevel@tonic-gate } else { 116*0Sstevel@tonic-gate retval = PAM_PERM_DENIED; 117*0Sstevel@tonic-gate } 118*0Sstevel@tonic-gate } 119*0Sstevel@tonic-gate 120*0Sstevel@tonic-gate if (retval != PAM_SUCCESS) 121*0Sstevel@tonic-gate goto cleanup; 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate authctxt->pam->state |= PAM_S_DONE_ACCT_MGMT; 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate retval = finish_userauth_do_pam(authctxt); 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate if (retval != PAM_SUCCESS) 128*0Sstevel@tonic-gate goto cleanup; 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate /* 131*0Sstevel@tonic-gate * PAM handle stays around so we can call pam_close_session() 132*0Sstevel@tonic-gate * on it later. 133*0Sstevel@tonic-gate */ 134*0Sstevel@tonic-gate authctxt->method->authenticated = 1; 135*0Sstevel@tonic-gate debug2("kbd-int: success (pam->state == %x)", authctxt->pam->state); 136*0Sstevel@tonic-gate return; 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gate cleanup: 139*0Sstevel@tonic-gate /* 140*0Sstevel@tonic-gate * Check for abandonment and cleanup. When kbdint is abandoned 141*0Sstevel@tonic-gate * authctxt->pam->h is NULLed and by this point a new handle may 142*0Sstevel@tonic-gate * be allocated. 143*0Sstevel@tonic-gate */ 144*0Sstevel@tonic-gate if (authctxt->pam->h != pamh) { 145*0Sstevel@tonic-gate log("Keyboard-interactive (PAM) userauth abandoned " 146*0Sstevel@tonic-gate "while %s", where); 147*0Sstevel@tonic-gate if ((retval2 = pam_end(pamh, retval)) != PAM_SUCCESS) { 148*0Sstevel@tonic-gate log("Cannot close PAM handle after " 149*0Sstevel@tonic-gate "kbd-int userauth abandonment[%d]: %.200s", 150*0Sstevel@tonic-gate retval2, PAM_STRERROR(pamh, retval2)); 151*0Sstevel@tonic-gate } 152*0Sstevel@tonic-gate authctxt->method->abandoned = 1; 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate /* 155*0Sstevel@tonic-gate * Avoid double counting; these are incremented in 156*0Sstevel@tonic-gate * kbdint_pam_abandon() so that they reflect the correct 157*0Sstevel@tonic-gate * count when userauth_finish() is called before 158*0Sstevel@tonic-gate * unwinding the dispatch_run() loop, but they are 159*0Sstevel@tonic-gate * incremented again in input_userauth_request() when 160*0Sstevel@tonic-gate * the loop is unwound, right here. 161*0Sstevel@tonic-gate */ 162*0Sstevel@tonic-gate if (authctxt->method->abandons) 163*0Sstevel@tonic-gate authctxt->method->abandons--; 164*0Sstevel@tonic-gate if (authctxt->method->attempts) 165*0Sstevel@tonic-gate authctxt->method->attempts--; 166*0Sstevel@tonic-gate } 167*0Sstevel@tonic-gate else { 168*0Sstevel@tonic-gate /* Save error value for pam_end() */ 169*0Sstevel@tonic-gate authctxt->pam->last_pam_retval = retval; 170*0Sstevel@tonic-gate log("Keyboard-interactive (PAM) userauth failed[%d] " 171*0Sstevel@tonic-gate "while %s: %.200s", retval, where, 172*0Sstevel@tonic-gate PAM_STRERROR(pamh, retval)); 173*0Sstevel@tonic-gate /* pam handle can be reused elsewhere, so no pam_end() here */ 174*0Sstevel@tonic-gate } 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate return; 177*0Sstevel@tonic-gate } 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate static int 180*0Sstevel@tonic-gate do_pam_conv_kbd_int(int num_msg, struct pam_message **msg, 181*0Sstevel@tonic-gate struct pam_response **resp, void *appdata_ptr) 182*0Sstevel@tonic-gate { 183*0Sstevel@tonic-gate int i, j; 184*0Sstevel@tonic-gate char *text; 185*0Sstevel@tonic-gate Convctxt *conv_ctxt; 186*0Sstevel@tonic-gate Authctxt *authctxt = (Authctxt *)appdata_ptr; 187*0Sstevel@tonic-gate 188*0Sstevel@tonic-gate if (!authctxt || !authctxt->method) { 189*0Sstevel@tonic-gate debug("Missing state during PAM conversation"); 190*0Sstevel@tonic-gate return PAM_CONV_ERR; 191*0Sstevel@tonic-gate } 192*0Sstevel@tonic-gate 193*0Sstevel@tonic-gate conv_ctxt = xmalloc(sizeof(Convctxt)); 194*0Sstevel@tonic-gate (void) memset(conv_ctxt, 0, sizeof(Convctxt)); 195*0Sstevel@tonic-gate conv_ctxt->finished = 0; 196*0Sstevel@tonic-gate conv_ctxt->num_received = 0; 197*0Sstevel@tonic-gate conv_ctxt->num_expected = 0; 198*0Sstevel@tonic-gate conv_ctxt->prompts = xmalloc(sizeof(int) * num_msg); 199*0Sstevel@tonic-gate conv_ctxt->responses = xmalloc(sizeof(struct pam_response) * num_msg); 200*0Sstevel@tonic-gate (void) memset(conv_ctxt->responses, 0, sizeof(struct pam_response) * num_msg); 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate text = NULL; 203*0Sstevel@tonic-gate for (i = 0, conv_ctxt->num_expected = 0; i < num_msg; i++) { 204*0Sstevel@tonic-gate int style = PAM_MSG_MEMBER(msg, i, msg_style); 205*0Sstevel@tonic-gate switch (style) { 206*0Sstevel@tonic-gate case PAM_PROMPT_ECHO_ON: 207*0Sstevel@tonic-gate debug2("PAM echo on prompt: %s", 208*0Sstevel@tonic-gate PAM_MSG_MEMBER(msg, i, msg)); 209*0Sstevel@tonic-gate conv_ctxt->num_expected++; 210*0Sstevel@tonic-gate break; 211*0Sstevel@tonic-gate case PAM_PROMPT_ECHO_OFF: 212*0Sstevel@tonic-gate debug2("PAM echo off prompt: %s", 213*0Sstevel@tonic-gate PAM_MSG_MEMBER(msg, i, msg)); 214*0Sstevel@tonic-gate conv_ctxt->num_expected++; 215*0Sstevel@tonic-gate break; 216*0Sstevel@tonic-gate case PAM_TEXT_INFO: 217*0Sstevel@tonic-gate debug2("PAM text info prompt: %s", 218*0Sstevel@tonic-gate PAM_MSG_MEMBER(msg, i, msg)); 219*0Sstevel@tonic-gate message_cat(&text, PAM_MSG_MEMBER(msg, i, msg)); 220*0Sstevel@tonic-gate break; 221*0Sstevel@tonic-gate case PAM_ERROR_MSG: 222*0Sstevel@tonic-gate debug2("PAM error prompt: %s", 223*0Sstevel@tonic-gate PAM_MSG_MEMBER(msg, i, msg)); 224*0Sstevel@tonic-gate message_cat(&text, PAM_MSG_MEMBER(msg, i, msg)); 225*0Sstevel@tonic-gate break; 226*0Sstevel@tonic-gate default: 227*0Sstevel@tonic-gate /* Capture all these messages to be sent at once */ 228*0Sstevel@tonic-gate message_cat(&text, PAM_MSG_MEMBER(msg, i, msg)); 229*0Sstevel@tonic-gate break; 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate } 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate if (conv_ctxt->num_expected == 0 && text == NULL) { 234*0Sstevel@tonic-gate xfree(conv_ctxt); 235*0Sstevel@tonic-gate return PAM_SUCCESS; 236*0Sstevel@tonic-gate } 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate authctxt->method->method_data = (void *) conv_ctxt; 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST); 241*0Sstevel@tonic-gate packet_put_cstring(""); /* Name */ 242*0Sstevel@tonic-gate packet_put_cstring(text ? text : ""); /* Instructions */ 243*0Sstevel@tonic-gate packet_put_cstring(""); /* Language */ 244*0Sstevel@tonic-gate packet_put_int(conv_ctxt->num_expected); 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate if (text) 247*0Sstevel@tonic-gate xfree(text); 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate for (i = 0, j = 0; i < num_msg; i++) { 250*0Sstevel@tonic-gate int style = PAM_MSG_MEMBER(msg, i, msg_style); 251*0Sstevel@tonic-gate 252*0Sstevel@tonic-gate /* Skip messages which don't need a reply */ 253*0Sstevel@tonic-gate if (style != PAM_PROMPT_ECHO_ON && style != PAM_PROMPT_ECHO_OFF) 254*0Sstevel@tonic-gate continue; 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate conv_ctxt->prompts[j++] = i; 257*0Sstevel@tonic-gate packet_put_cstring(PAM_MSG_MEMBER(msg, i, msg)); 258*0Sstevel@tonic-gate packet_put_char(style == PAM_PROMPT_ECHO_ON); 259*0Sstevel@tonic-gate } 260*0Sstevel@tonic-gate packet_send(); 261*0Sstevel@tonic-gate packet_write_wait(); 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gate /* 264*0Sstevel@tonic-gate * Here the dispatch_run() loop is nested. It should be unwound 265*0Sstevel@tonic-gate * if keyboard-interactive userauth is abandoned (or restarted; 266*0Sstevel@tonic-gate * same thing). 267*0Sstevel@tonic-gate * 268*0Sstevel@tonic-gate * The condition for breaking out of the nested dispatch_run() loop is 269*0Sstevel@tonic-gate * ((got kbd-int info reponse) || (kbd-int abandoned)) 270*0Sstevel@tonic-gate * 271*0Sstevel@tonic-gate * conv_ctxt->finished is set in either of those cases. 272*0Sstevel@tonic-gate * 273*0Sstevel@tonic-gate * When abandonment is detected the conv_ctxt->finished is set as 274*0Sstevel@tonic-gate * is conv_ctxt->abandoned, causing this function to signal 275*0Sstevel@tonic-gate * userauth nested dispatch_run() loop unwinding and to return 276*0Sstevel@tonic-gate * PAM_CONV_ERR; 277*0Sstevel@tonic-gate */ 278*0Sstevel@tonic-gate debug2("Nesting dispatch_run loop"); 279*0Sstevel@tonic-gate dispatch_run(DISPATCH_BLOCK, &conv_ctxt->finished, appdata_ptr); 280*0Sstevel@tonic-gate debug2("Nested dispatch_run loop exited"); 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate if (conv_ctxt->abandoned) { 283*0Sstevel@tonic-gate authctxt->unwind_dispatch_loop = 1; 284*0Sstevel@tonic-gate xfree(conv_ctxt); 285*0Sstevel@tonic-gate debug("PAM conv function returns PAM_CONV_ERR"); 286*0Sstevel@tonic-gate return PAM_CONV_ERR; 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate 289*0Sstevel@tonic-gate if (conv_ctxt->num_received == conv_ctxt->num_expected) { 290*0Sstevel@tonic-gate *resp = conv_ctxt->responses; 291*0Sstevel@tonic-gate xfree(conv_ctxt); 292*0Sstevel@tonic-gate debug("PAM conv function returns PAM_SUCCESS"); 293*0Sstevel@tonic-gate return PAM_SUCCESS; 294*0Sstevel@tonic-gate } 295*0Sstevel@tonic-gate 296*0Sstevel@tonic-gate debug("PAM conv function returns PAM_CONV_ERR"); 297*0Sstevel@tonic-gate xfree(conv_ctxt); 298*0Sstevel@tonic-gate return PAM_CONV_ERR; 299*0Sstevel@tonic-gate } 300*0Sstevel@tonic-gate 301*0Sstevel@tonic-gate static void 302*0Sstevel@tonic-gate input_userauth_info_response_pam(int type, u_int32_t seqnr, void *ctxt) 303*0Sstevel@tonic-gate { 304*0Sstevel@tonic-gate Authctxt *authctxt = ctxt; 305*0Sstevel@tonic-gate Convctxt *conv_ctxt; 306*0Sstevel@tonic-gate unsigned int nresp = 0, rlen = 0, i = 0; 307*0Sstevel@tonic-gate char *resp; 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate if (authctxt == NULL) 310*0Sstevel@tonic-gate fatal("input_userauth_info_response_pam: no authentication context"); 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate /* Check for spurious/unexpected info response */ 313*0Sstevel@tonic-gate if (method_kbdint.method_data == NULL) { 314*0Sstevel@tonic-gate debug("input_userauth_info_response_pam: no method context"); 315*0Sstevel@tonic-gate return; 316*0Sstevel@tonic-gate } 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate conv_ctxt = (Convctxt *) method_kbdint.method_data; 319*0Sstevel@tonic-gate 320*0Sstevel@tonic-gate nresp = packet_get_int(); /* Number of responses. */ 321*0Sstevel@tonic-gate debug("got %d responses", nresp); 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate 324*0Sstevel@tonic-gate #if 0 325*0Sstevel@tonic-gate if (nresp != conv_ctxt->num_expected) 326*0Sstevel@tonic-gate fatal("%s: Received incorrect number of responses " 327*0Sstevel@tonic-gate "(expected %d, received %u)", __func__, 328*0Sstevel@tonic-gate conv_ctxt->num_expected, nresp); 329*0Sstevel@tonic-gate #endif 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gate if (nresp > 100) 332*0Sstevel@tonic-gate fatal("%s: too many replies", __func__); 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate for (i = 0; i < nresp && i < conv_ctxt->num_expected ; i++) { 335*0Sstevel@tonic-gate int j = conv_ctxt->prompts[i]; 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate resp = packet_get_string(&rlen); 338*0Sstevel@tonic-gate if (i < conv_ctxt->num_expected) { 339*0Sstevel@tonic-gate conv_ctxt->responses[j].resp_retcode = PAM_SUCCESS; 340*0Sstevel@tonic-gate conv_ctxt->responses[j].resp = xstrdup(resp); 341*0Sstevel@tonic-gate conv_ctxt->num_received++; 342*0Sstevel@tonic-gate } 343*0Sstevel@tonic-gate xfree(resp); 344*0Sstevel@tonic-gate } 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate if (nresp < conv_ctxt->num_expected) 347*0Sstevel@tonic-gate fatal("%s: too few replies", __func__); 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate /* XXX - This could make a covert channel... */ 350*0Sstevel@tonic-gate if (nresp > conv_ctxt->num_expected) 351*0Sstevel@tonic-gate debug("Ignoring additional PAM replies"); 352*0Sstevel@tonic-gate 353*0Sstevel@tonic-gate conv_ctxt->finished = 1; 354*0Sstevel@tonic-gate 355*0Sstevel@tonic-gate packet_check_eom(); 356*0Sstevel@tonic-gate } 357*0Sstevel@tonic-gate 358*0Sstevel@tonic-gate #if 0 359*0Sstevel@tonic-gate int 360*0Sstevel@tonic-gate kbdint_pam_abandon_chk(Authctxt *authctxt, Authmethod *method) 361*0Sstevel@tonic-gate { 362*0Sstevel@tonic-gate if (!method) 363*0Sstevel@tonic-gate return 0; /* fatal(), really; it'll happen somewhere else */ 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate if (!method->method_data) 366*0Sstevel@tonic-gate return 0; 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate return 1; 369*0Sstevel@tonic-gate } 370*0Sstevel@tonic-gate #endif 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate void 373*0Sstevel@tonic-gate kbdint_pam_abandon(Authctxt *authctxt, Authmethod *method) 374*0Sstevel@tonic-gate { 375*0Sstevel@tonic-gate Convctxt *conv_ctxt; 376*0Sstevel@tonic-gate 377*0Sstevel@tonic-gate /* 378*0Sstevel@tonic-gate * But, if it ever becomes desirable and possible to support 379*0Sstevel@tonic-gate * kbd-int userauth abandonment, here's what must be done. 380*0Sstevel@tonic-gate */ 381*0Sstevel@tonic-gate if (!method) 382*0Sstevel@tonic-gate return; 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate if (!method->method_data) 385*0Sstevel@tonic-gate return; 386*0Sstevel@tonic-gate 387*0Sstevel@tonic-gate conv_ctxt = (Convctxt *) method->method_data; 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate /* dispatch_run() loop will exit */ 390*0Sstevel@tonic-gate conv_ctxt->abandoned = 1; 391*0Sstevel@tonic-gate conv_ctxt->finished = 1; 392*0Sstevel@tonic-gate 393*0Sstevel@tonic-gate /* 394*0Sstevel@tonic-gate * The method_data will be free in the corresponding, active 395*0Sstevel@tonic-gate * conversation function 396*0Sstevel@tonic-gate */ 397*0Sstevel@tonic-gate method->method_data = NULL; 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate /* update counts that can't be updated elsewhere */ 400*0Sstevel@tonic-gate method->abandons++; 401*0Sstevel@tonic-gate method->attempts++; 402*0Sstevel@tonic-gate 403*0Sstevel@tonic-gate /* Finally, we cannot re-use the current current PAM handle */ 404*0Sstevel@tonic-gate authctxt->pam->h = NULL; /* Let the conv function cleanup */ 405*0Sstevel@tonic-gate } 406*0Sstevel@tonic-gate #endif 407