comparison src/mail/ngx_mail_handler.c @ 1323:c4b2c893989d

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