Annotation of embedaddon/nginx/src/mail/ngx_mail_parse.c, revision 1.1.1.1

1.1       misho       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_pop3_module.h>
                     13: #include <ngx_mail_imap_module.h>
                     14: #include <ngx_mail_smtp_module.h>
                     15: 
                     16: 
                     17: ngx_int_t
                     18: ngx_mail_pop3_parse_command(ngx_mail_session_t *s)
                     19: {
                     20:     u_char      ch, *p, *c, c0, c1, c2, c3;
                     21:     ngx_str_t  *arg;
                     22:     enum {
                     23:         sw_start = 0,
                     24:         sw_spaces_before_argument,
                     25:         sw_argument,
                     26:         sw_almost_done
                     27:     } state;
                     28: 
                     29:     state = s->state;
                     30: 
                     31:     for (p = s->buffer->pos; p < s->buffer->last; p++) {
                     32:         ch = *p;
                     33: 
                     34:         switch (state) {
                     35: 
                     36:         /* POP3 command */
                     37:         case sw_start:
                     38:             if (ch == ' ' || ch == CR || ch == LF) {
                     39:                 c = s->buffer->start;
                     40: 
                     41:                 if (p - c == 4) {
                     42: 
                     43:                     c0 = ngx_toupper(c[0]);
                     44:                     c1 = ngx_toupper(c[1]);
                     45:                     c2 = ngx_toupper(c[2]);
                     46:                     c3 = ngx_toupper(c[3]);
                     47: 
                     48:                     if (c0 == 'U' && c1 == 'S' && c2 == 'E' && c3 == 'R')
                     49:                     {
                     50:                         s->command = NGX_POP3_USER;
                     51: 
                     52:                     } else if (c0 == 'P' && c1 == 'A' && c2 == 'S' && c3 == 'S')
                     53:                     {
                     54:                         s->command = NGX_POP3_PASS;
                     55: 
                     56:                     } else if (c0 == 'A' && c1 == 'P' && c2 == 'O' && c3 == 'P')
                     57:                     {
                     58:                         s->command = NGX_POP3_APOP;
                     59: 
                     60:                     } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T')
                     61:                     {
                     62:                         s->command = NGX_POP3_QUIT;
                     63: 
                     64:                     } else if (c0 == 'C' && c1 == 'A' && c2 == 'P' && c3 == 'A')
                     65:                     {
                     66:                         s->command = NGX_POP3_CAPA;
                     67: 
                     68:                     } else if (c0 == 'A' && c1 == 'U' && c2 == 'T' && c3 == 'H')
                     69:                     {
                     70:                         s->command = NGX_POP3_AUTH;
                     71: 
                     72:                     } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P')
                     73:                     {
                     74:                         s->command = NGX_POP3_NOOP;
                     75: #if (NGX_MAIL_SSL)
                     76:                     } else if (c0 == 'S' && c1 == 'T' && c2 == 'L' && c3 == 'S')
                     77:                     {
                     78:                         s->command = NGX_POP3_STLS;
                     79: #endif
                     80:                     } else {
                     81:                         goto invalid;
                     82:                     }
                     83: 
                     84:                 } else {
                     85:                     goto invalid;
                     86:                 }
                     87: 
                     88:                 switch (ch) {
                     89:                 case ' ':
                     90:                     state = sw_spaces_before_argument;
                     91:                     break;
                     92:                 case CR:
                     93:                     state = sw_almost_done;
                     94:                     break;
                     95:                 case LF:
                     96:                     goto done;
                     97:                 }
                     98:                 break;
                     99:             }
                    100: 
                    101:             if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) {
                    102:                 goto invalid;
                    103:             }
                    104: 
                    105:             break;
                    106: 
                    107:         case sw_spaces_before_argument:
                    108:             switch (ch) {
                    109:             case ' ':
                    110:                 break;
                    111:             case CR:
                    112:                 state = sw_almost_done;
                    113:                 s->arg_end = p;
                    114:                 break;
                    115:             case LF:
                    116:                 s->arg_end = p;
                    117:                 goto done;
                    118:             default:
                    119:                 if (s->args.nelts <= 2) {
                    120:                     state = sw_argument;
                    121:                     s->arg_start = p;
                    122:                     break;
                    123:                 }
                    124:                 goto invalid;
                    125:             }
                    126:             break;
                    127: 
                    128:         case sw_argument:
                    129:             switch (ch) {
                    130: 
                    131:             case ' ':
                    132: 
                    133:                 /*
                    134:                  * the space should be considered as part of the at username
                    135:                  * or password, but not of argument in other commands
                    136:                  */
                    137: 
                    138:                 if (s->command == NGX_POP3_USER
                    139:                     || s->command == NGX_POP3_PASS)
                    140:                 {
                    141:                     break;
                    142:                 }
                    143: 
                    144:                 /* fall through */
                    145: 
                    146:             case CR:
                    147:             case LF:
                    148:                 arg = ngx_array_push(&s->args);
                    149:                 if (arg == NULL) {
                    150:                     return NGX_ERROR;
                    151:                 }
                    152:                 arg->len = p - s->arg_start;
                    153:                 arg->data = s->arg_start;
                    154:                 s->arg_start = NULL;
                    155: 
                    156:                 switch (ch) {
                    157:                 case ' ':
                    158:                     state = sw_spaces_before_argument;
                    159:                     break;
                    160:                 case CR:
                    161:                     state = sw_almost_done;
                    162:                     break;
                    163:                 case LF:
                    164:                     goto done;
                    165:                 }
                    166:                 break;
                    167: 
                    168:             default:
                    169:                 break;
                    170:             }
                    171:             break;
                    172: 
                    173:         case sw_almost_done:
                    174:             switch (ch) {
                    175:             case LF:
                    176:                 goto done;
                    177:             default:
                    178:                 goto invalid;
                    179:             }
                    180:         }
                    181:     }
                    182: 
                    183:     s->buffer->pos = p;
                    184:     s->state = state;
                    185: 
                    186:     return NGX_AGAIN;
                    187: 
                    188: done:
                    189: 
                    190:     s->buffer->pos = p + 1;
                    191: 
                    192:     if (s->arg_start) {
                    193:         arg = ngx_array_push(&s->args);
                    194:         if (arg == NULL) {
                    195:             return NGX_ERROR;
                    196:         }
                    197:         arg->len = s->arg_end - s->arg_start;
                    198:         arg->data = s->arg_start;
                    199:         s->arg_start = NULL;
                    200:     }
                    201: 
                    202:     s->state = (s->command != NGX_POP3_AUTH) ? sw_start : sw_argument;
                    203: 
                    204:     return NGX_OK;
                    205: 
                    206: invalid:
                    207: 
                    208:     s->state = sw_start;
                    209:     s->arg_start = NULL;
                    210: 
                    211:     return NGX_MAIL_PARSE_INVALID_COMMAND;
                    212: }
                    213: 
                    214: 
                    215: ngx_int_t
                    216: ngx_mail_imap_parse_command(ngx_mail_session_t *s)
                    217: {
                    218:     u_char      ch, *p, *c;
                    219:     ngx_str_t  *arg;
                    220:     enum {
                    221:         sw_start = 0,
                    222:         sw_spaces_before_command,
                    223:         sw_command,
                    224:         sw_spaces_before_argument,
                    225:         sw_argument,
                    226:         sw_backslash,
                    227:         sw_literal,
                    228:         sw_no_sync_literal_argument,
                    229:         sw_start_literal_argument,
                    230:         sw_literal_argument,
                    231:         sw_end_literal_argument,
                    232:         sw_almost_done
                    233:     } state;
                    234: 
                    235:     state = s->state;
                    236: 
                    237:     for (p = s->buffer->pos; p < s->buffer->last; p++) {
                    238:         ch = *p;
                    239: 
                    240:         switch (state) {
                    241: 
                    242:         /* IMAP tag */
                    243:         case sw_start:
                    244:             switch (ch) {
                    245:             case ' ':
                    246:                 s->tag.len = p - s->buffer->start + 1;
                    247:                 s->tag.data = s->buffer->start;
                    248:                 state = sw_spaces_before_command;
                    249:                 break;
                    250:             case CR:
                    251:                 s->state = sw_start;
                    252:                 return NGX_MAIL_PARSE_INVALID_COMMAND;
                    253:             case LF:
                    254:                 s->state = sw_start;
                    255:                 return NGX_MAIL_PARSE_INVALID_COMMAND;
                    256:             }
                    257:             break;
                    258: 
                    259:         case sw_spaces_before_command:
                    260:             switch (ch) {
                    261:             case ' ':
                    262:                 break;
                    263:             case CR:
                    264:                 s->state = sw_start;
                    265:                 return NGX_MAIL_PARSE_INVALID_COMMAND;
                    266:             case LF:
                    267:                 s->state = sw_start;
                    268:                 return NGX_MAIL_PARSE_INVALID_COMMAND;
                    269:             default:
                    270:                 s->cmd_start = p;
                    271:                 state = sw_command;
                    272:                 break;
                    273:             }
                    274:             break;
                    275: 
                    276:         case sw_command:
                    277:             if (ch == ' ' || ch == CR || ch == LF) {
                    278: 
                    279:                 c = s->cmd_start;
                    280: 
                    281:                 switch (p - c) {
                    282: 
                    283:                 case 4:
                    284:                     if ((c[0] == 'N' || c[0] == 'n')
                    285:                         && (c[1] == 'O'|| c[1] == 'o')
                    286:                         && (c[2] == 'O'|| c[2] == 'o')
                    287:                         && (c[3] == 'P'|| c[3] == 'p'))
                    288:                     {
                    289:                         s->command = NGX_IMAP_NOOP;
                    290: 
                    291:                     } else {
                    292:                         goto invalid;
                    293:                     }
                    294:                     break;
                    295: 
                    296:                 case 5:
                    297:                     if ((c[0] == 'L'|| c[0] == 'l')
                    298:                         && (c[1] == 'O'|| c[1] == 'o')
                    299:                         && (c[2] == 'G'|| c[2] == 'g')
                    300:                         && (c[3] == 'I'|| c[3] == 'i')
                    301:                         && (c[4] == 'N'|| c[4] == 'n'))
                    302:                     {
                    303:                         s->command = NGX_IMAP_LOGIN;
                    304: 
                    305:                     } else {
                    306:                         goto invalid;
                    307:                     }
                    308:                     break;
                    309: 
                    310:                 case 6:
                    311:                     if ((c[0] == 'L'|| c[0] == 'l')
                    312:                         && (c[1] == 'O'|| c[1] == 'o')
                    313:                         && (c[2] == 'G'|| c[2] == 'g')
                    314:                         && (c[3] == 'O'|| c[3] == 'o')
                    315:                         && (c[4] == 'U'|| c[4] == 'u')
                    316:                         && (c[5] == 'T'|| c[5] == 't'))
                    317:                     {
                    318:                         s->command = NGX_IMAP_LOGOUT;
                    319: 
                    320:                     } else {
                    321:                         goto invalid;
                    322:                     }
                    323:                     break;
                    324: 
                    325: #if (NGX_MAIL_SSL)
                    326:                 case 8:
                    327:                     if ((c[0] == 'S'|| c[0] == 's')
                    328:                         && (c[1] == 'T'|| c[1] == 't')
                    329:                         && (c[2] == 'A'|| c[2] == 'a')
                    330:                         && (c[3] == 'R'|| c[3] == 'r')
                    331:                         && (c[4] == 'T'|| c[4] == 't')
                    332:                         && (c[5] == 'T'|| c[5] == 't')
                    333:                         && (c[6] == 'L'|| c[6] == 'l')
                    334:                         && (c[7] == 'S'|| c[7] == 's'))
                    335:                     {
                    336:                         s->command = NGX_IMAP_STARTTLS;
                    337: 
                    338:                     } else {
                    339:                         goto invalid;
                    340:                     }
                    341:                     break;
                    342: #endif
                    343: 
                    344:                 case 10:
                    345:                     if ((c[0] == 'C'|| c[0] == 'c')
                    346:                         && (c[1] == 'A'|| c[1] == 'a')
                    347:                         && (c[2] == 'P'|| c[2] == 'p')
                    348:                         && (c[3] == 'A'|| c[3] == 'a')
                    349:                         && (c[4] == 'B'|| c[4] == 'b')
                    350:                         && (c[5] == 'I'|| c[5] == 'i')
                    351:                         && (c[6] == 'L'|| c[6] == 'l')
                    352:                         && (c[7] == 'I'|| c[7] == 'i')
                    353:                         && (c[8] == 'T'|| c[8] == 't')
                    354:                         && (c[9] == 'Y'|| c[9] == 'y'))
                    355:                     {
                    356:                         s->command = NGX_IMAP_CAPABILITY;
                    357: 
                    358:                     } else {
                    359:                         goto invalid;
                    360:                     }
                    361:                     break;
                    362: 
                    363:                 case 12:
                    364:                     if ((c[0] == 'A'|| c[0] == 'a')
                    365:                         && (c[1] == 'U'|| c[1] == 'u')
                    366:                         && (c[2] == 'T'|| c[2] == 't')
                    367:                         && (c[3] == 'H'|| c[3] == 'h')
                    368:                         && (c[4] == 'E'|| c[4] == 'e')
                    369:                         && (c[5] == 'N'|| c[5] == 'n')
                    370:                         && (c[6] == 'T'|| c[6] == 't')
                    371:                         && (c[7] == 'I'|| c[7] == 'i')
                    372:                         && (c[8] == 'C'|| c[8] == 'c')
                    373:                         && (c[9] == 'A'|| c[9] == 'a')
                    374:                         && (c[10] == 'T'|| c[10] == 't')
                    375:                         && (c[11] == 'E'|| c[11] == 'e'))
                    376:                     {
                    377:                         s->command = NGX_IMAP_AUTHENTICATE;
                    378: 
                    379:                     } else {
                    380:                         goto invalid;
                    381:                     }
                    382:                     break;
                    383: 
                    384:                 default:
                    385:                     goto invalid;
                    386:                 }
                    387: 
                    388:                 switch (ch) {
                    389:                 case ' ':
                    390:                     state = sw_spaces_before_argument;
                    391:                     break;
                    392:                 case CR:
                    393:                     state = sw_almost_done;
                    394:                     break;
                    395:                 case LF:
                    396:                     goto done;
                    397:                 }
                    398:                 break;
                    399:             }
                    400: 
                    401:             if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) {
                    402:                 goto invalid;
                    403:             }
                    404: 
                    405:             break;
                    406: 
                    407:         case sw_spaces_before_argument:
                    408:             switch (ch) {
                    409:             case ' ':
                    410:                 break;
                    411:             case CR:
                    412:                 state = sw_almost_done;
                    413:                 s->arg_end = p;
                    414:                 break;
                    415:             case LF:
                    416:                 s->arg_end = p;
                    417:                 goto done;
                    418:             case '"':
                    419:                 if (s->args.nelts <= 2) {
                    420:                     s->quoted = 1;
                    421:                     s->arg_start = p + 1;
                    422:                     state = sw_argument;
                    423:                     break;
                    424:                 }
                    425:                 goto invalid;
                    426:             case '{':
                    427:                 if (s->args.nelts <= 2) {
                    428:                     state = sw_literal;
                    429:                     break;
                    430:                 }
                    431:                 goto invalid;
                    432:             default:
                    433:                 if (s->args.nelts <= 2) {
                    434:                     s->arg_start = p;
                    435:                     state = sw_argument;
                    436:                     break;
                    437:                 }
                    438:                 goto invalid;
                    439:             }
                    440:             break;
                    441: 
                    442:         case sw_argument:
                    443:             if (ch == ' ' && s->quoted) {
                    444:                 break;
                    445:             }
                    446: 
                    447:             switch (ch) {
                    448:             case '"':
                    449:                 if (!s->quoted) {
                    450:                     break;
                    451:                 }
                    452:                 s->quoted = 0;
                    453:                 /* fall through */
                    454:             case ' ':
                    455:             case CR:
                    456:             case LF:
                    457:                 arg = ngx_array_push(&s->args);
                    458:                 if (arg == NULL) {
                    459:                     return NGX_ERROR;
                    460:                 }
                    461:                 arg->len = p - s->arg_start;
                    462:                 arg->data = s->arg_start;
                    463:                 s->arg_start = NULL;
                    464: 
                    465:                 switch (ch) {
                    466:                 case '"':
                    467:                 case ' ':
                    468:                     state = sw_spaces_before_argument;
                    469:                     break;
                    470:                 case CR:
                    471:                     state = sw_almost_done;
                    472:                     break;
                    473:                 case LF:
                    474:                     goto done;
                    475:                 }
                    476:                 break;
                    477:             case '\\':
                    478:                 if (s->quoted) {
                    479:                     s->backslash = 1;
                    480:                     state = sw_backslash;
                    481:                 }
                    482:                 break;
                    483:             }
                    484:             break;
                    485: 
                    486:         case sw_backslash:
                    487:             switch (ch) {
                    488:             case CR:
                    489:             case LF:
                    490:                 goto invalid;
                    491:             default:
                    492:                 state = sw_argument;
                    493:             }
                    494:             break;
                    495: 
                    496:         case sw_literal:
                    497:             if (ch >= '0' && ch <= '9') {
                    498:                 s->literal_len = s->literal_len * 10 + (ch - '0');
                    499:                 break;
                    500:             }
                    501:             if (ch == '}') {
                    502:                 state = sw_start_literal_argument;
                    503:                 break;
                    504:             }
                    505:             if (ch == '+') {
                    506:                 state = sw_no_sync_literal_argument;
                    507:                 break;
                    508:             }
                    509:             goto invalid;
                    510: 
                    511:         case sw_no_sync_literal_argument:
                    512:             if (ch == '}') {
                    513:                 s->no_sync_literal = 1;
                    514:                 state = sw_start_literal_argument;
                    515:                 break;
                    516:             }
                    517:             goto invalid;
                    518: 
                    519:         case sw_start_literal_argument:
                    520:             switch (ch) {
                    521:             case CR:
                    522:                 break;
                    523:             case LF:
                    524:                 s->buffer->pos = p + 1;
                    525:                 s->arg_start = p + 1;
                    526:                 if (s->no_sync_literal == 0) {
                    527:                     s->state = sw_literal_argument;
                    528:                     return NGX_IMAP_NEXT;
                    529:                 }
                    530:                 state = sw_literal_argument;
                    531:                 s->no_sync_literal = 0;
                    532:                 break;
                    533:             default:
                    534:                 goto invalid;
                    535:             }
                    536:             break;
                    537: 
                    538:         case sw_literal_argument:
                    539:             if (s->literal_len && --s->literal_len) {
                    540:                 break;
                    541:             }
                    542: 
                    543:             arg = ngx_array_push(&s->args);
                    544:             if (arg == NULL) {
                    545:                 return NGX_ERROR;
                    546:             }
                    547:             arg->len = p + 1 - s->arg_start;
                    548:             arg->data = s->arg_start;
                    549:             s->arg_start = NULL;
                    550:             state = sw_end_literal_argument;
                    551: 
                    552:             break;
                    553: 
                    554:         case sw_end_literal_argument:
                    555:             switch (ch) {
                    556:             case '{':
                    557:                 if (s->args.nelts <= 2) {
                    558:                     state = sw_literal;
                    559:                     break;
                    560:                 }
                    561:                 goto invalid;
                    562:             case CR:
                    563:                 state = sw_almost_done;
                    564:                 break;
                    565:             case LF:
                    566:                 goto done;
                    567:             default:
                    568:                 state = sw_spaces_before_argument;
                    569:                 break;
                    570:             }
                    571:             break;
                    572: 
                    573:         case sw_almost_done:
                    574:             switch (ch) {
                    575:             case LF:
                    576:                 goto done;
                    577:             default:
                    578:                 goto invalid;
                    579:             }
                    580:         }
                    581:     }
                    582: 
                    583:     s->buffer->pos = p;
                    584:     s->state = state;
                    585: 
                    586:     return NGX_AGAIN;
                    587: 
                    588: done:
                    589: 
                    590:     s->buffer->pos = p + 1;
                    591: 
                    592:     if (s->arg_start) {
                    593:         arg = ngx_array_push(&s->args);
                    594:         if (arg == NULL) {
                    595:             return NGX_ERROR;
                    596:         }
                    597:         arg->len = s->arg_end - s->arg_start;
                    598:         arg->data = s->arg_start;
                    599: 
                    600:         s->arg_start = NULL;
                    601:         s->cmd_start = NULL;
                    602:         s->quoted = 0;
                    603:         s->no_sync_literal = 0;
                    604:         s->literal_len = 0;
                    605:     }
                    606: 
                    607:     s->state = (s->command != NGX_IMAP_AUTHENTICATE) ? sw_start : sw_argument;
                    608: 
                    609:     return NGX_OK;
                    610: 
                    611: invalid:
                    612: 
                    613:     s->state = sw_start;
                    614:     s->quoted = 0;
                    615:     s->no_sync_literal = 0;
                    616:     s->literal_len = 0;
                    617: 
                    618:     return NGX_MAIL_PARSE_INVALID_COMMAND;
                    619: }
                    620: 
                    621: 
                    622: ngx_int_t
                    623: ngx_mail_smtp_parse_command(ngx_mail_session_t *s)
                    624: {
                    625:     u_char      ch, *p, *c, c0, c1, c2, c3;
                    626:     ngx_str_t  *arg;
                    627:     enum {
                    628:         sw_start = 0,
                    629:         sw_spaces_before_argument,
                    630:         sw_argument,
                    631:         sw_almost_done
                    632:     } state;
                    633: 
                    634:     state = s->state;
                    635: 
                    636:     for (p = s->buffer->pos; p < s->buffer->last; p++) {
                    637:         ch = *p;
                    638: 
                    639:         switch (state) {
                    640: 
                    641:         /* SMTP command */
                    642:         case sw_start:
                    643:             if (ch == ' ' || ch == CR || ch == LF) {
                    644:                 c = s->buffer->start;
                    645: 
                    646:                 if (p - c == 4) {
                    647: 
                    648:                     c0 = ngx_toupper(c[0]);
                    649:                     c1 = ngx_toupper(c[1]);
                    650:                     c2 = ngx_toupper(c[2]);
                    651:                     c3 = ngx_toupper(c[3]);
                    652: 
                    653:                     if (c0 == 'H' && c1 == 'E' && c2 == 'L' && c3 == 'O')
                    654:                     {
                    655:                         s->command = NGX_SMTP_HELO;
                    656: 
                    657:                     } else if (c0 == 'E' && c1 == 'H' && c2 == 'L' && c3 == 'O')
                    658:                     {
                    659:                         s->command = NGX_SMTP_EHLO;
                    660: 
                    661:                     } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T')
                    662:                     {
                    663:                         s->command = NGX_SMTP_QUIT;
                    664: 
                    665:                     } else if (c0 == 'A' && c1 == 'U' && c2 == 'T' && c3 == 'H')
                    666:                     {
                    667:                         s->command = NGX_SMTP_AUTH;
                    668: 
                    669:                     } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P')
                    670:                     {
                    671:                         s->command = NGX_SMTP_NOOP;
                    672: 
                    673:                     } else if (c0 == 'M' && c1 == 'A' && c2 == 'I' && c3 == 'L')
                    674:                     {
                    675:                         s->command = NGX_SMTP_MAIL;
                    676: 
                    677:                     } else if (c0 == 'R' && c1 == 'S' && c2 == 'E' && c3 == 'T')
                    678:                     {
                    679:                         s->command = NGX_SMTP_RSET;
                    680: 
                    681:                     } else if (c0 == 'R' && c1 == 'C' && c2 == 'P' && c3 == 'T')
                    682:                     {
                    683:                         s->command = NGX_SMTP_RCPT;
                    684: 
                    685:                     } else if (c0 == 'V' && c1 == 'R' && c2 == 'F' && c3 == 'Y')
                    686:                     {
                    687:                         s->command = NGX_SMTP_VRFY;
                    688: 
                    689:                     } else if (c0 == 'E' && c1 == 'X' && c2 == 'P' && c3 == 'N')
                    690:                     {
                    691:                         s->command = NGX_SMTP_EXPN;
                    692: 
                    693:                     } else if (c0 == 'H' && c1 == 'E' && c2 == 'L' && c3 == 'P')
                    694:                     {
                    695:                         s->command = NGX_SMTP_HELP;
                    696: 
                    697:                     } else {
                    698:                         goto invalid;
                    699:                     }
                    700: #if (NGX_MAIL_SSL)
                    701:                 } else if (p - c == 8) {
                    702: 
                    703:                     if ((c[0] == 'S'|| c[0] == 's')
                    704:                         && (c[1] == 'T'|| c[1] == 't')
                    705:                         && (c[2] == 'A'|| c[2] == 'a')
                    706:                         && (c[3] == 'R'|| c[3] == 'r')
                    707:                         && (c[4] == 'T'|| c[4] == 't')
                    708:                         && (c[5] == 'T'|| c[5] == 't')
                    709:                         && (c[6] == 'L'|| c[6] == 'l')
                    710:                         && (c[7] == 'S'|| c[7] == 's'))
                    711:                     {
                    712:                         s->command = NGX_SMTP_STARTTLS;
                    713: 
                    714:                     } else {
                    715:                         goto invalid;
                    716:                     }
                    717: #endif
                    718:                 } else {
                    719:                     goto invalid;
                    720:                 }
                    721: 
                    722:                 switch (ch) {
                    723:                 case ' ':
                    724:                     state = sw_spaces_before_argument;
                    725:                     break;
                    726:                 case CR:
                    727:                     state = sw_almost_done;
                    728:                     break;
                    729:                 case LF:
                    730:                     goto done;
                    731:                 }
                    732:                 break;
                    733:             }
                    734: 
                    735:             if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) {
                    736:                 goto invalid;
                    737:             }
                    738: 
                    739:             break;
                    740: 
                    741:         case sw_spaces_before_argument:
                    742:             switch (ch) {
                    743:             case ' ':
                    744:                 break;
                    745:             case CR:
                    746:                 state = sw_almost_done;
                    747:                 s->arg_end = p;
                    748:                 break;
                    749:             case LF:
                    750:                 s->arg_end = p;
                    751:                 goto done;
                    752:             default:
                    753:                 if (s->args.nelts <= 10) {
                    754:                     state = sw_argument;
                    755:                     s->arg_start = p;
                    756:                     break;
                    757:                 }
                    758:                 goto invalid;
                    759:             }
                    760:             break;
                    761: 
                    762:         case sw_argument:
                    763:             switch (ch) {
                    764:             case ' ':
                    765:             case CR:
                    766:             case LF:
                    767:                 arg = ngx_array_push(&s->args);
                    768:                 if (arg == NULL) {
                    769:                     return NGX_ERROR;
                    770:                 }
                    771:                 arg->len = p - s->arg_start;
                    772:                 arg->data = s->arg_start;
                    773:                 s->arg_start = NULL;
                    774: 
                    775:                 switch (ch) {
                    776:                 case ' ':
                    777:                     state = sw_spaces_before_argument;
                    778:                     break;
                    779:                 case CR:
                    780:                     state = sw_almost_done;
                    781:                     break;
                    782:                 case LF:
                    783:                     goto done;
                    784:                 }
                    785:                 break;
                    786: 
                    787:             default:
                    788:                 break;
                    789:             }
                    790:             break;
                    791: 
                    792:         case sw_almost_done:
                    793:             switch (ch) {
                    794:             case LF:
                    795:                 goto done;
                    796:             default:
                    797:                 goto invalid;
                    798:             }
                    799:         }
                    800:     }
                    801: 
                    802:     s->buffer->pos = p;
                    803:     s->state = state;
                    804: 
                    805:     return NGX_AGAIN;
                    806: 
                    807: done:
                    808: 
                    809:     s->buffer->pos = p + 1;
                    810: 
                    811:     if (s->arg_start) {
                    812:         arg = ngx_array_push(&s->args);
                    813:         if (arg == NULL) {
                    814:             return NGX_ERROR;
                    815:         }
                    816:         arg->len = s->arg_end - s->arg_start;
                    817:         arg->data = s->arg_start;
                    818:         s->arg_start = NULL;
                    819:     }
                    820: 
                    821:     s->state = (s->command != NGX_SMTP_AUTH) ? sw_start : sw_argument;
                    822: 
                    823:     return NGX_OK;
                    824: 
                    825: invalid:
                    826: 
                    827:     s->state = sw_start;
                    828:     s->arg_start = NULL;
                    829: 
                    830:     return NGX_MAIL_PARSE_INVALID_COMMAND;
                    831: }
                    832: 
                    833: 
                    834: ngx_int_t
                    835: ngx_mail_auth_parse(ngx_mail_session_t *s, ngx_connection_t *c)
                    836: {
                    837:     ngx_str_t                 *arg;
                    838: 
                    839: #if (NGX_MAIL_SSL)
                    840:     if (ngx_mail_starttls_only(s, c)) {
                    841:         return NGX_MAIL_PARSE_INVALID_COMMAND;
                    842:     }
                    843: #endif
                    844: 
                    845:     arg = s->args.elts;
                    846: 
                    847:     if (arg[0].len == 5) {
                    848: 
                    849:         if (ngx_strncasecmp(arg[0].data, (u_char *) "LOGIN", 5) == 0) {
                    850: 
                    851:             if (s->args.nelts == 1) {
                    852:                 return NGX_MAIL_AUTH_LOGIN;
                    853:             }
                    854: 
                    855:             if (s->args.nelts == 2) {
                    856:                 return NGX_MAIL_AUTH_LOGIN_USERNAME;
                    857:             }
                    858: 
                    859:             return NGX_MAIL_PARSE_INVALID_COMMAND;
                    860:         }
                    861: 
                    862:         if (ngx_strncasecmp(arg[0].data, (u_char *) "PLAIN", 5) == 0) {
                    863: 
                    864:             if (s->args.nelts == 1) {
                    865:                 return NGX_MAIL_AUTH_PLAIN;
                    866:             }
                    867: 
                    868:             if (s->args.nelts == 2) {
                    869:                 return ngx_mail_auth_plain(s, c, 1);
                    870:             }
                    871:         }
                    872: 
                    873:         return NGX_MAIL_PARSE_INVALID_COMMAND;
                    874:     }
                    875: 
                    876:     if (arg[0].len == 8) {
                    877: 
                    878:         if (s->args.nelts != 1) {
                    879:             return NGX_MAIL_PARSE_INVALID_COMMAND;
                    880:         }
                    881: 
                    882:         if (ngx_strncasecmp(arg[0].data, (u_char *) "CRAM-MD5", 8) == 0) {
                    883:             return NGX_MAIL_AUTH_CRAM_MD5;
                    884:         }
                    885:     }
                    886: 
                    887:     return NGX_MAIL_PARSE_INVALID_COMMAND;
                    888: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>