1 /*
2 Copyright (c) 1998-2018 University Corporation for Atmospheric Research/Unidata
3 See COPYRIGHT for license information.
4 */
5 
6 
7 #include "config.h"
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #ifdef HAVE_UNISTD_H
12 #include <unistd.h>
13 #endif
14 #ifdef HAVE_STDARG_H
15 #include <stdarg.h>
16 #endif
17 #include "netcdf.h"
18 #include "ncbytes.h"
19 #include "ncuri.h"
20 #include "ncauth.h"
21 #include "nclog.h"
22 #include "ncwinpath.h"
23 
24 #ifdef _MSC_VER
25 #include <windows.h>
26 #endif
27 
28 #undef MEMCHECK
29 #define MEMCHECK(x) if((x)==NULL) {goto nomem;} else {}
30 
31 /* Define the curl flag defaults in envv style */
32 static const char* AUTHDEFAULTS[] = {
33 "HTTP.TIMEOUT","1800", /*seconds */ /* Long but not infinite */
34 "HTTP.CONNECTTIMEOUT","50", /*seconds */ /* Long but not infinite */
35 NULL
36 };
37 
38 /* Forward */
39 static int setauthfield(NCauth* auth, const char* flag, const char* value);
40 static void setdefaults(NCauth*);
41 
42 /**************************************************/
43 /* External Entry Points */
44 
45 int
NC_parseproxy(NCauth * auth,const char * surl)46 NC_parseproxy(NCauth* auth, const char* surl)
47 {
48     int ret = NC_NOERR;
49     NCURI* uri = NULL;
50     if(surl == NULL || strlen(surl) == 0)
51 	return (NC_NOERR); /* nothing there*/
52     if(ncuriparse(surl,&uri))
53 	return (NC_EURL);
54     auth->proxy.user = uri->user;
55     auth->proxy.pwd = uri->password;
56     auth->proxy.host = strdup(uri->host);
57     if(uri->port != NULL)
58         auth->proxy.port = atoi(uri->port);
59     else
60         auth->proxy.port = 80;
61     return (ret);
62 }
63 
64 char*
NC_combinehostport(NCURI * uri)65 NC_combinehostport(NCURI* uri)
66 {
67     size_t len;
68     char* host = NULL;
69     char* port = NULL;
70     char* hp = NULL;
71     if(uri == NULL) return NULL;
72     host = uri->host;
73     port = uri->port;
74     if(uri == NULL || host == NULL) return NULL;
75     if(port != NULL && strlen(port) == 0) port = NULL;
76     len = strlen(host);
77     if(port != NULL) len += (1+strlen(port));
78     hp = (char*)malloc(len+1);
79     if(hp == NULL) return NULL;
80     strncpy(hp,host,len);
81     if(port != NULL) {
82 	strncat(hp,":",len);
83 	strncat(hp,port,len);
84     }
85     return hp;
86 }
87 
88 int
NC_authsetup(NCauth * auth,NCURI * uri)89 NC_authsetup(NCauth* auth, NCURI* uri)
90 {
91     int ret = NC_NOERR;
92     char* uri_hostport = NULL;
93 
94     if(uri != NULL)
95       uri_hostport = NC_combinehostport(uri);
96     else
97       return NC_EDAP; /* Generic EDAP error. */
98     setdefaults(auth);
99 
100     /* Note, we still must do this function even if
101        ncrc_getglobalstate()->rc.ignore is set in order
102        to getinfo e.g. host+port  from url
103     */
104 
105     setauthfield(auth,"HTTP.DEFLATE",
106 		      NC_rclookup("HTTP.DEFLATE",uri_hostport));
107     setauthfield(auth,"HTTP.VERBOSE",
108 			NC_rclookup("HTTP.VERBOSE",uri_hostport));
109     setauthfield(auth,"HTTP.TIMEOUT",
110 			NC_rclookup("HTTP.TIMEOUT",uri_hostport));
111     setauthfield(auth,"HTTP.CONNECTTIMEOUT",
112 			NC_rclookup("HTTP.CONNECTTIMEOUT",uri_hostport));
113     setauthfield(auth,"HTTP.USERAGENT",
114 			NC_rclookup("HTTP.USERAGENT",uri_hostport));
115     setauthfield(auth,"HTTP.COOKIEFILE",
116 			NC_rclookup("HTTP.COOKIEFILE",uri_hostport));
117     setauthfield(auth,"HTTP.COOKIE_FILE",
118 			NC_rclookup("HTTP.COOKIE_FILE",uri_hostport));
119     setauthfield(auth,"HTTP.COOKIEJAR",
120 			NC_rclookup("HTTP.COOKIEJAR",uri_hostport));
121     setauthfield(auth,"HTTP.COOKIE_JAR",
122 			NC_rclookup("HTTP.COOKIE_JAR",uri_hostport));
123     setauthfield(auth,"HTTP.PROXY.SERVER",
124 			NC_rclookup("HTTP.PROXY.SERVER",uri_hostport));
125     setauthfield(auth,"HTTP.PROXY_SERVER",
126 			NC_rclookup("HTTP.PROXY_SERVER",uri_hostport));
127     setauthfield(auth,"HTTP.SSL.VALIDATE",
128 			NC_rclookup("HTTP.SSL.VALIDATE",uri_hostport));
129     setauthfield(auth,"HTTP.SSL.CERTIFICATE",
130 			NC_rclookup("HTTP.SSL.CERTIFICATE",uri_hostport));
131     setauthfield(auth,"HTTP.SSL.KEY",
132 			NC_rclookup("HTTP.SSL.KEY",uri_hostport));
133     setauthfield(auth,"HTTP.SSL.KEYPASSWORD",
134 			NC_rclookup("HTTP.SSL.KEYPASSWORD",uri_hostport));
135     setauthfield(auth,"HTTP.SSL.CAINFO",
136 			NC_rclookup("HTTP.SSL.CAINFO",uri_hostport));
137     setauthfield(auth,"HTTP.SSL.CAPATH",
138 			NC_rclookup("HTTP.SSL.CAPATH",uri_hostport));
139     setauthfield(auth,"HTTP.SSL.VERIFYPEER",
140 			NC_rclookup("HTTP.SSL.VERIFYPEER",uri_hostport));
141     setauthfield(auth,"HTTP.NETRC",
142 			NC_rclookup("HTTP.NETRC",uri_hostport));
143 
144     { /* Handle various cases for user + password */
145       /* First, see if the user+pwd was in the original url */
146       char* user = NULL;
147       char* pwd = NULL;
148       if(uri->user != NULL && uri->password != NULL) {
149 	    user = uri->user;
150 	    pwd = uri->password;
151       } else {
152    	    user = NC_rclookup("HTTP.CREDENTIALS.USER",uri_hostport);
153 	    pwd = NC_rclookup("HTTP.CREDENTIALS.PASSWORD",uri_hostport);
154       }
155       if(user != NULL && pwd != NULL) {
156         user = strdup(user); /* so we can consistently reclaim */
157         pwd = strdup(pwd);
158       } else {
159 	    /* Could not get user and pwd, so try USERPASSWORD */
160 	    const char* userpwd = NC_rclookup("HTTP.CREDENTIALS.USERPASSWORD",uri_hostport);
161 	    if(userpwd != NULL) {
162           ret = NC_parsecredentials(userpwd,&user,&pwd);
163           if(ret) {nullfree(uri_hostport); return ret;}
164 	    }
165       }
166       setauthfield(auth,"HTTP.CREDENTIALS.USERNAME",user);
167       setauthfield(auth,"HTTP.CREDENTIALS.PASSWORD",pwd);
168       nullfree(user);
169       nullfree(pwd);
170       nullfree(uri_hostport);
171     }
172     return (ret);
173 }
174 
175 void
NC_authclear(NCauth * auth)176 NC_authclear(NCauth* auth)
177 {
178     if(auth->curlflags.cookiejarcreated) {
179 #ifdef _MSC_VER
180         DeleteFile(auth->curlflags.cookiejar);
181 #else
182         remove(auth->curlflags.cookiejar);
183 #endif
184     }
185     nullfree(auth->curlflags.useragent);
186     nullfree(auth->curlflags.cookiejar);
187     nullfree(auth->curlflags.netrc);
188     nullfree(auth->ssl.certificate);
189     nullfree(auth->ssl.key);
190     nullfree(auth->ssl.keypasswd);
191     nullfree(auth->ssl.cainfo);
192     nullfree(auth->ssl.capath);
193     nullfree(auth->proxy.host);
194     nullfree(auth->proxy.user);
195     nullfree(auth->proxy.pwd);
196     nullfree(auth->creds.user);
197     nullfree(auth->creds.pwd);
198 }
199 
200 /**************************************************/
201 
202 static int
setauthfield(NCauth * auth,const char * flag,const char * value)203 setauthfield(NCauth* auth, const char* flag, const char* value)
204 {
205     int ret = NC_NOERR;
206     if(value == NULL) goto done;
207     if(strcmp(flag,"HTTP.DEFLATE")==0) {
208         if(atoi(value)) auth->curlflags.compress = 1;
209 #ifdef D4DEBUG
210         nclog(NCLOGNOTE,"HTTP.DEFLATE: %ld", infoflags.compress);
211 #endif
212     }
213     if(strcmp(flag,"HTTP.VERBOSE")==0) {
214         if(atoi(value)) auth->curlflags.verbose = 1;
215 #ifdef D4DEBUG
216             nclog(NCLOGNOTE,"HTTP.VERBOSE: %ld", auth->curlflags.verbose);
217 #endif
218     }
219     if(strcmp(flag,"HTTP.TIMEOUT")==0) {
220         if(atoi(value)) auth->curlflags.timeout = atoi(value);
221 #ifdef D4DEBUG
222             nclog(NCLOGNOTE,"HTTP.TIMEOUT: %ld", auth->curlflags.timeout);
223 #endif
224     }
225     if(strcmp(flag,"HTTP.CONNECTTIMEOUT")==0) {
226         if(atoi(value)) auth->curlflags.connecttimeout = atoi(value);
227 #ifdef D4DEBUG
228             nclog(NCLOGNOTE,"HTTP.CONNECTTIMEOUT: %ld", auth->curlflags.connecttimeout);
229 #endif
230     }
231     if(strcmp(flag,"HTTP.USERAGENT")==0) {
232         if(atoi(value)) auth->curlflags.useragent = strdup(value);
233         MEMCHECK(auth->curlflags.useragent);
234 #ifdef D4DEBUG
235             nclog(NCLOGNOTE,"HTTP.USERAGENT: %s", auth->curlflags.useragent);
236 #endif
237     }
238     if(
239 	strcmp(flag,"HTTP.COOKIEFILE")==0
240         || strcmp(flag,"HTTP.COOKIE_FILE")==0
241         || strcmp(flag,"HTTP.COOKIEJAR")==0
242         || strcmp(flag,"HTTP.COOKIE_JAR")==0
243       ) {
244 	nullfree(auth->curlflags.cookiejar);
245         auth->curlflags.cookiejar = strdup(value);
246         MEMCHECK(auth->curlflags.cookiejar);
247 #ifdef D4DEBUG
248             nclog(NCLOGNOTE,"HTTP.COOKIEJAR: %s", auth->curlflags.cookiejar);
249 #endif
250     }
251     if(strcmp(flag,"HTTP.PROXY.SERVER")==0 || strcmp(flag,"HTTP.PROXY_SERVER")==0) {
252         ret = NC_parseproxy(auth,value);
253         if(ret != NC_NOERR) goto done;
254 #ifdef D4DEBUG
255             nclog(NCLOGNOTE,"HTTP.PROXY.SERVER: %s", value);
256 #endif
257     }
258     if(strcmp(flag,"HTTP.SSL.VALIDATE")==0) {
259         if(atoi(value)) {
260 	    auth->ssl.verifypeer = 1;
261 	    auth->ssl.verifyhost = 1;
262 #ifdef D4DEBUG
263                 nclog(NCLOGNOTE,"HTTP.SSL.VALIDATE: %ld", 1);
264 #endif
265 	}
266     }
267 
268     if(strcmp(flag,"HTTP.SSL.CERTIFICATE")==0) {
269 	nullfree(auth->ssl.certificate);
270         auth->ssl.certificate = strdup(value);
271         MEMCHECK(auth->ssl.certificate);
272 #ifdef D4DEBUG
273             nclog(NCLOGNOTE,"HTTP.SSL.CERTIFICATE: %s", auth->ssl.certificate);
274 #endif
275     }
276 
277     if(strcmp(flag,"HTTP.SSL.KEY")==0) {
278 	nullfree(auth->ssl.key);
279         auth->ssl.key = strdup(value);
280         MEMCHECK(auth->ssl.key);
281 #ifdef D4DEBUG
282             nclog(NCLOGNOTE,"HTTP.SSL.KEY: %s", auth->ssl.key);
283 #endif
284     }
285 
286     if(strcmp(flag,"HTTP.SSL.KEYPASSWORD")==0) {
287 	nullfree(auth->ssl.keypasswd) ;
288         auth->ssl.keypasswd = strdup(value);
289         MEMCHECK(auth->ssl.keypasswd);
290 #ifdef D4DEBUG
291             nclog(NCLOGNOTE,"HTTP.SSL.KEYPASSWORD: %s", auth->ssl.keypasswd);
292 #endif
293     }
294 
295     if(strcmp(flag,"HTTP.SSL.CAINFO")==0) {
296 	nullfree(auth->ssl.cainfo) ;
297         auth->ssl.cainfo = strdup(value);
298         MEMCHECK(auth->ssl.cainfo);
299 #ifdef D4DEBUG
300             nclog(NCLOGNOTE,"HTTP.SSL.CAINFO: %s", auth->ssl.cainfo);
301 #endif
302     }
303 
304     if(strcmp(flag,"HTTP.SSL.CAPATH")==0) {
305 	nullfree(auth->ssl.capath) ;
306         auth->ssl.capath = strdup(value);
307         MEMCHECK(auth->ssl.capath);
308 #ifdef D4DEBUG
309             nclog(NCLOGNOTE,"HTTP.SSL.CAPATH: %s", auth->ssl.capath);
310 #endif
311     }
312 
313     if(strcmp(flag,"HTTP.SSL.VERIFYPEER")==0) {
314         const char* s = value;
315         int tf = 0;
316         if(s == NULL || strcmp(s,"0")==0 || strcasecmp(s,"false")==0)
317             tf = 0;
318         else if(strcmp(s,"1")==0 || strcasecmp(s,"true")==0)
319             tf = 1;
320         else
321             tf = 1; /* default if not null */
322         auth->ssl.verifypeer = tf;
323 #ifdef D4DEBUG
324             nclog(NCLOGNOTE,"HTTP.SSL.VERIFYPEER: %d", auth->ssl.verifypeer);
325 #endif
326     }
327 
328     if(strcmp(flag,"HTTP.NETRC")==0) {
329         nullfree(auth->curlflags.netrc);
330         auth->curlflags.netrc = strdup(value);
331         MEMCHECK(auth->curlflags.netrc);
332 #ifdef D4DEBUG
333             nclog(NCLOGNOTE,"HTTP.NETRC: %s", auth->curlflags.netrc);
334 #endif
335     }
336 
337     if(strcmp(flag,"HTTP.CREDENTIALS.USERNAME")==0) {
338         nullfree(auth->creds.user);
339         auth->creds.user = strdup(value);
340         MEMCHECK(auth->creds.user);
341     }
342     if(strcmp(flag,"HTTP.CREDENTIALS.PASSWORD")==0) {
343         nullfree(auth->creds.pwd);
344         auth->creds.pwd = strdup(value);
345         MEMCHECK(auth->creds.pwd);
346     }
347 
348 done:
349     return (ret);
350 
351 nomem:
352     return (NC_ENOMEM);
353 }
354 
355 /*
356 Given form user:pwd, parse into user and pwd
357 and do %xx unescaping
358 */
359 int
NC_parsecredentials(const char * userpwd,char ** userp,char ** pwdp)360 NC_parsecredentials(const char* userpwd, char** userp, char** pwdp)
361 {
362   char* user = NULL;
363   char* pwd = NULL;
364 
365   if(userpwd == NULL)
366 	return NC_EINVAL;
367   user = strdup(userpwd);
368   if(user == NULL)
369 	return NC_ENOMEM;
370   pwd = strchr(user,':');
371   if(pwd == NULL) {
372     free(user);
373 	return NC_EINVAL;
374   }
375   *pwd = '\0';
376   pwd++;
377   if(userp)
378 	*userp = ncuridecode(user);
379   if(pwdp)
380 	*pwdp = ncuridecode(pwd);
381   free(user);
382   return NC_NOERR;
383 }
384 
385 static void
setdefaults(NCauth * auth)386 setdefaults(NCauth* auth)
387 {
388     int ret = NC_NOERR;
389     const char** p;
390     for(p=AUTHDEFAULTS;*p;p+=2) {
391 	ret = setauthfield(auth,p[0],p[1]);
392 	if(ret) {
393             nclog(NCLOGERR, "RC file defaulting failed for: %s=%s",p[0],p[1]);
394 	}
395     }
396 }
397