X-Git-Url: http://git.marmaro.de/?a=blobdiff_plain;f=mts%2Fsmtp%2Fsmtp.c;h=850693dd8e32c8edcc3938783f3791bfdfb28b98;hb=d4178eb3eebbf5c51c51cc713df58a2bdaa6bede;hp=f2390b834560646f612a554095d5714658a6c47b;hpb=fc80e34e8e9e3c726073d321e2075ead77baba08;p=mmh diff --git a/mts/smtp/smtp.c b/mts/smtp/smtp.c index f2390b8..850693d 100644 --- a/mts/smtp/smtp.c +++ b/mts/smtp/smtp.c @@ -2,11 +2,15 @@ * smtp.c -- nmh SMTP interface * * $Id$ + * + * This code is Copyright (c) 2002, by the authors of nmh. See the + * COPYRIGHT file in the root directory of the nmh distribution for + * complete copyright information. */ #include #include "smtp.h" -#include +#include #include #include #ifdef MPOP @@ -14,7 +18,8 @@ #endif #ifdef CYRUS_SASL -#include +#include +#include #include #include #include @@ -55,14 +60,14 @@ /* * these codes must all be different! */ -#define SM_OPEN 90 /* Changed from 30 in case of nameserver flakiness */ +#define SM_OPEN 300 /* Changed to 5 minutes to comply with a SHOULD in RFC 1123 */ #define SM_HELO 20 #define SM_RSET 15 -#define SM_MAIL 40 -#define SM_RCPT 120 -#define SM_DATA 20 -#define SM_TEXT 150 -#define SM_DOT 180 +#define SM_MAIL 301 /* changed to 5 minutes and a second (for uniqueness), see above */ +#define SM_RCPT 302 /* see above */ +#define SM_DATA 120 /* see above */ +#define SM_TEXT 180 /* see above */ +#define SM_DOT 600 /* see above */ #define SM_QUIT 30 #define SM_CLOS 10 #define SM_AUTH 45 @@ -134,6 +139,7 @@ static RETSIGTYPE alrmser (int); static char *EHLOset (char *); #ifdef MPOP +static int sm_perror (char *fmt, ...); /* * smtp.c's own static copy of several nmh library subroutines */ @@ -150,7 +156,7 @@ char **smail_copyip (char **, char **, int); static int sm_auth_sasl(char *, char *, char *); #endif /* CYRUS_SASL */ -/* from zotnet/mts/client.c */ +/* from mts/generic/client.c */ int client (char *, char *, char *, int, char *, int); int @@ -497,15 +503,6 @@ rclient (char *server, char *protocol, char *service) return NOTOK; } -#ifdef CYRUS_SASL -#include -#include -#include -#include -#include -#include -#endif /* CYRUS_SASL */ - int sm_winit (int mode, char *from) { @@ -513,7 +510,7 @@ sm_winit (int mode, char *from) #ifdef MPOP if (sm_ispool && !sm_wfp) { - strlen (strcpy (sm_reply.text, "unable to create new spool file")); + sm_reply.length = strlen (strcpy (sm_reply.text, "unable to create new spool file")); sm_reply.code = NOTOK; return RP_BHST; } @@ -685,7 +682,8 @@ sm_end (int type) case NOTOK: sm_note.code = sm_reply.code; - strncpy (sm_note.text, sm_reply.text, sm_note.length = sm_reply.length);/* fall */ + sm_note.length = sm_reply.length; + memcpy (sm_note.text, sm_reply.text, sm_reply.length + 1);/* fall */ case DONE: if (smtalk (SM_RSET, "RSET") == 250 && type == DONE) return RP_OK; @@ -698,7 +696,8 @@ sm_end (int type) } if (type == NOTOK) { sm_reply.code = sm_note.code; - strncpy (sm_reply.text, sm_note.text, sm_reply.length = sm_note.length); + sm_reply.length = sm_note.length; + memcpy (sm_reply.text, sm_note.text, sm_note.length + 1); } break; } @@ -756,20 +755,7 @@ sm_bulk (char *file) gp = NULL; k = strlen (file) - sizeof(".bulk"); if ((fp = fopen (file, "r")) == NULL) { - int len; - - snprintf (sm_reply.text, sizeof(sm_reply.text), - "unable to read %s: ", file); - bp = sm_reply.text; - len = strlen (bp); - bp += len; - if ((s = strerror (errno))) - strncpy (bp, s, sizeof(sm_reply.text) - len); - else - snprintf (bp, sizeof(sm_reply.text) - len, "Error %d", errno); - sm_reply.length = strlen (sm_reply.text); - sm_reply.code = NOTOK; - return RP_BHST; + return sm_perror("unable to read %s: ", file); } if (sm_debug) { printf ("reading file %s\n", file); @@ -830,17 +816,7 @@ losing2: if ((cc = write (fileno (sm_wfp), dp, i)) == NOTOK) { int len; losing3: - strcpy (sm_reply.text, "error writing to server: ", - sizeof(sm_reply.text)); - bp = sm_reply.text; - len = strlen (bp); - bp += len; - if ((s = strerror (errno))) - strncpy (bp, s, sizeof(sm_reply.text) - len); - else - snprintf (bp, sizeof(sm_reply.text) - len, - "unknown error %d", errno); - sm_reply.length = strlen (sm_reply.text); + sm_perror("error writing to server: "); goto losing2; } else @@ -963,7 +939,7 @@ bad_data: free (cp); { -#ifdef HAVE_ST_BLKSIZE +#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE struct stat st; if (fstat (fileno (sm_wfp), &st) == NOTOK || (cc = st.st_blksize) < BUFSIZ) @@ -985,19 +961,7 @@ bad_data: for (dp = cp, i = cc; i > 0; dp += j, i -= j) if ((j = fread (cp, sizeof(*cp), i, fp)) == OK) { if (ferror (fp)) { - int len; - - snprintf (sm_reply.text, sizeof(sm_reply.text), - "error reading %s: ", file); - bp = sm_reply.text; - len = strlen (bp); - bp += len; - if ((s = strerror (errno))) - strncpy (bp, s, sizeof(sm_reply.text) - len); - else - snprintf (bp, sizeof(sm_reply.text) - len, - "unknown error %d", errno); - sm_reply.length = strlen (sm_reply.text); + sm_perror("error reading %s: ", file); goto losing2; } cc = dp - cp; @@ -1104,12 +1068,11 @@ no_dice: static int sm_auth_sasl(char *user, char *mechlist, char *host) { - int result, status, outlen; - unsigned int buflen; + int result, status; + unsigned int buflen, outlen; char *buf, outbuf[BUFSIZ]; const char *chosen_mech; sasl_security_properties_t secprops; - sasl_external_properties_t extprops; sasl_ssf_t *ssf; int *outbufmax; @@ -1162,7 +1125,7 @@ sm_auth_sasl(char *user, char *mechlist, char *host) return NOTOK; } - result = sasl_client_new("smtp", host, NULL, SASL_SECURITY_LAYER, &conn); + result = sasl_client_new("smtp", host, NULL, NULL, NULL, 0, &conn); if (result != SASL_OK) { sm_ierror("SASL client initialization failed: %s", @@ -1177,7 +1140,6 @@ sm_auth_sasl(char *user, char *mechlist, char *host) memset(&secprops, 0, sizeof(secprops)); secprops.maxbufsize = BUFSIZ; secprops.max_ssf = 0; /* XXX change this when we do encryption */ - memset(&extprops, 0, sizeof(extprops)); result = sasl_setprop(conn, SASL_SEC_PROPS, &secprops); @@ -1187,21 +1149,13 @@ sm_auth_sasl(char *user, char *mechlist, char *host) return NOTOK; } - result = sasl_setprop(conn, SASL_SSF_EXTERNAL, &extprops); - - if (result != SASL_OK) { - sm_ierror("SASL external property initialization failed: %s", - sasl_errstring(result, NULL, NULL)); - return NOTOK; - } - /* * Start the actual protocol. Feed the mech list into the library * and get out a possible initial challenge */ - result = sasl_client_start(conn, mechlist, NULL, NULL, &buf, &buflen, - &chosen_mech); + result = sasl_client_start(conn, mechlist, NULL, (const char **) &buf, + &buflen, (const char **) &chosen_mech); if (result != SASL_OK && result != SASL_CONTINUE) { sm_ierror("SASL client start failed: %s", @@ -1216,7 +1170,6 @@ sm_auth_sasl(char *user, char *mechlist, char *host) if (buflen) { status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL); - free(buf); if (status != SASL_OK) { sm_ierror("SASL base64 encode failed: %s", sasl_errstring(status, NULL, NULL)); @@ -1259,7 +1212,7 @@ sm_auth_sasl(char *user, char *mechlist, char *host) outlen = 0; } else { result = sasl_decode64(sm_reply.text, sm_reply.length, - outbuf, &outlen); + outbuf, sizeof(outbuf), &outlen); if (result != SASL_OK) { smtalk(SM_AUTH, "*"); @@ -1269,7 +1222,8 @@ sm_auth_sasl(char *user, char *mechlist, char *host) } } - 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) { smtalk(SM_AUTH, "*"); @@ -1279,7 +1233,6 @@ sm_auth_sasl(char *user, char *mechlist, char *host) } status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL); - free(buf); if (status != SASL_OK) { smtalk(SM_AUTH, "*"); @@ -1299,24 +1252,11 @@ sm_auth_sasl(char *user, char *mechlist, char *host) return RP_BHST; /* - * Depending on the mechanism, we need to do a FINAL call to - * sasl_client_step(). Do that now. - */ - - result = sasl_client_step(conn, NULL, 0, NULL, &buf, &buflen); - - if (result != SASL_OK) { - sm_ierror("SASL final client negotiation failed: %s", - sasl_errstring(result, NULL, NULL)); - return NOTOK; - } - - /* * We _should_ have completed the authentication successfully. * Get a few properties from the authentication exchange. */ - result = sasl_getprop(conn, SASL_MAXOUTBUF, (void **) &outbufmax); + result = sasl_getprop(conn, SASL_MAXOUTBUF, (const void **) &outbufmax); if (result != SASL_OK) { sm_ierror("Cannot retrieve SASL negotiated output buffer size: %s", @@ -1326,7 +1266,7 @@ sm_auth_sasl(char *user, char *mechlist, char *host) maxoutbuf = *outbufmax; - result = sasl_getprop(conn, SASL_SSF, (void **) &ssf); + result = sasl_getprop(conn, SASL_SSF, (const void **) &ssf); sasl_ssf = *ssf; @@ -1386,7 +1326,7 @@ sm_get_pass(sasl_conn_t *conn, void *context, int id, } (*psecret)->len = len; - strcpy((*psecret)->data, pass); + strcpy((char *) (*psecret)->data, pass); /* free(pass); */ return SASL_OK; @@ -1408,6 +1348,36 @@ sm_ierror (char *fmt, ...) return RP_BHST; } +#ifdef MPOP +static int +sm_perror (char *fmt, ...) +{ + /* Fill in sm_reply with a suitable error string based on errno. + * This isn't particularly MPOP specific, it just happens that that's + * the only code that uses it currently. + */ + char *bp, *s; + int len, eno = errno; + + va_list ap; + va_start(ap,fmt); + vsnprintf (sm_reply.text, sizeof(sm_reply.text), fmt, ap); + va_end(ap); + + bp = sm_reply.text; + len = strlen(bp); + bp += len; + if ((s = strerror(eno))) + snprintf(bp, sizeof(sm_reply.text) - len, "%s", s); + else + snprintf(bp, sizeof(sm_reply.text) - len, "unknown error %d", eno); + + sm_reply.length = strlen (sm_reply.text); + sm_reply.code = NOTOK; + + return RP_BHST; +} +#endif static int smtalk (int time, char *fmt, ...) @@ -1440,22 +1410,7 @@ smtalk (int time, char *fmt, ...) snprintf (file, sizeof(file), "%s%c.bulk", sm_tmpfil, (char) (sm_ispool + 'a' - 1)); if (rename (sm_tmpfil, file) == NOTOK) { - int len; - char *bp; - - snprintf (sm_reply.text, sizeof(sm_reply.text), - "error renaming %s to %s: ", sm_tmpfil, file); - bp = sm_reply.text; - len = strlen (bp); - bp += len; - if ((s = strerror (errno))) - strncpy (bp, s, sizeof(sm_reply.text) - len); - else - snprintf (bp, sizeof(sm_reply.text) - len, - "unknown error %d", errno); - sm_reply.length = strlen (sm_reply.text); - sm_reply.code = NOTOK; - return RP_BHST; + return sm_perror("error renaming %s to %s: ", sm_tmpfil, file); } fclose (sm_wfp); if (sm_wfp = fopen (sm_tmpfil, "w")) @@ -1598,7 +1553,8 @@ static int smhear (void) { int i, code, cont, bc, rc, more; - char *bp, *rp; + unsigned char *bp; + char *rp; char **ehlo, buffer[BUFSIZ]; if (doingEHLO) { @@ -1673,6 +1629,7 @@ again: ; sm_reply.code = code; more = cont; if (bc <= 0) { + /* can never fail to 0-terminate because of size of buffer vs fixed string */ strncpy (buffer, sm_noreply, sizeof(buffer)); bp = buffer; bc = strlen (sm_noreply); @@ -1680,12 +1637,14 @@ again: ; } if ((i = min (bc, rc)) > 0) { - strncpy (rp, bp, i); + memcpy (rp, bp, i); rp += i; rc -= i; - if (more && rc > strlen (sm_moreply) + 1) { - strncpy (sm_reply.text + rc, sm_moreply, sizeof(sm_reply.text) - rc); - rc += strlen (sm_moreply); + i = strlen(sm_moreply); + if (more && rc > i + 1) { + memcpy (rp, sm_moreply, i); /* safe because of check in if() */ + rp += i; + rc -= i; } } if (more) @@ -1699,6 +1658,7 @@ again: ; } sm_reply.length = rp - sm_reply.text; + sm_reply.text[sm_reply.length] = 0; return sm_reply.code; } return NOTOK; @@ -1715,15 +1675,17 @@ sm_rrecord (char *buffer, int *len) fgets (buffer, BUFSIZ, sm_rfp); *len = strlen (buffer); - if (ferror (sm_rfp) || feof (sm_rfp)) + /* *len should be >0 except on EOF, but check for safety's sake */ + if (ferror (sm_rfp) || feof (sm_rfp) || (*len == 0)) return sm_rerror (); if (buffer[*len - 1] != '\n') while (getc (sm_rfp) != '\n' && !ferror (sm_rfp) && !feof (sm_rfp)) continue; else - if (buffer[*len - 2] == '\r') + if ((*len > 1) && (buffer[*len - 2] == '\r')) *len -= 1; - buffer[*len - 1] = 0; + *len -= 1; + buffer[*len] = 0; return OK; }