comparison src/mail/ngx_mail_handler.c @ 398:f9e6413396d4 PATCH_NGINX_MAIL_0_2

Mail: IMAP AUTHENTICATE command support. Supported auth methods: PLAIN, LOGIN, CRAM-MD5.
author Maxim Dounin <mdounin@mdounin.ru>
date Thu, 19 Jul 2007 02:43:59 +0000
parents e2d916d7e50f
children f1e2fab7a46c
comparison
equal deleted inserted replaced
397:1aac47be9772 398:f9e6413396d4
282 282
283 if ((s->protocol == NGX_MAIL_POP3_PROTOCOL 283 if ((s->protocol == NGX_MAIL_POP3_PROTOCOL
284 && (cscf->pop3_auth_methods 284 && (cscf->pop3_auth_methods
285 & (NGX_MAIL_AUTH_APOP_ENABLED|NGX_MAIL_AUTH_CRAM_MD5_ENABLED))) 285 & (NGX_MAIL_AUTH_APOP_ENABLED|NGX_MAIL_AUTH_CRAM_MD5_ENABLED)))
286 286
287 || (s->protocol == NGX_MAIL_IMAP_PROTOCOL
288 && (cscf->imap_auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED))
289
287 || (s->protocol == NGX_MAIL_SMTP_PROTOCOL 290 || (s->protocol == NGX_MAIL_SMTP_PROTOCOL
288 && (cscf->smtp_auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED))) 291 && (cscf->smtp_auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)))
289 { 292 {
290 s->salt.data = ngx_palloc(c->pool, 293 s->salt.data = ngx_palloc(c->pool,
291 sizeof(" <18446744073709551616.@>" CRLF) - 1 294 sizeof(" <18446744073709551616.@>" CRLF) - 1
996 void 999 void
997 ngx_imap_auth_state(ngx_event_t *rev) 1000 ngx_imap_auth_state(ngx_event_t *rev)
998 { 1001 {
999 u_char *p, *last, *text, *dst, *src, *end; 1002 u_char *p, *last, *text, *dst, *src, *end;
1000 ssize_t text_len, last_len; 1003 ssize_t text_len, last_len;
1001 ngx_str_t *arg; 1004 ngx_str_t *arg, salt;
1002 ngx_int_t rc; 1005 ngx_int_t rc;
1003 ngx_uint_t tag, i; 1006 ngx_uint_t tag, i;
1004 ngx_connection_t *c; 1007 ngx_connection_t *c;
1005 ngx_mail_session_t *s; 1008 ngx_mail_session_t *s;
1006 ngx_mail_core_srv_conf_t *cscf; 1009 ngx_mail_core_srv_conf_t *cscf;
1066 } 1069 }
1067 1070
1068 s->backslash = 0; 1071 s->backslash = 0;
1069 } 1072 }
1070 1073
1071 switch (s->command) { 1074 switch (s->mail_state) {
1072 1075
1073 case NGX_IMAP_LOGIN: 1076 case ngx_imap_start:
1077
1078 switch (s->command) {
1079
1080 case NGX_IMAP_LOGIN:
1074 1081
1075 #if (NGX_MAIL_SSL) 1082 #if (NGX_MAIL_SSL)
1076 1083
1077 if (c->ssl == NULL) { 1084 if (c->ssl == NULL) {
1078 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); 1085 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
1079 1086
1080 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) { 1087 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
1088 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1089 break;
1090 }
1091 }
1092 #endif
1093
1094 arg = s->args.elts;
1095
1096 if (s->args.nelts == 2 && arg[0].len) {
1097
1098 s->login.len = arg[0].len;
1099 s->login.data = ngx_palloc(c->pool, s->login.len);
1100 if (s->login.data == NULL) {
1101 ngx_mail_session_internal_server_error(s);
1102 return;
1103 }
1104
1105 ngx_memcpy(s->login.data, arg[0].data, s->login.len);
1106
1107 s->passwd.len = arg[1].len;
1108 s->passwd.data = ngx_palloc(c->pool, s->passwd.len);
1109 if (s->passwd.data == NULL) {
1110 ngx_mail_session_internal_server_error(s);
1111 return;
1112 }
1113
1114 ngx_memcpy(s->passwd.data, arg[1].data, s->passwd.len);
1115
1116 #if (NGX_DEBUG_MAIL_PASSWD)
1117 ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
1118 "imap login:\"%V\" passwd:\"%V\"",
1119 &s->login, &s->passwd);
1120 #else
1121 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
1122 "imap login:\"%V\"", &s->login);
1123 #endif
1124
1125 ngx_mail_do_auth(s);
1126 return;
1127 }
1128
1129 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1130 break;
1131
1132 case NGX_IMAP_AUTHENTICATE:
1133
1134 #if (NGX_MAIL_SSL)
1135
1136 if (c->ssl == NULL) {
1137 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
1138
1139 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
1140 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1141 break;
1142 }
1143 }
1144 #endif
1145
1146 if (s->args.nelts != 1) {
1081 rc = NGX_MAIL_PARSE_INVALID_COMMAND; 1147 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1082 break; 1148 break;
1083 } 1149 }
1084 } 1150
1085 #endif 1151 arg = s->args.elts;
1086 1152
1153 if (arg[0].len == 5) {
1154
1155 if (ngx_strncasecmp(arg[0].data, (u_char *) "LOGIN", 5)
1156 == 0)
1157 {
1158
1159 s->mail_state = ngx_imap_auth_login_username;
1160
1161 last_len = sizeof(pop3_username) - 1;
1162 last = pop3_username;
1163 tag = 0;
1164
1165 break;
1166
1167 } else if (ngx_strncasecmp(arg[0].data, (u_char *) "PLAIN",
1168 5)
1169 == 0)
1170 {
1171
1172 s->mail_state = ngx_imap_auth_plain;
1173
1174 last_len = sizeof(pop3_next) - 1;
1175 last = pop3_next;
1176 tag = 0;
1177
1178 break;
1179 }
1180
1181 } else if (arg[0].len == 8
1182 && ngx_strncasecmp(arg[0].data,
1183 (u_char *) "CRAM-MD5", 8)
1184 == 0)
1185 {
1186 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
1187
1188 if (!(cscf->imap_auth_methods
1189 & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)
1190 || s->args.nelts != 1)
1191 {
1192 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1193 break;
1194 }
1195
1196 s->mail_state = ngx_imap_auth_cram_md5;
1197
1198 last = ngx_palloc(c->pool,
1199 sizeof("+ " CRLF) - 1
1200 + ngx_base64_encoded_length(s->salt.len));
1201 if (last == NULL) {
1202 ngx_mail_session_internal_server_error(s);
1203 return;
1204 }
1205
1206 last[0] = '+'; last[1]= ' ';
1207 salt.data = &last[2];
1208 s->salt.len -= 2;
1209
1210 ngx_encode_base64(&salt, &s->salt);
1211
1212 s->salt.len += 2;
1213 last_len = 2 + salt.len;
1214 last[last_len++] = CR; last[last_len++] = LF;
1215 tag = 0;
1216
1217 break;
1218 }
1219
1220 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1221 break;
1222
1223 case NGX_IMAP_CAPABILITY:
1224 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
1225
1226 #if (NGX_MAIL_SSL)
1227
1228 if (c->ssl == NULL) {
1229 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
1230
1231 if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) {
1232 text_len = cscf->imap_starttls_capability.len;
1233 text = cscf->imap_starttls_capability.data;
1234 break;
1235 }
1236
1237 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
1238 text_len = cscf->imap_starttls_only_capability.len;
1239 text = cscf->imap_starttls_only_capability.data;
1240 break;
1241 }
1242 }
1243 #endif
1244
1245 text_len = cscf->imap_capability.len;
1246 text = cscf->imap_capability.data;
1247 break;
1248
1249 case NGX_IMAP_LOGOUT:
1250 s->quit = 1;
1251 text = imap_bye;
1252 text_len = sizeof(imap_bye) - 1;
1253 break;
1254
1255 case NGX_IMAP_NOOP:
1256 break;
1257
1258 #if (NGX_MAIL_SSL)
1259
1260 case NGX_IMAP_STARTTLS:
1261 if (c->ssl == NULL) {
1262 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
1263 if (sslcf->starttls) {
1264 c->read->handler = ngx_mail_starttls_handler;
1265 break;
1266 }
1267 }
1268
1269 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1270 break;
1271 #endif
1272
1273 default:
1274 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1275 break;
1276 }
1277
1278 break;
1279
1280 case ngx_imap_auth_login_username:
1087 arg = s->args.elts; 1281 arg = s->args.elts;
1088 1282 s->mail_state = ngx_imap_auth_login_password;
1089 if (s->args.nelts == 2 && arg[0].len) { 1283
1090 1284 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
1091 s->login.len = arg[0].len; 1285 "imap auth login username: \"%V\"", &arg[0]);
1092 s->login.data = ngx_palloc(c->pool, s->login.len); 1286
1093 if (s->login.data == NULL) { 1287 s->login.data = ngx_palloc(c->pool,
1094 ngx_mail_session_internal_server_error(s); 1288 ngx_base64_decoded_length(arg[0].len));
1095 return; 1289 if (s->login.data == NULL){
1096 } 1290 ngx_mail_session_internal_server_error(s);
1097 1291 return;
1098 ngx_memcpy(s->login.data, arg[0].data, s->login.len); 1292 }
1099 1293
1100 s->passwd.len = arg[1].len; 1294 if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) {
1101 s->passwd.data = ngx_palloc(c->pool, s->passwd.len); 1295 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1102 if (s->passwd.data == NULL) { 1296 "client sent invalid base64 encoding "
1103 ngx_mail_session_internal_server_error(s); 1297 "in AUTH LOGIN command");
1104 return; 1298 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1105 } 1299 break;
1106 1300 }
1107 ngx_memcpy(s->passwd.data, arg[1].data, s->passwd.len); 1301
1302 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
1303 "imap auth login username: \"%V\"", &s->login);
1304
1305 last_len = sizeof(pop3_password) - 1;
1306 last = pop3_password;
1307 tag = 0;
1308
1309 break;
1310
1311 case ngx_imap_auth_login_password:
1312 arg = s->args.elts;
1108 1313
1109 #if (NGX_DEBUG_MAIL_PASSWD) 1314 #if (NGX_DEBUG_MAIL_PASSWD)
1110 ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0, 1315 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
1111 "imap login:\"%V\" passwd:\"%V\"", 1316 "imap auth login password: \"%V\"", &arg[0]);
1112 &s->login, &s->passwd); 1317 #endif
1113 #else 1318
1114 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, 1319 s->passwd.data = ngx_palloc(c->pool,
1115 "imap login:\"%V\"", &s->login); 1320 ngx_base64_decoded_length(arg[0].len));
1116 #endif 1321 if (s->passwd.data == NULL){
1117 1322 ngx_mail_session_internal_server_error(s);
1323 return;
1324 }
1325
1326 if (ngx_decode_base64(&s->passwd, &arg[0]) != NGX_OK) {
1327 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1328 "client sent invalid base64 encoding "
1329 "in AUTH LOGIN command");
1330 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1331 break;
1332 }
1333
1334 #if (NGX_DEBUG_MAIL_PASSWD)
1335 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
1336 "imap auth login password: \"%V\"", &s->passwd);
1337 #endif
1338
1339 ngx_mail_do_auth(s);
1340 return;
1341
1342 case ngx_imap_auth_plain:
1343 arg = s->args.elts;
1344
1345 rc = ngx_mail_decode_auth_plain(s, &arg[0]);
1346
1347 if (rc == NGX_OK) {
1118 ngx_mail_do_auth(s); 1348 ngx_mail_do_auth(s);
1119 return; 1349 return;
1120 } 1350 }
1121 1351
1122 rc = NGX_MAIL_PARSE_INVALID_COMMAND; 1352 if (rc == NGX_ERROR) {
1353 ngx_mail_session_internal_server_error(s);
1354 return;
1355 }
1356
1357 /* rc == NGX_MAIL_PARSE_INVALID_COMMAND */
1358
1123 break; 1359 break;
1124 1360
1125 case NGX_IMAP_CAPABILITY: 1361 case ngx_imap_auth_cram_md5:
1126 cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); 1362 arg = s->args.elts;
1127 1363
1128 #if (NGX_MAIL_SSL) 1364 ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
1129 1365 "imap auth cram-md5: \"%V\"", &arg[0]);
1130 if (c->ssl == NULL) { 1366
1131 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); 1367 s->login.data = ngx_palloc(c->pool,
1132 1368 ngx_base64_decoded_length(arg[0].len));
1133 if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) { 1369 if (s->login.data == NULL){
1134 text_len = cscf->imap_starttls_capability.len; 1370 ngx_mail_session_internal_server_error(s);
1135 text = cscf->imap_starttls_capability.data; 1371 return;
1372 }
1373
1374 if (ngx_decode_base64(&s->login, &arg[0]) != NGX_OK) {
1375 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1376 "client sent invalid base64 encoding "
1377 "in AUTH CRAM-MD5 command");
1378 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1379 break;
1380 }
1381
1382 p = s->login.data;
1383 last = p + s->login.len;
1384
1385 while (p < last) {
1386 if (*p++ == ' ') {
1387 s->login.len = p - s->login.data - 1;
1388 s->passwd.len = last - p;
1389 s->passwd.data = p;
1136 break; 1390 break;
1137 } 1391 }
1138 1392 }
1139 if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) { 1393
1140 text_len = cscf->imap_starttls_only_capability.len; 1394 if (s->passwd.len != 32) {
1141 text = cscf->imap_starttls_only_capability.data; 1395 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1142 break; 1396 "client sent invalid CRAM-MD5 hash "
1143 } 1397 "in AUTH CRAM-MD5 command");
1144 } 1398 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1145 #endif 1399 break;
1146 1400 }
1147 text_len = cscf->imap_capability.len; 1401
1148 text = cscf->imap_capability.data; 1402 ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
1149 break; 1403 "imap auth cram-md5: \"%V\" \"%V\"",
1150 1404 &s->login, &s->passwd);
1151 case NGX_IMAP_LOGOUT: 1405
1152 s->quit = 1; 1406 s->auth_method = NGX_MAIL_AUTH_CRAM_MD5;
1153 text = imap_bye; 1407
1154 text_len = sizeof(imap_bye) - 1; 1408 ngx_mail_do_auth(s);
1155 break; 1409 return;
1156 1410
1157 case NGX_IMAP_NOOP:
1158 break;
1159
1160 #if (NGX_MAIL_SSL)
1161
1162 case NGX_IMAP_STARTTLS:
1163 if (c->ssl == NULL) {
1164 sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
1165 if (sslcf->starttls) {
1166 c->read->handler = ngx_mail_starttls_handler;
1167 break;
1168 }
1169 }
1170
1171 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1172 break;
1173 #endif
1174
1175 default:
1176 rc = NGX_MAIL_PARSE_INVALID_COMMAND;
1177 break;
1178 } 1411 }
1179 1412
1180 } else if (rc == NGX_IMAP_NEXT) { 1413 } else if (rc == NGX_IMAP_NEXT) {
1181 last = imap_next; 1414 last = imap_next;
1182 last_len = sizeof(imap_next) - 1; 1415 last_len = sizeof(imap_next) - 1;
1183 tag = 0; 1416 tag = 0;
1184 } 1417 }
1185 1418
1186 if (rc == NGX_MAIL_PARSE_INVALID_COMMAND) { 1419 if (rc == NGX_MAIL_PARSE_INVALID_COMMAND) {
1420 s->mail_state = ngx_imap_start;
1421 s->state = 0;
1187 last = imap_invalid_command; 1422 last = imap_invalid_command;
1188 last_len = sizeof(imap_invalid_command) - 1; 1423 last_len = sizeof(imap_invalid_command) - 1;
1189 } 1424 }
1190 1425
1191 if (tag) { 1426 if (tag) {
1220 s->out.len = last_len; 1455 s->out.len = last_len;
1221 } 1456 }
1222 1457
1223 if (rc != NGX_IMAP_NEXT) { 1458 if (rc != NGX_IMAP_NEXT) {
1224 s->args.nelts = 0; 1459 s->args.nelts = 0;
1225 s->buffer->pos = s->buffer->start; 1460
1226 s->buffer->last = s->buffer->start; 1461 if (s->state) {
1227 s->tag.len = 0; 1462 /* preserve tag */
1463 s->arg_start = s->buffer->start + s->tag.len;
1464 s->buffer->pos = s->arg_start;
1465 s->buffer->last = s->arg_start;
1466 } else {
1467 s->buffer->pos = s->buffer->start;
1468 s->buffer->last = s->buffer->start;
1469 s->tag.len = 0;
1470 }
1228 } 1471 }
1229 1472
1230 ngx_mail_send(c->write); 1473 ngx_mail_send(c->write);
1231 } 1474 }
1232 1475