blob: 490921d844025048f4725d6aa5a2e3724bc05505 [file] [log] [blame]
Damien Millerb8481582000-12-03 11:51:51 +11001#include "includes.h"
Damien Miller8fa2bda2001-02-16 13:03:04 +11002RCSID("$Id: auth2-pam.c,v 1.10 2001/02/16 02:03:04 djm Exp $");
Damien Millerb8481582000-12-03 11:51:51 +11003
4#ifdef USE_PAM
Ben Lindstrom226cfa02001-01-22 05:34:40 +00005#include <security/pam_appl.h>
6
Damien Millerb8481582000-12-03 11:51:51 +11007#include "ssh.h"
8#include "ssh2.h"
9#include "auth.h"
Damien Miller63dc3e92001-02-07 12:58:33 +110010#include "auth-pam.h"
Damien Millerb8481582000-12-03 11:51:51 +110011#include "packet.h"
12#include "xmalloc.h"
13#include "dispatch.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000014#include "log.h"
Damien Millerb8481582000-12-03 11:51:51 +110015
Damien Miller63dc3e92001-02-07 12:58:33 +110016static int do_pam_conversation_kbd_int(int num_msg,
17 const struct pam_message **msg, struct pam_response **resp,
18 void *appdata_ptr);
19void input_userauth_info_response_pam(int type, int plen, void *ctxt);
20
Damien Millerb8481582000-12-03 11:51:51 +110021struct {
22 int finished, num_received, num_expected;
23 int *prompts;
24 struct pam_response *responses;
25} context_pam2 = {0, 0, 0, NULL};
26
Damien Miller63dc3e92001-02-07 12:58:33 +110027static struct pam_conv conv2 = {
28 do_pam_conversation_kbd_int,
Damien Millerb8481582000-12-03 11:51:51 +110029 NULL,
30};
31
Damien Millerb8481582000-12-03 11:51:51 +110032int
33auth2_pam(Authctxt *authctxt)
34{
35 int retval = -1;
Damien Millerb8481582000-12-03 11:51:51 +110036
37 if (authctxt->user == NULL)
38 fatal("auth2_pam: internal error: no user");
39
Damien Miller22e22bf2001-01-19 15:46:38 +110040 conv2.appdata_ptr = authctxt;
Damien Miller646aa602001-02-15 11:51:32 +110041 do_pam_set_conv(&conv2);
Damien Millerb8481582000-12-03 11:51:51 +110042
43 dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
Damien Miller63dc3e92001-02-07 12:58:33 +110044 &input_userauth_info_response_pam);
Damien Millerb8481582000-12-03 11:51:51 +110045 retval = (do_pam_authenticate(0) == PAM_SUCCESS);
46 dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
47
Damien Millerb8481582000-12-03 11:51:51 +110048 return retval;
49}
50
51static int
Damien Miller63dc3e92001-02-07 12:58:33 +110052do_pam_conversation_kbd_int(int num_msg, const struct pam_message **msg,
53 struct pam_response **resp, void *appdata_ptr)
Damien Millerb8481582000-12-03 11:51:51 +110054{
Damien Miller63dc3e92001-02-07 12:58:33 +110055 int i, j, done;
56 char *text;
Damien Millerb8481582000-12-03 11:51:51 +110057
58 context_pam2.finished = 0;
59 context_pam2.num_received = 0;
60 context_pam2.num_expected = 0;
61 context_pam2.prompts = xmalloc(sizeof(int) * num_msg);
62 context_pam2.responses = xmalloc(sizeof(struct pam_response) * num_msg);
63 memset(context_pam2.responses, 0, sizeof(struct pam_response) * num_msg);
64
Damien Miller63dc3e92001-02-07 12:58:33 +110065 text = NULL;
66 for (i = 0, context_pam2.num_expected = 0; i < num_msg; i++) {
67 int style = PAM_MSG_MEMBER(msg, i, msg_style);
68 switch (style) {
69 case PAM_PROMPT_ECHO_ON:
70 case PAM_PROMPT_ECHO_OFF:
71 context_pam2.num_expected++;
72 break;
73 case PAM_TEXT_INFO:
74 case PAM_ERROR_MSG:
75 default:
76 /* Capture all these messages to be sent at once */
77 message_cat(&text, PAM_MSG_MEMBER(msg, i, msg));
78 break;
Damien Millerb8481582000-12-03 11:51:51 +110079 }
80 }
Damien Miller63dc3e92001-02-07 12:58:33 +110081
82 if (context_pam2.num_expected == 0)
83 return PAM_SUCCESS;
84
85 packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
86 packet_put_cstring(""); /* Name */
87 packet_put_cstring(""); /* Instructions */
88 packet_put_cstring(""); /* Language */
89 packet_put_int(context_pam2.num_expected);
90
Damien Millerb8481582000-12-03 11:51:51 +110091 for (i = 0, j = 0; i < num_msg; i++) {
Damien Miller63dc3e92001-02-07 12:58:33 +110092 int style = PAM_MSG_MEMBER(msg, i, msg_style);
93
94 /* Skip messages which don't need a reply */
95 if (style != PAM_PROMPT_ECHO_ON && style != PAM_PROMPT_ECHO_OFF)
96 continue;
97
98 context_pam2.prompts[j++] = i;
99 if (text) {
100 message_cat(&text, PAM_MSG_MEMBER(msg, i, msg));
Damien Millerb8481582000-12-03 11:51:51 +1100101 packet_put_cstring(text);
Damien Millerb8481582000-12-03 11:51:51 +1100102 text = NULL;
Damien Miller63dc3e92001-02-07 12:58:33 +1100103 } else
104 packet_put_cstring(PAM_MSG_MEMBER(msg, i, msg));
105 packet_put_char(style == PAM_PROMPT_ECHO_ON);
Damien Millerb8481582000-12-03 11:51:51 +1100106 }
107 packet_send();
108 packet_write_wait();
109
Damien Miller8fa2bda2001-02-16 13:03:04 +1100110 /*
111 * Grabbing control of execution and spinning until we get what
Damien Millerb8481582000-12-03 11:51:51 +1100112 * we want is probably rude, but it seems to work properly, and
113 * the client *should* be in lock-step with us, so the loop should
Damien Miller8fa2bda2001-02-16 13:03:04 +1100114 * only be traversed once.
115 */
Damien Millerb8481582000-12-03 11:51:51 +1100116 while(context_pam2.finished == 0) {
117 done = 1;
118 dispatch_run(DISPATCH_BLOCK, &done, appdata_ptr);
Damien Miller63dc3e92001-02-07 12:58:33 +1100119 if(context_pam2.finished == 0)
Damien Millerb8481582000-12-03 11:51:51 +1100120 debug("extra packet during conversation");
Damien Millerb8481582000-12-03 11:51:51 +1100121 }
122
123 if(context_pam2.num_received == context_pam2.num_expected) {
124 *resp = context_pam2.responses;
125 return PAM_SUCCESS;
Damien Miller63dc3e92001-02-07 12:58:33 +1100126 } else
Damien Millerb8481582000-12-03 11:51:51 +1100127 return PAM_CONV_ERR;
Damien Millerb8481582000-12-03 11:51:51 +1100128}
129
130void
131input_userauth_info_response_pam(int type, int plen, void *ctxt)
132{
133 Authctxt *authctxt = ctxt;
134 unsigned int nresp = 0, rlen = 0, i = 0;
135 char *resp;
136
137 if (authctxt == NULL)
138 fatal("input_userauth_info_response_pam: no authentication context");
139
140 if (authctxt->attempt++ >= AUTH_FAIL_MAX)
141 packet_disconnect("too many failed userauth_requests");
142
143 nresp = packet_get_int(); /* Number of responses. */
144 debug("got %d responses", nresp);
145
146 for (i = 0; i < nresp; i++) {
147 int j = context_pam2.prompts[i];
Damien Miller63dc3e92001-02-07 12:58:33 +1100148
Damien Millerb8481582000-12-03 11:51:51 +1100149 resp = packet_get_string(&rlen);
Damien Millerb8481582000-12-03 11:51:51 +1100150 context_pam2.responses[j].resp_retcode = PAM_SUCCESS;
151 context_pam2.responses[j].resp = xstrdup(resp);
152 xfree(resp);
153 context_pam2.num_received++;
154 }
155
156 context_pam2.finished = 1;
157
158 packet_done();
159}
160
161#endif