LCOV - code coverage report
Current view: top level - src/server - auth.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 108 115 93.9 %
Date: 2019-11-30 11:33:35 Functions: 5 5 100.0 %

          Line data    Source code
       1             : #include "../burp.h"
       2             : #include "../alloc.h"
       3             : #include "../asfd.h"
       4             : #include "../async.h"
       5             : #include "../cmd.h"
       6             : #include "../conf.h"
       7             : #include "../conffile.h"
       8             : #include "../handy.h"
       9             : #include "../iobuf.h"
      10             : #include "../log.h"
      11             : #include "auth.h"
      12             : 
      13             : #include <time.h>
      14             : #include <assert.h>
      15             : #include <openssl/rand.h>
      16             : 
      17             : #ifndef UTEST
      18             : static
      19             : #endif
      20          12 : int compare_password(const char *secret, const char *client_supplied)
      21             : {
      22             :         int ret, status;
      23             : 
      24          12 :         status = strcmp(secret, client_supplied);
      25             : 
      26             :         // To prevent timing attacks passwords a random sleep is inserted when
      27             :         // the strings didn't match.
      28             :         //
      29             :         // Normally a constant-length string comparison would be preferred.
      30             :         // That doesn't work well here because the length of the secret value
      31             :         // (the configured password) is not known until measured which could
      32             :         // leak the length.
      33          12 :         if (status != 0) {
      34           4 :                 unsigned char delay_bytes[4] = {0};
      35           4 :                 uint32_t delay_nsec = 999999999;
      36             : 
      37             :                 assert(sizeof(delay_bytes) == sizeof(delay_nsec));
      38             : 
      39           4 :                 if (RAND_bytes(delay_bytes, sizeof(delay_bytes)) != 1) {
      40           0 :                         unsigned long err = ERR_get_error();
      41           0 :                         logp("RAND_bytes failed: %s\n", ERR_error_string(err, NULL));
      42             :                         // Keep going without random delay
      43             :                 } else {
      44           4 :                         memcpy(&delay_nsec, delay_bytes, sizeof(delay_nsec));
      45             :                 }
      46             : 
      47           4 :                 struct timespec req = {0};
      48             : 
      49             :                 // Biased, but good enough for the purpose (the random number
      50             :                 // is not what's important)
      51           4 :                 req.tv_nsec = delay_nsec % 1000000000;
      52             : 
      53           4 :                 ret = nanosleep(&req, NULL);
      54           4 :                 if (ret) {
      55           0 :                         logp("nanosleep failed with return value %d: %s\n",
      56           0 :                                 ret, strerror(errno));
      57           0 :                         return -1;
      58             :                 }
      59             :         }
      60             : 
      61             :         return status;
      62             : }
      63             : 
      64             : #ifndef UTEST
      65             : static
      66             : #endif
      67           8 : int check_passwd(const char *passwd, const char *plain_text)
      68             : {
      69             : #ifndef HAVE_OPENBSD_OS
      70             : #ifdef HAVE_CRYPT
      71           8 :         const char *encrypted=NULL;
      72           8 :         if(!plain_text || !passwd || strlen(passwd)<13)
      73             :                 return 0;
      74             : 
      75           5 :         encrypted=crypt(plain_text, passwd);
      76           5 :         if (encrypted == NULL) {
      77           0 :                 logp("crypt function failed: %s\n", strerror(errno));
      78           0 :                 return -1;
      79             :         }
      80             : 
      81           5 :         return !compare_password(passwd, encrypted);
      82             : #endif
      83             : #endif
      84             :         logp("Server compiled without crypt support - cannot use passwd option\n");
      85             :         return -1;
      86             : }
      87             : 
      88          11 : static int check_client_and_password(struct conf **globalcs,
      89             :         const char *password, struct conf **cconfs)
      90             : {
      91             :         const char *cname;
      92             :         int password_check;
      93             :         // Cannot load it until here, because we need to have the name of the
      94             :         // client.
      95          11 :         if(conf_load_clientconfdir(globalcs, cconfs)) return -1;
      96             : 
      97           9 :         cname=get_string(cconfs[OPT_CNAME]);
      98           9 :         password_check=get_int(cconfs[OPT_PASSWORD_CHECK]);
      99             : 
     100           9 :         if(!get_string(cconfs[OPT_SSL_PEER_CN]))
     101             :         {
     102           9 :                 logp("ssl_peer_cn unset");
     103           9 :                 if(cname)
     104             :                 {
     105           9 :                         logp("Falling back to using '%s'\n", cname);
     106           9 :                         if(set_string(cconfs[OPT_SSL_PEER_CN], cname))
     107             :                                 return -1;
     108             :                 }
     109             :         }
     110             : 
     111           9 :         cname=get_string(cconfs[OPT_CNAME]);
     112             : 
     113           9 :         if(password_check)
     114             :         {
     115           9 :                 const char *conf_passwd=get_string(cconfs[OPT_PASSWD]);
     116           9 :                 const char *conf_password=get_string(cconfs[OPT_PASSWORD]);
     117           9 :                 if(!conf_password && !conf_passwd)
     118             :                 {
     119           1 :                         logp("password rejected for client %s\n", cname);
     120           1 :                         return -1;
     121             :                 }
     122             :                 // check against plain text
     123           8 :                 if(conf_password && compare_password(conf_password, password))
     124             :                 {
     125           1 :                         logp("password rejected for client %s\n", cname);
     126           1 :                         return -1;
     127             :                 }
     128             :                 // check against encypted passwd
     129           7 :                 if(conf_passwd && !check_passwd(conf_passwd, password))
     130             :                 {
     131           1 :                         logp("password rejected for client %s\n", cname);
     132           1 :                         return -1;
     133             :                 }
     134             :         }
     135             : 
     136           6 :         if(!get_strlist(cconfs[OPT_KEEP]))
     137             :         {
     138           1 :                 logp("%s: you cannot set the keep value for a client to 0!\n",
     139             :                         cname);
     140           1 :                 return -1;
     141             :         }
     142             :         return 0;
     143             : }
     144             : 
     145           6 : void version_warn(struct asfd *asfd,
     146             :         struct cntr *cntr, struct conf **cconfs)
     147             : {
     148           6 :         const char *cname=get_string(cconfs[OPT_CNAME]);
     149           6 :         const char *peer_version=get_string(cconfs[OPT_PEER_VERSION]);
     150           6 :         if(!peer_version || strcmp(peer_version, PACKAGE_VERSION))
     151             :         {
     152           3 :                 char msg[256]="";
     153             : 
     154           3 :                 if(!peer_version || !*peer_version)
     155           2 :                         snprintf(msg, sizeof(msg), "Client '%s' has an unknown version. Please upgrade.", cname?cname:"unknown");
     156             :                 else
     157           1 :                         snprintf(msg, sizeof(msg), "Client '%s' version '%s' does not match server version '%s'. An upgrade is recommended.", cname?cname:"unknown", peer_version, PACKAGE_VERSION);
     158           3 :                 logw(asfd, cntr, "%s\n", msg);
     159             :         }
     160           6 : }
     161             : 
     162          15 : int authorise_server(struct asfd *asfd,
     163             :         struct conf **globalcs, struct conf **cconfs)
     164             : {
     165          15 :         int ret=-1;
     166          15 :         char *cp=NULL;
     167          15 :         char *password=NULL;
     168          15 :         char *cname=NULL;
     169          15 :         char whoareyou[256]="";
     170          15 :         struct iobuf *rbuf=asfd->rbuf;
     171          15 :         const char *peer_version=NULL;
     172          15 :         if(asfd->read(asfd))
     173             :         {
     174           1 :                 logp("unable to read initial message\n");
     175           1 :                 goto end;
     176             :         }
     177          14 :         if(rbuf->cmd!=CMD_GEN || strncmp_w(rbuf->buf, "hello"))
     178             :         {
     179           1 :                 iobuf_log_unexpected(rbuf, __func__);
     180           1 :                 goto end;
     181             :         }
     182             :         // String may look like...
     183             :         // "hello"
     184             :         // "hello:(version)"
     185             :         // (version) is a version number
     186          13 :         if((cp=strchr(rbuf->buf, ':')))
     187             :         {
     188          12 :                 cp++;
     189          12 :                 if(cp && set_string(cconfs[OPT_PEER_VERSION], cp))
     190             :                         goto end;
     191             :         }
     192          13 :         iobuf_free_content(rbuf);
     193             : 
     194          13 :         snprintf(whoareyou, sizeof(whoareyou), "whoareyou");
     195          13 :         peer_version=get_string(cconfs[OPT_PEER_VERSION]);
     196          13 :         if(peer_version)
     197             :         {
     198          12 :                 long min_ver=0;
     199          12 :                 long cli_ver=0;
     200          12 :                 if((min_ver=version_to_long("1.3.2"))<0
     201          12 :                   || (cli_ver=version_to_long(peer_version))<0)
     202             :                         return -1;
     203             :                 // Stick the server version on the end of the whoareyou string.
     204             :                 // if the client version is recent enough.
     205          12 :                 if(min_ver<=cli_ver)
     206          12 :                  snprintf(whoareyou, sizeof(whoareyou),
     207             :                         "whoareyou:%s", PACKAGE_VERSION);
     208             :         }
     209             : 
     210          13 :         if(asfd->write_str(asfd, CMD_GEN, whoareyou)
     211          12 :           || asfd->read(asfd))
     212             :         {
     213           1 :                 logp("unable to get client name\n");
     214           1 :                 goto end;
     215             :         }
     216             : 
     217          12 :         if(!(cname=strdup_w(rbuf->buf, __func__)))
     218             :                 goto end;
     219          12 :         if(!get_int(globalcs[OPT_CNAME_FQDN]))
     220           1 :                 strip_fqdn(&cname);
     221          12 :         if(get_int(globalcs[OPT_CNAME_LOWERCASE]))
     222           3 :                 strlwr(cname);
     223             : 
     224          12 :         if(set_string(cconfs[OPT_CNAME], cname))
     225             :                 goto end;
     226          12 :         iobuf_free_content(rbuf);
     227             : 
     228          12 :         if(asfd->write_str(asfd, CMD_GEN, "okpassword")
     229          11 :           || asfd->read(asfd))
     230             :         {
     231           1 :                 logp("unable to get password for client %s\n",
     232             :                         get_string(cconfs[OPT_CNAME]));
     233           1 :                 goto end;
     234             :         }
     235          11 :         password=rbuf->buf;
     236          11 :         iobuf_init(rbuf);
     237             : 
     238          11 :         if(check_client_and_password(globalcs, password, cconfs))
     239             :                 goto end;
     240             : 
     241           5 :         if(get_int(cconfs[OPT_VERSION_WARN]))
     242           5 :                 version_warn(asfd, get_cntr(globalcs), cconfs);
     243             : 
     244           5 :         logp("auth ok for: %s%s\n", get_string(cconfs[OPT_CNAME]),
     245           5 :                 get_int(cconfs[OPT_PASSWORD_CHECK])?
     246             :                         "":" (no password needed)");
     247             : 
     248           5 :         if(asfd->write_str(asfd, CMD_GEN, "ok"))
     249             :                 goto end;
     250             : 
     251           5 :         if(set_string(cconfs[OPT_CONNECT_CLIENT], cname))
     252             :                 goto end;
     253             : 
     254           5 :         ret=0;
     255             : end:
     256          15 :         iobuf_free_content(rbuf);
     257          15 :         free_w(&password);
     258          15 :         free_w(&cname);
     259          15 :         return ret;
     260             : }

Generated by: LCOV version 1.13