netcdf-c/libdispatch/dauth.c
Dennis Heimbigner 748d26c114 Add support for CURLOPT_CONNECTTIMEOUT
I see that there is no way to set CURLOPT_CONNECTTIMEOUT,
but there is support for CURLOPT_TIMEOUT.
So, accept the line 'HTTP.CONNECTTIMEOUT'
in .rc file to allow user to set CURLOPT_CONNECTTIMEOUT.
2020-01-09 11:48:04 -07:00

397 lines
11 KiB
C

/*
Copyright (c) 1998-2018 University Corporation for Atmospheric Research/Unidata
See COPYRIGHT for license information.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STDARG_H
#include <stdarg.h>
#endif
#include "netcdf.h"
#include "ncbytes.h"
#include "ncuri.h"
#include "ncauth.h"
#include "nclog.h"
#include "ncwinpath.h"
#ifdef _MSC_VER
#include <windows.h>
#endif
#undef MEMCHECK
#define MEMCHECK(x) if((x)==NULL) {goto nomem;} else {}
/* Define the curl flag defaults in envv style */
static const char* AUTHDEFAULTS[] = {
"HTTP.TIMEOUT","1800", /*seconds */ /* Long but not infinite */
"HTTP.CONNECTTIMEOUT","50", /*seconds */ /* Long but not infinite */
NULL
};
/* Forward */
static int setauthfield(NCauth* auth, const char* flag, const char* value);
static void setdefaults(NCauth*);
/**************************************************/
/* External Entry Points */
int
NC_parseproxy(NCauth* auth, const char* surl)
{
int ret = NC_NOERR;
NCURI* uri = NULL;
if(surl == NULL || strlen(surl) == 0)
return (NC_NOERR); /* nothing there*/
if(ncuriparse(surl,&uri))
return (NC_EURL);
auth->proxy.user = uri->user;
auth->proxy.pwd = uri->password;
auth->proxy.host = strdup(uri->host);
if(uri->port != NULL)
auth->proxy.port = atoi(uri->port);
else
auth->proxy.port = 80;
return (ret);
}
char*
NC_combinehostport(NCURI* uri)
{
size_t len;
char* host = NULL;
char* port = NULL;
char* hp = NULL;
if(uri == NULL) return NULL;
host = uri->host;
port = uri->port;
if(uri == NULL || host == NULL) return NULL;
if(port != NULL && strlen(port) == 0) port = NULL;
len = strlen(host);
if(port != NULL) len += (1+strlen(port));
hp = (char*)malloc(len+1);
if(hp == NULL) return NULL;
strncpy(hp,host,len);
if(port != NULL) {
strncat(hp,":",len);
strncat(hp,port,len);
}
return hp;
}
int
NC_authsetup(NCauth* auth, NCURI* uri)
{
int ret = NC_NOERR;
char* uri_hostport = NULL;
if(uri != NULL)
uri_hostport = NC_combinehostport(uri);
else
return NC_EDAP; /* Generic EDAP error. */
setdefaults(auth);
/* Note, we still must do this function even if
ncrc_getglobalstate()->rc.ignore is set in order
to getinfo e.g. host+port from url
*/
setauthfield(auth,"HTTP.DEFLATE",
NC_rclookup("HTTP.DEFLATE",uri_hostport));
setauthfield(auth,"HTTP.VERBOSE",
NC_rclookup("HTTP.VERBOSE",uri_hostport));
setauthfield(auth,"HTTP.TIMEOUT",
NC_rclookup("HTTP.TIMEOUT",uri_hostport));
setauthfield(auth,"HTTP.CONNECTTIMEOUT",
NC_rclookup("HTTP.CONNECTTIMEOUT",uri_hostport));
setauthfield(auth,"HTTP.USERAGENT",
NC_rclookup("HTTP.USERAGENT",uri_hostport));
setauthfield(auth,"HTTP.COOKIEFILE",
NC_rclookup("HTTP.COOKIEFILE",uri_hostport));
setauthfield(auth,"HTTP.COOKIE_FILE",
NC_rclookup("HTTP.COOKIE_FILE",uri_hostport));
setauthfield(auth,"HTTP.COOKIEJAR",
NC_rclookup("HTTP.COOKIEJAR",uri_hostport));
setauthfield(auth,"HTTP.COOKIE_JAR",
NC_rclookup("HTTP.COOKIE_JAR",uri_hostport));
setauthfield(auth,"HTTP.PROXY.SERVER",
NC_rclookup("HTTP.PROXY.SERVER",uri_hostport));
setauthfield(auth,"HTTP.PROXY_SERVER",
NC_rclookup("HTTP.PROXY_SERVER",uri_hostport));
setauthfield(auth,"HTTP.SSL.VALIDATE",
NC_rclookup("HTTP.SSL.VALIDATE",uri_hostport));
setauthfield(auth,"HTTP.SSL.CERTIFICATE",
NC_rclookup("HTTP.SSL.CERTIFICATE",uri_hostport));
setauthfield(auth,"HTTP.SSL.KEY",
NC_rclookup("HTTP.SSL.KEY",uri_hostport));
setauthfield(auth,"HTTP.SSL.KEYPASSWORD",
NC_rclookup("HTTP.SSL.KEYPASSWORD",uri_hostport));
setauthfield(auth,"HTTP.SSL.CAINFO",
NC_rclookup("HTTP.SSL.CAINFO",uri_hostport));
setauthfield(auth,"HTTP.SSL.CAPATH",
NC_rclookup("HTTP.SSL.CAPATH",uri_hostport));
setauthfield(auth,"HTTP.SSL.VERIFYPEER",
NC_rclookup("HTTP.SSL.VERIFYPEER",uri_hostport));
setauthfield(auth,"HTTP.NETRC",
NC_rclookup("HTTP.NETRC",uri_hostport));
{ /* Handle various cases for user + password */
/* First, see if the user+pwd was in the original url */
char* user = NULL;
char* pwd = NULL;
if(uri->user != NULL && uri->password != NULL) {
user = uri->user;
pwd = uri->password;
} else {
user = NC_rclookup("HTTP.CREDENTIALS.USER",uri_hostport);
pwd = NC_rclookup("HTTP.CREDENTIALS.PASSWORD",uri_hostport);
}
if(user != NULL && pwd != NULL) {
user = strdup(user); /* so we can consistently reclaim */
pwd = strdup(pwd);
} else {
/* Could not get user and pwd, so try USERPASSWORD */
const char* userpwd = NC_rclookup("HTTP.CREDENTIALS.USERPASSWORD",uri_hostport);
if(userpwd != NULL) {
ret = NC_parsecredentials(userpwd,&user,&pwd);
if(ret) {nullfree(uri_hostport); return ret;}
}
}
setauthfield(auth,"HTTP.CREDENTIALS.USERNAME",user);
setauthfield(auth,"HTTP.CREDENTIALS.PASSWORD",pwd);
nullfree(user);
nullfree(pwd);
nullfree(uri_hostport);
}
return (ret);
}
void
NC_authclear(NCauth* auth)
{
if(auth->curlflags.cookiejarcreated) {
#ifdef _MSC_VER
DeleteFile(auth->curlflags.cookiejar);
#else
remove(auth->curlflags.cookiejar);
#endif
}
nullfree(auth->curlflags.useragent);
nullfree(auth->curlflags.cookiejar);
nullfree(auth->curlflags.netrc);
nullfree(auth->ssl.certificate);
nullfree(auth->ssl.key);
nullfree(auth->ssl.keypasswd);
nullfree(auth->ssl.cainfo);
nullfree(auth->ssl.capath);
nullfree(auth->proxy.host);
nullfree(auth->proxy.user);
nullfree(auth->proxy.pwd);
nullfree(auth->creds.user);
nullfree(auth->creds.pwd);
}
/**************************************************/
static int
setauthfield(NCauth* auth, const char* flag, const char* value)
{
int ret = NC_NOERR;
if(value == NULL) goto done;
if(strcmp(flag,"HTTP.DEFLATE")==0) {
if(atoi(value)) auth->curlflags.compress = 1;
#ifdef D4DEBUG
nclog(NCLOGNOTE,"HTTP.DEFLATE: %ld", infoflags.compress);
#endif
}
if(strcmp(flag,"HTTP.VERBOSE")==0) {
if(atoi(value)) auth->curlflags.verbose = 1;
#ifdef D4DEBUG
nclog(NCLOGNOTE,"HTTP.VERBOSE: %ld", auth->curlflags.verbose);
#endif
}
if(strcmp(flag,"HTTP.TIMEOUT")==0) {
if(atoi(value)) auth->curlflags.timeout = atoi(value);
#ifdef D4DEBUG
nclog(NCLOGNOTE,"HTTP.TIMEOUT: %ld", auth->curlflags.timeout);
#endif
}
if(strcmp(flag,"HTTP.CONNECTTIMEOUT")==0) {
if(atoi(value)) auth->curlflags.connecttimeout = atoi(value);
#ifdef D4DEBUG
nclog(NCLOGNOTE,"HTTP.CONNECTTIMEOUT: %ld", auth->curlflags.connecttimeout);
#endif
}
if(strcmp(flag,"HTTP.USERAGENT")==0) {
if(atoi(value)) auth->curlflags.useragent = strdup(value);
MEMCHECK(auth->curlflags.useragent);
#ifdef D4DEBUG
nclog(NCLOGNOTE,"HTTP.USERAGENT: %s", auth->curlflags.useragent);
#endif
}
if(
strcmp(flag,"HTTP.COOKIEFILE")==0
|| strcmp(flag,"HTTP.COOKIE_FILE")==0
|| strcmp(flag,"HTTP.COOKIEJAR")==0
|| strcmp(flag,"HTTP.COOKIE_JAR")==0
) {
nullfree(auth->curlflags.cookiejar);
auth->curlflags.cookiejar = strdup(value);
MEMCHECK(auth->curlflags.cookiejar);
#ifdef D4DEBUG
nclog(NCLOGNOTE,"HTTP.COOKIEJAR: %s", auth->curlflags.cookiejar);
#endif
}
if(strcmp(flag,"HTTP.PROXY.SERVER")==0 || strcmp(flag,"HTTP.PROXY_SERVER")==0) {
ret = NC_parseproxy(auth,value);
if(ret != NC_NOERR) goto done;
#ifdef D4DEBUG
nclog(NCLOGNOTE,"HTTP.PROXY.SERVER: %s", value);
#endif
}
if(strcmp(flag,"HTTP.SSL.VALIDATE")==0) {
if(atoi(value)) {
auth->ssl.verifypeer = 1;
auth->ssl.verifyhost = 1;
#ifdef D4DEBUG
nclog(NCLOGNOTE,"HTTP.SSL.VALIDATE: %ld", 1);
#endif
}
}
if(strcmp(flag,"HTTP.SSL.CERTIFICATE")==0) {
nullfree(auth->ssl.certificate);
auth->ssl.certificate = strdup(value);
MEMCHECK(auth->ssl.certificate);
#ifdef D4DEBUG
nclog(NCLOGNOTE,"HTTP.SSL.CERTIFICATE: %s", auth->ssl.certificate);
#endif
}
if(strcmp(flag,"HTTP.SSL.KEY")==0) {
nullfree(auth->ssl.key);
auth->ssl.key = strdup(value);
MEMCHECK(auth->ssl.key);
#ifdef D4DEBUG
nclog(NCLOGNOTE,"HTTP.SSL.KEY: %s", auth->ssl.key);
#endif
}
if(strcmp(flag,"HTTP.SSL.KEYPASSWORD")==0) {
nullfree(auth->ssl.keypasswd) ;
auth->ssl.keypasswd = strdup(value);
MEMCHECK(auth->ssl.keypasswd);
#ifdef D4DEBUG
nclog(NCLOGNOTE,"HTTP.SSL.KEYPASSWORD: %s", auth->ssl.keypasswd);
#endif
}
if(strcmp(flag,"HTTP.SSL.CAINFO")==0) {
nullfree(auth->ssl.cainfo) ;
auth->ssl.cainfo = strdup(value);
MEMCHECK(auth->ssl.cainfo);
#ifdef D4DEBUG
nclog(NCLOGNOTE,"HTTP.SSL.CAINFO: %s", auth->ssl.cainfo);
#endif
}
if(strcmp(flag,"HTTP.SSL.CAPATH")==0) {
nullfree(auth->ssl.capath) ;
auth->ssl.capath = strdup(value);
MEMCHECK(auth->ssl.capath);
#ifdef D4DEBUG
nclog(NCLOGNOTE,"HTTP.SSL.CAPATH: %s", auth->ssl.capath);
#endif
}
if(strcmp(flag,"HTTP.SSL.VERIFYPEER")==0) {
const char* s = value;
int tf = 0;
if(s == NULL || strcmp(s,"0")==0 || strcasecmp(s,"false")==0)
tf = 0;
else if(strcmp(s,"1")==0 || strcasecmp(s,"true")==0)
tf = 1;
else
tf = 1; /* default if not null */
auth->ssl.verifypeer = tf;
#ifdef D4DEBUG
nclog(NCLOGNOTE,"HTTP.SSL.VERIFYPEER: %d", auth->ssl.verifypeer);
#endif
}
if(strcmp(flag,"HTTP.NETRC")==0) {
nullfree(auth->curlflags.netrc);
auth->curlflags.netrc = strdup(value);
MEMCHECK(auth->curlflags.netrc);
#ifdef D4DEBUG
nclog(NCLOGNOTE,"HTTP.NETRC: %s", auth->curlflags.netrc);
#endif
}
if(strcmp(flag,"HTTP.CREDENTIALS.USERNAME")==0) {
nullfree(auth->creds.user);
auth->creds.user = strdup(value);
MEMCHECK(auth->creds.user);
}
if(strcmp(flag,"HTTP.CREDENTIALS.PASSWORD")==0) {
nullfree(auth->creds.pwd);
auth->creds.pwd = strdup(value);
MEMCHECK(auth->creds.pwd);
}
done:
return (ret);
nomem:
return (NC_ENOMEM);
}
/*
Given form user:pwd, parse into user and pwd
and do %xx unescaping
*/
int
NC_parsecredentials(const char* userpwd, char** userp, char** pwdp)
{
char* user = NULL;
char* pwd = NULL;
if(userpwd == NULL)
return NC_EINVAL;
user = strdup(userpwd);
if(user == NULL)
return NC_ENOMEM;
pwd = strchr(user,':');
if(pwd == NULL) {
free(user);
return NC_EINVAL;
}
*pwd = '\0';
pwd++;
if(userp)
*userp = ncuridecode(user);
if(pwdp)
*pwdp = ncuridecode(pwd);
free(user);
return NC_NOERR;
}
static void
setdefaults(NCauth* auth)
{
int ret = NC_NOERR;
const char** p;
for(p=AUTHDEFAULTS;*p;p+=2) {
ret = setauthfield(auth,p[0],p[1]);
if(ret) {
nclog(NCLOGERR, "RC file defaulting failed for: %s=%s",p[0],p[1]);
}
}
}