5772980 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11/src/libssh-0.11/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 #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 }
5772981 [rkeene@sledge /home/rkeene/projects/libssh-win32/v0.11/src/libssh-0.11/libssh]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 2005-03-04 19:54:59