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