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