*/
#include <h/mh.h>
+#include <h/utils.h>
extern int client(char *args, char *protocol, char *service, int rproto,
char *response, int len_response);
#endif
#ifdef CYRUS_SASL
-# include <sasl.h>
+# include <sasl/sasl.h>
+# include <sasl/saslutil.h>
#endif /* CYRUS_SASL */
#include <h/popsbr.h>
#define POP_SASL_CB_N_USER 0
{ SASL_CB_PASS, sasl_get_pass, NULL },
#define POP_SASL_CB_N_PASS 1
+ { SASL_CB_LOG, NULL, NULL },
{ SASL_CB_LIST_END, NULL, NULL },
};
#else /* CYRUS_SASL */
int
pop_auth_sasl(char *user, char *host, char *mech)
{
- int result, status, sasl_capability = 0, outlen;
- unsigned int buflen;
+ int result, status, sasl_capability = 0;
+ unsigned int buflen, outlen;
char server_mechs[256], *buf, outbuf[BUFSIZ];
const char *chosen_mech;
sasl_security_properties_t secprops;
- sasl_external_properties_t extprops;
struct pass_context p_context;
sasl_ssf_t *ssf;
int *moutbuf;
return NOTOK;
}
- result = sasl_client_new("pop", host, NULL, SASL_SECURITY_LAYER, &conn);
+ result = sasl_client_new("pop", host, NULL, NULL, NULL, 0, &conn);
if (result != SASL_OK) {
snprintf(response, sizeof(response), "SASL client initialization "
memset(&secprops, 0, sizeof(secprops));
secprops.maxbufsize = BUFSIZ;
secprops.max_ssf = UINT_MAX;
- memset(&extprops, 0, sizeof(extprops));
result = sasl_setprop(conn, SASL_SEC_PROPS, &secprops);
if (result != SASL_OK) {
snprintf(response, sizeof(response), "SASL security property "
- "initialization failed: %s",
- sasl_errstring(result, NULL, NULL));
- return NOTOK;
- }
-
- result = sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops);
-
- if (result != SASL_OK) {
- snprintf(response, sizeof(response), "SASL external property "
- "initialization failed: %s",
- sasl_errstring(result, NULL, NULL));
+ "initialization failed: %s", sasl_errdetail(conn));
return NOTOK;
}
* and get out a possible initial challenge
*/
- result = sasl_client_start(conn, mech ? mech : server_mechs,
- NULL, NULL, &buf, &buflen, &chosen_mech);
+ result = sasl_client_start(conn,
+ (const char *) (mech ? mech : server_mechs),
+ NULL, (const char **) &buf,
+ &buflen, &chosen_mech);
if (result != SASL_OK && result != SASL_CONTINUE) {
snprintf(response, sizeof(response), "SASL client start failed: %s",
- sasl_errstring(result, NULL, NULL));
+ sasl_errdetail(conn));
return NOTOK;
}
if (buflen) {
status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL);
- free(buf);
if (status != SASL_OK) {
snprintf(response, sizeof(response), "SASL base64 encode "
"failed: %s", sasl_errstring(status, NULL, NULL));
}
result = sasl_decode64(response + 2, strlen(response + 2),
- outbuf, &outlen);
+ outbuf, sizeof(outbuf), &outlen);
if (result != SASL_OK) {
command("*");
return NOTOK;
}
- result = sasl_client_step(conn, outbuf, outlen, NULL, &buf, &buflen);
+ result = sasl_client_step(conn, outbuf, outlen, NULL,
+ (const char **) &buf, &buflen);
if (result != SASL_OK && result != SASL_CONTINUE) {
command("*");
snprintf(response, sizeof(response), "SASL client negotiaton "
- "failed: %s", sasl_errstring(result, NULL, NULL));
+ "failed: %s", sasl_errdetail(conn));
return NOTOK;
}
status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL);
- free(buf);
if (status != SASL_OK) {
command("*");
return NOTOK;
/*
- * Depending on the mechanism, we might need to call sasl_client_step()
- * one more time. Do that now.
- */
-
- result = sasl_client_step(conn, NULL, 0, NULL, &buf, &buflen);
-
- if (result != SASL_OK) {
- snprintf(response, sizeof(response), "SASL final client negotiaton "
- "failed: %s", sasl_errstring(result, NULL, NULL));
- return NOTOK;
- }
-
- /*
* We _should_ be okay now. Get a few properties now that negotiation
* has completed.
*/
- result = sasl_getprop(conn, SASL_MAXOUTBUF, (void **) &moutbuf);
+ result = sasl_getprop(conn, SASL_MAXOUTBUF, (const void **) &moutbuf);
if (result != SASL_OK) {
snprintf(response, sizeof(response), "Cannot retrieve SASL negotiated "
- "output buffer size: %s", sasl_errstring(result, NULL, NULL));
+ "output buffer size: %s", sasl_errdetail(conn));
return NOTOK;
}
maxoutbuf = *moutbuf;
- result = sasl_getprop(conn, SASL_SSF, (void **) &ssf);
+ result = sasl_getprop(conn, SASL_SSF, (const void **) &ssf);
sasl_ssf = *ssf;
if (result != SASL_OK) {
snprintf(response, sizeof(response), "Cannot retrieve SASL negotiated "
- "security strength factor: %s",
- sasl_errstring(result, NULL, NULL));
+ "security strength factor: %s", sasl_errdetail(conn));
return NOTOK;
}
len = strlen(pass);
- *psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len);
-
- if (! *psecret)
- return SASL_NOMEM;
+ *psecret = (sasl_secret_t *) mh_xmalloc(sizeof(sasl_secret_t) + len);
(*psecret)->len = len;
- strcpy((*psecret)->data, pass);
+ strcpy((char *) (*psecret)->data, pass);
return SASL_OK;
}
#endif /* CYRUS_SASL */
+
+/*
+ * Split string containing proxy command into an array of arguments
+ * suitable for passing to exec. Returned array must be freed. Shouldn't
+ * be possible to call this with host set to NULL.
+ */
+char **
+parse_proxy(char *proxy, char *host)
+{
+ char **pargv, **p;
+ int pargc = 2;
+ int hlen = strlen(host);
+ int plen = 1;
+ char *cur, *pro;
+ char *c;
+
+ /* skip any initial space */
+ for (pro = proxy; isspace(*pro); pro++)
+ continue;
+
+ /* calculate required size for argument array */
+ for (cur = pro; *cur; cur++) {
+ if (isspace(*cur) && cur[1] && !isspace(cur[1]))
+ plen++, pargc++;
+ else if (*cur == '%' && cur[1] == 'h') {
+ plen += hlen;
+ cur++;
+ } else if (!isspace(*cur))
+ plen++;
+ }
+
+ /* put together list of arguments */
+ p = pargv = mh_xmalloc(pargc * sizeof(char *));
+ c = *pargv = mh_xmalloc(plen * sizeof(char));
+ for (cur = pro; *cur; cur++) {
+ if (isspace(*cur) && cur[1] && !isspace(cur[1])) {
+ *c++ = '\0';
+ *++p = c;
+ } else if (*cur == '%' && cur[1] == 'h') {
+ strcpy (c, host);
+ c += hlen;
+ cur++;
+ } else if (!isspace(*cur))
+ *c++ = *cur;
+ }
+ *++p = NULL;
+ return pargv;
+}
+
int
-pop_init (char *host, char *user, char *pass, int snoop, int rpop, int kpop,
- int sasl, char *mech)
+pop_init (char *host, char *user, char *pass, char *proxy, int snoop,
+ int rpop, int kpop, int sasl, char *mech)
{
int fd1, fd2;
char buffer[BUFSIZ];
rpop = 0;
#endif
+ if (proxy && *proxy) {
+ int pid;
+ int inpipe[2]; /* for reading from the server */
+ int outpipe[2]; /* for sending to the server */
+
+ /* first give up any root priviledges we may have for rpop */
+ setuid(getuid());
+
+ pipe(inpipe);
+ pipe(outpipe);
+
+ pid=fork();
+ if (pid==0) {
+ char **argv;
+
+ /* in child */
+ close(0);
+ close(1);
+ dup2(outpipe[0],0); /* connect read end of connection */
+ dup2(inpipe[1], 1); /* connect write end of connection */
+ if(inpipe[0]>1) close(inpipe[0]);
+ if(inpipe[1]>1) close(inpipe[1]);
+ if(outpipe[0]>1) close(outpipe[0]);
+ if(outpipe[1]>1) close(outpipe[1]);
+
+ /* run the proxy command */
+ argv=parse_proxy(proxy, host);
+ execvp(argv[0],argv);
+
+ perror(argv[0]);
+ close(0);
+ close(1);
+ free(*argv);
+ free(argv);
+ exit(10);
+ }
+
+ /* okay in the parent we do some stuff */
+ close(inpipe[1]); /* child uses this */
+ close(outpipe[0]); /* child uses this */
+
+ /* we read on fd1 */
+ fd1=inpipe[0];
+
+ /* and write on fd2 */
+ fd2=outpipe[1];
+
+ } else {
+
#ifndef NNTP
+ if ( kpop ) {
# ifdef KPOP
- if ( kpop ) {
- snprintf (buffer, sizeof(buffer), "%s/%s", KPOP_PRINCIPAL, "kpop");
- if ((fd1 = client (host, "tcp", buffer, 0, response, sizeof(response))) == NOTOK) {
- return NOTOK;
- }
- } else {
-# endif /* KPOP */
- if ((fd1 = client (host, "tcp", POPSERVICE, rpop, response, sizeof(response))) == NOTOK) {
+ snprintf (buffer, sizeof(buffer), "%s/%s", KPOP_PRINCIPAL, "kpop");
+ if ((fd1 = client (host, "tcp", buffer, 0, response, sizeof(response))) == NOTOK) {
+ return NOTOK;
+ }
+# else /* KPOP */
+ snprintf (response, sizeof(response), "this version of nmh compiled without KPOP support");
return NOTOK;
- }
-# ifdef KPOP
- }
# endif /* KPOP */
+ } else {
+ if ((fd1 = client (host, "tcp", POPSERVICE, rpop, response, sizeof(response))) == NOTOK) {
+ return NOTOK;
+ }
+ }
#else /* NNTP */
- if ((fd1 = client (host, "tcp", "nntp", rpop, response, sizeof(response))) == NOTOK)
- return NOTOK;
+ if ((fd1 = client (host, "tcp", "nntp", rpop, response, sizeof(response))) == NOTOK)
+ return NOTOK;
#endif
- if ((fd2 = dup (fd1)) == NOTOK) {
- char *s;
+ if ((fd2 = dup (fd1)) == NOTOK) {
+ char *s;
- if ((s = strerror(errno)))
- snprintf (response, sizeof(response),
- "unable to dup connection descriptor: %s", s);
- else
- snprintf (response, sizeof(response),
- "unable to dup connection descriptor: unknown error");
- close (fd1);
- return NOTOK;
+ if ((s = strerror(errno)))
+ snprintf (response, sizeof(response),
+ "unable to dup connection descriptor: %s", s);
+ else
+ snprintf (response, sizeof(response),
+ "unable to dup connection descriptor: unknown error");
+ close (fd1);
+ return NOTOK;
+ }
}
#ifndef NNTP
if (pop_set (fd1, fd2, snoop) == NOTOK)
snprintf (buffer, sizeof(buffer), fmt, a, b, c, d);
ap = brkstring (buffer, " ", "\n"); /* a hack, i know... */
- if (!strcasecmp(ap[0], "x-bboards")) { /* XTND "X-BBOARDS group */
+ if (!mh_strcasecmp(ap[0], "x-bboards")) { /* XTND "X-BBOARDS group */
/* most of these parameters are meaningless under NNTP.
* bbc.c was modified to set AKA and LEADERS as appropriate,
* the rest are left blank.
*/
return OK;
}
- if (!strcasecmp (ap[0], "archive") && ap[1]) {
+ if (!mh_strcasecmp (ap[0], "archive") && ap[1]) {
snprintf (xtnd_name, sizeof(xtnd_name), "%s", ap[1]); /* save the name */
xtnd_last = 0;
xtnd_first = 1; /* setup to fail in pop_stat */
return OK;
}
- if (!strcasecmp (ap[0], "bboards")) {
+ if (!mh_strcasecmp (ap[0], "bboards")) {
if (ap[1]) { /* XTND "BBOARDS group" */
snprintf (xtnd_name, sizeof(xtnd_name), "%s", ap[1]); /* save the name */
return NOTOK; /* unknown XTND command */
#endif /* NNTP */
}
-#endif BPOP
+#endif /* BPOP */
int
#endif /* CYRUS_SASL */
fprintf (stderr, "<--- %s\n", response);
}
-#endif DEBUG
+#endif /* DEBUG */
if (strncmp (buffer, TRM, TRMLEN) == 0) {
if (buffer[TRMLEN] == 0)
return DONE;
outbuf[sizeof(outbuf) - 3] = '\0'; /* Just in case */
strcat(outbuf, "\r\n");
- result = sasl_encode(conn, outbuf, strlen(outbuf), &buf, &buflen);
+ result = sasl_encode(conn, outbuf, strlen(outbuf),
+ (const char **) &buf, &buflen);
if (result != SASL_OK) {
snprintf(response, sizeof(response), "SASL encoding error: %s",
- sasl_errstring(result, NULL, NULL));
+ sasl_errdetail(conn));
return NOTOK;
}
fwrite(buf, buflen, 1, iop);
- free(buf);
}
#endif /* CYRUS_SASL */
} else {
- result = sasl_decode(conn, tmpbuf, cc, &retbuf, &retbufsize);
+ result = sasl_decode(conn, tmpbuf, cc,
+ (const char **) &retbuf, &retbufsize);
if (result != SASL_OK) {
snprintf(response, sizeof(response), "Error during SASL "
- "decoding: %s", sasl_errstring(result, NULL, NULL));
+ "decoding: %s", sasl_errdetail(conn));
return -2;
}
}
}
if (retbufsize > size) {
- buffer = realloc(buffer, retbufsize);
- if (!buffer) {
- snprintf(response, sizeof(response), "Error during realloc in "
- "read routine: %s", strerror(errno));
- return -2;
- }
+ buffer = mh_xrealloc(buffer, retbufsize);
size = retbufsize;
}
memcpy(buffer, retbuf, retbufsize);
ptr = buffer + 1;
cnt = retbufsize - 1;
- if (sasl_complete)
- free(retbuf);
return (int) buffer[0];
}