📄 mutt_sasl.c
字号:
{ dprint (2, (debugfile, "mutt_sasl_interact: filling in SASL interaction %ld.\n", interaction->id)); snprintf (prompt, sizeof (prompt), "%s: ", interaction->prompt); resp[0] = '\0'; if (mutt_get_field (prompt, resp, sizeof (resp), 0)) return SASL_FAIL; interaction->len = mutt_strlen (resp)+1; interaction->result = safe_malloc (interaction->len); memcpy ((char *)interaction->result, resp, interaction->len); interaction++; } return SASL_OK;}/* SASL can stack a protection layer on top of an existing connection. * To handle this, we store a saslconn_t in conn->sockdata, and write * wrappers which en/decode the read/write stream, then replace sockdata * with an embedded copy of the old sockdata and call the underlying * functions (which we've also preserved). I thought about trying to make * a general stackable connection system, but it seemed like overkill - * something is wrong if we have 15 filters on top of a socket. Anyway, * anything else which wishes to stack can use the same method. The only * disadvantage is we have to write wrappers for all the socket methods, * even if we only stack over read and write. Thinking about it, the * abstraction problem is that there is more in CONNECTION than there * needs to be. Ideally it would have only (void*)data and methods. *//* mutt_sasl_setup_conn: replace connection methods, sockdata with * SASL wrappers, for protection layers. Also get ssf, as a fastpath * for the read/write methods. */void mutt_sasl_setup_conn (CONNECTION* conn, sasl_conn_t* saslconn){ SASL_DATA* sasldata = (SASL_DATA*) safe_malloc (sizeof (SASL_DATA)); sasldata->saslconn = saslconn; /* get ssf so we know whether we have to (en|de)code read/write */ sasl_getprop (saslconn, SASL_SSF, (const void**) &sasldata->ssf); dprint (3, (debugfile, "SASL protection strength: %u\n", *sasldata->ssf)); /* Add SASL SSF to transport SSF */ conn->ssf += *sasldata->ssf; sasl_getprop (saslconn, SASL_MAXOUTBUF, (const void**) &sasldata->pbufsize); dprint (3, (debugfile, "SASL protection buffer size: %u\n", *sasldata->pbufsize)); /* clear input buffer */ sasldata->buf = NULL; sasldata->bpos = 0; sasldata->blen = 0; /* preserve old functions */ sasldata->sockdata = conn->sockdata; sasldata->msasl_open = conn->conn_open; sasldata->msasl_close = conn->conn_close; sasldata->msasl_read = conn->conn_read; sasldata->msasl_write = conn->conn_write; /* and set up new functions */ conn->sockdata = sasldata; conn->conn_open = mutt_sasl_conn_open; conn->conn_close = mutt_sasl_conn_close; conn->conn_read = mutt_sasl_conn_read; conn->conn_write = mutt_sasl_conn_write;}/* mutt_sasl_cb_log: callback to log SASL messages */static int mutt_sasl_cb_log (void* context, int priority, const char* message){ dprint (priority, (debugfile, "SASL: %s\n", message)); return SASL_OK;}void mutt_sasl_done (void){ sasl_done ();}/* mutt_sasl_cb_authname: callback to retrieve authname or user from ACCOUNT */static int mutt_sasl_cb_authname (void* context, int id, const char** result, unsigned* len){ ACCOUNT* account = (ACCOUNT*) context; *result = NULL; if (len) *len = 0; if (!account) return SASL_BADPARAM; dprint (2, (debugfile, "mutt_sasl_cb_authname: getting %s for %s:%u\n", id == SASL_CB_AUTHNAME ? "authname" : "user", account->host, account->port)); if (id == SASL_CB_AUTHNAME) { if (mutt_account_getlogin (account)) return SASL_FAIL; *result = account->login; } else { if (mutt_account_getuser (account)) return SASL_FAIL; *result = account->user; } if (len) *len = strlen (*result); return SASL_OK;}static int mutt_sasl_cb_pass (sasl_conn_t* conn, void* context, int id, sasl_secret_t** psecret){ ACCOUNT* account = (ACCOUNT*) context; int len; if (!account || !psecret) return SASL_BADPARAM; dprint (2, (debugfile, "mutt_sasl_cb_pass: getting password for %s@%s:%u\n", account->login, account->host, account->port)); if (mutt_account_getpass (account)) return SASL_FAIL; len = strlen (account->pass); *psecret = (sasl_secret_t*) safe_malloc (sizeof (sasl_secret_t) + len); (*psecret)->len = len; strcpy ((char*)(*psecret)->data, account->pass); /* __STRCPY_CHECKED__ */ return SASL_OK;}/* mutt_sasl_conn_open: empty wrapper for underlying open function. We * don't know in advance that a connection will use SASL, so we * replace conn's methods with sasl methods when authentication * is successful, using mutt_sasl_setup_conn */static int mutt_sasl_conn_open (CONNECTION* conn){ SASL_DATA* sasldata; int rc; sasldata = (SASL_DATA*) conn->sockdata; conn->sockdata = sasldata->sockdata; rc = (sasldata->msasl_open) (conn); conn->sockdata = sasldata; return rc;}/* mutt_sasl_conn_close: calls underlying close function and disposes of * the sasl_conn_t object, then restores connection to pre-sasl state */static int mutt_sasl_conn_close (CONNECTION* conn){ SASL_DATA* sasldata; int rc; sasldata = (SASL_DATA*) conn->sockdata; /* restore connection's underlying methods */ conn->sockdata = sasldata->sockdata; conn->conn_open = sasldata->msasl_open; conn->conn_close = sasldata->msasl_close; conn->conn_read = sasldata->msasl_read; conn->conn_write = sasldata->msasl_write; /* release sasl resources */ sasl_dispose (&sasldata->saslconn); FREE (&sasldata); /* call underlying close */ rc = (conn->conn_close) (conn); return rc;}static int mutt_sasl_conn_read (CONNECTION* conn, char* buf, size_t len){ SASL_DATA* sasldata; int rc; unsigned int olen; sasldata = (SASL_DATA*) conn->sockdata; /* if we still have data in our read buffer, copy it into buf */ if (sasldata->blen > sasldata->bpos) { olen = (sasldata->blen - sasldata->bpos > len) ? len : sasldata->blen - sasldata->bpos; memcpy (buf, sasldata->buf+sasldata->bpos, olen); sasldata->bpos += olen; return olen; } conn->sockdata = sasldata->sockdata; sasldata->bpos = 0; sasldata->blen = 0; /* and decode the result, if necessary */ if (*sasldata->ssf) { do { /* call the underlying read function to fill the buffer */ rc = (sasldata->msasl_read) (conn, buf, len); if (rc <= 0) goto out; rc = sasl_decode (sasldata->saslconn, buf, rc, &sasldata->buf, &sasldata->blen); if (rc != SASL_OK) { dprint (1, (debugfile, "SASL decode failed: %s\n", sasl_errstring (rc, NULL, NULL))); goto out; } } while (!sasldata->blen); olen = (sasldata->blen - sasldata->bpos > len) ? len : sasldata->blen - sasldata->bpos; memcpy (buf, sasldata->buf, olen); sasldata->bpos += olen; rc = olen; } else rc = (sasldata->msasl_read) (conn, buf, len); out: conn->sockdata = sasldata; return rc;}static int mutt_sasl_conn_write (CONNECTION* conn, const char* buf, size_t len){ SASL_DATA* sasldata; int rc; const char *pbuf; unsigned int olen, plen; sasldata = (SASL_DATA*) conn->sockdata; conn->sockdata = sasldata->sockdata; /* encode data, if necessary */ if (*sasldata->ssf) { /* handle data larger than MAXOUTBUF */ do { olen = (len > *sasldata->pbufsize) ? *sasldata->pbufsize : len; rc = sasl_encode (sasldata->saslconn, buf, olen, &pbuf, &plen); if (rc != SASL_OK) { dprint (1, (debugfile, "SASL encoding failed: %s\n", sasl_errstring (rc, NULL, NULL))); goto fail; } rc = (sasldata->msasl_write) (conn, pbuf, plen); if (rc != plen) goto fail; len -= olen; buf += olen; } while (len > *sasldata->pbufsize); } else /* just write using the underlying socket function */ rc = (sasldata->msasl_write) (conn, buf, len); conn->sockdata = sasldata; return rc; fail: conn->sockdata = sasldata; return -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -