We now build libssh2 in Xcode and it's a much better UB/10.4 citizen
[printdrop.git] / Vendor / libssh2 / Source / userauth.c
1 /* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms,
5 * with or without modification, are permitted provided
6 * that the following conditions are met:
7 *
8 * Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the
10 * following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials
15 * provided with the distribution.
16 *
17 * Neither the name of the copyright holder nor the names
18 * of any other contributors may be used to endorse or
19 * promote products derived from this software without
20 * specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
23 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
34 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
35 * OF SUCH DAMAGE.
36 */
37
38 #include "libssh2_priv.h"
39
40 #include <ctype.h>
41 #include <stdio.h>
42
43 /* Needed for struct iovec on some platforms */
44 #ifdef HAVE_SYS_UIO_H
45 #include <sys/uio.h>
46 #endif
47
48
49 /* {{{ proto libssh2_userauth_list
50 * List authentication methods
51 * Will yield successful login if "none" happens to be allowable for this user
52 * Not a common configuration for any SSH server though
53 * username should be NULL, or a null terminated string
54 */
55 LIBSSH2_API char *
56 libssh2_userauth_list(LIBSSH2_SESSION * session, const char *username,
57 unsigned int username_len)
58 {
59 static const unsigned char reply_codes[3] =
60 { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
61 /* packet_type(1) + username_len(4) + service_len(4) +
62 service(14)"ssh-connection" + method_len(4) + method(4)"none" */
63 unsigned long methods_len;
64 unsigned char *s;
65 int rc;
66
67 if (session->userauth_list_state == libssh2_NB_state_idle) {
68 /* Zero the whole thing out */
69 memset(&session->userauth_list_packet_requirev_state, 0,
70 sizeof(session->userauth_list_packet_requirev_state));
71
72 session->userauth_list_data_len = username_len + 31;
73
74 s = session->userauth_list_data =
75 LIBSSH2_ALLOC(session, session->userauth_list_data_len);
76 if (!session->userauth_list_data) {
77 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
78 "Unable to allocate memory for userauth_list", 0);
79 return NULL;
80 }
81
82 *(s++) = SSH_MSG_USERAUTH_REQUEST;
83 libssh2_htonu32(s, username_len);
84 s += 4;
85 if (username) {
86 memcpy(s, username, username_len);
87 s += username_len;
88 }
89
90 libssh2_htonu32(s, 14);
91 s += 4;
92 memcpy(s, "ssh-connection", 14);
93 s += 14;
94
95 libssh2_htonu32(s, 4);
96 s += 4;
97 memcpy(s, "none", 4);
98 s += 4;
99
100 session->userauth_list_state = libssh2_NB_state_created;
101 }
102
103 if (session->userauth_list_state == libssh2_NB_state_created) {
104 rc = libssh2_packet_write(session, session->userauth_list_data,
105 session->userauth_list_data_len);
106 if (rc == PACKET_EAGAIN) {
107 libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
108 "Would block requesting userauth list", 0);
109 return NULL;
110 } else if (rc) {
111 libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
112 "Unable to send userauth-none request", 0);
113 LIBSSH2_FREE(session, session->userauth_list_data);
114 session->userauth_list_data = NULL;
115 session->userauth_list_state = libssh2_NB_state_idle;
116 return NULL;
117 }
118 LIBSSH2_FREE(session, session->userauth_list_data);
119 session->userauth_list_data = NULL;
120
121 session->userauth_list_state = libssh2_NB_state_sent;
122 }
123
124 if (session->userauth_list_state == libssh2_NB_state_sent) {
125 rc = libssh2_packet_requirev_ex(session, reply_codes,
126 &session->userauth_list_data,
127 &session->userauth_list_data_len, 0,
128 NULL, 0,
129 &session->
130 userauth_list_packet_requirev_state);
131 if (rc == PACKET_EAGAIN) {
132 libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
133 "Would block requesting userauth list", 0);
134 return NULL;
135 } else if (rc) {
136 libssh2_error(session, LIBSSH2_ERROR_NONE, "No error", 0);
137 session->userauth_list_state = libssh2_NB_state_idle;
138 return NULL;
139 }
140
141 if (session->userauth_list_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
142 /* Wow, who'dve thought... */
143 libssh2_error(session, LIBSSH2_ERROR_NONE, "No error", 0);
144 LIBSSH2_FREE(session, session->userauth_list_data);
145 session->userauth_list_data = NULL;
146 session->state |= LIBSSH2_STATE_AUTHENTICATED;
147 session->userauth_list_state = libssh2_NB_state_idle;
148 return NULL;
149 }
150
151 methods_len = libssh2_ntohu32(session->userauth_list_data + 1);
152 memcpy(session->userauth_list_data, session->userauth_list_data + 5,
153 methods_len);
154 session->userauth_list_data[methods_len] = '\0';
155 _libssh2_debug(session, LIBSSH2_DBG_AUTH, "Permitted auth methods: %s",
156 session->userauth_list_data);
157 }
158
159 session->userauth_list_state = libssh2_NB_state_idle;
160 return (char *) session->userauth_list_data;
161 }
162
163 /* }}} */
164
165 /* {{{ libssh2_userauth_authenticated
166 * 0 if not yet authenticated
167 * non-zero is already authenticated
168 */
169 LIBSSH2_API int
170 libssh2_userauth_authenticated(LIBSSH2_SESSION * session)
171 {
172 return session->state & LIBSSH2_STATE_AUTHENTICATED;
173 }
174
175 /* }}} */
176
177 /* {{{ libssh2_userauth_password
178 * Plain ol' login
179 */
180 LIBSSH2_API int
181 libssh2_userauth_password_ex(LIBSSH2_SESSION * session, const char *username,
182 unsigned int username_len, const char *password,
183 unsigned int password_len,
184 LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)))
185 {
186 unsigned char *s;
187 static const unsigned char reply_codes[4] =
188 { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE,
189 SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0
190 };
191 int rc;
192
193 if (session->userauth_pswd_state == libssh2_NB_state_idle) {
194 /* Zero the whole thing out */
195 memset(&session->userauth_pswd_packet_requirev_state, 0,
196 sizeof(session->userauth_pswd_packet_requirev_state));
197
198 /*
199 * 40 = acket_type(1) + username_len(4) + service_len(4) +
200 * service(14)"ssh-connection" + method_len(4) + method(8)"password" +
201 * chgpwdbool(1) + password_len(4) */
202 session->userauth_pswd_data_len = username_len + password_len + 40;
203
204 session->userauth_pswd_data0 = ~SSH_MSG_USERAUTH_PASSWD_CHANGEREQ;
205
206 s = session->userauth_pswd_data =
207 LIBSSH2_ALLOC(session, session->userauth_pswd_data_len);
208 if (!session->userauth_pswd_data) {
209 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
210 "Unable to allocate memory for userauth-password request",
211 0);
212 return -1;
213 }
214
215 *(s++) = SSH_MSG_USERAUTH_REQUEST;
216 libssh2_htonu32(s, username_len);
217 s += 4;
218 memcpy(s, username, username_len);
219 s += username_len;
220
221 libssh2_htonu32(s, sizeof("ssh-connection") - 1);
222 s += 4;
223 memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1);
224 s += sizeof("ssh-connection") - 1;
225
226 libssh2_htonu32(s, sizeof("password") - 1);
227 s += 4;
228 memcpy(s, "password", sizeof("password") - 1);
229 s += sizeof("password") - 1;
230
231 *s = '\0';
232 s++;
233
234 libssh2_htonu32(s, password_len);
235 s += 4;
236 memcpy(s, password, password_len);
237 s += password_len;
238
239 _libssh2_debug(session, LIBSSH2_DBG_AUTH,
240 "Attempting to login using password authentication");
241
242 session->userauth_pswd_state = libssh2_NB_state_created;
243 }
244
245 if (session->userauth_pswd_state == libssh2_NB_state_created) {
246 rc = libssh2_packet_write(session, session->userauth_pswd_data,
247 session->userauth_pswd_data_len);
248 if (rc == PACKET_EAGAIN) {
249 return PACKET_EAGAIN;
250 } else if (rc) {
251 libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
252 "Unable to send userauth-password request", 0);
253 LIBSSH2_FREE(session, session->userauth_pswd_data);
254 session->userauth_pswd_data = NULL;
255 session->userauth_pswd_state = libssh2_NB_state_idle;
256 return -1;
257 }
258 LIBSSH2_FREE(session, session->userauth_pswd_data);
259 session->userauth_pswd_data = NULL;
260
261 session->userauth_pswd_state = libssh2_NB_state_sent;
262 }
263
264 password_response:
265
266 if ((session->userauth_pswd_state == libssh2_NB_state_sent)
267 || (session->userauth_pswd_state == libssh2_NB_state_sent1)
268 || (session->userauth_pswd_state == libssh2_NB_state_sent2)) {
269 if (session->userauth_pswd_state == libssh2_NB_state_sent) {
270 rc = libssh2_packet_requirev_ex(session, reply_codes,
271 &session->userauth_pswd_data,
272 &session->userauth_pswd_data_len,
273 0, NULL, 0,
274 &session->
275 userauth_pswd_packet_requirev_state);
276 if (rc == PACKET_EAGAIN) {
277 return PACKET_EAGAIN;
278 } else if (rc) {
279 session->userauth_pswd_state = libssh2_NB_state_idle;
280 return -1;
281 }
282
283 if (session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
284 _libssh2_debug(session, LIBSSH2_DBG_AUTH,
285 "Password authentication successful");
286 LIBSSH2_FREE(session, session->userauth_pswd_data);
287 session->userauth_pswd_data = NULL;
288 session->state |= LIBSSH2_STATE_AUTHENTICATED;
289 session->userauth_pswd_state = libssh2_NB_state_idle;
290 return 0;
291 }
292
293 session->userauth_pswd_newpw = NULL;
294 session->userauth_pswd_newpw_len = 0;
295
296 session->userauth_pswd_state = libssh2_NB_state_sent1;
297 }
298
299 if ((session->userauth_pswd_data[0] ==
300 SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)
301 || (session->userauth_pswd_data0 ==
302 SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)) {
303 session->userauth_pswd_data0 = SSH_MSG_USERAUTH_PASSWD_CHANGEREQ;
304
305 if ((session->userauth_pswd_state == libssh2_NB_state_sent1) ||
306 (session->userauth_pswd_state == libssh2_NB_state_sent2)) {
307 if (session->userauth_pswd_state == libssh2_NB_state_sent1) {
308 _libssh2_debug(session, LIBSSH2_DBG_AUTH,
309 "Password change required");
310 LIBSSH2_FREE(session, session->userauth_pswd_data);
311 session->userauth_pswd_data = NULL;
312 }
313 if (passwd_change_cb) {
314 if (session->userauth_pswd_state == libssh2_NB_state_sent1) {
315 passwd_change_cb(session,
316 &session->userauth_pswd_newpw,
317 &session->userauth_pswd_newpw_len,
318 &session->abstract);
319 if (!session->userauth_pswd_newpw) {
320 libssh2_error(session,
321 LIBSSH2_ERROR_PASSWORD_EXPIRED,
322 "Password expired, and callback failed",
323 0);
324 return -1;
325 }
326
327 /* basic data_len + newpw_len(4) */
328 session->userauth_pswd_data_len =
329 username_len + password_len + 44 +
330 session->userauth_pswd_newpw_len;
331
332 s = session->userauth_pswd_data =
333 LIBSSH2_ALLOC(session,
334 session->userauth_pswd_data_len);
335 if (!session->userauth_pswd_data) {
336 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
337 "Unable to allocate memory for userauth-password-change request",
338 0);
339 LIBSSH2_FREE(session,
340 session->userauth_pswd_newpw);
341 session->userauth_pswd_newpw = NULL;
342 return -1;
343 }
344
345 *(s++) = SSH_MSG_USERAUTH_REQUEST;
346 libssh2_htonu32(s, username_len);
347 s += 4;
348 memcpy(s, username, username_len);
349 s += username_len;
350
351 libssh2_htonu32(s, sizeof("ssh-connection") - 1);
352 s += 4;
353 memcpy(s, "ssh-connection",
354 sizeof("ssh-connection") - 1);
355 s += sizeof("ssh-connection") - 1;
356
357 libssh2_htonu32(s, sizeof("password") - 1);
358 s += 4;
359 memcpy(s, "password", sizeof("password") - 1);
360 s += sizeof("password") - 1;
361
362 *s = 0x01;
363 s++;
364
365 libssh2_htonu32(s, password_len);
366 s += 4;
367 memcpy(s, password, password_len);
368 s += password_len;
369
370 libssh2_htonu32(s, session->userauth_pswd_newpw_len);
371 s += 4;
372 memcpy(s, session->userauth_pswd_newpw,
373 session->userauth_pswd_newpw_len);
374 s += session->userauth_pswd_newpw_len;
375
376 session->userauth_pswd_state = libssh2_NB_state_sent2;
377 }
378
379 if (session->userauth_pswd_state == libssh2_NB_state_sent2) {
380 rc = libssh2_packet_write(session,
381 session->userauth_pswd_data,
382 session->
383 userauth_pswd_data_len);
384 if (rc == PACKET_EAGAIN) {
385 return PACKET_EAGAIN;
386 } else if (rc) {
387 libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
388 "Unable to send userauth-password-change request",
389 0);
390 LIBSSH2_FREE(session, session->userauth_pswd_data);
391 session->userauth_pswd_data = NULL;
392 LIBSSH2_FREE(session,
393 session->userauth_pswd_newpw);
394 session->userauth_pswd_newpw = NULL;
395 return -1;
396 }
397 LIBSSH2_FREE(session, session->userauth_pswd_data);
398 session->userauth_pswd_data = NULL;
399 LIBSSH2_FREE(session, session->userauth_pswd_newpw);
400 session->userauth_pswd_newpw = NULL;
401
402 /*
403 * Ugliest use of goto ever. Blame it on the
404 * askN => requirev migration.
405 */
406 session->userauth_pswd_state = libssh2_NB_state_sent;
407 goto password_response;
408 }
409 }
410 } else {
411 libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED,
412 "Password Expired, and no callback specified",
413 0);
414 session->userauth_pswd_state = libssh2_NB_state_idle;
415 return -1;
416 }
417 }
418 }
419
420 /* FAILURE */
421 LIBSSH2_FREE(session, session->userauth_pswd_data);
422 session->userauth_pswd_data = NULL;
423 session->userauth_pswd_state = libssh2_NB_state_idle;
424 return -1;
425 }
426
427 /* }}} */
428
429 /* {{{ libssh2_file_read_publickey
430 * Read a public key from an id_???.pub style file
431 */
432 static int
433 libssh2_file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method,
434 unsigned long *method_len,
435 unsigned char **pubkeydata,
436 unsigned long *pubkeydata_len,
437 const char *pubkeyfile)
438 {
439 FILE *fd;
440 char c;
441 unsigned char *pubkey = NULL, *sp1, *sp2, *tmp;
442 size_t pubkey_len = 0;
443 unsigned int tmp_len;
444
445 _libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading public key file: %s",
446 pubkeyfile);
447 /* Read Public Key */
448 fd = fopen(pubkeyfile, "r");
449 if (!fd) {
450 libssh2_error(session, LIBSSH2_ERROR_FILE,
451 "Unable to open public key file", 0);
452 return -1;
453 }
454 while (!feof(fd) && (c = fgetc(fd)) != '\r' && c != '\n')
455 pubkey_len++;
456 if (feof(fd)) {
457 /* the last character was EOF */
458 pubkey_len--;
459 }
460 rewind(fd);
461
462 if (pubkey_len <= 1) {
463 libssh2_error(session, LIBSSH2_ERROR_FILE,
464 "Invalid data in public key file", 0);
465 fclose(fd);
466 return -1;
467 }
468
469 pubkey = LIBSSH2_ALLOC(session, pubkey_len);
470 if (!pubkey) {
471 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
472 "Unable to allocate memory for public key data", 0);
473 fclose(fd);
474 return -1;
475 }
476 if (fread(pubkey, 1, pubkey_len, fd) != pubkey_len) {
477 libssh2_error(session, LIBSSH2_ERROR_FILE,
478 "Unable to read public key from file", 0);
479 LIBSSH2_FREE(session, pubkey);
480 fclose(fd);
481 return -1;
482 }
483 fclose(fd);
484 /*
485 * Remove trailing whitespace
486 */
487 while (pubkey_len && isspace(pubkey[pubkey_len - 1]))
488 pubkey_len--;
489
490 if (!pubkey_len) {
491 libssh2_error(session, LIBSSH2_ERROR_FILE, "Missing public key data",
492 0);
493 LIBSSH2_FREE(session, pubkey);
494 return -1;
495 }
496
497 if ((sp1 = memchr(pubkey, ' ', pubkey_len)) == NULL) {
498 libssh2_error(session, LIBSSH2_ERROR_FILE, "Invalid public key data",
499 0);
500 LIBSSH2_FREE(session, pubkey);
501 return -1;
502 }
503 /* Wasting some bytes here (okay, more than some),
504 * but since it's likely to be freed soon anyway,
505 * we'll just avoid the extra free/alloc and call it a wash */
506 *method = pubkey;
507 *method_len = sp1 - pubkey;
508
509 sp1++;
510
511 if ((sp2 = memchr(sp1, ' ', pubkey_len - *method_len)) == NULL) {
512 /* Assume that the id string is missing, but that it's okay */
513 sp2 = pubkey + pubkey_len;
514 }
515
516 if (libssh2_base64_decode
517 (session, (char **) &tmp, &tmp_len, (char *) sp1, sp2 - sp1)) {
518 libssh2_error(session, LIBSSH2_ERROR_FILE,
519 "Invalid key data, not base64 encoded", 0);
520 LIBSSH2_FREE(session, pubkey);
521 return -1;
522 }
523 *pubkeydata = tmp;
524 *pubkeydata_len = tmp_len;
525
526 return 0;
527 }
528
529 /* }}} */
530
531 /* {{{ libssh2_file_read_privatekey
532 * Read a PEM encoded private key from an id_??? style file
533 */
534 static int
535 libssh2_file_read_privatekey(LIBSSH2_SESSION * session,
536 const LIBSSH2_HOSTKEY_METHOD ** hostkey_method,
537 void **hostkey_abstract,
538 const unsigned char *method, int method_len,
539 const char *privkeyfile, const char *passphrase)
540 {
541 const LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail =
542 libssh2_hostkey_methods();
543
544 _libssh2_debug(session, LIBSSH2_DBG_AUTH, "Loading private key file: %s",
545 privkeyfile);
546 *hostkey_method = NULL;
547 *hostkey_abstract = NULL;
548 while (*hostkey_methods_avail && (*hostkey_methods_avail)->name) {
549 if ((*hostkey_methods_avail)->initPEM
550 && strncmp((*hostkey_methods_avail)->name, (const char *) method,
551 method_len) == 0) {
552 *hostkey_method = *hostkey_methods_avail;
553 break;
554 }
555 hostkey_methods_avail++;
556 }
557 if (!*hostkey_method) {
558 libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE,
559 "No handler for specified private key", 0);
560 return -1;
561 }
562
563 if ((*hostkey_method)->
564 initPEM(session, privkeyfile, (unsigned char *) passphrase,
565 hostkey_abstract)) {
566 libssh2_error(session, LIBSSH2_ERROR_FILE,
567 "Unable to initialize private key from file", 0);
568 return -1;
569 }
570
571 return 0;
572 }
573
574 /* }}} */
575
576 /* {{{ libssh2_userauth_hostbased_fromfile_ex
577 * Authenticate using a keypair found in the named files
578 */
579 LIBSSH2_API int
580 libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION * session,
581 const char *username,
582 unsigned int username_len,
583 const char *publickey,
584 const char *privatekey,
585 const char *passphrase,
586 const char *hostname,
587 unsigned int hostname_len,
588 const char *local_username,
589 unsigned int local_username_len)
590 {
591 const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
592 void *abstract;
593 unsigned char buf[5];
594 struct iovec datavec[4];
595 unsigned char *pubkeydata, *sig;
596 static const unsigned char reply_codes[3] =
597 { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
598 unsigned long pubkeydata_len, sig_len, data_len;
599 int rc;
600
601 if (session->userauth_host_state == libssh2_NB_state_idle) {
602 /* Zero the whole thing out */
603 memset(&session->userauth_host_packet_requirev_state, 0,
604 sizeof(session->userauth_host_packet_requirev_state));
605
606 if (libssh2_file_read_publickey
607 (session, &session->userauth_host_method,
608 &session->userauth_host_method_len, &pubkeydata, &pubkeydata_len,
609 publickey)) {
610 return -1;
611 }
612
613 /*
614 * 48 = packet_type(1) + username_len(4) + servicename_len(4) +
615 * service_name(14)"ssh-connection" + authmethod_len(4) +
616 * authmethod(9)"hostbased" + method_len(4) + pubkeydata_len(4) +
617 * local_username_len(4)
618 */
619 session->userauth_host_packet_len =
620 username_len + session->userauth_host_method_len + hostname_len +
621 local_username_len + pubkeydata_len + 48;
622
623 /*
624 * Preallocate space for an overall length, method name again,
625 * and the signature, which won't be any larger than the size of
626 * the publickeydata itself
627 */
628 session->userauth_host_s = session->userauth_host_packet =
629 LIBSSH2_ALLOC(session,
630 session->userauth_host_packet_len + 4 + (4 +
631 session->
632 userauth_host_method_len)
633 + (4 + pubkeydata_len));
634 if (!session->userauth_host_packet) {
635 LIBSSH2_FREE(session, session->userauth_host_method);
636 session->userauth_host_method = NULL;
637 return -1;
638 }
639
640 *(session->userauth_host_s++) = SSH_MSG_USERAUTH_REQUEST;
641 libssh2_htonu32(session->userauth_host_s, username_len);
642 session->userauth_host_s += 4;
643 memcpy(session->userauth_host_s, username, username_len);
644 session->userauth_host_s += username_len;
645
646 libssh2_htonu32(session->userauth_host_s, 14);
647 session->userauth_host_s += 4;
648 memcpy(session->userauth_host_s, "ssh-connection", 14);
649 session->userauth_host_s += 14;
650
651 libssh2_htonu32(session->userauth_host_s, 9);
652 session->userauth_host_s += 4;
653 memcpy(session->userauth_host_s, "hostbased", 9);
654 session->userauth_host_s += 9;
655
656 libssh2_htonu32(session->userauth_host_s,
657 session->userauth_host_method_len);
658 session->userauth_host_s += 4;
659 memcpy(session->userauth_host_s, session->userauth_host_method,
660 session->userauth_host_method_len);
661 session->userauth_host_s += session->userauth_host_method_len;
662
663 libssh2_htonu32(session->userauth_host_s, pubkeydata_len);
664 session->userauth_host_s += 4;
665 memcpy(session->userauth_host_s, pubkeydata, pubkeydata_len);
666 session->userauth_host_s += pubkeydata_len;
667
668 libssh2_htonu32(session->userauth_host_s, hostname_len);
669 session->userauth_host_s += 4;
670 memcpy(session->userauth_host_s, hostname, hostname_len);
671 session->userauth_host_s += hostname_len;
672
673 libssh2_htonu32(session->userauth_host_s, local_username_len);
674 session->userauth_host_s += 4;
675 memcpy(session->userauth_host_s, local_username, local_username_len);
676 session->userauth_host_s += local_username_len;
677
678 if (libssh2_file_read_privatekey
679 (session, &privkeyobj, &abstract, session->userauth_host_method,
680 session->userauth_host_method_len, privatekey, passphrase)) {
681 LIBSSH2_FREE(session, session->userauth_host_method);
682 session->userauth_host_method = NULL;
683 LIBSSH2_FREE(session, session->userauth_host_packet);
684 session->userauth_host_packet = NULL;
685 return -1;
686 }
687
688 libssh2_htonu32(buf, session->session_id_len);
689 datavec[0].iov_base = buf;
690 datavec[0].iov_len = 4;
691 datavec[1].iov_base = session->session_id;
692 datavec[1].iov_len = session->session_id_len;
693 datavec[2].iov_base = session->userauth_host_packet;
694 datavec[2].iov_len = session->userauth_host_packet_len;
695
696 if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
697 LIBSSH2_FREE(session, session->userauth_host_method);
698 session->userauth_host_method = NULL;
699 LIBSSH2_FREE(session, session->userauth_host_packet);
700 session->userauth_host_packet = NULL;
701 if (privkeyobj->dtor) {
702 privkeyobj->dtor(session, &abstract);
703 }
704 return -1;
705 }
706
707 if (privkeyobj->dtor) {
708 privkeyobj->dtor(session, &abstract);
709 }
710
711 if (sig_len > pubkeydata_len) {
712 unsigned char *newpacket;
713 /* Should *NEVER* happen, but...well.. better safe than sorry */
714 newpacket = LIBSSH2_REALLOC(session, session->userauth_host_packet, session->userauth_host_packet_len + 4 + (4 + session->userauth_host_method_len) + (4 + sig_len)); /* PK sigblob */
715 if (!newpacket) {
716 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
717 "Failed allocating additional space for userauth-hostbased packet",
718 0);
719 LIBSSH2_FREE(session, sig);
720 LIBSSH2_FREE(session, session->userauth_host_packet);
721 session->userauth_host_packet = NULL;
722 LIBSSH2_FREE(session, session->userauth_host_method);
723 session->userauth_host_method = NULL;
724 return -1;
725 }
726 session->userauth_host_packet = newpacket;
727 }
728
729 session->userauth_host_s =
730 session->userauth_host_packet + session->userauth_host_packet_len;
731
732 libssh2_htonu32(session->userauth_host_s,
733 4 + session->userauth_host_method_len + 4 + sig_len);
734 session->userauth_host_s += 4;
735
736 libssh2_htonu32(session->userauth_host_s,
737 session->userauth_host_method_len);
738 session->userauth_host_s += 4;
739 memcpy(session->userauth_host_s, session->userauth_host_method,
740 session->userauth_host_method_len);
741 session->userauth_host_s += session->userauth_host_method_len;
742 LIBSSH2_FREE(session, session->userauth_host_method);
743 session->userauth_host_method = NULL;
744
745 libssh2_htonu32(session->userauth_host_s, sig_len);
746 session->userauth_host_s += 4;
747 memcpy(session->userauth_host_s, sig, sig_len);
748 session->userauth_host_s += sig_len;
749 LIBSSH2_FREE(session, sig);
750
751 _libssh2_debug(session, LIBSSH2_DBG_AUTH,
752 "Attempting hostbased authentication");
753
754 session->userauth_host_state = libssh2_NB_state_created;
755 }
756
757 if (session->userauth_host_state == libssh2_NB_state_created) {
758 rc = libssh2_packet_write(session, session->userauth_host_packet,
759 session->userauth_host_s -
760 session->userauth_host_packet);
761 if (rc == PACKET_EAGAIN) {
762 return PACKET_EAGAIN;
763 } else if (rc) {
764 libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
765 "Unable to send userauth-hostbased request", 0);
766 LIBSSH2_FREE(session, session->userauth_host_packet);
767 session->userauth_host_packet = NULL;
768 session->userauth_host_state = libssh2_NB_state_idle;
769 return -1;
770 }
771 LIBSSH2_FREE(session, session->userauth_host_packet);
772 session->userauth_host_packet = NULL;
773
774 session->userauth_host_state = libssh2_NB_state_sent;
775 }
776
777 if (session->userauth_host_state == libssh2_NB_state_sent) {
778 rc = libssh2_packet_requirev_ex(session, reply_codes,
779 &session->userauth_host_data,
780 &data_len, 0, NULL, 0,
781 &session->
782 userauth_host_packet_requirev_state);
783 if (rc == PACKET_EAGAIN) {
784 return PACKET_EAGAIN;
785 } else if (rc) {
786 session->userauth_host_state = libssh2_NB_state_idle;
787 return -1;
788 }
789
790 if (session->userauth_host_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
791 _libssh2_debug(session, LIBSSH2_DBG_AUTH,
792 "Hostbased authentication successful");
793 /* We are us and we've proved it. */
794 LIBSSH2_FREE(session, session->userauth_host_data);
795 session->userauth_host_data = NULL;
796 session->state |= LIBSSH2_STATE_AUTHENTICATED;
797 session->userauth_host_state = libssh2_NB_state_idle;
798 return 0;
799 }
800 }
801
802 /* This public key is not allowed for this user on this server */
803 LIBSSH2_FREE(session, session->userauth_host_data);
804 session->userauth_host_data = NULL;
805 libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
806 "Invalid signature for supplied public key, or bad username/public key combination",
807 0);
808 session->userauth_host_state = libssh2_NB_state_idle;
809 return -1;
810 }
811
812 /* }}} */
813
814 /* {{{ libssh2_userauth_publickey_fromfile_ex
815 * Authenticate using a keypair found in the named files
816 */
817 LIBSSH2_API int
818 libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION * session,
819 const char *username,
820 unsigned int username_len,
821 const char *publickey,
822 const char *privatekey,
823 const char *passphrase)
824 {
825 const LIBSSH2_HOSTKEY_METHOD *privkeyobj;
826 void *abstract;
827 unsigned char buf[5];
828 struct iovec datavec[4];
829 unsigned char *pubkeydata, *sig;
830 unsigned char reply_codes[4] =
831 { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE,
832 SSH_MSG_USERAUTH_PK_OK, 0
833 };
834 unsigned long pubkeydata_len, sig_len;
835 int rc;
836
837 if (session->userauth_pblc_state == libssh2_NB_state_idle) {
838 /* Zero the whole thing out */
839 memset(&session->userauth_pblc_packet_requirev_state, 0,
840 sizeof(session->userauth_pblc_packet_requirev_state));
841
842 if (libssh2_file_read_publickey
843 (session, &session->userauth_pblc_method,
844 &session->userauth_pblc_method_len, &pubkeydata, &pubkeydata_len,
845 publickey)) {
846 return -1;
847 }
848
849 /*
850 * 45 = packet_type(1) + username_len(4) + servicename_len(4) +
851 * service_name(14)"ssh-connection" + authmethod_len(4) +
852 * authmethod(9)"publickey" + sig_included(1)'\0' + algmethod_len(4) +
853 * publickey_len(4)
854 */
855 session->userauth_pblc_packet_len =
856 username_len + session->userauth_pblc_method_len + pubkeydata_len +
857 45;
858
859 /*
860 * Preallocate space for an overall length, method name again, and
861 * the signature, which won't be any larger than the size of the
862 * publickeydata itself
863 */
864 session->userauth_pblc_s = session->userauth_pblc_packet =
865 LIBSSH2_ALLOC(session,
866 session->userauth_pblc_packet_len + 4 + (4 +
867 session->
868 userauth_pblc_method_len)
869 + (4 + pubkeydata_len));
870 if (!session->userauth_pblc_packet) {
871 LIBSSH2_FREE(session, session->userauth_pblc_method);
872 session->userauth_pblc_method = NULL;
873 LIBSSH2_FREE(session, pubkeydata);
874 return -1;
875 }
876
877 *(session->userauth_pblc_s++) = SSH_MSG_USERAUTH_REQUEST;
878 libssh2_htonu32(session->userauth_pblc_s, username_len);
879 session->userauth_pblc_s += 4;
880 memcpy(session->userauth_pblc_s, username, username_len);
881 session->userauth_pblc_s += username_len;
882
883 libssh2_htonu32(session->userauth_pblc_s, 14);
884 session->userauth_pblc_s += 4;
885 memcpy(session->userauth_pblc_s, "ssh-connection", 14);
886 session->userauth_pblc_s += 14;
887
888 libssh2_htonu32(session->userauth_pblc_s, 9);
889 session->userauth_pblc_s += 4;
890 memcpy(session->userauth_pblc_s, "publickey", 9);
891 session->userauth_pblc_s += 9;
892
893 session->userauth_pblc_b = session->userauth_pblc_s;
894 /* Not sending signature with *this* packet */
895 *(session->userauth_pblc_s++) = 0;
896
897 libssh2_htonu32(session->userauth_pblc_s,
898 session->userauth_pblc_method_len);
899 session->userauth_pblc_s += 4;
900 memcpy(session->userauth_pblc_s, session->userauth_pblc_method,
901 session->userauth_pblc_method_len);
902 session->userauth_pblc_s += session->userauth_pblc_method_len;
903
904 libssh2_htonu32(session->userauth_pblc_s, pubkeydata_len);
905 session->userauth_pblc_s += 4;
906 memcpy(session->userauth_pblc_s, pubkeydata, pubkeydata_len);
907 session->userauth_pblc_s += pubkeydata_len;
908 LIBSSH2_FREE(session, pubkeydata);
909
910 _libssh2_debug(session, LIBSSH2_DBG_AUTH,
911 "Attempting publickey authentication");
912
913 session->userauth_pblc_state = libssh2_NB_state_created;
914 }
915
916 if (session->userauth_pblc_state == libssh2_NB_state_created) {
917 rc = libssh2_packet_write(session, session->userauth_pblc_packet,
918 session->userauth_pblc_packet_len);
919 if (rc == PACKET_EAGAIN) {
920 return PACKET_EAGAIN;
921 } else if (rc) {
922 libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
923 "Unable to send userauth-publickey request", 0);
924 LIBSSH2_FREE(session, session->userauth_pblc_packet);
925 session->userauth_pblc_packet = NULL;
926 LIBSSH2_FREE(session, session->userauth_pblc_method);
927 session->userauth_pblc_method = NULL;
928 session->userauth_pblc_state = libssh2_NB_state_idle;
929 return -1;
930 }
931
932 session->userauth_pblc_state = libssh2_NB_state_sent;
933 }
934
935 if (session->userauth_pblc_state == libssh2_NB_state_sent) {
936 rc = libssh2_packet_requirev_ex(session, reply_codes,
937 &session->userauth_pblc_data,
938 &session->userauth_pblc_data_len, 0,
939 NULL, 0,
940 &session->
941 userauth_pblc_packet_requirev_state);
942 if (rc == PACKET_EAGAIN) {
943 return PACKET_EAGAIN;
944 } else if (rc) {
945 LIBSSH2_FREE(session, session->userauth_pblc_packet);
946 session->userauth_pblc_packet = NULL;
947 LIBSSH2_FREE(session, session->userauth_pblc_method);
948 session->userauth_pblc_method = NULL;
949 session->userauth_pblc_state = libssh2_NB_state_idle;
950 return -1;
951 }
952
953 if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
954 _libssh2_debug(session, LIBSSH2_DBG_AUTH,
955 "Pubkey authentication prematurely successful");
956 /*
957 * God help any SSH server that allows an UNVERIFIED
958 * public key to validate the user
959 */
960 LIBSSH2_FREE(session, session->userauth_pblc_data);
961 session->userauth_pblc_data = NULL;
962 LIBSSH2_FREE(session, session->userauth_pblc_packet);
963 session->userauth_pblc_packet = NULL;
964 LIBSSH2_FREE(session, session->userauth_pblc_method);
965 session->userauth_pblc_method = NULL;
966 session->state |= LIBSSH2_STATE_AUTHENTICATED;
967 session->userauth_pblc_state = libssh2_NB_state_idle;
968 return 0;
969 }
970
971 if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_FAILURE) {
972 /* This public key is not allowed for this user on this server */
973 LIBSSH2_FREE(session, session->userauth_pblc_data);
974 session->userauth_pblc_data = NULL;
975 LIBSSH2_FREE(session, session->userauth_pblc_packet);
976 session->userauth_pblc_packet = NULL;
977 LIBSSH2_FREE(session, session->userauth_pblc_method);
978 session->userauth_pblc_method = NULL;
979 libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED,
980 "Username/PublicKey combination invalid", 0);
981 session->userauth_pblc_state = libssh2_NB_state_idle;
982 return -1;
983 }
984
985 /* Semi-Success! */
986 LIBSSH2_FREE(session, session->userauth_pblc_data);
987 session->userauth_pblc_data = NULL;
988
989 if (libssh2_file_read_privatekey
990 (session, &privkeyobj, &abstract, session->userauth_pblc_method,
991 session->userauth_pblc_method_len, privatekey, passphrase)) {
992 LIBSSH2_FREE(session, session->userauth_pblc_method);
993 session->userauth_pblc_method = NULL;
994 LIBSSH2_FREE(session, session->userauth_pblc_packet);
995 session->userauth_pblc_packet = NULL;
996 session->userauth_pblc_state = libssh2_NB_state_idle;
997 return -1;
998 }
999
1000 *session->userauth_pblc_b = 0x01;
1001
1002 libssh2_htonu32(buf, session->session_id_len);
1003 datavec[0].iov_base = buf;
1004 datavec[0].iov_len = 4;
1005 datavec[1].iov_base = session->session_id;
1006 datavec[1].iov_len = session->session_id_len;
1007 datavec[2].iov_base = session->userauth_pblc_packet;
1008 datavec[2].iov_len = session->userauth_pblc_packet_len;
1009
1010 if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
1011 LIBSSH2_FREE(session, session->userauth_pblc_method);
1012 session->userauth_pblc_method = NULL;
1013 LIBSSH2_FREE(session, session->userauth_pblc_packet);
1014 session->userauth_pblc_packet = NULL;
1015 if (privkeyobj->dtor) {
1016 privkeyobj->dtor(session, &abstract);
1017 }
1018 session->userauth_pblc_state = libssh2_NB_state_idle;
1019 return -1;
1020 }
1021
1022 if (privkeyobj->dtor) {
1023 privkeyobj->dtor(session, &abstract);
1024 }
1025
1026 if (sig_len > pubkeydata_len) {
1027 unsigned char *newpacket;
1028 /* Should *NEVER* happen, but...well.. better safe than sorry */
1029 newpacket = LIBSSH2_REALLOC(session, session->userauth_pblc_packet, session->userauth_pblc_packet_len + 4 + (4 + session->userauth_pblc_method_len) + (4 + sig_len)); /* PK sigblob */
1030 if (!newpacket) {
1031 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1032 "Failed allocating additional space for userauth-publickey packet",
1033 0);
1034 LIBSSH2_FREE(session, sig);
1035 LIBSSH2_FREE(session, session->userauth_pblc_packet);
1036 session->userauth_pblc_packet = NULL;
1037 LIBSSH2_FREE(session, session->userauth_pblc_method);
1038 session->userauth_pblc_method = NULL;
1039 session->userauth_pblc_state = libssh2_NB_state_idle;
1040 return -1;
1041 }
1042 session->userauth_pblc_packet = newpacket;
1043 }
1044
1045 session->userauth_pblc_s =
1046 session->userauth_pblc_packet + session->userauth_pblc_packet_len;
1047
1048 libssh2_htonu32(session->userauth_pblc_s,
1049 4 + session->userauth_pblc_method_len + 4 + sig_len);
1050 session->userauth_pblc_s += 4;
1051
1052 libssh2_htonu32(session->userauth_pblc_s,
1053 session->userauth_pblc_method_len);
1054 session->userauth_pblc_s += 4;
1055 memcpy(session->userauth_pblc_s, session->userauth_pblc_method,
1056 session->userauth_pblc_method_len);
1057 session->userauth_pblc_s += session->userauth_pblc_method_len;
1058 LIBSSH2_FREE(session, session->userauth_pblc_method);
1059 session->userauth_pblc_method = NULL;
1060
1061 libssh2_htonu32(session->userauth_pblc_s, sig_len);
1062 session->userauth_pblc_s += 4;
1063 memcpy(session->userauth_pblc_s, sig, sig_len);
1064 session->userauth_pblc_s += sig_len;
1065 LIBSSH2_FREE(session, sig);
1066
1067 _libssh2_debug(session, LIBSSH2_DBG_AUTH,
1068 "Attempting publickey authentication -- phase 2");
1069
1070 session->userauth_pblc_state = libssh2_NB_state_sent1;
1071 }
1072
1073 if (session->userauth_pblc_state == libssh2_NB_state_sent1) {
1074 rc = libssh2_packet_write(session, session->userauth_pblc_packet,
1075 session->userauth_pblc_s -
1076 session->userauth_pblc_packet);
1077 if (rc == PACKET_EAGAIN) {
1078 return PACKET_EAGAIN;
1079 } else if (rc) {
1080 libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
1081 "Unable to send userauth-publickey request", 0);
1082 LIBSSH2_FREE(session, session->userauth_pblc_packet);
1083 session->userauth_pblc_packet = NULL;
1084 session->userauth_pblc_state = libssh2_NB_state_idle;
1085 return -1;
1086 }
1087 LIBSSH2_FREE(session, session->userauth_pblc_packet);
1088 session->userauth_pblc_packet = NULL;
1089
1090 session->userauth_pblc_state = libssh2_NB_state_sent2;
1091 }
1092
1093 /* PK_OK is no longer valid */
1094 reply_codes[2] = 0;
1095
1096 rc = libssh2_packet_requirev_ex(session, reply_codes,
1097 &session->userauth_pblc_data,
1098 &session->userauth_pblc_data_len, 0, NULL,
1099 0,
1100 &session->
1101 userauth_pblc_packet_requirev_state);
1102 if (rc == PACKET_EAGAIN) {
1103 return PACKET_EAGAIN;
1104 } else if (rc) {
1105 session->userauth_pblc_state = libssh2_NB_state_idle;
1106 return -1;
1107 }
1108
1109 if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
1110 _libssh2_debug(session, LIBSSH2_DBG_AUTH,
1111 "Publickey authentication successful");
1112 /* We are us and we've proved it. */
1113 LIBSSH2_FREE(session, session->userauth_pblc_data);
1114 session->userauth_pblc_data = NULL;
1115 session->state |= LIBSSH2_STATE_AUTHENTICATED;
1116 session->userauth_pblc_state = libssh2_NB_state_idle;
1117 return 0;
1118 }
1119
1120 /* This public key is not allowed for this user on this server */
1121 LIBSSH2_FREE(session, session->userauth_pblc_data);
1122 session->userauth_pblc_data = NULL;
1123 libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED,
1124 "Invalid signature for supplied public key, or bad username/public key combination",
1125 0);
1126 session->userauth_pblc_state = libssh2_NB_state_idle;
1127 return -1;
1128 }
1129
1130 /* }}} */
1131
1132 /* {{{ libssh2_userauth_keyboard_interactive
1133 * Authenticate using a challenge-response authentication
1134 */
1135 LIBSSH2_API int
1136 libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION * session,
1137 const char *username,
1138 unsigned int username_len,
1139 LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)))
1140 {
1141 unsigned char *s;
1142 int rc;
1143
1144 static const unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS,
1145 SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0
1146 };
1147 unsigned int language_tag_len;
1148 unsigned int i;
1149
1150 if (session->userauth_kybd_state == libssh2_NB_state_idle) {
1151 session->userauth_kybd_auth_name = NULL;
1152 session->userauth_kybd_auth_instruction = NULL;
1153 session->userauth_kybd_num_prompts = 0;
1154 session->userauth_kybd_auth_failure = 1;
1155 session->userauth_kybd_prompts = NULL;
1156 session->userauth_kybd_responses = NULL;
1157
1158 /* Zero the whole thing out */
1159 memset(&session->userauth_kybd_packet_requirev_state, 0,
1160 sizeof(session->userauth_kybd_packet_requirev_state));
1161
1162 session->userauth_kybd_packet_len = 1 /* byte SSH_MSG_USERAUTH_REQUEST */
1163 + 4 + username_len /* string user name (ISO-10646 UTF-8, as defined in [RFC-3629]) */
1164 + 4 + 14 /* string service name (US-ASCII) */
1165 + 4 + 20 /* string "keyboard-interactive" (US-ASCII) */
1166 + 4 + 0 /* string language tag (as defined in [RFC-3066]) */
1167 + 4 + 0 /* string submethods (ISO-10646 UTF-8) */
1168 ;
1169
1170 session->userauth_kybd_data = s =
1171 LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len);
1172 if (!s) {
1173 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1174 "Unable to allocate memory for keyboard-interactive authentication",
1175 0);
1176 return -1;
1177 }
1178
1179 *s++ = SSH_MSG_USERAUTH_REQUEST;
1180
1181 /* user name */
1182 libssh2_htonu32(s, username_len);
1183 s += 4;
1184 memcpy(s, username, username_len);
1185 s += username_len;
1186
1187 /* service name */
1188 libssh2_htonu32(s, sizeof("ssh-connection") - 1);
1189 s += 4;
1190 memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1);
1191 s += sizeof("ssh-connection") - 1;
1192
1193 /* "keyboard-interactive" */
1194 libssh2_htonu32(s, sizeof("keyboard-interactive") - 1);
1195 s += 4;
1196 memcpy(s, "keyboard-interactive", sizeof("keyboard-interactive") - 1);
1197 s += sizeof("keyboard-interactive") - 1;
1198
1199 /* language tag */
1200 libssh2_htonu32(s, 0);
1201 s += 4;
1202
1203 /* submethods */
1204 libssh2_htonu32(s, 0);
1205 s += 4;
1206
1207 _libssh2_debug(session, LIBSSH2_DBG_AUTH,
1208 "Attempting keyboard-interactive authentication");
1209
1210 session->userauth_kybd_state = libssh2_NB_state_created;
1211 }
1212
1213 if (session->userauth_kybd_state == libssh2_NB_state_created) {
1214 rc = libssh2_packet_write(session, session->userauth_kybd_data,
1215 session->userauth_kybd_packet_len);
1216 if (rc == PACKET_EAGAIN) {
1217 return PACKET_EAGAIN;
1218 } else if (rc) {
1219 libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
1220 "Unable to send keyboard-interactive request", 0);
1221 LIBSSH2_FREE(session, session->userauth_kybd_data);
1222 session->userauth_kybd_data = NULL;
1223 session->userauth_kybd_state = libssh2_NB_state_idle;
1224 return -1;
1225 }
1226 LIBSSH2_FREE(session, session->userauth_kybd_data);
1227 session->userauth_kybd_data = NULL;
1228
1229 session->userauth_kybd_state = libssh2_NB_state_sent;
1230 }
1231
1232 for(;;) {
1233 if (session->userauth_kybd_state == libssh2_NB_state_sent) {
1234 rc = libssh2_packet_requirev_ex(session, reply_codes,
1235 &session->userauth_kybd_data,
1236 &session->userauth_kybd_data_len,
1237 0, NULL, 0,
1238 &session->
1239 userauth_kybd_packet_requirev_state);
1240 if (rc == PACKET_EAGAIN) {
1241 return PACKET_EAGAIN;
1242 } else if (rc) {
1243 session->userauth_kybd_state = libssh2_NB_state_idle;
1244 return -1;
1245 }
1246
1247 if (session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_SUCCESS) {
1248 _libssh2_debug(session, LIBSSH2_DBG_AUTH,
1249 "Keyboard-interactive authentication successful");
1250 LIBSSH2_FREE(session, session->userauth_kybd_data);
1251 session->userauth_kybd_data = NULL;
1252 session->state |= LIBSSH2_STATE_AUTHENTICATED;
1253 session->userauth_kybd_state = libssh2_NB_state_idle;
1254 return 0;
1255 }
1256
1257 if (session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_FAILURE) {
1258 LIBSSH2_FREE(session, session->userauth_kybd_data);
1259 session->userauth_kybd_data = NULL;
1260 session->userauth_kybd_state = libssh2_NB_state_idle;
1261 return -1;
1262 }
1263
1264 /* server requested PAM-like conversation */
1265
1266 s = session->userauth_kybd_data + 1;
1267
1268 /* string name (ISO-10646 UTF-8) */
1269 session->userauth_kybd_auth_name_len = libssh2_ntohu32(s);
1270 s += 4;
1271 session->userauth_kybd_auth_name =
1272 LIBSSH2_ALLOC(session, session->userauth_kybd_auth_name_len);
1273 if (!session->userauth_kybd_auth_name) {
1274 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1275 "Unable to allocate memory for keyboard-interactive 'name' request field",
1276 0);
1277 goto cleanup;
1278 }
1279 memcpy(session->userauth_kybd_auth_name, s,
1280 session->userauth_kybd_auth_name_len);
1281 s += session->userauth_kybd_auth_name_len;
1282
1283 /* string instruction (ISO-10646 UTF-8) */
1284 session->userauth_kybd_auth_instruction_len = libssh2_ntohu32(s);
1285 s += 4;
1286 session->userauth_kybd_auth_instruction =
1287 LIBSSH2_ALLOC(session,
1288 session->userauth_kybd_auth_instruction_len);
1289 if (!session->userauth_kybd_auth_instruction) {
1290 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1291 "Unable to allocate memory for keyboard-interactive 'instruction' request field",
1292 0);
1293 goto cleanup;
1294 }
1295 memcpy(session->userauth_kybd_auth_instruction, s,
1296 session->userauth_kybd_auth_instruction_len);
1297 s += session->userauth_kybd_auth_instruction_len;
1298
1299 /* string language tag (as defined in [RFC-3066]) */
1300 language_tag_len = libssh2_ntohu32(s);
1301 s += 4;
1302 /* ignoring this field as deprecated */
1303 s += language_tag_len;
1304
1305 /* int num-prompts */
1306 session->userauth_kybd_num_prompts = libssh2_ntohu32(s);
1307 s += 4;
1308
1309 session->userauth_kybd_prompts =
1310 LIBSSH2_ALLOC(session,
1311 sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) *
1312 session->userauth_kybd_num_prompts);
1313 if (!session->userauth_kybd_prompts) {
1314 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1315 "Unable to allocate memory for keyboard-interactive prompts array",
1316 0);
1317 goto cleanup;
1318 }
1319 memset(session->userauth_kybd_prompts, 0,
1320 sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) *
1321 session->userauth_kybd_num_prompts);
1322
1323 session->userauth_kybd_responses =
1324 LIBSSH2_ALLOC(session,
1325 sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) *
1326 session->userauth_kybd_num_prompts);
1327 if (!session->userauth_kybd_responses) {
1328 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1329 "Unable to allocate memory for keyboard-interactive responses array",
1330 0);
1331 goto cleanup;
1332 }
1333 memset(session->userauth_kybd_responses, 0,
1334 sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) *
1335 session->userauth_kybd_num_prompts);
1336
1337 for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
1338 /* string prompt[1] (ISO-10646 UTF-8) */
1339 session->userauth_kybd_prompts[i].length = libssh2_ntohu32(s);
1340 s += 4;
1341 session->userauth_kybd_prompts[i].text =
1342 LIBSSH2_ALLOC(session,
1343 session->userauth_kybd_prompts[i].length);
1344 if (!session->userauth_kybd_prompts[i].text) {
1345 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1346 "Unable to allocate memory for keyboard-interactive prompt message",
1347 0);
1348 goto cleanup;
1349 }
1350 memcpy(session->userauth_kybd_prompts[i].text, s,
1351 session->userauth_kybd_prompts[i].length);
1352 s += session->userauth_kybd_prompts[i].length;
1353
1354 /* boolean echo[1] */
1355 session->userauth_kybd_prompts[i].echo = *s++;
1356 }
1357
1358 response_callback(session->userauth_kybd_auth_name,
1359 session->userauth_kybd_auth_name_len,
1360 session->userauth_kybd_auth_instruction,
1361 session->userauth_kybd_auth_instruction_len,
1362 session->userauth_kybd_num_prompts,
1363 session->userauth_kybd_prompts,
1364 session->userauth_kybd_responses,
1365 &session->abstract);
1366
1367 _libssh2_debug(session, LIBSSH2_DBG_AUTH,
1368 "Keyboard-interactive response callback function invoked");
1369
1370 session->userauth_kybd_packet_len = 1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */
1371 + 4 /* int num-responses */
1372 ;
1373
1374 for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
1375 /* string response[1] (ISO-10646 UTF-8) */
1376 session->userauth_kybd_packet_len +=
1377 4 + session->userauth_kybd_responses[i].length;
1378 }
1379
1380 session->userauth_kybd_data = s =
1381 LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len);
1382 if (!s) {
1383 libssh2_error(session, LIBSSH2_ERROR_ALLOC,
1384 "Unable to allocate memory for keyboard-interactive response packet",
1385 0);
1386 goto cleanup;
1387 }
1388
1389 *s = SSH_MSG_USERAUTH_INFO_RESPONSE;
1390 s++;
1391 libssh2_htonu32(s, session->userauth_kybd_num_prompts);
1392 s += 4;
1393
1394 for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
1395 libssh2_htonu32(s, session->userauth_kybd_responses[i].length);
1396 s += 4;
1397 memcpy(s, session->userauth_kybd_responses[i].text,
1398 session->userauth_kybd_responses[i].length);
1399 s += session->userauth_kybd_responses[i].length;
1400 }
1401
1402 session->userauth_kybd_state = libssh2_NB_state_sent1;
1403 }
1404
1405 if (session->userauth_kybd_state == libssh2_NB_state_sent1) {
1406 rc = libssh2_packet_write(session, session->userauth_kybd_data,
1407 session->userauth_kybd_packet_len);
1408 if (rc == PACKET_EAGAIN) {
1409 return PACKET_EAGAIN;
1410 }
1411 if (rc) {
1412 libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
1413 "Unable to send userauth-keyboard-interactive request",
1414 0);
1415 goto cleanup;
1416 }
1417
1418 session->userauth_kybd_auth_failure = 0;
1419 }
1420
1421 cleanup:
1422 /*
1423 * It's safe to clean all the data here, because unallocated pointers
1424 * are filled by zeroes
1425 */
1426
1427 LIBSSH2_FREE(session, session->userauth_kybd_data);
1428 session->userauth_kybd_data = NULL;
1429
1430 if (session->userauth_kybd_prompts) {
1431 for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
1432 LIBSSH2_FREE(session, session->userauth_kybd_prompts[i].text);
1433 session->userauth_kybd_prompts[i].text = NULL;
1434 }
1435 }
1436
1437 if (session->userauth_kybd_responses) {
1438 for(i = 0; i != session->userauth_kybd_num_prompts; ++i) {
1439 LIBSSH2_FREE(session,
1440 session->userauth_kybd_responses[i].text);
1441 session->userauth_kybd_responses[i].text = NULL;
1442 }
1443 }
1444
1445 LIBSSH2_FREE(session, session->userauth_kybd_prompts);
1446 session->userauth_kybd_prompts = NULL;
1447 LIBSSH2_FREE(session, session->userauth_kybd_responses);
1448 session->userauth_kybd_responses = NULL;
1449
1450 if (session->userauth_kybd_auth_failure) {
1451 session->userauth_kybd_state = libssh2_NB_state_idle;
1452 return -1;
1453 }
1454
1455 session->userauth_kybd_state = libssh2_NB_state_sent;
1456 }
1457 }
1458
1459 /* }}} */