Ignore:
Timestamp:
Jan 1, 2014, 12:47:38 AM (10 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.21.1
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/3.2/mindi-busybox/mailutils/sendmail.c

    r2725 r3232  
    77 * Licensed under GPLv2, see file LICENSE in this source tree.
    88 */
     9
     10//kbuild:lib-$(CONFIG_SENDMAIL) += sendmail.o mail.o
     11
     12//usage:#define sendmail_trivial_usage
     13//usage:       "[OPTIONS] [RECIPIENT_EMAIL]..."
     14//usage:#define sendmail_full_usage "\n\n"
     15//usage:       "Read email from stdin and send it\n"
     16//usage:     "\nStandard options:"
     17//usage:     "\n    -t      Read additional recipients from message body"
     18//usage:     "\n    -f SENDER   Sender (required)"
     19//usage:     "\n    -o OPTIONS  Various options. -oi implied, others are ignored"
     20//usage:     "\n    -i      -oi synonym. implied and ignored"
     21//usage:     "\n"
     22//usage:     "\nBusybox specific options:"
     23//usage:     "\n    -v      Verbose"
     24//usage:     "\n    -w SECS     Network timeout"
     25//usage:     "\n    -H 'PROG ARGS'  Run connection helper"
     26//usage:     "\n            Examples:"
     27//usage:     "\n            -H 'exec openssl s_client -quiet -tls1 -starttls smtp"
     28//usage:     "\n                -connect smtp.gmail.com:25' <email.txt"
     29//usage:     "\n                [4<username_and_passwd.txt | -auUSER -apPASS]"
     30//usage:     "\n            -H 'exec openssl s_client -quiet -tls1"
     31//usage:     "\n                -connect smtp.gmail.com:465' <email.txt"
     32//usage:     "\n                [4<username_and_passwd.txt | -auUSER -apPASS]"
     33//usage:     "\n    -S HOST[:PORT]  Server"
     34//usage:     "\n    -auUSER     Username for AUTH LOGIN"
     35//usage:     "\n    -apPASS     Password for AUTH LOGIN"
     36////usage:     "\n  -amMETHOD   Authentication method. Ignored. LOGIN is implied"
     37//usage:     "\n"
     38//usage:     "\nOther options are silently ignored; -oi -t is implied"
     39//usage:    IF_MAKEMIME(
     40//usage:     "\nUse makemime to create emails with attachments"
     41//usage:    )
     42
    943#include "libbb.h"
    1044#include "mail.h"
     
    1448#define MAX_HEADERS 256
    1549
     50static void send_r_n(const char *s)
     51{
     52    if (verbose)
     53        bb_error_msg("send:'%s'", s);
     54    printf("%s\r\n", s);
     55}
     56
    1657static int smtp_checkp(const char *fmt, const char *param, int code)
    1758{
    1859    char *answer;
    19     const char *msg = command(fmt, param);
     60    char *msg = send_mail_command(fmt, param);
    2061    // read stdin
    21     // if the string has a form \d\d\d- -- read next string. E.g. EHLO response
     62    // if the string has a form NNN- -- read next string. E.g. EHLO response
    2263    // parse first bytes to a number
    2364    // if code = -1 then just return this number
    2465    // if code != -1 then checks whether the number equals the code
    2566    // if not equal -> die saying msg
    26     while ((answer = xmalloc_fgetline(stdin)) != NULL)
     67    while ((answer = xmalloc_fgetline(stdin)) != NULL) {
     68        if (verbose)
     69            bb_error_msg("recv:'%.*s'", (int)(strchrnul(answer, '\r') - answer), answer);
    2770        if (strlen(answer) <= 3 || '-' != answer[3])
    2871            break;
     72        free(answer);
     73    }
    2974    if (answer) {
    3075        int n = atoi(answer);
     
    3277            alarm(0);
    3378        free(answer);
    34         if (-1 == code || n == code)
     79        if (-1 == code || n == code) {
     80            free(msg);
    3581            return n;
     82        }
    3683    }
    3784    bb_error_msg_and_die("%s failed", msg);
     
    72119    char *s;
    73120    llist_t *list = NULL;
    74     char *domain = sane_address(safe_getdomainname());
     121    char *host = sane_address(safe_gethostname());
    75122    unsigned nheaders = 0;
    76123    int code;
     
    87134        OPT_S = 1 << 6,         // specify connection string
    88135        OPT_a = 1 << 7,         // authentication tokens
     136        OPT_v = 1 << 8,         // verbosity
    89137    };
    90138
     
    97145
    98146    // parse options
    99     // -f is required. -H and -S are mutually exclusive
    100     opt_complementary = "f:w+:H--S:S--H:a::";
     147    // -v is a counter, -f is required. -H and -S are mutually exclusive, -a is a list
     148    opt_complementary = "vv:f:w+:H--S:S--H:a::";
    101149    // N.B. since -H and -S are mutually exclusive they do not interfere in opt_connect
    102150    // -a is for ssmtp (http://downloads.openwrt.org/people/nico/man/man8/ssmtp.8.html) compatibility,
    103151    // it is still under development.
    104     opts = getopt32(argv, "tf:o:iw:H:S:a::", &opt_from, NULL, &timeout, &opt_connect, &opt_connect, &list);
     152    opts = getopt32(argv, "tf:o:iw:H:S:a::v", &opt_from, NULL,
     153            &timeout, &opt_connect, &opt_connect, &list, &verbose);
    105154    //argc -= optind;
    106155    argv += optind;
     
    129178        // plug it in
    130179        launch_helper(args);
    131     // vanilla connection
     180        // Now:
     181        // our stdout will go to helper's stdin,
     182        // helper's stdout will be available on our stdin.
     183
     184        // Wait for initial server message.
     185        // If helper (such as openssl) invokes STARTTLS, the initial 220
     186        // is swallowed by helper (and not repeated after TLS is initiated).
     187        // We will send NOOP cmd to server and check the response.
     188        // We should get 220+250 on plain connection, 250 on STARTTLSed session.
     189        //
     190        // The problem here is some servers delay initial 220 message,
     191        // and consider client to be a spammer if it starts sending cmds
     192        // before 220 reached it. The code below is unsafe in this regard:
     193        // in non-STARTTLSed case, we potentially send NOOP before 220
     194        // is sent by server.
     195        // Ideas? (--delay SECS opt? --assume-starttls-helper opt?)
     196        code = smtp_check("NOOP", -1);
     197        if (code == 220)
     198            // we got 220 - this is not STARTTLSed connection,
     199            // eat 250 response to our NOOP
     200            smtp_check(NULL, 250);
     201        else
     202        if (code != 250)
     203            bb_error_msg_and_die("SMTP init failed");
    132204    } else {
     205        // vanilla connection
    133206        int fd;
    134207        // host[:port] not explicitly specified? -> use $SMTPHOST
    135         // no $SMTPHOST ? -> use localhost
     208        // no $SMTPHOST? -> use localhost
    136209        if (!(opts & OPT_S)) {
    137210            opt_connect = getenv("SMTPHOST");
     
    144217        xmove_fd(fd, STDIN_FILENO);
    145218        xdup2(STDIN_FILENO, STDOUT_FILENO);
    146     }
    147     // N.B. from now we know nothing about network :)
    148 
    149     // wait for initial server OK
    150     // N.B. if we used openssl the initial 220 answer is already swallowed during openssl TLS init procedure
    151     // so we need to kick the server to see whether we are ok
    152     code = smtp_check("NOOP", -1);
    153     // 220 on plain connection, 250 on openssl-helped TLS session
    154     if (220 == code)
    155         smtp_check(NULL, 250); // reread the code to stay in sync
    156     else if (250 != code)
    157         bb_error_msg_and_die("INIT failed");
     219
     220        // Wait for initial server 220 message
     221        smtp_check(NULL, 220);
     222    }
    158223
    159224    // we should start with modern EHLO
    160     if (250 != smtp_checkp("EHLO %s", domain, -1)) {
    161         smtp_checkp("HELO %s", domain, 250);
    162     }
    163     if (ENABLE_FEATURE_CLEAN_UP)
    164         free(domain);
     225    if (250 != smtp_checkp("EHLO %s", host, -1))
     226        smtp_checkp("HELO %s", host, 250);
     227    free(host);
    165228
    166229    // perform authentication
     
    177240
    178241    // set sender
    179     // N.B. we have here a very loosely defined algotythm
     242    // N.B. we have here a very loosely defined algorythm
    180243    // since sendmail historically offers no means to specify secrets on cmdline.
    181244    // 1) server can require no authentication ->
     
    194257    //  opt_from = xasprintf("%s@%s", G.user, domain);
    195258    //}
    196     //if (ENABLE_FEATURE_CLEAN_UP)
    197     //  free(domain);
    198259    smtp_checkp("MAIL FROM:<%s>", opt_from, 250);
    199260
     
    215276                printf(".");
    216277            // dump read line
    217             printf("%s\r\n", s);
     278            send_r_n(s);
    218279            free(s);
    219280            continue;
     
    222283        // analyze headers
    223284        // To: or Cc: headers add recipients
    224         if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) {
    225             rcptto(sane_address(s+3));
    226             goto addheader;
    227         // Bcc: header adds blind copy (hidden) recipient
    228         } else if (0 == strncasecmp("Bcc:", s, 4)) {
    229             rcptto(sane_address(s+4));
    230             free(s);
    231             // N.B. Bcc: vanishes from headers!
    232 
    233         // other headers go verbatim
    234 
    235         // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines.
    236         // Continuation is denoted by prefixing additional lines with whitespace(s).
    237         // Thanks (stefan.seyfried at googlemail.com) for pointing this out.
    238         } else if (strchr(s, ':') || (list && skip_whitespace(s) != s)) {
     285        if (opts & OPT_t) {
     286            if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) {
     287                rcptto(sane_address(s+3));
     288                goto addheader;
     289            }
     290            // Bcc: header adds blind copy (hidden) recipient
     291            if (0 == strncasecmp("Bcc:", s, 4)) {
     292                rcptto(sane_address(s+4));
     293                free(s);
     294                continue; // N.B. Bcc: vanishes from headers!
     295            }
     296        }
     297        if (strchr(s, ':') || (list && isspace(s[0]))) {
     298            // other headers go verbatim
     299            // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines.
     300            // Continuation is denoted by prefixing additional lines with whitespace(s).
     301            // Thanks (stefan.seyfried at googlemail.com) for pointing this out.
    239302 addheader:
    240303            // N.B. we allow MAX_HEADERS generic headers at most to prevent attacks
     
    242305                goto bail;
    243306            llist_add_to_end(&list, s);
    244         // a line without ":" (an empty line too, by definition) doesn't look like a valid header
    245         // so stop "analyze headers" mode
    246307        } else {
     308            // a line without ":" (an empty line too, by definition) doesn't look like a valid header
     309            // so stop "analyze headers" mode
    247310 reenter:
    248311            // put recipients specified on cmdline
     
    262325            // dump the headers
    263326            while (list) {
    264                 printf("%s\r\n", (char *) llist_pop(&list));
     327                send_r_n((char *) llist_pop(&list));
    265328            }
    266329            // stop analyzing headers
     
    269332            // just dump empty line and break the loop
    270333            if (!s) {
    271                 puts("\r");
     334                send_r_n("");
    272335                break;
    273336            }
Note: See TracChangeset for help on using the changeset viewer.