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