]> andersk Git - gssapi-openssh.git/blob - openssh/auth2-pam.c
b1f19d22d4e119ca2f857cab46835f365c3b6790
[gssapi-openssh.git] / openssh / auth2-pam.c
1 #include "includes.h"
2 RCSID("$Id$");
3
4 #ifdef USE_PAM
5 #include <security/pam_appl.h>
6
7 #include "ssh.h"
8 #include "ssh2.h"
9 #include "auth.h"
10 #include "auth-pam.h"
11 #include "packet.h"
12 #include "xmalloc.h"
13 #include "dispatch.h"
14 #include "log.h"
15
16 static int do_pam_conversation_kbd_int(int num_msg, 
17     const struct pam_message **msg, struct pam_response **resp, 
18     void *appdata_ptr);
19 void input_userauth_info_response_pam(int type, u_int32_t seqnr, void *ctxt);
20
21 struct {
22         int finished, num_received, num_expected;
23         int *prompts;
24         struct pam_response *responses;
25 } context_pam2 = {0, 0, 0, NULL};
26
27 static struct pam_conv conv2 = {
28         do_pam_conversation_kbd_int,
29         NULL,
30 };
31
32 int
33 auth2_pam(Authctxt *authctxt)
34 {
35         int retval = -1;
36
37         if (authctxt->user == NULL)
38                 fatal("auth2_pam: internal error: no user");
39
40         conv2.appdata_ptr = authctxt;
41         do_pam_set_conv(&conv2);
42
43         dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
44             &input_userauth_info_response_pam);
45         retval = (do_pam_authenticate(0) == PAM_SUCCESS);
46         dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
47
48         return retval;
49 }
50
51 static int
52 do_pam_conversation_kbd_int(int num_msg, const struct pam_message **msg,
53     struct pam_response **resp, void *appdata_ptr)
54 {
55         int i, j, done;
56         char *text;
57
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
65         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;
79                 }
80         }
81
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         
91         for (i = 0, j = 0; i < num_msg; i++) {
92                 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));
101                         packet_put_cstring(text);
102                         text = NULL;
103                 } else
104                         packet_put_cstring(PAM_MSG_MEMBER(msg, i, msg));
105                 packet_put_char(style == PAM_PROMPT_ECHO_ON);
106         }
107         packet_send();
108         packet_write_wait();
109
110         /*
111          * Grabbing control of execution and spinning until we get what
112          * 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
114          * only be traversed once.
115          */
116         while(context_pam2.finished == 0) {
117                 done = 1;
118                 dispatch_run(DISPATCH_BLOCK, &done, appdata_ptr);
119                 if (context_pam2.finished == 0)
120                         debug("extra packet during conversation");
121         }
122
123         if (context_pam2.num_received == context_pam2.num_expected) {
124                 *resp = context_pam2.responses;
125                 return PAM_SUCCESS;
126         } else
127                 return PAM_CONV_ERR;
128 }
129
130 void
131 input_userauth_info_response_pam(int type, u_int32_t seqnr, 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         nresp = packet_get_int();       /* Number of responses. */
141         debug("got %d responses", nresp);
142
143
144         if (nresp != context_pam2.num_expected)
145                 fatal("%s: Received incorrect number of responses "
146                     "(expected %d, received %u)", __func__, 
147                     context_pam2.num_expected, nresp);
148
149         if (nresp > 100)
150                 fatal("%s: too many replies", __func__);
151
152         for (i = 0; i < nresp; i++) {
153                 int j = context_pam2.prompts[i];
154
155                 resp = packet_get_string(&rlen);
156                 context_pam2.responses[j].resp_retcode = PAM_SUCCESS;
157                 context_pam2.responses[j].resp = resp;
158                 context_pam2.num_received++;
159         }
160
161         context_pam2.finished = 1;
162
163         packet_check_eom();
164 }
165 #endif
This page took 0.446755 seconds and 3 git commands to generate.