/[libspopc]/session.c
ViewVC logotype

Annotation of /session.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26