diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2020-02-26 17:43:56 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2020-02-27 17:40:57 +0200 |
commit | 9b546466f4e0f34a63e5f49c752dffea3ef9a47a (patch) | |
tree | c22c12030250c22e76bf3c4c3cfcfb2a51b614c0 /src | |
parent | 3b2d57c14f1ed207c79362b7136e3da4054ad817 (diff) | |
download | ping903-9b546466f4e0f34a63e5f49c752dffea3ef9a47a.tar.gz ping903-9b546466f4e0f34a63e5f49c752dffea3ef9a47a.tar.bz2 |
ping903q: optionally supply credentials in the command line
New command line option -R supplies the authentication realm for
ping903q. If given, the credentials for that realm will be looked
up on startup and sent with each HTTP request. This allows the program
to avoid sending an extra HTTP request.
* src/ping903q.c (get_auth_creds): Split into two functions:
get_auth_creds and get_realm_creds.
(http_query): Don't attemt send lookup for authorization credentials.
(main): New option -R (authentication realm). Look up credentials for
that realm if given.
Diffstat (limited to 'src')
-rw-r--r-- | src/ping903q.c | 152 |
1 files changed, 100 insertions, 52 deletions
diff --git a/src/ping903q.c b/src/ping903q.c index 85388f8..a9024c7 100644 --- a/src/ping903q.c +++ b/src/ping903q.c @@ -385,9 +385,13 @@ http_query_primitive(char const *meth, char const *url, char **hdr) static char *std_headers[] = { "Accept: application/json", "User-Agent: ping903q (" PACKAGE_STRING ")", - NULL + NULL, + NULL, }; +/* Place where to insert the Authorization header to std_headers */ +#define AUTH_HDR_IDX 2 + #define BASICPREF "Basic realm=\"" #define BASICLEN (sizeof(BASICPREF)-1) @@ -478,10 +482,13 @@ machinecmp(char const *pat) return strcmp(pat, service); } +#define HTTP_AUTHORIZATION "Authorization: Basic " +#define HTTP_AUTHORIZATION_LEN (sizeof(HTTP_AUTHORIZATION)-1) + static int -get_auth_creds(char const *auth, char **retval) +get_realm_creds(char const *realm, char **retval) { - char *realm, *p; + char *p; size_t len; char const *cfname; FILE *fp; @@ -489,32 +496,11 @@ get_auth_creds(char const *auth, char **retval) int ln = 0; int skip_to_eol = 0; int ret; - int i; - if (!auth || strncmp(auth, BASICPREF, BASICLEN)) - return -1; - auth += BASICLEN; - len = strlen(auth); - if (len == 0 || auth[len-1] != '"') - return -1; - len--; - if (auth[len-1] == '\\') - return -1; - realm = emalloc(len + 1); - memcpy(realm, auth, len); - for (i = 0; i < len; ) { - if (*auth == '\\') - auth++; - realm[i++] = *auth++; - } - realm[i] = 0; - cfname = get_cred_file_name(); fp = fopen(cfname, "r"); - if (!fp) { - free(realm); + if (!fp) return -1; - } ret = -1; while (fgets(buf, sizeof(buf), fp)) { @@ -577,11 +563,33 @@ get_auth_creds(char const *auth, char **retval) && (strcmp(av[1], "*") == 0 || strcmp(av[1], realm) == 0)) { len = strlen(av[2]) + strlen(av[3]) + 2; - char *p = emalloc(len); - strcpy(p, av[2]); - strcat(p, ":"); - strcat(p, av[3]); - *retval = p; + char *plaintext; + char *b64; + size_t b64_len; + char *hdr; + + /* Create plaintext auth string */ + plaintext = emalloc(len); + strcpy(plaintext, av[2]); + strcat(plaintext, ":"); + strcat(plaintext, av[3]); + + /* Encode it to base64 */ + if (base64_encode(plaintext, len, &b64, &b64_len)) + emalloc_die(); + + free(plaintext); + + /* Create Authorization header */ + hdr = emalloc(HTTP_AUTHORIZATION_LEN + + b64_len + + 1); + strcpy(hdr, HTTP_AUTHORIZATION); + strcat(hdr, b64); + free(b64); + + /* Return it */ + *retval = hdr; ret = 0; argcv_free(ac, av); break; @@ -591,12 +599,52 @@ get_auth_creds(char const *auth, char **retval) } err: fclose(fp); - free(realm); return ret; } -#define HTTP_AUTHORIZATION "Authorization: Basic " -#define HTTP_AUTHORIZATION_LEN (sizeof(HTTP_AUTHORIZATION)-1) +static int +get_auth_creds(char const *auth, char **retval) +{ + char *realm; + size_t len; + int rc; + int i; + + if (!auth || strncmp(auth, BASICPREF, BASICLEN)) + return -1; + auth += BASICLEN; + len = strlen(auth); + if (len == 0 || auth[len-1] != '"') + return -1; + len--; + if (auth[len-1] == '\\') + return -1; + realm = emalloc(len + 1); + memcpy(realm, auth, len); + for (i = 0; i < len; ) { + if (*auth == '\\') + auth++; + realm[i++] = *auth++; + } + realm[i] = 0; + + rc = get_realm_creds(realm, retval); + free(realm); + return rc; +} + +static int +has_authorization(char **hdr) +{ + size_t i; + if (!hdr) + return 0; + for (i = 0; hdr[i]; i++) + if (strncmp(hdr[i], HTTP_AUTHORIZATION, + HTTP_AUTHORIZATION_LEN) == 0) + return 1; + return 0; +} static void http_query(char const *meth, char const *url, char **hdr, @@ -605,17 +653,14 @@ http_query(char const *meth, char const *url, char **hdr, http_query_primitive(meth, url, hdr); http_recv(resp); if (resp->code != 200) { - if (resp->code == 401) { + if (resp->code == 401 && !has_authorization(hdr)) { char *creds; char const *auth = http_resp_get_header(resp, "WWW-Authenticate"); if (get_auth_creds(auth, &creds) == 0) { - char *b64creds; - size_t b64creds_len; char **new_hdr; size_t i, nhdr; - char *auth_hdr; for (nhdr = 0; hdr[nhdr]; nhdr++) ; @@ -623,26 +668,14 @@ http_query(char const *meth, char const *url, char **hdr, sizeof(new_hdr[0])); for (i = 0; i < nhdr; i++) new_hdr[i] = hdr[i]; - - if (base64_encode(creds, strlen(creds), - &b64creds, &b64creds_len)) - emalloc_die(); - free(creds); - - auth_hdr = emalloc(HTTP_AUTHORIZATION_LEN - + b64creds_len - + 1); - strcpy(auth_hdr, HTTP_AUTHORIZATION); - strcat(auth_hdr, b64creds); - free(b64creds); - new_hdr[i] = auth_hdr; + new_hdr[i] = creds; new_hdr[i+1] = NULL; http_query_primitive(meth, url, new_hdr); http_recv(resp); free(new_hdr); - free(auth_hdr); + free(creds); } } } @@ -997,6 +1030,7 @@ usage(void) printf("Options:\n\n"); printf(" -f FILE read configuration from FILE\n"); printf(" -h print this help test\n"); + printf(" -R REALM use credentials for this authentication realm\n"); printf(" -r resolve HOST to IP address\n"); printf(" -V print program version and exit\n"); printf(" -v additional verbosity\n"); @@ -1045,6 +1079,7 @@ main(int argc, char **argv) char const *host = NULL; char *c_opt = NULL; char *w_opt = NULL; + char *realm = NULL; struct nagios_check_data chkdata; set_progname(argv[0]); @@ -1059,7 +1094,7 @@ main(int argc, char **argv) exit(0); } } - while ((c = getopt(argc, argv, "c:f:H:hmp:rVvw:")) != EOF) { + while ((c = getopt(argc, argv, "c:f:H:hmp:R:rVvw:")) != EOF) { switch (c) { case 'c': c_opt = optarg; @@ -1081,6 +1116,9 @@ main(int argc, char **argv) case 'p': nagios_prefix_format = optarg; break; + case 'R': + realm = optarg; + break; case 'r': resolve_ip = 1; break; @@ -1132,6 +1170,16 @@ main(int argc, char **argv) http_connect(nodename, service); free(p); + if (realm) { + char *auth_hdr; + if (get_realm_creds(realm, &auth_hdr) == 0) { + std_headers[AUTH_HDR_IDX] = auth_hdr; + } else + error("can't find credentials for realm %s at %s:%s", + realm, nodename, service); + } + + switch (mode) { case MODE_DEFAULT: switch (argc) { |