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#include "setup.h"
23
24#include <curl/curl.h>
25
26#include "rawstr.h"
27
28#define ENABLE_CURLX_PRINTF
29/* use our own printf() functions */
30#include "curlx.h"
31
32#include "tool_cfgable.h"
33#include "tool_getparam.h"
34#include "tool_getpass.h"
35#include "tool_homedir.h"
36#include "tool_msgs.h"
37#include "tool_paramhlp.h"
38
39#include "memdebug.h" /* keep this as LAST include */
40
41struct getout *new_getout(struct Configurable *config)
42{
43  struct getout *node = calloc(1, sizeof(struct getout));
44  struct getout *last = config->url_last;
45  if(node) {
46    /* append this new node last in the list */
47    if(last)
48      last->next = node;
49    else
50      config->url_list = node; /* first node */
51
52    /* move the last pointer */
53    config->url_last = node;
54
55    node->flags = config->default_node_flags;
56  }
57  return node;
58}
59
60ParameterError file2string(char **bufp, FILE *file)
61{
62  char buffer[256];
63  char *ptr;
64  char *string = NULL;
65  size_t stringlen = 0;
66  size_t buflen;
67
68  if(file) {
69    while(fgets(buffer, sizeof(buffer), file)) {
70      if((ptr = strchr(buffer, '\r')) != NULL)
71        *ptr = '\0';
72      if((ptr = strchr(buffer, '\n')) != NULL)
73        *ptr = '\0';
74      buflen = strlen(buffer);
75      if((ptr = realloc(string, stringlen+buflen+1)) == NULL) {
76        Curl_safefree(string);
77        return PARAM_NO_MEM;
78      }
79      string = ptr;
80      strcpy(string+stringlen, buffer);
81      stringlen += buflen;
82    }
83  }
84  *bufp = string;
85  return PARAM_OK;
86}
87
88ParameterError file2memory(char **bufp, size_t *size, FILE *file)
89{
90  char *newbuf;
91  char *buffer = NULL;
92  size_t alloc = 512;
93  size_t nused = 0;
94  size_t nread;
95
96  if(file) {
97    do {
98      if(!buffer || (alloc == nused)) {
99        /* size_t overflow detection for huge files */
100        if(alloc+1 > ((size_t)-1)/2) {
101          Curl_safefree(buffer);
102          return PARAM_NO_MEM;
103        }
104        alloc *= 2;
105        /* allocate an extra char, reserved space, for null termination */
106        if((newbuf = realloc(buffer, alloc+1)) == NULL) {
107          Curl_safefree(buffer);
108          return PARAM_NO_MEM;
109        }
110        buffer = newbuf;
111      }
112      nread = fread(buffer+nused, 1, alloc-nused, file);
113      nused += nread;
114    } while(nread);
115    /* null terminate the buffer in case it's used as a string later */
116    buffer[nused] = '\0';
117    /* free trailing slack space, if possible */
118    if(alloc != nused) {
119      if((newbuf = realloc(buffer, nused+1)) == NULL) {
120        Curl_safefree(buffer);
121        return PARAM_NO_MEM;
122      }
123      buffer = newbuf;
124    }
125    /* discard buffer if nothing was read */
126    if(!nused) {
127      Curl_safefree(buffer); /* no string */
128    }
129  }
130  *size = nused;
131  *bufp = buffer;
132  return PARAM_OK;
133}
134
135void cleanarg(char *str)
136{
137#ifdef HAVE_WRITABLE_ARGV
138  /* now that GetStr has copied the contents of nextarg, wipe the next
139   * argument out so that the username:password isn't displayed in the
140   * system process list */
141  if(str) {
142    size_t len = strlen(str);
143    memset(str, ' ', len);
144  }
145#else
146  (void)str;
147#endif
148}
149
150/*
151 * Parse the string and write the integer in the given address. Return
152 * non-zero on failure, zero on success.
153 *
154 * The string must start with a digit to be valid.
155 *
156 * Since this function gets called with the 'nextarg' pointer from within the
157 * getparameter a lot, we must check it for NULL before accessing the str
158 * data.
159 */
160
161int str2num(long *val, const char *str)
162{
163  if(str && ISDIGIT(*str)) {
164    char *endptr;
165    long num = strtol(str, &endptr, 10);
166    if((endptr != str) && (endptr == str + strlen(str))) {
167      *val = num;
168      return 0;  /* Ok */
169    }
170  }
171  return 1; /* badness */
172}
173
174/*
175 * Parse the string and modify the long in the given address. Return
176 * non-zero on failure, zero on success.
177 *
178 * The string is a list of protocols
179 *
180 * Since this function gets called with the 'nextarg' pointer from within the
181 * getparameter a lot, we must check it for NULL before accessing the str
182 * data.
183 */
184
185long proto2num(struct Configurable *config, long *val, const char *str)
186{
187  char *buffer;
188  const char *sep = ",";
189  char *token;
190
191  static struct sprotos {
192    const char *name;
193    long bit;
194  } const protos[] = {
195    { "all", CURLPROTO_ALL },
196    { "http", CURLPROTO_HTTP },
197    { "https", CURLPROTO_HTTPS },
198    { "ftp", CURLPROTO_FTP },
199    { "ftps", CURLPROTO_FTPS },
200    { "scp", CURLPROTO_SCP },
201    { "sftp", CURLPROTO_SFTP },
202    { "telnet", CURLPROTO_TELNET },
203    { "ldap", CURLPROTO_LDAP },
204    { "ldaps", CURLPROTO_LDAPS },
205    { "dict", CURLPROTO_DICT },
206    { "file", CURLPROTO_FILE },
207    { "tftp", CURLPROTO_TFTP },
208    { "imap", CURLPROTO_IMAP },
209    { "imaps", CURLPROTO_IMAPS },
210    { "pop3", CURLPROTO_POP3 },
211    { "pop3s", CURLPROTO_POP3S },
212    { "smtp", CURLPROTO_SMTP },
213    { "smtps", CURLPROTO_SMTPS },
214    { "rtsp", CURLPROTO_RTSP },
215    { "gopher", CURLPROTO_GOPHER },
216    { NULL, 0 }
217  };
218
219  if(!str)
220    return 1;
221
222  buffer = strdup(str); /* because strtok corrupts it */
223  if(!buffer)
224    return 1;
225
226  for(token = strtok(buffer, sep);
227      token;
228      token = strtok(NULL, sep)) {
229    enum e_action { allow, deny, set } action = allow;
230
231    struct sprotos const *pp;
232
233    /* Process token modifiers */
234    while(!ISALNUM(*token)) { /* may be NULL if token is all modifiers */
235      switch (*token++) {
236      case '=':
237        action = set;
238        break;
239      case '-':
240        action = deny;
241        break;
242      case '+':
243        action = allow;
244        break;
245      default: /* Includes case of terminating NULL */
246        Curl_safefree(buffer);
247        return 1;
248      }
249    }
250
251    for(pp=protos; pp->name; pp++) {
252      if(curlx_raw_equal(token, pp->name)) {
253        switch (action) {
254        case deny:
255          *val &= ~(pp->bit);
256          break;
257        case allow:
258          *val |= pp->bit;
259          break;
260        case set:
261          *val = pp->bit;
262          break;
263        }
264        break;
265      }
266    }
267
268    if(!(pp->name)) { /* unknown protocol */
269      /* If they have specified only this protocol, we say treat it as
270         if no protocols are allowed */
271      if(action == set)
272        *val = 0;
273      warnf(config, "unrecognized protocol '%s'\n", token);
274    }
275  }
276  Curl_safefree(buffer);
277  return 0;
278}
279
280/**
281 * Parses the given string looking for an offset (which may be
282 * a larger-than-integer value).
283 *
284 * @param val  the offset to populate
285 * @param str  the buffer containing the offset
286 * @return zero if successful, non-zero if failure.
287 */
288int str2offset(curl_off_t *val, const char *str)
289{
290#if(CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
291  *val = curlx_strtoofft(str, NULL, 0);
292  if((*val == CURL_OFF_T_MAX || *val == CURL_OFF_T_MIN) && (ERRNO == ERANGE))
293    return 1;
294#else
295  *val = strtol(str, NULL, 0);
296  if((*val == LONG_MIN || *val == LONG_MAX) && ERRNO == ERANGE)
297    return 1;
298#endif
299  return 0;
300}
301
302ParameterError checkpasswd(const char *kind, /* for what purpose */
303                           char **userpwd)   /* pointer to allocated string */
304{
305  char *ptr;
306
307  if(!*userpwd)
308    return PARAM_OK;
309
310  ptr = strchr(*userpwd, ':');
311  if(!ptr) {
312    /* no password present, prompt for one */
313    char passwd[256] = "";
314    char prompt[256];
315    size_t passwdlen;
316    size_t userlen = strlen(*userpwd);
317    char *passptr;
318
319    /* build a nice-looking prompt */
320    curlx_msnprintf(prompt, sizeof(prompt),
321                    "Enter %s password for user '%s':",
322                    kind, *userpwd);
323
324    /* get password */
325    getpass_r(prompt, passwd, sizeof(passwd));
326    passwdlen = strlen(passwd);
327
328    /* extend the allocated memory area to fit the password too */
329    passptr = realloc(*userpwd,
330                      passwdlen + 1 + /* an extra for the colon */
331                      userlen + 1);   /* an extra for the zero */
332    if(!passptr)
333      return PARAM_NO_MEM;
334
335    /* append the password separated with a colon */
336    passptr[userlen] = ':';
337    memcpy(&passptr[userlen+1], passwd, passwdlen+1);
338    *userpwd = passptr;
339  }
340  return PARAM_OK;
341}
342
343ParameterError add2list(struct curl_slist **list, const char *ptr)
344{
345  struct curl_slist *newlist = curl_slist_append(*list, ptr);
346  if(newlist)
347    *list = newlist;
348  else
349    return PARAM_NO_MEM;
350
351  return PARAM_OK;
352}
353
354int ftpfilemethod(struct Configurable *config, const char *str)
355{
356  if(curlx_raw_equal("singlecwd", str))
357    return CURLFTPMETHOD_SINGLECWD;
358  if(curlx_raw_equal("nocwd", str))
359    return CURLFTPMETHOD_NOCWD;
360  if(curlx_raw_equal("multicwd", str))
361    return CURLFTPMETHOD_MULTICWD;
362  warnf(config, "unrecognized ftp file method '%s', using default\n", str);
363  return CURLFTPMETHOD_MULTICWD;
364}
365
366int ftpcccmethod(struct Configurable *config, const char *str)
367{
368  if(curlx_raw_equal("passive", str))
369    return CURLFTPSSL_CCC_PASSIVE;
370  if(curlx_raw_equal("active", str))
371    return CURLFTPSSL_CCC_ACTIVE;
372  warnf(config, "unrecognized ftp CCC method '%s', using default\n", str);
373  return CURLFTPSSL_CCC_PASSIVE;
374}
375
376long delegation(struct Configurable *config, char *str)
377{
378  if(curlx_raw_equal("none", str))
379    return CURLGSSAPI_DELEGATION_NONE;
380  if(curlx_raw_equal("policy", str))
381    return CURLGSSAPI_DELEGATION_POLICY_FLAG;
382  if(curlx_raw_equal("always", str))
383    return CURLGSSAPI_DELEGATION_FLAG;
384  warnf(config, "unrecognized delegation method '%s', using none\n", str);
385  return CURLGSSAPI_DELEGATION_NONE;
386}
387
388