Coverage Report

Created: 2026-08-22 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/netcdf-c/libdispatch/dauth.c
Line
Count
Source
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 "nclog.h"
21
#include "ncpathmgr.h"
22
#include "ncs3sdk.h"
23
#include "ncauth.h"
24
25
#ifdef _MSC_VER
26
#include <windows.h>
27
#endif
28
29
#include "ncrc.h"
30
31
#define DEBUG 0
32
#if DEBUG
33
#define DEBUGLOG(...) nclog(__VA_ARGS__)
34
#else
35
0
#define DEBUGLOG(...) ((void)0)
36
#endif
37
38
#undef MEMCHECK
39
0
#define MEMCHECK(x) if((x)==NULL) {goto nomem;} else {}
40
41
42
0
#define NCAUTH_DEFAULT_SSL_VERIFY -1
43
44
static const NCauth default_auth = {
45
    .ssl = {
46
        .verifyhost = NCAUTH_DEFAULT_SSL_VERIFY,
47
        .verifypeer = NCAUTH_DEFAULT_SSL_VERIFY,
48
    },
49
    .curlflags.timeout = 1800,
50
    .curlflags.connecttimeout=50,
51
    .curlflags.encode = 1,
52
};
53
54
/* Forward for helper functions */
55
static int setauthfield(NCauth* auth, const char* flag, const char* value);
56
static void setdefaults(NCauth*);
57
58
/**************************************************/
59
/* External Entry Points */
60
61
int
62
NC_parseproxy(NCauth* auth, const char* surl)
63
0
{
64
0
    int ret = NC_NOERR;
65
0
    NCURI* uri = NULL;
66
0
    if(surl == NULL || strlen(surl) == 0)
67
0
  return (NC_NOERR); /* nothing there*/
68
0
    if(ncuriparse(surl,&uri))
69
0
  return (NC_EURL);
70
0
    auth->proxy.user = uri->user;
71
0
    auth->proxy.pwd = uri->password;
72
0
    auth->proxy.host = strdup(uri->host);
73
0
    if(uri->port != NULL)
74
0
        auth->proxy.port = atoi(uri->port);
75
0
    else
76
0
        auth->proxy.port = 80;
77
0
    return (ret);
78
0
}
79
80
char*
81
NC_combinehostport(NCURI* uri)
82
0
{
83
0
    size_t len;
84
0
    char* host = NULL;
85
0
    char* port = NULL;
86
0
    char* hp = NULL;
87
0
    if(uri == NULL) return NULL;
88
0
    host = uri->host;
89
0
    port = uri->port;
90
0
    if(uri == NULL || host == NULL) return NULL;
91
0
    if(port != NULL && strlen(port) == 0) port = NULL;
92
0
    len = strlen(host);
93
0
    if(port != NULL) len += (1+strlen(port));
94
0
    hp = (char*)malloc(len+1);
95
0
    if(hp == NULL) return NULL;
96
0
    snprintf(hp, len+1, "%s%s%s", host, port ? ":" : "", port ? port : "");
97
0
    return hp;
98
0
}
99
100
int
101
NC_authsetup(NCauth** authp, NCURI* uri)
102
0
{
103
0
    int ret = NC_NOERR;
104
0
    char* uri_hostport = NULL;
105
0
    NCauth* auth = NULL;
106
0
    struct AWSprofile* ap = NULL;
107
108
0
    if(uri != NULL)
109
0
      uri_hostport = NC_combinehostport(uri);
110
0
    else
111
0
      {ret = NC_EDAP; goto done;}  /* Generic EDAP error. */
112
0
    if((auth=calloc(1,sizeof(NCauth)))==NULL)
113
0
        {ret = NC_ENOMEM; goto done;}
114
115
0
    memcpy(auth, &default_auth, sizeof(default_auth));
116
117
    /* Note, we still must do this function even if
118
       ncrc_getglobalstate()->rc.ignore is set in order
119
       to getinfo e.g. host+port  from url
120
    */
121
122
0
    setauthfield(auth,"HTTP.VERBOSE",
123
0
      NC_rclookup("HTTP.VERBOSE",uri_hostport,uri->path));
124
0
    setauthfield(auth,"HTTP.TIMEOUT",
125
0
      NC_rclookup("HTTP.TIMEOUT",uri_hostport,uri->path));
126
0
    setauthfield(auth,"HTTP.CONNECTTIMEOUT",
127
0
      NC_rclookup("HTTP.CONNECTTIMEOUT",uri_hostport,uri->path));
128
0
    setauthfield(auth,"HTTP.USERAGENT",
129
0
      NC_rclookup("HTTP.USERAGENT",uri_hostport,uri->path));
130
0
    setauthfield(auth,"HTTP.COOKIEFILE",
131
0
      NC_rclookup("HTTP.COOKIEFILE",uri_hostport,uri->path));
132
0
    setauthfield(auth,"HTTP.COOKIE_FILE",
133
0
      NC_rclookup("HTTP.COOKIE_FILE",uri_hostport,uri->path));
134
0
    setauthfield(auth,"HTTP.COOKIEJAR",
135
0
      NC_rclookup("HTTP.COOKIEJAR",uri_hostport,uri->path));
136
0
    setauthfield(auth,"HTTP.COOKIE_JAR",
137
0
      NC_rclookup("HTTP.COOKIE_JAR",uri_hostport,uri->path));
138
0
    setauthfield(auth,"HTTP.PROXY.SERVER",
139
0
      NC_rclookup("HTTP.PROXY.SERVER",uri_hostport,uri->path));
140
0
    setauthfield(auth,"HTTP.PROXY_SERVER",
141
0
      NC_rclookup("HTTP.PROXY_SERVER",uri_hostport,uri->path));
142
0
    setauthfield(auth,"HTTP.SSL.CERTIFICATE",
143
0
      NC_rclookup("HTTP.SSL.CERTIFICATE",uri_hostport,uri->path));
144
0
    setauthfield(auth,"HTTP.SSL.KEY",
145
0
      NC_rclookup("HTTP.SSL.KEY",uri_hostport,uri->path));
146
0
    setauthfield(auth,"HTTP.SSL.KEYPASSWORD",
147
0
      NC_rclookup("HTTP.SSL.KEYPASSWORD",uri_hostport,uri->path));
148
0
    setauthfield(auth,"HTTP.SSL.CAINFO",
149
0
      NC_rclookup("HTTP.SSL.CAINFO",uri_hostport,uri->path));
150
0
    setauthfield(auth,"HTTP.SSL.CAPATH",
151
0
      NC_rclookup("HTTP.SSL.CAPATH",uri_hostport,uri->path));
152
0
    setauthfield(auth,"HTTP.SSL.VERIFYPEER",
153
0
      NC_rclookup("HTTP.SSL.VERIFYPEER",uri_hostport,uri->path));
154
0
    setauthfield(auth,"HTTP.SSL.VERIFYHOST",
155
0
      NC_rclookup("HTTP.SSL.VERIFYHOST",uri_hostport,uri->path));
156
    /* Alias for VERIFYHOST + VERIFYPEER */
157
0
    setauthfield(auth,"HTTP.SSL.VALIDATE",
158
0
      NC_rclookup("HTTP.SSL.VALIDATE",uri_hostport,uri->path));
159
0
    setauthfield(auth,"HTTP.NETRC",
160
0
      NC_rclookup("HTTP.NETRC",uri_hostport,uri->path));
161
162
0
    { /* Handle various cases for user + password */
163
      /* First, see if the user+pwd was in the original url */
164
0
      char* user = NULL;
165
0
      char* pwd = NULL;
166
0
      if(uri->user != NULL && uri->password != NULL) {
167
0
      user = uri->user;
168
0
      pwd = uri->password;
169
0
      } else {
170
0
        user = NC_rclookup("HTTP.CREDENTIALS.USER",uri_hostport,uri->path);
171
0
      pwd = NC_rclookup("HTTP.CREDENTIALS.PASSWORD",uri_hostport,uri->path);
172
0
      }
173
0
      if(user != NULL && pwd != NULL) {
174
0
        user = strdup(user); /* so we can consistently reclaim */
175
0
        pwd = strdup(pwd);
176
0
      } else {
177
      /* Could not get user and pwd, so try USERPASSWORD */
178
0
      const char* userpwd = NC_rclookup("HTTP.CREDENTIALS.USERPASSWORD",uri_hostport,uri->path);
179
0
      if(userpwd != NULL) {
180
0
                if((ret = NC_parsecredentials(userpwd,&user,&pwd))) goto done;
181
0
      }
182
0
      }
183
0
      setauthfield(auth,"HTTP.CREDENTIALS.USERNAME",user);
184
0
      setauthfield(auth,"HTTP.CREDENTIALS.PASSWORD",pwd);
185
0
      nullfree(user);
186
0
      nullfree(pwd);
187
0
    }
188
189
    /* Get the Default profile */
190
0
    if((ret=NC_authgets3profile("no",&ap))) goto done;
191
0
    if(ap == NULL)
192
0
        if((ret=NC_authgets3profile("default",&ap))) goto done;
193
0
    if(ap != NULL)
194
0
        auth->s3profile = strdup(ap->name);
195
0
    else
196
0
        auth->s3profile = NULL;
197
198
0
    if(authp) {*authp = auth; auth = NULL;}
199
0
done:
200
0
    nullfree(uri_hostport);
201
0
    return (ret);
202
0
}
203
204
void
205
NC_authfree(NCauth* auth)
206
0
{
207
0
    if(auth == NULL) return;
208
0
    if(auth->curlflags.cookiejarcreated) {
209
#ifdef _MSC_VER
210
        DeleteFile(auth->curlflags.cookiejar);
211
#else
212
0
        remove(auth->curlflags.cookiejar);
213
0
#endif
214
0
    }
215
0
    nullfree(auth->curlflags.useragent);
216
0
    nullfree(auth->curlflags.cookiejar);
217
0
    nullfree(auth->curlflags.netrc);
218
0
    nullfree(auth->ssl.certificate);
219
0
    nullfree(auth->ssl.key);
220
0
    nullfree(auth->ssl.keypasswd);
221
0
    nullfree(auth->ssl.cainfo);
222
0
    nullfree(auth->ssl.capath);
223
0
    nullfree(auth->proxy.host);
224
0
    nullfree(auth->proxy.user);
225
0
    nullfree(auth->proxy.pwd);
226
0
    nullfree(auth->creds.user);
227
0
    nullfree(auth->creds.pwd);
228
0
    nullfree(auth->s3profile);
229
0
    nullfree(auth);
230
0
}
231
232
/**************************************************/
233
234
0
static int is_numeric(const char * str){
235
0
    if (str == NULL || strlen(str) == 0) {
236
0
        return 0;
237
0
    }
238
239
0
    for (const char *c = str; c < str + strlen(str); c++)
240
0
    {
241
0
        if ( !('0' <= *c  && *c <= '9')) {
242
0
            return 0;
243
0
        }
244
0
    }
245
246
0
    return 1;
247
0
}
248
249
0
static void truthy_to_int(const char* value, int*value_int) {
250
0
    if (value == NULL || value_int == NULL) {
251
0
        return;
252
0
    }
253
0
    if (strcasecmp(value, "False") == 0 || strcasecmp(value, "No") == 0 || strcasecmp(value,"Off")==0)
254
0
    {
255
0
        *value_int = 0;
256
0
    }
257
0
    else if (strcasecmp(value, "True") == 0 || strcasecmp(value, "Yes") == 0 || strcasecmp(value, "On") == 0 )
258
0
    {
259
0
        *value_int = 1;
260
0
    }
261
0
    else if (is_numeric(value))
262
0
    {
263
0
        *value_int = atoi(value);
264
0
    }
265
0
}
266
267
static int
268
setauthfield(NCauth* auth, const char* flag, const char* value)
269
0
{
270
0
    int ret = NC_NOERR;
271
0
    if(value == NULL) goto done;
272
273
0
    int int_value = NCAUTH_DEFAULT_SSL_VERIFY;
274
0
    truthy_to_int(value, &int_value);
275
276
0
    if(strcmp(flag,"HTTP.ENCODE")==0) {
277
0
        if(atoi(value)) {auth->curlflags.encode = 1;} else {auth->curlflags.encode = 0;}
278
0
        DEBUGLOG(NCLOGNOTE,"HTTP.encode: %ld", (long)auth->curlflags.encode);
279
0
    }
280
0
    if(strcmp(flag,"HTTP.VERBOSE")==0) {
281
0
        if(atoi(value)) auth->curlflags.verbose = 1;
282
0
        DEBUGLOG(NCLOGNOTE,"HTTP.VERBOSE: %ld", (long)auth->curlflags.verbose);
283
0
    }
284
0
    if(strcmp(flag,"HTTP.TIMEOUT")==0) {
285
0
        if(atoi(value)) auth->curlflags.timeout = atoi(value);
286
0
        DEBUGLOG(NCLOGNOTE,"HTTP.TIMEOUT: %ld", (long)auth->curlflags.timeout);
287
0
    }
288
0
    if(strcmp(flag,"HTTP.CONNECTTIMEOUT")==0) {
289
0
        if(atoi(value)) auth->curlflags.connecttimeout = atoi(value);
290
0
        DEBUGLOG(NCLOGNOTE,"HTTP.CONNECTTIMEOUT: %ld", (long)auth->curlflags.connecttimeout);
291
0
    }
292
0
    if(strcmp(flag,"HTTP.USERAGENT")==0) {
293
0
        if(atoi(value)) auth->curlflags.useragent = strdup(value);
294
0
        MEMCHECK(auth->curlflags.useragent);
295
0
        DEBUGLOG(NCLOGNOTE,"HTTP.USERAGENT: %s", auth->curlflags.useragent);
296
0
    }
297
0
    if(
298
0
  strcmp(flag,"HTTP.COOKIEFILE")==0
299
0
        || strcmp(flag,"HTTP.COOKIE_FILE")==0
300
0
        || strcmp(flag,"HTTP.COOKIEJAR")==0
301
0
        || strcmp(flag,"HTTP.COOKIE_JAR")==0
302
0
      ) {
303
0
  nullfree(auth->curlflags.cookiejar);
304
0
        auth->curlflags.cookiejar = strdup(value);
305
0
        MEMCHECK(auth->curlflags.cookiejar);
306
0
        DEBUGLOG(NCLOGNOTE,"HTTP.COOKIEJAR: %s", auth->curlflags.cookiejar);
307
0
    }
308
0
    if(strcmp(flag,"HTTP.PROXY.SERVER")==0 || strcmp(flag,"HTTP.PROXY_SERVER")==0) {
309
0
        ret = NC_parseproxy(auth,value);
310
0
        if(ret != NC_NOERR) goto done;
311
0
        DEBUGLOG(NCLOGNOTE,"HTTP.PROXY.SERVER: %s", value);
312
0
    }
313
0
    if(strcmp(flag,"HTTP.SSL.VERIFYPEER")==0) {
314
0
        if (NCAUTH_DEFAULT_SSL_VERIFY == int_value) {
315
0
            nclog(NCLOGWARN, "RC-File key \"HTTP.SSL.VERIFYPEER\" contains invalid value! Ignoring it.");
316
0
            ret = NC_ERCFILE;
317
0
        }
318
0
      auth->ssl.verifypeer = int_value;
319
0
        DEBUGLOG(NCLOGNOTE,"HTTP.SSL.VERIFYPEER: %d", int_value);
320
0
    }
321
0
    if(strcmp(flag,"HTTP.SSL.VERIFYHOST")==0) {
322
0
        if (NCAUTH_DEFAULT_SSL_VERIFY == int_value) {
323
0
            nclog(NCLOGWARN, "RC-File key \"HTTP.SSL.VERIFYHOST\" contains invalid value! Ignoring it.");
324
0
            ret = NC_ERCFILE;
325
0
        }
326
0
      auth->ssl.verifyhost = int_value;
327
0
        DEBUGLOG(NCLOGNOTE,"HTTP.SSL.VERIFYHOST: %d", int_value);
328
0
    }
329
0
    if(strcmp(flag,"HTTP.SSL.VALIDATE")==0) {
330
0
        switch (int_value) {
331
0
            case NCAUTH_DEFAULT_SSL_VERIFY: //default
332
0
                nclog(NCLOGWARN, "RC-File Key \"HTTP.SSL.VALIDATE\" contains invalid value! Ignoring it.");
333
0
                auth->ssl.verifypeer = NCAUTH_DEFAULT_SSL_VERIFY;
334
0
                auth->ssl.verifyhost = NCAUTH_DEFAULT_SSL_VERIFY;
335
0
                ret = NC_ERCFILE;
336
0
                break;
337
0
            case 0:
338
0
                auth->ssl.verifypeer = 0;
339
0
                auth->ssl.verifyhost = 0;
340
0
                break;
341
0
            default:
342
0
                auth->ssl.verifypeer = 1;
343
0
                auth->ssl.verifyhost = 2;
344
0
                break;
345
0
        }
346
0
    }
347
348
0
    if(strcmp(flag,"HTTP.SSL.CERTIFICATE")==0) {
349
0
  nullfree(auth->ssl.certificate);
350
0
        auth->ssl.certificate = strdup(value);
351
0
        MEMCHECK(auth->ssl.certificate);
352
0
        DEBUGLOG(NCLOGNOTE,"HTTP.SSL.CERTIFICATE: %s", auth->ssl.certificate);
353
0
    }
354
355
0
    if(strcmp(flag,"HTTP.SSL.KEY")==0) {
356
0
  nullfree(auth->ssl.key);
357
0
        auth->ssl.key = strdup(value);
358
0
        MEMCHECK(auth->ssl.key);
359
0
        DEBUGLOG(NCLOGNOTE,"HTTP.SSL.KEY: %s", auth->ssl.key);
360
0
    }
361
362
0
    if(strcmp(flag,"HTTP.SSL.KEYPASSWORD")==0) {
363
0
  nullfree(auth->ssl.keypasswd) ;
364
0
        auth->ssl.keypasswd = strdup(value);
365
0
        MEMCHECK(auth->ssl.keypasswd);
366
0
        DEBUGLOG(NCLOGNOTE,"HTTP.SSL.KEYPASSWORD: %s", auth->ssl.keypasswd);
367
0
    }
368
369
0
    if(strcmp(flag,"HTTP.SSL.CAINFO")==0) {
370
0
  nullfree(auth->ssl.cainfo) ;
371
0
        auth->ssl.cainfo = strdup(value);
372
0
        MEMCHECK(auth->ssl.cainfo);
373
0
        DEBUGLOG(NCLOGNOTE,"HTTP.SSL.CAINFO: %s", auth->ssl.cainfo);
374
0
    }
375
376
0
    if(strcmp(flag,"HTTP.SSL.CAPATH")==0) {
377
0
  nullfree(auth->ssl.capath) ;
378
0
        auth->ssl.capath = strdup(value);
379
0
        MEMCHECK(auth->ssl.capath);
380
0
        DEBUGLOG(NCLOGNOTE,"HTTP.SSL.CAPATH: %s", auth->ssl.capath);
381
0
    }
382
0
    if(strcmp(flag,"HTTP.NETRC")==0) {
383
0
        nullfree(auth->curlflags.netrc);
384
0
        auth->curlflags.netrc = strdup(value);
385
0
        MEMCHECK(auth->curlflags.netrc);
386
0
        DEBUGLOG(NCLOGNOTE,"HTTP.NETRC: %s", auth->curlflags.netrc);
387
0
    }
388
389
0
    if(strcmp(flag,"HTTP.CREDENTIALS.USERNAME")==0) {
390
0
        nullfree(auth->creds.user);
391
0
        auth->creds.user = strdup(value);
392
0
        MEMCHECK(auth->creds.user);
393
0
    }
394
0
    if(strcmp(flag,"HTTP.CREDENTIALS.PASSWORD")==0) {
395
0
        nullfree(auth->creds.pwd);
396
0
        auth->creds.pwd = strdup(value);
397
0
        MEMCHECK(auth->creds.pwd);
398
0
    }
399
400
0
done:
401
0
    return (ret);
402
403
0
nomem:
404
0
    return (NC_ENOMEM);
405
0
}
406
407
/*
408
Given form user:pwd, parse into user and pwd
409
and do %xx unescaping
410
*/
411
int
412
NC_parsecredentials(const char* userpwd, char** userp, char** pwdp)
413
0
{
414
0
  char* user = NULL;
415
0
  char* pwd = NULL;
416
417
0
  if(userpwd == NULL)
418
0
  return NC_EINVAL;
419
0
  user = strdup(userpwd);
420
0
  if(user == NULL)
421
0
  return NC_ENOMEM;
422
0
  pwd = strchr(user,':');
423
0
  if(pwd == NULL) {
424
0
    free(user);
425
0
  return NC_EINVAL;
426
0
  }
427
0
  *pwd = '\0';
428
0
  pwd++;
429
0
  if(userp)
430
0
  *userp = ncuridecode(user);
431
0
  if(pwdp)
432
0
  *pwdp = ncuridecode(pwd);
433
0
  free(user);
434
0
  return NC_NOERR;
435
0
}