5772864 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11/src/libssh-0.11-win32/libssh]$ cat -n auth.c
  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 }
5772865 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11/src/libssh-0.11-win32/libssh]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2007-02-17 17:46:50