X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=socket.c;h=e8ed58402f80d3113ba8754c9b0007eb56d46bd3;hb=f16d8d23439b5569f0c2e1af22494708b507f277;hp=39bf2c2cfd93847b1fac1ee4b05457613ae22541;hpb=121bfdf03f639a0979d340f60880038fafc739b0;p=~andy%2Ffetchmail diff --git a/socket.c b/socket.c index 39bf2c2c..e8ed5840 100644 --- a/socket.c +++ b/socket.c @@ -10,68 +10,36 @@ #include #include #include /* isspace() */ -#ifdef HAVE_MEMORY_H -#include -#endif /* HAVE_MEMORY_H */ #include #include -#ifndef HAVE_NET_SOCKET_H #include -#else -#include -#endif #include #include -#ifdef HAVE_ARPA_INET_H #include -#endif #include -#if defined(STDC_HEADERS) #include -#endif -#if defined(HAVE_UNISTD_H) #include -#endif -#if defined(HAVE_STDARG_H) #include -#else -#include -#endif -#if TIME_WITH_SYS_TIME -# include -# include -#else -# if HAVE_SYS_TIME_H -# include -# else -# include -# endif -#endif +#include +#include #include "socket.h" #include "fetchmail.h" #include "getaddrinfo.h" -#include "i18n.h" +#include "gettext.h" #include "sdump.h" -/* Defines to allow BeOS and Cygwin to play nice... */ -#ifdef __BEOS__ -static char peeked; -#define fm_close(a) closesocket(a) -#define fm_write(a,b,c) send(a,b,c,0) -#define fm_peek(a,b,c) recv(a,b,c,0) -#define fm_read(a,b,c) recv(a,b,c,0) -#else -#define fm_close(a) close(a) +/* Defines to allow Cygwin to play nice... */ +#define fm_close(a) close(a) #define fm_write(a,b,c) write(a,b,c) #define fm_peek(a,b,c) recv(a,b,c, MSG_PEEK) + #ifdef __CYGWIN__ #define fm_read(a,b,c) cygwin_read(a,b,c) static ssize_t cygwin_read(int sock, void *buf, size_t count); #else /* ! __CYGWIN__ */ #define fm_read(a,b,c) read(a,b,c) #endif /* __CYGWIN__ */ -#endif /* We need to define h_errno only if it is not already */ #ifndef h_errno @@ -80,7 +48,6 @@ extern int h_errno; # endif #endif /* ndef h_errno */ -#ifdef HAVE_SOCKETPAIR static char *const *parse_plugin(const char *plugin, const char *host, const char *service) { char **argvec; @@ -134,6 +101,7 @@ static char *const *parse_plugin(const char *plugin, const char *host, const cha if (!argvec) { report(stderr, GT_("fetchmail: malloc failed\n")); + free(plugin_copy); return NULL; } memset(argvec, 0, s); @@ -179,7 +147,7 @@ static int handle_plugin(const char *host, (void) close(fds[1]); if ( (dup2(fds[0],0) == -1) || (dup2(fds[0],1) == -1) ) { report(stderr, GT_("dup2 failed\n")); - exit(1); + _exit(EXIT_FAILURE); } /* fds[0] is now connected to 0 and 1; close it */ (void) close(fds[0]); @@ -188,7 +156,7 @@ static int handle_plugin(const char *host, argvec = parse_plugin(plugin,host,service); execvp(*argvec, argvec); report(stderr, GT_("execvp(%s) failed\n"), *argvec); - exit(0); + _exit(EXIT_FAILURE); break; default: /* parent */ /* NOP */ @@ -198,31 +166,12 @@ static int handle_plugin(const char *host, (void) close(fds[0]); return fds[1]; } -#endif /* HAVE_SOCKETPAIR */ -#ifdef __UNUSED__ - -int SockCheckOpen(int fd) -/* poll given socket; is it selectable? */ -{ - fd_set r, w, e; - int rt; - struct timeval tv; - - for (;;) - { - FD_ZERO(&r); FD_ZERO(&w); FD_ZERO(&e); - FD_SET(fd, &e); - - tv.tv_sec = 0; tv.tv_usec = 0; - rt = select(fd+1, &r, &w, &e, &tv); - if (rt == -1 && (errno != EAGAIN && errno != EINTR)) - return 0; - if (rt != -1) - return 1; - } +/** Set socket to SO_KEEPALIVE. \return 0 for success. */ +int SockKeepalive(int sock) { + int keepalive = 1; + return setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof keepalive); } -#endif /* __UNUSED__ */ int UnixOpen(const char *path) { @@ -239,12 +188,12 @@ int UnixOpen(const char *path) return -1; } - /* Socket opened saved. Usefull if connect timeout - * because it can be closed. - */ - mailserver_socket_temp = sock; - - if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) < 0) + /* Socket opened saved. Useful if connect timeout + * because it can be closed. + */ + mailserver_socket_temp = sock; + + if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) < 0) { int olderr = errno; fm_close(sock); /* don't use SockClose, no traffic yet */ @@ -252,9 +201,9 @@ int UnixOpen(const char *path) errno = olderr; sock = -1; } - - /* No connect timeout, then no need to set mailserver_socket_temp */ - mailserver_socket_temp = -1; + + /* No connect timeout, then no need to set mailserver_socket_temp */ + mailserver_socket_temp = -1; return sock; } @@ -267,10 +216,8 @@ int SockOpen(const char *host, const char *service, int ord; char errbuf[8192] = ""; -#ifdef HAVE_SOCKETPAIR if (plugin) return handle_plugin(host,service,plugin); -#endif /* HAVE_SOCKETPAIR */ memset(&req, 0, sizeof(struct addrinfo)); req.ai_socktype = SOCK_STREAM; @@ -318,6 +265,8 @@ int SockOpen(const char *host, const char *service, continue; } + SockKeepalive(i); + /* Save socket descriptor. * Used to close the socket after connect timeout. */ mailserver_socket_temp = i; @@ -359,32 +308,19 @@ int SockOpen(const char *host, const char *service, return i; } - -#if defined(HAVE_STDARG_H) int SockPrintf(int sock, const char* format, ...) { -#else -int SockPrintf(sock,format,va_alist) -int sock; -char *format; -va_dcl { -#endif - va_list ap; char buf[8192]; -#if defined(HAVE_STDARG_H) va_start(ap, format) ; -#else - va_start(ap); -#endif vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); return SockWrite(sock, buf, strlen(buf)); - } #ifdef SSL_ENABLE +#define OPENSSL_NO_SSL_INTERN 1 #include #include #include @@ -431,14 +367,6 @@ int SockRead(int sock, char *buf, int len) if (--len < 1) return(-1); -#ifdef __BEOS__ - if (peeked != 0){ - (*bp) = peeked; - bp++; - len--; - peeked = 0; - } -#endif do { /* * The reason for these gymnastics is that we want two things: @@ -452,7 +380,7 @@ int SockRead(int sock, char *buf, int len) /* OK... SSL_peek works a little different from MSG_PEEK Problem is that SSL_peek can return 0 if there is no data currently available. If, on the other - hand, we loose the socket, we also get a zero, but + hand, we lose the socket, we also get a zero, but the SSL_read then SEGFAULTS! To deal with this, we'll check the error code any time we get a return of zero from SSL_peek. If we have an error, we bail. @@ -501,18 +429,12 @@ int SockRead(int sock, char *buf, int len) #endif /* SSL_ENABLE */ { -#ifdef __BEOS__ - if ((n = fm_read(sock, bp, 1)) <= 0) -#else if ((n = fm_peek(sock, bp, len)) <= 0) -#endif return (-1); if ((newline = (char *)memchr(bp, '\n', n)) != NULL) n = newline - bp + 1; -#ifndef __BEOS__ if ((n = fm_read(sock, bp, n)) == -1) return(-1); -#endif /* __BEOS__ */ } bp += n; len -= n; @@ -567,9 +489,6 @@ int SockPeek(int sock) if (n == -1) return -1; -#ifdef __BEOS__ - peeked = ch; -#endif return(ch); } @@ -593,26 +512,6 @@ SSL *SSLGetContext( int sock ) return _ssl_context[sock]; } -/** A picky certificate name check: - * check if the pattern or string in s1 (from a certificate) matches the - * hostname (in s2), returns true if matched. - * - * The only place where a wildcard is allowed is in the leftmost - * position of p1. */ -static int name_match(const char *p1, const char *p2) { - if (p1[0] == '*') { - size_t l1, l2; - - ++p1; - l1 = strlen(p1); - l2 = strlen(p2); - if (l2 > l1) - p2 += l2 - l1; - } - - return (0 == strcasecmp(p1, p2)); -} - /* ok_return (preverify_ok) is 1 if this stage of certificate verification passed, or 0 if it failed. This callback lets us display informative errors, and perform additional validation (e.g. CN matches) */ @@ -638,7 +537,7 @@ static int SSL_verify_callback( int ok_return, X509_STORE_CTX *ctx, int strict ) if (outlevel >= O_VERBOSE) { if (depth == 0 && SSLverbose) - report(stderr, GT_("Server certificate:\n")); + report(stdout, GT_("Server certificate:\n")); else { if (_firstrun) { _firstrun = 0; @@ -707,20 +606,20 @@ static int SSL_verify_callback( int ok_return, X509_STORE_CTX *ctx, int strict ) for (j = 0, r = sk_GENERAL_NAME_num(gens); j < r; ++j) { const GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, j); if (gn->type == GEN_DNS) { - char *p1 = (char *)gn->d.ia5->data; - char *p2 = _ssl_server_cname; + char *pp1 = (char *)gn->d.ia5->data; + char *pp2 = _ssl_server_cname; if (outlevel >= O_VERBOSE) { - report(stdout, GT_("Subject Alternative Name: %s\n"), (tt = sdump(p1, (size_t)gn->d.ia5->length))); + report(stdout, GT_("Subject Alternative Name: %s\n"), (tt = sdump(pp1, (size_t)gn->d.ia5->length))); xfree(tt); } /* Name contains embedded NUL characters, so we complain. This * is likely a certificate spoofing attack. */ - if ((size_t)gn->d.ia5->length != strlen(p1)) { + if ((size_t)gn->d.ia5->length != strlen(pp1)) { report(stderr, GT_("Bad certificate: Subject Alternative Name contains NUL, aborting!\n")); sk_GENERAL_NAME_free(gens); return 0; } - if (name_match(p1, p2)) { + if (name_match(pp1, pp2)) { matched = 1; } } @@ -909,16 +808,14 @@ int SSLOpen(int sock, char *mycert, char *mykey, const char *myproto, int certck /* Make sure a connection referring to an older context is not left */ _ssl_context[sock] = NULL; if(myproto) { - if(!strcasecmp("ssl2",myproto)) { - _ctx[sock] = SSL_CTX_new(SSLv2_client_method()); - } else if(!strcasecmp("ssl3",myproto)) { + if(!strcasecmp("ssl3",myproto)) { _ctx[sock] = SSL_CTX_new(SSLv3_client_method()); } else if(!strcasecmp("tls1",myproto)) { _ctx[sock] = SSL_CTX_new(TLSv1_client_method()); } else if (!strcasecmp("ssl23",myproto)) { myproto = NULL; } else { - fprintf(stderr,GT_("Invalid SSL protocol '%s' specified, using default (SSLv23).\n"), myproto); + fprintf(stderr,GT_("Invalid SSL protocol '%s' specified, using default (SSL23).\n"), myproto); myproto = NULL; } } @@ -930,7 +827,7 @@ int SSLOpen(int sock, char *mycert, char *mykey, const char *myproto, int certck return(-1); } - SSL_CTX_set_options(_ctx[sock], SSL_OP_ALL); + SSL_CTX_set_options(_ctx[sock], (SSL_OP_ALL | SSL_OP_NO_SSLv2) & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); if (certck) { SSL_CTX_set_verify(_ctx[sock], SSL_VERIFY_PEER, SSL_ck_verify_callback); @@ -1049,30 +946,6 @@ int SockClose(int sock) } #endif -#ifdef __UNUSED__ - /* - * This hangs in RedHat 6.2 after fetchmail runs for a while a - * FIN_WAIT2 comes up in netstat and fetchmail never returns from - * the recv system call. (Reported from jtnews - * , Wed, 24 May 2000 21:26:02.) - * - * Half-close the connection first so the other end gets notified. - * - * This stops sends but allows receives (effectively, it sends a - * TCP ). */ - if (shutdown(sock, 1) == 0) { - char ch; - /* If there is any data still waiting in the queue, discard it. - * Call recv() until either it returns 0 (meaning we received a FIN) - * or any error occurs. This makes sure all data sent by the other - * side is acknowledged at the TCP level. - */ - if (fm_peek(sock, &ch, 1) > 0) - while (fm_read(sock, &ch, 1) > 0) - continue; - } -#endif /* __UNUSED__ */ - /* if there's an error closing at this point, not much we can do */ return(fm_close(sock)); /* this is guarded */ } @@ -1085,7 +958,7 @@ int SockClose(int sock) */ static ssize_t cygwin_read(int sock, void *buf, size_t count) { - char *bp = buf; + char *bp = (char *)buf; size_t n = 0; if ((n = read(sock, bp, count)) == (size_t)-1) @@ -1105,21 +978,3 @@ static ssize_t cygwin_read(int sock, void *buf, size_t count) return count; } #endif /* __CYGWIN__ */ - -#ifdef MAIN -/* - * Use the chargen service to test input buffering directly. - * You may have to uncomment the `chargen' service description in your - * inetd.conf (and then SIGHUP inetd) for this to work. */ -main() -{ - int sock = SockOpen("localhost", "chargen", NULL); - char buf[80]; - - while (SockRead(sock, buf, sizeof(buf)-1)) - SockWrite(1, buf, strlen(buf)); - SockClose(sock); -} -#endif /* MAIN */ - -/* socket.c ends here */