static int multiline(void);
#ifdef CYRUS_SASL
-static int pop_auth_sasl(char *, char *, char *, char *);
+static int pop_auth_sasl(char *, char *, char *);
static int sasl_fgetc(FILE *);
#endif /* CYRUS_SASL */
* 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 *password, char *host, char *mech)
+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;
callbacks[POP_SASL_CB_N_USER].context = user;
p_context.user = user;
p_context.host = host;
- p_context.password = password;
callbacks[POP_SASL_CB_N_PASS].context = &p_context;
result = sasl_client_init(callbacks);
}
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;
}
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
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;
}
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).
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 = p_context->password;
+ struct nmh_creds creds = { 0, 0, 0 };
int len;
NMH_UNUSED (conn);
if (! psecret || id != SASL_CB_PASS)
return SASL_BADPARAM;
- len = strlen(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 (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;
}
} else if (!isspace(*cur))
*c++ = *cur;
}
+ *c = '\0';
*++p = NULL;
return pargv;
}
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) {
if (*response == '+') {
# ifdef CYRUS_SASL
if (sasl) {
- if (pop_auth_sasl(user, pass, host, mech) != NOTOK)
+ if (pop_auth_sasl(user, host, mech) != NOTOK)
return OK;
} else
# endif /* CYRUS_SASL */
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)
*p = 0;
if (*--p == '\n')
*p = 0;
- if (*--p == '\r')
+ if (p > s && *--p == '\r')
*p = 0;
return OK;
return NOTOK;
}
- fwrite(buf, buflen, 1, iop);
+ if (fwrite(buf, buflen, 1, iop) < 1) {
+ advise ("putline", "fwrite");
+ }
}
#endif /* CYRUS_SASL */