#include <memory.h>
#endif /* HAVE_MEMORY_H */
#include <sys/types.h>
+#ifndef HAVE_NET_SOCKET_H
#include <sys/socket.h>
+#else
+#include <net/socket.h>
+#endif
#include <netinet/in.h>
+#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
+#endif
#include <netdb.h>
#if defined(STDC_HEADERS)
#include <stdlib.h>
#include "fetchmail.h"
#include "i18n.h"
+/* Defines to allow BeOS 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)
+#define fm_write(a,b,c) write(a,b,c)
+#define fm_peek(a,b,c) recv(a,b,c, MSG_PEEK)
+#define fm_read(a,b,c) read(a,b,c)
+#endif
+
/* We need to define h_errno only if it is not already */
#ifndef h_errno
#endif /* NET_SECURITY */
#ifdef HAVE_SOCKETPAIR
+const char **parse_plugin(const char *plugin, const char *host, const char *service)
+{ const char **argvec;
+ char *c, *p, *plugin_copy;
+ unsigned int s = 2 * sizeof(char*), i;
+
+ plugin_copy = strdup(plugin);
+ if (!plugin_copy)
+ {
+ report(stderr, _("fetchmail: malloc failed\n"));
+ return NULL;
+ }
+ for (c = p = plugin_copy; *c; c++)
+ { if (isspace(*c) && !isspace(*p))
+ s += sizeof(char*);
+ p = c;
+ }
+ argvec = malloc(s);
+ if (!argvec)
+ {
+ report(stderr, _("fetchmail: malloc failed\n"));
+ return NULL;
+ }
+ memset(argvec, 0, s);
+ for (c = p = plugin_copy, i = 0; *c; c++)
+ { if ((!isspace(*c)) && (c == p ? 1 : isspace(*p))) {
+ argvec[i] = c;
+ i++;
+ }
+ p = c;
+ }
+ for (c = plugin_copy; *c; c++)
+ { if (isspace(*c))
+ *c = 0;
+ }
+ for (i = 0; argvec[i]; i++)
+ { if (strcmp(argvec[i], "%h") == 0)
+ argvec[i] = host;
+ if (strcmp(argvec[i], "%p") == 0)
+ argvec[i] = service;
+ }
+ return argvec;
+}
+
static int handle_plugin(const char *host,
const char *service, const char *plugin)
/* get a socket mediated through a given external command */
{
int fds[2];
+ char *const *argvec;
if (socketpair(AF_UNIX,SOCK_STREAM,0,fds))
{
report(stderr, _("fetchmail: socketpair failed\n"));
(void) close(fds[0]);
if (outlevel >= O_VERBOSE)
report(stderr, _("running %s %s %s\n"), plugin, host, service);
- execlp(plugin,plugin,host,service,0);
- report(stderr, _("execl(%s) failed\n"), plugin);
+ argvec = (char *const *)parse_plugin(plugin,host,service);
+ execvp(*argvec, argvec);
+ report(stderr, _("execvp(%s) failed\n"), *argvec);
exit(0);
break;
default: /* parent */
int SockOpen(const char *host, const char *service, const char *options,
const char *plugin)
{
- struct addrinfo *ai, req;
+ struct addrinfo *ai, *ai0, req;
int i;
#if NET_SECURITY
void *request = NULL;
memset(&req, 0, sizeof(struct addrinfo));
req.ai_socktype = SOCK_STREAM;
- if (getaddrinfo(host, service, &req, &ai)) {
+ if (getaddrinfo(host, service, &req, &ai0)) {
report(stderr, _("fetchmail: getaddrinfo(%s.%s)\n"), host,service);
return -1;
- };
+ }
#if NET_SECURITY
if (!options)
if (net_security_strtorequest((char *)options, &request, &requestlen))
goto ret;
- i = inner_connect(ai, request, requestlen, NULL, NULL, "fetchmail", NULL);
+ i = inner_connect(ai0, request, requestlen, NULL, NULL, "fetchmail", NULL);
if (request)
free(request);
ret:
#else /* NET_SECURITY */
#ifdef HAVE_INNER_CONNECT
- i = inner_connect(ai, NULL, 0, NULL, NULL, "fetchmail", NULL);
+ i = inner_connect(ai0, NULL, 0, NULL, NULL, "fetchmail", NULL);
+ if (i >= 0)
+ break;
#else
- i = socket(ai->ai_family, ai->ai_socktype, 0);
- if (i < 0) {
- freeaddrinfo(ai);
- return -1;
- }
- if (connect(i, (struct sockaddr *) ai->ai_addr, ai->ai_addrlen) < 0) {
- freeaddrinfo(ai);
- close(i); /* don't use SockClose, no traffic yet */
- return -1;
+ i = -1;
+ for (ai = ai0; ai; ai = ai->ai_next) {
+ i = socket(ai->ai_family, ai->ai_socktype, 0);
+ if (i < 0)
+ continue;
+ if (connect(i, (struct sockaddr *) ai->ai_addr, ai->ai_addrlen) < 0) {
+ fm_close(i);
+ i = -1;
+ continue;
+ }
+ break;
}
#endif
#endif /* NET_SECURITY */
- freeaddrinfo(ai);
+ freeaddrinfo(ai0);
return i;
-};
+}
#else /* INET6_ENABLE */
#ifndef HAVE_INET_ATON
#ifndef INADDR_NONE
if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) < 0)
{
int olderr = errno;
- close(sock); /* don't use SockClose, no traffic yet */
+ fm_close(sock); /* don't use SockClose, no traffic yet */
h_errno = 0;
errno = olderr;
return -1;
memcpy(&ad.sin_addr, *pptr, sizeof(struct in_addr));
if (connect(sock, (struct sockaddr *) &ad, sizeof(ad)) == 0)
break; /* success */
- close(sock); /* don't use SockClose, no traffic yet */
+ fm_close(sock); /* don't use SockClose, no traffic yet */
memset(&ad, 0, sizeof(ad));
ad.sin_family = AF_INET;
}
if(*pptr == NULL)
{
int olderr = errno;
- close(sock); /* don't use SockClose, no traffic yet */
+ fm_close(sock); /* don't use SockClose, no traffic yet */
h_errno = 0;
errno = olderr;
return -1;
}
}
+
return(sock);
}
#endif /* INET6_ENABLE */
}
#ifdef SSL_ENABLE
-#include "ssl.h"
-#include "err.h"
-#include "pem.h"
-#include "x509.h"
+#include "openssl/ssl.h"
+#include "openssl/err.h"
+#include "openssl/pem.h"
+#include "openssl/x509.h"
static SSL_CTX *_ctx = NULL;
static SSL *_ssl_context[FD_SETSIZE];
if( NULL != ( ssl = SSLGetContext( sock ) ) )
n = SSL_write(ssl, buf, len);
else
- n = write(sock, buf, len);
+ n = fm_write(sock, buf, len);
#else
- n = write(sock, buf, len);
+ n = fm_write(sock, buf, len);
#endif
if (n <= 0)
return -1;
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:
newline = bp;
}
} else {
- if ((n = recv(sock, bp, len, MSG_PEEK)) <= 0)
+ if ((n = fm_peek(sock, bp, len)) <= 0)
return(-1);
if ((newline = memchr(bp, '\n', n)) != NULL)
n = newline - bp + 1;
- if ((n = read(sock, bp, n)) == -1)
+ if ((n = fm_read(sock, bp, n)) == -1)
return(-1);
}
#else
- if ((n = recv(sock, bp, len, MSG_PEEK)) <= 0)
- return(-1);
+
+#ifdef __BEOS__
+ if ((n = fm_read(sock, bp, 1)) <= 0)
+#else
+ if ((n = fm_peek(sock, bp, len)) <= 0)
+#endif
+ return (-1);
if ((newline = memchr(bp, '\n', n)) != NULL)
n = newline - bp + 1;
- if ((n = read(sock, bp, n)) == -1)
+#ifndef __BEOS__
+ if ((n = fm_read(sock, bp, n)) == -1)
return(-1);
+#endif /* __BEOS__ */
#endif
bp += n;
len -= n;
return 0; /* Give him a '\0' character */
}
} else {
- n = recv(sock, &ch, 1, MSG_PEEK);
+ n = fm_peek(sock, &ch, 1);
}
#else
- n = recv(sock, &ch, 1, MSG_PEEK);
-#endif
+
+ n = fm_peek(sock, &ch, 1);
+
+#endif /* SSL_ENABLE */
if (n == -1)
return -1;
- else
- return(ch);
+
+#ifdef __BEOS__
+ peeked = ch;
+#endif
+ return(ch);
}
#ifdef SSL_ENABLE
report(stdout, "Server CommonName: %s\n", cbuf );
/* Should we have some wildcarding here? */
if ( NULL != _ssl_server_cname
- && 0 != strcmp( cbuf, _ssl_server_cname ) ) {
+ && 0 != strcasecmp( cbuf, _ssl_server_cname ) ) {
report(stdout,
"Server CommonName mismatch: %s != %s\n",
cbuf, _ssl_server_cname );
switch (ctx->error) {
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
- report(stdout, "unknown issuer= %s", buf);
+ report(stdout, _("unknown issuer= %s"), buf);
break;
case X509_V_ERR_CERT_NOT_YET_VALID:
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
- report(stderr, "Server Certificate not yet valid");
+ report(stderr, _("Server Certificate not yet valid"));
break;
case X509_V_ERR_CERT_HAS_EXPIRED:
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
- report(stderr, "Server Certificate expired");
+ report(stderr, _("Server Certificate expired"));
break;
}
/* We are not requiring or validating server or issuer id's as yet */
int SockClose(int sock)
/* close a socket gracefully */
{
- char ch;
#ifdef SSL_ENABLE
SSL *ssl;
}
#endif
- /* Half-close the connection first so the other end gets notified.
+#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
+ * <jtnews@bellatlantic.net>, 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 <FIN>).
- */
- if (shutdown(sock, 1) == SUCCESS)
+ * TCP <FIN>). */
+ 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 (recv(sock, &ch, 1, MSG_PEEK) > 0)
- while (read(sock, &ch, 1) > 0)
+ 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(close(sock)); /* this is guarded */
+ return(fm_close(sock)); /* this is guarded */
}
#ifdef MAIN