Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_mail_imap_handler.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_event.h>
11 #include <ngx_mail.h>
12 #include <ngx_mail_imap_module.h>
13 
14 
15 static ngx_int_t ngx_mail_imap_login(ngx_mail_session_t *s,
16  ngx_connection_t *c);
17 static ngx_int_t ngx_mail_imap_authenticate(ngx_mail_session_t *s,
18  ngx_connection_t *c);
19 static ngx_int_t ngx_mail_imap_capability(ngx_mail_session_t *s,
20  ngx_connection_t *c);
21 static ngx_int_t ngx_mail_imap_starttls(ngx_mail_session_t *s,
22  ngx_connection_t *c);
23 
24 
25 static u_char imap_greeting[] = "* OK IMAP4 ready" CRLF;
26 static u_char imap_star[] = "* ";
27 static u_char imap_ok[] = "OK completed" CRLF;
28 static u_char imap_next[] = "+ OK" CRLF;
29 static u_char imap_plain_next[] = "+ " CRLF;
30 static u_char imap_username[] = "+ VXNlcm5hbWU6" CRLF;
31 static u_char imap_password[] = "+ UGFzc3dvcmQ6" CRLF;
32 static u_char imap_bye[] = "* BYE" CRLF;
33 static u_char imap_invalid_command[] = "BAD invalid command" CRLF;
34 
35 
36 void
38 {
40 
42 
43  ngx_str_set(&s->out, imap_greeting);
44 
46 
47  ngx_add_timer(c->read, cscf->timeout);
48 
49  if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
51  }
52 
53  ngx_mail_send(c->write);
54 }
55 
56 
57 void
59 {
63 
64  c = rev->data;
65 
66  c->log->action = "in auth state";
67 
68  if (rev->timedout) {
69  ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
70  c->timedout = 1;
72  return;
73  }
74 
75  s = c->data;
76 
77  if (s->buffer == NULL) {
78  if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t))
79  == NGX_ERROR)
80  {
82  return;
83  }
84 
86 
88  if (s->buffer == NULL) {
90  return;
91  }
92  }
93 
96 
98 }
99 
100 
101 void
103 {
104  u_char *p, *dst, *src, *end;
105  ngx_str_t *arg;
106  ngx_int_t rc;
107  ngx_uint_t tag, i;
108  ngx_connection_t *c;
110 
111  c = rev->data;
112  s = c->data;
113 
114  ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap auth state");
115 
116  if (rev->timedout) {
117  ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
118  c->timedout = 1;
120  return;
121  }
122 
123  if (s->out.len) {
124  ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap send handler busy");
125  s->blocked = 1;
126  return;
127  }
128 
129  s->blocked = 0;
130 
131  rc = ngx_mail_read_command(s, c);
132 
133  if (rc == NGX_AGAIN || rc == NGX_ERROR) {
134  return;
135  }
136 
137  tag = 1;
138  s->text.len = 0;
139  ngx_str_set(&s->out, imap_ok);
140 
141  if (rc == NGX_OK) {
142 
143  ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0, "imap auth command: %i",
144  s->command);
145 
146  if (s->backslash) {
147 
148  arg = s->args.elts;
149 
150  for (i = 0; i < s->args.nelts; i++) {
151  dst = arg[i].data;
152  end = dst + arg[i].len;
153 
154  for (src = dst; src < end; dst++) {
155  *dst = *src;
156  if (*src++ == '\\') {
157  *dst = *src++;
158  }
159  }
160 
161  arg[i].len = dst - arg[i].data;
162  }
163 
164  s->backslash = 0;
165  }
166 
167  switch (s->mail_state) {
168 
169  case ngx_imap_start:
170 
171  switch (s->command) {
172 
173  case NGX_IMAP_LOGIN:
174  rc = ngx_mail_imap_login(s, c);
175  break;
176 
178  rc = ngx_mail_imap_authenticate(s, c);
179  tag = (rc != NGX_OK);
180  break;
181 
182  case NGX_IMAP_CAPABILITY:
183  rc = ngx_mail_imap_capability(s, c);
184  break;
185 
186  case NGX_IMAP_LOGOUT:
187  s->quit = 1;
188  ngx_str_set(&s->text, imap_bye);
189  break;
190 
191  case NGX_IMAP_NOOP:
192  break;
193 
194  case NGX_IMAP_STARTTLS:
195  rc = ngx_mail_imap_starttls(s, c);
196  break;
197 
198  default:
200  break;
201  }
202 
203  break;
204 
206  rc = ngx_mail_auth_login_username(s, c, 0);
207 
208  tag = 0;
209  ngx_str_set(&s->out, imap_password);
211 
212  break;
213 
215  rc = ngx_mail_auth_login_password(s, c);
216  break;
217 
218  case ngx_imap_auth_plain:
219  rc = ngx_mail_auth_plain(s, c, 0);
220  break;
221 
223  rc = ngx_mail_auth_cram_md5(s, c);
224  break;
225  }
226 
227  } else if (rc == NGX_IMAP_NEXT) {
228  tag = 0;
229  ngx_str_set(&s->out, imap_next);
230  }
231 
232  switch (rc) {
233 
234  case NGX_DONE:
235  ngx_mail_auth(s, c);
236  return;
237 
238  case NGX_ERROR:
240  return;
241 
243  s->state = 0;
244  ngx_str_set(&s->out, imap_invalid_command);
246  break;
247  }
248 
249  if (tag) {
250  if (s->tag.len == 0) {
251  ngx_str_set(&s->tag, imap_star);
252  }
253 
254  if (s->tagged_line.len < s->tag.len + s->text.len + s->out.len) {
255  s->tagged_line.len = s->tag.len + s->text.len + s->out.len;
257  if (s->tagged_line.data == NULL) {
259  return;
260  }
261  }
262 
263  p = s->tagged_line.data;
264 
265  if (s->text.len) {
266  p = ngx_cpymem(p, s->text.data, s->text.len);
267  }
268 
269  p = ngx_cpymem(p, s->tag.data, s->tag.len);
270  ngx_memcpy(p, s->out.data, s->out.len);
271 
272  s->out.len = s->text.len + s->tag.len + s->out.len;
273  s->out.data = s->tagged_line.data;
274  }
275 
276  if (rc != NGX_IMAP_NEXT) {
277  s->args.nelts = 0;
278 
279  if (s->state) {
280  /* preserve tag */
281  s->arg_start = s->buffer->start + s->tag.len;
282  s->buffer->pos = s->arg_start;
283  s->buffer->last = s->arg_start;
284 
285  } else {
286  s->buffer->pos = s->buffer->start;
287  s->buffer->last = s->buffer->start;
288  s->tag.len = 0;
289  }
290  }
291 
292  ngx_mail_send(c->write);
293 }
294 
295 
296 static ngx_int_t
297 ngx_mail_imap_login(ngx_mail_session_t *s, ngx_connection_t *c)
298 {
299  ngx_str_t *arg;
300 
301 #if (NGX_MAIL_SSL)
302  if (ngx_mail_starttls_only(s, c)) {
304  }
305 #endif
306 
307  arg = s->args.elts;
308 
309  if (s->args.nelts != 2 || arg[0].len == 0) {
311  }
312 
313  s->login.len = arg[0].len;
314  s->login.data = ngx_pnalloc(c->pool, s->login.len);
315  if (s->login.data == NULL) {
316  return NGX_ERROR;
317  }
318 
319  ngx_memcpy(s->login.data, arg[0].data, s->login.len);
320 
321  s->passwd.len = arg[1].len;
322  s->passwd.data = ngx_pnalloc(c->pool, s->passwd.len);
323  if (s->passwd.data == NULL) {
324  return NGX_ERROR;
325  }
326 
327  ngx_memcpy(s->passwd.data, arg[1].data, s->passwd.len);
328 
329 #if (NGX_DEBUG_MAIL_PASSWD)
331  "imap login:\"%V\" passwd:\"%V\"",
332  &s->login, &s->passwd);
333 #else
335  "imap login:\"%V\"", &s->login);
336 #endif
337 
338  return NGX_DONE;
339 }
340 
341 
342 static ngx_int_t
343 ngx_mail_imap_authenticate(ngx_mail_session_t *s, ngx_connection_t *c)
344 {
345  ngx_int_t rc;
348 
349 #if (NGX_MAIL_SSL)
350  if (ngx_mail_starttls_only(s, c)) {
352  }
353 #endif
354 
355  rc = ngx_mail_auth_parse(s, c);
356 
357  switch (rc) {
358 
359  case NGX_MAIL_AUTH_LOGIN:
360 
361  ngx_str_set(&s->out, imap_username);
363 
364  return NGX_OK;
365 
367 
368  ngx_str_set(&s->out, imap_password);
370 
371  return ngx_mail_auth_login_username(s, c, 1);
372 
373  case NGX_MAIL_AUTH_PLAIN:
374 
375  ngx_str_set(&s->out, imap_plain_next);
377 
378  return NGX_OK;
379 
381 
383 
386  }
387 
388  if (s->salt.data == NULL) {
390 
391  if (ngx_mail_salt(s, c, cscf) != NGX_OK) {
392  return NGX_ERROR;
393  }
394  }
395 
396  if (ngx_mail_auth_cram_md5_salt(s, c, "+ ", 2) == NGX_OK) {
398  return NGX_OK;
399  }
400 
401  return NGX_ERROR;
402  }
403 
404  return rc;
405 }
406 
407 
408 static ngx_int_t
409 ngx_mail_imap_capability(ngx_mail_session_t *s, ngx_connection_t *c)
410 {
412 
414 
415 #if (NGX_MAIL_SSL)
416 
417  if (c->ssl == NULL) {
418  ngx_mail_ssl_conf_t *sslcf;
419 
421 
422  if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) {
423  s->text = iscf->starttls_capability;
424  return NGX_OK;
425  }
426 
427  if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
428  s->text = iscf->starttls_only_capability;
429  return NGX_OK;
430  }
431  }
432 #endif
433 
434  s->text = iscf->capability;
435 
436  return NGX_OK;
437 }
438 
439 
440 static ngx_int_t
441 ngx_mail_imap_starttls(ngx_mail_session_t *s, ngx_connection_t *c)
442 {
443 #if (NGX_MAIL_SSL)
444  ngx_mail_ssl_conf_t *sslcf;
445 
446  if (c->ssl == NULL) {
448  if (sslcf->starttls) {
449  c->read->handler = ngx_mail_starttls_handler;
450  return NGX_OK;
451  }
452  }
453 
454 #endif
455 
457 }