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