LCOV - code coverage report
Current view: top level - openssh-6.6p1 - auth2-chall.c (source / functions) Hit Total Coverage
Test: lcov_coverage_final.info Lines: 4 138 2.9 %
Date: 2014-08-01 Functions: 1 9 11.1 %
Branches: 1 87 1.1 %

           Branch data     Line data    Source code
       1                 :            : /* $OpenBSD: auth2-chall.c,v 1.41 2014/02/02 03:44:31 djm Exp $ */
       2                 :            : /*
       3                 :            :  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
       4                 :            :  * Copyright (c) 2001 Per Allansson.  All rights reserved.
       5                 :            :  *
       6                 :            :  * Redistribution and use in source and binary forms, with or without
       7                 :            :  * modification, are permitted provided that the following conditions
       8                 :            :  * are met:
       9                 :            :  * 1. Redistributions of source code must retain the above copyright
      10                 :            :  *    notice, this list of conditions and the following disclaimer.
      11                 :            :  * 2. Redistributions in binary form must reproduce the above copyright
      12                 :            :  *    notice, this list of conditions and the following disclaimer in the
      13                 :            :  *    documentation and/or other materials provided with the distribution.
      14                 :            :  *
      15                 :            :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
      16                 :            :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      17                 :            :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      18                 :            :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
      19                 :            :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      20                 :            :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      21                 :            :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      22                 :            :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      23                 :            :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      24                 :            :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      25                 :            :  */
      26                 :            : 
      27                 :            : #include "includes.h"
      28                 :            : 
      29                 :            : #include <sys/types.h>
      30                 :            : 
      31                 :            : #include <stdarg.h>
      32                 :            : #include <stdio.h>
      33                 :            : #include <string.h>
      34                 :            : 
      35                 :            : #include "xmalloc.h"
      36                 :            : #include "ssh2.h"
      37                 :            : #include "key.h"
      38                 :            : #include "hostfile.h"
      39                 :            : #include "auth.h"
      40                 :            : #include "buffer.h"
      41                 :            : #include "packet.h"
      42                 :            : #include "dispatch.h"
      43                 :            : #include "log.h"
      44                 :            : #include "servconf.h"
      45                 :            : 
      46                 :            : /* import */
      47                 :            : extern ServerOptions options;
      48                 :            : 
      49                 :            : static int auth2_challenge_start(Authctxt *);
      50                 :            : static int send_userauth_info_request(Authctxt *);
      51                 :            : static void input_userauth_info_response(int, u_int32_t, void *);
      52                 :            : 
      53                 :            : #ifdef BSD_AUTH
      54                 :            : extern KbdintDevice bsdauth_device;
      55                 :            : #else
      56                 :            : #ifdef USE_PAM
      57                 :            : extern KbdintDevice sshpam_device;
      58                 :            : #endif
      59                 :            : #ifdef SKEY
      60                 :            : extern KbdintDevice skey_device;
      61                 :            : #endif
      62                 :            : #endif
      63                 :            : 
      64                 :            : KbdintDevice *devices[] = {
      65                 :            : #ifdef BSD_AUTH
      66                 :            :         &bsdauth_device,
      67                 :            : #else
      68                 :            : #ifdef USE_PAM
      69                 :            :         &sshpam_device,
      70                 :            : #endif
      71                 :            : #ifdef SKEY
      72                 :            :         &skey_device,
      73                 :            : #endif
      74                 :            : #endif
      75                 :            :         NULL
      76                 :            : };
      77                 :            : 
      78                 :            : typedef struct KbdintAuthctxt KbdintAuthctxt;
      79                 :            : struct KbdintAuthctxt
      80                 :            : {
      81                 :            :         char *devices;
      82                 :            :         void *ctxt;
      83                 :            :         KbdintDevice *device;
      84                 :            :         u_int nreq;
      85                 :            : };
      86                 :            : 
      87                 :            : #ifdef USE_PAM
      88                 :            : void
      89                 :            : remove_kbdint_device(const char *devname)
      90                 :            : {
      91                 :            :         int i, j;
      92                 :            : 
      93                 :            :         for (i = 0; devices[i] != NULL; i++)
      94                 :            :                 if (strcmp(devices[i]->name, devname) == 0) {
      95                 :            :                         for (j = i; devices[j] != NULL; j++)
      96                 :            :                                 devices[j] = devices[j+1];
      97                 :            :                         i--;
      98                 :            :                 }
      99                 :            : }
     100                 :            : #endif
     101                 :            : 
     102                 :            : static KbdintAuthctxt *
     103                 :          0 : kbdint_alloc(const char *devs)
     104                 :            : {
     105                 :            :         KbdintAuthctxt *kbdintctxt;
     106                 :            :         Buffer b;
     107                 :            :         int i;
     108                 :            : 
     109                 :            : #ifdef USE_PAM
     110                 :            :         if (!options.use_pam)
     111                 :            :                 remove_kbdint_device("pam");
     112                 :            : #endif
     113                 :            : 
     114                 :          0 :         kbdintctxt = xcalloc(1, sizeof(KbdintAuthctxt));
     115         [ #  # ]:          0 :         if (strcmp(devs, "") == 0) {
     116                 :          0 :                 buffer_init(&b);
     117         [ #  # ]:          0 :                 for (i = 0; devices[i]; i++) {
     118         [ #  # ]:          0 :                         if (buffer_len(&b) > 0)
     119                 :          0 :                                 buffer_append(&b, ",", 1);
     120                 :          0 :                         buffer_append(&b, devices[i]->name,
     121                 :          0 :                             strlen(devices[i]->name));
     122                 :            :                 }
     123                 :          0 :                 buffer_append(&b, "\0", 1);
     124                 :          0 :                 kbdintctxt->devices = xstrdup(buffer_ptr(&b));
     125                 :          0 :                 buffer_free(&b);
     126                 :            :         } else {
     127                 :          0 :                 kbdintctxt->devices = xstrdup(devs);
     128                 :            :         }
     129                 :          0 :         debug("kbdint_alloc: devices '%s'", kbdintctxt->devices);
     130                 :          0 :         kbdintctxt->ctxt = NULL;
     131                 :          0 :         kbdintctxt->device = NULL;
     132                 :          0 :         kbdintctxt->nreq = 0;
     133                 :            : 
     134                 :          0 :         return kbdintctxt;
     135                 :            : }
     136                 :            : static void
     137                 :            : kbdint_reset_device(KbdintAuthctxt *kbdintctxt)
     138                 :            : {
     139 [ #  # ][ #  # ]:          0 :         if (kbdintctxt->ctxt) {
     140                 :          0 :                 kbdintctxt->device->free_ctx(kbdintctxt->ctxt);
     141                 :          0 :                 kbdintctxt->ctxt = NULL;
     142                 :            :         }
     143                 :          0 :         kbdintctxt->device = NULL;
     144                 :            : }
     145                 :            : static void
     146                 :          0 : kbdint_free(KbdintAuthctxt *kbdintctxt)
     147                 :            : {
     148         [ #  # ]:          0 :         if (kbdintctxt->device)
     149                 :          0 :                 kbdint_reset_device(kbdintctxt);
     150                 :          0 :         free(kbdintctxt->devices);
     151                 :          0 :         explicit_bzero(kbdintctxt, sizeof(*kbdintctxt));
     152                 :          0 :         free(kbdintctxt);
     153                 :          0 : }
     154                 :            : /* get next device */
     155                 :            : static int
     156                 :          0 : kbdint_next_device(Authctxt *authctxt, KbdintAuthctxt *kbdintctxt)
     157                 :            : {
     158                 :            :         size_t len;
     159                 :            :         char *t;
     160                 :            :         int i;
     161                 :            : 
     162         [ #  # ]:          0 :         if (kbdintctxt->device)
     163                 :          0 :                 kbdint_reset_device(kbdintctxt);
     164                 :            :         do {
     165                 :          0 :                 len = kbdintctxt->devices ?
     166         [ #  # ]:          0 :                     strcspn(kbdintctxt->devices, ",") : 0;
     167                 :            : 
     168         [ #  # ]:          0 :                 if (len == 0)
     169                 :            :                         break;
     170         [ #  # ]:          0 :                 for (i = 0; devices[i]; i++) {
     171         [ #  # ]:          0 :                         if (!auth2_method_allowed(authctxt,
     172                 :            :                             "keyboard-interactive", devices[i]->name))
     173                 :          0 :                                 continue;
     174         [ #  # ]:          0 :                         if (strncmp(kbdintctxt->devices, devices[i]->name, len) == 0)
     175                 :          0 :                                 kbdintctxt->device = devices[i];
     176                 :            :                 }
     177                 :          0 :                 t = kbdintctxt->devices;
     178         [ #  # ]:          0 :                 kbdintctxt->devices = t[len] ? xstrdup(t+len+1) : NULL;
     179                 :          0 :                 free(t);
     180         [ #  # ]:          0 :                 debug2("kbdint_next_device: devices %s", kbdintctxt->devices ?
     181                 :            :                     kbdintctxt->devices : "<empty>");
     182 [ #  # ][ #  # ]:          0 :         } while (kbdintctxt->devices && !kbdintctxt->device);
     183                 :            : 
     184                 :          0 :         return kbdintctxt->device ? 1 : 0;
     185                 :            : }
     186                 :            : 
     187                 :            : /*
     188                 :            :  * try challenge-response, set authctxt->postponed if we have to
     189                 :            :  * wait for the response.
     190                 :            :  */
     191                 :            : int
     192                 :          0 : auth2_challenge(Authctxt *authctxt, char *devs)
     193                 :            : {
     194 [ #  # ][ #  # ]:          0 :         debug("auth2_challenge: user=%s devs=%s",
     195                 :          0 :             authctxt->user ? authctxt->user : "<nouser>",
     196                 :            :             devs ? devs : "<no devs>");
     197                 :            : 
     198 [ #  # ][ #  # ]:          0 :         if (authctxt->user == NULL || !devs)
     199                 :            :                 return 0;
     200         [ #  # ]:          0 :         if (authctxt->kbdintctxt == NULL)
     201                 :          0 :                 authctxt->kbdintctxt = kbdint_alloc(devs);
     202                 :          0 :         return auth2_challenge_start(authctxt);
     203                 :            : }
     204                 :            : 
     205                 :            : /* unregister kbd-int callbacks and context */
     206                 :            : void
     207                 :       2342 : auth2_challenge_stop(Authctxt *authctxt)
     208                 :            : {
     209                 :            :         /* unregister callback */
     210                 :       2342 :         dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE, NULL);
     211         [ -  + ]:       2342 :         if (authctxt->kbdintctxt != NULL) {
     212                 :          0 :                 kbdint_free(authctxt->kbdintctxt);
     213                 :          0 :                 authctxt->kbdintctxt = NULL;
     214                 :            :         }
     215                 :       2342 : }
     216                 :            : 
     217                 :            : /* side effect: sets authctxt->postponed if a reply was sent*/
     218                 :            : static int
     219                 :          0 : auth2_challenge_start(Authctxt *authctxt)
     220                 :            : {
     221                 :          0 :         KbdintAuthctxt *kbdintctxt = authctxt->kbdintctxt;
     222                 :            : 
     223         [ #  # ]:          0 :         debug2("auth2_challenge_start: devices %s",
     224                 :          0 :             kbdintctxt->devices ?  kbdintctxt->devices : "<empty>");
     225                 :            : 
     226         [ #  # ]:          0 :         if (kbdint_next_device(authctxt, kbdintctxt) == 0) {
     227                 :          0 :                 auth2_challenge_stop(authctxt);
     228                 :          0 :                 return 0;
     229                 :            :         }
     230                 :          0 :         debug("auth2_challenge_start: trying authentication method '%s'",
     231                 :          0 :             kbdintctxt->device->name);
     232                 :            : 
     233         [ #  # ]:          0 :         if ((kbdintctxt->ctxt = kbdintctxt->device->init_ctx(authctxt)) == NULL) {
     234                 :          0 :                 auth2_challenge_stop(authctxt);
     235                 :          0 :                 return 0;
     236                 :            :         }
     237         [ #  # ]:          0 :         if (send_userauth_info_request(authctxt) == 0) {
     238                 :          0 :                 auth2_challenge_stop(authctxt);
     239                 :          0 :                 return 0;
     240                 :            :         }
     241                 :          0 :         dispatch_set(SSH2_MSG_USERAUTH_INFO_RESPONSE,
     242                 :            :             &input_userauth_info_response);
     243                 :            : 
     244                 :          0 :         authctxt->postponed = 1;
     245                 :          0 :         return 0;
     246                 :            : }
     247                 :            : 
     248                 :            : static int
     249                 :          0 : send_userauth_info_request(Authctxt *authctxt)
     250                 :            : {
     251                 :            :         KbdintAuthctxt *kbdintctxt;
     252                 :            :         char *name, *instr, **prompts;
     253                 :            :         u_int i, *echo_on;
     254                 :            : 
     255                 :          0 :         kbdintctxt = authctxt->kbdintctxt;
     256         [ #  # ]:          0 :         if (kbdintctxt->device->query(kbdintctxt->ctxt,
     257                 :            :             &name, &instr, &kbdintctxt->nreq, &prompts, &echo_on))
     258                 :            :                 return 0;
     259                 :            : 
     260                 :          0 :         packet_start(SSH2_MSG_USERAUTH_INFO_REQUEST);
     261                 :          0 :         packet_put_cstring(name);
     262                 :          0 :         packet_put_cstring(instr);
     263                 :          0 :         packet_put_cstring("");               /* language not used */
     264                 :          0 :         packet_put_int(kbdintctxt->nreq);
     265         [ #  # ]:          0 :         for (i = 0; i < kbdintctxt->nreq; i++) {
     266                 :          0 :                 packet_put_cstring(prompts[i]);
     267                 :          0 :                 packet_put_char(echo_on[i]);
     268                 :            :         }
     269                 :          0 :         packet_send();
     270                 :          0 :         packet_write_wait();
     271                 :            : 
     272         [ #  # ]:          0 :         for (i = 0; i < kbdintctxt->nreq; i++)
     273                 :          0 :                 free(prompts[i]);
     274                 :          0 :         free(prompts);
     275                 :          0 :         free(echo_on);
     276                 :          0 :         free(name);
     277                 :          0 :         free(instr);
     278                 :            :         return 1;
     279                 :            : }
     280                 :            : 
     281                 :            : static void
     282                 :          0 : input_userauth_info_response(int type, u_int32_t seq, void *ctxt)
     283                 :            : {
     284                 :          0 :         Authctxt *authctxt = ctxt;
     285                 :            :         KbdintAuthctxt *kbdintctxt;
     286                 :          0 :         int authenticated = 0, res;
     287                 :            :         u_int i, nresp;
     288                 :          0 :         const char *devicename = NULL;
     289                 :          0 :         char **response = NULL;
     290                 :            : 
     291         [ #  # ]:          0 :         if (authctxt == NULL)
     292                 :          0 :                 fatal("input_userauth_info_response: no authctxt");
     293                 :          0 :         kbdintctxt = authctxt->kbdintctxt;
     294 [ #  # ][ #  # ]:          0 :         if (kbdintctxt == NULL || kbdintctxt->ctxt == NULL)
     295                 :          0 :                 fatal("input_userauth_info_response: no kbdintctxt");
     296         [ #  # ]:          0 :         if (kbdintctxt->device == NULL)
     297                 :          0 :                 fatal("input_userauth_info_response: no device");
     298                 :            : 
     299                 :          0 :         authctxt->postponed = 0;     /* reset */
     300                 :          0 :         nresp = packet_get_int();
     301         [ #  # ]:          0 :         if (nresp != kbdintctxt->nreq)
     302                 :          0 :                 fatal("input_userauth_info_response: wrong number of replies");
     303         [ #  # ]:          0 :         if (nresp > 100)
     304                 :          0 :                 fatal("input_userauth_info_response: too many replies");
     305         [ #  # ]:          0 :         if (nresp > 0) {
     306                 :          0 :                 response = xcalloc(nresp, sizeof(char *));
     307         [ #  # ]:          0 :                 for (i = 0; i < nresp; i++)
     308                 :          0 :                         response[i] = packet_get_string(NULL);
     309                 :            :         }
     310         [ #  # ]:          0 :         packet_check_eom();
     311                 :            : 
     312                 :          0 :         res = kbdintctxt->device->respond(kbdintctxt->ctxt, nresp, response);
     313                 :            : 
     314         [ #  # ]:          0 :         for (i = 0; i < nresp; i++) {
     315                 :          0 :                 explicit_bzero(response[i], strlen(response[i]));
     316                 :          0 :                 free(response[i]);
     317                 :            :         }
     318                 :          0 :         free(response);
     319                 :            : 
     320      [ #  #  # ]:          0 :         switch (res) {
     321                 :            :         case 0:
     322                 :            :                 /* Success! */
     323                 :          0 :                 authenticated = authctxt->valid ? 1 : 0;
     324                 :          0 :                 break;
     325                 :            :         case 1:
     326                 :            :                 /* Authentication needs further interaction */
     327         [ #  # ]:          0 :                 if (send_userauth_info_request(authctxt) == 1)
     328                 :          0 :                         authctxt->postponed = 1;
     329                 :            :                 break;
     330                 :            :         default:
     331                 :            :                 /* Failure! */
     332                 :            :                 break;
     333                 :            :         }
     334                 :          0 :         devicename = kbdintctxt->device->name;
     335         [ #  # ]:          0 :         if (!authctxt->postponed) {
     336         [ #  # ]:          0 :                 if (authenticated) {
     337                 :          0 :                         auth2_challenge_stop(authctxt);
     338                 :            :                 } else {
     339                 :            :                         /* start next device */
     340                 :            :                         /* may set authctxt->postponed */
     341                 :          0 :                         auth2_challenge_start(authctxt);
     342                 :            :                 }
     343                 :            :         }
     344                 :          0 :         userauth_finish(authctxt, authenticated, "keyboard-interactive",
     345                 :            :             devicename);
     346                 :          0 : }
     347                 :            : 
     348                 :            : void
     349                 :          0 : privsep_challenge_enable(void)
     350                 :            : {
     351                 :            : #if defined(BSD_AUTH) || defined(USE_PAM) || defined(SKEY)
     352                 :            :         int n = 0;
     353                 :            : #endif
     354                 :            : #ifdef BSD_AUTH
     355                 :            :         extern KbdintDevice mm_bsdauth_device;
     356                 :            : #endif
     357                 :            : #ifdef USE_PAM
     358                 :            :         extern KbdintDevice mm_sshpam_device;
     359                 :            : #endif
     360                 :            : #ifdef SKEY
     361                 :            :         extern KbdintDevice mm_skey_device;
     362                 :            : #endif
     363                 :            : 
     364                 :            : #ifdef BSD_AUTH
     365                 :            :         devices[n++] = &mm_bsdauth_device;
     366                 :            : #else
     367                 :            : #ifdef USE_PAM
     368                 :            :         devices[n++] = &mm_sshpam_device;
     369                 :            : #endif
     370                 :            : #ifdef SKEY
     371                 :            :         devices[n++] = &mm_skey_device;
     372                 :            : #endif
     373                 :            : #endif
     374                 :          0 : }

Generated by: LCOV version 1.9