#ifdef CYRUS_SASL
# include <sasl/sasl.h>
# include <sasl/saslutil.h>
+# 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 <h/popsbr.h>
#include <h/signals.h>
-#include <signal.h>
-#include <errno.h>
#define TRM "."
#define TRMLEN (sizeof TRM - 1)
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 },
* 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;
}
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 = 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;
}
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);
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)