Home | History | Annotate | Download | only in lib
      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 1998 - 2016, 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 name */
     67 
     68 #define NETRC DOT_CHAR "netrc"
     69 
     70   if(!netrcfile) {
     71     bool home_alloc = FALSE;
     72     char *home = curl_getenv("HOME"); /* portable environment reader */
     73     if(home) {
     74       home_alloc = TRUE;
     75 #if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
     76     }
     77     else {
     78       struct passwd pw, *pw_res;
     79       char pwbuf[1024];
     80       if(!getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res)
     81          && pw_res) {
     82         home = strdup(pw.pw_dir);
     83         if(!home)
     84           return CURLE_OUT_OF_MEMORY;
     85         home_alloc = TRUE;
     86       }
     87 #elif defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
     88     }
     89     else {
     90       struct passwd *pw;
     91       pw= getpwuid(geteuid());
     92       if(pw) {
     93         home = pw->pw_dir;
     94       }
     95 #endif
     96     }
     97 
     98     if(!home)
     99       return retcode; /* no home directory found (or possibly out of memory) */
    100 
    101     netrcfile = curl_maprintf("%s%s%s", home, DIR_CHAR, NETRC);
    102     if(home_alloc)
    103       free(home);
    104     if(!netrcfile) {
    105       return -1;
    106     }
    107     netrc_alloc = TRUE;
    108   }
    109 
    110   file = fopen(netrcfile, FOPEN_READTEXT);
    111   if(netrc_alloc)
    112     free(netrcfile);
    113   if(file) {
    114     char *tok;
    115     char *tok_buf;
    116     bool done=FALSE;
    117     char netrcbuffer[256];
    118     int  netrcbuffsize = (int)sizeof(netrcbuffer);
    119 
    120     while(!done && fgets(netrcbuffer, netrcbuffsize, file)) {
    121       tok=strtok_r(netrcbuffer, " \t\n", &tok_buf);
    122       while(!done && tok) {
    123 
    124         if((*loginp && **loginp) && (*passwordp && **passwordp)) {
    125           done=TRUE;
    126           break;
    127         }
    128 
    129         switch(state) {
    130         case NOTHING:
    131           if(strcasecompare("machine", tok)) {
    132             /* the next tok is the machine name, this is in itself the
    133                delimiter that starts the stuff entered for this machine,
    134                after this we need to search for 'login' and
    135                'password'. */
    136             state=HOSTFOUND;
    137           }
    138           else if(strcasecompare("default", tok)) {
    139             state=HOSTVALID;
    140             retcode=0; /* we did find our host */
    141           }
    142           break;
    143         case HOSTFOUND:
    144           if(strcasecompare(host, tok)) {
    145             /* and yes, this is our host! */
    146             state=HOSTVALID;
    147             retcode=0; /* we did find our host */
    148           }
    149           else
    150             /* not our host */
    151             state=NOTHING;
    152           break;
    153         case HOSTVALID:
    154           /* we are now parsing sub-keywords concerning "our" host */
    155           if(state_login) {
    156             if(specific_login) {
    157               state_our_login = strcasecompare(*loginp, tok);
    158             }
    159             else {
    160               free(*loginp);
    161               *loginp = strdup(tok);
    162               if(!*loginp) {
    163                 retcode = -1; /* allocation failed */
    164                 goto out;
    165               }
    166             }
    167             state_login=0;
    168           }
    169           else if(state_password) {
    170             if(state_our_login || !specific_login) {
    171               free(*passwordp);
    172               *passwordp = strdup(tok);
    173               if(!*passwordp) {
    174                 retcode = -1; /* allocation failed */
    175                 goto out;
    176               }
    177             }
    178             state_password=0;
    179           }
    180           else if(strcasecompare("login", tok))
    181             state_login=1;
    182           else if(strcasecompare("password", tok))
    183             state_password=1;
    184           else if(strcasecompare("machine", tok)) {
    185             /* ok, there's machine here go => */
    186             state = HOSTFOUND;
    187             state_our_login = FALSE;
    188           }
    189           break;
    190         } /* switch (state) */
    191 
    192         tok = strtok_r(NULL, " \t\n", &tok_buf);
    193       } /* while(tok) */
    194     } /* while fgets() */
    195 
    196     out:
    197     fclose(file);
    198   }
    199 
    200   return retcode;
    201 }
    202