int
auth_get_no64_data(uschar **aptr, uschar *challenge)
{
int c;
int p = 0;
smtp_printf("334 %s\r\n", challenge);
while ((c = receive_getc()) != '\n' && c != EOF)
  {
  if (p >= big_buffer_size - 1) return BAD64;
  big_buffer[p++] = c;
  }
if (p > 0 && big_buffer[p-1] == '\r') p--;
big_buffer[p] = 0;
if (Ustrcmp(big_buffer, "*") == 0) return CANCELLED;
*aptr = big_buffer;
return OK;
}
Exemple #2
0
int
auth_get_data(uschar **aptr, uschar *challenge, int challen)
{
int c;
int p = 0;
smtp_printf("334 %s\r\n", b64encode(challenge, challen));
while ((c = receive_getc()) != '\n' && c != EOF)
  {
  if (p >= big_buffer_size - 1) return BAD64;
  big_buffer[p++] = c;
  }
if (p > 0 && big_buffer[p-1] == '\r') p--;
big_buffer[p] = 0;
DEBUG(D_receive) debug_printf("SMTP<< %s\n", big_buffer);
if (Ustrcmp(big_buffer, "*") == 0) return CANCELLED;
*aptr = big_buffer;
return OK;
}
Exemple #3
0
static void data_done(int unused, char *context)
{
    SESSION *session = (SESSION *) context;
    RESPONSE *resp;
    int     except;
    static const char *mydate;
    static int mypid;

    /*
     * Get response to DATA command.
     */
    if ((except = vstream_setjmp(session->stream)) != 0)
        msg_fatal("%s while sending DATA command", exception_text(except));
    if ((resp = response(session->stream, buffer))->code == 354) {
        /* see below */ ;
    } else if (allow_reject) {
        msg_warn("data rejected: %d %s", resp->code, resp->str);
        if (resp->code == 421 || resp->code == 521) {
            close_session(session);
            return;
        }
        send_rset(unused, context);
        return;
    } else {
        msg_fatal("data rejected: %d %s", resp->code, resp->str);
    }

    /*
     * Send basic header to keep mailers that bother to examine them happy.
     */
    if (send_headers) {
        if (mydate == 0) {
            mydate = mail_date(time((time_t *) 0));
            mypid = getpid();
        }
        smtp_printf(session->stream, "From: <%s>", sender);
        smtp_printf(session->stream, "To: <%s>", recipient);
        smtp_printf(session->stream, "Date: %s", mydate);
        smtp_printf(session->stream, "Message-Id: <%04x.%04x.%04x@%s>",
                    mypid, vstream_fileno(session->stream), message_count, var_myhostname);
        if (subject)
            smtp_printf(session->stream, "Subject: %s", subject);
        smtp_fputs("", 0, session->stream);
    }

    /*
     * Send some garbage.
     */
    if ((except = vstream_setjmp(session->stream)) != 0)
        msg_fatal("%s while sending message", exception_text(except));
    if (message_length == 0) {
        smtp_fputs("La de da de da 1.", 17, session->stream);
        smtp_fputs("La de da de da 2.", 17, session->stream);
        smtp_fputs("La de da de da 3.", 17, session->stream);
        smtp_fputs("La de da de da 4.", 17, session->stream);
    } else {

        /*
         * XXX This may cause the process to block with message content
         * larger than VSTREAM_BUFIZ bytes.
         */
        smtp_fputs(message_data, message_length, session->stream);
    }

    /*
     * Send end of message and process the server response.
     */
    command(session->stream, ".");

    /*
     * Update the running counter.
     */
    if (count) {
        counter++;
        vstream_printf("%d\r", counter);
        vstream_fflush(VSTREAM_OUT);
    }

    /*
     * Prepare for the next event.
     */
    event_enable_read(vstream_fileno(session->stream), dot_done, (char *) session);
}
Exemple #4
0
static void soft_err_resp(SINK_STATE *state)
{
    smtp_printf(state->stream, SOFT_ERROR_RESP);
    smtp_flush(state->stream);
}
Exemple #5
0
static void hard_err_resp(SINK_STATE *state)
{
    smtp_printf(state->stream, HARD_ERROR_RESP);
    smtp_flush(state->stream);
}
Exemple #6
0
static void soft_err_resp(SINK_STATE *state)
{
    smtp_printf(state->stream, "%s", soft_error_resp);
    SMTP_FLUSH(state->stream);
}
Exemple #7
0
int
tls_server_start(uschar *require_ciphers, uschar *require_mac,
  uschar *require_kx, uschar *require_proto)
{
int rc;
const char *error;
uschar *expciphers = NULL;
uschar *expmac = NULL;
uschar *expkx = NULL;
uschar *expproto = NULL;

/* Check for previous activation */

if (tls_active >= 0)
  {
  tls_error("STARTTLS received after TLS started", NULL, "");
  smtp_printf("554 Already in TLS\r\n");
  return FAIL;
  }

/* Initialize the library. If it fails, it will already have logged the error
and sent an SMTP response. */

DEBUG(D_tls) debug_printf("initializing GnuTLS as a server\n");

rc = tls_init(NULL, tls_certificate, tls_privatekey, tls_verify_certificates,
  tls_crl);
if (rc != OK) return rc;

if (!expand_check(require_ciphers, US"tls_require_ciphers", &expciphers) ||
    !expand_check(require_mac, US"gnutls_require_mac", &expmac) ||
    !expand_check(require_kx, US"gnutls_require_kx", &expkx) ||
    !expand_check(require_proto, US"gnutls_require_proto", &expproto))
  return FAIL;

/* If this is a host for which certificate verification is mandatory or
optional, set up appropriately. */

tls_certificate_verified = FALSE;
verify_requirement = VERIFY_NONE;

if (verify_check_host(&tls_verify_hosts) == OK)
  verify_requirement = VERIFY_REQUIRED;
else if (verify_check_host(&tls_try_verify_hosts) == OK)
  verify_requirement = VERIFY_OPTIONAL;

/* Prepare for new connection */

tls_session = tls_session_init(GNUTLS_SERVER, expciphers, expmac, expkx,
  expproto);
if (tls_session == NULL)
  return tls_error(US"tls_session_init", NULL,
    gnutls_strerror(GNUTLS_E_MEMORY_ERROR));

/* Set context and tell client to go ahead, except in the case of TLS startup
on connection, where outputting anything now upsets the clients and tends to
make them disconnect. We need to have an explicit fflush() here, to force out
the response. Other smtp_printf() calls do not need it, because in non-TLS
mode, the fflush() happens when smtp_getc() is called. */

if (!tls_on_connect)
  {
  smtp_printf("220 TLS go ahead\r\n");
  fflush(smtp_out);
  }

/* Now negotiate the TLS session. We put our own timer on it, since it seems
that the GnuTLS library doesn't. */

gnutls_transport_set_ptr2(tls_session, (gnutls_transport_ptr)fileno(smtp_in),
                                       (gnutls_transport_ptr)fileno(smtp_out));

sigalrm_seen = FALSE;
if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
rc = gnutls_handshake(tls_session);
alarm(0);

if (rc < 0)
  {
  tls_error(US"gnutls_handshake", NULL,
    sigalrm_seen ? "timed out" : gnutls_strerror(rc));

  /* It seems that, except in the case of a timeout, we have to close the
  connection right here; otherwise if the other end is running OpenSSL it hangs
  until the server times out. */

  if (!sigalrm_seen)
    {
    (void)fclose(smtp_out);
    (void)fclose(smtp_in);
    }

  return FAIL;
  }

DEBUG(D_tls) debug_printf("gnutls_handshake was successful\n");

if (verify_requirement != VERIFY_NONE &&
     !verify_certificate(tls_session, &error))
  {
  tls_error(US"certificate verification failed", NULL, error);
  return FAIL;
  }

construct_cipher_name(tls_session);

/* TLS has been set up. Adjust the input functions to read via TLS,
and initialize appropriately. */

ssl_xfer_buffer = store_malloc(ssl_xfer_buffer_size);
ssl_xfer_buffer_lwm = ssl_xfer_buffer_hwm = 0;
ssl_xfer_eof = ssl_xfer_error = 0;

receive_getc = tls_getc;
receive_ungetc = tls_ungetc;
receive_feof = tls_feof;
receive_ferror = tls_ferror;
receive_smtp_buffered = tls_smtp_buffered;

tls_active = fileno(smtp_out);

return OK;
}
static void soft_err_resp(SINK_STATE *state)
{
    smtp_printf(state->stream, soft_error_resp);
    smtp_flush(state->stream);
}
Exemple #9
0
void server( vsock_t *ssrv ) {

    struct smtp_resp *resp;
    struct smtp_cmd  *cmd;

    char *mail_from = NULL;

    vsock_t *sclnt;

    if ( (sclnt = vsock_connect(connect_to, 1500, timeout)) == NULL ) {
        error( "Can't forward connection" );

        smtp_putreply( ssrv, 554, "Sorry, can't forward connection", 0 );

        while( (cmd = smtp_readcmd(ssrv)) != NULL ) {
            if ( strcasecmp(cmd->command, "QUIT") == NULL ) 
                break;
            free_smtp_cmd( cmd );
            smtp_putreply( ssrv, 503, "bad sequence of commands", 0 );
        }
        free_smtp_cmd( cmd );
        smtp_putreply( ssrv, 221, "Bye", 0 );
        vsock_close( ssrv );

        return ;
    }

    resp = smtp_readreply( sclnt );

    if ( resp->code != 220 ) {
        error( "forward server not ready: %d %s", resp->code, resp->text  );

        while( resp != NULL && resp->cont ) {
            smtp_putreply(  ssrv, resp->code, resp->text, resp->cont );
            free_smtp_resp( resp );
            resp = smtp_readreply( sclnt );
        }
        
        smtp_putreply( ssrv, resp->code, resp->text, resp->cont );
        free_smtp_resp( resp );

        while( 1 ) {
            if ( (cmd = smtp_readcmd( ssrv )) == NULL ) {
                break;
            }
            if ( smtp_putcmd( sclnt, cmd ) ) {
                free_smtp_cmd( cmd );
                break;
            }

            resp = smtp_readreply(sclnt);
            while( resp != NULL && resp->cont ) {
                smtp_putreply(  ssrv, resp->code, resp->text, resp->cont );
                free_smtp_resp( resp );
                resp = smtp_readreply( sclnt );
            }
            if ( resp == NULL ) {
                break;
            }

            if ( smtp_putreply( ssrv, resp->code, resp->text, resp->cont )) {
                free_smtp_resp( resp );
                break;
            }
            free_smtp_resp( resp );
        }

        vsock_close( ssrv  );
        vsock_close( sclnt );
        
        return ;
    } 
    free_smtp_resp( resp );

    smtp_putreply( ssrv, 220, "localhost SMTP AV-filter " VERSION, 0 );

    while( 1 ) {
        int rc;

        cmd = smtp_readcmd( ssrv );
        if ( cmd == NULL ) {
            break;
        }
        if ( !strcasecmp(cmd->command, "MAIL") ) {
            if ( mail_from != NULL ) {
                free( mail_from );
                mail_from = NULL;
            }
            if ( cmd->argv[0] != NULL) {
                char *p;
                if ( (p = strchr(cmd->argv[0], ':')) != NULL ) { 
                    mail_from = strdup( p + 1 );
                }
            }
        }
        if ( strcasecmp(cmd->command, "DATA") == NULL ) {
            struct mem_chunk *data;

            smtp_putreply( ssrv, 354, "End data with <CR><LF>.<CR><LF>", 0 );
            debug( "enter DATA" );
            data = smtp_readdata( ssrv );
            if ( check_data( data ) ) {
                free_mem_chunks( data );
                error("message from %s infected", mail_from == NULL ?  "<unknown user>" : mail_from );
                cmd->command = "RSET";
                cmd->argc = 0;
                smtp_putcmd( sclnt, cmd );
                resp = smtp_readreply( sclnt );
                free_smtp_resp( resp );
                smtp_putreply(  ssrv, 550, "Content rejected (Message infected with virus)", 0 );
            }
            else { 
                notice( "message from %s passed virus check", 
                        mail_from == NULL ?  "<unknown user>" : mail_from );

                rc = smtp_putcmd( sclnt, cmd );
                free_smtp_cmd( cmd );
                if ( rc ) { 
                    debug( "smtp_putcmd failed, breaking loop" );
                    break;
                }
                debug( "loop: rr1-1" );
                resp = smtp_readreply( sclnt );
                if ( resp == NULL ) {
                    debug( "smtp_readreply failed, breaking loop" );
                    break;
                }
                if ( resp->code != 354 ) {
                    error("DATA failed: %d %s", resp->code, resp->text);
                    cmd->command = "DATA";
                    cmd->argc = 0;
                    /* FIXME */
                    smtp_putcmd( sclnt, cmd );
                    smtp_readreply( sclnt );
                }
                free_smtp_resp( resp );

                smtp_printf( sclnt, "Received: from %s by %s (AV-filter %s) ;" ,
                        "localhost", "localhost", VERSION  );
                smtp_printf( sclnt, "\t%s",  mail_date( time( NULL )));

                smtp_putdata( sclnt, data );
                free_mem_chunks( data );
                resp = smtp_readreply( sclnt );
                smtp_putreply(  ssrv, resp->code, resp->text, resp->cont );
                free_smtp_resp( resp );
            }
        } 
        else {
            rc = smtp_putcmd( sclnt, cmd );
            free_smtp_cmd( cmd ); 
            if ( rc ) { 
                debug( "smtp_putcmd failed, breaking loop" );
                break;
            }
            resp = smtp_readreply( sclnt );
            while( resp != NULL && resp->cont ) {
#if 0                
                if ( strcasecmp(resp->text, "PIPELINING") != NULL )
#endif
                    smtp_putreply(  ssrv, resp->code, resp->text, resp->cont );
                free_smtp_resp( resp );
                resp = smtp_readreply( sclnt );
            }
            if ( resp == NULL ) {
                debug( "smtp_readreply failed, breaking loop" );
                break;
            }
            rc = smtp_putreply( ssrv, resp->code, resp->text, resp->cont );
            if ( rc ) {
                free_smtp_resp( resp );
                debug( "smtp_putreply failed, breaking loop" );
                break;
            }
            if ( resp->code == 221 ) {
                free_smtp_resp( resp );
                debug( "221 response received" );
                break;
            }
            free_smtp_resp( resp );
        }

    }
    vsock_close( ssrv  );
    vsock_close( sclnt );
}