Annotation of embedaddon/mini_sendmail/mini_sendmail.c, revision 1.1.1.1.2.2

1.1       misho       1: /* mini_sendmail - accept email on behalf of real sendmail
                      2: **
1.1.1.1.2.2! misho       3: ** Copyright © 1999,2015 by Jef Poskanzer <jef@mail.acme.com>.
1.1       misho       4: ** All rights reserved.
                      5: **
                      6: ** Redistribution and use in source and binary forms, with or without
                      7: ** modification, are permitted provided that the following conditions
                      8: ** are met:
                      9: ** 1. Redistributions of source code must retain the above copyright
                     10: **    notice, this list of conditions and the following disclaimer.
                     11: ** 2. Redistributions in binary form must reproduce the above copyright
                     12: **    notice, this list of conditions and the following disclaimer in the
                     13: **    documentation and/or other materials provided with the distribution.
                     14: **
                     15: ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     16: ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     17: ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     18: ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     19: ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     20: ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     21: ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     22: ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     23: ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     24: ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     25: ** SUCH DAMAGE.
                     26: */
                     27: 
                     28: 
                     29: /* These defines control some optional features of the program.  If you
                     30: ** don't want the features you can undef the symbols; some of them mean
                     31: ** a significant savings in executable size.
                     32: */
                     33: #define DO_RECEIVED    /* whether to add a "Received:" header */
                     34: #define DO_GETPWUID    /* whether to try a getpwuid() if getlogin() fails */
                     35: #define DO_MINUS_SP    /* whether to implement the -s and -p flags */
                     36: #define DO_DNS         /* whether to do a name lookup on -s, or just IP# */
                     37: 
                     38: 
                     39: #include <unistd.h>
                     40: #include <stdlib.h>
                     41: #include <stdio.h>
                     42: #include <signal.h>
                     43: #include <string.h>
                     44: #include <sys/types.h>
                     45: #include <sys/socket.h>
                     46: #include <netinet/in.h>
1.1.1.1.2.2! misho      47: #include <arpa/inet.h>
1.1       misho      48: #include <netdb.h>
                     49: 
                     50: #ifdef DO_RECEIVED
                     51: #include <time.h>
                     52: #endif /* DO_RECEIVED */
                     53: #ifdef DO_GETPWUID
                     54: #include <pwd.h>
                     55: #endif /* DO_GETPWUID */
                     56: 
                     57: #include "version.h"
                     58: 
                     59: 
                     60: /* Defines. */
                     61: #define SMTP_PORT 25
                     62: #define DEFAULT_TIMEOUT 60
                     63: 
                     64: 
                     65: /* Globals. */
                     66: static char* argv0;
                     67: static char* fake_from;
                     68: static int parse_message, verbose;
                     69: #ifdef DO_MINUS_SP
                     70: static char* server;
                     71: static short port;
                     72: #endif /* DO_MINUS_SP */
                     73: static int timeout;
                     74: static int sockfd1, sockfd2;
                     75: static FILE* sockrfp;
                     76: static FILE* sockwfp;
                     77: static int got_a_recipient;
                     78: 
                     79: 
                     80: /* Forwards. */
                     81: static void usage( void );
                     82: static char* slurp_message( void );
                     83: #ifdef DO_RECEIVED
                     84: static char* make_received( char* from, char* username, char* hostname );
                     85: #endif /* DO_RECEIVED */
                     86: static void parse_for_recipients( char* message );
                     87: static void add_recipient( char* recipient, int len );
                     88: static int open_client_socket( void );
                     89: static int read_response( void );
                     90: static void send_command( char* command );
                     91: static void send_data( char* data );
                     92: static void send_done( void );
                     93: static void sigcatch( int sig );
                     94: static void show_error( char* cause );
                     95: 
                     96: 
1.1.1.1.2.2! misho      97: /* Do overlapping strcpy safely, by using memmove. */
        !            98: #define ol_strcpy(dst,src) memmove(dst,src,strlen(src)+1)
        !            99: 
        !           100: 
1.1       misho     101: int
                    102: main( int argc, char** argv )
                    103:     {
                    104:     int argn;
                    105:     char* message;
                    106: #ifdef DO_RECEIVED
                    107:     char* received;
                    108: #endif /* DO_RECEIVED */
                    109:     char* username;
                    110:     char hostname[500];
                    111:     char from[1000];
                    112:     int status;
                    113:     char buf[2000];
                    114: 
                    115:     /* Parse args. */
                    116:     argv0 = argv[0];
                    117:     fake_from = (char*) 0;
                    118:     parse_message = 0;
                    119: #ifdef DO_MINUS_SP
                    120:     server = "127.0.0.1";
                    121:     port = SMTP_PORT;
                    122: #endif /* DO_MINUS_SP */
                    123:     verbose = 0;
                    124:     timeout = DEFAULT_TIMEOUT;
                    125:     argn = 1;
                    126:     while ( argn < argc && argv[argn][0] == '-' )
                    127:        {
                    128:        if ( strncmp( argv[argn], "-f", 2 ) == 0 && argv[argn][2] != '\0' )
                    129:            fake_from = &(argv[argn][2]);
                    130:        else if ( strcmp( argv[argn], "-t" ) == 0 )
                    131:            parse_message = 1;
                    132: #ifdef DO_MINUS_SP
                    133:        else if ( strncmp( argv[argn], "-s", 2 ) == 0 && argv[argn][2] != '\0' )
                    134:            server = &(argv[argn][2]);
                    135:        else if ( strncmp( argv[argn], "-p", 2 ) == 0 && argv[argn][2] != '\0' )
                    136:            port = atoi( &(argv[argn][2]) );
                    137: #endif /* DO_MINUS_SP */
                    138:        else if ( strncmp( argv[argn], "-T", 2 ) == 0 && argv[argn][2] != '\0' )
                    139:            timeout = atoi( &(argv[argn][2]) );
                    140:        else if ( strcmp( argv[argn], "-v" ) == 0 )
                    141:            verbose = 1;
                    142:        else if ( strcmp( argv[argn], "-i" ) == 0 )
                    143:            ;   /* ignore */
                    144:        else if ( strcmp( argv[argn], "-oi" ) == 0 )
                    145:            ;   /* ignore */
                    146:        else if ( strcmp( argv[argn], "--" ) == 0 )
                    147:            ;   /* ignore */
                    148:        else
                    149:            usage();
                    150:        ++argn;
                    151:        }
                    152: 
                    153:     username = getlogin();
                    154:     if ( username == (char*) 0 )
                    155:        {
                    156: #ifdef DO_GETPWUID
                    157:        struct passwd* pw = getpwuid( getuid() );
                    158:        if ( pw == (struct passwd*) 0 )
                    159:            {
                    160:            (void) fprintf( stderr, "%s: can't determine username\n", argv0 );
                    161:            exit( 1 );
                    162:            }
                    163:        username = pw->pw_name;
                    164: #else /* DO_GETPWUID */
                    165:        (void) fprintf( stderr, "%s: can't determine username\n", argv0 );
                    166:        exit( 1 );
                    167: #endif /* DO_GETPWUID */
                    168:        }
                    169: 
                    170:     if ( gethostname( hostname, sizeof(hostname) - 1 ) < 0 )
                    171:        show_error( "gethostname" );
                    172: 
                    173:     if ( fake_from == (char*) 0 )
                    174:        (void) snprintf( from, sizeof(from), "%s@%s", username, hostname );
                    175:     else
                    176:        if ( strchr( fake_from, '@' ) == (char*) 0 )
                    177:            (void) snprintf( from, sizeof(from), "%s@%s", fake_from, hostname );
                    178:        else
                    179:            (void) snprintf( from, sizeof(from), "%s", fake_from );
                    180: 
                    181:     /* Strip off any angle brackets in the from address. */
                    182:     while ( from[0] == '<' )
1.1.1.1.2.2! misho     183:        (void) ol_strcpy( from, &from[1] );
1.1       misho     184:     while ( from[strlen(from)-1] == '>' )
                    185:        from[strlen(from)-1] = '\0';
                    186: 
                    187:     message = slurp_message();
                    188: #ifdef DO_RECEIVED
                    189:     received = make_received( from, username, hostname );
                    190: #endif /* DO_RECEIVED */
                    191: 
                    192:     (void) signal( SIGALRM, sigcatch );
                    193: 
                    194:     (void) alarm( timeout );
                    195:     sockfd1 = open_client_socket();
                    196: 
                    197:     sockfd2 = dup( sockfd1 );
                    198:     sockrfp = fdopen( sockfd1, "r" );
                    199:     sockwfp = fdopen( sockfd2, "w" );
                    200: 
                    201:     /* The full SMTP protocol is spelled out in RFC821, available at
                    202:     ** http://www.faqs.org/rfcs/rfc821.html
                    203:     ** The only non-obvious wrinkles:
                    204:     **  - The commands are terminated with CRLF, not newline.
                    205:     **  - Newlines in the data file get turned into CRLFs.
                    206:     **  - Any data lines beginning with a period get an extra period prepended.
                    207:     */
                    208: 
                    209:     status = read_response();
                    210:     if ( status != 220 )
                    211:        {
                    212:        (void) fprintf(
                    213:            stderr,  "%s: unexpected initial greeting %d\n", argv0, status );
                    214:        exit( 1 );
                    215:        }
                    216: 
                    217:     (void) snprintf( buf, sizeof(buf), "HELO %s", hostname );
                    218:     send_command( buf );
                    219:     status = read_response();
                    220:     if ( status != 250 )
                    221:        {
                    222:        (void) fprintf(
                    223:            stderr,  "%s: unexpected response %d to HELO command\n",
                    224:            argv0, status );
                    225:        exit( 1 );
                    226:        }
                    227: 
                    228:     (void) snprintf( buf, sizeof(buf), "MAIL FROM:<%s>", from );
                    229:     send_command( buf );
                    230:     status = read_response();
                    231:     if ( status != 250 )
                    232:        {
                    233:        (void) fprintf(
                    234:            stderr,  "%s: unexpected response %d to MAIL FROM command\n",
                    235:            argv0, status );
                    236:        exit( 1 );
                    237:        }
                    238: 
                    239:     got_a_recipient = 0;
                    240:     for ( ; argn < argc; ++argn )
                    241:        add_recipient( argv[argn], strlen( argv[argn] ) );
                    242:     if ( parse_message )
                    243:        parse_for_recipients( message );
                    244:     if ( ! got_a_recipient )
                    245:        {
                    246:        (void) fprintf( stderr,  "%s: no recipients found\n", argv0 );
                    247:        exit( 1 );
                    248:        }
                    249: 
                    250:     send_command( "DATA" );
                    251:     status = read_response();
                    252:     if ( status != 354 )
                    253:        {
                    254:        (void) fprintf(
                    255:            stderr,  "%s: unexpected response %d to DATA command\n",
                    256:            argv0, status );
                    257:        exit( 1 );
                    258:        }
                    259: 
                    260: #ifdef DO_RECEIVED
                    261:     send_data( received );
                    262: #endif /* DO_RECEIVED */
                    263:     send_data( message );
                    264:     send_done();
                    265:     status = read_response();
                    266:     if ( status != 250 )
                    267:        {
                    268:        (void) fprintf(
                    269:            stderr,  "%s: unexpected response %d to DATA\n", argv0, status );
                    270:        exit( 1 );
                    271:        }
                    272: 
                    273:     send_command( "QUIT" );
                    274:     status = read_response();
                    275:     if ( status != 221 )
                    276:        (void) fprintf(
                    277:            stderr,  "%s: unexpected response %d to QUIT command - ignored\n",
                    278:            argv0, status );
                    279: 
                    280:     (void) close( sockfd1 );
                    281:     (void) close( sockfd2 );
                    282: 
                    283:     exit( 0 );
                    284:     }
                    285: 
                    286: 
                    287: static void
                    288: usage( void )
                    289:     {
                    290: #ifdef DO_MINUS_SP
                    291: #ifdef DO_DNS
                    292:     char* spflag = "[-s<server>] [-p<port>] ";
                    293: #else /* DO_DNS */
                    294:     char* spflag = "[-s<server_ip>] [-p<port>] ";
                    295: #endif /* DO_DNS */
                    296: #else /* DO_MINUS_SP */
                    297:     char* spflag = "";
                    298: #endif /* DO_MINUS_SP */
                    299:     (void) fprintf( stderr, "usage:  %s [-f<name>] [-t] %s[-T<timeout>] [-v] [address ...]\n", argv0, spflag );
                    300:     exit( 1 );
                    301:     }
                    302: 
                    303: 
                    304: static char*
                    305: slurp_message( void )
                    306:     {
                    307:     char* message;
                    308:     int message_size, message_len;
                    309:     int c;
                    310: 
                    311:     message_size = 5000;
                    312:     message = (char*) malloc( message_size );
                    313:     if ( message == (char*) 0 )
                    314:        {
                    315:        (void) fprintf( stderr, "%s: out of memory\n", argv0 );
                    316:        exit( 1 );
                    317:        }
                    318:     message_len = 0;
                    319: 
                    320:     for (;;)
                    321:        {
                    322:        c = getchar();
                    323:        if ( c == EOF )
                    324:            break;
                    325:        if ( message_len + 1 >= message_size )
                    326:            {
                    327:            message_size *= 2;
                    328:            message = (char*) realloc( (void*) message, message_size );
                    329:            if ( message == (char*) 0 )
                    330:                {
                    331:                (void) fprintf( stderr, "%s: out of memory\n", argv0 );
                    332:                exit( 1 );
                    333:                }
                    334:            }
                    335:        message[message_len++] = c;
                    336:        }
                    337:     message[message_len] = '\0';
                    338: 
                    339:     return message;
                    340:     }
                    341: 
                    342: 
                    343: #ifdef DO_RECEIVED
                    344: static char*
                    345: make_received( char* from, char* username, char* hostname )
                    346:     {
                    347:     int received_size;
                    348:     char* received;
                    349:     time_t t;
                    350:     struct tm* tmP;
                    351:     char timestamp[100];
                    352: 
                    353:     t = time( (time_t*) 0 );
                    354:     tmP = localtime( &t );
                    355:     (void) strftime( timestamp, sizeof(timestamp), "%a, %d %b %Y %T %Z", tmP );
                    356:     received_size =
1.1.1.1.2.2! misho     357:        500 + strlen( from ) + strlen( hostname ) * 2 + strlen( MINI_SENDMAIL_VERSION ) +
1.1       misho     358:        strlen( timestamp ) + strlen( username );
                    359:     received = (char*) malloc( received_size );
                    360:     if ( received == (char*) 0 )
                    361:        {
                    362:        (void) fprintf( stderr, "%s: out of memory\n", argv0 );
                    363:        exit( 1 );
                    364:        }
                    365:     (void) snprintf(
                    366:        received, received_size,
                    367:        "Received: (from %s)\n\tby %s (%s);\n\t%s\n\t(sender %s@%s)\n",
1.1.1.1.2.2! misho     368:        from, hostname, MINI_SENDMAIL_VERSION, timestamp, username, hostname );
1.1       misho     369:     return received;
                    370:     }
                    371: #endif /* DO_RECEIVED */
                    372: 
                    373: 
                    374: static void
                    375: parse_for_recipients( char* message )
                    376:     {
                    377:     /* A little finite-state machine that parses the message, looking
                    378:     ** for To:, Cc:, and Bcc: recipients.
                    379:     */
                    380:     int state;
                    381: #define ST_BOL         0
                    382: #define ST_OTHERHEAD   1
                    383: #define ST_T           2
                    384: #define ST_C           3
                    385: #define ST_B           4
                    386: #define ST_BC          5
                    387: #define ST_RECIPHEAD   6
                    388: #define ST_RECIPS      7
                    389:     char* cp;
                    390:     char* bcc;
1.1.1.1.2.2! misho     391:     char* recip = (char*) 0;
1.1       misho     392: 
                    393:     state = ST_BOL;
                    394:     bcc = (char*) 0;
                    395:     for ( cp = message; *cp != '\0'; ++cp )
                    396:        {
                    397:        switch ( state )
                    398:            {
                    399:            case ST_BOL:
                    400:            switch ( *cp )
                    401:                {
                    402:                case '\n':
                    403:                return;
                    404:                case 'T':
                    405:                case 't':
                    406:                state = ST_T;
                    407:                break;
                    408:                case 'C':
                    409:                case 'c':
                    410:                state = ST_C;
                    411:                break;
                    412:                case 'B':
                    413:                case 'b':
                    414:                state = ST_B;
                    415:                bcc = cp;
                    416:                break;
                    417:                default:
                    418:                state = ST_OTHERHEAD;
                    419:                break;
                    420:                }
                    421:            break;
                    422:            case ST_OTHERHEAD:
                    423:            switch ( *cp )
                    424:                {
                    425:                case '\n':
                    426:                state = ST_BOL;
                    427:                break;
                    428:                }
                    429:            break;
                    430:            case ST_T:
                    431:            switch ( *cp )
                    432:                {
                    433:                case '\n':
                    434:                state = ST_BOL;
                    435:                break;
                    436:                case 'O':
                    437:                case 'o':
                    438:                state = ST_RECIPHEAD;
                    439:                break;
                    440:                default:
                    441:                state = ST_OTHERHEAD;
                    442:                break;
                    443:                }
                    444:            break;
                    445:            case ST_C:
                    446:            switch ( *cp )
                    447:                {
                    448:                case '\n':
                    449:                state = ST_BOL;
                    450:                break;
                    451:                case 'C':
                    452:                case 'c':
                    453:                state = ST_RECIPHEAD;
                    454:                break;
                    455:                default:
                    456:                state = ST_OTHERHEAD;
                    457:                break;
                    458:                }
                    459:            break;
                    460:            case ST_B:
                    461:            switch ( *cp )
                    462:                {
                    463:                case '\n':
                    464:                state = ST_BOL;
                    465:                bcc = (char*) 0;
                    466:                break;
                    467:                case 'C':
                    468:                case 'c':
                    469:                state = ST_BC;
                    470:                break;
                    471:                default:
                    472:                state = ST_OTHERHEAD;
                    473:                bcc = (char*) 0;
                    474:                break;
                    475:                }
                    476:            break;
                    477:            case ST_BC:
                    478:            switch ( *cp )
                    479:                {
                    480:                case '\n':
                    481:                state = ST_BOL;
                    482:                bcc = (char*) 0;
                    483:                break;
                    484:                case 'C':
                    485:                case 'c':
                    486:                state = ST_RECIPHEAD;
                    487:                break;
                    488:                default:
                    489:                state = ST_OTHERHEAD;
                    490:                bcc = (char*) 0;
                    491:                break;
                    492:                }
                    493:            break;
                    494:            case ST_RECIPHEAD:
                    495:            switch ( *cp )
                    496:                {
                    497:                case '\n':
                    498:                state = ST_BOL;
                    499:                bcc = (char*) 0;
                    500:                break;
                    501:                case ':':
                    502:                state = ST_RECIPS;
                    503:                recip = cp + 1;
                    504:                break;
                    505:                default:
                    506:                state = ST_OTHERHEAD;
                    507:                bcc = (char*) 0;
                    508:                break;
                    509:                }
                    510:            break;
                    511:            case ST_RECIPS:
                    512:            switch ( *cp )
                    513:                {
                    514:                case '\n':
                    515:                add_recipient( recip, ( cp - recip ) );
                    516:                state = ST_BOL;
                    517:                if ( bcc != (char*) 0 )
                    518:                    {
                    519:                    /* Elide the Bcc: line, and reset cp. */
1.1.1.1.2.2! misho     520:                    (void) ol_strcpy( bcc, cp + 1 );
1.1       misho     521:                    cp = bcc - 1;
                    522:                    bcc = (char*) 0;
                    523:                    }
                    524:                break;
                    525:                case ',':
                    526:                add_recipient( recip, ( cp - recip ) );
                    527:                recip = cp + 1;
                    528:                break;
                    529:                }
                    530:            break;
                    531:            }
                    532:        }
                    533:     }
                    534: 
                    535: 
                    536: static void
                    537: add_recipient( char* recipient, int len )
                    538:     {
                    539:     char buf[1000];
                    540:     int status;
                    541: 
                    542:     /* Skip leading whitespace. */
                    543:     while ( len > 0 && ( *recipient == ' ' || *recipient == '\t' ) )
                    544:        {
                    545:        ++recipient;
                    546:        --len;
                    547:        }
                    548: 
                    549:     /* Strip off any angle brackets. */
1.1.1.1.2.2! misho     550: /*
1.1       misho     551:     while ( len > 0 && *recipient == '<' )
                    552:        {
                    553:        ++recipient;
                    554:        --len;
                    555:        }
                    556:     while ( len > 0 && recipient[len-1] == '>' )
                    557:        --len;
                    558: 
                    559:     (void) snprintf( buf, sizeof(buf), "RCPT TO:<%.*s>", len, recipient );
1.1.1.1.2.2! misho     560: */
        !           561:     if (len > 0 && recipient[len-1] == '>' )
        !           562:     {
        !           563:         /* "<name@domain>" or: "Full Name <name@domain>" */
        !           564:         while (len > 0 && *recipient != '<' )
        !           565:             {
        !           566:             ++recipient;
        !           567:             --len;
        !           568:             }
        !           569:         (void) snprintf( buf, sizeof(buf), "RCPT TO:%.*s", len, recipient );
        !           570:     }
        !           571:     else
        !           572:     {
        !           573:         /* name@domain */
        !           574:         (void) snprintf( buf, sizeof(buf), "RCPT TO:<%.*s>", len, recipient );
        !           575:     }
        !           576: 
1.1       misho     577:     send_command( buf );
                    578:     status = read_response();
                    579:     if ( status != 250  && status != 251 )
                    580:        {
                    581:        (void) fprintf(
                    582:            stderr,  "%s: unexpected response %d to RCPT TO command\n",
                    583:            argv0, status );
                    584:        exit( 1 );
                    585:        }
                    586:     got_a_recipient = 1;
                    587:     }
                    588: 
                    589: 
                    590: #if defined(AF_INET6) && defined(IN6_IS_ADDR_V4MAPPED)
                    591: #define USE_IPV6
                    592: #endif
                    593: 
                    594: static int
                    595: open_client_socket( void )
                    596:     {
                    597: #ifdef USE_IPV6
1.1.1.1.2.2! misho     598:     struct sockaddr_in6 sa_in;
1.1       misho     599: #else /* USE_IPV6 */
1.1.1.1.2.2! misho     600:     struct sockaddr_in sa_in;
1.1       misho     601: #endif /* USE_IPV6 */
                    602:     int sa_len, sock_family, sock_type, sock_protocol;
                    603:     int sockfd;
                    604: 
                    605:     sock_type = SOCK_STREAM;
                    606:     sock_protocol = 0;
1.1.1.1.2.2! misho     607:     sa_len = sizeof(sa_in);
        !           608:     (void) memset( (void*) &sa_in, 0, sa_len );
1.1       misho     609: 
                    610: #ifdef USE_IPV6
                    611: 
                    612:     {
                    613: #ifdef DO_MINUS_SP
1.1.1.1.2.2! misho     614:     struct sockaddr_in sa_in4;
1.1       misho     615:     struct addrinfo hints;
                    616:     char portstr[10];
                    617:     int gaierr;
                    618:     struct addrinfo* ai;
                    619:     struct addrinfo* ai2;
                    620:     struct addrinfo* aiv4;
                    621:     struct addrinfo* aiv6;
                    622: #endif /* DO_MINUS_SP */
                    623: 
                    624:     sock_family = PF_INET6;
                    625: 
                    626: #ifdef DO_MINUS_SP
1.1.1.1.2.2! misho     627:     (void) memset( (void*) &sa_in4, 0, sizeof(sa_in4) );
        !           628:     if ( inet_pton( AF_INET, server, (void*) &sa_in4.sin_addr ) == 1 )
1.1       misho     629:        {
                    630:        sock_family = PF_INET;
1.1.1.1.2.2! misho     631:        sa_in4.sin_port = htons( port );
        !           632:        sa_len = sizeof(sa_in4);
        !           633:        (void) memmove( &sa_in, &sa_in4, sa_len );
1.1       misho     634:        }
1.1.1.1.2.2! misho     635:     else if ( inet_pton( AF_INET6, server, (void*) &sa_in.sin6_addr ) != 1 )
1.1       misho     636:        {
                    637: #ifdef DO_DNS
                    638:        (void) memset( &hints, 0, sizeof(hints) );
                    639:        hints.ai_family = PF_UNSPEC;
                    640:        hints.ai_socktype = SOCK_STREAM;
                    641:        (void) snprintf( portstr, sizeof(portstr), "%d", port );
                    642:        if ( (gaierr = getaddrinfo( server, portstr, &hints, &ai )) != 0 )
                    643:            {
                    644:            (void) fprintf(
                    645:                stderr, "%s: getaddrinfo %s - %s\n", argv0, server,
                    646:                gai_strerror( gaierr ) );
                    647:            exit( 1 );
                    648:            }
                    649: 
                    650:        /* Find the first IPv4 and IPv6 entries. */
                    651:        aiv4 = (struct addrinfo*) 0;
                    652:        aiv6 = (struct addrinfo*) 0;
                    653:        for ( ai2 = ai; ai2 != (struct addrinfo*) 0; ai2 = ai2->ai_next )
                    654:            {
                    655:            switch ( ai2->ai_family )
                    656:                {
                    657:                case PF_INET:
                    658:                if ( aiv4 == (struct addrinfo*) 0 )
                    659:                    aiv4 = ai2;
                    660:                break;
                    661:                case PF_INET6:
                    662:                if ( aiv6 == (struct addrinfo*) 0 )
                    663:                    aiv6 = ai2;
                    664:                break;
                    665:                }
                    666:            }
                    667: 
                    668:        /* If there's an IPv4 address, use that, otherwise try IPv6. */
                    669:        if ( aiv4 != (struct addrinfo*) 0 )
                    670:            {
1.1.1.1.2.2! misho     671:            if ( sizeof(sa_in) < aiv4->ai_addrlen )
1.1       misho     672:                {
                    673:                (void) fprintf(
                    674:                    stderr, "%s - sockaddr too small (%lu < %lu)\n",
1.1.1.1.2.2! misho     675:                    server, (unsigned long) sizeof(sa_in),
1.1       misho     676:                    (unsigned long) aiv4->ai_addrlen );
                    677:                exit( 1 );
                    678:                }
                    679:            sock_family = aiv4->ai_family;
                    680:            sock_type = aiv4->ai_socktype;
                    681:            sock_protocol = aiv4->ai_protocol;
                    682:            sa_len = aiv4->ai_addrlen;
1.1.1.1.2.2! misho     683:            (void) memmove( &sa_in, aiv4->ai_addr, sa_len );
1.1       misho     684:            goto ok;
                    685:            }
                    686:        if ( aiv6 != (struct addrinfo*) 0 )
                    687:            {
1.1.1.1.2.2! misho     688:            if ( sizeof(sa_in) < aiv6->ai_addrlen )
1.1       misho     689:                {
                    690:                (void) fprintf(
                    691:                    stderr, "%s - sockaddr too small (%lu < %lu)\n",
1.1.1.1.2.2! misho     692:                    server, (unsigned long) sizeof(sa_in),
1.1       misho     693:                    (unsigned long) aiv6->ai_addrlen );
                    694:                exit( 1 );
                    695:                }
                    696:            sock_family = aiv6->ai_family;
                    697:            sock_type = aiv6->ai_socktype;
                    698:            sock_protocol = aiv6->ai_protocol;
                    699:            sa_len = aiv6->ai_addrlen;
1.1.1.1.2.2! misho     700:            (void) memmove( &sa_in, aiv6->ai_addr, sa_len );
1.1       misho     701:            goto ok;
                    702:            }
                    703: 
                    704:        (void) fprintf(
                    705:            stderr, "%s: no valid address found for host %s\n", argv0, server );
                    706:        exit( 1 );
                    707: 
                    708:        ok:
                    709:        freeaddrinfo( ai );
                    710: #else /* DO_DNS */
                    711:         (void) fprintf(
                    712:            stderr, "%s: bad server IP address %s\n", argv0, server );
                    713:        exit( 1 );
                    714: #endif /* DO_DNS */
                    715:        }
                    716: #else /* DO_MINUS_SP */
1.1.1.1.2.2! misho     717:     sa_in.sin6_addr = in6addr_any;
        !           718:     sa_in.sin6_port = htons( SMTP_PORT );
1.1       misho     719: #endif /* DO_MINUS_SP */
                    720: 
1.1.1.1.2.2! misho     721:     sa_in.sin6_family = sock_family;
1.1       misho     722: 
                    723:     }
                    724: 
                    725: #else /* USE_IPV6 */
                    726: 
                    727:     {
                    728: #ifdef DO_MINUS_SP
                    729:     struct hostent *he;
                    730: #else /* DO_MINUS_SP */
                    731:     char local_addr[4] = { 127, 0, 0, 1 };
                    732: #endif /* DO_MINUS_SP */
                    733: 
                    734:     sock_family = PF_INET;
                    735: 
                    736: #ifdef DO_MINUS_SP
1.1.1.1.2.2! misho     737:     sa_in.sin_addr.s_addr = inet_addr( server );
        !           738:     sa_in.sin_port = htons( port );
        !           739:     if ( (int32_t) sa_in.sin_addr.s_addr == -1 )
1.1       misho     740:        {
                    741: #ifdef DO_DNS
                    742:        he = gethostbyname( server );
                    743:        if ( he == (struct hostent*) 0 )
                    744:            {
                    745:            (void) fprintf(
                    746:                stderr, "%s: server name lookup of '%s' failed - %s\n",
                    747:                argv0, server, hstrerror( h_errno ) );
                    748:            exit( 1 );
                    749:            }
                    750:        sock_family = he->h_addrtype;
1.1.1.1.2.2! misho     751:        (void) memmove( &sa_in.sin_addr, he->h_addr, he->h_length );
1.1       misho     752: #else /* DO_DNS */
                    753:        (void) fprintf(
                    754:            stderr, "%s: bad server IP address %s\n", argv0, server );
                    755:        exit( 1 );
                    756: #endif /* DO_DNS */
                    757:        }
                    758: #else /* DO_MINUS_SP */
1.1.1.1.2.2! misho     759:     (void) memmove( &sa_in.sin_addr, local_addr, sizeof(local_addr) );
        !           760:     sa_in.sin_port = htons( SMTP_PORT );
1.1       misho     761: #endif /* DO_MINUS_SP */
                    762: 
1.1.1.1.2.2! misho     763:     sa_in.sin_family = sock_family;
1.1       misho     764:     }
                    765: 
                    766: #endif /* USE_IPV6 */
                    767: 
                    768:     sockfd = socket( sock_family, sock_type, sock_protocol );
                    769:     if ( sockfd < 0 )
                    770:        show_error( "socket" );
                    771: 
1.1.1.1.2.2! misho     772:     if ( connect( sockfd, (struct sockaddr*) &sa_in, sa_len ) < 0 )
1.1       misho     773:        show_error( "connect" );
                    774: 
                    775:     return sockfd;
                    776:     }
                    777: 
                    778: 
                    779: static int
                    780: read_response( void )
                    781:     {
                    782:     char buf[10000];
                    783:     char* cp;
                    784:     int status;
                    785: 
                    786:     for (;;)
                    787:        {
                    788:        (void) alarm( timeout );
                    789:        if ( fgets( buf, sizeof(buf), sockrfp ) == (char*) 0 )
                    790:            {
                    791:            (void) fprintf( stderr, "%s: unexpected EOF\n", argv0 );
                    792:            exit( 1 );
                    793:            }
                    794:        if ( verbose )
                    795:            (void) fprintf( stderr, "<<<< %s", buf );
                    796:        for ( status = 0, cp = buf; *cp >= '0' && *cp <= '9'; ++cp )
                    797:            status = 10 * status + ( *cp - '0' );
                    798:        if ( *cp == ' ' )
                    799:            break;
                    800:        if ( *cp != '-' )
                    801:            {
                    802:            (void) fprintf(
                    803:                stderr,  "%s: bogus reply syntax - '%s'\n", argv0, buf );
                    804:            exit( 1 );
                    805:            }
                    806:        }
                    807:     return status;
                    808:     }
                    809: 
                    810: 
                    811: static void
                    812: send_command( char* command )
                    813:     {
                    814:     (void) alarm( timeout );
                    815:     if ( verbose )
                    816:        (void) fprintf( stderr, ">>>> %s\n", command );
                    817:     (void) fprintf( sockwfp, "%s\r\n", command );
                    818:     (void) fflush( sockwfp );
                    819:     }
                    820: 
                    821: 
                    822: static void
                    823: send_data( char* data )
                    824:     {
                    825:     int bol;
                    826: 
                    827:     for ( bol = 1; *data != '\0'; ++data )
                    828:        {
                    829:        if ( bol && *data == '.' )
                    830:            putc( '.', sockwfp );
                    831:        bol = 0;
                    832:        if ( *data == '\n' )
                    833:            {
                    834:            putc( '\r', sockwfp );
                    835:            bol = 1;
                    836:            }
                    837:        putc( *data, sockwfp );
                    838:        }
                    839:     if ( ! bol )
                    840:        (void) fputs( "\r\n", sockwfp );
                    841:     }
                    842: 
                    843: 
                    844: static void
                    845: send_done( void )
                    846:     {
                    847:     (void) fputs( ".\r\n", sockwfp );
                    848:     (void) fflush( sockwfp );
                    849:     }
                    850: 
                    851: 
                    852: static void
                    853: sigcatch( int sig )
                    854:     {
                    855:     (void) fprintf( stderr, "%s: timed out\n", argv0 );
                    856:     exit( 1 );
                    857:     }
                    858: 
                    859: 
                    860: static void
                    861: show_error( char* cause )
                    862:     {
                    863:     char buf[5000];
                    864: 
                    865:     (void) snprintf( buf, sizeof(buf), "%s: %s", argv0, cause );
                    866:     perror( buf );
                    867:     exit( 1 );
                    868:     }

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