]> andersk Git - openssh.git/blob - auth2-pam.c
Hopefully things did not get mixed around too much. It compiles under
[openssh.git] / 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 "packet.h"
11 #include "xmalloc.h"
12 #include "dispatch.h"
13 #include "log.h"
14
15 struct {
16         int finished, num_received, num_expected;
17         int *prompts;
18         struct pam_response *responses;
19 } context_pam2 = {0, 0, 0, NULL};
20
21 static int do_conversation2(int num_msg, const struct pam_message **msg,
22                             struct pam_response **resp, void *appdata_ptr);
23
24 static struct pam_conv
25 conv2 = {
26         do_conversation2,
27         NULL,
28 };
29
30 void input_userauth_info_response_pam(int type, int plen, void *ctxt);
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         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_conversation2(int num_msg, const struct pam_message **msg,
53                  struct pam_response **resp, void *appdata_ptr)
54 {
55         int echo = 0, i = 0, j = 0, done = 0;
56         char *tmp = NULL, *text = NULL;
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         packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
66         packet_put_cstring("");                         /* Name */
67         packet_put_cstring("");                         /* Instructions */
68         packet_put_cstring("");                         /* Language */
69         for (i = 0, j = 0; i < num_msg; i++) {
70                 if((PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_ON) ||
71                    (PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_OFF) ||
72                    (i == num_msg - 1)) {
73                         j++;
74                 }
75         }
76         packet_put_int(j);                              /* Number of prompts. */
77         context_pam2.num_expected = j;
78         for (i = 0, j = 0; i < num_msg; i++) {
79                 switch(PAM_MSG_MEMBER(msg, i, msg_style)) {
80                         case PAM_PROMPT_ECHO_ON:
81                                 echo = 1;
82                                 break;
83                         case PAM_PROMPT_ECHO_OFF:
84                                 echo = 0;
85                                 break;
86                         default:
87                                 echo = 0;
88                                 break;
89                 }
90                 if(text) {
91                         tmp = xmalloc(strlen(text) + strlen(PAM_MSG_MEMBER(msg, i, msg)) + 2);
92                         strcpy(tmp, text);
93                         strcat(tmp, "\n");
94                         strcat(tmp, PAM_MSG_MEMBER(msg, i, msg));
95                         xfree(text);
96                         text = tmp;
97                         tmp = NULL;
98                 } else {
99                         text = xstrdup(PAM_MSG_MEMBER(msg, i, msg));
100                 }
101                 if((PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_ON) ||
102                    (PAM_MSG_MEMBER(msg, i, msg_style) == PAM_PROMPT_ECHO_OFF) ||
103                    (i == num_msg - 1)) {
104                         debug("sending prompt ssh-%d(pam-%d) = \"%s\"",
105                               j, i, text);
106                         context_pam2.prompts[j++] = i;
107                         packet_put_cstring(text);
108                         packet_put_char(echo);
109                         xfree(text);
110                         text = NULL;
111                 }
112         }
113         packet_send();
114         packet_write_wait();
115
116         /* Grabbing control of execution and spinning until we get what
117          * we want is probably rude, but it seems to work properly, and
118          * the client *should* be in lock-step with us, so the loop should
119          * only be traversed once. */
120         while(context_pam2.finished == 0) {
121                 done = 1;
122                 dispatch_run(DISPATCH_BLOCK, &done, appdata_ptr);
123                 if(context_pam2.finished == 0) {
124                         debug("extra packet during conversation");
125                 }
126         }
127
128         if(context_pam2.num_received == context_pam2.num_expected) {
129                 *resp = context_pam2.responses;
130                 return PAM_SUCCESS;
131         } else {
132                 return PAM_CONV_ERR;
133         }
134 }
135
136 void
137 input_userauth_info_response_pam(int type, int plen, void *ctxt)
138 {
139         Authctxt *authctxt = ctxt;
140         unsigned int nresp = 0, rlen = 0, i = 0;
141         char *resp;
142
143         if (authctxt == NULL)
144                 fatal("input_userauth_info_response_pam: no authentication context");
145
146         if (authctxt->attempt++ >= AUTH_FAIL_MAX)
147                 packet_disconnect("too many failed userauth_requests");
148
149         nresp = packet_get_int();       /* Number of responses. */
150         debug("got %d responses", nresp);
151
152         for (i = 0; i < nresp; i++) {
153                 int j = context_pam2.prompts[i];
154                 resp = packet_get_string(&rlen);
155                 debug("response ssh-%d(pam-%d) = \"%s\"", i, j, resp);
156                 context_pam2.responses[j].resp_retcode = PAM_SUCCESS;
157                 context_pam2.responses[j].resp = xstrdup(resp);
158                 xfree(resp);
159                 context_pam2.num_received++;
160         }
161
162         context_pam2.finished = 1;
163
164         packet_done();
165 }
166
167 #endif
This page took 0.059472 seconds and 5 git commands to generate.