Home | History | Annotate | Download | only in lib
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel (at) haxx.se>, et al.
      9  *
     10  * This software is licensed as described in the file COPYING, which
     11  * you should have received as part of this distribution. The terms
     12  * are also available at https://curl.haxx.se/docs/copyright.html.
     13  *
     14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     15  * copies of the Software, and permit persons to whom the Software is
     16  * furnished to do so, under the terms of the COPYING file.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  ***************************************************************************/
     22 
     23 #include "curl_setup.h"
     24 
     25 #ifdef HAVE_PWD_H
     26 #include <pwd.h>
     27 #endif
     28 
     29 #include <curl/curl.h>
     30 #include "netrc.h"
     31 #include "strtok.h"
     32 #include "strcase.h"
     33 
     34 /* The last 3 #include files should be in this order */
     35 #include "curl_printf.h"
     36 #include "curl_memory.h"
     37 #include "memdebug.h"
     38 
     39 /* Get user and password from .netrc when given a machine name */
     40 
     41 enum host_lookup_state {
     42   NOTHING,
     43   HOSTFOUND,    /* the 'machine' keyword was found */
     44   HOSTVALID     /* this is "our" machine! */
     45 };
     46 
     47 /*
     48  * @unittest: 1304
     49  *
     50  * *loginp and *passwordp MUST be allocated if they aren't NULL when passed
     51  * in.
     52  */
     53 int Curl_parsenetrc(const char *host,
     54                     char **loginp,
     55                     char **passwordp,
     56                     char *netrcfile)
     57 {
     58   FILE *file;
     59   int retcode = 1;
     60   int specific_login = (*loginp && **loginp != 0);
     61   bool netrc_alloc = FALSE;
     62   enum host_lookup_state state = NOTHING;
     63 
     64   char state_login = 0;      /* Found a login keyword */
     65   char state_password = 0;   /* Found a password keyword */
     66   int state_our_login = FALSE;  /* With specific_login, found *our* login
     67                                    name */
     68 
     69 #define NETRC DOT_CHAR "netrc"
     70 
     71   if(!netrcfile) {
     72     bool home_alloc = FALSE;
     73     char *home = curl_getenv("HOME"); /* portable environment reader */
     74     if(home) {
     75       home_alloc = TRUE;
     76 #if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
     77     }
     78     else {
     79       struct passwd pw, *pw_res;
     80       char pwbuf[1024];
     81       if(!getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res)
     82          && pw_res) {
     83         home = strdup(pw.pw_dir);
     84         if(!home)
     85           return CURLE_OUT_OF_MEMORY;
     86         home_alloc = TRUE;
     87       }
     88 #elif defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
     89     }
     90     else {
     91       struct passwd *pw;
     92       pw = getpwuid(geteuid());
     93       if(pw) {
     94         home = pw->pw_dir;
     95       }
     96 #endif
     97     }
     98 
     99     if(!home)
    100       return retcode; /* no home directory found (or possibly out of memory) */
    101 
    102     netrcfile = curl_maprintf("%s%s%s", home, DIR_CHAR, NETRC);
    103     if(home_alloc)
    104       free(home);
    105     if(!netrcfile) {
    106       return -1;
    107     }
    108     netrc_alloc = TRUE;
    109   }
    110 
    111   file = fopen(netrcfile, FOPEN_READTEXT);
    112   if(netrc_alloc)
    113     free(netrcfile);
    114   if(file) {
    115     char *tok;
    116     char *tok_buf;
    117     bool done = FALSE;
    118     char netrcbuffer[256];
    119     int  netrcbuffsize = (int)sizeof(netrcbuffer);
    120 
    121     while(!done && fgets(netrcbuffer, netrcbuffsize, file)) {
    122       tok = strtok_r(netrcbuffer, " \t\n", &tok_buf);
    123       if(tok && *tok == '#')
    124         /* treat an initial hash as a comment line */
    125         continue;
    126       while(!done && tok) {
    127 
    128         if((*loginp && **loginp) && (*passwordp && **passwordp)) {
    129           done = TRUE;
    130           break;
    131         }
    132 
    133         switch(state) {
    134         case NOTHING:
    135           if(strcasecompare("machine", tok)) {
    136             /* the next tok is the machine name, this is in itself the
    137                delimiter that starts the stuff entered for this machine,
    138                after this we need to search for 'login' and
    139                'password'. */
    140             state = HOSTFOUND;
    141           }
    142           else if(strcasecompare("default", tok)) {
    143             state = HOSTVALID;
    144             retcode = 0; /* we did find our host */
    145           }
    146           break;
    147         case HOSTFOUND:
    148           if(strcasecompare(host, tok)) {
    149             /* and yes, this is our host! */
    150             state = HOSTVALID;
    151             retcode = 0; /* we did find our host */
    152           }
    153           else
    154             /* not our host */
    155             state = NOTHING;
    156           break;
    157         case HOSTVALID:
    158           /* we are now parsing sub-keywords concerning "our" host */
    159           if(state_login) {
    160             if(specific_login) {
    161               state_our_login = strcasecompare(*loginp, tok);
    162             }
    163             else {
    164               free(*loginp);
    165               *loginp = strdup(tok);
    166               if(!*loginp) {
    167                 retcode = -1; /* allocation failed */
    168                 goto out;
    169               }
    170             }
    171             state_login = 0;
    172           }
    173           else if(state_password) {
    174             if(state_our_login || !specific_login) {
    175               free(*passwordp);
    176               *passwordp = strdup(tok);
    177               if(!*passwordp) {
    178                 retcode = -1; /* allocation failed */
    179                 goto out;
    180               }
    181             }
    182             state_password = 0;
    183           }
    184           else if(strcasecompare("login", tok))
    185             state_login = 1;
    186           else if(strcasecompare("password", tok))
    187             state_password = 1;
    188           else if(strcasecompare("machine", tok)) {
    189             /* ok, there's machine here go => */
    190             state = HOSTFOUND;
    191             state_our_login = FALSE;
    192           }
    193           break;
    194         } /* switch (state) */
    195 
    196         tok = strtok_r(NULL, " \t\n", &tok_buf);
    197       } /* while(tok) */
    198     } /* while fgets() */
    199 
    200     out:
    201     fclose(file);
    202   }
    203 
    204   return retcode;
    205 }
    206