diff options
author | djm <> | 2006-01-25 23:21:37 +0000 |
---|---|---|
committer | djm <> | 2006-01-25 23:21:37 +0000 |
commit | 9a4d7f3f204beeffd203f2d34f204cc19d7321e4 (patch) | |
tree | 35b595e90f1ecf05250205412afa830537e2371f /src/usr.bin/nc/socks.c | |
parent | f9006c0d860615bd798c2a8b553ba592ec3b4524 (diff) | |
download | openbsd-9a4d7f3f204beeffd203f2d34f204cc19d7321e4.tar.gz openbsd-9a4d7f3f204beeffd203f2d34f204cc19d7321e4.tar.bz2 openbsd-9a4d7f3f204beeffd203f2d34f204cc19d7321e4.zip |
implement HTTP proxy authentication support, very useful in a ssh_config
ProxyCommand; ok beck@
Diffstat (limited to 'src/usr.bin/nc/socks.c')
-rw-r--r-- | src/usr.bin/nc/socks.c | 89 |
1 files changed, 72 insertions, 17 deletions
diff --git a/src/usr.bin/nc/socks.c b/src/usr.bin/nc/socks.c index de61439400..daed99712e 100644 --- a/src/usr.bin/nc/socks.c +++ b/src/usr.bin/nc/socks.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: socks.c,v 1.15 2005/05/24 20:13:28 avsm Exp $ */ | 1 | /* $OpenBSD: socks.c,v 1.16 2006/01/25 23:21:37 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 1999 Niklas Hallqvist. All rights reserved. | 4 | * Copyright (c) 1999 Niklas Hallqvist. All rights reserved. |
@@ -37,6 +37,8 @@ | |||
37 | #include <stdlib.h> | 37 | #include <stdlib.h> |
38 | #include <string.h> | 38 | #include <string.h> |
39 | #include <unistd.h> | 39 | #include <unistd.h> |
40 | #include <resolv.h> | ||
41 | #include <readpassphrase.h> | ||
40 | #include "atomicio.h" | 42 | #include "atomicio.h" |
41 | 43 | ||
42 | #define SOCKS_PORT "1080" | 44 | #define SOCKS_PORT "1080" |
@@ -52,9 +54,9 @@ | |||
52 | #define SOCKS_IPV6 4 | 54 | #define SOCKS_IPV6 4 |
53 | 55 | ||
54 | int remote_connect(const char *, const char *, struct addrinfo); | 56 | int remote_connect(const char *, const char *, struct addrinfo); |
55 | int socks_connect(const char *host, const char *port, struct addrinfo hints, | 57 | int socks_connect(const char *, const char *, struct addrinfo, |
56 | const char *proxyhost, const char *proxyport, struct addrinfo proxyhints, | 58 | const char *, const char *, struct addrinfo, int, |
57 | int socksv); | 59 | const char *); |
58 | 60 | ||
59 | static int | 61 | static int |
60 | decode_addrport(const char *h, const char *p, struct sockaddr *addr, | 62 | decode_addrport(const char *h, const char *p, struct sockaddr *addr, |
@@ -107,13 +109,26 @@ proxy_read_line(int fd, char *buf, size_t bufsz) | |||
107 | return (off); | 109 | return (off); |
108 | } | 110 | } |
109 | 111 | ||
112 | static const char * | ||
113 | getproxypass(const char *proxyuser, const char *proxyhost) | ||
114 | { | ||
115 | char prompt[512]; | ||
116 | static char pw[256]; | ||
117 | |||
118 | snprintf(prompt, sizeof(prompt), "Proxy password for %s@%s: ", | ||
119 | proxyuser, proxyhost); | ||
120 | if (readpassphrase(prompt, pw, sizeof(pw), RPP_REQUIRE_TTY) == NULL) | ||
121 | errx(1, "Unable to read proxy passphrase"); | ||
122 | return (pw); | ||
123 | } | ||
124 | |||
110 | int | 125 | int |
111 | socks_connect(const char *host, const char *port, | 126 | socks_connect(const char *host, const char *port, |
112 | struct addrinfo hints __attribute__ ((__unused__)), | 127 | struct addrinfo hints __attribute__ ((__unused__)), |
113 | const char *proxyhost, const char *proxyport, struct addrinfo proxyhints, | 128 | const char *proxyhost, const char *proxyport, struct addrinfo proxyhints, |
114 | int socksv) | 129 | int socksv, const char *proxyuser) |
115 | { | 130 | { |
116 | int proxyfd, r; | 131 | int proxyfd, r, authretry = 0; |
117 | size_t hlen, wlen; | 132 | size_t hlen, wlen; |
118 | unsigned char buf[1024]; | 133 | unsigned char buf[1024]; |
119 | size_t cnt; | 134 | size_t cnt; |
@@ -121,21 +136,26 @@ socks_connect(const char *host, const char *port, | |||
121 | struct sockaddr_in *in4 = (struct sockaddr_in *)&addr; | 136 | struct sockaddr_in *in4 = (struct sockaddr_in *)&addr; |
122 | struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&addr; | 137 | struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&addr; |
123 | in_port_t serverport; | 138 | in_port_t serverport; |
139 | const char *proxypass = NULL; | ||
124 | 140 | ||
125 | if (proxyport == NULL) | 141 | if (proxyport == NULL) |
126 | proxyport = (socksv == -1) ? HTTP_PROXY_PORT : SOCKS_PORT; | 142 | proxyport = (socksv == -1) ? HTTP_PROXY_PORT : SOCKS_PORT; |
127 | 143 | ||
128 | proxyfd = remote_connect(proxyhost, proxyport, proxyhints); | ||
129 | |||
130 | if (proxyfd < 0) | ||
131 | return (-1); | ||
132 | |||
133 | /* Abuse API to lookup port */ | 144 | /* Abuse API to lookup port */ |
134 | if (decode_addrport("0.0.0.0", port, (struct sockaddr *)&addr, | 145 | if (decode_addrport("0.0.0.0", port, (struct sockaddr *)&addr, |
135 | sizeof(addr), 1, 1) == -1) | 146 | sizeof(addr), 1, 1) == -1) |
136 | errx(1, "unknown port \"%.64s\"", port); | 147 | errx(1, "unknown port \"%.64s\"", port); |
137 | serverport = in4->sin_port; | 148 | serverport = in4->sin_port; |
138 | 149 | ||
150 | again: | ||
151 | if (authretry++ > 3) | ||
152 | errx(1, "Too many authentication failures"); | ||
153 | |||
154 | proxyfd = remote_connect(proxyhost, proxyport, proxyhints); | ||
155 | |||
156 | if (proxyfd < 0) | ||
157 | return (-1); | ||
158 | |||
139 | if (socksv == 5) { | 159 | if (socksv == 5) { |
140 | if (decode_addrport(host, port, (struct sockaddr *)&addr, | 160 | if (decode_addrport(host, port, (struct sockaddr *)&addr, |
141 | sizeof(addr), 0, 1) == -1) | 161 | sizeof(addr), 0, 1) == -1) |
@@ -239,11 +259,11 @@ socks_connect(const char *host, const char *port, | |||
239 | /* Try to be sane about numeric IPv6 addresses */ | 259 | /* Try to be sane about numeric IPv6 addresses */ |
240 | if (strchr(host, ':') != NULL) { | 260 | if (strchr(host, ':') != NULL) { |
241 | r = snprintf(buf, sizeof(buf), | 261 | r = snprintf(buf, sizeof(buf), |
242 | "CONNECT [%s]:%d HTTP/1.0\r\n\r\n", | 262 | "CONNECT [%s]:%d HTTP/1.0\r\n", |
243 | host, ntohs(serverport)); | 263 | host, ntohs(serverport)); |
244 | } else { | 264 | } else { |
245 | r = snprintf(buf, sizeof(buf), | 265 | r = snprintf(buf, sizeof(buf), |
246 | "CONNECT %s:%d HTTP/1.0\r\n\r\n", | 266 | "CONNECT %s:%d HTTP/1.0\r\n", |
247 | host, ntohs(serverport)); | 267 | host, ntohs(serverport)); |
248 | } | 268 | } |
249 | if (r == -1 || (size_t)r >= sizeof(buf)) | 269 | if (r == -1 || (size_t)r >= sizeof(buf)) |
@@ -254,15 +274,50 @@ socks_connect(const char *host, const char *port, | |||
254 | if (cnt != r) | 274 | if (cnt != r) |
255 | err(1, "write failed (%d/%d)", cnt, r); | 275 | err(1, "write failed (%d/%d)", cnt, r); |
256 | 276 | ||
257 | /* Read reply */ | 277 | if (authretry > 1) { |
278 | char resp[1024]; | ||
279 | |||
280 | proxypass = getproxypass(proxyuser, proxyhost); | ||
281 | r = snprintf(buf, sizeof(buf), "%s:%s", | ||
282 | proxyuser, proxypass); | ||
283 | if (r == -1 || (size_t)r >= sizeof(buf) || | ||
284 | b64_ntop(buf, strlen(buf), resp, | ||
285 | sizeof(resp)) == -1) | ||
286 | errx(1, "Proxy username/password too long"); | ||
287 | r = snprintf(buf, sizeof(buf), "Proxy-Authorization: " | ||
288 | "Basic %s\r\n", resp); | ||
289 | if (r == -1 || (size_t)r >= sizeof(buf)) | ||
290 | errx(1, "Proxy auth response too long"); | ||
291 | r = strlen(buf); | ||
292 | if ((cnt = atomicio(vwrite, proxyfd, buf, r)) != r) | ||
293 | err(1, "write failed (%d/%d)", cnt, r); | ||
294 | } | ||
295 | |||
296 | /* Terminate headers */ | ||
297 | if ((r = atomicio(vwrite, proxyfd, "\r\n", 2)) != 2) | ||
298 | err(1, "write failed (2/%d)", r); | ||
299 | |||
300 | /* Read status reply */ | ||
301 | proxy_read_line(proxyfd, buf, sizeof(buf)); | ||
302 | if (proxyuser != NULL && | ||
303 | strncmp(buf, "HTTP/1.0 407 ", 12) == 0) { | ||
304 | if (authretry > 1) { | ||
305 | fprintf(stderr, "Proxy authentication " | ||
306 | "failed\n"); | ||
307 | } | ||
308 | close(proxyfd); | ||
309 | goto again; | ||
310 | } else if (strncmp(buf, "HTTP/1.0 200 ", 12) != 0) | ||
311 | errx(1, "Proxy error: \"%s\"", buf); | ||
312 | |||
313 | /* Headers continue until we hit an empty line */ | ||
258 | for (r = 0; r < HTTP_MAXHDRS; r++) { | 314 | for (r = 0; r < HTTP_MAXHDRS; r++) { |
259 | proxy_read_line(proxyfd, buf, sizeof(buf)); | 315 | proxy_read_line(proxyfd, buf, sizeof(buf)); |
260 | if (r == 0 && strncmp(buf, "HTTP/1.0 200 ", 12) != 0) | ||
261 | errx(1, "Proxy error: \"%s\"", buf); | ||
262 | /* Discard headers until we hit an empty line */ | ||
263 | if (*buf == '\0') | 316 | if (*buf == '\0') |
264 | break; | 317 | break; |
265 | } | 318 | } |
319 | if (*buf != '\0') | ||
320 | errx(1, "Too many proxy headers received"); | ||
266 | } else | 321 | } else |
267 | errx(1, "Unknown proxy protocol %d", socksv); | 322 | errx(1, "Unknown proxy protocol %d", socksv); |
268 | 323 | ||