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 !LIBSSH2_RSA
832     return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
833                           "RSA is not supported by crypto backend");
834 #endif
835 
836     if(session->userauth_host_state == libssh2_NB_state_idle) {
837         const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
838         unsigned char *pubkeydata = NULL;
839         unsigned char *sig = NULL;
840         size_t pubkeydata_len = 0;
841         size_t sig_len = 0;
842         void *abstract;
843         unsigned char buf[5];
844         struct iovec datavec[4];
845 
846         /* Zero the whole thing out */
847         memset(&session->userauth_host_packet_requirev_state, 0,
848                sizeof(session->userauth_host_packet_requirev_state));
849 
850         if(publickey) {
851             rc = file_read_publickey(session, &session->userauth_host_method,
852                                      &session->userauth_host_method_len,
853                                      &pubkeydata, &pubkeydata_len, publickey);
854             if(rc)
855                 /* Note: file_read_publickey() calls _libssh2_error() */
856                 return rc;
857         }
858         else {
859             /* Compute public key from private key. */
860             rc = _libssh2_pub_priv_keyfile(session,
861                                            &session->userauth_host_method,
862                                            &session->userauth_host_method_len,
863                                            &pubkeydata, &pubkeydata_len,
864                                            privatekey, passphrase);
865             if(rc)
866                 /* libssh2_pub_priv_keyfile calls _libssh2_error() */
867                 return rc;
868         }
869 
870         /*
871          * 52 = packet_type(1) + username_len(4) + servicename_len(4) +
872          * service_name(14)"ssh-connection" + authmethod_len(4) +
873          * authmethod(9)"hostbased" + method_len(4) + pubkeydata_len(4) +
874          * hostname_len(4) + local_username_len(4)
875          */
876         session->userauth_host_packet_len =
877             username_len + session->userauth_host_method_len + hostname_len +
878             local_username_len + pubkeydata_len + 52;
879 
880         /*
881          * Preallocate space for an overall length,  method name again,
882          * and the signature, which won't be any larger than the size of
883          * the publickeydata itself
884          */
885         session->userauth_host_s = session->userauth_host_packet =
886             LIBSSH2_ALLOC(session,
887                           session->userauth_host_packet_len + 4 +
888                           (4 + session->userauth_host_method_len) +
889                           (4 + pubkeydata_len));
890         if(!session->userauth_host_packet) {
891             LIBSSH2_FREE(session, session->userauth_host_method);
892             session->userauth_host_method = NULL;
893             LIBSSH2_FREE(session, pubkeydata);
894             return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
895                                   "Out of memory");
896         }
897 
898         *(session->userauth_host_s++) = SSH_MSG_USERAUTH_REQUEST;
899         _libssh2_store_str(&session->userauth_host_s, username, username_len);
900         _libssh2_store_str(&session->userauth_host_s, "ssh-connection", 14);
901         _libssh2_store_str(&session->userauth_host_s, "hostbased", 9);
902         _libssh2_store_str(&session->userauth_host_s,
903                            (const char *)session->userauth_host_method,
904                            session->userauth_host_method_len);
905         _libssh2_store_str(&session->userauth_host_s, (const char *)pubkeydata,
906                            pubkeydata_len);
907         LIBSSH2_FREE(session, pubkeydata);
908         _libssh2_store_str(&session->userauth_host_s, hostname, hostname_len);
909         _libssh2_store_str(&session->userauth_host_s, local_username,
910                            local_username_len);
911 
912         rc = file_read_privatekey(session, &privkeyobj, &abstract,
913                                   session->userauth_host_method,
914                                   session->userauth_host_method_len,
915                                   privatekey, passphrase);
916         if(rc) {
917             /* Note: file_read_privatekey() calls _libssh2_error() */
918             LIBSSH2_FREE(session, session->userauth_host_method);
919             session->userauth_host_method = NULL;
920             LIBSSH2_FREE(session, session->userauth_host_packet);
921             session->userauth_host_packet = NULL;
922             return rc;
923         }
924 
925         _libssh2_htonu32(buf, session->session_id_len);
926         libssh2_prepare_iovec(datavec, 4);
927         datavec[0].iov_base = (void *)buf;
928         datavec[0].iov_len = 4;
929         datavec[1].iov_base = (void *)session->session_id;
930         datavec[1].iov_len = session->session_id_len;
931         datavec[2].iov_base = (void *)session->userauth_host_packet;
932         datavec[2].iov_len = session->userauth_host_packet_len;
933 
934         if(privkeyobj && privkeyobj->signv &&
935                           privkeyobj->signv(session, &sig, &sig_len, 3,
936                                             datavec, &abstract)) {
937             LIBSSH2_FREE(session, session->userauth_host_method);
938             session->userauth_host_method = NULL;
939             LIBSSH2_FREE(session, session->userauth_host_packet);
940             session->userauth_host_packet = NULL;
941             if(privkeyobj->dtor) {
942                 privkeyobj->dtor(session, &abstract);
943             }
944             return -1;
945         }
946 
947         if(privkeyobj && privkeyobj->dtor) {
948             privkeyobj->dtor(session, &abstract);
949         }
950 
951         if(sig_len > pubkeydata_len) {
952             unsigned char *newpacket;
953             /* Should *NEVER* happen, but...well.. better safe than sorry */
954             newpacket = LIBSSH2_REALLOC(session, session->userauth_host_packet,
955                                         session->userauth_host_packet_len + 4 +
956                                         (4 + session->userauth_host_method_len)
957                                         + (4 + sig_len)); /* PK sigblob */
958             if(!newpacket) {
959                 LIBSSH2_FREE(session, sig);
960                 LIBSSH2_FREE(session, session->userauth_host_packet);
961                 session->userauth_host_packet = NULL;
962                 LIBSSH2_FREE(session, session->userauth_host_method);
963                 session->userauth_host_method = NULL;
964                 return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
965                                       "Failed allocating additional space for "
966                                       "userauth-hostbased packet");
967             }
968             session->userauth_host_packet = newpacket;
969         }
970 
971         session->userauth_host_s =
972             session->userauth_host_packet + session->userauth_host_packet_len;
973 
974         _libssh2_store_u32(&session->userauth_host_s,
975                            4 + session->userauth_host_method_len +
976                            4 + sig_len);
977         _libssh2_store_str(&session->userauth_host_s,
978                            (const char *)session->userauth_host_method,
979                            session->userauth_host_method_len);
980         LIBSSH2_FREE(session, session->userauth_host_method);
981         session->userauth_host_method = NULL;
982 
983         _libssh2_store_str(&session->userauth_host_s, (const char *)sig,
984                            sig_len);
985         LIBSSH2_FREE(session, sig);
986 
987         _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
988                        "Attempting hostbased authentication");
989 
990         session->userauth_host_state = libssh2_NB_state_created;
991     }
992 
993     if(session->userauth_host_state == libssh2_NB_state_created) {
994         rc = _libssh2_transport_send(session, session->userauth_host_packet,
995                                      session->userauth_host_s -
996                                      session->userauth_host_packet,
997                                      NULL, 0);
998         if(rc == LIBSSH2_ERROR_EAGAIN) {
999             return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
1000                                   "Would block");
1001         }
1002         else if(rc) {
1003             LIBSSH2_FREE(session, session->userauth_host_packet);
1004             session->userauth_host_packet = NULL;
1005             session->userauth_host_state = libssh2_NB_state_idle;
1006             return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
1007                                   "Unable to send userauth-hostbased request");
1008         }
1009         LIBSSH2_FREE(session, session->userauth_host_packet);
1010         session->userauth_host_packet = NULL;
1011 
1012         session->userauth_host_state = libssh2_NB_state_sent;
1013     }
1014 
1015     if(session->userauth_host_state == libssh2_NB_state_sent) {
1016         static const unsigned char reply_codes[3] =
1017             { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
1018         size_t data_len;
1019         rc = _libssh2_packet_requirev(session, reply_codes,
1020                                       &session->userauth_host_data,
1021                                       &data_len, 0, NULL, 0,
1022                                       &session->
1023                                       userauth_host_packet_requirev_state);
1024         if(rc == LIBSSH2_ERROR_EAGAIN) {
1025             return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
1026                                   "Would block");
1027         }
1028 
1029         session->userauth_host_state = libssh2_NB_state_idle;
1030         if(rc || data_len < 1) {
1031             return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
1032                                   "Auth failed");
1033         }
1034 
1035         if(session->userauth_host_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
1036             _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
1037                            "Hostbased authentication successful");
1038             /* We are us and we've proved it. */
1039             LIBSSH2_FREE(session, session->userauth_host_data);
1040             session->userauth_host_data = NULL;
1041             session->state |= LIBSSH2_STATE_AUTHENTICATED;
1042             return 0;
1043         }
1044     }
1045 
1046     /* This public key is not allowed for this user on this server */
1047     LIBSSH2_FREE(session, session->userauth_host_data);
1048     session->userauth_host_data = NULL;
1049     return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
1050                           "Invalid signature for supplied public key, or bad "
1051                           "username/public key combination");
1052 }
1053 
1054 /* libssh2_userauth_hostbased_fromfile_ex
1055  * Authenticate using a keypair found in the named files
1056  */
1057 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)1058 libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session,
1059                                        const char *user,
1060                                        unsigned int user_len,
1061                                        const char *publickey,
1062                                        const char *privatekey,
1063                                        const char *passphrase,
1064                                        const char *host,
1065                                        unsigned int host_len,
1066                                        const char *localuser,
1067                                        unsigned int localuser_len)
1068 {
1069     int rc;
1070     BLOCK_ADJUST(rc, session,
1071                  userauth_hostbased_fromfile(session, user, user_len,
1072                                              publickey, privatekey,
1073                                              passphrase, host, host_len,
1074                                              localuser, localuser_len));
1075     return rc;
1076 }
1077 
1078 
1079 
1080 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)1081 _libssh2_userauth_publickey(LIBSSH2_SESSION *session,
1082                             const char *username,
1083                             unsigned int username_len,
1084                             const unsigned char *pubkeydata,
1085                             unsigned long pubkeydata_len,
1086                             LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC
1087                             ((*sign_callback)),
1088                             void *abstract)
1089 {
1090     unsigned char reply_codes[4] =
1091         { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE,
1092           SSH_MSG_USERAUTH_PK_OK, 0
1093         };
1094     int rc;
1095     unsigned char *s;
1096 
1097     if(session->userauth_pblc_state == libssh2_NB_state_idle) {
1098 
1099         /*
1100          * The call to _libssh2_ntohu32 later relies on pubkeydata having at
1101          * least 4 valid bytes containing the length of the method name.
1102          */
1103         if(pubkeydata_len < 4)
1104             return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
1105                                   "Invalid public key, too short");
1106 
1107         /* Zero the whole thing out */
1108         memset(&session->userauth_pblc_packet_requirev_state, 0,
1109                sizeof(session->userauth_pblc_packet_requirev_state));
1110 
1111         /*
1112          * As an optimisation, userauth_publickey_fromfile reuses a
1113          * previously allocated copy of the method name to avoid an extra
1114          * allocation/free.
1115          * For other uses, we allocate and populate it here.
1116          */
1117         if(!session->userauth_pblc_method) {
1118             session->userauth_pblc_method_len = _libssh2_ntohu32(pubkeydata);
1119 
1120             if(session->userauth_pblc_method_len > pubkeydata_len - 4)
1121                 /* the method length simply cannot be longer than the entire
1122                    passed in data, so we use this to detect crazy input
1123                    data */
1124                 return _libssh2_error(session,
1125                                       LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
1126                                       "Invalid public key");
1127 
1128             session->userauth_pblc_method =
1129                 LIBSSH2_ALLOC(session, session->userauth_pblc_method_len);
1130             if(!session->userauth_pblc_method) {
1131                 return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1132                                       "Unable to allocate memory "
1133                                       "for public key data");
1134             }
1135             memcpy(session->userauth_pblc_method, pubkeydata + 4,
1136                    session->userauth_pblc_method_len);
1137         }
1138         /*
1139          * The length of the method name read from plaintext prefix in the
1140          * file must match length embedded in the key.
1141          * TODO: The data should match too but we don't check that. Should we?
1142          */
1143         else if(session->userauth_pblc_method_len !=
1144                  _libssh2_ntohu32(pubkeydata))
1145             return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
1146                                   "Invalid public key");
1147 
1148         /*
1149          * 45 = packet_type(1) + username_len(4) + servicename_len(4) +
1150          * service_name(14)"ssh-connection" + authmethod_len(4) +
1151          * authmethod(9)"publickey" + sig_included(1)'\0' + algmethod_len(4) +
1152          * publickey_len(4)
1153          */
1154         session->userauth_pblc_packet_len =
1155             username_len + session->userauth_pblc_method_len + pubkeydata_len +
1156             45;
1157 
1158         /*
1159          * Preallocate space for an overall length, method name again, and the
1160          * signature, which won't be any larger than the size of the
1161          * publickeydata itself.
1162          *
1163          * Note that the 'pubkeydata_len' extra bytes allocated here will not
1164          * be used in this first send, but will be used in the later one where
1165          * this same allocation is re-used.
1166          */
1167         s = session->userauth_pblc_packet =
1168             LIBSSH2_ALLOC(session,
1169                           session->userauth_pblc_packet_len + 4 +
1170                           (4 + session->userauth_pblc_method_len)
1171                           + (4 + pubkeydata_len));
1172         if(!session->userauth_pblc_packet) {
1173             LIBSSH2_FREE(session, session->userauth_pblc_method);
1174             session->userauth_pblc_method = NULL;
1175             return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1176                                   "Out of memory");
1177         }
1178 
1179         *s++ = SSH_MSG_USERAUTH_REQUEST;
1180         _libssh2_store_str(&s, username, username_len);
1181         _libssh2_store_str(&s, "ssh-connection", 14);
1182         _libssh2_store_str(&s, "publickey", 9);
1183 
1184         session->userauth_pblc_b = s;
1185         /* Not sending signature with *this* packet */
1186         *s++ = 0;
1187 
1188         _libssh2_store_str(&s, (const char *)session->userauth_pblc_method,
1189                            session->userauth_pblc_method_len);
1190         _libssh2_store_str(&s, (const char *)pubkeydata, pubkeydata_len);
1191 
1192         _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
1193                        "Attempting publickey authentication");
1194 
1195         session->userauth_pblc_state = libssh2_NB_state_created;
1196     }
1197 
1198     if(session->userauth_pblc_state == libssh2_NB_state_created) {
1199         rc = _libssh2_transport_send(session, session->userauth_pblc_packet,
1200                                      session->userauth_pblc_packet_len,
1201                                      NULL, 0);
1202         if(rc == LIBSSH2_ERROR_EAGAIN)
1203             return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
1204                                   "Would block");
1205         else if(rc) {
1206             LIBSSH2_FREE(session, session->userauth_pblc_packet);
1207             session->userauth_pblc_packet = NULL;
1208             LIBSSH2_FREE(session, session->userauth_pblc_method);
1209             session->userauth_pblc_method = NULL;
1210             session->userauth_pblc_state = libssh2_NB_state_idle;
1211             return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
1212                                   "Unable to send userauth-publickey request");
1213         }
1214 
1215         session->userauth_pblc_state = libssh2_NB_state_sent;
1216     }
1217 
1218     if(session->userauth_pblc_state == libssh2_NB_state_sent) {
1219         rc = _libssh2_packet_requirev(session, reply_codes,
1220                                       &session->userauth_pblc_data,
1221                                       &session->userauth_pblc_data_len, 0,
1222                                       NULL, 0,
1223                                       &session->
1224                                       userauth_pblc_packet_requirev_state);
1225         if(rc == LIBSSH2_ERROR_EAGAIN) {
1226             return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
1227                                   "Would block");
1228         }
1229         else if(rc || (session->userauth_pblc_data_len < 1)) {
1230             LIBSSH2_FREE(session, session->userauth_pblc_packet);
1231             session->userauth_pblc_packet = NULL;
1232             LIBSSH2_FREE(session, session->userauth_pblc_method);
1233             session->userauth_pblc_method = NULL;
1234             session->userauth_pblc_state = libssh2_NB_state_idle;
1235             return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
1236                                   "Waiting for USERAUTH response");
1237         }
1238 
1239         if(session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
1240             _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
1241                            "Pubkey authentication prematurely successful");
1242             /*
1243              * God help any SSH server that allows an UNVERIFIED
1244              * public key to validate the user
1245              */
1246             LIBSSH2_FREE(session, session->userauth_pblc_data);
1247             session->userauth_pblc_data = NULL;
1248             LIBSSH2_FREE(session, session->userauth_pblc_packet);
1249             session->userauth_pblc_packet = NULL;
1250             LIBSSH2_FREE(session, session->userauth_pblc_method);
1251             session->userauth_pblc_method = NULL;
1252             session->state |= LIBSSH2_STATE_AUTHENTICATED;
1253             session->userauth_pblc_state = libssh2_NB_state_idle;
1254             return 0;
1255         }
1256 
1257         if(session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_FAILURE) {
1258             /* This public key is not allowed for this user on this server */
1259             LIBSSH2_FREE(session, session->userauth_pblc_data);
1260             session->userauth_pblc_data = NULL;
1261             LIBSSH2_FREE(session, session->userauth_pblc_packet);
1262             session->userauth_pblc_packet = NULL;
1263             LIBSSH2_FREE(session, session->userauth_pblc_method);
1264             session->userauth_pblc_method = NULL;
1265             session->userauth_pblc_state = libssh2_NB_state_idle;
1266             return _libssh2_error(session, LIBSSH2_ERROR_AUTHENTICATION_FAILED,
1267                                   "Username/PublicKey combination invalid");
1268         }
1269 
1270         /* Semi-Success! */
1271         LIBSSH2_FREE(session, session->userauth_pblc_data);
1272         session->userauth_pblc_data = NULL;
1273 
1274         *session->userauth_pblc_b = 0x01;
1275         session->userauth_pblc_state = libssh2_NB_state_sent1;
1276     }
1277 
1278     if(session->userauth_pblc_state == libssh2_NB_state_sent1) {
1279         unsigned char *buf;
1280         unsigned char *sig;
1281         size_t sig_len;
1282 
1283         s = buf = LIBSSH2_ALLOC(session, 4 + session->session_id_len
1284                                 + session->userauth_pblc_packet_len);
1285         if(!buf) {
1286             return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1287                                   "Unable to allocate memory for "
1288                                   "userauth-publickey signed data");
1289         }
1290 
1291         _libssh2_store_str(&s, (const char *)session->session_id,
1292                            session->session_id_len);
1293 
1294         memcpy(s, session->userauth_pblc_packet,
1295                session->userauth_pblc_packet_len);
1296         s += session->userauth_pblc_packet_len;
1297 
1298         rc = sign_callback(session, &sig, &sig_len, buf, s - buf, abstract);
1299         LIBSSH2_FREE(session, buf);
1300         if(rc == LIBSSH2_ERROR_EAGAIN) {
1301             return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
1302                                   "Would block");
1303         }
1304         else if(rc) {
1305             LIBSSH2_FREE(session, session->userauth_pblc_method);
1306             session->userauth_pblc_method = NULL;
1307             LIBSSH2_FREE(session, session->userauth_pblc_packet);
1308             session->userauth_pblc_packet = NULL;
1309             session->userauth_pblc_state = libssh2_NB_state_idle;
1310             return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
1311                                   "Callback returned error");
1312         }
1313 
1314         /*
1315          * If this function was restarted, pubkeydata_len might still be 0
1316          * which will cause an unnecessary but harmless realloc here.
1317          */
1318         if(sig_len > pubkeydata_len) {
1319             unsigned char *newpacket;
1320             /* Should *NEVER* happen, but...well.. better safe than sorry */
1321             newpacket = LIBSSH2_REALLOC(session,
1322                                         session->userauth_pblc_packet,
1323                                         session->userauth_pblc_packet_len + 4 +
1324                                         (4 + session->userauth_pblc_method_len)
1325                                         + (4 + sig_len)); /* PK sigblob */
1326             if(!newpacket) {
1327                 LIBSSH2_FREE(session, sig);
1328                 LIBSSH2_FREE(session, session->userauth_pblc_packet);
1329                 session->userauth_pblc_packet = NULL;
1330                 LIBSSH2_FREE(session, session->userauth_pblc_method);
1331                 session->userauth_pblc_method = NULL;
1332                 session->userauth_pblc_state = libssh2_NB_state_idle;
1333                 return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1334                                       "Failed allocating additional space for "
1335                                       "userauth-publickey packet");
1336             }
1337             session->userauth_pblc_packet = newpacket;
1338         }
1339 
1340         s = session->userauth_pblc_packet + session->userauth_pblc_packet_len;
1341         session->userauth_pblc_b = NULL;
1342 
1343         _libssh2_store_u32(&s,
1344                            4 + session->userauth_pblc_method_len + 4 +
1345                            sig_len);
1346         _libssh2_store_str(&s, (const char *)session->userauth_pblc_method,
1347                            session->userauth_pblc_method_len);
1348 
1349         LIBSSH2_FREE(session, session->userauth_pblc_method);
1350         session->userauth_pblc_method = NULL;
1351 
1352         _libssh2_store_str(&s, (const char *)sig, sig_len);
1353         LIBSSH2_FREE(session, sig);
1354 
1355         _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
1356                        "Attempting publickey authentication -- phase 2");
1357 
1358         session->userauth_pblc_s = s;
1359         session->userauth_pblc_state = libssh2_NB_state_sent2;
1360     }
1361 
1362     if(session->userauth_pblc_state == libssh2_NB_state_sent2) {
1363         rc = _libssh2_transport_send(session, session->userauth_pblc_packet,
1364                                      session->userauth_pblc_s -
1365                                      session->userauth_pblc_packet,
1366                                      NULL, 0);
1367         if(rc == LIBSSH2_ERROR_EAGAIN) {
1368             return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
1369                                   "Would block");
1370         }
1371         else if(rc) {
1372             LIBSSH2_FREE(session, session->userauth_pblc_packet);
1373             session->userauth_pblc_packet = NULL;
1374             session->userauth_pblc_state = libssh2_NB_state_idle;
1375             return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
1376                                   "Unable to send userauth-publickey request");
1377         }
1378         LIBSSH2_FREE(session, session->userauth_pblc_packet);
1379         session->userauth_pblc_packet = NULL;
1380 
1381         session->userauth_pblc_state = libssh2_NB_state_sent3;
1382     }
1383 
1384     /* PK_OK is no longer valid */
1385     reply_codes[2] = 0;
1386 
1387     rc = _libssh2_packet_requirev(session, reply_codes,
1388                                &session->userauth_pblc_data,
1389                                &session->userauth_pblc_data_len, 0, NULL, 0,
1390                                &session->userauth_pblc_packet_requirev_state);
1391     if(rc == LIBSSH2_ERROR_EAGAIN) {
1392         return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
1393                               "Would block requesting userauth list");
1394     }
1395     else if(rc || session->userauth_pblc_data_len < 1) {
1396         session->userauth_pblc_state = libssh2_NB_state_idle;
1397         return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
1398                               "Waiting for publickey USERAUTH response");
1399     }
1400 
1401     if(session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
1402         _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
1403                        "Publickey authentication successful");
1404         /* We are us and we've proved it. */
1405         LIBSSH2_FREE(session, session->userauth_pblc_data);
1406         session->userauth_pblc_data = NULL;
1407         session->state |= LIBSSH2_STATE_AUTHENTICATED;
1408         session->userauth_pblc_state = libssh2_NB_state_idle;
1409         return 0;
1410     }
1411 
1412     /* This public key is not allowed for this user on this server */
1413     LIBSSH2_FREE(session, session->userauth_pblc_data);
1414     session->userauth_pblc_data = NULL;
1415     session->userauth_pblc_state = libssh2_NB_state_idle;
1416     return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
1417                           "Invalid signature for supplied public key, or bad "
1418                           "username/public key combination");
1419 }
1420 
1421  /*
1422   * userauth_publickey_frommemory
1423   * Authenticate using a keypair from memory
1424   */
1425 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)1426 userauth_publickey_frommemory(LIBSSH2_SESSION *session,
1427                               const char *username,
1428                               size_t username_len,
1429                               const char *publickeydata,
1430                               size_t publickeydata_len,
1431                               const char *privatekeydata,
1432                               size_t privatekeydata_len,
1433                               const char *passphrase)
1434 {
1435     unsigned char *pubkeydata = NULL;
1436     size_t pubkeydata_len = 0;
1437     struct privkey_file privkey_file;
1438     void *abstract = &privkey_file;
1439     int rc;
1440 
1441 #if !LIBSSH2_RSA
1442     return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
1443                           "RSA is not supported by crypto backend");
1444 #endif
1445 
1446     privkey_file.filename = privatekeydata;
1447     privkey_file.passphrase = passphrase;
1448 
1449     if(session->userauth_pblc_state == libssh2_NB_state_idle) {
1450         if(publickeydata_len && publickeydata) {
1451             rc = memory_read_publickey(session, &session->userauth_pblc_method,
1452                                        &session->userauth_pblc_method_len,
1453                                        &pubkeydata, &pubkeydata_len,
1454                                        publickeydata, publickeydata_len);
1455             if(rc)
1456                 return rc;
1457         }
1458         else if(privatekeydata_len && privatekeydata) {
1459             /* Compute public key from private key. */
1460             if(_libssh2_pub_priv_keyfilememory(session,
1461                                             &session->userauth_pblc_method,
1462                                             &session->userauth_pblc_method_len,
1463                                             &pubkeydata, &pubkeydata_len,
1464                                             privatekeydata, privatekeydata_len,
1465                                             passphrase))
1466                 return _libssh2_error(session, LIBSSH2_ERROR_FILE,
1467                                       "Unable to extract public key "
1468                                       "from private key.");
1469         }
1470         else {
1471             return _libssh2_error(session, LIBSSH2_ERROR_FILE,
1472                                   "Invalid data in public and private key.");
1473         }
1474     }
1475 
1476     rc = _libssh2_userauth_publickey(session, username, username_len,
1477                                      pubkeydata, pubkeydata_len,
1478                                      sign_frommemory, &abstract);
1479     if(pubkeydata)
1480         LIBSSH2_FREE(session, pubkeydata);
1481 
1482     return rc;
1483 }
1484 
1485 /*
1486  * userauth_publickey_fromfile
1487  * Authenticate using a keypair found in the named files
1488  */
1489 static int
userauth_publickey_fromfile(LIBSSH2_SESSION * session,const char * username,size_t username_len,const char * publickey,const char * privatekey,const char * passphrase)1490 userauth_publickey_fromfile(LIBSSH2_SESSION *session,
1491                             const char *username,
1492                             size_t username_len,
1493                             const char *publickey,
1494                             const char *privatekey,
1495                             const char *passphrase)
1496 {
1497     unsigned char *pubkeydata = NULL;
1498     size_t pubkeydata_len = 0;
1499     struct privkey_file privkey_file;
1500     void *abstract = &privkey_file;
1501     int rc;
1502 
1503 #if !LIBSSH2_RSA
1504     return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED,
1505                           "RSA is not supported by crypto backend");
1506 #endif
1507 
1508     privkey_file.filename = privatekey;
1509     privkey_file.passphrase = passphrase;
1510 
1511     if(session->userauth_pblc_state == libssh2_NB_state_idle) {
1512         if(publickey) {
1513             rc = file_read_publickey(session, &session->userauth_pblc_method,
1514                                      &session->userauth_pblc_method_len,
1515                                      &pubkeydata, &pubkeydata_len, publickey);
1516             if(rc)
1517                 return rc;
1518         }
1519         else {
1520             /* Compute public key from private key. */
1521             rc = _libssh2_pub_priv_keyfile(session,
1522                                            &session->userauth_pblc_method,
1523                                            &session->userauth_pblc_method_len,
1524                                            &pubkeydata, &pubkeydata_len,
1525                                            privatekey, passphrase);
1526 
1527             /* _libssh2_pub_priv_keyfile calls _libssh2_error() */
1528             if(rc)
1529                 return rc;
1530         }
1531     }
1532 
1533     rc = _libssh2_userauth_publickey(session, username, username_len,
1534                                      pubkeydata, pubkeydata_len,
1535                                      sign_fromfile, &abstract);
1536     if(pubkeydata)
1537         LIBSSH2_FREE(session, pubkeydata);
1538 
1539     return rc;
1540 }
1541 
1542 /* libssh2_userauth_publickey_frommemory
1543  * Authenticate using a keypair from memory
1544  */
1545 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)1546 libssh2_userauth_publickey_frommemory(LIBSSH2_SESSION *session,
1547                                       const char *user,
1548                                       size_t user_len,
1549                                       const char *publickeyfiledata,
1550                                       size_t publickeyfiledata_len,
1551                                       const char *privatekeyfiledata,
1552                                       size_t privatekeyfiledata_len,
1553                                       const char *passphrase)
1554 {
1555     int rc;
1556 
1557     if(NULL == passphrase)
1558         /* if given a NULL pointer, make it point to a zero-length
1559            string to save us from having to check this all over */
1560         passphrase = "";
1561 
1562     BLOCK_ADJUST(rc, session,
1563                  userauth_publickey_frommemory(session, user, user_len,
1564                                                publickeyfiledata,
1565                                                publickeyfiledata_len,
1566                                                privatekeyfiledata,
1567                                                privatekeyfiledata_len,
1568                                                passphrase));
1569     return rc;
1570 }
1571 
1572 /* libssh2_userauth_publickey_fromfile_ex
1573  * Authenticate using a keypair found in the named files
1574  */
1575 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)1576 libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session,
1577                                        const char *user,
1578                                        unsigned int user_len,
1579                                        const char *publickey,
1580                                        const char *privatekey,
1581                                        const char *passphrase)
1582 {
1583     int rc;
1584 
1585     if(NULL == passphrase)
1586         /* if given a NULL pointer, make it point to a zero-length
1587            string to save us from having to check this all over */
1588         passphrase = "";
1589 
1590     BLOCK_ADJUST(rc, session,
1591                  userauth_publickey_fromfile(session, user, user_len,
1592                                              publickey, privatekey,
1593                                              passphrase));
1594     return rc;
1595 }
1596 
1597 /* libssh2_userauth_publickey_ex
1598  * Authenticate using an external callback function
1599  */
1600 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)1601 libssh2_userauth_publickey(LIBSSH2_SESSION *session,
1602                            const char *user,
1603                            const unsigned char *pubkeydata,
1604                            size_t pubkeydata_len,
1605                            LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC
1606                            ((*sign_callback)),
1607                            void **abstract)
1608 {
1609     int rc;
1610 
1611     if(!session)
1612         return LIBSSH2_ERROR_BAD_USE;
1613 
1614     BLOCK_ADJUST(rc, session,
1615                  _libssh2_userauth_publickey(session, user, strlen(user),
1616                                              pubkeydata, pubkeydata_len,
1617                                              sign_callback, abstract));
1618     return rc;
1619 }
1620 
1621 
1622 
1623 /*
1624  * userauth_keyboard_interactive
1625  *
1626  * Authenticate using a challenge-response authentication
1627  */
1628 static int
userauth_keyboard_interactive(LIBSSH2_SESSION * session,const char * username,unsigned int username_len,LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC ((* response_callback)))1629 userauth_keyboard_interactive(LIBSSH2_SESSION * session,
1630                               const char *username,
1631                               unsigned int username_len,
1632                               LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC
1633                               ((*response_callback)))
1634 {
1635     unsigned char *s;
1636     int rc;
1637 
1638     static const unsigned char reply_codes[4] = {
1639         SSH_MSG_USERAUTH_SUCCESS,
1640         SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0
1641     };
1642     unsigned int language_tag_len;
1643     unsigned int i;
1644 
1645     if(session->userauth_kybd_state == libssh2_NB_state_idle) {
1646         session->userauth_kybd_auth_name = NULL;
1647         session->userauth_kybd_auth_instruction = NULL;
1648         session->userauth_kybd_num_prompts = 0;
1649         session->userauth_kybd_auth_failure = 1;
1650         session->userauth_kybd_prompts = NULL;
1651         session->userauth_kybd_responses = NULL;
1652 
1653         /* Zero the whole thing out */
1654         memset(&session->userauth_kybd_packet_requirev_state, 0,
1655                sizeof(session->userauth_kybd_packet_requirev_state));
1656 
1657         session->userauth_kybd_packet_len =
1658             1                   /* byte    SSH_MSG_USERAUTH_REQUEST */
1659             + 4 + username_len  /* string  user name (ISO-10646 UTF-8, as
1660                                    defined in [RFC-3629]) */
1661             + 4 + 14            /* string  service name (US-ASCII) */
1662             + 4 + 20            /* string  "keyboard-interactive" (US-ASCII) */
1663             + 4 + 0             /* string  language tag (as defined in
1664                                    [RFC-3066]) */
1665             + 4 + 0             /* string  submethods (ISO-10646 UTF-8) */
1666             ;
1667 
1668         session->userauth_kybd_data = s =
1669             LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len);
1670         if(!s) {
1671             return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1672                                   "Unable to allocate memory for "
1673                                   "keyboard-interactive authentication");
1674         }
1675 
1676         *s++ = SSH_MSG_USERAUTH_REQUEST;
1677 
1678         /* user name */
1679         _libssh2_store_str(&s, username, username_len);
1680 
1681         /* service name */
1682         _libssh2_store_str(&s, "ssh-connection", sizeof("ssh-connection") - 1);
1683 
1684         /* "keyboard-interactive" */
1685         _libssh2_store_str(&s, "keyboard-interactive",
1686                            sizeof("keyboard-interactive") - 1);
1687         /* language tag */
1688         _libssh2_store_u32(&s, 0);
1689 
1690         /* submethods */
1691         _libssh2_store_u32(&s, 0);
1692 
1693         _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
1694                        "Attempting keyboard-interactive authentication");
1695 
1696         session->userauth_kybd_state = libssh2_NB_state_created;
1697     }
1698 
1699     if(session->userauth_kybd_state == libssh2_NB_state_created) {
1700         rc = _libssh2_transport_send(session, session->userauth_kybd_data,
1701                                      session->userauth_kybd_packet_len,
1702                                      NULL, 0);
1703         if(rc == LIBSSH2_ERROR_EAGAIN) {
1704             return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
1705                                   "Would block");
1706         }
1707         else if(rc) {
1708             LIBSSH2_FREE(session, session->userauth_kybd_data);
1709             session->userauth_kybd_data = NULL;
1710             session->userauth_kybd_state = libssh2_NB_state_idle;
1711             return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
1712                                   "Unable to send keyboard-interactive"
1713                                   " request");
1714         }
1715         LIBSSH2_FREE(session, session->userauth_kybd_data);
1716         session->userauth_kybd_data = NULL;
1717 
1718         session->userauth_kybd_state = libssh2_NB_state_sent;
1719     }
1720 
1721     for(;;) {
1722         if(session->userauth_kybd_state == libssh2_NB_state_sent) {
1723             rc = _libssh2_packet_requirev(session, reply_codes,
1724                                           &session->userauth_kybd_data,
1725                                           &session->userauth_kybd_data_len,
1726                                           0, NULL, 0,
1727                                           &session->
1728                                           userauth_kybd_packet_requirev_state);
1729             if(rc == LIBSSH2_ERROR_EAGAIN) {
1730                 return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
1731                                       "Would block");
1732             }
1733             else if(rc || session->userauth_kybd_data_len < 1) {
1734                 session->userauth_kybd_state = libssh2_NB_state_idle;
1735                 return _libssh2_error(session,
1736                                       LIBSSH2_ERROR_AUTHENTICATION_FAILED,
1737                                       "Waiting for keyboard "
1738                                       "USERAUTH response");
1739             }
1740 
1741             if(session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
1742                 _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
1743                                "Keyboard-interactive "
1744                                "authentication successful");
1745                 LIBSSH2_FREE(session, session->userauth_kybd_data);
1746                 session->userauth_kybd_data = NULL;
1747                 session->state |= LIBSSH2_STATE_AUTHENTICATED;
1748                 session->userauth_kybd_state = libssh2_NB_state_idle;
1749                 return 0;
1750             }
1751 
1752             if(session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_FAILURE) {
1753                 _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
1754                                "Keyboard-interactive authentication failed");
1755                 LIBSSH2_FREE(session, session->userauth_kybd_data);
1756                 session->userauth_kybd_data = NULL;
1757                 session->userauth_kybd_state = libssh2_NB_state_idle;
1758                 return _libssh2_error(session,
1759                                       LIBSSH2_ERROR_AUTHENTICATION_FAILED,
1760                                       "Authentication failed "
1761                                       "(keyboard-interactive)");
1762             }
1763 
1764             /* server requested PAM-like conversation */
1765             s = session->userauth_kybd_data + 1;
1766 
1767             if(session->userauth_kybd_data_len >= 5) {
1768                 /* string    name (ISO-10646 UTF-8) */
1769                 session->userauth_kybd_auth_name_len = _libssh2_ntohu32(s);
1770                 s += 4;
1771             }
1772             else {
1773                 _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
1774                                "userauth keyboard data buffer too small"
1775                                "to get length");
1776                 goto cleanup;
1777             }
1778 
1779             if(session->userauth_kybd_auth_name_len) {
1780                 session->userauth_kybd_auth_name =
1781                     LIBSSH2_ALLOC(session,
1782                                   session->userauth_kybd_auth_name_len);
1783                 if(!session->userauth_kybd_auth_name) {
1784                     _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1785                                    "Unable to allocate memory for "
1786                                    "keyboard-interactive 'name' "
1787                                    "request field");
1788                     goto cleanup;
1789                 }
1790                 if(s + session->userauth_list_data_len <=
1791                    session->userauth_kybd_data +
1792                    session->userauth_kybd_data_len) {
1793                     memcpy(session->userauth_kybd_auth_name, s,
1794                            session->userauth_kybd_auth_name_len);
1795                     s += session->userauth_kybd_auth_name_len;
1796                 }
1797                 else {
1798                     _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
1799                                    "userauth keyboard data buffer too small"
1800                                    "for auth name");
1801                     goto cleanup;
1802                 }
1803             }
1804 
1805             if(s + 4 <= session->userauth_kybd_data +
1806                session->userauth_kybd_data_len) {
1807                 /* string    instruction (ISO-10646 UTF-8) */
1808                 session->userauth_kybd_auth_instruction_len =
1809                     _libssh2_ntohu32(s);
1810                 s += 4;
1811             }
1812             else {
1813                 _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
1814                                "userauth keyboard data buffer too small"
1815                                "for auth instruction length");
1816                 goto cleanup;
1817             }
1818 
1819             if(session->userauth_kybd_auth_instruction_len) {
1820                 session->userauth_kybd_auth_instruction =
1821                     LIBSSH2_ALLOC(session,
1822                                   session->userauth_kybd_auth_instruction_len);
1823                 if(!session->userauth_kybd_auth_instruction) {
1824                     _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1825                                    "Unable to allocate memory for "
1826                                    "keyboard-interactive 'instruction' "
1827                                    "request field");
1828                     goto cleanup;
1829                 }
1830                 if(s + session->userauth_kybd_auth_instruction_len <=
1831                    session->userauth_kybd_data +
1832                    session->userauth_kybd_data_len) {
1833                     memcpy(session->userauth_kybd_auth_instruction, s,
1834                            session->userauth_kybd_auth_instruction_len);
1835                     s += session->userauth_kybd_auth_instruction_len;
1836                 }
1837                 else {
1838                     _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
1839                                    "userauth keyboard data buffer too small"
1840                                    "for auth instruction");
1841                     goto cleanup;
1842                 }
1843             }
1844 
1845             if(s + 4 <= session->userauth_kybd_data +
1846                session->userauth_kybd_data_len) {
1847                 /* string    language tag (as defined in [RFC-3066]) */
1848                 language_tag_len = _libssh2_ntohu32(s);
1849                 s += 4;
1850             }
1851             else {
1852                 _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
1853                                "userauth keyboard data buffer too small"
1854                                "for auth language tag length");
1855                 goto cleanup;
1856             }
1857 
1858             if(s + language_tag_len <= session->userauth_kybd_data +
1859                session->userauth_kybd_data_len) {
1860                 /* ignoring this field as deprecated */
1861                 s += language_tag_len;
1862             }
1863             else {
1864                 _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
1865                                "userauth keyboard data buffer too small"
1866                                "for auth language tag");
1867                 goto cleanup;
1868             }
1869 
1870             if(s + 4 <= session->userauth_kybd_data +
1871                session->userauth_kybd_data_len) {
1872                 /* int       num-prompts */
1873                 session->userauth_kybd_num_prompts = _libssh2_ntohu32(s);
1874                 s += 4;
1875             }
1876             else {
1877                 _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
1878                                "userauth keyboard data buffer too small"
1879                                "for auth num keyboard prompts");
1880                 goto cleanup;
1881             }
1882 
1883             if(session->userauth_kybd_num_prompts > 100) {
1884                 _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY,
1885                                "Too many replies for "
1886                                "keyboard-interactive prompts");
1887                 goto cleanup;
1888             }
1889 
1890             if(session->userauth_kybd_num_prompts) {
1891                 session->userauth_kybd_prompts =
1892                     LIBSSH2_CALLOC(session,
1893                                    sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) *
1894                                    session->userauth_kybd_num_prompts);
1895                 if(!session->userauth_kybd_prompts) {
1896                     _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1897                                    "Unable to allocate memory for "
1898                                    "keyboard-interactive prompts array");
1899                     goto cleanup;
1900                 }
1901 
1902                 session->userauth_kybd_responses =
1903                     LIBSSH2_CALLOC(session,
1904                                    sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) *
1905                                    session->userauth_kybd_num_prompts);
1906                 if(!session->userauth_kybd_responses) {
1907                     _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1908                                    "Unable to allocate memory for "
1909                                    "keyboard-interactive responses array");
1910                     goto cleanup;
1911                 }
1912 
1913                 for(i = 0; i < session->userauth_kybd_num_prompts; i++) {
1914                     if(s + 4 <= session->userauth_kybd_data +
1915                        session->userauth_kybd_data_len) {
1916                         /* string    prompt[1] (ISO-10646 UTF-8) */
1917                         session->userauth_kybd_prompts[i].length =
1918                             _libssh2_ntohu32(s);
1919                         s += 4;
1920                     }
1921                     else {
1922                         _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
1923                                        "userauth keyboard data buffer too "
1924                                        "small for auth keyboard "
1925                                        "prompt length");
1926                         goto cleanup;
1927                     }
1928 
1929                     session->userauth_kybd_prompts[i].text =
1930                         LIBSSH2_CALLOC(session,
1931                                        session->userauth_kybd_prompts[i].
1932                                        length);
1933                     if(!session->userauth_kybd_prompts[i].text) {
1934                         _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1935                                        "Unable to allocate memory for "
1936                                        "keyboard-interactive prompt message");
1937                         goto cleanup;
1938                     }
1939 
1940                     if(s + session->userauth_kybd_prompts[i].length <=
1941                        session->userauth_kybd_data +
1942                        session->userauth_kybd_data_len) {
1943                         memcpy(session->userauth_kybd_prompts[i].text, s,
1944                                session->userauth_kybd_prompts[i].length);
1945                         s += session->userauth_kybd_prompts[i].length;
1946                     }
1947                     else {
1948                         _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
1949                                        "userauth keyboard data buffer too "
1950                                        "small for auth keyboard prompt");
1951                         goto cleanup;
1952                     }
1953                     if(s < session->userauth_kybd_data +
1954                        session->userauth_kybd_data_len) {
1955                         /* boolean   echo[1] */
1956                         session->userauth_kybd_prompts[i].echo = *s++;
1957                     }
1958                     else {
1959                         _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
1960                                        "userauth keyboard data buffer too "
1961                                        "small for auth keyboard prompt echo");
1962                         goto cleanup;
1963                     }
1964                 }
1965             }
1966 
1967             response_callback(session->userauth_kybd_auth_name,
1968                               session->userauth_kybd_auth_name_len,
1969                               session->userauth_kybd_auth_instruction,
1970                               session->userauth_kybd_auth_instruction_len,
1971                               session->userauth_kybd_num_prompts,
1972                               session->userauth_kybd_prompts,
1973                               session->userauth_kybd_responses,
1974                               &session->abstract);
1975 
1976             _libssh2_debug(session, LIBSSH2_TRACE_AUTH,
1977                            "Keyboard-interactive response callback function"
1978                            " invoked");
1979 
1980             session->userauth_kybd_packet_len =
1981                 1 /* byte      SSH_MSG_USERAUTH_INFO_RESPONSE */
1982                 + 4             /* int       num-responses */
1983                 ;
1984 
1985             for(i = 0; i < session->userauth_kybd_num_prompts; i++) {
1986                 /* string    response[1] (ISO-10646 UTF-8) */
1987                 if(session->userauth_kybd_responses[i].length <=
1988                    (SIZE_MAX - 4 - session->userauth_kybd_packet_len) ) {
1989                     session->userauth_kybd_packet_len +=
1990                         4 + session->userauth_kybd_responses[i].length;
1991                 }
1992                 else {
1993                     _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1994                                    "Unable to allocate memory for keyboard-"
1995                                    "interactive response packet");
1996                     goto cleanup;
1997                 }
1998             }
1999 
2000             /* A new userauth_kybd_data area is to be allocated, free the
2001                former one. */
2002             LIBSSH2_FREE(session, session->userauth_kybd_data);
2003 
2004             session->userauth_kybd_data = s =
2005                 LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len);
2006             if(!s) {
2007                 _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
2008                                "Unable to allocate memory for keyboard-"
2009                                "interactive response packet");
2010                 goto cleanup;
2011             }
2012 
2013             *s = SSH_MSG_USERAUTH_INFO_RESPONSE;
2014             s++;
2015             _libssh2_store_u32(&s, session->userauth_kybd_num_prompts);
2016 
2017             for(i = 0; i < session->userauth_kybd_num_prompts; i++) {
2018                 _libssh2_store_str(&s,
2019                                    session->userauth_kybd_responses[i].text,
2020                                    session->userauth_kybd_responses[i].length);
2021             }
2022 
2023             session->userauth_kybd_state = libssh2_NB_state_sent1;
2024         }
2025 
2026         if(session->userauth_kybd_state == libssh2_NB_state_sent1) {
2027             rc = _libssh2_transport_send(session, session->userauth_kybd_data,
2028                                          session->userauth_kybd_packet_len,
2029                                          NULL, 0);
2030             if(rc == LIBSSH2_ERROR_EAGAIN)
2031                 return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
2032                                       "Would block");
2033             if(rc) {
2034                 _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
2035                                "Unable to send userauth-keyboard-interactive"
2036                                " request");
2037                 goto cleanup;
2038             }
2039 
2040             session->userauth_kybd_auth_failure = 0;
2041         }
2042 
2043       cleanup:
2044         /*
2045          * It's safe to clean all the data here, because unallocated pointers
2046          * are filled by zeroes
2047          */
2048 
2049         LIBSSH2_FREE(session, session->userauth_kybd_data);
2050         session->userauth_kybd_data = NULL;
2051 
2052         if(session->userauth_kybd_prompts) {
2053             for(i = 0; i < session->userauth_kybd_num_prompts; i++) {
2054                 LIBSSH2_FREE(session, session->userauth_kybd_prompts[i].text);
2055                 session->userauth_kybd_prompts[i].text = NULL;
2056             }
2057         }
2058 
2059         if(session->userauth_kybd_responses) {
2060             for(i = 0; i < session->userauth_kybd_num_prompts; i++) {
2061                 LIBSSH2_FREE(session,
2062                              session->userauth_kybd_responses[i].text);
2063                 session->userauth_kybd_responses[i].text = NULL;
2064             }
2065         }
2066 
2067         if(session->userauth_kybd_prompts) {
2068             LIBSSH2_FREE(session, session->userauth_kybd_prompts);
2069             session->userauth_kybd_prompts = NULL;
2070         }
2071         if(session->userauth_kybd_responses) {
2072             LIBSSH2_FREE(session, session->userauth_kybd_responses);
2073             session->userauth_kybd_responses = NULL;
2074         }
2075         if(session->userauth_kybd_auth_name) {
2076             LIBSSH2_FREE(session, session->userauth_kybd_auth_name);
2077             session->userauth_kybd_auth_name = NULL;
2078         }
2079         if(session->userauth_kybd_auth_instruction) {
2080             LIBSSH2_FREE(session, session->userauth_kybd_auth_instruction);
2081             session->userauth_kybd_auth_instruction = NULL;
2082         }
2083 
2084         if(session->userauth_kybd_auth_failure) {
2085             session->userauth_kybd_state = libssh2_NB_state_idle;
2086             return -1;
2087         }
2088 
2089         session->userauth_kybd_state = libssh2_NB_state_sent;
2090     }
2091 }
2092 
2093 /*
2094  * libssh2_userauth_keyboard_interactive_ex
2095  *
2096  * Authenticate using a challenge-response authentication
2097  */
2098 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)))2099 libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session,
2100                                          const char *user,
2101                                          unsigned int user_len,
2102                                          LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC
2103                                          ((*response_callback)))
2104 {
2105     int rc;
2106     BLOCK_ADJUST(rc, session,
2107                  userauth_keyboard_interactive(session, user, user_len,
2108                                                response_callback));
2109     return rc;
2110 }
2111