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