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