#endif
#ifdef CYRUS_SASL
-#include <sasl.h>
+#include <sasl/sasl.h>
+#include <sasl/saslutil.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/*
* 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
static char *EHLOset (char *);
#ifdef MPOP
+static int sm_perror (char *fmt, ...);
/*
* smtp.c's own static copy of several nmh library subroutines
*/
return NOTOK;
}
-#ifdef CYRUS_SASL
-#include <sasl.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <errno.h>
-#endif /* CYRUS_SASL */
-
int
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;
}
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;
}
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;
}
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);
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
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)
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;
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;
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",
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);
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",
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));
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, "*");
}
}
- 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, "*");
}
status = sasl_encode64(buf, buflen, outbuf, sizeof(outbuf), NULL);
- free(buf);
if (status != SASL_OK) {
smtalk(SM_AUTH, "*");
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",
maxoutbuf = *outbufmax;
- result = sasl_getprop(conn, SASL_SSF, (void **) &ssf);
+ result = sasl_getprop(conn, SASL_SSF, (const void **) &ssf);
sasl_ssf = *ssf;
}
(*psecret)->len = len;
- strcpy((*psecret)->data, pass);
+ strcpy((char *) (*psecret)->data, pass);
/* free(pass); */
return SASL_OK;
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, ...)
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"))
smhear (void)
{
int i, code, cont, bc, rc, more;
- char *bp, *rp;
+ unsigned char *bp;
+ char *rp;
char **ehlo, buffer[BUFSIZ];
if (doingEHLO) {
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);
}
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)
}
sm_reply.length = rp - sm_reply.text;
+ sm_reply.text[sm_reply.length] = 0;
return sm_reply.code;
}
return NOTOK;
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;
}