diff options
Diffstat (limited to 'auth.c')
-rw-r--r-- | auth.c | 235 |
1 files changed, 235 insertions, 0 deletions
@@ -0,0 +1,235 @@ +#include "links.h" + +static struct list_head auth = {&auth, &auth}; + +struct http_auth { + struct http_auth *next; + struct http_auth *prev; + unsigned char *host; + int port; + unsigned char *realm; + unsigned char *user; + unsigned char *password; + unsigned char *directory; + unsigned char *user_password_encoded; + int proxy; +}; + +static unsigned char base64_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static unsigned char *base64_encode(unsigned char *in) +{ + unsigned char *out, *outstr; + size_t inlen = strlen(in); + if (inlen > MAXINT / 4) overalloc(); + outstr = out = mem_alloc(((inlen / 3) + 1) * 4 + 1 ); + while (inlen >= 3) { + *out++ = base64_chars[ (int)(*in >> 2) ]; + *out++ = base64_chars[ (int)((*in << 4 | *(in + 1) >> 4) & 63) ]; + *out++ = base64_chars[ (int)((*(in + 1) << 2 | *(in + 2) >> 6) & 63) ]; + *out++ = base64_chars[ (int)(*(in + 2) & 63) ]; + inlen -= 3; in += 3; + } + if (inlen == 1) { + *out++ = base64_chars[ (int)(*in >> 2) ]; + *out++ = base64_chars[ (int)(*in << 4 & 63) ]; + *out++ = '='; + *out++ = '='; + } + if (inlen == 2) { + *out++ = base64_chars[ (int)(*in >> 2) ]; + *out++ = base64_chars[ (int)((*in << 4 | *(in + 1) >> 4) & 63) ]; + *out++ = base64_chars[ (int)((*(in + 1) << 2) & 63) ]; + *out++ = '='; + } + *out = 0; + return outstr; +} + +static unsigned char *basic_encode(unsigned char *user, unsigned char *password) +{ + unsigned char *e, *p = mem_alloc(strlen(user) + strlen(password) + 2); + strcpy(p, user); + strcat(p, ":"); + strcat(p, password); + e = base64_encode(p); + mem_free(p); + return e; +} + +unsigned char *get_auth_realm(unsigned char *url, unsigned char *head, int proxy) +{ + unsigned char *ch = head; + unsigned char *h, *q, *r; + int l; + int unknown = 0; + int known = 0; + try_next: + h = parse_http_header(ch, !proxy ? "WWW-Authenticate" : "Proxy-Authenticate", &ch); + if (!h) { + if (unknown && !known) return NULL; + if (proxy) return stracpy(proxies.http_proxy); + h = get_host_name(url); + if (h) return h; + return stracpy(""); + } + if (casecmp(h, "Basic", 5)) { + mem_free(h); + unknown = 1; + goto try_next; + } + known = 1; + q = strchr(h, '"'); + if (!q) { + mem_free(h); + goto try_next; + } + q++; + r = init_str(); + l = 0; + while (*q && *q != '"') { + if (*q == '\\' && !*++q) break; + add_chr_to_str(&r, &l, *q++); + } + mem_free(h); + return r; +} + +unsigned char *get_auth_string(unsigned char *url) +{ + struct http_auth *a; + unsigned char *host; + int port; + unsigned char *r = NULL; + int l = 0; + unsigned char *user, *password; + if (!(host = get_host_name(url))) return NULL; + port = get_port(url); + if (upcase(url[0]) == 'P') { + foreach(a, auth) { + if (a->proxy && !strcasecmp(a->host, host) && a->port == port) { + if (!r) r = init_str(); + add_to_str(&r, &l, "Proxy-Authorization: Basic "); + add_to_str(&r, &l, a->user_password_encoded); + add_to_str(&r, &l, "\r\n"); + break; + } + } + url = get_url_data(url); + mem_free(host); + if (!(host = get_host_name(url))) return NULL; + port = get_port(url); + } + + user = get_user_name(url); + password = get_pass(url); + if (user && *user && password) { + unsigned char *e = basic_encode(user, password); + if (!r) r = init_str(); + add_to_str(&r, &l, "Authorization: Basic "); + add_to_str(&r, &l, e); + add_to_str(&r, &l, "\r\n"); + mem_free(e); + if (user) mem_free(user); + if (password) mem_free(password); + goto have_passwd; + } + if (user) mem_free(user); + if (password) mem_free(password); + + foreach(a, auth) if (!a->proxy && !strcasecmp(a->host, host) && a->port == port) { + unsigned char *d, *data; + data = get_url_data(url); + d = strrchr(data, '/'); + if (!d) d = data; + else d++; + if ((size_t)(d - data) >= strlen(a->directory) && !memcmp(data, a->directory, strlen(a->directory))) { + if (!r) r = init_str(); + add_to_str(&r, &l, "Authorization: Basic "); + add_to_str(&r, &l, a->user_password_encoded); + add_to_str(&r, &l, "\r\n"); + goto have_passwd; + } + } + have_passwd: + mem_free(host); + return r; +} + +static void free_auth_entry(struct http_auth *a) +{ + mem_free(a->host); + mem_free(a->realm); + mem_free(a->user); + mem_free(a->password); + if (a->directory) mem_free(a->directory); + mem_free(a->user_password_encoded); + del_from_list(a); + mem_free(a); +} + +void cleanup_auth(void) +{ + while (!list_empty(auth)) free_auth_entry(auth.next); +} + +void add_auth(unsigned char *url, unsigned char *realm, unsigned char *user, unsigned char *password, int proxy) +{ + struct http_auth *a; + unsigned char *host; + int port; + if (!proxy) { + host = get_host_name(url); + port = get_port(url); + } else { + unsigned char *p = get_proxy(url); + host = get_host_name(p); + port = get_port(p); + mem_free(p); + } + if (!host) return; + foreach(a, auth) if (a->proxy == proxy && !strcasecmp(a->host, host) && a->port == port && !strcmp(a->realm, realm)) { + a = a->prev; + free_auth_entry(a->next); + } + a = mem_alloc(sizeof(struct http_auth)); + a->host = host; + a->port = port; + a->realm = stracpy(realm); + a->user = stracpy(user); + a->password = stracpy(password); + if (!proxy) { + unsigned char *data = stracpy(get_url_data(url)); + unsigned char *d = strrchr(data, '/'); + if (d) d[1] = 0; + else data[0] = 0; + a->directory = data; + } else a->directory = NULL; + a->proxy = proxy; + a->user_password_encoded = basic_encode(a->user, a->password); + add_to_list(auth, a); +} + +int find_auth(unsigned char *url, unsigned char *realm) +{ + struct http_auth *a; + unsigned char *data, *d; + unsigned char *host = get_host_name(url); + int port = get_port(url); + if (!host) return -1; + data = stracpy(get_url_data(url)); + d = strrchr(data, '/'); + if (d) d[1] = 0; + foreach(a, auth) if (!a->proxy && !strcasecmp(a->host, host) && a->port == port && !strcmp(a->realm, realm) && strcmp(a->directory, data)) { + mem_free(a->directory); + a->directory = data; + mem_free(host); + del_from_list(a); + add_to_list(auth, a); + return 0; + } + mem_free(host); + mem_free(data); + return -1; +} + |