/[libspopc]/session.c
ViewVC logotype

Contents of /session.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (show annotations)
Fri Apr 13 23:39:42 2012 UTC (7 years, 1 month ago) by ben
File MIME type: text/plain
File size: 10068 byte(s)
Renegotiate automatically SSL session keys.

1 /* this is session.c file, part of the libspopc library sources
2 * copyright © 2002- Benoit Rouits <brouits@free.fr>
3 * released under the terms of the GNU Lesser General Public Licence.
4 *
5 * libspopc offers simple API for a pop3 client.
6 * See RFC 1725 for pop3 specifications.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 /*I casted 'port' to true unsigned, now, tell me if warning continues */
24 /*; #pragma warning(disable: 4761)*/ /* disable "integral size mismatch in argument" -warning */
25
26 #ifdef WIN32
27 #include <winsock.h>
28 #include <stdio.h>
29 #else
30 #include <netdb.h>
31 #include <unistd.h>
32 #include <netinet/in.h>
33 #include <sys/socket.h>
34 #endif
35
36
37 #include <stdlib.h>
38 #include <string.h> /* strdup */
39 #include <stdio.h> /* perror */
40 #include <sys/types.h>
41
42 #include "libspopc.h"
43 #include "mutex.h"
44
45 #define socklen_t int /* actually true on most systems */
46
47 /* needs from queries.c */
48 extern int pop3_recv (pop3sock_t sock, char* buf, int len);
49
50 /* mutex locks for this object (must be declared in libspopc.c) */
51 extern mutex GETHOSTBYNAME;
52 /* end mutex locks */
53
54 #ifdef USE_SSL
55
56 #define SSL_USE_NEVER -1 /* never use SSL even on port 995 */
57 #define SSL_USE_AUTO 0 /* use SSL only on port 995 (default) */
58 #define SSL_USE_ALWAYS 1 /* force SSL whatever the port is */
59
60 static int SSL_UP = 0; /* prevent SSL_library_init() to be called twice */
61 static char* SSL_CERT = NULL; /* whole application on-disk certfile */
62
63 /* set default behaviour as SSL_USE_AUTO for backward compatibility */
64 static int SSL_USE = SSL_USE_AUTO;
65
66
67 /* let libspopc never use SSL even connecting on port 995 */
68 DLLIMPORT void pop3_ssl_never(void)
69 {
70 SSL_USE = SSL_USE_NEVER;
71 }
72
73 /* let libspopc use SSL when connecting port 995 */
74 DLLIMPORT void pop3_ssl_auto(void)
75 {
76 SSL_USE = SSL_USE_AUTO;
77 }
78
79 /* let libspopc use SSL connecting on any port, even 110 */
80 DLLIMPORT void pop3_ssl_always(void)
81 {
82 SSL_USE = SSL_USE_ALWAYS;
83 }
84
85 /* set the filename of the certificate */
86 DLLIMPORT void pop3_cert_setup(const char *certfile)
87 {
88 if (SSL_CERT) free(SSL_CERT);
89 SSL_CERT=NULL;
90 if (certfile) SSL_CERT=strdup(certfile);
91 }
92
93 /* callback for error reporting on ssl verification
94 * just return 0 on error, 1 else
95 */
96 DLLIMPORT int ssl_verify_callback(int ok, X509_STORE_CTX *ctx) {
97 if (!ok) { /* bad identification */
98 int err;
99 err = X509_STORE_CTX_get_error(ctx);
100 return 0;
101 }
102 return 1;
103 }
104
105 /* init ssl library and context
106 * depending on port and SSL_USE_*
107 */
108 DLLIMPORT pop3sock_t ssl_prepare(const int port){
109 pop3sock_t sock;
110
111 sock =(pop3sock_t)malloc(sizeof(pop3sock));
112 sock->sock=socket(AF_INET,SOCK_STREAM,0);
113 if(-1==sock->sock){
114 perror("ssl_prepare.socket");
115 free(sock);
116 return(NULL);
117 }
118 if (( (995 == port) && (SSL_USE == SSL_USE_AUTO))
119 || (SSL_USE == SSL_USE_ALWAYS) ) {
120 if (0 == SSL_UP) SSL_UP=SSL_library_init();
121
122 if (1 != SSL_UP) {
123 #ifdef WIN32
124 closesocket(sock->sock);
125 #else
126 close(sock->sock);
127 #endif
128 free(sock);
129 perror("ssl_prepare.SSL_library_init");
130 return(NULL);
131 }
132 SSL_load_error_strings();
133 sock->ctx = SSL_CTX_new(SSLv23_client_method());
134 if (NULL == sock->ctx) {
135 #ifdef WIN32
136 closesocket(sock->sock);
137 #else
138 close(sock->sock);
139 #endif
140 free(sock);
141 perror("ssl_prepare.SSLv23_client_method");
142 return(NULL);
143 }
144 SSL_CTX_set_mode(sock->ctx, SSL_MODE_AUTO_RETRY);
145 if ( SSL_CERT != NULL ) {
146 SSL_CTX_load_verify_locations(sock->ctx, SSL_CERT, 0);
147 SSL_CTX_set_verify(sock->ctx, SSL_VERIFY_PEER, &ssl_verify_callback);
148 }
149 sock->ssl = SSL_new(sock->ctx);
150 if (NULL == sock->ssl) {
151 #ifdef WIN32
152 closesocket(sock->sock);
153 #else
154 close(sock->sock);
155 #endif
156 SSL_CTX_free(sock->ctx);
157 free(sock);
158 perror("ssl_prepare.SSL_new");
159 return(NULL);
160 }
161 SSL_set_fd(sock->ssl, sock->sock);
162 } else { /* port != 995 or SSL_USE_NEVER */
163 sock->ssl=NULL;
164 sock->ctx=NULL;
165 }
166 return sock;
167 }
168
169 #endif
170
171 /* prepares the socket options
172 * mainly set read an write timeouts
173 * this way may be either ignored
174 * or refused on some platform
175 */
176 DLLIMPORT int socket_prepare(int sock, int timeout){
177 int ret=0;
178 #ifdef WIN32
179 timeout *= 1000;
180 if (ret += setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, (void*)&timeout, sizeof timeout))
181 perror("socket_prepare.setsockopt");
182 if (ret += setsockopt (sock, SOL_SOCKET, SO_SNDTIMEO, (void*)&timeout, sizeof timeout))
183 perror("socket_prepare.setsockopt");
184 #else
185 struct timeval tv;
186 tv.tv_sec = timeout;
187 tv.tv_usec = 0 ;
188
189 if (ret += setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, (void*)&tv, sizeof tv))
190 perror("socket_prepare.setsockopt");
191 if (ret += setsockopt (sock, SOL_SOCKET, SO_SNDTIMEO, (void*)&tv, sizeof tv))
192 perror("socket_prepare.setsockopt");
193 #endif
194 return ret;
195 }
196
197 /* prepares the pop session and returns a socket descriptor */
198 DLLIMPORT pop3sock_t pop3_prepare(const char* servername, const int port, struct sockaddr_in* connection, struct hostent* server){
199 pop3sock_t sock;
200 struct hostent* hostent_buf;
201 int i;
202 #ifdef WIN32
203
204 WSADATA wsaData;
205
206 if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0)
207 {
208 exit(1);
209 }
210
211 #endif
212
213 memset((char*)connection,0,sizeof(struct sockaddr_in));
214
215 /* here, enter a critical section to perform atomic name resolution */
216 mutex_in(&GETHOSTBYNAME);
217 hostent_buf=gethostbyname(servername);
218 if(!hostent_buf){
219 #ifdef WIN32
220 perror("pop3_prepare.gethostbyname");
221 #else
222 herror("pop3_prepare.gethostbyname");
223 #endif
224 /* we don't want somebody to go out with mutex locked */
225 mutex_out(&GETHOSTBYNAME);
226 return BAD_SOCK;
227 }
228 /* begin hostent deep copy */
229 memmove(server,hostent_buf,sizeof(struct hostent));
230 server->h_name=strdup(hostent_buf->h_name);
231 server->h_aliases=NULL;
232 i=0;
233 while (hostent_buf->h_aliases[i])
234 {
235 server->h_aliases=realloc(server->h_aliases,(i+1)*sizeof(char*));
236 server->h_aliases[i]=strdup(hostent_buf->h_aliases[i]);
237 i++;
238 }
239 if (i>0) {
240 server->h_aliases=realloc(server->h_aliases,(i+1)*sizeof(char*));
241 server->h_aliases[i]=NULL;
242 }
243
244 server->h_addr_list=NULL;
245 i=0;
246 while (hostent_buf->h_addr_list[i])
247 { /* has at least one adress */
248 server->h_addr_list=realloc(server->h_addr_list,(i+1)*sizeof(char*));
249 server->h_addr_list[i]=malloc(server->h_length);
250 memmove(server->h_addr_list[i],hostent_buf->h_addr_list[i],server->h_length);
251 i++;
252 }
253 if (i>0) {
254 server->h_addr_list=realloc(server->h_addr_list, (i+1)*sizeof(char*));
255 server->h_addr_list[i]=NULL;
256 }
257
258 /* end hostent deep copy */
259 mutex_out(&GETHOSTBYNAME);
260 /* end of critical section (name resolution) */
261
262 memmove((char*)&(connection->sin_addr.s_addr),server->h_addr,server->h_length);
263 connection->sin_family=AF_INET;
264 connection->sin_port=htons(port?(unsigned short int)port:(unsigned short int)110);
265 /* integral size mismatch in argument - htons(port)*/
266
267 #ifdef USE_SSL
268 sock = ssl_prepare(port);
269 #else
270 sock=socket(AF_INET,SOCK_STREAM,0);
271 if(BAD_SOCK == sock){
272 perror("pop3_prepare.socket");
273 }
274 #endif
275 #ifdef USE_SSL
276 socket_prepare(sock->sock, SOCKET_TIMEOUT);
277 #else
278 socket_prepare(sock, SOCKET_TIMEOUT);
279 #endif
280 return(sock);
281 }
282
283 /* connects to the server through the sock and returns server's welcome */
284 DLLIMPORT char* pop3_connect(pop3sock_t sock, struct sockaddr_in* connection){
285 int r;
286 char* buf;
287
288
289 #ifdef USE_SSL
290 r=connect(sock->sock,(struct sockaddr*)connection,(socklen_t)sizeof(*connection));
291 if ( r!=-1 && sock->ssl ) {
292 if (SSL_connect(sock->ssl) == -1) {
293 #ifdef WIN32
294 closesocket(sock->sock);
295 #else
296 close(sock->sock);
297 #endif
298 return(NULL);
299 }
300 if ( SSL_CERT ) {
301 if ( !SSL_get_peer_certificate(sock->ssl) ) {
302 #ifdef WIN32
303 closesocket(sock->sock);
304 #else
305 close(sock->sock);
306 #endif
307 return(NULL);
308 }
309 }
310 }
311 #else
312 r=connect(sock,(struct sockaddr*)connection,(socklen_t)sizeof(*connection));
313 #endif
314
315 if(r==-1){
316 perror("pop3_connect.connect");
317 return(NULL);
318 }
319
320
321 buf=(char*)malloc(POPBUF);
322 if(!buf){
323 perror("pop3_connect.malloc");
324 return(NULL);
325 }
326 r=pop3_recv(sock,buf,POPBUF); /* 512 is enough, as say RFC 1939 */
327 if(r==0 || r==-1){
328 /* -1: transport error (timeout?) */
329 /* 0: server error (busy?) */
330 perror("pop3_connect.pop3_recv");
331 free(buf);
332 return(NULL);
333 }
334 buf[r]='\0';
335 return buf;
336 }
337
338 DLLIMPORT void pop3_disconnect(pop3sock_t sock, struct hostent* server){
339 int i;
340 /* close socket */
341 #ifdef USE_SSL
342 if (sock->sock>0)
343 {
344 #ifdef WIN32
345 closesocket(sock->sock);
346 #else
347 shutdown(sock->sock,SHUT_RDWR);
348 close(sock->sock);
349 #endif
350 }
351 if (NULL != sock->ssl) {
352 /* a memory leak has been reported with: SSL_shutdown(sock->ssl);*/
353 SSL_free(sock->ssl);
354 }
355 if ( NULL != sock->ctx ) {
356 SSL_CTX_free(sock->ctx);
357 }
358
359 free(sock);
360 #else
361 if (sock>0) {
362 #ifdef WIN32
363 closesocket(sock);
364 #else
365 shutdown(sock,SHUT_RDWR);
366 close(sock);
367 #endif
368 }
369 #endif
370 /* free deep copy of struct hostent */
371 if (server->h_addr_list) {
372 i=0;
373 while(NULL != server->h_addr_list[i]) {
374 /* has at least one adress */
375 free(server->h_addr_list[i]);
376 i++;
377 }
378 free(server->h_addr_list);
379 }
380 if (server->h_aliases) {
381 i=0;
382 while (NULL != server->h_aliases[i]) {
383 free(server->h_aliases[i]);
384 i++;
385 }
386 free(server->h_aliases);
387 }
388 free(server->h_name);
389 #ifdef WIN32
390 WSACleanup();
391 #endif
392 }
393
394 /* sets the timeout in seconds for a socket descriptor */
395 DLLIMPORT int pop3_timeout(pop3sock_t sock, int timeout){
396 #ifdef USE_SSL
397 return socket_prepare(sock->sock, timeout);
398 #else
399 return socket_prepare(sock, timeout);
400 #endif
401 }

  ViewVC Help
Powered by ViewVC 1.1.26