Ignore:
Timestamp:
Dec 20, 2016, 4:07:32 PM (7 years ago)
Author:
Bruno Cornec
Message:

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

Location:
branches/3.3
Files:
1 edited
1 copied

Legend:

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

    r3232 r3621  
    1616//usage:     "\nStandard options:"
    1717//usage:     "\n    -t      Read additional recipients from message body"
    18 //usage:     "\n    -f SENDER   Sender (required)"
     18//usage:     "\n    -f SENDER   For use in MAIL FROM:<sender>. Can be empty string"
     19//usage:     "\n            Default: -auUSER, or username of current UID"
    1920//usage:     "\n    -o OPTIONS  Various options. -oi implied, others are ignored"
    2021//usage:     "\n    -i      -oi synonym. implied and ignored"
     
    4142//usage:    )
    4243
     44/* Currently we don't sanitize or escape user-supplied SENDER and RECIPIENT_EMAILs.
     45 * We may need to do so. For one, '.' in usernames seems to require escaping!
     46 *
     47 * From http://cr.yp.to/smtp/address.html:
     48 *
     49 * SMTP offers three ways to encode a character inside an address:
     50 *
     51 * "safe": the character, if it is not <>()[].,;:@, backslash,
     52 *  double-quote, space, or an ASCII control character;
     53 * "quoted": the character, if it is not \012, \015, backslash,
     54 *   or double-quote; or
     55 * "slashed": backslash followed by the character.
     56 *
     57 * An encoded box part is either (1) a sequence of one or more slashed
     58 * or safe characters or (2) a double quote, a sequence of zero or more
     59 * slashed or quoted characters, and a double quote. It represents
     60 * the concatenation of the characters encoded inside it.
     61 *
     62 * For example, the encoded box parts
     63 *  angels
     64 *  \a\n\g\e\l\s
     65 *  "\a\n\g\e\l\s"
     66 *  "angels"
     67 *  "ang\els"
     68 * all represent the 6-byte string "angels", and the encoded box parts
     69 *  a\,comma
     70 *  \a\,\c\o\m\m\a
     71 *  "a,comma"
     72 * all represent the 7-byte string "a,comma".
     73 *
     74 * An encoded address contains
     75 *  the byte <;
     76 *  optionally, a route followed by a colon;
     77 *  an encoded box part, the byte @, and a domain; and
     78 *  the byte >.
     79 *
     80 * It represents an Internet mail address, given by concatenating
     81 * the string represented by the encoded box part, the byte @,
     82 * and the domain. For example, the encoded addresses
     83 *     <God@heaven.af.mil>
     84 *     <\God@heaven.af.mil>
     85 *     <"God"@heaven.af.mil>
     86 *     <@gateway.af.mil,@uucp.local:"\G\o\d"@heaven.af.mil>
     87 * all represent the Internet mail address "God@heaven.af.mil".
     88 */
     89
    4390#include "libbb.h"
    4491#include "mail.h"
     
    93140static char *sane_address(char *str)
    94141{
    95     char *s = str;
    96     char *p = s;
     142    char *s;
     143
     144    trim(str);
     145    s = str;
    97146    while (*s) {
    98         if (isalnum(*s) || '_' == *s || '-' == *s || '.' == *s || '@' == *s) {
    99             *p++ = *s;
     147        if (!isalnum(*s) && !strchr("_-.@", *s)) {
     148            bb_error_msg("bad address '%s'", str);
     149            /* returning "": */
     150            str[0] = '\0';
     151            return str;
    100152        }
    101153        s++;
    102154    }
    103     *p = '\0';
    104155    return str;
    105156}
    106157
     158// check for an address inside angle brackets, if not found fall back to normal
     159static char *angle_address(char *str)
     160{
     161    char *s, *e;
     162
     163    trim(str);
     164    e = last_char_is(str, '>');
     165    if (e) {
     166        s = strrchr(str, '<');
     167        if (s) {
     168            *e = '\0';
     169            str = s + 1;
     170        }
     171    }
     172    return sane_address(str);
     173}
     174
    107175static void rcptto(const char *s)
    108176{
     177    if (!*s)
     178        return;
    109179    // N.B. we don't die if recipient is rejected, for the other recipients may be accepted
    110180    if (250 != smtp_checkp("RCPT TO:<%s>", s, -1))
     
    112182}
    113183
     184// send to a list of comma separated addresses
     185static void rcptto_list(const char *list)
     186{
     187    char *str = xstrdup(list);
     188    char *s = str;
     189    char prev = 0;
     190    int in_quote = 0;
     191
     192    while (*s) {
     193        char ch = *s++;
     194
     195        if (ch == '"' && prev != '\\') {
     196            in_quote = !in_quote;
     197        } else if (!in_quote && ch == ',') {
     198            s[-1] = '\0';
     199            rcptto(angle_address(str));
     200            str = s;
     201        }
     202        prev = ch;
     203    }
     204    if (prev != ',')
     205        rcptto(angle_address(str));
     206    free(str);
     207}
     208
    114209int sendmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
    115210int sendmail_main(int argc UNUSED_PARAM, char **argv)
    116211{
    117212    char *opt_connect = opt_connect;
    118     char *opt_from;
     213    char *opt_from = NULL;
    119214    char *s;
    120215    llist_t *list = NULL;
     
    122217    unsigned nheaders = 0;
    123218    int code;
     219    enum {
     220        HDR_OTHER = 0,
     221        HDR_TOCC,
     222        HDR_BCC,
     223    } last_hdr = 0;
     224    int check_hdr;
     225    int has_to = 0;
    124226
    125227    enum {
     
    145247
    146248    // parse options
    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::";
     249    // -v is a counter, -H and -S are mutually exclusive, -a is a list
     250    opt_complementary = "vv:w+:H--S:S--H:a::";
    149251    // N.B. since -H and -S are mutually exclusive they do not interfere in opt_connect
    150252    // -a is for ssmtp (http://downloads.openwrt.org/people/nico/man/man8/ssmtp.8.html) compatibility,
     
    169271    }
    170272    // N.B. list == NULL here
    171     //bb_info_msg("OPT[%x] AU[%s], AP[%s], AM[%s], ARGV[%s]", opts, au, ap, am, *argv);
     273    //bb_error_msg("OPT[%x] AU[%s], AP[%s], AM[%s], ARGV[%s]", opts, au, ap, am, *argv);
    172274
    173275    // connect to server
     
    225327    if (250 != smtp_checkp("EHLO %s", host, -1))
    226328        smtp_checkp("HELO %s", host, 250);
    227     free(host);
    228329
    229330    // perform authentication
     
    250351    //  file descriptor (e.g. 4), or again from a secured file.
    251352
    252     // got no sender address? -> use system username as a resort
    253     // N.B. we marked -f as required option!
    254     //if (!G.user) {
    255     //  // N.B. IMHO getenv("USER") can be way easily spoofed!
    256     //  G.user = xuid2uname(getuid());
    257     //  opt_from = xasprintf("%s@%s", G.user, domain);
    258     //}
     353    // got no sender address? use auth name, then UID username as a last resort
     354    if (!opt_from) {
     355        opt_from = xasprintf("%s@%s",
     356                             G.user ? G.user : xuid2uname(getuid()),
     357                             xgethostbyname(host)->h_name);
     358    }
     359    free(host);
     360
    259361    smtp_checkp("MAIL FROM:<%s>", opt_from, 250);
    260362
     
    274376            // whether it is single or not character on the line
    275377            if ('.' == s[0] /*&& '\0' == s[1] */)
    276                 printf(".");
     378                bb_putchar('.');
    277379            // dump read line
    278380            send_r_n(s);
     
    283385        // analyze headers
    284386        // To: or Cc: headers add recipients
     387        check_hdr = (0 == strncasecmp("To:", s, 3));
     388        has_to |= check_hdr;
    285389        if (opts & OPT_t) {
    286             if (0 == strncasecmp("To:", s, 3) || 0 == strncasecmp("Bcc:" + 1, s, 3)) {
    287                 rcptto(sane_address(s+3));
     390            if (check_hdr || 0 == strncasecmp("Bcc:" + 1, s, 3)) {
     391                rcptto_list(s+3);
     392                last_hdr = HDR_TOCC;
    288393                goto addheader;
    289394            }
    290395            // Bcc: header adds blind copy (hidden) recipient
    291396            if (0 == strncasecmp("Bcc:", s, 4)) {
    292                 rcptto(sane_address(s+4));
     397                rcptto_list(s+4);
    293398                free(s);
     399                last_hdr = HDR_BCC;
    294400                continue; // N.B. Bcc: vanishes from headers!
    295401            }
    296402        }
    297         if (strchr(s, ':') || (list && isspace(s[0]))) {
     403        check_hdr = (list && isspace(s[0]));
     404        if (strchr(s, ':') || check_hdr) {
    298405            // other headers go verbatim
    299406            // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines.
    300407            // Continuation is denoted by prefixing additional lines with whitespace(s).
    301408            // Thanks (stefan.seyfried at googlemail.com) for pointing this out.
     409            if (check_hdr && last_hdr != HDR_OTHER) {
     410                rcptto_list(s+1);
     411                if (last_hdr == HDR_BCC)
     412                    continue;
     413                    // N.B. Bcc: vanishes from headers!
     414            } else {
     415                last_hdr = HDR_OTHER;
     416            }
    302417 addheader:
    303418            // N.B. we allow MAX_HEADERS generic headers at most to prevent attacks
     
    310425 reenter:
    311426            // put recipients specified on cmdline
     427            check_hdr = 1;
    312428            while (*argv) {
    313429                char *t = sane_address(*argv);
     
    315431                //if (MAX_HEADERS && ++nheaders >= MAX_HEADERS)
    316432                //  goto bail;
    317                 llist_add_to_end(&list, xasprintf("To: %s", t));
     433                if (!has_to) {
     434                    const char *hdr;
     435
     436                    if (check_hdr && argv[1])
     437                        hdr = "To: %s,";
     438                    else if (check_hdr)
     439                        hdr = "To: %s";
     440                    else if (argv[1])
     441                        hdr = "To: %s," + 3;
     442                    else
     443                        hdr = "To: %s" + 3;
     444                    llist_add_to_end(&list,
     445                            xasprintf(hdr, t));
     446                    check_hdr = 0;
     447                }
    318448                argv++;
    319449            }
Note: See TracChangeset for help on using the changeset viewer.