1 /* auth.c deals with authentication methods */ 2 /* 3 Copyright 2003 Aris Adamantiadis 4 5 This file is part of the SSH Library 6 7 The SSH Library is free software; you can redistribute it and/or modify 8 it under the terms of the GNU Lesser General Public License as published by 9 the Free Software Foundation; either version 2.1 of the License, or (at your 10 option) any later version. 11 12 The SSH Library is distributed in the hope that it will be useful, but 13 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15 License for more details. 16 17 You should have received a copy of the GNU Lesser General Public License 18 along with the SSH Library; see the file COPYING. If not, write to 19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, 20 MA 02111-1307, USA. */ 21 22 #include "libssh/priv.h" 23 #include "libssh/ssh2.h" 24 #include <string.h> 25 #include <netdb.h> 26 27 static int ask_userauth(SSH_SESSION *session){ 28 if(session->auth_service_asked) 29 return 0; 30 else { 31 if(ssh_service_request(session,"ssh-userauth")) 32 return -1; 33 else 34 session->auth_service_asked++; 35 } 36 return 0; 37 38 } 39 40 static void burn(char *ptr){ 41 if(ptr) 42 memset(ptr,'X',strlen(ptr)); 43 } 44 45 static void string_burn(STRING *s){ 46 memset(s->string,'X',string_len(s)); 47 } 48 49 static int wait_auth_status(SSH_SESSION *session,int kbdint){ 50 int err=SSH_AUTH_ERROR; 51 int cont=1; 52 STRING *can_continue; 53 u8 partial=0; 54 char *c_cont; 55 while(cont){ 56 if(packet_read(session)) 57 break; 58 if(packet_translate(session)) 59 break; 60 switch(session->in_packet.type){ 61 case SSH2_MSG_USERAUTH_FAILURE: 62 can_continue=buffer_get_ssh_string(session->in_buffer); 63 if(!can_continue || buffer_get_u8(session->in_buffer,&partial)!=1 ){ 64 ssh_set_error(session,SSH_INVALID_DATA,"invalid SSH_MSG_USERAUTH_FAILURE message"); 65 return SSH_AUTH_ERROR; 66 } 67 c_cont=string_to_char(can_continue); 68 if(partial){ 69 err=SSH_AUTH_PARTIAL; 70 ssh_set_error(session,SSH_NO_ERROR,"partial success, authentications that can continue : %s",c_cont); 71 } 72 else { 73 err=SSH_AUTH_DENIED; 74 ssh_set_error(session,SSH_REQUEST_DENIED,"Access denied. authentications that can continue : %s",c_cont); 75 } 76 free(can_continue); 77 free(c_cont); 78 cont=0; 79 break; 80 case SSH2_MSG_USERAUTH_PK_OK: 81 /* SSH monkeys have defined the same number for both */ 82 /* SSH_MSG_USERAUTH_PK_OK and SSH_MSG_USERAUTH_INFO_REQUEST */ 83 /* which is not really smart; */ 84 /*case SSH2_MSG_USERAUTH_INFO_REQUEST: */ 85 if(kbdint){ 86 err=SSH_AUTH_INFO; 87 cont=0; 88 break; 89 } 90 /* continue through success */ 91 case SSH2_MSG_USERAUTH_SUCCESS: 92 err=SSH_AUTH_SUCCESS; 93 cont=0; 94 break; 95 case SSH2_MSG_USERAUTH_BANNER: 96 { 97 STRING *banner=buffer_get_ssh_string(session->in_buffer); 98 if(!banner){ 99 ssh_say(1,"The banner message was invalid. continuing though\n"); 100 break; 101 } 102 ssh_say(2,"Received a message banner\n"); 103 if(session->banner) 104 free(session->banner); /* erase the older one */ 105 session->banner=banner; 106 break; 107 } 108 default: 109 packet_parse(session); 110 break; 111 } 112 } 113 return err; 114 } 115 116 /* use the "none" authentication question */ 117 118 int ssh_userauth_none(SSH_SESSION *session,char *username){ 119 STRING *user; 120 STRING *service; 121 STRING *method; 122 if(!username) 123 if(!(username=session->options->username)){ 124 if(options_default_username(session->options)) 125 return SSH_AUTH_ERROR; 126 else 127 username=session->options->username; 128 } 129 if(ask_userauth(session)) 130 return SSH_AUTH_ERROR; 131 user=string_from_char(username); 132 method=string_from_char("none"); 133 service=string_from_char("ssh-connection"); 134 packet_clear_out(session); 135 buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST); 136 buffer_add_ssh_string(session->out_buffer,user); 137 buffer_add_ssh_string(session->out_buffer,service); 138 buffer_add_ssh_string(session->out_buffer,method); 139 free(service); 140 free(method); 141 free(user); 142 packet_send(session); 143 return wait_auth_status(session,0); 144 } 145 146 int ssh_userauth_offer_pubkey(SSH_SESSION *session, char *username,int type, STRING *publickey){ 147 STRING *user; 148 STRING *service; 149 STRING *method; 150 STRING *algo; 151 int err=SSH_AUTH_ERROR; 152 if(!username) 153 if(!(username=session->options->username)){ 154 if(options_default_username(session->options)) 155 return SSH_AUTH_ERROR; 156 else 157 username=session->options->username; 158 } 159 if(ask_userauth(session)) 160 return SSH_AUTH_ERROR; 161 user=string_from_char(username); 162 service=string_from_char("ssh-connection"); 163 method=string_from_char("publickey"); 164 algo=string_from_char(ssh_type_to_char(type)); 165 166 packet_clear_out(session); 167 buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST); 168 buffer_add_ssh_string(session->out_buffer,user); 169 buffer_add_ssh_string(session->out_buffer,service); 170 buffer_add_ssh_string(session->out_buffer,method); 171 buffer_add_u8(session->out_buffer,0); 172 buffer_add_ssh_string(session->out_buffer,algo); 173 buffer_add_ssh_string(session->out_buffer,publickey); 174 packet_send(session); 175 err=wait_auth_status(session,0); 176 free(user); 177 free(method); 178 free(service); 179 free(algo); 180 return err; 181 } 182 183 int ssh_userauth_pubkey(SSH_SESSION *session, char *username, STRING *publickey, PRIVATE_KEY *privatekey){ 184 STRING *user; 185 STRING *service; 186 STRING *method; 187 STRING *algo; 188 STRING *sign; 189 int err=SSH_AUTH_ERROR; 190 if(!username) 191 if(!(username=session->options->username)){ 192 if(options_default_username(session->options)) 193 return err; 194 else 195 username=session->options->username; 196 } 197 if(ask_userauth(session)) 198 return err; 199 user=string_from_char(username); 200 service=string_from_char("ssh-connection"); 201 method=string_from_char("publickey"); 202 algo=string_from_char(ssh_type_to_char(privatekey->type)); 203 204 205 /* we said previously the public key was accepted */ 206 packet_clear_out(session); 207 buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST); 208 buffer_add_ssh_string(session->out_buffer,user); 209 buffer_add_ssh_string(session->out_buffer,service); 210 buffer_add_ssh_string(session->out_buffer,method); 211 buffer_add_u8(session->out_buffer,1); 212 buffer_add_ssh_string(session->out_buffer,algo); 213 buffer_add_ssh_string(session->out_buffer,publickey); 214 sign=ssh_do_sign(session,session->out_buffer,privatekey); 215 if(sign){ 216 buffer_add_ssh_string(session->out_buffer,sign); 217 free(sign); 218 packet_send(session); 219 err=wait_auth_status(session,0); 220 } 221 free(user); 222 free(service); 223 free(method); 224 free(algo); 225 return err; 226 } 227 228 int ssh_userauth_password(SSH_SESSION *session,char *username,char *password){ 229 STRING *user; 230 STRING *service; 231 STRING *method; 232 STRING *password_s; 233 int err; 234 if(!username) 235 if(!(username=session->options->username)){ 236 if(options_default_username(session->options)) 237 return SSH_AUTH_ERROR; 238 else 239 username=session->options->username; 240 } 241 if(ask_userauth(session)) 242 return SSH_AUTH_ERROR; 243 user=string_from_char(username); 244 service=string_from_char("ssh-connection"); 245 method=string_from_char("password"); 246 password_s=string_from_char(password); 247 248 packet_clear_out(session); 249 buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST); 250 buffer_add_ssh_string(session->out_buffer,user); 251 buffer_add_ssh_string(session->out_buffer,service); 252 buffer_add_ssh_string(session->out_buffer,method); 253 buffer_add_u8(session->out_buffer,0); 254 buffer_add_ssh_string(session->out_buffer,password_s); 255 free(user); 256 free(service); 257 free(method); 258 memset(password_s,0,strlen(password)+4); 259 free(password_s); 260 packet_send(session); 261 err=wait_auth_status(session,0); 262 return err; 263 } 264 265 static char *keys_path[]={NULL,"%s/.ssh/identity","%s/.ssh/id_dsa","%s/.ssh/id_rsa",NULL}; 266 static char *pub_keys_path[]={NULL,"%s/.ssh/identity.pub","%s/.ssh/id_dsa.pub","%s/.ssh/id_rsa.pub",NULL}; 267 268 /* this function initialy was in the client */ 269 /* but the fools are the ones who never change mind */ 270 int ssh_userauth_autopubkey(SSH_SESSION *session){ 271 int count=1; /* bypass identity */ 272 int type=0; 273 int err; 274 STRING *pubkey; 275 char *privkeyfile=NULL; 276 PRIVATE_KEY *privkey; 277 char *id=NULL; 278 // always testing none 279 err=ssh_userauth_none(session,NULL); 280 if(err==SSH_AUTH_ERROR || err==SSH_AUTH_SUCCESS){ 281 return err; 282 } 283 if(session->options->identity){ 284 ssh_say(2,"Trying identity file %s\n",session->options->identity); 285 keys_path[0]=session->options->identity; 286 /* let's hope alloca exists */ 287 id=malloc(strlen(session->options->identity)+1 + 4); 288 sprintf(id,"%s.pub",session->options->identity); 289 pub_keys_path[0]=id; 290 count =0; 291 } 292 while((pubkey=publickey_from_next_file(session,pub_keys_path,keys_path, &privkeyfile,&type,&count))){ 293 err=ssh_userauth_offer_pubkey(session,NULL,type,pubkey); 294 if(err==SSH_AUTH_ERROR){ 295 if(id){ 296 pub_keys_path[0]=NULL; 297 keys_path[0]=NULL; 298 free(id); 299 } 300 free(pubkey); 301 return err; 302 } else 303 if(err != SSH_AUTH_SUCCESS){ 304 ssh_say(2,"Public key refused by server\n"); 305 free(pubkey); 306 continue; 307 } 308 /* pubkey accepted by server ! */ 309 privkey=privatekey_from_file(session,privkeyfile,type,NULL); 310 if(!privkey){ 311 ssh_say(0,"Reading private key %s failed (bad passphrase ?)\n",privkeyfile); 312 free(pubkey); 313 continue; /* continue the loop with other pubkey */ 314 } 315 err=ssh_userauth_pubkey(session,NULL,pubkey,privkey); 316 if(err==SSH_AUTH_ERROR){ 317 if(id){ 318 pub_keys_path[0]=NULL; 319 keys_path[0]=NULL; 320 free(id); 321 } 322 free(pubkey); 323 private_key_free(privkey); 324 return err; 325 } else 326 if(err != SSH_AUTH_SUCCESS){ 327 ssh_say(0,"Weird : server accepted our public key but refused the signature\nit might be a bug of libssh\n"); 328 free(pubkey); 329 private_key_free(privkey); 330 continue; 331 } 332 /* auth success */ 333 ssh_say(1,"Authentication using %s success\n",privkeyfile); 334 free(pubkey); 335 private_key_free(privkey); 336 free(privkeyfile); 337 if(id){ 338 pub_keys_path[0]=NULL; 339 keys_path[0]=NULL; 340 free(id); 341 } 342 return SSH_AUTH_SUCCESS; 343 } 344 ssh_say(1,"Tried every public key, none matched\n"); 345 ssh_set_error(session,SSH_NO_ERROR,"no public key matched"); 346 if(id){ 347 pub_keys_path[0]=NULL; 348 keys_path[0]=NULL; 349 free(id); 350 } 351 352 return SSH_AUTH_DENIED; 353 } 354 355 static struct ssh_kbdint *kbdint_new(){ 356 struct ssh_kbdint *kbd=malloc(sizeof (struct ssh_kbdint)); 357 memset(kbd,0,sizeof(*kbd)); 358 return kbd; 359 } 360 361 362 static void kbdint_free(struct ssh_kbdint *kbd){ 363 int i,n=kbd->nprompts; 364 if(kbd->name) 365 free(kbd->name); 366 if(kbd->instruction) 367 free(kbd->instruction); 368 if(kbd->prompts){ 369 for(i=0;i<n;++i){ 370 burn(kbd->prompts[i]); 371 free(kbd->prompts[i]); 372 } 373 free(kbd->prompts); 374 } 375 if(kbd->answers){ 376 for(i=0;i<n;++i){ 377 burn(kbd->answers[i]); 378 free(kbd->answers[i]); 379 } 380 free(kbd->answers); 381 } 382 if(kbd->echo){ 383 free(kbd->echo); 384 } 385 free(kbd); 386 } 387 388 static void kbdint_clean(struct ssh_kbdint *kbd){ 389 int i,n=kbd->nprompts; 390 if(kbd->name){ 391 free(kbd->name); 392 kbd->name=NULL; 393 } 394 if(kbd->instruction){ 395 free(kbd->instruction); 396 kbd->instruction=NULL; 397 } 398 if(kbd->prompts){ 399 for(i=0;i<n;++i){ 400 burn(kbd->prompts[i]); 401 free(kbd->prompts[i]); 402 } 403 free(kbd->prompts); 404 kbd->prompts=NULL; 405 } 406 if(kbd->answers){ 407 for(i=0;i<n;++i){ 408 burn(kbd->answers[i]); 409 free(kbd->answers[i]); 410 } 411 free(kbd->answers); 412 kbd->answers=NULL; 413 } 414 if(kbd->echo){ 415 free(kbd->echo); 416 kbd->echo=NULL; 417 } 418 kbd->nprompts=0; 419 } 420 421 /* this function sends the first packet as explained in section 3.1 422 * of the draft */ 423 static int kbdauth_init(SSH_SESSION *session, 424 char *user, char *submethods){ 425 STRING *user_s=string_from_char(user); 426 STRING *submethods_s=(submethods ? string_from_char(submethods): string_from_char("")); 427 STRING *service=string_from_char("ssh-connection"); 428 STRING *method=string_from_char("keyboard-interactive"); 429 packet_clear_out(session); 430 buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_REQUEST); 431 buffer_add_ssh_string(session->out_buffer,user_s); 432 buffer_add_ssh_string(session->out_buffer,service); 433 buffer_add_ssh_string(session->out_buffer,method); 434 buffer_add_u32(session->out_buffer,0); // language tag 435 buffer_add_ssh_string(session->out_buffer,submethods_s); 436 free(user_s); 437 free(service); 438 free(method); 439 free(submethods_s); 440 if(packet_send(session)) 441 return SSH_AUTH_ERROR; 442 return wait_auth_status(session,1); 443 } 444 445 static int kbdauth_info_get(SSH_SESSION *session){ 446 STRING *name; /* name of the "asking" window showed to client */ 447 STRING *instruction; 448 STRING *tmp; 449 u32 nprompts; 450 int i; 451 name=buffer_get_ssh_string(session->in_buffer); 452 instruction=buffer_get_ssh_string(session->in_buffer); 453 tmp=buffer_get_ssh_string(session->in_buffer); 454 buffer_get_u32(session->in_buffer,&nprompts); 455 if(!name || !instruction || !tmp){ 456 if(name) 457 free(name); 458 if(instruction) 459 free(instruction); 460 // tmp must be empty if we got here 461 ssh_set_error(session,SSH_FATAL,"Invalid USERAUTH_INFO_REQUEST msg"); 462 return SSH_AUTH_ERROR; 463 } 464 if(tmp) 465 free(tmp); // no use 466 if(!session->kbdint) 467 session->kbdint=kbdint_new(); 468 else 469 kbdint_clean(session->kbdint); 470 session->kbdint->name=string_to_char(name); 471 free(name); 472 session->kbdint->instruction=string_to_char(instruction); 473 free(instruction); 474 nprompts=ntohl(nprompts); 475 if(nprompts>KBDINT_MAX_PROMPT){ 476 ssh_set_error(session,SSH_FATAL,"Too much prompt asked from server: %lu(0x%.8lx)",nprompts,nprompts); 477 return SSH_AUTH_ERROR; 478 } 479 session->kbdint->nprompts=nprompts; 480 session->kbdint->prompts=malloc(nprompts*sizeof(char *)); 481 memset(session->kbdint->prompts,0,nprompts*sizeof(char *)); 482 session->kbdint->echo=malloc(nprompts); 483 memset(session->kbdint->echo,0,nprompts); 484 for(i=0;i<nprompts;++i){ 485 tmp=buffer_get_ssh_string(session->in_buffer); 486 buffer_get_u8(session->in_buffer,&session->kbdint->echo[i]); 487 if(!tmp){ 488 ssh_set_error(session,SSH_FATAL,"Short INFO_REQUEST packet"); 489 return SSH_AUTH_ERROR; 490 } 491 session->kbdint->prompts[i]=string_to_char(tmp); 492 free(tmp); 493 } 494 return SSH_AUTH_INFO; /* we are not auth. but we parsed the packet */ 495 } 496 497 /* sends challenge back to the server */ 498 static int kbdauth_send(SSH_SESSION *session) { 499 STRING *answer; 500 int i; 501 packet_clear_out(session); 502 buffer_add_u8(session->out_buffer,SSH2_MSG_USERAUTH_INFO_RESPONSE); 503 buffer_add_u32(session->out_buffer,htonl(session->kbdint->nprompts)); 504 for(i=0;i<session->kbdint->nprompts;++i){ 505 if(session->kbdint->answers[i]) 506 answer=string_from_char(session->kbdint->answers[i]); 507 else 508 answer=string_from_char(""); 509 buffer_add_ssh_string(session->out_buffer,answer); 510 string_burn(answer); 511 free(answer); 512 } 513 if(packet_send(session)) 514 return SSH_AUTH_ERROR; 515 return wait_auth_status(session,1); 516 } 517 518 /* the heart of the whole keyboard interactive login */ 519 int ssh_userauth_kbdint(SSH_SESSION *session,char *user,char *submethods){ 520 int err; 521 if( !session->kbdint){ 522 /* first time we call. we must ask for a challenge */ 523 if(!user) 524 if(!(user=session->options->username)){ 525 if(options_default_username(session->options)) 526 return SSH_AUTH_ERROR; 527 else 528 user=session->options->username; 529 } 530 if(ask_userauth(session)) 531 return SSH_AUTH_ERROR; 532 err=kbdauth_init(session,user,submethods); 533 if(err!=SSH_AUTH_INFO) 534 return err; /* error or first try success */ 535 err=kbdauth_info_get(session); 536 if(err==SSH_AUTH_ERROR){ 537 kbdint_free(session->kbdint); 538 session->kbdint=NULL; 539 } 540 return err; 541 } 542 /* if we are at this point, it's because session->kbdint exists */ 543 /* it means the user has set some informations there we need to send * 544 * the server. and then we need to ack the status (new questions or ok * 545 * pass in */ 546 err=kbdauth_send(session); 547 kbdint_free(session->kbdint); 548 session->kbdint=NULL; 549 if(err!=SSH_AUTH_INFO) 550 return err; 551 err=kbdauth_info_get(session); 552 if(err==SSH_AUTH_ERROR){ 553 kbdint_free(session->kbdint); 554 session->kbdint=NULL; 555 } 556 return err; 557 } 558 559 int ssh_userauth_kbdint_getnprompts(SSH_SESSION *session){ 560 return session->kbdint->nprompts; 561 } 562 563 char *ssh_userauth_kbdint_getname(SSH_SESSION *session){ 564 return session->kbdint->name; 565 } 566 567 char *ssh_userauth_kbdint_getinstruction(SSH_SESSION *session){ 568 return session->kbdint->instruction; 569 } 570 571 char *ssh_userauth_kbdint_getprompt(SSH_SESSION *session, int i, 572 char *echo){ 573 if(i > session->kbdint->nprompts) 574 return NULL; 575 if(echo) 576 *echo=session->kbdint->echo[i]; 577 return session->kbdint->prompts[i]; 578 } 579 580 void ssh_userauth_kbdint_setanswer(SSH_SESSION *session, unsigned int i, char *answer){ 581 if (i>session->kbdint->nprompts) 582 return; 583 if(!session->kbdint->answers){ 584 session->kbdint->answers=malloc(sizeof(char*)*session->kbdint->nprompts); 585 memset(session->kbdint->answers,0,sizeof(char *) * session->kbdint->nprompts); 586 } 587 if(session->kbdint->answers[i]){ 588 burn(session->kbdint->answers[i]); 589 free(session->kbdint->answers[i]); 590 } 591 session->kbdint->answers[i]=strdup(answer); 592 } |