netcdf-c/libdispatch/dauth.c
Dennis Heimbigner a2e0f069ec This pr should probably be delayed until after Version 4.5.
Primary change is to cleanup code and remove duplicated code.

1. Unify the rc file reading into libdispatch/drc.c. Eventually extend
   if we need rc file for netcdf itself as opposed to the dap code.
2. Unify the extraction from the rc file of DAP authorization info.
3. Misc. other small unifications: make temp file, read file.
4. Avoid use of libcurl when reading file:// because
   there is some kind of problem with the Visual Studio version.
   Might be related to the winpath problem.
   In any case, do direct read instead.
5. Add new error code NC_ERCFILE for errors in reading RC file.
6. Complete documentation cleanup as indicated in this comment
   https://github.com/Unidata/netcdf-c/pull/472#issuecomment-325926426
7. Convert some occurrences of #ifdef _WIN32 to #ifdef _MSC_VER
2017-09-02 18:09:36 -06:00

383 lines
10 KiB
C

/*
Copyright (c) 1998-2017 University Corporation for Atmospheric Research/Unidata
See LICENSE.txt 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","10", /*seconds */
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) != NCU_OK)
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;
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));
char* 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);
setdefaults(auth);
/* Note, we still must do this function even if
ncrc_globalstate.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.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) return ret;
}
}
setauthfield(auth,"HTTP.USERNAME",user);
setauthfield(auth,"HTTP.PASSWORD",pwd);
nullfree(user);
nullfree(pwd);
}
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.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)
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]);
}
}
}