Mercurial > hg
annotate mcabber/connwrap/connwrap.c @ 880:ea983a945eba
/buffer scroll_unlock: Don't always jump to the end of the buffer
If there is no pending message, do not jump to the bottom of the buffer.
For special buffers (e.g. for the status buffer) pending flag is currently
disabled so we jump unconditionally.
author | Mikael Berthe <mikael@lilotux.net> |
---|---|
date | Sat, 27 May 2006 15:59:05 +0200 |
parents | 89aeb8fdd215 |
children | 40175f3dcef7 |
rev | line source |
---|---|
25 | 1 #include "connwrap.h" |
2 | |
302
8ca708a0d550
Remove compilation warnings in connwrap library
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
3 #include <stdio.h> |
8ca708a0d550
Remove compilation warnings in connwrap library
Mikael Berthe <mikael@lilotux.net>
parents:
235
diff
changeset
|
4 #include <stdlib.h> |
25 | 5 #include <netdb.h> |
6 #include <string.h> | |
7 #include <netinet/in.h> | |
8 #include <errno.h> | |
9 #include <arpa/inet.h> | |
10 #include <fcntl.h> | |
11 #include <sys/time.h> | |
112 | 12 #include <unistd.h> |
25 | 13 |
14 #define PROXY_TIMEOUT 10 | |
15 // HTTP proxy timeout in seconds (for the CONNECT method) | |
16 | |
17 #ifdef HAVE_OPENSSL | |
18 | |
19 #define OPENSSL_NO_KRB5 1 | |
20 #include <openssl/ssl.h> | |
21 #include <openssl/err.h> | |
22 | |
134 | 23 #else |
24 # ifdef HAVE_GNUTLS | |
25 # include <gnutls/openssl.h> | |
26 # define HAVE_OPENSSL | |
27 # endif | |
25 | 28 #endif |
29 | |
30 static int in_http_connect = 0; | |
31 | |
32 #ifdef HAVE_OPENSSL | |
33 | |
34 static SSL_CTX *ctx = 0; | |
35 | |
36 typedef struct { int fd; SSL *ssl; } sslsock; | |
37 | |
38 static sslsock *socks = 0; | |
39 static int sockcount = 0; | |
40 | |
41 static sslsock *getsock(int fd) { | |
42 int i; | |
43 | |
44 for(i = 0; i < sockcount; i++) | |
45 if(socks[i].fd == fd) | |
46 return &socks[i]; | |
47 | |
48 return 0; | |
49 } | |
50 | |
51 static sslsock *addsock(int fd) { | |
52 sslsock *p; | |
53 socks = (sslsock *) realloc(socks, sizeof(sslsock)*++sockcount); | |
54 | |
55 p = &socks[sockcount-1]; | |
56 | |
57 if(!ctx) { | |
58 SSL_library_init(); | |
59 SSL_load_error_strings(); | |
60 | |
61 #ifdef HAVE_SSLEAY | |
62 SSLeay_add_all_algorithms(); | |
63 #else | |
64 OpenSSL_add_all_algorithms(); | |
65 #endif | |
66 | |
134 | 67 //ctx = SSL_CTX_new(SSLv23_method()); |
68 ctx = SSL_CTX_new(SSLv23_client_method()); | |
25 | 69 } |
70 | |
71 p->ssl = SSL_new(ctx); | |
72 SSL_set_fd(p->ssl, p->fd = fd); | |
73 | |
74 return p; | |
75 } | |
76 | |
77 static void delsock(int fd) { | |
78 int i, nsockcount; | |
79 sslsock *nsocks; | |
80 | |
81 nsockcount = 0; | |
82 nsocks = (sslsock *) malloc(sizeof(sslsock)*(sockcount-1)); | |
83 | |
84 for(i = 0; i < sockcount; i++) { | |
85 if(socks[i].fd != fd) { | |
86 nsocks[nsockcount++] = socks[i]; | |
87 } else { | |
88 SSL_free(socks[i].ssl); | |
89 } | |
90 } | |
91 | |
92 free(socks); | |
93 | |
94 socks = nsocks; | |
95 sockcount = nsockcount; | |
96 } | |
97 | |
98 #endif | |
99 | |
100 static char *bindaddr = 0, *proxyhost = 0, *proxyuser = 0, *proxypass = 0; | |
101 static int proxyport = 3128; | |
102 static int proxy_ssl = 0; | |
103 | |
104 #define SOCKOUT(s) write(sockfd, s, strlen(s)) | |
105 | |
106 int cw_http_connect(int sockfd, const struct sockaddr *serv_addr, int addrlen) { | |
107 int err, pos, fl; | |
108 struct hostent *server; | |
109 struct sockaddr_in paddr; | |
110 char buf[512]; | |
111 fd_set rfds; | |
112 | |
400
e536ab271584
Kill a warning in the connwrap library
Mikael Berthe <mikael@lilotux.net>
parents:
302
diff
changeset
|
113 fl = 0; |
25 | 114 err = 0; |
115 in_http_connect = 1; | |
116 | |
117 if(!(server = gethostbyname(proxyhost))) { | |
118 errno = h_errno; | |
119 err = -1; | |
120 } | |
121 | |
122 if(!err) { | |
123 memset(&paddr, 0, sizeof(paddr)); | |
124 paddr.sin_family = AF_INET; | |
125 memcpy(&paddr.sin_addr.s_addr, *server->h_addr_list, server->h_length); | |
126 paddr.sin_port = htons(proxyport); | |
127 | |
128 fl = fcntl(sockfd, F_GETFL); | |
129 fcntl(sockfd, F_SETFL, fl & ~O_NONBLOCK); | |
130 | |
131 buf[0] = 0; | |
132 | |
133 err = cw_connect(sockfd, (struct sockaddr *) &paddr, sizeof(paddr), proxy_ssl); | |
134 } | |
135 | |
136 errno = ECONNREFUSED; | |
137 | |
138 if(!err) { | |
139 struct sockaddr_in *sin = (struct sockaddr_in *) serv_addr; | |
140 char *ip = inet_ntoa(sin->sin_addr), c; | |
141 struct timeval tv; | |
142 | |
143 sprintf(buf, "%d", ntohs(sin->sin_port)); | |
144 SOCKOUT("CONNECT "); | |
145 SOCKOUT(ip); | |
146 SOCKOUT(":"); | |
147 SOCKOUT(buf); | |
148 SOCKOUT(" HTTP/1.0\r\n"); | |
149 | |
150 if(proxyuser) { | |
151 char *b; | |
152 SOCKOUT("Proxy-Authorization: Basic "); | |
153 | |
427
ac85ce87f539
Fix buffer overflow in cw_setproxy()
Mikael Berthe <mikael@lilotux.net>
parents:
414
diff
changeset
|
154 snprintf(buf, sizeof(buf), "%s:%s", proxyuser, proxypass); |
25 | 155 b = cw_base64_encode(buf); |
156 SOCKOUT(b); | |
157 free(b); | |
158 | |
159 SOCKOUT("\r\n"); | |
160 } | |
161 | |
162 SOCKOUT("\r\n"); | |
163 | |
164 buf[0] = 0; | |
165 | |
166 while(err != -1) { | |
167 FD_ZERO(&rfds); | |
168 FD_SET(sockfd, &rfds); | |
169 | |
170 tv.tv_sec = PROXY_TIMEOUT; | |
171 tv.tv_usec = 0; | |
172 | |
173 err = select(sockfd+1, &rfds, 0, 0, &tv); | |
174 | |
175 if(err < 1) err = -1; | |
176 | |
177 if(err != -1 && FD_ISSET(sockfd, &rfds)) { | |
178 err = read(sockfd, &c, 1); | |
179 if(!err) err = -1; | |
180 | |
181 if(err != -1) { | |
182 pos = strlen(buf); | |
183 buf[pos] = c; | |
184 buf[pos+1] = 0; | |
185 | |
186 if(strlen(buf) > 4) | |
187 if(!strcmp(buf+strlen(buf)-4, "\r\n\r\n")) | |
188 break; | |
189 } | |
190 } | |
191 } | |
192 } | |
193 | |
194 if(err != -1 && strlen(buf)) { | |
195 char *p = strstr(buf, " "); | |
196 | |
197 err = -1; | |
198 | |
199 if(p) | |
200 if(atoi(++p) == 200) | |
201 err = 0; | |
202 | |
203 fcntl(sockfd, F_SETFL, fl); | |
204 if(fl & O_NONBLOCK) { | |
205 errno = EINPROGRESS; | |
206 err = -1; | |
207 } | |
208 } | |
209 | |
210 in_http_connect = 0; | |
211 | |
212 return err; | |
213 } | |
214 | |
215 int cw_connect(int sockfd, const struct sockaddr *serv_addr, int addrlen, int ssl) { | |
216 int rc; | |
217 struct sockaddr_in ba; | |
218 | |
219 if(bindaddr) | |
220 if(strlen(bindaddr)) { | |
221 #ifdef HAVE_INET_ATON | |
222 struct in_addr addr; | |
223 rc = inet_aton(bindaddr, &addr); | |
224 ba.sin_addr.s_addr = addr.s_addr; | |
225 #else | |
226 rc = inet_pton(AF_INET, bindaddr, &ba); | |
227 #endif | |
228 | |
229 if(rc) { | |
230 ba.sin_port = 0; | |
231 rc = bind(sockfd, (struct sockaddr *) &ba, sizeof(ba)); | |
232 } else { | |
233 rc = -1; | |
234 } | |
235 | |
236 if(rc) return rc; | |
237 } | |
238 | |
239 if(proxyhost && !in_http_connect) rc = cw_http_connect(sockfd, serv_addr, addrlen); | |
240 else rc = connect(sockfd, serv_addr, addrlen); | |
241 | |
242 #ifdef HAVE_OPENSSL | |
243 if(ssl && !rc) { | |
244 sslsock *p = addsock(sockfd); | |
245 if(SSL_connect(p->ssl) != 1) | |
246 return -1; | |
247 } | |
248 #endif | |
249 | |
250 return rc; | |
251 } | |
252 | |
253 int cw_nb_connect(int sockfd, const struct sockaddr *serv_addr, int addrlen, int ssl, int *state) { | |
254 int rc = 0; | |
255 struct sockaddr_in ba; | |
256 | |
257 if(bindaddr) | |
258 if(strlen(bindaddr)) { | |
259 #ifdef HAVE_INET_ATON | |
260 struct in_addr addr; | |
261 rc = inet_aton(bindaddr, &addr); | |
262 ba.sin_addr.s_addr = addr.s_addr; | |
263 #else | |
264 rc = inet_pton(AF_INET, bindaddr, &ba); | |
265 #endif | |
266 | |
267 if(rc) { | |
268 ba.sin_port = 0; | |
269 rc = bind(sockfd, (struct sockaddr *) &ba, sizeof(ba)); | |
270 } else { | |
271 rc = -1; | |
272 } | |
273 | |
274 if(rc) return rc; | |
275 } | |
276 | |
277 #ifdef HAVE_OPENSSL | |
278 if(ssl) { | |
279 if ( !(*state & CW_CONNECT_WANT_SOMETHING)) | |
280 rc = cw_connect(sockfd, serv_addr, addrlen, 0); | |
281 else{ /* check if the socket is connected correctly */ | |
282 int optlen = sizeof(int), optval; | |
235 | 283 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, (socklen_t*)&optlen) || optval) |
25 | 284 return -1; |
285 } | |
286 | |
287 if(!rc) { | |
288 sslsock *p; | |
289 if (*state & CW_CONNECT_SSL) | |
290 p = getsock(sockfd); | |
291 else | |
292 p = addsock(sockfd); | |
414
ec86d759ed54
Trailing whitespace cleanup
Mikael Berthe <mikael@lilotux.net>
parents:
409
diff
changeset
|
293 |
25 | 294 rc = SSL_connect(p->ssl); |
295 switch(rc){ | |
296 case 1: | |
297 *state = 0; | |
298 return 0; | |
299 case 0: | |
300 return -1; | |
301 default: | |
302 switch (SSL_get_error(p->ssl, rc)){ | |
303 case SSL_ERROR_WANT_READ: | |
304 *state = CW_CONNECT_SSL | CW_CONNECT_WANT_READ; | |
305 return 0; | |
306 case SSL_ERROR_WANT_WRITE: | |
307 *state = CW_CONNECT_SSL | CW_CONNECT_WANT_WRITE; | |
308 return 0; | |
309 default: | |
310 return -1; | |
311 } | |
312 } | |
313 } | |
314 else{ /* catch EINPROGRESS error from the connect call */ | |
315 if (errno == EINPROGRESS){ | |
316 *state = CW_CONNECT_STARTED | CW_CONNECT_WANT_WRITE; | |
317 return 0; | |
318 } | |
319 } | |
320 | |
321 return rc; | |
322 } | |
323 #endif | |
324 if ( !(*state & CW_CONNECT_WANT_SOMETHING)) | |
325 rc = connect(sockfd, serv_addr, addrlen); | |
326 else{ /* check if the socket is connected correctly */ | |
327 int optlen = sizeof(int), optval; | |
235 | 328 if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, (socklen_t*)&optlen) || optval) |
25 | 329 return -1; |
330 *state = 0; | |
331 return 0; | |
332 } | |
333 if (rc) | |
334 if (errno == EINPROGRESS){ | |
335 *state = CW_CONNECT_STARTED | CW_CONNECT_WANT_WRITE; | |
336 return 0; | |
337 } | |
338 return rc; | |
339 } | |
340 | |
341 int cw_accept(int s, struct sockaddr *addr, int *addrlen, int ssl) { | |
342 #ifdef HAVE_OPENSSL | |
343 int rc; | |
344 | |
345 if(ssl) { | |
235 | 346 rc = accept(s, addr, (socklen_t*)addrlen); |
25 | 347 |
348 if(!rc) { | |
349 sslsock *p = addsock(s); | |
350 if(SSL_accept(p->ssl) != 1) | |
351 return -1; | |
352 | |
353 } | |
354 | |
355 return rc; | |
356 } | |
357 #endif | |
235 | 358 return accept(s, addr, (socklen_t*)addrlen); |
25 | 359 } |
360 | |
361 int cw_write(int fd, const void *buf, int count, int ssl) { | |
362 #ifdef HAVE_OPENSSL | |
363 sslsock *p; | |
364 | |
365 if(ssl) | |
235 | 366 if((p = getsock(fd)) != NULL) |
25 | 367 return SSL_write(p->ssl, buf, count); |
368 #endif | |
369 return write(fd, buf, count); | |
370 } | |
371 | |
372 int cw_read(int fd, void *buf, int count, int ssl) { | |
373 #ifdef HAVE_OPENSSL | |
374 sslsock *p; | |
375 | |
376 if(ssl) | |
235 | 377 if((p = getsock(fd)) != NULL) |
25 | 378 return SSL_read(p->ssl, buf, count); |
379 #endif | |
380 return read(fd, buf, count); | |
381 } | |
382 | |
235 | 383 void cw_close(int fd) { |
25 | 384 #ifdef HAVE_OPENSSL |
385 delsock(fd); | |
386 #endif | |
387 close(fd); | |
388 } | |
389 | |
390 #define FREEVAR(v) if(v) free(v), v = 0; | |
391 | |
392 void cw_setbind(const char *abindaddr) { | |
393 FREEVAR(bindaddr); | |
394 bindaddr = strdup(abindaddr); | |
395 } | |
396 | |
397 void cw_setproxy(const char *aproxyhost, int aproxyport, const char *aproxyuser, const char *aproxypass) { | |
398 FREEVAR(proxyhost); | |
399 FREEVAR(proxyuser); | |
400 FREEVAR(proxypass); | |
401 | |
402 if(aproxyhost && strlen(aproxyhost)) proxyhost = strdup(aproxyhost); | |
403 if(aproxyuser && strlen(aproxyuser)) proxyuser = strdup(aproxyuser); | |
404 if(aproxypass && strlen(aproxypass)) proxypass = strdup(aproxypass); | |
405 proxyport = aproxyport; | |
406 } | |
407 | |
408 char *cw_base64_encode(const char *in) { | |
409 static char base64digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._"; | |
410 | |
411 int j = 0; | |
412 int inlen = strlen(in); | |
413 char *out = (char *) malloc(inlen*4+1), c; | |
414 | |
415 for(out[0] = 0; inlen >= 3; inlen -= 3) { | |
416 strncat(out, &base64digits[ in[j] >> 2 ], 1); | |
417 strncat(out, &base64digits[ ((in[j] << 4) & 0x30) | (in[j+1] >> 4) ], 1); | |
418 strncat(out, &base64digits[ ((in[j+1] << 2) & 0x3c) | (in[j+2] >> 6) ], 1); | |
419 strncat(out, &base64digits[ in[j+2] & 0x3f ], 1); | |
420 j += 3; | |
421 } | |
422 | |
423 if(inlen > 0) { | |
424 unsigned char fragment; | |
425 | |
426 strncat(out, &base64digits[in[j] >> 2], 1); | |
427 fragment = (in[j] << 4) & 0x30; | |
428 | |
429 if(inlen > 1) | |
430 fragment |= in[j+1] >> 4; | |
431 | |
432 strncat(out, &base64digits[fragment], 1); | |
433 | |
434 c = (inlen < 2) ? '-' : base64digits[ (in[j+1] << 2) & 0x3c ]; | |
435 strncat(out, &c, 1); | |
436 c = '-'; | |
437 strncat(out, &c, 1); | |
438 } | |
414
ec86d759ed54
Trailing whitespace cleanup
Mikael Berthe <mikael@lilotux.net>
parents:
409
diff
changeset
|
439 |
25 | 440 return out; |
441 } |