1/***************************************************************************
2 *                                  _   _ ____  _
3 *  Project                     ___| | | |  _ \| |
4 *                             / __| | | | |_) | |
5 *                            | (__| |_| |  _ <| |___
6 *                             \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@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 http://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 "setup.h"
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28
29#ifdef HAVE_UNISTD_H
30#include <unistd.h>
31#endif
32#ifdef HAVE_PWD_H
33#include <pwd.h>
34#endif
35#ifdef __VMS
36#include <unixlib.h>
37#endif
38
39#include <curl/curl.h>
40#include "netrc.h"
41
42#include "strequal.h"
43#include "strtok.h"
44#include "curl_memory.h"
45#include "rawstr.h"
46
47#define _MPRINTF_REPLACE /* use our functions only */
48#include <curl/mprintf.h>
49
50/* The last #include file should be: */
51#include "memdebug.h"
52
53/* Get user and password from .netrc when given a machine name */
54
55enum host_lookup_state {
56  NOTHING,
57  HOSTFOUND,    /* the 'machine' keyword was found */
58  HOSTCOMPLETE, /* the machine name following the keyword was found too */
59  HOSTVALID,    /* this is "our" machine! */
60
61  HOSTEND /* LAST enum */
62};
63
64/*
65 * @unittest: 1304
66 */
67int Curl_parsenetrc(const char *host,
68                    char *login,
69                    char *password,
70                    char *netrcfile)
71{
72  FILE *file;
73  int retcode=1;
74  int specific_login = (login[0] != 0);
75  char *home = NULL;
76  bool home_alloc = FALSE;
77  bool netrc_alloc = FALSE;
78  enum host_lookup_state state=NOTHING;
79
80  char state_login=0;      /* Found a login keyword */
81  char state_password=0;   /* Found a password keyword */
82  int state_our_login=FALSE;  /* With specific_login, found *our* login name */
83
84#define NETRC DOT_CHAR "netrc"
85
86  if(!netrcfile) {
87    home = curl_getenv("HOME"); /* portable environment reader */
88    if(home) {
89      home_alloc = TRUE;
90#if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
91    }
92    else {
93      struct passwd *pw;
94      pw= getpwuid(geteuid());
95      if(pw) {
96#ifdef __VMS
97        home = decc_translate_vms(pw->pw_dir);
98#else
99        home = pw->pw_dir;
100#endif
101      }
102#endif
103    }
104
105    if(!home)
106      return -1;
107
108    netrcfile = curl_maprintf("%s%s%s", home, DIR_CHAR, NETRC);
109    if(!netrcfile) {
110      if(home_alloc)
111        free(home);
112      return -1;
113    }
114    netrc_alloc = TRUE;
115  }
116
117  file = fopen(netrcfile, "r");
118  if(file) {
119    char *tok;
120    char *tok_buf;
121    bool done=FALSE;
122    char netrcbuffer[256];
123    int  netrcbuffsize = (int)sizeof(netrcbuffer);
124
125    while(!done && fgets(netrcbuffer, netrcbuffsize, file)) {
126      tok=strtok_r(netrcbuffer, " \t\n", &tok_buf);
127      while(!done && tok) {
128
129        if(login[0] && password[0]) {
130          done=TRUE;
131          break;
132        }
133
134        switch(state) {
135        case NOTHING:
136          if(Curl_raw_equal("machine", tok)) {
137            /* the next tok is the machine name, this is in itself the
138               delimiter that starts the stuff entered for this machine,
139               after this we need to search for 'login' and
140               'password'. */
141            state=HOSTFOUND;
142          }
143          break;
144        case HOSTFOUND:
145          if(Curl_raw_equal(host, tok)) {
146            /* and yes, this is our host! */
147            state=HOSTVALID;
148            retcode=0; /* we did find our host */
149          }
150          else
151            /* not our host */
152            state=NOTHING;
153          break;
154        case HOSTVALID:
155          /* we are now parsing sub-keywords concerning "our" host */
156          if(state_login) {
157            if(specific_login) {
158              state_our_login = Curl_raw_equal(login, tok);
159            }
160            else {
161              strncpy(login, tok, LOGINSIZE-1);
162            }
163            state_login=0;
164          }
165          else if(state_password) {
166            if(state_our_login || !specific_login) {
167              strncpy(password, tok, PASSWORDSIZE-1);
168            }
169            state_password=0;
170          }
171          else if(Curl_raw_equal("login", tok))
172            state_login=1;
173          else if(Curl_raw_equal("password", tok))
174            state_password=1;
175          else if(Curl_raw_equal("machine", tok)) {
176            /* ok, there's machine here go => */
177            state = HOSTFOUND;
178            state_our_login = FALSE;
179          }
180          break;
181        case HOSTCOMPLETE:
182        case HOSTEND:
183            /* Should not be reached. */
184            DEBUGASSERT(0);
185        } /* switch (state) */
186
187        tok = strtok_r(NULL, " \t\n", &tok_buf);
188      } /* while(tok) */
189    } /* while fgets() */
190
191    fclose(file);
192  }
193
194  if(home_alloc)
195    free(home);
196  if(netrc_alloc)
197    free(netrcfile);
198
199  return retcode;
200}
201