blob: 85912a2efeedd7db22f8a394f30e8555e643b87e [file] [log] [blame]
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2012, 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 "tool_setup.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 long 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 PARAM_OK; /* Ok */
}
}
return PARAM_BAD_NUMERIC; /* badness */
}
/*
* Parse the string and write the long in the given address. Return non-zero
* on failure, zero on success. ONLY ACCEPTS POSITIVE NUMBERS!
*
* 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 str2unum(long *val, const char *str)
{
if(str[0]=='-')
return PARAM_NEGATIVE_NUMERIC; /* badness */
return str2num(val, str);
}
/*
* 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). The offset CANNOT be negative!
*
* @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)
{
char *endptr;
if(str[0] == '-')
/* offsets aren't negative, this indicates weird input */
return PARAM_NEGATIVE_NUMERIC;
#if(CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
*val = curlx_strtoofft(str, &endptr, 0);
if((*val == CURL_OFF_T_MAX || *val == CURL_OFF_T_MIN) && (ERRNO == ERANGE))
return PARAM_BAD_NUMERIC;
#else
*val = strtol(str, &endptr, 0);
if((*val == LONG_MIN || *val == LONG_MAX) && ERRNO == ERANGE)
return PARAM_BAD_NUMERIC;
#endif
if((endptr != str) && (endptr == str + strlen(str)))
return 0; /* Ok */
return PARAM_BAD_NUMERIC;
}
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;
}