]> andersk Git - openssh.git/blob - auth2-pam.c
Please grep through the source and look for 'ISSUE' comments and verify
[openssh.git] / auth2-pam.c
1 #include "includes.h"
2 RCSID("$Id$");
3
4 #ifdef USE_PAM
5 #include "ssh.h"
6 #include "ssh2.h"
7 #include "auth.h"
8 #include "packet.h"
9 #include "xmalloc.h"
10 #include "dispatch.h"
11 #include <security/pam_appl.h>
12
13 struct {
14         int finished, num_received, num_expected;
15         int *prompts;
16         struct pam_response *responses;
17 } context_pam2 = {0, 0, 0, NULL};
18
19 static int do_conversation2(int num_msg, const struct pam_message **msg,
20                             struct pam_response **resp, void *appdata_ptr);
21
22 static struct pam_conv
23 conv2 = {
24         do_conversation2,
25         NULL,
26 };
27
28 void input_userauth_info_response_pam(int type, int plen, void *ctxt);
29
30 int
31 auth2_pam(Authctxt *authctxt)
32 {
33         int retval = -1;
34         char *method = "PAM";
35
36         if (authctxt->user == NULL)
37                 fatal("auth2_pam: internal error: no user");
38
39         if (authctxt->valid) {
40                 conv2.appdata_ptr = authctxt;
41                 pam_set_conv(&conv2);
42         }
43
44         dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
45                      &input_userauth_info_response_pam);
46         retval = (do_pam_authenticate(0) == PAM_SUCCESS);
47         dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
48
49 #if 0           /* ISSUE: No longer valid, but should this still be
50                         handled?? */
51         userauth_log(authctxt, retval, method);
52 #endif
53         return retval;
54 }
55
56 static int
57 do_conversation2(int num_msg, const struct pam_message **msg,
58                  struct pam_response **resp, void *appdata_ptr)
59 {
60         int echo = 0, i = 0, j = 0, done = 0;
61         char *tmp = NULL, *text = NULL;
62
63         context_pam2.finished = 0;
64         context_pam2.num_received = 0;
65         context_pam2.num_expected = 0;
66         context_pam2.prompts = xmalloc(sizeof(int) * num_msg);
67         context_pam2.responses = xmalloc(sizeof(struct pam_response) * num_msg);
68         memset(context_pam2.responses, 0, sizeof(struct pam_response) * num_msg);
69
70         packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
71         packet_put_cstring("");                         /* Name */
72         packet_put_cstring("");                         /* Instructions */
73         packet_put_cstring("");                         /* Language */
74         for (i = 0, j = 0; i < num_msg; i++) {
75                 if((PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_ON) ||
76                    (PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_OFF) ||
77                    (i == num_msg - 1)) {
78                         j++;
79                 }
80         }
81         packet_put_int(j);                              /* Number of prompts. */
82         context_pam2.num_expected = j;
83         for (i = 0, j = 0; i < num_msg; i++) {
84                 switch(PAM_MSG_MEMBER(msg, i, msg_style)) {
85                         case PAM_PROMPT_ECHO_ON:
86                                 echo = 1;
87                                 break;
88                         case PAM_PROMPT_ECHO_OFF:
89                                 echo = 0;
90                                 break;
91                         default:
92                                 echo = 0;
93                                 break;
94                 }
95                 if(text) {
96                         tmp = xmalloc(strlen(text) + strlen(PAM_MSG_MEMBER(msg, i, msg)) + 2);
97                         strcpy(tmp, text);
98                         strcat(tmp, "\n");
99                         strcat(tmp, PAM_MSG_MEMBER(msg, i, msg));
100                         xfree(text);
101                         text = tmp;
102                         tmp = NULL;
103                 } else {
104                         text = xstrdup(PAM_MSG_MEMBER(msg, i, msg));
105                 }
106                 if((PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_ON) ||
107                    (PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_OFF) ||
108                    (i == num_msg - 1)) {
109                         debug("sending prompt ssh-%d(pam-%d) = \"%s\"",
110                               j, i, text);
111                         context_pam2.prompts[j++] = i;
112                         packet_put_cstring(text);
113                         packet_put_char(echo);
114                         xfree(text);
115                         text = NULL;
116                 }
117         }
118         packet_send();
119         packet_write_wait();
120
121         /* Grabbing control of execution and spinning until we get what
122          * we want is probably rude, but it seems to work properly, and
123          * the client *should* be in lock-step with us, so the loop should
124          * only be traversed once. */
125         while(context_pam2.finished == 0) {
126                 done = 1;
127                 dispatch_run(DISPATCH_BLOCK, &done, appdata_ptr);
128                 if(context_pam2.finished == 0) {
129                         debug("extra packet during conversation");
130                 }
131         }
132
133         if(context_pam2.num_received == context_pam2.num_expected) {
134                 *resp = context_pam2.responses;
135                 return PAM_SUCCESS;
136         } else {
137                 return PAM_CONV_ERR;
138         }
139 }
140
141 void
142 input_userauth_info_response_pam(int type, int plen, void *ctxt)
143 {
144         Authctxt *authctxt = ctxt;
145         unsigned int nresp = 0, rlen = 0, i = 0;
146         char *resp;
147
148         if (authctxt == NULL)
149                 fatal("input_userauth_info_response_pam: no authentication context");
150
151         if (authctxt->attempt++ >= AUTH_FAIL_MAX)
152                 packet_disconnect("too many failed userauth_requests");
153
154         nresp = packet_get_int();       /* Number of responses. */
155         debug("got %d responses", nresp);
156
157         for (i = 0; i < nresp; i++) {
158                 int j = context_pam2.prompts[i];
159                 resp = packet_get_string(&rlen);
160                 debug("response ssh-%d(pam-%d) = \"%s\"", i, j, resp);
161                 context_pam2.responses[j].resp_retcode = PAM_SUCCESS;
162                 context_pam2.responses[j].resp = xstrdup(resp);
163                 xfree(resp);
164                 context_pam2.num_received++;
165         }
166
167         context_pam2.finished = 1;
168
169         packet_done();
170 }
171
172 #endif
This page took 0.082688 seconds and 5 git commands to generate.