}
}
-bool cmd_auth(struct pop3_client *pop3_client, const char *args)
+int cmd_auth(struct pop3_client *pop3_client, bool *parsed_r)
{
+ /* NOTE: This command's input is handled specially because the
+ SASL-IR can be large. */
struct client *client = &pop3_client->common;
- const struct auth_mech_desc *mech;
- const char *mech_name, *init_resp, *p;
-
- if (*args == '\0') {
- /* Old-style SASL discovery, used by MS Outlook */
- unsigned int i, count;
-
- client_send_raw(client, "+OK\r\n");
- mech = sasl_server_get_advertised_mechs(client, &count);
- for (i = 0; i < count; i++) {
- client_send_raw(client, mech[i].name);
- client_send_raw(client, "\r\n");
+ const unsigned char *data;
+ size_t i, size;
+ int ret;
+
+ *parsed_r = FALSE;
+
+ /* <auth mechanism name> [<initial SASL response>] */
+ if (!pop3_client->auth_mech_name_parsed) {
+ data = i_stream_get_data(client->input, &size);
+ for (i = 0; i < size; i++) {
+ if (data[i] == ' ' ||
+ data[i] == '\r' || data[i] == '\n')
+ break;
}
- client_send_raw(client, ".\r\n");
- return TRUE;
- }
-
- /* <mechanism name> <initial response> */
- p = strchr(args, ' ');
- if (p == NULL) {
- mech_name = args;
- /* no initial response */
- init_resp = NULL;
- } else {
- mech_name = t_strdup_until(args, p);
- init_resp = p + 1;
- if (*init_resp == '\0') {
- /* no initial response */
- init_resp = NULL;
- } else if (strcmp(init_resp, "=") == 0) {
- /* empty initial response */
- init_resp = "";
+ if (i == size)
+ return 0;
+ if (i == 0) {
+ /* Old-style SASL discovery, used by MS Outlook */
+ unsigned int i, count;
+ const struct auth_mech_desc *mech;
+
+ client_send_raw(client, "+OK\r\n");
+ mech = sasl_server_get_advertised_mechs(client, &count);
+ for (i = 0; i < count; i++) {
+ client_send_raw(client, mech[i].name);
+ client_send_raw(client, "\r\n");
+ }
+ client_send_raw(client, ".\r\n");
+ *parsed_r = TRUE;
+ return 1;
}
+ i_free(client->auth_mech_name);
+ client->auth_mech_name = i_strndup(data, i);
+ pop3_client->auth_mech_name_parsed = TRUE;
+ if (data[i] == ' ')
+ i++;
+ i_stream_skip(client->input, i);
}
- (void)client_auth_begin(client, mech_name, init_resp);
- return TRUE;
+ /* get SASL-IR, if any */
+ if ((ret = client_auth_read_line(client)) <= 0)
+ return ret;
+
+ const char *ir = NULL;
+ if (client->auth_response->used > 0)
+ ir = t_strdup(str_c(client->auth_response));
+
+ *parsed_r = TRUE;
+ pop3_client->auth_mech_name_parsed = FALSE;
+ return client_auth_begin(client, t_strdup(client->auth_mech_name), ir);
}
bool cmd_user(struct pop3_client *pop3_client, const char *args)
return cmd_user(client, args);
if (strcmp(cmd, "PASS") == 0)
return cmd_pass(client, args);
- if (strcmp(cmd, "AUTH") == 0)
- return cmd_auth(client, args);
if (strcmp(cmd, "APOP") == 0)
return cmd_apop(client, args);
if (strcmp(cmd, "STLS") == 0)
const char *cmd, *args;
bool parsed;
- if (!client_read_cmd_name(client, &cmd))
+ if (!pop3_client->authenticating && !client_read_cmd_name(client, &cmd))
return FALSE;
+
+ if (pop3_client->authenticating ||
+ strcmp(cmd, "AUTH") == 0) {
+ pop3_client->authenticating = TRUE;
+ int ret = cmd_auth(pop3_client, &parsed);
+ if (ret == 0 || !parsed)
+ return FALSE;
+ pop3_client->authenticating = !parsed;
+ return parsed;
+ }
+
if ((args = i_stream_next_line(client->input)) == NULL)
return FALSE;