X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/5dd6771b28c257af405d7248639ed0e3bcdce38b..f345b9b480296b4b6a8469d6221752893c5d1420:/uip/popsbr.c diff --git a/uip/popsbr.c b/uip/popsbr.c index 3ac88be4..ccc76c7c 100644 --- a/uip/popsbr.c +++ b/uip/popsbr.c @@ -9,27 +9,20 @@ #include #include -#if defined(NNTP) && !defined(PSHSBR) -# undef NNTP -#endif - -#ifdef NNTP /* building pshsbr.o from popsbr.c */ -# include -#endif /* NNTP */ - -#if !defined(NNTP) && defined(APOP) -# include -#endif - #ifdef CYRUS_SASL # include # include +# if SASL_VERSION_FULL < 0x020125 + /* Cyrus SASL 2.1.25 introduced the sasl_callback_ft prototype, + which has an explicit void parameter list, according to best + practice. So we need to cast to avoid compile warnings. + Provide this prototype for earlier versions. */ + typedef int (*sasl_callback_ft)(); +# endif /* SASL_VERSION_FULL < 0x020125 */ #endif /* CYRUS_SASL */ #include #include -#include -#include #define TRM "." #define TRMLEN (sizeof TRM - 1) @@ -42,21 +35,6 @@ char response[BUFSIZ]; static FILE *input; static FILE *output; -#define targ_t char * - -#if !defined(NNTP) && defined(MPOP) -# define command pop_command -# define multiline pop_multiline -#endif - -#ifdef NNTP -# ifdef BPOP /* stupid */ -static int xtnd_last = -1; -static int xtnd_first = 0; -static char xtnd_name[512]; /* INCREDIBLE HACK!! */ -# endif -#endif /* NNTP */ - #ifdef CYRUS_SASL static sasl_conn_t *conn; /* SASL connection state */ static int sasl_complete = 0; /* Has sasl authentication succeeded? */ @@ -66,13 +44,14 @@ static int sasl_get_user(void *, int, const char **, unsigned *); static int sasl_get_pass(sasl_conn_t *, void *, int, sasl_secret_t **); struct pass_context { char *user; + char *password; char *host; }; static sasl_callback_t callbacks[] = { - { SASL_CB_USER, sasl_get_user, NULL }, + { SASL_CB_USER, (sasl_callback_ft) sasl_get_user, NULL }, #define POP_SASL_CB_N_USER 0 - { SASL_CB_PASS, sasl_get_pass, NULL }, + { SASL_CB_PASS, (sasl_callback_ft) sasl_get_pass, NULL }, #define POP_SASL_CB_N_PASS 1 { SASL_CB_LOG, NULL, NULL }, { SASL_CB_LIST_END, NULL, NULL }, @@ -86,15 +65,9 @@ static sasl_callback_t callbacks[] = { /* * static prototypes */ -#if !defined(NNTP) && defined(APOP) -static char *pop_auth (char *, char *); -#endif -#if defined(NNTP) || !defined(MPOP) -/* otherwise they are not static functions */ static int command(const char *, ...); static int multiline(void); -#endif #ifdef CYRUS_SASL static int pop_auth_sasl(char *, char *, char *); @@ -107,50 +80,6 @@ static int sasl_getline (char *, int, FILE *); static int putline (char *, FILE *); -#if !defined(NNTP) && defined(APOP) -static char * -pop_auth (char *user, char *pass) -{ - int len, buflen; - char *cp, *lp; - unsigned char *dp, *ep, digest[16]; - MD5_CTX mdContext; - static char buffer[BUFSIZ]; - - if ((cp = strchr (response, '<')) == NULL - || (lp = strchr (cp, '>')) == NULL) { - snprintf (buffer, sizeof(buffer), "APOP not available: %s", response); - strncpy (response, buffer, sizeof(response)); - return NULL; - } - - *(++lp) = '\0'; - snprintf (buffer, sizeof(buffer), "%s%s", cp, pass); - - MD5Init (&mdContext); - MD5Update (&mdContext, (unsigned char *) buffer, - (unsigned int) strlen (buffer)); - MD5Final (digest, &mdContext); - - cp = buffer; - buflen = sizeof(buffer); - - snprintf (cp, buflen, "%s ", user); - len = strlen (cp); - cp += len; - buflen -= len; - - for (ep = (dp = digest) + sizeof(digest) / sizeof(digest[0]); dp < ep; ) { - snprintf (cp, buflen, "%02x", *dp++ & 0xff); - cp += 2; - buflen -= 2; - } - *cp = '\0'; - - return buffer; -} -#endif /* !NNTP && APOP */ - #ifdef CYRUS_SASL /* * This function implements the AUTH command for various SASL mechanisms @@ -160,12 +89,20 @@ pop_auth (char *user, char *pass) * layer. */ +#define CHECKB64SIZE(insize, outbuf, outsize) \ + { size_t wantout = (((insize + 2) / 3) * 4) + 32; \ + if (wantout > outsize) { \ + outbuf = mh_xrealloc(outbuf, outsize = wantout); \ + } \ + } + int pop_auth_sasl(char *user, char *host, char *mech) { int result, status, sasl_capability = 0; unsigned int buflen, outlen; - char server_mechs[256], *buf, outbuf[BUFSIZ]; + char server_mechs[256], *buf, *outbuf = NULL; + size_t outbufsize = 0; const char *chosen_mech; sasl_security_properties_t secprops; struct pass_context p_context; @@ -280,10 +217,13 @@ pop_auth_sasl(char *user, char *host, char *mech) } if (buflen) { - status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL); + CHECKB64SIZE(buflen, outbuf, outbufsize); + status = sasl_encode64(buf, buflen, outbuf, outbufsize, NULL); if (status != SASL_OK) { snprintf(response, sizeof(response), "SASL base64 encode " "failed: %s", sasl_errstring(status, NULL, NULL)); + if (outbuf) + free(outbuf); return NOTOK; } @@ -292,8 +232,13 @@ pop_auth_sasl(char *user, char *host, char *mech) status = command("AUTH %s", chosen_mech); while (result == SASL_CONTINUE) { - if (status == NOTOK) + size_t inlen; + + if (status == NOTOK) { + if (outbuf) + free(outbuf); return NOTOK; + } /* * If we get a "+OK" prefix to our response, then we should @@ -312,16 +257,31 @@ pop_auth_sasl(char *user, char *host, char *mech) command("*"); snprintf(response, sizeof(response), "Malformed authentication message from server"); + if (outbuf) + free(outbuf); return NOTOK; } + /* + * For decode, it will always be shorter, so just make sure + * that outbuf is as at least as big as the encoded response. + */ + + inlen = strlen(response + 2); + + if (inlen > outbufsize) { + outbuf = mh_xrealloc(outbuf, outbufsize = inlen); + } + result = sasl_decode64(response + 2, strlen(response + 2), - outbuf, sizeof(outbuf), &outlen); + outbuf, outbufsize, &outlen); if (result != SASL_OK) { command("*"); snprintf(response, sizeof(response), "SASL base64 decode " "failed: %s", sasl_errstring(result, NULL, NULL)); + if (outbuf) + free(outbuf); return NOTOK; } @@ -332,21 +292,30 @@ pop_auth_sasl(char *user, char *host, char *mech) command("*"); snprintf(response, sizeof(response), "SASL client negotiaton " "failed: %s", sasl_errdetail(conn)); + if (outbuf) + free(outbuf); return NOTOK; } - status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL); + CHECKB64SIZE(buflen, outbuf, outbufsize); + + status = sasl_encode64(buf, buflen, outbuf, outbufsize, NULL); if (status != SASL_OK) { command("*"); snprintf(response, sizeof(response), "SASL base64 encode " "failed: %s", sasl_errstring(status, NULL, NULL)); + if (outbuf) + free(outbuf); return NOTOK; } status = command(outbuf); } + if (outbuf) + free(outbuf); + /* * If we didn't get a positive final response, then error out * (that probably means we failed an authorization check). @@ -421,20 +390,33 @@ static int sasl_get_pass(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret) { struct pass_context *p_context = (struct pass_context *) context; - char *pass = NULL; + struct nmh_creds creds = { 0, 0, 0 }; int len; + NMH_UNUSED (conn); + if (! psecret || id != SASL_CB_PASS) return SASL_BADPARAM; - ruserpass(p_context->user, &(p_context->host), &pass); + if (creds.password == NULL) { + /* + * Pass the 0 third argument to nmh_get_credentials() so + * that the default password isn't used. With legacy/.netrc + * credentials support, we'll only get here if the -user + * switch to send(1)/post(8) wasn't used. + */ + if (nmh_get_credentials (p_context->host, p_context->user, 0, &creds) + != OK) { + return SASL_BADPARAM; + } + } - len = strlen(pass); + len = strlen (creds.password); *psecret = (sasl_secret_t *) mh_xmalloc(sizeof(sasl_secret_t) + len); (*psecret)->len = len; - strcpy((char *) (*psecret)->data, pass); + strcpy((char *) (*psecret)->data, creds.password); return SASL_OK; } @@ -485,34 +467,33 @@ parse_proxy(char *proxy, char *host) } else if (!isspace(*cur)) *c++ = *cur; } + *c = '\0'; *++p = NULL; return pargv; } int -pop_init (char *host, char *user, char *pass, char *proxy, int snoop, - int rpop, int kpop, int sasl, char *mech) +pop_init (char *host, char *port, char *user, char *pass, char *proxy, + int snoop, int sasl, char *mech) { int fd1, fd2; char buffer[BUFSIZ]; - -#ifdef APOP - int apop; - - if ((apop = rpop) < 0) - rpop = 0; -#endif +#ifndef CYRUS_SASL + NMH_UNUSED (sasl); + NMH_UNUSED (mech); +#endif /* ! CYRUS_SASL */ 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); + if (pipe(inpipe) < 0) { + adios ("inpipe", "pipe"); + } + if (pipe(outpipe) < 0) { + adios ("outpipe", "pipe"); + } pid=fork(); if (pid==0) { @@ -546,32 +527,15 @@ pop_init (char *host, char *user, char *pass, char *proxy, int snoop, /* we read on fd1 */ fd1=inpipe[0]; - /* and write on fd2 */ fd2=outpipe[1]; } else { -#ifndef NNTP - if ( kpop ) { -# ifdef KPOP - 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"); + if ((fd1 = client (host, port ? port : "pop3", response, + sizeof(response), snoop)) == NOTOK) { return NOTOK; -# endif /* KPOP */ - } else { - if ((fd1 = client (host, POPSERVICE, response, sizeof(response), snoop)) == NOTOK) { - return NOTOK; - } } -#else /* NNTP */ - if ((fd1 = client (host, "nntp", response, sizeof(response), snoop)) == NOTOK) - return NOTOK; -#endif if ((fd2 = dup (fd1)) == NOTOK) { char *s; @@ -586,11 +550,7 @@ pop_init (char *host, char *user, char *pass, char *proxy, int snoop, return NOTOK; } } -#ifndef NNTP if (pop_set (fd1, fd2, snoop) == NOTOK) -#else /* NNTP */ - if (pop_set (fd1, fd2, snoop, (char *)0) == NOTOK) -#endif /* NNTP */ return NOTOK; SIGNAL (SIGPIPE, SIG_IGN); @@ -599,18 +559,7 @@ pop_init (char *host, char *user, char *pass, char *proxy, int snoop, case OK: if (poprint) fprintf (stderr, "<--- %s\n", response); -#ifndef NNTP if (*response == '+') { -# ifndef KPOP -# ifdef APOP - if (apop < 0) { - char *cp = pop_auth (user, pass); - - if (cp && command ("APOP %s", cp) != NOTOK) - return OK; - } - else -# endif /* APOP */ # ifdef CYRUS_SASL if (sasl) { if (pop_auth_sasl(user, host, mech) != NOTOK) @@ -618,21 +567,10 @@ pop_init (char *host, char *user, char *pass, char *proxy, int snoop, } else # endif /* CYRUS_SASL */ if (command ("USER %s", user) != NOTOK - && command ("%s %s", rpop ? "RPOP" : (pophack++, "PASS"), + && command ("%s %s", (pophack++, "PASS"), pass) != NOTOK) return OK; -# else /* KPOP */ - if (command ("USER %s", user) != NOTOK - && command ("PASS %s", pass) != NOTOK) - return OK; -# endif - } -#else /* NNTP */ - if (*response < CHAR_ERR) { - command ("MODE READER"); - return OK; } -#endif strncpy (buffer, response, sizeof(buffer)); command ("QUIT"); strncpy (response, buffer, sizeof(response)); @@ -650,22 +588,10 @@ pop_init (char *host, char *user, char *pass, char *proxy, int snoop, return NOTOK; /* NOTREACHED */ } -#ifdef NNTP -int -pop_set (int in, int out, int snoop, char *myname) -#else int pop_set (int in, int out, int snoop) -#endif { -#ifdef NNTP - if (myname && *myname) { - /* interface from bbc to msh */ - strncpy (xtnd_name, myname, sizeof(xtnd_name)); - } -#endif /* NNTP */ - if ((input = fdopen (in, "r")) == NULL || (output = fdopen (out, "w")) == NULL) { strncpy (response, "fdopen failed on connection descriptor", sizeof(response)); @@ -700,69 +626,24 @@ pop_fd (char *in, int inlen, char *out, int outlen) int pop_stat (int *nmsgs, int *nbytes) { -#ifdef NNTP - char **ap; -#endif /* NNTP */ -#ifndef NNTP if (command ("STAT") == NOTOK) return NOTOK; *nmsgs = *nbytes = 0; sscanf (response, "+OK %d %d", nmsgs, nbytes); -#else /* NNTP */ - if (xtnd_last < 0) { /* in msh, xtnd_name is set from myname */ - if (command("GROUP %s", xtnd_name) == NOTOK) - return NOTOK; - - ap = brkstring (response, " ", "\n"); /* "211 nart first last ggg" */ - xtnd_first = atoi (ap[2]); - xtnd_last = atoi (ap[3]); - } - - /* nmsgs is not the real nart, but an incredible simuation */ - if (xtnd_last > 0) - *nmsgs = xtnd_last - xtnd_first + 1; /* because of holes... */ - else - *nmsgs = 0; - *nbytes = xtnd_first; /* for subtracting offset in msh() */ -#endif /* NNTP */ - return OK; } -#ifdef NNTP -int -pop_exists (int (*action)()) -{ -#ifdef XMSGS /* hacked into NNTP 1.5 */ - if (traverse (action, "XMSGS %d-%d", (targ_t) xtnd_first, (targ_t) xtnd_last) == OK) - return OK; -#endif - /* provided by INN 1.4 */ - if (traverse (action, "LISTGROUP") == OK) - return OK; - return traverse (action, "XHDR NONAME %d-%d", (targ_t) xtnd_first, (targ_t) xtnd_last); -} -#endif /* NNTP */ - -#ifdef BPOP -int -pop_list (int msgno, int *nmsgs, int *msgs, int *bytes, int *ids) -#else int pop_list (int msgno, int *nmsgs, int *msgs, int *bytes) -#endif { int i; -#ifndef BPOP int *ids = NULL; -#endif if (msgno) { -#ifndef NNTP if (command ("LIST %d", msgno) == NOTOK) return NOTOK; *msgs = *bytes = 0; @@ -772,18 +653,9 @@ pop_list (int msgno, int *nmsgs, int *msgs, int *bytes) } else sscanf (response, "+OK %d %d", msgs, bytes); -#else /* NNTP */ - *msgs = *bytes = 0; - if (command ("STAT %d", msgno) == NOTOK) - return NOTOK; - if (ids) { - *ids = msgno; - } -#endif /* NNTP */ return OK; } -#ifndef NNTP if (command ("LIST") == NOTOK) return NOTOK; @@ -814,20 +686,13 @@ pop_list (int msgno, int *nmsgs, int *msgs, int *bytes) case OK: break; } -#else /* NNTP */ - return NOTOK; -#endif /* NNTP */ } int pop_retr (int msgno, int (*action)(char *)) { -#ifndef NNTP - return traverse (action, "RETR %d", (targ_t) msgno); -#else /* NNTP */ - return traverse (action, "ARTICLE %d", (targ_t) msgno); -#endif /* NNTP */ + return traverse (action, "RETR %d", msgno); } @@ -876,15 +741,6 @@ pop_noop (void) } -#if defined(MPOP) && !defined(NNTP) -int -pop_last (void) -{ - return command ("LAST"); -} -#endif - - int pop_rset (void) { @@ -895,76 +751,10 @@ pop_rset (void) int pop_top (int msgno, int lines, int (*action)(char *)) { -#ifndef NNTP - return traverse (action, "TOP %d %d", (targ_t) msgno, (targ_t) lines); -#else /* NNTP */ - return traverse (action, "HEAD %d", (targ_t) msgno); -#endif /* NNTP */ + return traverse (action, "TOP %d %d", msgno, lines); } -#ifdef BPOP -int -pop_xtnd (int (*action)(), char *fmt, ...) -{ - int result; - va_list ap; - char buffer[BUFSIZ]; - -#ifdef NNTP - char **ap; -#endif - - va_start(ap, fmt); -#ifndef NNTP - /* needs to be fixed... va_end needs to be added */ - snprintf (buffer, sizeof(buffer), "XTND %s", fmt); - result = traverse (action, buffer, a, b, c, d); - va_end(ap); - return result; -#else /* NNTP */ - snprintf (buffer, sizeof(buffer), fmt, a, b, c, d); - ap = brkstring (buffer, " ", "\n"); /* a hack, i know... */ - - 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 (!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 (!mh_strcasecmp (ap[0], "bboards")) { - - if (ap[1]) { /* XTND "BBOARDS group" */ - snprintf (xtnd_name, sizeof(xtnd_name), "%s", ap[1]); /* save the name */ - if (command("GROUP %s", xtnd_name) == NOTOK) - return NOTOK; - - /* action must ignore extra args */ - strncpy (buffer, response, sizeof(buffer)); - ap = brkstring (response, " ", "\n");/* "211 nart first last g" */ - xtnd_first = atoi (ap[2]); - xtnd_last = atoi (ap[3]); - - (*action) (buffer); - return OK; - - } else { /* XTND "BBOARDS" */ - return traverse (action, "LIST", a, b, c, d); - } - } - return NOTOK; /* unknown XTND command */ -#endif /* NNTP */ -} -#endif /* BPOP */ - - int pop_quit (void) { @@ -991,9 +781,6 @@ pop_done (void) } -#if !defined(MPOP) || defined(NNTP) -static -#endif int command(const char *fmt, ...) { @@ -1011,9 +798,10 @@ command(const char *fmt, ...) static int vcommand (const char *fmt, va_list ap) { - char *cp, buffer[BUFSIZ]; + char *cp, buffer[65536]; vsnprintf (buffer, sizeof(buffer), fmt, ap); + if (poprint) { #ifdef CYRUS_SASL if (sasl_ssf) @@ -1043,11 +831,7 @@ vcommand (const char *fmt, va_list ap) case OK: if (poprint) fprintf (stderr, "<--- %s\n", response); -#ifndef NNTP return (*response == '+' ? OK : NOTOK); -#else /* NNTP */ - return (*response < CHAR_ERR ? OK : NOTOK); -#endif /* NNTP */ case NOTOK: case DONE: @@ -1060,13 +844,8 @@ vcommand (const char *fmt, va_list ap) } -#if defined(MPOP) && !defined(NNTP) int multiline (void) -#else -static int -multiline (void) -#endif { char buffer[BUFSIZ + TRMLEN]; @@ -1121,7 +900,7 @@ sasl_getline (char *s, int n, FILE *iop) *p = 0; if (*--p == '\n') *p = 0; - if (*--p == '\r') + if (p > s && *--p == '\r') *p = 0; return OK; @@ -1158,7 +937,9 @@ putline (char *s, FILE *iop) return NOTOK; } - fwrite(buf, buflen, 1, iop); + if (fwrite(buf, buflen, 1, iop) < 1) { + advise ("putline", "fwrite"); + } } #endif /* CYRUS_SASL */ @@ -1180,7 +961,7 @@ static int sasl_fgetc(FILE *f) { static unsigned char *buffer = NULL, *ptr; - static int size = 0; + static unsigned int size = 0; static int cnt = 0; unsigned int retbufsize = 0; int cc, result;