X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/83ffa51bdfbcf4e1f93e57fb64d57ddbeeeb2304..63621a81d16ab743de6b57d47578a9a2c670ad22:/uip/popsbr.c diff --git a/uip/popsbr.c b/uip/popsbr.c index 70d71044..a9319054 100644 --- a/uip/popsbr.c +++ b/uip/popsbr.c @@ -1,5 +1,4 @@ -/* - * popsbr.c -- POP client subroutines +/* popsbr.c -- POP client subroutines * * This code is Copyright (c) 2002, by the authors of nmh. See the * COPYRIGHT file in the root directory of the nmh distribution for @@ -13,12 +12,11 @@ #include #include +#include "sbr/base64.h" #define TRM "." -#define TRMLEN (sizeof TRM - 1) static int poprint = 0; -static int pophack = 0; char response[BUFSIZ]; static netsec_context *nsc = NULL; @@ -27,11 +25,12 @@ static netsec_context *nsc = NULL; * static prototypes */ -static int command(const char *, ...); +static int command(const char *, ...) CHECK_PRINTF(1, 2); static int multiline(void); -static int traverse (int (*)(char *), const char *, ...); -static int vcommand(const char *, va_list); +static int traverse(int (*)(void *, char *), void *closure, + const char *, ...) CHECK_PRINTF(3, 4); +static int vcommand(const char *, va_list) CHECK_PRINTF(1, 0); static int pop_getline (char *, int, netsec_context *); static int pop_sasl_callback(enum sasl_message_type, unsigned const char *, unsigned int, unsigned char **, unsigned int *, @@ -57,23 +56,16 @@ check_mech(char *server_mechs, size_t server_mechs_size) return NOTOK; } - while ((status = multiline()) != DONE) - switch (status) { - case NOTOK: + while ((status = multiline()) != DONE) { + if (status == NOTOK) return NOTOK; - break; - case DONE: /* Shouldn't be possible, but just in case */ - break; - case OK: - if (strncasecmp(response, "SASL ", 5) == 0) { - /* - * We've seen the SASL capability. Grab the mech list - */ - sasl_capability++; - strncpy(server_mechs, response + 5, server_mechs_size); - } - break; - } + + if (strncasecmp(response, "SASL ", 5) == 0) { + /* We've seen the SASL capability. Grab the mech list. */ + sasl_capability++; + strncpy(server_mechs, response + 5, server_mechs_size); + } + } if (!sasl_capability) { snprintf(response, sizeof(response), "POP server does not support " @@ -134,8 +126,8 @@ parse_proxy(char *proxy, char *host) } int -pop_init (char *host, char *port, char *user, char *pass, char *proxy, - int snoop, int sasl, char *mech, int tls, const char *oauth_svc) +pop_init (char *host, char *port, char *user, char *proxy, int snoop, + int sasl, char *mech, int tls, const char *oauth_svc) { int fd1, fd2; char buffer[BUFSIZ]; @@ -146,6 +138,8 @@ pop_init (char *host, char *port, char *user, char *pass, char *proxy, if (user) netsec_set_userid(nsc, user); + netsec_set_hostname(nsc, host); + if (oauth_svc != NULL) { if (netsec_set_oauth_service(nsc, oauth_svc) != OK) { snprintf(response, sizeof(response), "OAuth2 not supported"); @@ -213,8 +207,8 @@ pop_init (char *host, char *port, char *user, char *pass, char *proxy, netsec_set_fd(nsc, fd1, fd2); netsec_set_snoop(nsc, snoop); - if (tls) { - if (netsec_set_tls(nsc, 1, &errstr) != OK) { + if (tls & P_INITTLS) { + if (netsec_set_tls(nsc, 1, tls & P_NOVERIFY, &errstr) != OK) { snprintf(response, sizeof(response), "%s", errstr); free(errstr); return NOTOK; @@ -228,8 +222,8 @@ pop_init (char *host, char *port, char *user, char *pass, char *proxy, } if (sasl) { - if (netsec_set_sasl_params(nsc, host, "pop", mech, - pop_sasl_callback, &errstr) != OK) { + if (netsec_set_sasl_params(nsc, "pop", mech, pop_sasl_callback, + &errstr) != OK) { snprintf(response, sizeof(response), "%s", errstr); free(errstr); return NOTOK; @@ -241,6 +235,8 @@ pop_init (char *host, char *port, char *user, char *pass, char *proxy, if (poprint) fprintf (stderr, "<--- %s\n", response); if (*response == '+') { + nmh_creds_t creds; + if (sasl) { char server_mechs[256]; if (check_mech(server_mechs, sizeof(server_mechs)) != OK) @@ -253,22 +249,32 @@ pop_init (char *host, char *port, char *user, char *pass, char *proxy, return NOTOK; } return OK; - } else - if (command ("USER %s", user) != NOTOK - && command ("%s %s", (pophack++, "PASS"), - pass) != NOTOK) - return OK; + } + + if (!(creds = nmh_get_credentials(host, user))) + return NOTOK; + if (command ("USER %s", nmh_cred_get_user(creds)) + != NOTOK) { + if (command("PASS %s", nmh_cred_get_password(creds)) + != NOTOK) { + nmh_credentials_free(creds); + return OK; + } + } + nmh_credentials_free(creds); } strncpy (buffer, response, sizeof(buffer)); command ("QUIT"); strncpy (response, buffer, sizeof(response)); - /* and fall */ + /* FALLTHRU */ case NOTOK: case DONE: - if (poprint) - fprintf (stderr, "%s\n", response); - netsec_shutdown(nsc, 1); + if (poprint) { + fputs(response, stderr); + putc('\n', stderr); + } + netsec_shutdown(nsc); nsc = NULL; return NOTOK; } @@ -347,6 +353,7 @@ pop_sasl_callback(enum sasl_message_type mtype, unsigned const char *indata, rc = netsec_printf(nsc, errstr, "AUTH %s %s\r\n", mech, b64data); free(b64data); + netsec_set_snoop_callback(nsc, NULL, NULL); if (rc != OK) return NOTOK; if (netsec_flush(nsc, errstr) != OK) @@ -382,10 +389,12 @@ pop_sasl_callback(enum sasl_message_type mtype, unsigned const char *indata, *outdata = NULL; *outdatalen = 0; } else { - rc = decodeBase64(line + 2, (const char **) outdata, &len, 0, NULL); + rc = decodeBase64(line + 2, outdata, &len, 0, NULL); *outdatalen = len; - if (rc != OK) + if (rc != OK) { + netsec_err(errstr, "Unable to decode base64 response"); return NOTOK; + } } break; @@ -411,8 +420,6 @@ pop_sasl_callback(enum sasl_message_type mtype, unsigned const char *indata, if (netsec_flush(nsc, errstr) != OK) return NOTOK; - - return OK; break; /* @@ -424,7 +431,7 @@ pop_sasl_callback(enum sasl_message_type mtype, unsigned const char *indata, if (line == NULL) return NOTOK; - if (strncmp(line, "+OK", 3) != 0) { + if (!has_prefix(line, "+OK")) { netsec_err(errstr, "Authentication failed: %s", line); return NOTOK; } @@ -447,7 +454,8 @@ pop_sasl_callback(enum sasl_message_type mtype, unsigned const char *indata, return NOTOK; break; } -return OK; + + return OK; } /* @@ -470,68 +478,16 @@ pop_stat (int *nmsgs, int *nbytes) int -pop_list (int msgno, int *nmsgs, int *msgs, int *bytes) +pop_retr (int msgno, int (*action)(void *, char *), void *closure) { - int i; - int *ids = NULL; - - if (msgno) { - if (command ("LIST %d", msgno) == NOTOK) - return NOTOK; - *msgs = *bytes = 0; - if (ids) { - *ids = 0; - sscanf (response, "+OK %d %d %d", msgs, bytes, ids); - } - else - sscanf (response, "+OK %d %d", msgs, bytes); - return OK; - } - - if (command ("LIST") == NOTOK) - return NOTOK; - - for (i = 0; i < *nmsgs; i++) - switch (multiline ()) { - case NOTOK: - return NOTOK; - case DONE: - *nmsgs = ++i; - return OK; - case OK: - *msgs = *bytes = 0; - if (ids) { - *ids = 0; - sscanf (response, "%d %d %d", - msgs++, bytes++, ids++); - } - else - sscanf (response, "%d %d", msgs++, bytes++); - break; - } - for (;;) - switch (multiline ()) { - case NOTOK: - return NOTOK; - case DONE: - return OK; - case OK: - break; - } -} - - -int -pop_retr (int msgno, int (*action)(char *)) -{ - return traverse (action, "RETR %d", msgno); + return traverse (action, closure, "RETR %d", msgno); } static int -traverse (int (*action)(char *), const char *fmt, ...) +traverse (int (*action)(void *, char *), void *closure, const char *fmt, ...) { - int result; + int result, snoopstate; va_list ap; char buffer[sizeof(response)]; @@ -543,19 +499,24 @@ traverse (int (*action)(char *), const char *fmt, ...) return NOTOK; strncpy (buffer, response, sizeof(buffer)); - for (;;) - switch (multiline ()) { - case NOTOK: - return NOTOK; - - case DONE: - strncpy (response, buffer, sizeof(response)); - return OK; + if ((snoopstate = netsec_get_snoop(nsc))) + netsec_set_snoop(nsc, 0); + + for (;;) { + result = multiline(); + if (result == OK) { + result = (*action)(closure, response); + if (result == OK) + continue; + } else if (result == DONE) { + strncpy(response, buffer, sizeof(response)); + result = OK; + } + break; + } - case OK: - (*action) (response); - break; - } + netsec_set_snoop(nsc, snoopstate); + return result; } @@ -566,27 +527,6 @@ pop_dele (int msgno) } -int -pop_noop (void) -{ - return command ("NOOP"); -} - - -int -pop_rset (void) -{ - return command ("RSET"); -} - - -int -pop_top (int msgno, int lines, int (*action)(char *)) -{ - return traverse (action, "TOP %d %d", msgno, lines); -} - - int pop_quit (void) { @@ -603,7 +543,7 @@ int pop_done (void) { if (nsc) - netsec_shutdown(nsc, 1); + netsec_shutdown(nsc); return OK; } @@ -658,8 +598,10 @@ vcommand (const char *fmt, va_list ap) case NOTOK: case DONE: - if (poprint) - fprintf (stderr, "%s\n", response); + if (poprint) { + fputs(response, stderr); + putc('\n', stderr); + } return NOTOK; } @@ -670,15 +612,14 @@ vcommand (const char *fmt, va_list ap) int multiline (void) { - char buffer[BUFSIZ + TRMLEN]; + char buffer[BUFSIZ + LEN(TRM)]; if (pop_getline (buffer, sizeof buffer, nsc) != OK) return NOTOK; - if (strncmp (buffer, TRM, TRMLEN) == 0) { - if (buffer[TRMLEN] == 0) + if (has_prefix(buffer, TRM)) { + if (buffer[LEN(TRM)] == 0) return DONE; - else - strncpy (response, buffer + TRMLEN, sizeof(response)); + strncpy (response, buffer + LEN(TRM), sizeof(response)); } else strncpy (response, buffer, sizeof(response)); @@ -715,11 +656,11 @@ pop_getline (char *s, int n, netsec_context *ns) * * We get a length back from netsec_readline, but the rest of the POP * code doesn't handle it; the assumptions are that everything from - * the network can be respresented as C strings. That should get fixed + * the network can be represented as C strings. That should get fixed * someday. */ - destlen = len < ((size_t) (n - 1)) ? len : n - 1; + destlen = min(len, (size_t)(n - 1)); memcpy(s, p, destlen); s[destlen] = '\0';