[BACK]Return to auth2-chall.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/auth2-chall.c between version 1.2.2.7 and 1.3

version 1.2.2.7, 2002/03/08 17:04:41 version 1.3, 2001/03/02 18:54:31
Line 1 
Line 1 
 /*  /*
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.   * Copyright (c) 2001 Markus Friedl.  All rights reserved.
  * Copyright (c) 2001 Per Allansson.  All rights reserved.  
  *   *
  * Redistribution and use in source and binary forms, with or without   * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions   * modification, are permitted provided that the following conditions
Line 27 
Line 26 
   
 #include "ssh2.h"  #include "ssh2.h"
 #include "auth.h"  #include "auth.h"
 #include "buffer.h"  
 #include "packet.h"  #include "packet.h"
 #include "xmalloc.h"  #include "xmalloc.h"
 #include "dispatch.h"  #include "dispatch.h"
 #include "auth.h"  
 #include "log.h"  #include "log.h"
   
 static int auth2_challenge_start(Authctxt *);  void send_userauth_into_request(Authctxt *authctxt, char *challenge, int echo);
 static int send_userauth_info_request(Authctxt *);  void input_userauth_info_response(int type, int plen, void *ctxt);
 static void input_userauth_info_response(int, u_int32_t, void *);  
   
 #ifdef BSD_AUTH  
 extern KbdintDevice bsdauth_device;  
 #else  
 #ifdef SKEY  
 extern KbdintDevice skey_device;  
 #endif  
 #endif  
   
 KbdintDevice *devices[] = {  
 #ifdef BSD_AUTH  
         &bsdauth_device,  
 #else  
 #ifdef SKEY  
         &skey_device,  
 #endif  
 #endif  
         NULL  
 };  
   
 typedef struct KbdintAuthctxt KbdintAuthctxt;  
 struct KbdintAuthctxt  
 {  
         char *devices;  
         void *ctxt;  
         KbdintDevice *device;  
 };  
   
 static KbdintAuthctxt *  
 kbdint_alloc(const char *devs)  
 {  
         KbdintAuthctxt *kbdintctxt;  
         Buffer b;  
         int i;  
   
         kbdintctxt = xmalloc(sizeof(KbdintAuthctxt));  
         if (strcmp(devs, "") == 0) {  
                 buffer_init(&b);  
                 for (i = 0; devices[i]; i++) {  
                         if (buffer_len(&b) > 0)  
                                 buffer_append(&b, ",", 1);  
                         buffer_append(&b, devices[i]->name,  
                             strlen(devices[i]->name));  
                 }  
                 buffer_append(&b, "\0", 1);  
                 kbdintctxt->devices = xstrdup(buffer_ptr(&b));  
                 buffer_free(&b);  
         } else {  
                 kbdintctxt->devices = xstrdup(devs);  
         }  
         debug("kbdint_alloc: devices '%s'", kbdintctxt->devices);  
         kbdintctxt->ctxt = NULL;  
         kbdintctxt->device = NULL;  
   
         return kbdintctxt;  
 }  
 static void  
 kbdint_reset_device(KbdintAuthctxt *kbdintctxt)  
 {  
         if (kbdintctxt->ctxt) {  
                 kbdintctxt->device->free_ctx(kbdintctxt->ctxt);  
                 kbdintctxt->ctxt = NULL;  
         }  
         kbdintctxt->device = NULL;  
 }  
 static void  
 kbdint_free(KbdintAuthctxt *kbdintctxt)  
 {  
         if (kbdintctxt->device)  
                 kbdint_reset_device(kbdintctxt);  
         if (kbdintctxt->devices) {  
                 xfree(kbdintctxt->devices);  
                 kbdintctxt->devices = NULL;  
         }  
         xfree(kbdintctxt);  
 }  
 /* get next device */  
 static int  
 kbdint_next_device(KbdintAuthctxt *kbdintctxt)  
 {  
         size_t len;  
         char *t;  
         int i;  
   
         if (kbdintctxt->device)  
                 kbdint_reset_device(kbdintctxt);  
         do {  
                 len = kbdintctxt->devices ?  
                     strcspn(kbdintctxt->devices, ",") : 0;  
   
                 if (len == 0)  
                         break;  
                 for (i = 0; devices[i]; i++)  
                         if (strncmp(kbdintctxt->devices, devices[i]->name, len) == 0)  
                                 kbdintctxt->device = devices[i];  
                 t = kbdintctxt->devices;  
                 kbdintctxt->devices = t[len] ? xstrdup(t+len+1) : NULL;  
                 xfree(t);  
                 debug2("kbdint_next_device: devices %s", kbdintctxt->devices ?  
                    kbdintctxt->devices : "<empty>");  
         } while (kbdintctxt->devices && !kbdintctxt->device);  
   
         return kbdintctxt->device ? 1 : 0;  
 }  
   
 /*  /*
  * try challenge-response, set authctxt->postponed if we have to   * try challenge-reponse, return -1 (= postponed) if we have to
  * wait for the response.   * wait for the response.
  */   */
 int  int
 auth2_challenge(Authctxt *authctxt, char *devs)  auth2_challenge(Authctxt *authctxt, char *devs)
 {  {
         debug("auth2_challenge: user=%s devs=%s",          char *challenge;
             authctxt->user ? authctxt->user : "<nouser>",  
             devs ? devs : "<no devs>");  
   
         if (authctxt->user == NULL || !devs)          if (!authctxt->valid || authctxt->user == NULL)
                 return 0;                  return 0;
         if (authctxt->kbdintctxt == NULL)          if ((challenge = get_challenge(authctxt, devs)) == NULL)
                 authctxt->kbdintctxt = kbdint_alloc(devs);  
         return auth2_challenge_start(authctxt);  
 }  
   
 /* unregister kbd-int callbacks and context */  
 void  
 auth2_challenge_stop(Authctxt *authctxt)  
 {  
         /* unregister callback */  
         dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);  
         if (authctxt->kbdintctxt != NULL)  {  
                 kbdint_free(authctxt->kbdintctxt);  
                 authctxt->kbdintctxt = NULL;  
         }  
 }  
   
 /* side effect: sets authctxt->postponed if a reply was sent*/  
 static int  
 auth2_challenge_start(Authctxt *authctxt)  
 {  
         KbdintAuthctxt *kbdintctxt = authctxt->kbdintctxt;  
   
         debug2("auth2_challenge_start: devices %s",  
             kbdintctxt->devices ?  kbdintctxt->devices : "<empty>");  
   
         if (kbdint_next_device(kbdintctxt) == 0) {  
                 auth2_challenge_stop(authctxt);  
                 return 0;                  return 0;
         }          send_userauth_into_request(authctxt, challenge, 0);
         debug("auth2_challenge_start: trying authentication method '%s'",  
             kbdintctxt->device->name);  
   
         if ((kbdintctxt->ctxt = kbdintctxt->device->init_ctx(authctxt)) == NULL) {  
                 auth2_challenge_stop(authctxt);  
                 return 0;  
         }  
         if (send_userauth_info_request(authctxt) == 0) {  
                 auth2_challenge_stop(authctxt);  
                 return 0;  
         }  
         dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,          dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
             &input_userauth_info_response);              &input_userauth_info_response);
   
         authctxt->postponed = 1;          authctxt->postponed = 1;
         return 0;          return 0;
 }  }
   
 static int  void
 send_userauth_info_request(Authctxt *authctxt)  send_userauth_into_request(Authctxt *authctxt, char *challenge, int echo)
 {  {
         KbdintAuthctxt *kbdintctxt;          int nprompts = 1;
         char *name, *instr, **prompts;  
         int i;  
         u_int numprompts, *echo_on;  
   
         kbdintctxt = authctxt->kbdintctxt;  
         if (kbdintctxt->device->query(kbdintctxt->ctxt,  
             &name, &instr, &numprompts, &prompts, &echo_on))  
                 return 0;  
   
         packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);          packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
         packet_put_cstring(name);          /* name, instruction and language are unused */
         packet_put_cstring(instr);          packet_put_cstring("");
         packet_put_cstring("");         /* language not used */          packet_put_cstring("");
         packet_put_int(numprompts);          packet_put_cstring("");
         for (i = 0; i < numprompts; i++) {          packet_put_int(nprompts);
                 packet_put_cstring(prompts[i]);          packet_put_cstring(challenge);
                 packet_put_char(echo_on[i]);          packet_put_char(echo);
         }  
         packet_send();          packet_send();
         packet_write_wait();          packet_write_wait();
   
         for (i = 0; i < numprompts; i++)  
                 xfree(prompts[i]);  
         xfree(prompts);  
         xfree(echo_on);  
         xfree(name);  
         xfree(instr);  
         return 1;  
 }  }
   
 static void  void
 input_userauth_info_response(int type, u_int32_t seq, void *ctxt)  input_userauth_info_response(int type, int plen, void *ctxt)
 {  {
         Authctxt *authctxt = ctxt;          Authctxt *authctxt = ctxt;
         KbdintAuthctxt *kbdintctxt;          int authenticated = 0;
         int i, authenticated = 0, res, len;          u_int nresp, rlen;
         u_int nresp;          char *response, *method = "challenge-reponse";
         char **response = NULL, *method;  
   
         if (authctxt == NULL)          if (authctxt == NULL)
                 fatal("input_userauth_info_response: no authctxt");                  fatal("input_userauth_info_response: no authctxt");
         kbdintctxt = authctxt->kbdintctxt;  
         if (kbdintctxt == NULL || kbdintctxt->ctxt == NULL)  
                 fatal("input_userauth_info_response: no kbdintctxt");  
         if (kbdintctxt->device == NULL)  
                 fatal("input_userauth_info_response: no device");  
   
         authctxt->postponed = 0;        /* reset */          authctxt->postponed = 0;        /* reset */
         nresp = packet_get_int();          nresp = packet_get_int();
         if (nresp > 0) {          if (nresp == 1) {
                 response = xmalloc(nresp * sizeof(char*));                  response = packet_get_string(&rlen);
                 for (i = 0; i < nresp; i++)                  packet_done();
                         response[i] = packet_get_string(NULL);                  if (strlen(response) == 0) {
         }                          /*
         packet_check_eom();                           * if we received an empty response, resend challenge
                            * with echo enabled
         if (authctxt->valid) {                           */
                 res = kbdintctxt->device->respond(kbdintctxt->ctxt,                          char *challenge = get_challenge(authctxt, NULL);
                     nresp, response);                          if (challenge != NULL) {
         } else {                                  send_userauth_into_request(authctxt,
                 res = -1;                                      challenge, 1);
         }                                  authctxt->postponed = 1;
                           }
         for (i = 0; i < nresp; i++) {                  } else if (authctxt->valid) {
                 memset(response[i], 'r', strlen(response[i]));                          authenticated = verify_response(authctxt, response);
                 xfree(response[i]);                          memset(response, 'r', rlen);
         }                  }
         if (response)  
                 xfree(response);                  xfree(response);
   
         switch (res) {  
         case 0:  
                 /* Success! */  
                 authenticated = 1;  
                 break;  
         case 1:  
                 /* Authentication needs further interaction */  
                 if (send_userauth_info_request(authctxt) == 1)  
                         authctxt->postponed = 1;  
                 break;  
         default:  
                 /* Failure! */  
                 break;  
         }          }
           auth_log(authctxt, authenticated, method, " ssh2");
         len = strlen("keyboard-interactive") + 2 +  
                 strlen(kbdintctxt->device->name);  
         method = xmalloc(len);  
         snprintf(method, len, "keyboard-interactive/%s",  
             kbdintctxt->device->name);  
   
         if (!authctxt->postponed) {          if (!authctxt->postponed) {
                 if (authenticated) {                  /* unregister callback and send reply */
                         auth2_challenge_stop(authctxt);                  dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
                 } else {                  userauth_reply(authctxt, authenticated);
                         /* start next device */  
                         /* may set authctxt->postponed */  
                         auth2_challenge_start(authctxt);  
                 }  
         }          }
         userauth_finish(authctxt, authenticated, method);  
         xfree(method);  
 }  }

Legend:
Removed from v.1.2.2.7  
changed lines
  Added in v.1.3