1 /* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
2  * Copyright (c) 2005 Mikhail Gusarov <dottedmag@dottedmag.net>
3  * Copyright (c) 2009-2014 by Daniel Stenberg
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms,
7  * with or without modification, are permitted provided
8  * that the following conditions are met:
9  *
10  *   Redistributions of source code must retain the above
11  *   copyright notice, this list of conditions and the
12  *   following disclaimer.
13  *
14  *   Redistributions in binary form must reproduce the above
15  *   copyright notice, this list of conditions and the following
16  *   disclaimer in the documentation and/or other materials
17  *   provided with the distribution.
18  *
19  *   Neither the name of the copyright holder nor the names
20  *   of any other contributors may be used to endorse or
21  *   promote products derived from this software without
22  *   specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
25  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
26  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
29  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
34  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
36  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
37  * OF SUCH DAMAGE.
38  */
39 
40 #include "libssh2_priv.h"
41 
42 #include <ctype.h>
43 #include <stdio.h>
44 
45 #include <assert.h>
46 
47 /* Needed for struct iovec on some platforms */
48 #ifdef HAVE_SYS_UIO_H
49 #include <sys/uio.h>
50 #endif
51 
52 #include "transport.h"
53 #include "session.h"
54 #include "userauth.h"
55 
56 /* libssh2_userauth_list
57  *
58  * List authentication methods
59  * Will yield successful login if "none" happens to be allowable for this user
60  * Not a common configuration for any SSH server though
61  * username should be NULL, or a null terminated string
62  */
userauth_list(LIBSSH2_SESSION * session,const char * username,unsigned int username_len)63 static char *userauth_list(LIBSSH2_SESSION *session, const char *username,
64                            unsigned int username_len)
65 {
66     static const unsigned char reply_codes[3] =
67         { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
68     /* packet_type(1) + username_len(4) + service_len(4) +
69        service(14)"ssh-connection" + method_len(4) = 27 */
70     unsigned long methods_len;
71     unsigned char *s;
72     int rc;
73 
74     if (session->userauth_list_state == libssh2_NB_state_idle) {
75         /* Zero the whole thing out */
76         memset(&session->userauth_list_packet_requirev_state, 0,
77                sizeof(session->userauth_list_packet_requirev_state));
78 
79         session->userauth_list_data_len = username_len + 27;
80 
81         s = session->userauth_list_data =
82             LIBSSH2_ALLOC(session, session->userauth_list_data_len);
83         if (!session->userauth_list_data) {
84             _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
85                            "Unable to allocate memory for userauth_list");
86             return NULL;
87         }
88 
89         *(s++) = SSH_MSG_USERAUTH_REQUEST;
90         _libssh2_store_str(&s, username, username_len);
91         _libssh2_store_str(&s, "ssh-connection", 14);
92         _libssh2_store_u32(&s, 4); /* send "none" separately */
93 
94         session->userauth_list_state = libssh2_NB_state_created;
95     }
96 
97     if (session->userauth_list_state == libssh2_NB_state_created) {
98         rc = _libssh2_transport_send(session, session->userauth_list_data,
99                                      session->userauth_list_data_len,
100                                      (unsigned char *)"none", 4);
101         if (rc == LIBSSH2_ERROR_EAGAIN) {
102             _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
103                            "Would block requesting userauth list");
104             return NULL;
105         }
106         /* now free the packet that was sent */
107         LIBSSH2_FREE(session, session->userauth_list_data);
108         session->userauth_list_data = NULL;
109 
110         if (rc) {
111             _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
112                            "Unable to send userauth-none request");
113             session->userauth_list_state = libssh2_NB_state_idle;
114             return NULL;
115         }
116 
117         session->userauth_list_state = libssh2_NB_state_sent;
118     }
119 
120     if (session->userauth_list_state == libssh2_NB_state_sent) {
121         rc = _libssh2_packet_requirev(session, reply_codes,
122                                       &session->userauth_list_data,
123                                       &session->userauth_list_data_len, 0,
124                                       NULL, 0,
125                                       &session->userauth_list_packet_requirev_state);
126         if (rc == LIBSSH2_ERROR_EAGAIN) {
127             _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
128                            "Would block requesting userauth list");
129             return NULL;
130         } else if (rc) {
131             _libssh2_error(session, rc, "Failed getting response");
132             session->userauth_list_state = libssh2_NB_state_idle;
133             return NULL;
134         }
135 
136         if (session->userauth_list_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
137             /* Wow, who'dve thought... */
138             _libssh2_error(session, LIBSSH2_ERROR_NONE, "No error");
139             LIBSSH2_FREE(session, session->userauth_list_data);
140             session->userauth_list_data = NULL;
141             session->state |= LIBSSH2_STATE_AUTHENTICATED;
142             session->userauth_list_state = libssh2_NB_state_idle;
143             return NULL;
144         }
145 
146         methods_len = _libssh2_ntohu32(session->userauth_list_data + 1);
147 
148         /* Do note that the memory areas overlap! */
149         memmove(session->userauth_list_data, session->userauth_list_data + 5,
150                 methods_len);
151         session->userauth_list_data[methods_len] = '\0';
152         _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
153                        "Permitted auth methods: %s",
154                        session->userauth_list_data);
155     }
156 
157     session->userauth_list_state = libssh2_NB_state_idle;
158     return (char *) session->userauth_list_data;
159 }
160 
161 /* libssh2_userauth_list
162  *
163  * List authentication methods
164  * Will yield successful login if "none" happens to be allowable for this user
165  * Not a common configuration for any SSH server though
166  * username should be NULL, or a null terminated string
167  */
168 LIBSSH2_API char *
libssh2_userauth_list(LIBSSH2_SESSION * session,const char * user,unsigned int user_len)169 libssh2_userauth_list(LIBSSH2_SESSION * session, const char *user,
170                       unsigned int user_len)
171 {
172     char *ptr;
173     BLOCK_ADJUST_ERRNO(ptr, session,
174                        userauth_list(session, user, user_len));
175     return ptr;
176 }
177 
178 /*
179  * libssh2_userauth_authenticated
180  *
181  * Returns: 0 if not yet authenticated
182  *          1 if already authenticated
183  */
184 LIBSSH2_API int
libssh2_userauth_authenticated(LIBSSH2_SESSION * session)185 libssh2_userauth_authenticated(LIBSSH2_SESSION * session)
186 {
187     return (session->state & LIBSSH2_STATE_AUTHENTICATED)?1:0;
188 }
189 
190 
191 
192 /* userauth_password
193  * Plain ol' login
194  */
195 static int
userauth_password(LIBSSH2_SESSION * session,const char * username,unsigned int username_len,const unsigned char * password,unsigned int password_len,LIBSSH2_PASSWD_CHANGEREQ_FUNC ((* passwd_change_cb)))196 userauth_password(LIBSSH2_SESSION *session,
197                   const char *username, unsigned int username_len,
198                   const unsigned char *password, unsigned int password_len,
199                   LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)))
200 {
201     unsigned char *s;
202     static const unsigned char reply_codes[4] =
203         { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE,
204           SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0
205         };
206     int rc;
207 
208     if (session->userauth_pswd_state == libssh2_NB_state_idle) {
209         /* Zero the whole thing out */
210         memset(&session->userauth_pswd_packet_requirev_state, 0,
211                sizeof(session->userauth_pswd_packet_requirev_state));
212 
213         /*
214          * 40 = packet_type(1) + username_len(4) + service_len(4) +
215          * service(14)"ssh-connection" + method_len(4) + method(8)"password" +
216          * chgpwdbool(1) + password_len(4) */
217         session->userauth_pswd_data_len = username_len + 40;
218 
219         session->userauth_pswd_data0 =
220             (unsigned char) ~SSH_MSG_USERAUTH_PASSWD_CHANGEREQ;
221 
222         /* TODO: remove this alloc with a fixed buffer in the session
223            struct */
224         s = session->userauth_pswd_data =
225             LIBSSH2_ALLOC(session, session->userauth_pswd_data_len);
226         if (!session->userauth_pswd_data) {
227             return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
228                                   "Unable to allocate memory for "
229                                   "userauth-password request");
230         }
231 
232         *(s++) = SSH_MSG_USERAUTH_REQUEST;
233         _libssh2_store_str(&s, username, username_len);
234         _libssh2_store_str(&s, "ssh-connection", sizeof("ssh-connection") - 1);
235         _libssh2_store_str(&s, "password", sizeof("password") - 1);
236         *s++ = '\0';
237         _libssh2_store_u32(&s, password_len);
238         /* 'password' is sent separately */
239 
240         _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
241                        "Attempting to login using password authentication");
242 
243         session->userauth_pswd_state = libssh2_NB_state_created;
244     }
245 
246     if (session->userauth_pswd_state == libssh2_NB_state_created) {
247         rc = _libssh2_transport_send(session, session->userauth_pswd_data,
248                                      session->userauth_pswd_data_len,
249                                      password, password_len);
250         if (rc == LIBSSH2_ERROR_EAGAIN) {
251             return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
252                                   "Would block writing password request");
253         }
254 
255         /* now free the sent packet */
256         LIBSSH2_FREE(session, session->userauth_pswd_data);
257         session->userauth_pswd_data = NULL;
258 
259         if (rc) {
260             session->userauth_pswd_state = libssh2_NB_state_idle;
261             return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
262                                   "Unable to send userauth-password request");
263         }
264 
265         session->userauth_pswd_state = libssh2_NB_state_sent;
266     }
267 
268   password_response:
269 
270     if ((session->userauth_pswd_state == libssh2_NB_state_sent)
271         || (session->userauth_pswd_state == libssh2_NB_state_sent1)
272         || (session->userauth_pswd_state == libssh2_NB_state_sent2)) {
273         if (session->userauth_pswd_state == libssh2_NB_state_sent) {
274             rc = _libssh2_packet_requirev(session, reply_codes,
275                                           &session->userauth_pswd_data,
276                                           &session->userauth_pswd_data_len,
277                                           0, NULL, 0,
278                                           &session->
279                                           userauth_pswd_packet_requirev_state);
280 
281             if (rc) {
282                 if (rc != LIBSSH2_ERROR_EAGAIN)
283                     session->userauth_pswd_state = libssh2_NB_state_idle;
284 
285                 return _libssh2_error(session, rc,
286                                       "Waiting for password response");
287             }
288 
289             if (session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
290                 _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
291                                "Password authentication successful");
292                 LIBSSH2_FREE(session, session->userauth_pswd_data);
293                 session->userauth_pswd_data = NULL;
294                 session->state |= LIBSSH2_STATE_AUTHENTICATED;
295                 session->userauth_pswd_state = libssh2_NB_state_idle;
296                 return 0;
297             } else if (session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_FAILURE) {
298                 _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
299                                "Password authentication failed");
300                 LIBSSH2_FREE(session, session->userauth_pswd_data);
301                 session->userauth_pswd_data = NULL;
302                 session->userauth_pswd_state = libssh2_NB_state_idle;
303                 return _libssh2_error(session,
304                                       LIBSSH2_ERROR_AUTHENTICATION_FAILED,
305                                       "Authentication failed "
306                                       "(username/password)");
307             }
308 
309             session->userauth_pswd_newpw = NULL;
310             session->userauth_pswd_newpw_len = 0;
311 
312             session->userauth_pswd_state = libssh2_NB_state_sent1;
313         }
314 
315         if ((session->userauth_pswd_data[0] ==
316              SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)
317             || (session->userauth_pswd_data0 ==
318                 SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)) {
319             session->userauth_pswd_data0 = SSH_MSG_USERAUTH_PASSWD_CHANGEREQ;
320 
321             if ((session->userauth_pswd_state == libssh2_NB_state_sent1) ||
322                 (session->userauth_pswd_state == libssh2_NB_state_sent2)) {
323                 if (session->userauth_pswd_state == libssh2_NB_state_sent1) {
324                     _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
325                                    "Password change required");
326                     LIBSSH2_FREE(session, session->userauth_pswd_data);
327                     session->userauth_pswd_data = NULL;
328                 }
329                 if (passwd_change_cb) {
330                     if (session->userauth_pswd_state == libssh2_NB_state_sent1) {
331                         passwd_change_cb(session,
332                                          &session->userauth_pswd_newpw,
333                                          &session->userauth_pswd_newpw_len,
334                                          &session->abstract);
335                         if (!session->userauth_pswd_newpw) {
336                             return _libssh2_error(session,
337                                                   LIBSSH2_ERROR_PASSWORD_EXPIRED,
338                                                   "Password expired, and "
339                                                   "callback failed");
340                         }
341 
342                         /* basic data_len + newpw_len(4) */
343                         session->userauth_pswd_data_len =
344                             username_len + password_len + 44;
345 
346                         s = session->userauth_pswd_data =
347                             LIBSSH2_ALLOC(session,
348                                           session->userauth_pswd_data_len);
349                         if (!session->userauth_pswd_data) {
350                             LIBSSH2_FREE(session,
351                                          session->userauth_pswd_newpw);
352                             session->userauth_pswd_newpw = NULL;
353                             return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
354                                                   "Unable to allocate memory "
355                                                   "for userauth password "
356                                                   "change request");
357                         }
358 
359                         *(s++) = SSH_MSG_USERAUTH_REQUEST;
360                         _libssh2_store_str(&s, username, username_len);
361                         _libssh2_store_str(&s, "ssh-connection",
362                                            sizeof("ssh-connection") - 1);
363                         _libssh2_store_str(&s, "password",
364                                            sizeof("password") - 1);
365                         *s++ = 0x01;
366                         _libssh2_store_str(&s, (char *)password, password_len);
367                         _libssh2_store_u32(&s,
368                                            session->userauth_pswd_newpw_len);
369                         /* send session->userauth_pswd_newpw separately */
370 
371                         session->userauth_pswd_state = libssh2_NB_state_sent2;
372                     }
373 
374                     if (session->userauth_pswd_state == libssh2_NB_state_sent2) {
375                         rc = _libssh2_transport_send(session,
376                                                      session->userauth_pswd_data,
377                                                      session->userauth_pswd_data_len,
378                                                      (unsigned char *)
379                                                      session->userauth_pswd_newpw,
380                                                      session->userauth_pswd_newpw_len);
381                         if (rc == LIBSSH2_ERROR_EAGAIN) {
382                             return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
383                                                   "Would block waiting");
384                         }
385 
386                         /* free the allocated packets again */
387                         LIBSSH2_FREE(session, session->userauth_pswd_data);
388                         session->userauth_pswd_data = NULL;
389                         LIBSSH2_FREE(session, session->userauth_pswd_newpw);
390                         session->userauth_pswd_newpw = NULL;
391 
392                         if (rc) {
393                             return _libssh2_error(session,
394                                                   LIBSSH2_ERROR_SOCKET_SEND,
395                                                   "Unable to send userauth "
396                                                   "password-change request");
397                         }
398 
399                         /*
400                          * Ugliest use of goto ever.  Blame it on the
401                          * askN => requirev migration.
402                          */
403                         session->userauth_pswd_state = libssh2_NB_state_sent;
404                         goto password_response;
405                     }
406                 }
407             } else {
408                 session->userauth_pswd_state = libssh2_NB_state_idle;
409                 return _libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED,
410                                       "Password Expired, and no callback "
411                                       "specified");
412             }
413         }
414     }
415 
416     /* FAILURE */
417     LIBSSH2_FREE(session, session->userauth_pswd_data);
418     session->userauth_pswd_data = NULL;
419     session->userauth_pswd_state = libssh2_NB_state_idle;
420 
421     return _libssh2_error(session, LIBSSH2_ERROR_AUTHENTICATION_FAILED,
422                           "Authentication failed");
423 }
424 
425 /*
426  * libssh2_userauth_password_ex
427  *
428  * Plain ol' login
429  */
430 
431 LIBSSH2_API int
libssh2_userauth_password_ex(LIBSSH2_SESSION * session,const char * username,unsigned int username_len,const char * password,unsigned int password_len,LIBSSH2_PASSWD_CHANGEREQ_FUNC ((* passwd_change_cb)))432 libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username,
433                              unsigned int username_len, const char *password,
434                              unsigned int password_len,
435                              LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)))
436 {
437     int rc;
438     BLOCK_ADJUST(rc, session,
439                  userauth_password(session, username, username_len,
440                                    (unsigned char *)password, password_len,
441                                    passwd_change_cb));
442     return rc;
443 }
444 
445 static int
memory_read_publickey(LIBSSH2_SESSION * session,unsigned char ** method,size_t * method_len,unsigned char ** pubkeydata,size_t * pubkeydata_len,const char * pubkeyfiledata,size_t pubkeyfiledata_len)446 memory_read_publickey(LIBSSH2_SESSION * session, unsigned char **method,
447                       size_t *method_len,
448                       unsigned char **pubkeydata,
449                       size_t *pubkeydata_len,
450                       const char *pubkeyfiledata,
451                       size_t pubkeyfiledata_len)
452 {
453     unsigned char *pubkey = NULL, *sp1, *sp2, *tmp;
454     size_t pubkey_len = pubkeyfiledata_len;
455     unsigned int tmp_len;
456 
457     if (pubkeyfiledata_len <= 1) {
458         return _libssh2_error(session, LIBSSH2_ERROR_FILE,
459                               "Invalid data in public key file");
460     }
461 
462     pubkey = LIBSSH2_ALLOC(session, pubkeyfiledata_len);
463     if (!pubkey) {
464         return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
465                               "Unable to allocate memory for public key data");
466     }
467 
468     memcpy(pubkey, pubkeyfiledata, pubkeyfiledata_len);
469 
470     /*
471      *   Remove trailing whitespace
472      */
473     while (pubkey_len && isspace(pubkey[pubkey_len - 1]))
474         pubkey_len--;
475 
476     if (!pubkey_len) {
477         LIBSSH2_FREE(session, pubkey);
478         return _libssh2_error(session, LIBSSH2_ERROR_FILE,
479                               "Missing public key data");
480     }
481 
482     if ((sp1 = memchr(pubkey, ' ', pubkey_len)) == NULL) {
483         LIBSSH2_FREE(session, pubkey);
484         return _libssh2_error(session, LIBSSH2_ERROR_FILE,
485                               "Invalid public key data");
486     }
487 
488     sp1++;
489 
490     if ((sp2 = memchr(sp1, ' ', pubkey_len - (sp1 - pubkey - 1))) == NULL) {
491         /* Assume that the id string is missing, but that it's okay */
492         sp2 = pubkey + pubkey_len;
493     }
494 
495     if (libssh2_base64_decode(session, (char **) &tmp, &tmp_len,
496                               (char *) sp1, sp2 - sp1)) {
497         LIBSSH2_FREE(session, pubkey);
498         return _libssh2_error(session, LIBSSH2_ERROR_FILE,
499                                   "Invalid key data, not base64 encoded");
500     }
501 
502     /* Wasting some bytes here (okay, more than some), but since it's likely
503      * to be freed soon anyway, we'll just avoid the extra free/alloc and call
504      * it a wash
505      */
506     *method = pubkey;
507     *method_len = sp1 - pubkey - 1;
508 
509     *pubkeydata = tmp;
510     *pubkeydata_len = tmp_len;
511 
512     return 0;
513 }
514 
515 /*
516  * file_read_publickey
517  *
518  * Read a public key from an id_???.pub style file
519  *
520  * Returns an allocated string containing the decoded key in *pubkeydata
521  * on success.
522  * Returns an allocated string containing the key method (e.g. "ssh-dss")
523  * in method on success.
524  */
525 static int
file_read_publickey(LIBSSH2_SESSION * session,unsigned char ** method,size_t * method_len,unsigned char ** pubkeydata,size_t * pubkeydata_len,const char * pubkeyfile)526 file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method,
527                     size_t *method_len,
528                     unsigned char **pubkeydata,
529                     size_t *pubkeydata_len,
530                     const char *pubkeyfile)
531 {
532     FILE *fd;
533     char c;
534     unsigned char *pubkey = NULL, *sp1, *sp2, *tmp;
535     size_t pubkey_len = 0, sp_len;
536     unsigned int tmp_len;
537 
538     _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Loading public key file: %s",
539                    pubkeyfile);
540     /* Read Public Key */
541     fd = fopen(pubkeyfile, "r");
542     if (!fd) {
543         return _libssh2_error(session, LIBSSH2_ERROR_FILE,
544                               "Unable to open public key file");
545     }
546     while (!feof(fd) && 1 == fread(&c, 1, 1, fd) && c != '\r' && c != '\n') {
547         pubkey_len++;
548     }
549     rewind(fd);
550 
551     if (pubkey_len <= 1) {
552         fclose(fd);
553         return _libssh2_error(session, LIBSSH2_ERROR_FILE,
554                               "Invalid data in public key file");
555     }
556 
557     pubkey = LIBSSH2_ALLOC(session, pubkey_len);
558     if (!pubkey) {
559         fclose(fd);
560         return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
561                               "Unable to allocate memory for public key data");
562     }
563     if (fread(pubkey, 1, pubkey_len, fd) != pubkey_len) {
564         LIBSSH2_FREE(session, pubkey);
565         fclose(fd);
566         return _libssh2_error(session, LIBSSH2_ERROR_FILE,
567                               "Unable to read public key from file");
568     }
569     fclose(fd);
570     /*
571      * Remove trailing whitespace
572      */
573     while (pubkey_len && isspace(pubkey[pubkey_len - 1])) {
574         pubkey_len--;
575     }
576 
577     if (!pubkey_len) {
578         LIBSSH2_FREE(session, pubkey);
579         return _libssh2_error(session, LIBSSH2_ERROR_FILE,
580                               "Missing public key data");
581     }
582 
583     if ((sp1 = memchr(pubkey, ' ', pubkey_len)) == NULL) {
584         LIBSSH2_FREE(session, pubkey);
585         return _libssh2_error(session, LIBSSH2_ERROR_FILE,
586                               "Invalid public key data");
587     }
588 
589     sp1++;
590 
591     sp_len = sp1 > pubkey ? (sp1 - pubkey) - 1 : 0;
592     if ((sp2 = memchr(sp1, ' ', pubkey_len - sp_len)) == NULL) {
593         /* Assume that the id string is missing, but that it's okay */
594         sp2 = pubkey + pubkey_len;
595     }
596 
597     if (libssh2_base64_decode(session, (char **) &tmp, &tmp_len,
598                               (char *) sp1, sp2 - sp1)) {
599         LIBSSH2_FREE(session, pubkey);
600         return _libssh2_error(session, LIBSSH2_ERROR_FILE,
601                               "Invalid key data, not base64 encoded");
602     }
603 
604     /* Wasting some bytes here (okay, more than some), but since it's likely
605      * to be freed soon anyway, we'll just avoid the extra free/alloc and call
606      * it a wash */
607     *method = pubkey;
608     *method_len = sp1 - pubkey - 1;
609 
610     *pubkeydata = tmp;
611     *pubkeydata_len = tmp_len;
612 
613     return 0;
614 }
615 
616 static int
memory_read_privatekey(LIBSSH2_SESSION * session,const LIBSSH2_HOSTKEY_METHOD ** hostkey_method,void ** hostkey_abstract,const unsigned char * method,int method_len,const char * privkeyfiledata,size_t privkeyfiledata_len,const char * passphrase)617 memory_read_privatekey(LIBSSH2_SESSION * session,
618                        const LIBSSH2_HOSTKEY_METHOD ** hostkey_method,
619                        void **hostkey_abstract,
620                        const unsigned char *method, int method_len,
621                        const char *privkeyfiledata, size_t privkeyfiledata_len,
622                        const char *passphrase)
623 {
624     const LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail =
625         libssh2_hostkey_methods();
626 
627     *hostkey_method = NULL;
628     *hostkey_abstract = NULL;
629     while (*hostkey_methods_avail && (*hostkey_methods_avail)->name) {
630         if ((*hostkey_methods_avail)->initPEMFromMemory
631              && strncmp((*hostkey_methods_avail)->name, (const char *) method,
632                         method_len) == 0) {
633             *hostkey_method = *hostkey_methods_avail;
634             break;
635         }
636         hostkey_methods_avail++;
637     }
638     if (!*hostkey_method) {
639         return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE,
640                               "No handler for specified private key");
641     }
642 
643     if ((*hostkey_method)->
644         initPEMFromMemory(session, privkeyfiledata, privkeyfiledata_len,
645                           (unsigned char *) passphrase,
646                           hostkey_abstract)) {
647         return _libssh2_error(session, LIBSSH2_ERROR_FILE,
648                               "Unable to initialize private key from file");
649     }
650 
651     return 0;
652 }
653 
654 /* libssh2_file_read_privatekey
655  * Read a PEM encoded private key from an id_??? style file
656  */
657 static int
file_read_privatekey(LIBSSH2_SESSION * session,const LIBSSH2_HOSTKEY_METHOD ** hostkey_method,void ** hostkey_abstract,const unsigned char * method,int method_len,const char * privkeyfile,const char * passphrase)658 file_read_privatekey(LIBSSH2_SESSION * session,
659                      const LIBSSH2_HOSTKEY_METHOD ** hostkey_method,
660                      void **hostkey_abstract,
661                      const unsigned char *method, int method_len,
662                      const char *privkeyfile, const char *passphrase)
663 {
664     const LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail =
665         libssh2_hostkey_methods();
666 
667     _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Loading private key file: %s",
668                    privkeyfile);
669     *hostkey_method = NULL;
670     *hostkey_abstract = NULL;
671     while (*hostkey_methods_avail && (*hostkey_methods_avail)->name) {
672         if ((*hostkey_methods_avail)->initPEM
673             && strncmp((*hostkey_methods_avail)->name, (const char *) method,
674                        method_len) == 0) {
675             *hostkey_method = *hostkey_methods_avail;
676             break;
677         }
678         hostkey_methods_avail++;
679     }
680     if (!*hostkey_method) {
681         return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE,
682                               "No handler for specified private key");
683     }
684 
685     if ((*hostkey_method)->
686         initPEM(session, privkeyfile, (unsigned char *) passphrase,
687                 hostkey_abstract)) {
688         return _libssh2_error(session, LIBSSH2_ERROR_FILE,
689                               "Unable to initialize private key from file");
690     }
691 
692     return 0;
693 }
694 
695 struct privkey_file {
696     const char *filename;
697     const char *passphrase;
698 };
699 
700 static int
sign_frommemory(LIBSSH2_SESSION * session,unsigned char ** sig,size_t * sig_len,const unsigned char * data,size_t data_len,void ** abstract)701 sign_frommemory(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
702                 const unsigned char *data, size_t data_len, void **abstract)
703 {
704     struct privkey_file *pk_file = (struct privkey_file *) (*abstract);
705     const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
706     void *hostkey_abstract;
707     struct iovec datavec;
708     int rc;
709 
710     rc = memory_read_privatekey(session, &privkeyobj, &hostkey_abstract,
711                                 session->userauth_pblc_method,
712                                 session->userauth_pblc_method_len,
713                                 pk_file->filename,
714                                 strlen(pk_file->filename),
715                                 pk_file->passphrase);
716     if(rc)
717         return rc;
718 
719     datavec.iov_base = (void *)data;
720     datavec.iov_len  = data_len;
721 
722     if (privkeyobj->signv(session, sig, sig_len, 1, &datavec,
723                           &hostkey_abstract)) {
724         if (privkeyobj->dtor) {
725             privkeyobj->dtor(session, abstract);
726         }
727         return -1;
728     }
729 
730     if (privkeyobj->dtor) {
731         privkeyobj->dtor(session, &hostkey_abstract);
732     }
733     return 0;
734 }
735 
736 static int
sign_fromfile(LIBSSH2_SESSION * session,unsigned char ** sig,size_t * sig_len,const unsigned char * data,size_t data_len,void ** abstract)737 sign_fromfile(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
738               const unsigned char *data, size_t data_len, void **abstract)
739 {
740     struct privkey_file *privkey_file = (struct privkey_file *) (*abstract);
741     const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
742     void *hostkey_abstract;
743     struct iovec datavec;
744     int rc;
745 
746     rc = file_read_privatekey(session, &privkeyobj, &hostkey_abstract,
747                               session->userauth_pblc_method,
748                               session->userauth_pblc_method_len,
749                               privkey_file->filename,
750                               privkey_file->passphrase);
751     if(rc)
752         return rc;
753 
754     datavec.iov_base = (void *)data;
755     datavec.iov_len  = data_len;
756 
757     if (privkeyobj->signv(session, sig, sig_len, 1, &datavec,
758                           &hostkey_abstract)) {
759         if (privkeyobj->dtor) {
760             privkeyobj->dtor(session, &hostkey_abstract);
761         }
762         return -1;
763     }
764 
765     if (privkeyobj->dtor) {
766         privkeyobj->dtor(session, &hostkey_abstract);
767     }
768     return 0;
769 }
770 
771 
772 
773 /* userauth_hostbased_fromfile
774  * Authenticate using a keypair found in the named files
775  */
776 static int
userauth_hostbased_fromfile(LIBSSH2_SESSION * session,const char * username,size_t username_len,const char * publickey,const char * privatekey,const char * passphrase,const char * hostname,size_t hostname_len,const char * local_username,size_t local_username_len)777 userauth_hostbased_fromfile(LIBSSH2_SESSION *session,
778                             const char *username, size_t username_len,
779                             const char *publickey, const char *privatekey,
780                             const char *passphrase, const char *hostname,
781                             size_t hostname_len,
782                             const char *local_username,
783                             size_t local_username_len)
784 {
785     int rc;
786 
787     if (session->userauth_host_state == libssh2_NB_state_idle) {
788         const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
789         unsigned char *pubkeydata, *sig = NULL;
790         size_t pubkeydata_len = 0;
791         size_t sig_len = 0;
792         void *abstract;
793         unsigned char buf[5];
794         struct iovec datavec[4];
795 
796         /* Zero the whole thing out */
797         memset(&session->userauth_host_packet_requirev_state, 0,
798                sizeof(session->userauth_host_packet_requirev_state));
799 
800         if (publickey) {
801             rc = file_read_publickey(session, &session->userauth_host_method,
802                                      &session->userauth_host_method_len,
803                                      &pubkeydata, &pubkeydata_len, publickey);
804             if(rc)
805                 /* Note: file_read_publickey() calls _libssh2_error() */
806                 return rc;
807         }
808         else {
809             /* Compute public key from private key. */
810             rc = _libssh2_pub_priv_keyfile(session,
811                                            &session->userauth_host_method,
812                                            &session->userauth_host_method_len,
813                                            &pubkeydata, &pubkeydata_len,
814                                            privatekey, passphrase);
815             if (rc)
816                 /* libssh2_pub_priv_keyfile calls _libssh2_error() */
817                 return rc;
818         }
819 
820         /*
821          * 52 = packet_type(1) + username_len(4) + servicename_len(4) +
822          * service_name(14)"ssh-connection" + authmethod_len(4) +
823          * authmethod(9)"hostbased" + method_len(4) + pubkeydata_len(4) +
824          * hostname_len(4) + local_username_len(4)
825          */
826         session->userauth_host_packet_len =
827             username_len + session->userauth_host_method_len + hostname_len +
828             local_username_len + pubkeydata_len + 52;
829 
830         /*
831          * Preallocate space for an overall length,  method name again,
832          * and the signature, which won't be any larger than the size of
833          * the publickeydata itself
834          */
835         session->userauth_host_s = session->userauth_host_packet =
836             LIBSSH2_ALLOC(session,
837                           session->userauth_host_packet_len + 4 +
838                           (4 + session->userauth_host_method_len) +
839                           (4 + pubkeydata_len));
840         if (!session->userauth_host_packet) {
841             LIBSSH2_FREE(session, session->userauth_host_method);
842             session->userauth_host_method = NULL;
843             LIBSSH2_FREE(session, pubkeydata);
844             return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
845                                   "Out of memory");
846         }
847 
848         *(session->userauth_host_s++) = SSH_MSG_USERAUTH_REQUEST;
849         _libssh2_store_str(&session->userauth_host_s, username, username_len);
850         _libssh2_store_str(&session->userauth_host_s, "ssh-connection", 14);
851         _libssh2_store_str(&session->userauth_host_s, "hostbased", 9);
852         _libssh2_store_str(&session->userauth_host_s,
853                            (const char *)session->userauth_host_method,
854                            session->userauth_host_method_len);
855         _libssh2_store_str(&session->userauth_host_s, (const char *)pubkeydata,
856                            pubkeydata_len);
857         LIBSSH2_FREE(session, pubkeydata);
858         _libssh2_store_str(&session->userauth_host_s, hostname, hostname_len);
859         _libssh2_store_str(&session->userauth_host_s, local_username,
860                            local_username_len);
861 
862         rc = file_read_privatekey(session, &privkeyobj, &abstract,
863                                   session->userauth_host_method,
864                                   session->userauth_host_method_len,
865                                   privatekey, passphrase);
866         if(rc) {
867             /* Note: file_read_privatekey() calls _libssh2_error() */
868             LIBSSH2_FREE(session, session->userauth_host_method);
869             session->userauth_host_method = NULL;
870             LIBSSH2_FREE(session, session->userauth_host_packet);
871             session->userauth_host_packet = NULL;
872             return rc;
873         }
874 
875         _libssh2_htonu32(buf, session->session_id_len);
876         datavec[0].iov_base = (void *)buf;
877         datavec[0].iov_len = 4;
878         datavec[1].iov_base = (void *)session->session_id;
879         datavec[1].iov_len = session->session_id_len;
880         datavec[2].iov_base = (void *)session->userauth_host_packet;
881         datavec[2].iov_len = session->userauth_host_packet_len;
882 
883         if (privkeyobj && privkeyobj->signv &&
884                           privkeyobj->signv(session, &sig, &sig_len, 3,
885                                             datavec, &abstract)) {
886             LIBSSH2_FREE(session, session->userauth_host_method);
887             session->userauth_host_method = NULL;
888             LIBSSH2_FREE(session, session->userauth_host_packet);
889             session->userauth_host_packet = NULL;
890             if (privkeyobj->dtor) {
891                 privkeyobj->dtor(session, &abstract);
892             }
893             return -1;
894         }
895 
896         if (privkeyobj && privkeyobj->dtor) {
897             privkeyobj->dtor(session, &abstract);
898         }
899 
900         if (sig_len > pubkeydata_len) {
901             unsigned char *newpacket;
902             /* Should *NEVER* happen, but...well.. better safe than sorry */
903             newpacket = LIBSSH2_REALLOC(session, session->userauth_host_packet,
904                                         session->userauth_host_packet_len + 4 +
905                                         (4 + session->userauth_host_method_len)
906                                         + (4 + sig_len)); /* PK sigblob */
907             if (!newpacket) {
908                 LIBSSH2_FREE(session, sig);
909                 LIBSSH2_FREE(session, session->userauth_host_packet);
910                 session->userauth_host_packet = NULL;
911                 LIBSSH2_FREE(session, session->userauth_host_method);
912                 session->userauth_host_method = NULL;
913                 return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
914                                       "Failed allocating additional space for "
915                                       "userauth-hostbased packet");
916             }
917             session->userauth_host_packet = newpacket;
918         }
919 
920         session->userauth_host_s =
921             session->userauth_host_packet + session->userauth_host_packet_len;
922 
923         _libssh2_store_u32(&session->userauth_host_s,
924                            4 + session->userauth_host_method_len + 4 + sig_len);
925         _libssh2_store_str(&session->userauth_host_s,
926                            (const char *)session->userauth_host_method,
927                            session->userauth_host_method_len);
928         LIBSSH2_FREE(session, session->userauth_host_method);
929         session->userauth_host_method = NULL;
930 
931         _libssh2_store_str(&session->userauth_host_s, (const char *)sig,
932                            sig_len);
933         LIBSSH2_FREE(session, sig);
934 
935         _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
936                        "Attempting hostbased authentication");
937 
938         session->userauth_host_state = libssh2_NB_state_created;
939     }
940 
941     if (session->userauth_host_state == libssh2_NB_state_created) {
942         rc = _libssh2_transport_send(session, session->userauth_host_packet,
943                                      session->userauth_host_s -
944                                      session->userauth_host_packet,
945                                      NULL, 0);
946         if (rc == LIBSSH2_ERROR_EAGAIN) {
947             return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block");
948         }
949         else if (rc) {
950             LIBSSH2_FREE(session, session->userauth_host_packet);
951             session->userauth_host_packet = NULL;
952             session->userauth_host_state = libssh2_NB_state_idle;
953             return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
954                                   "Unable to send userauth-hostbased request");
955         }
956         LIBSSH2_FREE(session, session->userauth_host_packet);
957         session->userauth_host_packet = NULL;
958 
959         session->userauth_host_state = libssh2_NB_state_sent;
960     }
961 
962     if (session->userauth_host_state == libssh2_NB_state_sent) {
963         static const unsigned char reply_codes[3] =
964             { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
965         size_t data_len;
966         rc = _libssh2_packet_requirev(session, reply_codes,
967                                       &session->userauth_host_data,
968                                       &data_len, 0, NULL, 0,
969                                       &session->
970                                       userauth_host_packet_requirev_state);
971         if (rc == LIBSSH2_ERROR_EAGAIN) {
972             return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block");
973         }
974 
975         session->userauth_host_state = libssh2_NB_state_idle;
976         if (rc) {
977             return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
978                                   "Auth failed");
979         }
980 
981         if (session->userauth_host_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
982             _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
983                            "Hostbased authentication successful");
984             /* We are us and we've proved it. */
985             LIBSSH2_FREE(session, session->userauth_host_data);
986             session->userauth_host_data = NULL;
987             session->state |= LIBSSH2_STATE_AUTHENTICATED;
988             return 0;
989         }
990     }
991 
992     /* This public key is not allowed for this user on this server */
993     LIBSSH2_FREE(session, session->userauth_host_data);
994     session->userauth_host_data = NULL;
995     return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
996                           "Invalid signature for supplied public key, or bad "
997                           "username/public key combination");
998 }
999 
1000 /* libssh2_userauth_hostbased_fromfile_ex
1001  * Authenticate using a keypair found in the named files
1002  */
1003 LIBSSH2_API int
libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION * session,const char * user,unsigned int user_len,const char * publickey,const char * privatekey,const char * passphrase,const char * host,unsigned int host_len,const char * localuser,unsigned int localuser_len)1004 libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session,
1005                                        const char *user,
1006                                        unsigned int user_len,
1007                                        const char *publickey,
1008                                        const char *privatekey,
1009                                        const char *passphrase,
1010                                        const char *host,
1011                                        unsigned int host_len,
1012                                        const char *localuser,
1013                                        unsigned int localuser_len)
1014 {
1015     int rc;
1016     BLOCK_ADJUST(rc, session,
1017                  userauth_hostbased_fromfile(session, user, user_len,
1018                                              publickey, privatekey,
1019                                              passphrase, host, host_len,
1020                                              localuser, localuser_len));
1021     return rc;
1022 }
1023 
1024 
1025 
1026 int
_libssh2_userauth_publickey(LIBSSH2_SESSION * session,const char * username,unsigned int username_len,const unsigned char * pubkeydata,unsigned long pubkeydata_len,LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC ((* sign_callback)),void * abstract)1027 _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
1028                             const char *username,
1029                             unsigned int username_len,
1030                             const unsigned char *pubkeydata,
1031                             unsigned long pubkeydata_len,
1032                             LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)),
1033                             void *abstract)
1034 {
1035     unsigned char reply_codes[4] =
1036         { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE,
1037           SSH_MSG_USERAUTH_PK_OK, 0
1038         };
1039     int rc;
1040     unsigned char *s;
1041 
1042     if (session->userauth_pblc_state == libssh2_NB_state_idle) {
1043 
1044         /*
1045          * The call to _libssh2_ntohu32 later relies on pubkeydata having at
1046          * least 4 valid bytes containing the length of the method name.
1047          */
1048         if (pubkeydata_len < 4)
1049             return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
1050                                   "Invalid public key, too short");
1051 
1052         /* Zero the whole thing out */
1053         memset(&session->userauth_pblc_packet_requirev_state, 0,
1054                sizeof(session->userauth_pblc_packet_requirev_state));
1055 
1056         /*
1057          * As an optimisation, userauth_publickey_fromfile reuses a
1058          * previously allocated copy of the method name to avoid an extra
1059          * allocation/free.
1060          * For other uses, we allocate and populate it here.
1061          */
1062         if (!session->userauth_pblc_method) {
1063             session->userauth_pblc_method_len = _libssh2_ntohu32(pubkeydata);
1064 
1065             if(session->userauth_pblc_method_len > pubkeydata_len)
1066                 /* the method length simply cannot be longer than the entire
1067                    passed in data, so we use this to detect crazy input
1068                    data */
1069                 return _libssh2_error(session,
1070                                       LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
1071                                       "Invalid public key");
1072 
1073             session->userauth_pblc_method =
1074                 LIBSSH2_ALLOC(session, session->userauth_pblc_method_len);
1075             if (!session->userauth_pblc_method) {
1076                 return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1077                                       "Unable to allocate memory for public key "
1078                                       "data");
1079             }
1080             memcpy(session->userauth_pblc_method, pubkeydata + 4,
1081                    session->userauth_pblc_method_len);
1082         }
1083         /*
1084          * The length of the method name read from plaintext prefix in the
1085          * file must match length embedded in the key.
1086          * TODO: The data should match too but we don't check that. Should we?
1087          */
1088         else if (session->userauth_pblc_method_len !=
1089                  _libssh2_ntohu32(pubkeydata))
1090             return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
1091                                   "Invalid public key");
1092 
1093         /*
1094          * 45 = packet_type(1) + username_len(4) + servicename_len(4) +
1095          * service_name(14)"ssh-connection" + authmethod_len(4) +
1096          * authmethod(9)"publickey" + sig_included(1)'\0' + algmethod_len(4) +
1097          * publickey_len(4)
1098          */
1099         session->userauth_pblc_packet_len =
1100             username_len + session->userauth_pblc_method_len + pubkeydata_len +
1101             45;
1102 
1103         /*
1104          * Preallocate space for an overall length, method name again, and the
1105          * signature, which won't be any larger than the size of the
1106          * publickeydata itself.
1107          *
1108          * Note that the 'pubkeydata_len' extra bytes allocated here will not
1109          * be used in this first send, but will be used in the later one where
1110          * this same allocation is re-used.
1111          */
1112         s = session->userauth_pblc_packet =
1113             LIBSSH2_ALLOC(session,
1114                           session->userauth_pblc_packet_len + 4 +
1115                           (4 + session->userauth_pblc_method_len)
1116                           + (4 + pubkeydata_len));
1117         if (!session->userauth_pblc_packet) {
1118             LIBSSH2_FREE(session, session->userauth_pblc_method);
1119             session->userauth_pblc_method = NULL;
1120             return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1121                                   "Out of memory");
1122         }
1123 
1124         *s++ = SSH_MSG_USERAUTH_REQUEST;
1125         _libssh2_store_str(&s, username, username_len);
1126         _libssh2_store_str(&s, "ssh-connection", 14);
1127         _libssh2_store_str(&s, "publickey", 9);
1128 
1129         session->userauth_pblc_b = s;
1130         /* Not sending signature with *this* packet */
1131         *s++ = 0;
1132 
1133         _libssh2_store_str(&s, (const char *)session->userauth_pblc_method,
1134                            session->userauth_pblc_method_len);
1135         _libssh2_store_str(&s, (const char *)pubkeydata, pubkeydata_len);
1136 
1137         _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
1138                        "Attempting publickey authentication");
1139 
1140         session->userauth_pblc_state = libssh2_NB_state_created;
1141     }
1142 
1143     if (session->userauth_pblc_state == libssh2_NB_state_created) {
1144         rc = _libssh2_transport_send(session, session->userauth_pblc_packet,
1145                                      session->userauth_pblc_packet_len,
1146                                      NULL, 0);
1147         if (rc == LIBSSH2_ERROR_EAGAIN)
1148             return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block");
1149         else if (rc) {
1150             LIBSSH2_FREE(session, session->userauth_pblc_packet);
1151             session->userauth_pblc_packet = NULL;
1152             LIBSSH2_FREE(session, session->userauth_pblc_method);
1153             session->userauth_pblc_method = NULL;
1154             session->userauth_pblc_state = libssh2_NB_state_idle;
1155             return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
1156                                   "Unable to send userauth-publickey request");
1157         }
1158 
1159         session->userauth_pblc_state = libssh2_NB_state_sent;
1160     }
1161 
1162     if (session->userauth_pblc_state == libssh2_NB_state_sent) {
1163         rc = _libssh2_packet_requirev(session, reply_codes,
1164                                       &session->userauth_pblc_data,
1165                                       &session->userauth_pblc_data_len, 0,
1166                                       NULL, 0,
1167                                       &session->
1168                                       userauth_pblc_packet_requirev_state);
1169         if (rc == LIBSSH2_ERROR_EAGAIN) {
1170             return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block");
1171         }
1172         else if (rc) {
1173             LIBSSH2_FREE(session, session->userauth_pblc_packet);
1174             session->userauth_pblc_packet = NULL;
1175             LIBSSH2_FREE(session, session->userauth_pblc_method);
1176             session->userauth_pblc_method = NULL;
1177             session->userauth_pblc_state = libssh2_NB_state_idle;
1178             return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
1179                                   "Waiting for USERAUTH response");
1180         }
1181 
1182         if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
1183             _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
1184                            "Pubkey authentication prematurely successful");
1185             /*
1186              * God help any SSH server that allows an UNVERIFIED
1187              * public key to validate the user
1188              */
1189             LIBSSH2_FREE(session, session->userauth_pblc_data);
1190             session->userauth_pblc_data = NULL;
1191             LIBSSH2_FREE(session, session->userauth_pblc_packet);
1192             session->userauth_pblc_packet = NULL;
1193             LIBSSH2_FREE(session, session->userauth_pblc_method);
1194             session->userauth_pblc_method = NULL;
1195             session->state |= LIBSSH2_STATE_AUTHENTICATED;
1196             session->userauth_pblc_state = libssh2_NB_state_idle;
1197             return 0;
1198         }
1199 
1200         if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_FAILURE) {
1201             /* This public key is not allowed for this user on this server */
1202             LIBSSH2_FREE(session, session->userauth_pblc_data);
1203             session->userauth_pblc_data = NULL;
1204             LIBSSH2_FREE(session, session->userauth_pblc_packet);
1205             session->userauth_pblc_packet = NULL;
1206             LIBSSH2_FREE(session, session->userauth_pblc_method);
1207             session->userauth_pblc_method = NULL;
1208             session->userauth_pblc_state = libssh2_NB_state_idle;
1209             return _libssh2_error(session, LIBSSH2_ERROR_AUTHENTICATION_FAILED,
1210                                   "Username/PublicKey combination invalid");
1211         }
1212 
1213         /* Semi-Success! */
1214         LIBSSH2_FREE(session, session->userauth_pblc_data);
1215         session->userauth_pblc_data = NULL;
1216 
1217         *session->userauth_pblc_b = 0x01;
1218         session->userauth_pblc_state = libssh2_NB_state_sent1;
1219     }
1220 
1221     if (session->userauth_pblc_state == libssh2_NB_state_sent1) {
1222         unsigned char *buf;
1223         unsigned char *sig;
1224         size_t sig_len;
1225 
1226         s = buf = LIBSSH2_ALLOC(session, 4 + session->session_id_len
1227                                 + session->userauth_pblc_packet_len);
1228         if (!buf) {
1229             return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1230                                   "Unable to allocate memory for "
1231                                   "userauth-publickey signed data");
1232         }
1233 
1234         _libssh2_store_str(&s, (const char *)session->session_id,
1235                            session->session_id_len);
1236 
1237         memcpy (s, session->userauth_pblc_packet,
1238                 session->userauth_pblc_packet_len);
1239         s += session->userauth_pblc_packet_len;
1240 
1241         rc = sign_callback(session, &sig, &sig_len, buf, s - buf, abstract);
1242         LIBSSH2_FREE(session, buf);
1243         if (rc == LIBSSH2_ERROR_EAGAIN) {
1244             return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block");
1245         } else if (rc) {
1246             LIBSSH2_FREE(session, session->userauth_pblc_method);
1247             session->userauth_pblc_method = NULL;
1248             LIBSSH2_FREE(session, session->userauth_pblc_packet);
1249             session->userauth_pblc_packet = NULL;
1250             session->userauth_pblc_state = libssh2_NB_state_idle;
1251             return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
1252                                   "Callback returned error");
1253         }
1254 
1255         /*
1256          * If this function was restarted, pubkeydata_len might still be 0
1257          * which will cause an unnecessary but harmless realloc here.
1258          */
1259         if (sig_len > pubkeydata_len) {
1260             unsigned char *newpacket;
1261             /* Should *NEVER* happen, but...well.. better safe than sorry */
1262             newpacket = LIBSSH2_REALLOC(session,
1263                                         session->userauth_pblc_packet,
1264                                         session->userauth_pblc_packet_len + 4 +
1265                                         (4 + session->userauth_pblc_method_len)
1266                                         + (4 + sig_len)); /* PK sigblob */
1267             if (!newpacket) {
1268                 LIBSSH2_FREE(session, sig);
1269                 LIBSSH2_FREE(session, session->userauth_pblc_packet);
1270                 session->userauth_pblc_packet = NULL;
1271                 LIBSSH2_FREE(session, session->userauth_pblc_method);
1272                 session->userauth_pblc_method = NULL;
1273                 session->userauth_pblc_state = libssh2_NB_state_idle;
1274                 return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1275                                       "Failed allocating additional space for "
1276                                       "userauth-publickey packet");
1277             }
1278             session->userauth_pblc_packet = newpacket;
1279         }
1280 
1281         s = session->userauth_pblc_packet + session->userauth_pblc_packet_len;
1282         session->userauth_pblc_b = NULL;
1283 
1284         _libssh2_store_u32(&s,
1285                            4 + session->userauth_pblc_method_len + 4 + sig_len);
1286         _libssh2_store_str(&s, (const char *)session->userauth_pblc_method,
1287                            session->userauth_pblc_method_len);
1288 
1289         LIBSSH2_FREE(session, session->userauth_pblc_method);
1290         session->userauth_pblc_method = NULL;
1291 
1292         _libssh2_store_str(&s, (const char *)sig, sig_len);
1293         LIBSSH2_FREE(session, sig);
1294 
1295         _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
1296                        "Attempting publickey authentication -- phase 2");
1297 
1298         session->userauth_pblc_s = s;
1299         session->userauth_pblc_state = libssh2_NB_state_sent2;
1300     }
1301 
1302     if (session->userauth_pblc_state == libssh2_NB_state_sent2) {
1303         rc = _libssh2_transport_send(session, session->userauth_pblc_packet,
1304                                      session->userauth_pblc_s -
1305                                      session->userauth_pblc_packet,
1306                                      NULL, 0);
1307         if (rc == LIBSSH2_ERROR_EAGAIN) {
1308             return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block");
1309         } else if (rc) {
1310             LIBSSH2_FREE(session, session->userauth_pblc_packet);
1311             session->userauth_pblc_packet = NULL;
1312             session->userauth_pblc_state = libssh2_NB_state_idle;
1313             return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
1314                                   "Unable to send userauth-publickey request");
1315         }
1316         LIBSSH2_FREE(session, session->userauth_pblc_packet);
1317         session->userauth_pblc_packet = NULL;
1318 
1319         session->userauth_pblc_state = libssh2_NB_state_sent3;
1320     }
1321 
1322     /* PK_OK is no longer valid */
1323     reply_codes[2] = 0;
1324 
1325     rc = _libssh2_packet_requirev(session, reply_codes,
1326                                   &session->userauth_pblc_data,
1327                                   &session->userauth_pblc_data_len, 0, NULL, 0,
1328                                   &session->userauth_pblc_packet_requirev_state);
1329     if (rc == LIBSSH2_ERROR_EAGAIN) {
1330         return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
1331                               "Would block requesting userauth list");
1332     } else if (rc) {
1333         session->userauth_pblc_state = libssh2_NB_state_idle;
1334         return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
1335                               "Waiting for publickey USERAUTH response");
1336     }
1337 
1338     if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
1339         _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
1340                        "Publickey authentication successful");
1341         /* We are us and we've proved it. */
1342         LIBSSH2_FREE(session, session->userauth_pblc_data);
1343         session->userauth_pblc_data = NULL;
1344         session->state |= LIBSSH2_STATE_AUTHENTICATED;
1345         session->userauth_pblc_state = libssh2_NB_state_idle;
1346         return 0;
1347     }
1348 
1349     /* This public key is not allowed for this user on this server */
1350     LIBSSH2_FREE(session, session->userauth_pblc_data);
1351     session->userauth_pblc_data = NULL;
1352     session->userauth_pblc_state = libssh2_NB_state_idle;
1353     return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
1354                           "Invalid signature for supplied public key, or bad "
1355                           "username/public key combination");
1356 }
1357 
1358  /*
1359   * userauth_publickey_frommemory
1360   * Authenticate using a keypair from memory
1361   */
1362 static int
userauth_publickey_frommemory(LIBSSH2_SESSION * session,const char * username,size_t username_len,const char * publickeydata,size_t publickeydata_len,const char * privatekeydata,size_t privatekeydata_len,const char * passphrase)1363 userauth_publickey_frommemory(LIBSSH2_SESSION *session,
1364                               const char *username,
1365                               size_t username_len,
1366                               const char *publickeydata,
1367                               size_t publickeydata_len,
1368                               const char *privatekeydata,
1369                               size_t privatekeydata_len,
1370                               const char *passphrase)
1371 {
1372     unsigned char *pubkeydata = NULL;
1373     size_t pubkeydata_len = 0;
1374     struct privkey_file privkey_file;
1375     void *abstract = &privkey_file;
1376     int rc;
1377 
1378     privkey_file.filename = privatekeydata;
1379     privkey_file.passphrase = passphrase;
1380 
1381     if (session->userauth_pblc_state == libssh2_NB_state_idle) {
1382         if (publickeydata_len && publickeydata) {
1383             rc = memory_read_publickey(session, &session->userauth_pblc_method,
1384                                        &session->userauth_pblc_method_len,
1385                                        &pubkeydata, &pubkeydata_len,
1386                                        publickeydata, publickeydata_len);
1387             if(rc)
1388                 return rc;
1389         }
1390         else if (privatekeydata_len && privatekeydata) {
1391             /* Compute public key from private key. */
1392             if (_libssh2_pub_priv_keyfilememory(session,
1393                                                 &session->userauth_pblc_method,
1394                                                 &session->userauth_pblc_method_len,
1395                                                 &pubkeydata, &pubkeydata_len,
1396                                                 privatekeydata, privatekeydata_len,
1397                                                 passphrase))
1398                 return _libssh2_error(session, LIBSSH2_ERROR_FILE,
1399                                       "Unable to extract public key "
1400                                       "from private key.");
1401         }
1402         else {
1403             return _libssh2_error(session, LIBSSH2_ERROR_FILE,
1404                                   "Invalid data in public and private key.");
1405         }
1406     }
1407 
1408     rc = _libssh2_userauth_publickey(session, username, username_len,
1409                                      pubkeydata, pubkeydata_len,
1410                                      sign_frommemory, &abstract);
1411     if(pubkeydata)
1412         LIBSSH2_FREE(session, pubkeydata);
1413 
1414     return rc;
1415 }
1416 
1417 /*
1418  * userauth_publickey_fromfile
1419  * Authenticate using a keypair found in the named files
1420  */
1421 static int
userauth_publickey_fromfile(LIBSSH2_SESSION * session,const char * username,size_t username_len,const char * publickey,const char * privatekey,const char * passphrase)1422 userauth_publickey_fromfile(LIBSSH2_SESSION *session,
1423                             const char *username,
1424                             size_t username_len,
1425                             const char *publickey,
1426                             const char *privatekey,
1427                             const char *passphrase)
1428 {
1429     unsigned char *pubkeydata = NULL;
1430     size_t pubkeydata_len = 0;
1431     struct privkey_file privkey_file;
1432     void *abstract = &privkey_file;
1433     int rc;
1434 
1435     privkey_file.filename = privatekey;
1436     privkey_file.passphrase = passphrase;
1437 
1438     if (session->userauth_pblc_state == libssh2_NB_state_idle) {
1439         if (publickey) {
1440             rc = file_read_publickey(session, &session->userauth_pblc_method,
1441                                      &session->userauth_pblc_method_len,
1442                                      &pubkeydata, &pubkeydata_len,publickey);
1443             if (rc)
1444                 return rc;
1445         }
1446         else {
1447             /* Compute public key from private key. */
1448             rc = _libssh2_pub_priv_keyfile(session,
1449                                            &session->userauth_pblc_method,
1450                                            &session->userauth_pblc_method_len,
1451                                            &pubkeydata, &pubkeydata_len,
1452                                            privatekey, passphrase);
1453 
1454             /* _libssh2_pub_priv_keyfile calls _libssh2_error() */
1455             if (rc)
1456                 return rc;
1457         }
1458     }
1459 
1460     rc = _libssh2_userauth_publickey(session, username, username_len,
1461                                      pubkeydata, pubkeydata_len,
1462                                      sign_fromfile, &abstract);
1463     if(pubkeydata)
1464         LIBSSH2_FREE(session, pubkeydata);
1465 
1466     return rc;
1467 }
1468 
1469 /* libssh2_userauth_publickey_frommemory
1470  * Authenticate using a keypair from memory
1471  */
1472 LIBSSH2_API int
libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION * session,const char * user,size_t user_len,const char * publickeyfiledata,size_t publickeyfiledata_len,const char * privatekeyfiledata,size_t privatekeyfiledata_len,const char * passphrase)1473 libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session,
1474                                       const char *user,
1475                                       size_t user_len,
1476                                       const char *publickeyfiledata,
1477                                       size_t publickeyfiledata_len,
1478                                       const char *privatekeyfiledata,
1479                                       size_t privatekeyfiledata_len,
1480                                       const char *passphrase)
1481 {
1482     int rc;
1483 
1484     if(NULL == passphrase)
1485         /* if given a NULL pointer, make it point to a zero-length
1486            string to save us from having to check this all over */
1487         passphrase="";
1488 
1489     BLOCK_ADJUST(rc, session,
1490                  userauth_publickey_frommemory(session, user, user_len,
1491                                                publickeyfiledata,
1492                                                publickeyfiledata_len,
1493                                                privatekeyfiledata,
1494                                                privatekeyfiledata_len,
1495                                                passphrase));
1496     return rc;
1497 }
1498 
1499 /* libssh2_userauth_publickey_fromfile_ex
1500  * Authenticate using a keypair found in the named files
1501  */
1502 LIBSSH2_API int
libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION * session,const char * user,unsigned int user_len,const char * publickey,const char * privatekey,const char * passphrase)1503 libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
1504                                        const char *user,
1505                                        unsigned int user_len,
1506                                        const char *publickey,
1507                                        const char *privatekey,
1508                                        const char *passphrase)
1509 {
1510     int rc;
1511 
1512     if(NULL == passphrase)
1513         /* if given a NULL pointer, make it point to a zero-length
1514            string to save us from having to check this all over */
1515         passphrase="";
1516 
1517     BLOCK_ADJUST(rc, session,
1518                  userauth_publickey_fromfile(session, user, user_len,
1519                                              publickey, privatekey,
1520                                              passphrase));
1521     return rc;
1522 }
1523 
1524 /* libssh2_userauth_publickey_ex
1525  * Authenticate using an external callback function
1526  */
1527 LIBSSH2_API int
libssh2_userauth_publickey(LIBSSH2_SESSION * session,const char * user,const unsigned char * pubkeydata,size_t pubkeydata_len,LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC ((* sign_callback)),void ** abstract)1528 libssh2_userauth_publickey(LIBSSH2_SESSION *session,
1529                            const char *user,
1530                            const unsigned char *pubkeydata,
1531                            size_t pubkeydata_len,
1532                            LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)),
1533                            void **abstract)
1534 {
1535     int rc;
1536 
1537     if(!session)
1538         return LIBSSH2_ERROR_BAD_USE;
1539 
1540     BLOCK_ADJUST(rc, session,
1541                  _libssh2_userauth_publickey(session, user, strlen(user),
1542                                              pubkeydata, pubkeydata_len,
1543                                              sign_callback, abstract));
1544     return rc;
1545 }
1546 
1547 
1548 
1549 /*
1550  * userauth_keyboard_interactive
1551  *
1552  * Authenticate using a challenge-response authentication
1553  */
1554 static int
userauth_keyboard_interactive(LIBSSH2_SESSION * session,const char * username,unsigned int username_len,LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC ((* response_callback)))1555 userauth_keyboard_interactive(LIBSSH2_SESSION * session,
1556                               const char *username,
1557                               unsigned int username_len,
1558                               LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)))
1559 {
1560     unsigned char *s;
1561     int rc;
1562 
1563     static const unsigned char reply_codes[4] = {
1564         SSH_MSG_USERAUTH_SUCCESS,
1565         SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0
1566     };
1567     unsigned int language_tag_len;
1568     unsigned int i;
1569 
1570     if (session->userauth_kybd_state == libssh2_NB_state_idle) {
1571         session->userauth_kybd_auth_name = NULL;
1572         session->userauth_kybd_auth_instruction = NULL;
1573         session->userauth_kybd_num_prompts = 0;
1574         session->userauth_kybd_auth_failure = 1;
1575         session->userauth_kybd_prompts = NULL;
1576         session->userauth_kybd_responses = NULL;
1577 
1578         /* Zero the whole thing out */
1579         memset(&session->userauth_kybd_packet_requirev_state, 0,
1580                sizeof(session->userauth_kybd_packet_requirev_state));
1581 
1582         session->userauth_kybd_packet_len =
1583             1                   /* byte    SSH_MSG_USERAUTH_REQUEST */
1584             + 4 + username_len  /* string  user name (ISO-10646 UTF-8, as
1585                                    defined in [RFC-3629]) */
1586             + 4 + 14            /* string  service name (US-ASCII) */
1587             + 4 + 20            /* string  "keyboard-interactive" (US-ASCII) */
1588             + 4 + 0             /* string  language tag (as defined in
1589                                    [RFC-3066]) */
1590             + 4 + 0             /* string  submethods (ISO-10646 UTF-8) */
1591             ;
1592 
1593         session->userauth_kybd_data = s =
1594             LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len);
1595         if (!s) {
1596             return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1597                                   "Unable to allocate memory for "
1598                                   "keyboard-interactive authentication");
1599         }
1600 
1601         *s++ = SSH_MSG_USERAUTH_REQUEST;
1602 
1603         /* user name */
1604         _libssh2_store_str(&s, username, username_len);
1605 
1606         /* service name */
1607         _libssh2_store_str(&s, "ssh-connection", sizeof("ssh-connection") - 1);
1608 
1609         /* "keyboard-interactive" */
1610         _libssh2_store_str(&s, "keyboard-interactive",
1611                            sizeof("keyboard-interactive") - 1);
1612         /* language tag */
1613         _libssh2_store_u32(&s, 0);
1614 
1615         /* submethods */
1616         _libssh2_store_u32(&s, 0);
1617 
1618         _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
1619                        "Attempting keyboard-interactive authentication");
1620 
1621         session->userauth_kybd_state = libssh2_NB_state_created;
1622     }
1623 
1624     if (session->userauth_kybd_state == libssh2_NB_state_created) {
1625         rc = _libssh2_transport_send(session, session->userauth_kybd_data,
1626                                      session->userauth_kybd_packet_len,
1627                                      NULL, 0);
1628         if (rc == LIBSSH2_ERROR_EAGAIN) {
1629             return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block");
1630         } else if (rc) {
1631             LIBSSH2_FREE(session, session->userauth_kybd_data);
1632             session->userauth_kybd_data = NULL;
1633             session->userauth_kybd_state = libssh2_NB_state_idle;
1634             return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
1635                                   "Unable to send keyboard-interactive request");
1636         }
1637         LIBSSH2_FREE(session, session->userauth_kybd_data);
1638         session->userauth_kybd_data = NULL;
1639 
1640         session->userauth_kybd_state = libssh2_NB_state_sent;
1641     }
1642 
1643     for(;;) {
1644         if (session->userauth_kybd_state == libssh2_NB_state_sent) {
1645             rc = _libssh2_packet_requirev(session, reply_codes,
1646                                           &session->userauth_kybd_data,
1647                                           &session->userauth_kybd_data_len,
1648                                           0, NULL, 0,
1649                                           &session->
1650                                           userauth_kybd_packet_requirev_state);
1651             if (rc == LIBSSH2_ERROR_EAGAIN) {
1652                 return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
1653                                       "Would block");
1654             } else if (rc) {
1655                 session->userauth_kybd_state = libssh2_NB_state_idle;
1656                 return _libssh2_error(session,
1657                                       LIBSSH2_ERROR_AUTHENTICATION_FAILED,
1658                                       "Waiting for keyboard USERAUTH response");
1659             }
1660 
1661             if (session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
1662                 _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
1663                                "Keyboard-interactive authentication successful");
1664                 LIBSSH2_FREE(session, session->userauth_kybd_data);
1665                 session->userauth_kybd_data = NULL;
1666                 session->state |= LIBSSH2_STATE_AUTHENTICATED;
1667                 session->userauth_kybd_state = libssh2_NB_state_idle;
1668                 return 0;
1669             }
1670 
1671             if (session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_FAILURE) {
1672                 _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
1673                                "Keyboard-interactive authentication failed");
1674                 LIBSSH2_FREE(session, session->userauth_kybd_data);
1675                 session->userauth_kybd_data = NULL;
1676                 session->userauth_kybd_state = libssh2_NB_state_idle;
1677                 return _libssh2_error(session,
1678                                       LIBSSH2_ERROR_AUTHENTICATION_FAILED,
1679                                       "Authentication failed "
1680                                       "(keyboard-interactive)");
1681             }
1682 
1683             /* server requested PAM-like conversation */
1684             s = session->userauth_kybd_data + 1;
1685 
1686             /* string    name (ISO-10646 UTF-8) */
1687             session->userauth_kybd_auth_name_len = _libssh2_ntohu32(s);
1688             s += 4;
1689             if(session->userauth_kybd_auth_name_len) {
1690                 session->userauth_kybd_auth_name =
1691                     LIBSSH2_ALLOC(session,
1692                                   session->userauth_kybd_auth_name_len);
1693                 if (!session->userauth_kybd_auth_name) {
1694                     _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1695                                    "Unable to allocate memory for "
1696                                    "keyboard-interactive 'name' "
1697                                    "request field");
1698                     goto cleanup;
1699                 }
1700                 memcpy(session->userauth_kybd_auth_name, s,
1701                        session->userauth_kybd_auth_name_len);
1702                 s += session->userauth_kybd_auth_name_len;
1703             }
1704 
1705             /* string    instruction (ISO-10646 UTF-8) */
1706             session->userauth_kybd_auth_instruction_len = _libssh2_ntohu32(s);
1707             s += 4;
1708             if(session->userauth_kybd_auth_instruction_len) {
1709                 session->userauth_kybd_auth_instruction =
1710                     LIBSSH2_ALLOC(session,
1711                                   session->userauth_kybd_auth_instruction_len);
1712                 if (!session->userauth_kybd_auth_instruction) {
1713                     _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1714                                    "Unable to allocate memory for "
1715                                    "keyboard-interactive 'instruction' "
1716                                    "request field");
1717                     goto cleanup;
1718                 }
1719                 memcpy(session->userauth_kybd_auth_instruction, s,
1720                        session->userauth_kybd_auth_instruction_len);
1721                 s += session->userauth_kybd_auth_instruction_len;
1722             }
1723 
1724             /* string    language tag (as defined in [RFC-3066]) */
1725             language_tag_len = _libssh2_ntohu32(s);
1726             s += 4;
1727 
1728             /* ignoring this field as deprecated */
1729             s += language_tag_len;
1730 
1731             /* int       num-prompts */
1732             session->userauth_kybd_num_prompts = _libssh2_ntohu32(s);
1733             s += 4;
1734 
1735             if(session->userauth_kybd_num_prompts) {
1736                 session->userauth_kybd_prompts =
1737                     LIBSSH2_CALLOC(session,
1738                                    sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) *
1739                                    session->userauth_kybd_num_prompts);
1740                 if (!session->userauth_kybd_prompts) {
1741                     _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1742                                    "Unable to allocate memory for "
1743                                    "keyboard-interactive prompts array");
1744                     goto cleanup;
1745                 }
1746 
1747                 session->userauth_kybd_responses =
1748                     LIBSSH2_CALLOC(session,
1749                                    sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) *
1750                                    session->userauth_kybd_num_prompts);
1751                 if (!session->userauth_kybd_responses) {
1752                     _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1753                                    "Unable to allocate memory for "
1754                                    "keyboard-interactive responses array");
1755                     goto cleanup;
1756                 }
1757 
1758                 for(i = 0; i < session->userauth_kybd_num_prompts; i++) {
1759                     /* string    prompt[1] (ISO-10646 UTF-8) */
1760                     session->userauth_kybd_prompts[i].length =
1761                         _libssh2_ntohu32(s);
1762                     s += 4;
1763                     session->userauth_kybd_prompts[i].text =
1764                         LIBSSH2_CALLOC(session,
1765                                        session->userauth_kybd_prompts[i].length);
1766                     if (!session->userauth_kybd_prompts[i].text) {
1767                         _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1768                                        "Unable to allocate memory for "
1769                                        "keyboard-interactive prompt message");
1770                         goto cleanup;
1771                     }
1772                     memcpy(session->userauth_kybd_prompts[i].text, s,
1773                            session->userauth_kybd_prompts[i].length);
1774                     s += session->userauth_kybd_prompts[i].length;
1775 
1776                     /* boolean   echo[1] */
1777                     session->userauth_kybd_prompts[i].echo = *s++;
1778                 }
1779             }
1780 
1781             response_callback(session->userauth_kybd_auth_name,
1782                               session->userauth_kybd_auth_name_len,
1783                               session->userauth_kybd_auth_instruction,
1784                               session->userauth_kybd_auth_instruction_len,
1785                               session->userauth_kybd_num_prompts,
1786                               session->userauth_kybd_prompts,
1787                               session->userauth_kybd_responses,
1788                               &session->abstract);
1789 
1790             _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
1791                            "Keyboard-interactive response callback function"
1792                            " invoked");
1793 
1794             session->userauth_kybd_packet_len =
1795                 1 /* byte      SSH_MSG_USERAUTH_INFO_RESPONSE */
1796                 + 4             /* int       num-responses */
1797                 ;
1798 
1799             for(i = 0; i < session->userauth_kybd_num_prompts; i++) {
1800                 /* string    response[1] (ISO-10646 UTF-8) */
1801                 session->userauth_kybd_packet_len +=
1802                     4 + session->userauth_kybd_responses[i].length;
1803             }
1804 
1805             /* A new userauth_kybd_data area is to be allocated, free the
1806                former one. */
1807             LIBSSH2_FREE(session, session->userauth_kybd_data);
1808 
1809             session->userauth_kybd_data = s =
1810                 LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len);
1811             if (!s) {
1812                 _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1813                                "Unable to allocate memory for keyboard-"
1814                                "interactive response packet");
1815                 goto cleanup;
1816             }
1817 
1818             *s = SSH_MSG_USERAUTH_INFO_RESPONSE;
1819             s++;
1820             _libssh2_store_u32(&s, session->userauth_kybd_num_prompts);
1821 
1822             for(i = 0; i < session->userauth_kybd_num_prompts; i++) {
1823                 _libssh2_store_str(&s,
1824                                    session->userauth_kybd_responses[i].text,
1825                                    session->userauth_kybd_responses[i].length);
1826             }
1827 
1828             session->userauth_kybd_state = libssh2_NB_state_sent1;
1829         }
1830 
1831         if (session->userauth_kybd_state == libssh2_NB_state_sent1) {
1832             rc = _libssh2_transport_send(session, session->userauth_kybd_data,
1833                                          session->userauth_kybd_packet_len,
1834                                          NULL, 0);
1835             if (rc == LIBSSH2_ERROR_EAGAIN)
1836                 return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
1837                                       "Would block");
1838             if (rc) {
1839                 _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
1840                                "Unable to send userauth-keyboard-interactive"
1841                                " request");
1842                 goto cleanup;
1843             }
1844 
1845             session->userauth_kybd_auth_failure = 0;
1846         }
1847 
1848       cleanup:
1849         /*
1850          * It's safe to clean all the data here, because unallocated pointers
1851          * are filled by zeroes
1852          */
1853 
1854         LIBSSH2_FREE(session, session->userauth_kybd_data);
1855         session->userauth_kybd_data = NULL;
1856 
1857         if (session->userauth_kybd_prompts) {
1858             for(i = 0; i < session->userauth_kybd_num_prompts; i++) {
1859                 LIBSSH2_FREE(session, session->userauth_kybd_prompts[i].text);
1860                 session->userauth_kybd_prompts[i].text = NULL;
1861             }
1862         }
1863 
1864         if (session->userauth_kybd_responses) {
1865             for(i = 0; i < session->userauth_kybd_num_prompts; i++) {
1866                 LIBSSH2_FREE(session,
1867                              session->userauth_kybd_responses[i].text);
1868                 session->userauth_kybd_responses[i].text = NULL;
1869             }
1870         }
1871 
1872         if(session->userauth_kybd_prompts) {
1873             LIBSSH2_FREE(session, session->userauth_kybd_prompts);
1874             session->userauth_kybd_prompts = NULL;
1875         }
1876         if(session->userauth_kybd_responses) {
1877             LIBSSH2_FREE(session, session->userauth_kybd_responses);
1878             session->userauth_kybd_responses = NULL;
1879         }
1880         if(session->userauth_kybd_auth_name) {
1881             LIBSSH2_FREE(session, session->userauth_kybd_auth_name);
1882             session->userauth_kybd_auth_name = NULL;
1883         }
1884         if(session->userauth_kybd_auth_instruction) {
1885             LIBSSH2_FREE(session, session->userauth_kybd_auth_instruction);
1886             session->userauth_kybd_auth_instruction = NULL;
1887         }
1888 
1889         if (session->userauth_kybd_auth_failure) {
1890             session->userauth_kybd_state = libssh2_NB_state_idle;
1891             return -1;
1892         }
1893 
1894         session->userauth_kybd_state = libssh2_NB_state_sent;
1895     }
1896 }
1897 
1898 /*
1899  * libssh2_userauth_keyboard_interactive_ex
1900  *
1901  * Authenticate using a challenge-response authentication
1902  */
1903 LIBSSH2_API int
libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION * session,const char * user,unsigned int user_len,LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC ((* response_callback)))1904 libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session,
1905                                          const char *user,
1906                                          unsigned int user_len,
1907                                          LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)))
1908 {
1909     int rc;
1910     BLOCK_ADJUST(rc, session,
1911                  userauth_keyboard_interactive(session, user, user_len,
1912                                                response_callback));
1913     return rc;
1914 }
1915