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 }