links

lynx-like text mode web browser
git clone anongit@rnpnr.xyz:links.git
Log | Files | Refs | Feed | README | LICENSE

auth.c (6948B)


      1 #include <limits.h>
      2 
      3 #include "links.h"
      4 
      5 static struct list_head auth = { &auth, &auth };
      6 
      7 struct http_auth {
      8 	list_entry_1st;
      9 	unsigned char *host;
     10 	int port;
     11 	unsigned char *realm;
     12 	unsigned char *user;
     13 	unsigned char *password;
     14 	unsigned char *directory;
     15 	unsigned char *user_password_encoded;
     16 	int proxy;
     17 };
     18 
     19 static const unsigned char base64_chars[] =
     20     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     21 
     22 static unsigned char *
     23 base64_encode(unsigned char *in, size_t inlen)
     24 {
     25 	unsigned char *out, *outstr;
     26 	size_t data_len;
     27 	int line_mask = ~0;
     28 	int col;
     29 	if (inlen > INT_MAX / 2)
     30 		overalloc();
     31 	data_len = ((inlen + 2) / 3) * 4;
     32 	out = outstr = xmalloc(data_len + 1);
     33 	col = 0;
     34 	while (inlen >= 3) {
     35 		*out++ = base64_chars[(int)(in[0] >> 2)];
     36 		*out++ = base64_chars[(int)((in[0] << 4 | in[1] >> 4) & 63)];
     37 		*out++ = base64_chars[(int)((in[1] << 2 | in[2] >> 6) & 63)];
     38 		*out++ = base64_chars[(int)(in[2] & 63)];
     39 		inlen -= 3;
     40 		in += 3;
     41 		if (!((col += 4) & line_mask))
     42 			*out++ = '\n';
     43 	}
     44 	switch (inlen) {
     45 	case 1:
     46 		*out++ = base64_chars[(int)(in[0] >> 2)];
     47 		*out++ = base64_chars[(int)(in[0] << 4 & 63)];
     48 		*out++ = '=';
     49 		*out++ = '=';
     50 		break;
     51 	case 2:
     52 		*out++ = base64_chars[(int)(in[0] >> 2)];
     53 		*out++ = base64_chars[(int)((in[0] << 4 | in[1] >> 4) & 63)];
     54 		*out++ = base64_chars[(int)((in[1] << 2) & 63)];
     55 		*out++ = '=';
     56 	default:;
     57 	}
     58 	strlcpy((char *)out, "", 2);
     59 	return outstr;
     60 }
     61 
     62 static unsigned char *
     63 basic_encode(unsigned char *user, unsigned char *password)
     64 {
     65 	unsigned char *e, *p;
     66 	p = stracpy(user);
     67 	add_to_strn(&p, cast_uchar ":");
     68 	add_to_strn(&p, password);
     69 	e = base64_encode(p, strlen(cast_const_char p));
     70 	free(p);
     71 	return e;
     72 }
     73 
     74 unsigned char *
     75 get_auth_realm(unsigned char *url, unsigned char *head, int proxy)
     76 {
     77 	unsigned char *ch = head;
     78 	unsigned char *h, *q, *r;
     79 	int l;
     80 	int unknown = 0;
     81 	int known = 0;
     82 try_next:
     83 	h = parse_http_header(ch,
     84 	                      !proxy ? (unsigned char *)"WWW-Authenticate"
     85 	                             : (unsigned char *)"Proxy-Authenticate",
     86 	                      &ch);
     87 	if (!h) {
     88 		if (unknown && !known)
     89 			return NULL;
     90 		if (proxy) {
     91 			unsigned char *p = get_proxy_string(url);
     92 			if (!p)
     93 				p = cast_uchar "";
     94 			return stracpy(p);
     95 		} else {
     96 			unsigned char *u = get_host_name(url);
     97 			if (u)
     98 				return u;
     99 			return stracpy(cast_uchar "");
    100 		}
    101 	}
    102 	if (casecmp(h, cast_uchar "Basic", 5)) {
    103 		free(h);
    104 		unknown = 1;
    105 		goto try_next;
    106 	}
    107 	known = 1;
    108 	q = cast_uchar strchr(cast_const_char h, '"');
    109 	if (!q) {
    110 		free(h);
    111 		goto try_next;
    112 	}
    113 	q++;
    114 	r = NULL;
    115 	l = 0;
    116 	while (*q && *q != '"') {
    117 		if (*q == '\\' && !*++q)
    118 			break;
    119 		l = add_chr_to_str(&r, l, *q++);
    120 	}
    121 	free(h);
    122 	return r;
    123 }
    124 
    125 static unsigned char *
    126 auth_from_url(unsigned char *url, int proxy)
    127 {
    128 	unsigned char *r = NULL;
    129 	size_t l = 0;
    130 	unsigned char *user, *password;
    131 
    132 	user = get_user_name(url);
    133 	password = get_pass(url);
    134 	if (user && *user && password) {
    135 		unsigned char *e = basic_encode(user, password);
    136 		r = NULL;
    137 		if (proxy)
    138 			l = add_to_str(&r, l, cast_uchar "Proxy-");
    139 		l = add_to_str(&r, l, cast_uchar "Authorization: Basic ");
    140 		l = add_to_str(&r, l, e);
    141 		l = add_to_str(&r, l, cast_uchar "\r\n");
    142 		free(e);
    143 		free(user);
    144 		free(password);
    145 		return r;
    146 	}
    147 	free(user);
    148 	free(password);
    149 	return NULL;
    150 }
    151 
    152 unsigned char *
    153 get_auth_string(unsigned char *url, int proxy)
    154 {
    155 	struct http_auth *a = NULL;
    156 	struct list_head *la;
    157 	unsigned char *host;
    158 	int port;
    159 	unsigned char *r = NULL;
    160 	size_t l = 0;
    161 	if (proxy && !is_proxy_url(url))
    162 		return NULL;
    163 	if (!(host = get_host_name(url)))
    164 		return NULL;
    165 	port = get_port(url);
    166 
    167 	if (!proxy && (r = auth_from_url(url, proxy)))
    168 		goto have_passwd;
    169 
    170 	foreach (struct http_auth, a, la, auth)
    171 		if (a->proxy == proxy && !casestrcmp(a->host, host)
    172 		    && a->port == port) {
    173 			unsigned char *d, *data;
    174 			if (proxy)
    175 				goto skip_dir_check;
    176 			data = get_url_data(url);
    177 			d = cast_uchar strrchr(cast_const_char data, '/');
    178 			if (!d)
    179 				d = data;
    180 			else
    181 				d++;
    182 			if ((size_t)(d - data)
    183 			        >= strlen(cast_const_char a->directory)
    184 			    && !memcmp(data, a->directory,
    185 			               strlen(cast_const_char a->directory))) {
    186 skip_dir_check:
    187 				r = NULL;
    188 				if (proxy)
    189 					l = add_to_str(&r, l,
    190 					               cast_uchar "Proxy-");
    191 				l = add_to_str(
    192 				    &r, l, cast_uchar "Authorization: Basic ");
    193 				l = add_to_str(&r, l, a->user_password_encoded);
    194 				l = add_to_str(&r, l, cast_uchar "\r\n");
    195 				goto have_passwd;
    196 			}
    197 		}
    198 
    199 	if (proxy && (r = auth_from_url(url, proxy)))
    200 		goto have_passwd;
    201 
    202 have_passwd:
    203 	free(host);
    204 	return r;
    205 }
    206 
    207 static void
    208 free_auth_entry(struct http_auth *a)
    209 {
    210 	free(a->host);
    211 	free(a->realm);
    212 	free(a->user);
    213 	free(a->password);
    214 	free(a->directory);
    215 	free(a->user_password_encoded);
    216 	del_from_list(a);
    217 	free(a);
    218 }
    219 
    220 void
    221 free_auth(void)
    222 {
    223 	while (!list_empty(auth))
    224 		free_auth_entry(list_struct(auth.next, struct http_auth));
    225 }
    226 
    227 void
    228 add_auth(unsigned char *url, unsigned char *realm, unsigned char *user,
    229          unsigned char *password, int proxy)
    230 {
    231 	struct http_auth *a = NULL;
    232 	struct list_head *la;
    233 	unsigned char *host = NULL;
    234 	int port = 0 /* against warning */;
    235 	if (!proxy) {
    236 		host = get_host_name(url);
    237 		port = get_port(url);
    238 	} else {
    239 		unsigned char *p = get_proxy(url);
    240 		if (strcmp(cast_const_char p, cast_const_char url)) {
    241 			host = get_host_name(p);
    242 			port = get_port(p);
    243 		}
    244 		free(p);
    245 	}
    246 	if (!host)
    247 		return;
    248 	foreach (struct http_auth, a, la, auth)
    249 		if (a->proxy == proxy && !casestrcmp(a->host, host)
    250 		    && a->port == port
    251 		    && !strcmp(cast_const_char a->realm,
    252 		               cast_const_char realm)) {
    253 			la = la->prev;
    254 			free_auth_entry(a);
    255 		}
    256 	a = xmalloc(sizeof(struct http_auth));
    257 	a->host = host;
    258 	a->port = port;
    259 	a->realm = stracpy(realm);
    260 	a->user = stracpy(user);
    261 	a->password = stracpy(password);
    262 	if (!proxy) {
    263 		unsigned char *data = stracpy(get_url_data(url));
    264 		unsigned char *d =
    265 		    cast_uchar strrchr(cast_const_char data, '/');
    266 		if (d)
    267 			d[1] = 0;
    268 		else
    269 			data[0] = 0;
    270 		a->directory = data;
    271 	} else
    272 		a->directory = NULL;
    273 	a->proxy = proxy;
    274 	a->user_password_encoded = basic_encode(a->user, a->password);
    275 	add_to_list(auth, a);
    276 }
    277 
    278 int
    279 find_auth(unsigned char *url, unsigned char *realm)
    280 {
    281 	struct http_auth *a = NULL;
    282 	struct list_head *la;
    283 	unsigned char *data, *d;
    284 	unsigned char *host = get_host_name(url);
    285 	int port = get_port(url);
    286 	if (!host)
    287 		return -1;
    288 	data = stracpy(get_url_data(url));
    289 	d = cast_uchar strrchr(cast_const_char data, '/');
    290 	if (d)
    291 		d[1] = 0;
    292 	foreach (struct http_auth, a, la, auth)
    293 		if (!a->proxy && !casestrcmp(a->host, host) && a->port == port
    294 		    && !strcmp(cast_const_char a->realm, cast_const_char realm)
    295 		    && strcmp(cast_const_char a->directory,
    296 		              cast_const_char data)) {
    297 			free(a->directory);
    298 			a->directory = data;
    299 			free(host);
    300 			del_from_list(a);
    301 			add_to_list(auth, a);
    302 			return 0;
    303 		}
    304 	free(host);
    305 	free(data);
    306 	return -1;
    307 }