1 /*
2  * ProFTPD - mod_sftp keyboard-interactive driver mgmt
3  * Copyright (c) 2008-2020 TJ Saunders
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18  *
19  * As a special exemption, TJ Saunders and other respective copyright holders
20  * give permission to link this program with OpenSSL, and distribute the
21  * resulting executable, without including the source code for OpenSSL in the
22  * source distribution.
23  */
24 
25 #include "mod_sftp.h"
26 #include "ssh2.h"
27 #include "packet.h"
28 #include "msg.h"
29 #include "utf8.h"
30 #include "kbdint.h"
31 
32 #define SFTP_KBDINT_MAX_RESPONSES	500
33 
34 extern pr_response_t *resp_list, *resp_err_list;
35 
36 struct kbdint_driver {
37   struct kbdint_driver *next, *prev;
38 
39   const char *name;
40   sftp_kbdint_driver_t *driver;
41 };
42 
43 static pool *kbdint_pool = NULL;
44 static struct kbdint_driver *drivers = NULL;
45 static unsigned int ndrivers = 0;
46 
47 static const char *trace_channel = "ssh2";
48 
sftp_kbdint_have_drivers(void)49 unsigned int sftp_kbdint_have_drivers(void) {
50   return ndrivers;
51 }
52 
sftp_kbdint_get_driver(const char * name)53 sftp_kbdint_driver_t *sftp_kbdint_get_driver(const char *name) {
54   struct kbdint_driver *kd;
55 
56   if (name == NULL) {
57     errno = EINVAL;
58     return NULL;
59   }
60 
61   for (kd = drivers; kd; kd = kd->next) {
62     if (strcmp(kd->name, name) == 0) {
63       return kd->driver;
64     }
65   }
66 
67   errno = ENOENT;
68   return NULL;
69 }
70 
71 static struct kbdint_driver *kdi = NULL;
72 
sftp_kbdint_first_driver(void)73 sftp_kbdint_driver_t *sftp_kbdint_first_driver(void) {
74   sftp_kbdint_driver_t *d = NULL;
75 
76   if (drivers == NULL) {
77     errno = ENOENT;
78     return NULL;
79   }
80 
81   if (kdi != NULL) {
82     errno = EPERM;
83     return NULL;
84   }
85 
86   d = drivers->driver;
87   kdi = drivers->next;
88 
89   return d;
90 }
91 
sftp_kbdint_next_driver(void)92 sftp_kbdint_driver_t *sftp_kbdint_next_driver(void) {
93   sftp_kbdint_driver_t *d = NULL;
94 
95   if (drivers == NULL) {
96     errno = ENOENT;
97     return NULL;
98   }
99 
100   if (kdi == NULL) {
101     errno = EPERM;
102     return NULL;
103   }
104 
105   d = kdi->driver;
106   kdi = kdi->next;
107 
108   return d;
109 }
110 
sftp_kbdint_register_driver(const char * name,sftp_kbdint_driver_t * driver)111 int sftp_kbdint_register_driver(const char *name,
112     sftp_kbdint_driver_t *driver) {
113   struct kbdint_driver *kd;
114 
115   if (name == NULL ||
116       driver == NULL) {
117     errno = EINVAL;
118     return -1;
119   }
120 
121   if (kbdint_pool == NULL) {
122     kbdint_pool = make_sub_pool(permanent_pool);
123     pr_pool_tag(kbdint_pool, "SFTP keyboard-interactive API Pool");
124   }
125 
126   /* Make sure that the driver hasn't already been registered. */
127   if (sftp_kbdint_get_driver(name) != NULL) {
128     errno = EEXIST;
129     return -1;
130   }
131 
132   kd = pcalloc(kbdint_pool, sizeof(struct kbdint_driver));
133 
134   /* XXX Should this name string be dup'd from the kbdint_pool? */
135   kd->name = name;
136   driver->driver_name = pstrdup(kbdint_pool, name);
137   kd->driver = driver;
138 
139   if (drivers) {
140     kd->next = drivers;
141 
142   } else {
143     kd->next = NULL;
144   }
145 
146   drivers = kd;
147   ndrivers++;
148 
149   return 0;
150 }
151 
sftp_kbdint_unregister_driver(const char * name)152 int sftp_kbdint_unregister_driver(const char *name) {
153   struct kbdint_driver *kd;
154 
155   if (name == NULL) {
156     errno = EINVAL;
157     return -1;
158   }
159 
160   for (kd = drivers; kd; kd = kd->next) {
161     if (strcmp(kd->name, name) == 0) {
162 
163       if (kd->prev) {
164         kd->prev->next = kd->next;
165 
166       } else {
167         /* If prev is NULL, this is the head of the list. */
168         drivers = kd->next;
169       }
170 
171       if (kd->next)
172         kd->next->prev = kd->prev;
173 
174       kd->next = kd->prev = NULL;
175       ndrivers--;
176 
177       /* NOTE: a counter should be kept of the number of unregistrations,
178        * as the memory for a registration is not freed on unregistration.
179        */
180 
181       return 0;
182     }
183   }
184 
185   errno = ENOENT;
186   return -1;
187 }
188 
189 /* Convenience functions that can be used by the driver implementations
190  * for communicating with the client, without needing to worry about
191  * SSH2 message formatting, I/O, etc.
192  */
193 
sftp_kbdint_send_challenge(const char * user,const char * instruction,uint32_t count,sftp_kbdint_challenge_t * challenges)194 int sftp_kbdint_send_challenge(const char *user, const char *instruction,
195     uint32_t count, sftp_kbdint_challenge_t *challenges) {
196   register unsigned int i;
197   unsigned char *buf, *ptr;
198   uint32_t buflen, bufsz;
199   struct ssh2_packet *pkt;
200   int res;
201 
202   if (count == 0 ||
203       challenges == NULL) {
204     errno = EINVAL;
205     return -1;
206   }
207 
208   pkt = sftp_ssh2_packet_create(kbdint_pool);
209 
210   /* XXX Is this large enough?  Too large? */
211   buflen = bufsz = 3072;
212   buf = ptr = palloc(pkt->pool, bufsz);
213 
214   /* See RFC4256, Section 3.2. */
215   sftp_msg_write_byte(&buf, &buflen, SFTP_SSH2_MSG_USER_AUTH_INFO_REQ);
216 
217   if (user) {
218     sftp_msg_write_string(&buf, &buflen,
219       sftp_utf8_encode_str(pkt->pool, user));
220 
221   } else {
222     /* Empty user strings are allowed. */
223     sftp_msg_write_string(&buf, &buflen, "");
224   }
225 
226   if (instruction) {
227     sftp_msg_write_string(&buf, &buflen,
228       sftp_utf8_encode_str(pkt->pool, instruction));
229 
230   } else {
231     /* Empty instruction strings are allowed. */
232     sftp_msg_write_string(&buf, &buflen, "");
233   }
234 
235   /* Empty language string. */
236   sftp_msg_write_string(&buf, &buflen, "");
237 
238   sftp_msg_write_int(&buf, &buflen, count);
239 
240   for (i = 0; i < count; i++) {
241     sftp_msg_write_string(&buf, &buflen, challenges[i].challenge);
242     sftp_msg_write_bool(&buf, &buflen, challenges[i].display_response);
243   }
244 
245   pkt->payload = ptr;
246   pkt->payload_len = (bufsz - buflen);
247 
248   pr_trace_msg(trace_channel, 9,
249     "sending USER_AUTH_INFO_REQ message to client");
250 
251   res = sftp_ssh2_packet_write(sftp_conn->wfd, pkt);
252   destroy_pool(pkt->pool);
253 
254   return res;
255 }
256 
read_response_packet(pool * p)257 static struct ssh2_packet *read_response_packet(pool *p) {
258   struct ssh2_packet *pkt = NULL;
259 
260   /* Keep looping until we get the desired message, or we time out. */
261   while (pkt == NULL) {
262     int res;
263     char mesg_type;
264 
265     pr_signals_handle();
266 
267     pkt = sftp_ssh2_packet_create(kbdint_pool);
268     res = sftp_ssh2_packet_read(sftp_conn->rfd, pkt);
269     if (res < 0) {
270       int xerrno = errno;
271 
272       destroy_pool(pkt->pool);
273 
274       errno = xerrno;
275       return NULL;
276     }
277 
278     pr_response_clear(&resp_list);
279     pr_response_clear(&resp_err_list);
280 
281     /* Per RFC 4253, Section 11, DEBUG, DISCONNECT, IGNORE, and UNIMPLEMENTED
282      * messages can occur at any time, even during KEX.  We have to be prepared
283      * for this, and Do The Right Thing(tm).
284      */
285 
286     mesg_type = sftp_ssh2_packet_get_mesg_type(pkt);
287 
288     switch (mesg_type) {
289       case SFTP_SSH2_MSG_DEBUG:
290         sftp_ssh2_packet_handle_debug(pkt);
291         pkt = NULL;
292         break;
293 
294       case SFTP_SSH2_MSG_DISCONNECT:
295         sftp_ssh2_packet_handle_disconnect(pkt);
296         pkt = NULL;
297         break;
298 
299       case SFTP_SSH2_MSG_IGNORE:
300         sftp_ssh2_packet_handle_ignore(pkt);
301         pkt = NULL;
302         break;
303 
304       case SFTP_SSH2_MSG_UNIMPLEMENTED:
305         sftp_ssh2_packet_handle_unimplemented(pkt);
306         pkt = NULL;
307         break;
308 
309       case SFTP_SSH2_MSG_USER_AUTH_INFO_RESP:
310         pr_trace_msg(trace_channel, 13,
311           "received expected %s message",
312           sftp_ssh2_packet_get_mesg_type_desc(mesg_type));
313         break;
314 
315       default:
316         (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
317           "expecting USER_AUTH_INFO_RESP message, received %s (%d)",
318           sftp_ssh2_packet_get_mesg_type_desc(mesg_type), mesg_type);
319         destroy_pool(pkt->pool);
320         errno = EPERM;
321         return NULL;
322     }
323   }
324 
325   return pkt;
326 }
327 
sftp_kbdint_recv_response(pool * p,uint32_t expected_count,uint32_t * rcvd_count,const char *** responses)328 int sftp_kbdint_recv_response(pool *p, uint32_t expected_count,
329     uint32_t *rcvd_count, const char ***responses) {
330   register unsigned int i;
331   unsigned char *buf;
332   cmd_rec *cmd;
333   array_header *list;
334   uint32_t buflen, resp_count;
335   struct ssh2_packet *pkt = NULL;
336   pool *resp_pool = NULL;
337 
338   if (p == NULL ||
339       rcvd_count == NULL ||
340       responses == NULL) {
341     errno = EINVAL;
342     return -1;
343   }
344 
345   pkt = read_response_packet(p);
346   if (pkt == NULL) {
347     return -1;
348   }
349 
350   /* Cache a reference to the current response pool used. */
351   resp_pool = pr_response_get_pool();
352   pr_response_set_pool(pkt->pool);
353 
354   cmd = pr_cmd_alloc(pkt->pool, 2, pstrdup(pkt->pool, "USER_AUTH_INFO_RESP"));
355   cmd->arg = "(data)";
356 
357   pr_trace_msg(trace_channel, 9,
358     "reading USER_AUTH_INFO_RESP message from client");
359 
360   buf = pkt->payload;
361   buflen = pkt->payload_len;
362 
363   resp_count = sftp_msg_read_int(pkt->pool, &buf, &buflen);
364 
365   /* Ensure that the number of responses sent by the client is the same
366    * as the number of challenges sent, lest a malicious client attempt to
367    * trick us into allocating too much memory (Bug#3973).
368    */
369   if (resp_count != expected_count) {
370     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
371       "sent %lu %s, but received %lu %s", (unsigned long) expected_count,
372       expected_count != 1 ? "challenges" : "challenge",
373       (unsigned long) resp_count, resp_count != 1 ? "responses" : "response");
374     destroy_pool(pkt->pool);
375     pr_response_set_pool(resp_pool);
376     errno = EPERM;
377     return -1;
378   }
379 
380   if (resp_count > SFTP_KBDINT_MAX_RESPONSES) {
381     (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
382       "received too many responses (%lu > max %lu), rejecting",
383       (unsigned long) resp_count, (unsigned long) SFTP_KBDINT_MAX_RESPONSES);
384     destroy_pool(pkt->pool);
385     pr_response_set_pool(resp_pool);
386     errno = EPERM;
387     return -1;
388   }
389 
390   list = make_array(p, resp_count, sizeof(char *));
391   for (i = 0; i < resp_count; i++) {
392     char *resp;
393 
394     resp = sftp_msg_read_string(pkt->pool, &buf, &buflen);
395     *((char **) push_array(list)) = pstrdup(p, sftp_utf8_decode_str(p, resp));
396   }
397 
398   *rcvd_count = resp_count;
399   *responses = ((const char **) list->elts);
400   destroy_pool(pkt->pool);
401   pr_response_set_pool(resp_pool);
402 
403   return 0;
404 }
405