1 /*
2  * Packet protocol layer for the server side of the SSH-2 userauth
3  * protocol (RFC 4252).
4  */
5 
6 #include <assert.h>
7 
8 #include "putty.h"
9 #include "ssh.h"
10 #include "sshbpp.h"
11 #include "sshppl.h"
12 #include "sshcr.h"
13 #include "sshserver.h"
14 
15 #ifndef NO_GSSAPI
16 #include "sshgssc.h"
17 #include "sshgss.h"
18 #endif
19 
20 struct ssh2_userauth_server_state {
21     int crState;
22 
23     PacketProtocolLayer *transport_layer, *successor_layer;
24     ptrlen session_id;
25 
26     AuthPolicy *authpolicy;
27     const SshServerConfig *ssc;
28 
29     ptrlen username, service, method;
30     unsigned methods, this_method;
31     bool partial_success;
32 
33     AuthKbdInt *aki;
34 
35     PacketProtocolLayer ppl;
36 };
37 
38 static void ssh2_userauth_server_free(PacketProtocolLayer *);
39 static void ssh2_userauth_server_process_queue(PacketProtocolLayer *);
40 
41 static const PacketProtocolLayerVtable ssh2_userauth_server_vtable = {
42     .free = ssh2_userauth_server_free,
43     .process_queue = ssh2_userauth_server_process_queue,
44     .queued_data_size = ssh_ppl_default_queued_data_size,
45     .name = "ssh-userauth",
46     /* other methods are NULL */
47 };
48 
free_auth_kbdint(AuthKbdInt * aki)49 static void free_auth_kbdint(AuthKbdInt *aki)
50 {
51     int i;
52 
53     if (!aki)
54         return;
55 
56     sfree(aki->title);
57     sfree(aki->instruction);
58     for (i = 0; i < aki->nprompts; i++)
59         sfree(aki->prompts[i].prompt);
60     sfree(aki->prompts);
61     sfree(aki);
62 }
63 
ssh2_userauth_server_new(PacketProtocolLayer * successor_layer,AuthPolicy * authpolicy,const SshServerConfig * ssc)64 PacketProtocolLayer *ssh2_userauth_server_new(
65     PacketProtocolLayer *successor_layer, AuthPolicy *authpolicy,
66     const SshServerConfig *ssc)
67 {
68     struct ssh2_userauth_server_state *s =
69         snew(struct ssh2_userauth_server_state);
70     memset(s, 0, sizeof(*s));
71     s->ppl.vt = &ssh2_userauth_server_vtable;
72 
73     s->successor_layer = successor_layer;
74     s->authpolicy = authpolicy;
75     s->ssc = ssc;
76 
77     return &s->ppl;
78 }
79 
ssh2_userauth_server_set_transport_layer(PacketProtocolLayer * userauth,PacketProtocolLayer * transport)80 void ssh2_userauth_server_set_transport_layer(PacketProtocolLayer *userauth,
81                                               PacketProtocolLayer *transport)
82 {
83     struct ssh2_userauth_server_state *s =
84         container_of(userauth, struct ssh2_userauth_server_state, ppl);
85     s->transport_layer = transport;
86 }
87 
ssh2_userauth_server_free(PacketProtocolLayer * ppl)88 static void ssh2_userauth_server_free(PacketProtocolLayer *ppl)
89 {
90     struct ssh2_userauth_server_state *s =
91         container_of(ppl, struct ssh2_userauth_server_state, ppl);
92 
93     if (s->successor_layer)
94         ssh_ppl_free(s->successor_layer);
95 
96     free_auth_kbdint(s->aki);
97 
98     sfree(s);
99 }
100 
ssh2_userauth_server_pop(struct ssh2_userauth_server_state * s)101 static PktIn *ssh2_userauth_server_pop(struct ssh2_userauth_server_state *s)
102 {
103     return pq_pop(s->ppl.in_pq);
104 }
105 
ssh2_userauth_server_add_session_id(struct ssh2_userauth_server_state * s,strbuf * sigdata)106 static void ssh2_userauth_server_add_session_id(
107     struct ssh2_userauth_server_state *s, strbuf *sigdata)
108 {
109     if (s->ppl.remote_bugs & BUG_SSH2_PK_SESSIONID) {
110         put_datapl(sigdata, s->session_id);
111     } else {
112         put_stringpl(sigdata, s->session_id);
113     }
114 }
115 
ssh2_userauth_server_process_queue(PacketProtocolLayer * ppl)116 static void ssh2_userauth_server_process_queue(PacketProtocolLayer *ppl)
117 {
118     struct ssh2_userauth_server_state *s =
119         container_of(ppl, struct ssh2_userauth_server_state, ppl);
120     PktIn *pktin;
121     PktOut *pktout;
122 
123     crBegin(s->crState);
124 
125     s->session_id = ssh2_transport_get_session_id(s->transport_layer);
126 
127     if (s->ssc->banner.ptr) {
128         pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_USERAUTH_BANNER);
129         put_stringpl(pktout, s->ssc->banner);
130         put_stringz(pktout, ""); /* language tag */
131         pq_push(s->ppl.out_pq, pktout);
132     }
133 
134     while (1) {
135         crMaybeWaitUntilV((pktin = ssh2_userauth_server_pop(s)) != NULL);
136         if (pktin->type != SSH2_MSG_USERAUTH_REQUEST) {
137             ssh_proto_error(s->ppl.ssh, "Received unexpected packet when "
138                             "expecting USERAUTH_REQUEST, type %d (%s)",
139                             pktin->type,
140                             ssh2_pkt_type(s->ppl.bpp->pls->kctx,
141                                           s->ppl.bpp->pls->actx, pktin->type));
142             return;
143         }
144 
145         s->username = get_string(pktin);
146         s->service = get_string(pktin);
147         s->method = get_string(pktin);
148 
149         if (!ptrlen_eq_string(s->service, s->successor_layer->vt->name)) {
150             /*
151              * Unconditionally reject authentication for any service
152              * other than the one we're going to hand over to.
153              */
154             pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_USERAUTH_FAILURE);
155             put_stringz(pktout, "");
156             put_bool(pktout, false);
157             pq_push(s->ppl.out_pq, pktout);
158             continue;
159         }
160 
161         s->methods = auth_methods(s->authpolicy);
162         s->partial_success = false;
163 
164         if (ptrlen_eq_string(s->method, "none")) {
165             s->this_method = AUTHMETHOD_NONE;
166             if (!(s->methods & s->this_method))
167                 goto failure;
168 
169             if (!auth_none(s->authpolicy, s->username))
170                 goto failure;
171         } else if (ptrlen_eq_string(s->method, "password")) {
172             bool changing;
173             ptrlen password, new_password, *new_password_ptr;
174 
175             s->this_method = AUTHMETHOD_PASSWORD;
176             if (!(s->methods & s->this_method))
177                 goto failure;
178 
179             changing = get_bool(pktin);
180             password = get_string(pktin);
181 
182             if (changing) {
183                 new_password = get_string(pktin);
184                 new_password_ptr = &new_password;
185             } else {
186                 new_password_ptr = NULL;
187             }
188 
189             int result = auth_password(s->authpolicy, s->username,
190                                        password, new_password_ptr);
191             if (result == 2) {
192                 pktout = ssh_bpp_new_pktout(
193                     s->ppl.bpp, SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ);
194                 put_stringz(pktout, "Please change your password");
195                 put_stringz(pktout, ""); /* language tag */
196                 pq_push(s->ppl.out_pq, pktout);
197                 continue; /* skip USERAUTH_{SUCCESS,FAILURE} epilogue */
198             } else if (result != 1) {
199                 goto failure;
200             }
201         } else if (ptrlen_eq_string(s->method, "publickey")) {
202             bool has_signature, success, send_pk_ok, key_really_ok;
203             ptrlen algorithm, blob, signature;
204             const ssh_keyalg *keyalg;
205             ssh_key *key;
206             strbuf *sigdata;
207 
208             s->this_method = AUTHMETHOD_PUBLICKEY;
209             if (!(s->methods & s->this_method))
210                 goto failure;
211 
212             has_signature = get_bool(pktin);
213             algorithm = get_string(pktin);
214             blob = get_string(pktin);
215 
216             key_really_ok = auth_publickey(s->authpolicy, s->username, blob);
217             send_pk_ok = key_really_ok ||
218                 s->ssc->stunt_pretend_to_accept_any_pubkey;
219 
220             if (!has_signature) {
221                 if (!send_pk_ok)
222                     goto failure;
223 
224                 pktout = ssh_bpp_new_pktout(
225                     s->ppl.bpp, SSH2_MSG_USERAUTH_PK_OK);
226                 put_stringpl(pktout, algorithm);
227                 put_stringpl(pktout, blob);
228                 pq_push(s->ppl.out_pq, pktout);
229                 continue; /* skip USERAUTH_{SUCCESS,FAILURE} epilogue */
230             }
231 
232             if (!key_really_ok)
233                 goto failure;
234 
235             keyalg = find_pubkey_alg_len(algorithm);
236             if (!keyalg)
237                 goto failure;
238             key = ssh_key_new_pub(keyalg, blob);
239             if (!key)
240                 goto failure;
241 
242             sigdata = strbuf_new();
243             ssh2_userauth_server_add_session_id(s, sigdata);
244             put_byte(sigdata, SSH2_MSG_USERAUTH_REQUEST);
245             put_stringpl(sigdata, s->username);
246             put_stringpl(sigdata, s->service);
247             put_stringpl(sigdata, s->method);
248             put_bool(sigdata, has_signature);
249             put_stringpl(sigdata, algorithm);
250             put_stringpl(sigdata, blob);
251 
252             signature = get_string(pktin);
253             success = ssh_key_verify(key, signature,
254                                      ptrlen_from_strbuf(sigdata));
255             ssh_key_free(key);
256             strbuf_free(sigdata);
257 
258             if (!success)
259                 goto failure;
260         } else if (ptrlen_eq_string(s->method, "keyboard-interactive")) {
261             int i, ok;
262             unsigned n;
263 
264             s->this_method = AUTHMETHOD_KBDINT;
265             if (!(s->methods & s->this_method))
266                 goto failure;
267 
268             do {
269                 s->aki = auth_kbdint_prompts(s->authpolicy, s->username);
270                 if (!s->aki)
271                     goto failure;
272 
273                 pktout = ssh_bpp_new_pktout(
274                     s->ppl.bpp, SSH2_MSG_USERAUTH_INFO_REQUEST);
275                 put_stringz(pktout, s->aki->title);
276                 put_stringz(pktout, s->aki->instruction);
277                 put_stringz(pktout, ""); /* language tag */
278                 put_uint32(pktout, s->aki->nprompts);
279                 for (i = 0; i < s->aki->nprompts; i++) {
280                     put_stringz(pktout, s->aki->prompts[i].prompt);
281                     put_bool(pktout, s->aki->prompts[i].echo);
282                 }
283                 pq_push(s->ppl.out_pq, pktout);
284 
285                 crMaybeWaitUntilV(
286                     (pktin = ssh2_userauth_server_pop(s)) != NULL);
287                 if (pktin->type != SSH2_MSG_USERAUTH_INFO_RESPONSE) {
288                     ssh_proto_error(
289                         s->ppl.ssh, "Received unexpected packet when "
290                         "expecting USERAUTH_INFO_RESPONSE, type %d (%s)",
291                         pktin->type,
292                         ssh2_pkt_type(s->ppl.bpp->pls->kctx,
293                                       s->ppl.bpp->pls->actx, pktin->type));
294                     return;
295                 }
296 
297                 n = get_uint32(pktin);
298                 if (n != s->aki->nprompts) {
299                     ssh_proto_error(
300                         s->ppl.ssh, "Received %u keyboard-interactive "
301                         "responses after sending %u prompts",
302                         n, s->aki->nprompts);
303                     return;
304                 }
305 
306                 {
307                     ptrlen *responses = snewn(s->aki->nprompts, ptrlen);
308                     for (i = 0; i < s->aki->nprompts; i++)
309                         responses[i] = get_string(pktin);
310                     ok = auth_kbdint_responses(s->authpolicy, responses);
311                     sfree(responses);
312                 }
313 
314                 free_auth_kbdint(s->aki);
315                 s->aki = NULL;
316             } while (ok == 0);
317 
318             if (ok <= 0)
319                 goto failure;
320         } else {
321             goto failure;
322         }
323 
324         /*
325          * If we get here, we've successfully completed this
326          * authentication step.
327          */
328         if (auth_successful(s->authpolicy, s->username, s->this_method)) {
329             /*
330              * ... and it was the last one, so we're completely done.
331              */
332             pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_USERAUTH_SUCCESS);
333             pq_push(s->ppl.out_pq, pktout);
334             break;
335         } else {
336             /*
337              * ... but another is required, so fall through to
338              * generation of USERAUTH_FAILURE, having first refreshed
339              * the bit mask of available methods.
340              */
341             s->methods = auth_methods(s->authpolicy);
342         }
343         s->partial_success = true;
344 
345       failure:
346         pktout = ssh_bpp_new_pktout(s->ppl.bpp, SSH2_MSG_USERAUTH_FAILURE);
347         {
348             strbuf *list = strbuf_new();
349             if (s->methods & AUTHMETHOD_NONE)
350                 add_to_commasep(list, "none");
351             if (s->methods & AUTHMETHOD_PASSWORD)
352                 add_to_commasep(list, "password");
353             if (s->methods & AUTHMETHOD_PUBLICKEY)
354                 add_to_commasep(list, "publickey");
355             if (s->methods & AUTHMETHOD_KBDINT)
356                 add_to_commasep(list, "keyboard-interactive");
357             put_stringsb(pktout, list);
358         }
359         put_bool(pktout, s->partial_success);
360         pq_push(s->ppl.out_pq, pktout);
361     }
362 
363     /*
364      * Finally, hand over to our successor layer, and return
365      * immediately without reaching the crFinishV: ssh_ppl_replace
366      * will have freed us, so crFinishV's zeroing-out of crState would
367      * be a use-after-free bug.
368      */
369     {
370         PacketProtocolLayer *successor = s->successor_layer;
371         s->successor_layer = NULL;     /* avoid freeing it ourself */
372         ssh_ppl_replace(&s->ppl, successor);
373         return;   /* we've just freed s, so avoid even touching s->crState */
374     }
375 
376     crFinishV;
377 }
378