| /*************************************************************************** |
| * _ _ ____ _ |
| * Project ___| | | | _ \| | |
| * / __| | | | |_) | | |
| * | (__| |_| | _ <| |___ |
| * \___|\___/|_| \_\_____| |
| * |
| * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. |
| * |
| * This software is licensed as described in the file COPYING, which |
| * you should have received as part of this distribution. The terms |
| * are also available at http://curl.haxx.se/docs/copyright.html. |
| * |
| * You may opt to use, copy, modify, merge, publish, distribute and/or sell |
| * copies of the Software, and permit persons to whom the Software is |
| * furnished to do so, under the terms of the COPYING file. |
| * |
| * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| * KIND, either express or implied. |
| * |
| ***************************************************************************/ |
| #include "setup.h" |
| |
| #include <curl/curl.h> |
| |
| #include "rawstr.h" |
| |
| #define ENABLE_CURLX_PRINTF |
| /* use our own printf() functions */ |
| #include "curlx.h" |
| |
| #include "tool_cfgable.h" |
| #include "tool_getparam.h" |
| #include "tool_getpass.h" |
| #include "tool_homedir.h" |
| #include "tool_msgs.h" |
| #include "tool_paramhlp.h" |
| |
| #include "memdebug.h" /* keep this as LAST include */ |
| |
| struct getout *new_getout(struct Configurable *config) |
| { |
| struct getout *node = calloc(1, sizeof(struct getout)); |
| struct getout *last = config->url_last; |
| if(node) { |
| /* append this new node last in the list */ |
| if(last) |
| last->next = node; |
| else |
| config->url_list = node; /* first node */ |
| |
| /* move the last pointer */ |
| config->url_last = node; |
| |
| node->flags = config->default_node_flags; |
| } |
| return node; |
| } |
| |
| ParameterError file2string(char **bufp, FILE *file) |
| { |
| char buffer[256]; |
| char *ptr; |
| char *string = NULL; |
| size_t stringlen = 0; |
| size_t buflen; |
| |
| if(file) { |
| while(fgets(buffer, sizeof(buffer), file)) { |
| if((ptr = strchr(buffer, '\r')) != NULL) |
| *ptr = '\0'; |
| if((ptr = strchr(buffer, '\n')) != NULL) |
| *ptr = '\0'; |
| buflen = strlen(buffer); |
| if((ptr = realloc(string, stringlen+buflen+1)) == NULL) { |
| Curl_safefree(string); |
| return PARAM_NO_MEM; |
| } |
| string = ptr; |
| strcpy(string+stringlen, buffer); |
| stringlen += buflen; |
| } |
| } |
| *bufp = string; |
| return PARAM_OK; |
| } |
| |
| ParameterError file2memory(char **bufp, size_t *size, FILE *file) |
| { |
| char *newbuf; |
| char *buffer = NULL; |
| size_t alloc = 512; |
| size_t nused = 0; |
| size_t nread; |
| |
| if(file) { |
| do { |
| if(!buffer || (alloc == nused)) { |
| /* size_t overflow detection for huge files */ |
| if(alloc+1 > ((size_t)-1)/2) { |
| Curl_safefree(buffer); |
| return PARAM_NO_MEM; |
| } |
| alloc *= 2; |
| /* allocate an extra char, reserved space, for null termination */ |
| if((newbuf = realloc(buffer, alloc+1)) == NULL) { |
| Curl_safefree(buffer); |
| return PARAM_NO_MEM; |
| } |
| buffer = newbuf; |
| } |
| nread = fread(buffer+nused, 1, alloc-nused, file); |
| nused += nread; |
| } while(nread); |
| /* null terminate the buffer in case it's used as a string later */ |
| buffer[nused] = '\0'; |
| /* free trailing slack space, if possible */ |
| if(alloc != nused) { |
| if((newbuf = realloc(buffer, nused+1)) == NULL) { |
| Curl_safefree(buffer); |
| return PARAM_NO_MEM; |
| } |
| buffer = newbuf; |
| } |
| /* discard buffer if nothing was read */ |
| if(!nused) { |
| Curl_safefree(buffer); /* no string */ |
| } |
| } |
| *size = nused; |
| *bufp = buffer; |
| return PARAM_OK; |
| } |
| |
| void cleanarg(char *str) |
| { |
| #ifdef HAVE_WRITABLE_ARGV |
| /* now that GetStr has copied the contents of nextarg, wipe the next |
| * argument out so that the username:password isn't displayed in the |
| * system process list */ |
| if(str) { |
| size_t len = strlen(str); |
| memset(str, ' ', len); |
| } |
| #else |
| (void)str; |
| #endif |
| } |
| |
| /* |
| * Parse the string and write the integer in the given address. Return |
| * non-zero on failure, zero on success. |
| * |
| * Since this function gets called with the 'nextarg' pointer from within the |
| * getparameter a lot, we must check it for NULL before accessing the str |
| * data. |
| */ |
| |
| int str2num(long *val, const char *str) |
| { |
| if(str) { |
| char *endptr; |
| long num = strtol(str, &endptr, 10); |
| if((endptr != str) && (endptr == str + strlen(str))) { |
| *val = num; |
| return 0; /* Ok */ |
| } |
| } |
| return 1; /* badness */ |
| } |
| |
| /* |
| * Parse the string and modify the long in the given address. Return |
| * non-zero on failure, zero on success. |
| * |
| * The string is a list of protocols |
| * |
| * Since this function gets called with the 'nextarg' pointer from within the |
| * getparameter a lot, we must check it for NULL before accessing the str |
| * data. |
| */ |
| |
| long proto2num(struct Configurable *config, long *val, const char *str) |
| { |
| char *buffer; |
| const char *sep = ","; |
| char *token; |
| |
| static struct sprotos { |
| const char *name; |
| long bit; |
| } const protos[] = { |
| { "all", CURLPROTO_ALL }, |
| { "http", CURLPROTO_HTTP }, |
| { "https", CURLPROTO_HTTPS }, |
| { "ftp", CURLPROTO_FTP }, |
| { "ftps", CURLPROTO_FTPS }, |
| { "scp", CURLPROTO_SCP }, |
| { "sftp", CURLPROTO_SFTP }, |
| { "telnet", CURLPROTO_TELNET }, |
| { "ldap", CURLPROTO_LDAP }, |
| { "ldaps", CURLPROTO_LDAPS }, |
| { "dict", CURLPROTO_DICT }, |
| { "file", CURLPROTO_FILE }, |
| { "tftp", CURLPROTO_TFTP }, |
| { "imap", CURLPROTO_IMAP }, |
| { "imaps", CURLPROTO_IMAPS }, |
| { "pop3", CURLPROTO_POP3 }, |
| { "pop3s", CURLPROTO_POP3S }, |
| { "smtp", CURLPROTO_SMTP }, |
| { "smtps", CURLPROTO_SMTPS }, |
| { "rtsp", CURLPROTO_RTSP }, |
| { "gopher", CURLPROTO_GOPHER }, |
| { NULL, 0 } |
| }; |
| |
| if(!str) |
| return 1; |
| |
| buffer = strdup(str); /* because strtok corrupts it */ |
| if(!buffer) |
| return 1; |
| |
| for(token = strtok(buffer, sep); |
| token; |
| token = strtok(NULL, sep)) { |
| enum e_action { allow, deny, set } action = allow; |
| |
| struct sprotos const *pp; |
| |
| /* Process token modifiers */ |
| while(!ISALNUM(*token)) { /* may be NULL if token is all modifiers */ |
| switch (*token++) { |
| case '=': |
| action = set; |
| break; |
| case '-': |
| action = deny; |
| break; |
| case '+': |
| action = allow; |
| break; |
| default: /* Includes case of terminating NULL */ |
| Curl_safefree(buffer); |
| return 1; |
| } |
| } |
| |
| for(pp=protos; pp->name; pp++) { |
| if(curlx_raw_equal(token, pp->name)) { |
| switch (action) { |
| case deny: |
| *val &= ~(pp->bit); |
| break; |
| case allow: |
| *val |= pp->bit; |
| break; |
| case set: |
| *val = pp->bit; |
| break; |
| } |
| break; |
| } |
| } |
| |
| if(!(pp->name)) { /* unknown protocol */ |
| /* If they have specified only this protocol, we say treat it as |
| if no protocols are allowed */ |
| if(action == set) |
| *val = 0; |
| warnf(config, "unrecognized protocol '%s'\n", token); |
| } |
| } |
| Curl_safefree(buffer); |
| return 0; |
| } |
| |
| /** |
| * Parses the given string looking for an offset (which may be |
| * a larger-than-integer value). |
| * |
| * @param val the offset to populate |
| * @param str the buffer containing the offset |
| * @return zero if successful, non-zero if failure. |
| */ |
| int str2offset(curl_off_t *val, const char *str) |
| { |
| #if(CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG) |
| *val = curlx_strtoofft(str, NULL, 0); |
| if((*val == CURL_OFF_T_MAX || *val == CURL_OFF_T_MIN) && (ERRNO == ERANGE)) |
| return 1; |
| #else |
| *val = strtol(str, NULL, 0); |
| if((*val == LONG_MIN || *val == LONG_MAX) && ERRNO == ERANGE) |
| return 1; |
| #endif |
| return 0; |
| } |
| |
| ParameterError checkpasswd(const char *kind, /* for what purpose */ |
| char **userpwd) /* pointer to allocated string */ |
| { |
| char *ptr; |
| |
| if(!*userpwd) |
| return PARAM_OK; |
| |
| ptr = strchr(*userpwd, ':'); |
| if(!ptr) { |
| /* no password present, prompt for one */ |
| char passwd[256] = ""; |
| char prompt[256]; |
| size_t passwdlen; |
| size_t userlen = strlen(*userpwd); |
| char *passptr; |
| |
| /* build a nice-looking prompt */ |
| curlx_msnprintf(prompt, sizeof(prompt), |
| "Enter %s password for user '%s':", |
| kind, *userpwd); |
| |
| /* get password */ |
| getpass_r(prompt, passwd, sizeof(passwd)); |
| passwdlen = strlen(passwd); |
| |
| /* extend the allocated memory area to fit the password too */ |
| passptr = realloc(*userpwd, |
| passwdlen + 1 + /* an extra for the colon */ |
| userlen + 1); /* an extra for the zero */ |
| if(!passptr) |
| return PARAM_NO_MEM; |
| |
| /* append the password separated with a colon */ |
| passptr[userlen] = ':'; |
| memcpy(&passptr[userlen+1], passwd, passwdlen+1); |
| *userpwd = passptr; |
| } |
| return PARAM_OK; |
| } |
| |
| ParameterError add2list(struct curl_slist **list, const char *ptr) |
| { |
| struct curl_slist *newlist = curl_slist_append(*list, ptr); |
| if(newlist) |
| *list = newlist; |
| else |
| return PARAM_NO_MEM; |
| |
| return PARAM_OK; |
| } |
| |
| int ftpfilemethod(struct Configurable *config, const char *str) |
| { |
| if(curlx_raw_equal("singlecwd", str)) |
| return CURLFTPMETHOD_SINGLECWD; |
| if(curlx_raw_equal("nocwd", str)) |
| return CURLFTPMETHOD_NOCWD; |
| if(curlx_raw_equal("multicwd", str)) |
| return CURLFTPMETHOD_MULTICWD; |
| warnf(config, "unrecognized ftp file method '%s', using default\n", str); |
| return CURLFTPMETHOD_MULTICWD; |
| } |
| |
| int ftpcccmethod(struct Configurable *config, const char *str) |
| { |
| if(curlx_raw_equal("passive", str)) |
| return CURLFTPSSL_CCC_PASSIVE; |
| if(curlx_raw_equal("active", str)) |
| return CURLFTPSSL_CCC_ACTIVE; |
| warnf(config, "unrecognized ftp CCC method '%s', using default\n", str); |
| return CURLFTPSSL_CCC_PASSIVE; |
| } |
| |
| long delegation(struct Configurable *config, char *str) |
| { |
| if(curlx_raw_equal("none", str)) |
| return CURLGSSAPI_DELEGATION_NONE; |
| if(curlx_raw_equal("policy", str)) |
| return CURLGSSAPI_DELEGATION_POLICY_FLAG; |
| if(curlx_raw_equal("always", str)) |
| return CURLGSSAPI_DELEGATION_FLAG; |
| warnf(config, "unrecognized delegation method '%s', using none\n", str); |
| return CURLGSSAPI_DELEGATION_NONE; |
| } |
| |