/*
* Copyright (c) 2004-2006 Sendmail, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*/
/*
** Send RFC 2821 addresses (or certs) to SMAR for access checks.
** Used by t-access-[012].sh
*/
#include "sm/generic.h"
SM_RCSID("@(#)$Id: t-access-0.c,v 1.37 2007/06/10 16:14:42 ca Exp $")
#include "sm/error.h"
#include "sm/assert.h"
#include "sm/memops.h"
#include "sm/io.h"
#include "sm/rcb.h"
#include "sm/qmgr.h"
#include "sm/qmgr-int.h"
#include "sm/dns.h"
#include "sm/smar.h"
#include "sm/reccom.h"
#include "sm/unixsock.h"
#include "sm/sysexits.h"
#include "sm/test.h"
/* context for requests */
struct t_req_S
{
char **rq_pa;
char *rq_pa2;
int rq_count;
uint32_t rq_rt;
uint32_t rq_type;
uint32_t rq_flags;
rcbcom_ctx_P rq_qar_com;
sm_evthr_task_P rq_wr_tsk;
};
#define SMAXLEN 256
typedef struct t_req_S t_req_T, *t_req_P;
static pthread_mutex_t mutex;
static pthread_cond_t cond;
static int Verbose = 0;
static uint MaxCount = (DNS_TIMEOUT + 1) * 10;
static int Requests = 0;
static int aqt_rcpts_ar = 0;
static sm_evthr_ctx_P evthr_ctx;
static rcbcom_ctx_T rcb_com;
static sm_ret_T ar2qmgr(sm_evthr_task_P _tsk);
static sm_ret_T qmgr2ar(sm_evthr_task_P _tsk);
/*
** FCTS -- "sleep" function: this function terminates the evthr system
** either after a certain number of iterations or if there are no
** more outstanding requests.
**
** Parameters:
** tsk -- evthr task
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
fcts(sm_evthr_task_P tsk)
{
static uint count = 0;
struct timeval sleept, delay;
++count;
if (Verbose > 3 && (count % 10 == 0))
sm_io_fprintf(smioerr, "fcts: count=%u/%u, ", count, MaxCount);
/* Theoretically Requests needs to be protected by a mutex... */
if (Requests <= 0 || count > MaxCount)
return EVTHR_DEL|EVTHR_TERM;
sm_memzero(&sleept, sizeof(sleept));
gettimeofday(&sleept, NULL);
delay.tv_sec = 1;
delay.tv_usec = 0;
timeradd(&sleept, &delay, &tsk->evthr_t_sleep);
return EVTHR_SLPQ;
}
/*
** QMGR_AR -- test program to AR interface
**
** Parameters:
** tsk -- evthr task
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
qmgr_ar(sm_evthr_task_P tsk)
{
sm_ret_T ret;
SM_IS_EVTHR_TSK(tsk);
if (is_valid_fd(tsk->evthr_t_fd)) {
ret = EVTHR_WAITQ;
if (evthr_got_wr(tsk)) {
if (Verbose > 3)
sm_io_fprintf(smioerr, "write\n");
ret = qmgr2ar(tsk); /* XXX check ret here? */
if (sm_is_err(ret) && Verbose > 0)
fprintf(stderr, "qmgr2ar=%x\n", ret);
}
if (evthr_got_rd(tsk)) {
if (Verbose > 3)
sm_io_fprintf(smioerr, "read\n");
ret = ar2qmgr(tsk);
}
if (sm_is_err(ret)) {
if (Verbose > 1)
sm_io_fprintf(smioerr, "qmgr_ar=%x\n", ret);
return ret;
}
return ret;
}
return EVTHR_DEL;
}
/*
** QR2AR -- Send address data to AR, i.e., put it into RCB
**
** Parameters:
** pa -- printable address
** rt -- record type
** type -- lookup type
** flags -- lookup flags
** rcbe -- RCB entry
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
qr2ar(sm_str_P pa, sm_str_P pa2, uint32_t rt, uint32_t type, uint32_t flags, sm_rcbe_P rcbe)
{
sm_rcb_P rcb;
sm_ret_T ret;
sessta_id_T ta_id;
ret = SM_SUCCESS;
rcb = &rcbe->rcbe_rcb;
sm_snprintf(ta_id, sizeof(ta_id), SMTPS_STID_FORMAT, (ulonglong_T)0, 0);
/*
** Currently clt2ar.c doesn't care much about the RT, i.e.,
** it can be CLT_A even though it is a mail address.
*/
ret = sm_rcb_putv(rcb, RCB_PUTV_FIRST,
SM_RCBV_INT, RT_PROT_VER, PROT_VER_RT,
SM_RCBV_INT, RT_S2A_ID, 1,
SM_RCBV_BUF, RT_S2A_TAID, ta_id, SMTP_STID_SIZE,
SM_RCBV_STR, rt, pa,
SM_RCBV_INT2, RT_S2A_LTYPE, type, flags,
SM_RCBV_INT,
SM_IS_FLAG(type, SMARA_LT_GREY) ? RT_S2A_TIME : RT_NOSEND,
(uint32_t) time(NULL),
SM_RCBV_END);
if (sm_is_err(ret))
goto error;
if (pa2 != NULL) {
ret = sm_rcb_putv(rcb, RCB_PUTV_NONE,
SM_RCBV_STR,
SM_IS_FLAG(type, SMARA_LT_RCPT_PROT)
? RT_S2A_MAIL : RT_S2A_CERTSUB,
pa2,
SM_RCBV_END);
if (sm_is_err(ret))
goto error;
}
if (Verbose > 4)
sm_io_fprintf(smioerr,
"func=qr2ar, ret=%d, rw=%d, size=%d, len=%d, max=%d\n"
, ret
, rcb->sm_rcb_rw
, rcb->sm_rcb_size
, rcb->sm_rcb_len
, rcb->sm_rcb_max
);
return ret;
error:
/* XXX leave rcb in a consistent state? */
return ret;
}
/*
** RCPT2AR -- send a recipient to SMAR
**
** Parameters:
** qar_tsk -- evthr task
** pa -- printable address of recipient
** rt -- record type
** type -- lookup type
** flags -- lookup flags
** qar_com -- RCBCOM context
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
rcpt2ar(sm_evthr_task_P qar_tsk, sm_str_P pa, sm_str_P pa2, uint32_t rt, uint32_t type, uint32_t flags, rcbcom_ctx_P qar_com)
{
sm_ret_T ret;
sm_rcbe_P rcbe;
ret = sm_rcbe_new_enc(&rcbe, -1, 0);
if (sm_is_err(ret))
goto error;
ret = qr2ar(pa, pa2, rt, type, flags, rcbe);
if (sm_is_err(ret))
goto error;
ret = sm_rcbcom_endrep(qar_com, qar_tsk, true, &rcbe);
if (sm_is_err(ret))
goto error;
++aqt_rcpts_ar;
return SM_SUCCESS;
error:
if (rcbe != NULL)
sm_rcbe_free(rcbe);
return ret;
}
/*
** QMGR2AR -- Test program to AR interface
**
** Parameters:
** tsk -- evthr task
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
qmgr2ar(sm_evthr_task_P tsk)
{
sm_ret_T ret;
rcbcom_ctx_P qar_com;
t_req_P t_req;
SM_IS_EVTHR_TSK(tsk);
t_req = (t_req_P) tsk->evthr_t_actx;
qar_com = t_req->rq_qar_com;
ret = sm_rcbcom2mod(tsk, qar_com);
if (Verbose > 4)
sm_io_fprintf(smioerr, "qmgr2ar, ret=%d\n", ret);
return ret;
}
/*
** REACT -- Decode data received from AR and act accordingly
**
** Parameters:
** tsk -- evthr task
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
react(sm_evthr_task_P tsk)
{
uint32_t v, l, rt, tl;
sm_ret_T ret;
sm_rcb_P rcb;
sessta_id_T ta_id;
char statt[256], rhs2[256];
t_req_P t_req;
rcbcom_ctx_P qar_com;
sm_cstr_P cstr;
bool gotstatt;
/* decode rcb */
t_req = (t_req_P) tsk->evthr_t_actx;
qar_com = t_req->rq_qar_com;
rcb = qar_com->rcbcom_rdrcb;
cstr = NULL;
ret = sm_rcb_open_dec(rcb);
if (sm_is_err(ret))
goto error;
/* total length of record */
ret = sm_rcb_getuint32(rcb, &tl);
if (sm_is_err(ret) || tl > QM_AR_MAX_REC_LEN ||
tl > sm_rcb_getlen(rcb))
goto err2;
/* protocol header: version */
ret = sm_rcb_get3uint32(rcb, &l, &rt, &v);
if (sm_is_err(ret))
goto err2;
if (l != 4 || rt != RT_PROT_VER || v != PROT_VER_RT)
goto err2;
/* XXX define protocol first in smX docs! */
/*
*/
/* XXX decode data, act accordingly... */
ret = sm_rcb_get3uint32(rcb, &l, &rt, &v);
if (sm_is_err(ret) || l != 4 || rt != RT_A2S_ID)
goto err2;
ret = sm_rcb_get2uint32(rcb, &l, &rt);
if (sm_is_err(ret) || l != SMTP_STID_SIZE || rt != RT_A2S_TAID)
goto err2;
ret = sm_rcb_getn(rcb, (uchar *) ta_id, l);
if (sm_is_err(ret))
goto err2;
ret = sm_rcb_get3uint32(rcb, &l, &rt, &v);
if (sm_is_err(ret) || l != 4)
goto err3;
SM_TEST(RT_A2S_MAP_RES == rt);
if (RT_A2S_MAP_RES == rt && SM_ACC_FOUND == v) {
ret = sm_rcb_get3uint32(rcb, &l, &rt, &v);
if (sm_is_err(ret) || l != 4)
goto err3;
/*
SM_TEST(RT_A2S_MAIL_ST == rt);
*/
if (RT_A2S_CLT_A_ST == rt)
sm_io_fprintf(smioerr, "clt_a_status=%d\n", v);
if (RT_A2S_CLT_N_ST == rt)
sm_io_fprintf(smioerr, "clt_n_status=%d\n", v);
if (RT_A2S_MAIL_ST == rt)
sm_io_fprintf(smioerr, "status=%d\n", v);
if (RT_A2S_RCPT_ST == rt)
sm_io_fprintf(smioerr, "rcpt-status=%d\n", v);
if (RT_A2S_CERT_ST == rt)
sm_io_fprintf(smioerr, "cert-status=%d\n", v);
}
gotstatt = false;
while (!SM_RCB_ISEOB(rcb)) {
ret = sm_rcb_get2uint32(rcb, &l, &rt);
switch (rt) {
case RT_A2S_STATT:
gotstatt = true;
if (l < sizeof(statt)) {
sm_memzero(statt, sizeof(statt));
ret = sm_rcb_getn(rcb, (uchar *) statt, l);
sm_io_fprintf(smioerr, "react=statt, ret=%x, statt='%.256s'\n", ret, statt);
if (sm_is_err(ret))
goto err2;
}
else {
sm_io_fprintf(smioerr, "ERROR: react=statt, stat=too-long\n");
SM_TEST(false);
goto err2;
}
break;
case RT_A2S_RVRS_ST:
ret = sm_rcb_getuint32(rcb, &v);
if (sm_is_err(ret))
goto err2;
sm_io_fprintf(smioerr, "react=rvrs_st, ret=%x, v=%#x\n", ret, v);
break;
case RT_A2S_MAP2_RES:
ret = sm_rcb_getuint32(rcb, &v);
if (sm_is_err(ret))
goto err2;
sm_io_fprintf(smioerr, "react=rhs2, ret=%x, res2=%#x\n", ret, v);
break;
case RT_A2S_RHS2_TXT:
if (l < sizeof(rhs2)) {
sm_memzero(rhs2, sizeof(rhs2));
ret = sm_rcb_getn(rcb, (uchar *) rhs2, l);
sm_io_fprintf(smioerr, "react=rhs2, ret=%x, rhs2='%.256s'\n", ret, rhs2);
if (sm_is_err(ret))
goto err2;
}
else {
sm_io_fprintf(smioerr, "ERROR: react=rhs2, stat=too-long\n");
SM_TEST(false);
goto err2;
}
break;
case RT_A2S_MAP_RES_CNF:
ret = sm_rcb_getuint32(rcb, &v);
if (sm_is_err(ret))
goto err2;
sm_io_fprintf(smioerr, "react=rhsconf, ret=%x, resconf=%#x\n", ret, v);
break;
case RT_A2S_RHS_CNF:
if (l < sizeof(rhs2)) {
sm_memzero(rhs2, sizeof(rhs2));
ret = sm_rcb_getn(rcb, (uchar *) rhs2, l);
sm_io_fprintf(smioerr, "react=rhsconf, ret=%x, rhsconf='%.256s'\n", ret, rhs2);
if (sm_is_err(ret))
goto err2;
}
else {
sm_io_fprintf(smioerr, "ERROR: react=rhsconf, stat=too-long\n");
SM_TEST(false);
goto err2;
}
break;
default:
sm_io_fprintf(smioerr, "ERROR: record-type=unknown, rt=%x, l=%d\n", rt, l);
SM_TEST(false);
sm_rcb_skip(rcb, l);
break;
}
}
if (!gotstatt)
sm_io_fprintf(smioerr, "react=no_match\n");
#if 0
ret = sm_rcb_get3uint32(rcb, &l, &rt, &v);
if (sm_is_err(ret) || l != 4 || rt != RT_R2Q_RCPT_NAR)
goto err3;
#endif /* 0 */
ret = sm_rcb_close_dec(qar_com->rcbcom_rdrcb);
(void) sm_rcb_open_rcv(qar_com->rcbcom_rdrcb);
--Requests;
return ret;
err3:
err2:
/* use rcb functions that don't do check the state */
(void) sm_rcb_close_decn(qar_com->rcbcom_rdrcb);
error:
/* open rcb for receiving next record */
(void) sm_rcb_open_rcvn(qar_com->rcbcom_rdrcb);
sm_io_fprintf(smioerr, "ERROR: react=%x\n", ret);
#if 0
errret:
#endif
--Requests;
return ret;
}
/*
** AR2QMGR -- AR - test program interface
**
** Parameters:
** tsk -- evthr task
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
ar2qmgr(sm_evthr_task_P tsk)
{
int fd;
sm_ret_T ret;
t_req_P t_req;
rcbcom_ctx_P qar_com;
SM_IS_EVTHR_TSK(tsk);
t_req = (t_req_P) tsk->evthr_t_actx;
qar_com = t_req->rq_qar_com;
fd = tsk->evthr_t_fd; /* checked in caller */
ret = sm_rcb_rcv(fd, qar_com->rcbcom_rdrcb, QSS_RC_MINSZ);
if (Verbose > 4)
sm_io_fprintf(smioerr, "ar2qmgr, ret=%d, rw=%d, size=%d, len=%d, max=%d\n"
, ret
, qar_com->rcbcom_rdrcb->sm_rcb_rw
, qar_com->rcbcom_rdrcb->sm_rcb_size
, qar_com->rcbcom_rdrcb->sm_rcb_len
, qar_com->rcbcom_rdrcb->sm_rcb_max
);
else if (Verbose > 1)
sm_io_fprintf(smioerr, "ar2qmgr, ret=%d\n", ret);
if (ret > 0)
return EVTHR_WAITQ;
else if (0 == ret) {
ret = sm_rcb_close_rcv(qar_com->rcbcom_rdrcb);
/* start appropriate function ... */
ret = react(tsk);
if (sm_is_err(ret))
goto termit; /* too harsh? */
else if (QMGR_R_WAITQ == ret)
return EVTHR_WAITQ;
else if (QMGR_R_ASYNC == ret)
return EVTHR_OK;
else if (EVTHR_DEL == ret)
goto termit;
else
return ret;
}
else if (SM_IO_EOF == ret) {
ret = sm_rcb_close_rcv(qar_com->rcbcom_rdrcb);
termit:
close(fd);
/* XXX see comment in qm_fr_ss() */
tsk->evthr_t_fd = INVALID_FD; /* make it invalid */
return EVTHR_DEL;
}
else /* if (ret < 0) */
{
}
#if 0
error:
#endif
return EVTHR_DEL;
}
/*
** LOOKUP -- queue recipient address lookups to SMAR
**
** Parameters:
** tsk -- evthr task
**
** Returns:
** usual sm_error code
*/
static sm_ret_T
lookup(sm_evthr_task_P tsk)
{
t_req_P t_req;
int n;
sm_ret_T ret;
char *addr;
sm_str_P pa, pa2;
SM_REQUIRE(tsk != NULL);
t_req = (t_req_P) tsk->evthr_t_actx;
if (NULL == t_req)
return EVTHR_DEL|EVTHR_TERM;
pa = NULL;
pa2 = NULL;
if (t_req->rq_pa2 != NULL) {
pa2 = sm_str_scpy(NULL, t_req->rq_pa2, SMAXLEN);
SM_TEST(pa2 != NULL);
if (NULL == pa2)
goto error;
}
#if 0
n = pthread_mutex_lock(&mutex);
SM_TEST(0 == n);
n = pthread_cond_wait(&cond, &mutex);
SM_TEST(0 == n);
#endif /* 0 */
if (Verbose > 1)
sm_io_fprintf(smioerr, "lookup, count=%d\n", t_req->rq_count);
for (n = 0; n < t_req->rq_count; n++) {
addr = t_req->rq_pa[n];
if (NULL == addr || *addr == '\0')
return EVTHR_DEL|EVTHR_TERM;
if (NULL == pa) {
pa = sm_str_scpy(NULL, addr, SMAXLEN);
SM_TEST(pa != NULL);
if (NULL == pa)
goto error;
}
else {
sm_str_clr(pa);
ret = sm_str_scat(pa, addr);
SM_TEST(SM_SUCCESS == ret);
if (sm_is_err(ret))
goto error;
}
if (Verbose > 1)
sm_io_fprintf(smioerr, "addr[%d]=%.256s\n", n, addr);
ret = rcpt2ar(tsk, pa, pa2, t_req->rq_rt, t_req->rq_type,
t_req->rq_flags, t_req->rq_qar_com);
if (sm_is_err(ret))
goto error;
}
/* Wakeup write task */
SM_TEST(t_req->rq_wr_tsk != NULL);
if (t_req->rq_wr_tsk != NULL) {
ret = evthr_en_wr(t_req->rq_wr_tsk);
if (Verbose > 1)
sm_io_fprintf(smioerr, "wakeup=%x\n", ret);
SM_TEST(sm_is_success(ret));
}
/* Paranoia... */
t_req->rq_count = 0;
SM_STR_FREE(pa);
/* We're done */
return EVTHR_DEL;
error:
SM_STR_FREE(pa);
return EVTHR_DEL|EVTHR_TERM;
}
/*
** TESTSMAR -- Test SMAR
**
** Parameters:
** t_req -- test context
**
** Returns:
** none.
*/
static void
testsmar(t_req_P t_req)
{
sm_ret_T ret;
sm_evthr_task_P task, task2, task3;
struct timeval sleept;
int lfd, n;
rcbcom_ctx_P qar_com;
evthr_ctx = NULL;
task = task3 = NULL;
ret = thr_init();
SM_TEST(sm_is_success(ret));
if (sm_is_err(ret))
goto errq;
ret = evthr_init(&evthr_ctx, 1, 6, 10);
SM_TEST(sm_is_success(ret));
if (sm_is_err(ret))
goto errt1;
SM_TEST(evthr_ctx != NULL);
n = pthread_cond_init(&cond, NULL);
SM_TEST(0 == n);
n = pthread_mutex_init(&mutex, NULL);
SM_TEST(0 == n);
qar_com = t_req->rq_qar_com;
ret = sm_rcbcom_open(qar_com);
if (sm_is_err(ret))
goto error;
SM_IS_RCB(qar_com->rcbcom_rdrcb);
#if SMAR_TCP_NET
(void) net_client_connect(smarip, smarport, &lfd);
#else
(void) unix_client_connect(smarsock, &lfd);
#endif
if (lfd < 0) {
ret = sm_error_perm(SM_EM_AR, errno);
goto error;
}
ret = sm_rcb_open_rcv(qar_com->rcbcom_rdrcb);
if (sm_is_err(ret))
goto error;
ret = sm_fd_nonblock(lfd, true);
if (sm_is_err(ret))
goto error; /* XXX COMPLAIN */
ret = evthr_task_new(evthr_ctx, &task, EVTHR_EV_RD,
lfd, NULL, qmgr_ar, (void *) t_req);
if (sm_is_err(ret))
goto error;
t_req->rq_wr_tsk = task;
n = gettimeofday(&sleept, NULL);
SM_TEST(0 == n);
sleept.tv_usec += 1000;
ret = evthr_task_new(evthr_ctx, &task3, EVTHR_EV_SL, -1, &sleept,
fcts, (void *) NULL);
SM_TEST(sm_is_success(ret));
SM_TEST(task3 != NULL);
sleept.tv_usec += 1;
ret = evthr_task_new(evthr_ctx, &task2, EVTHR_EV_SL, -1, &sleept,
lookup, (void *) t_req);
SM_TEST(sm_is_success(ret));
SM_TEST(task2 != NULL);
ret = evthr_loop(evthr_ctx);
SM_TEST(sm_is_success(ret));
goto done;
error:
sm_io_fprintf(smioerr, "ERROR\n");
done:
pthread_cond_destroy(&cond);
pthread_mutex_destroy(&mutex);
ret = evthr_stop(evthr_ctx);
SM_TEST(sm_is_success(ret));
errt1:
ret = thr_stop();
SM_TEST(sm_is_success(ret));
errq:
return;
}
/*
** USAGE -- usage message
**
** Parameters:
** prg -- program name
**
** Returns:
** none
*/
static void
usage(const char *prg)
{
fprintf(stderr, "usage: %s [options] addresses...\n"
"perform access checks, needs smar server\n"
"default checks: lookup type=SMARA_LT_MAIL_ACC, flags=LFL_2821\n"
"-A set lookup type SMARA_LT_MAIL_ACC\n"
"-C set lookup type SMARA_LT_CLT_A_ACC\n"
"-c certsubject set lookup type SMARA_LT_CERT_RELAY\n"
"-D implicitly match +detail for protected addresses\n"
"-e set lookup type SMARA_LT_EHLO_ACC\n"
"-F flags set lookup flags\n"
"-g perform greylisting too\n"
"-L set lookup type SMARA_LT_MAIL_LOCAL\n"
"-M set lookup type SMARA_LT_MAIL_ROUTE\n"
"-m set lookup flag SMARA_LFL_PROTMAP\n"
"-p address set lookup type SMARA_LT_RCPT_PROT\n"
"-r set lookup type SMARA_LT_RCPT_ACC\n"
"-S set lookup type SMARA_LT_SS_SE_CONF\n"
"-T type set lookup type\n"
"-V increase verbosity\n"
"-X set lookup flag SMARA_LFL_MXACC\n"
, prg
);
return;
}
/*
** MAIN -- guess...
**
** Parameters:
** argc -- arg counter
** argv -- arg vector
**
** Returns:
** usual exit code
*/
int
main(int argc, char *argv[])
{
int r;
t_req_T t_req;
char *pa2;
char **h;
void *ptr;
ptr = NULL;
h = NULL;
pa2 = NULL;
t_req.rq_rt = 0;
t_req.rq_type = 0;
t_req.rq_flags = 0;
while ((r = getopt(argc, argv, "ACc:DeF:fgLMmp:rR:SsT:VX")) != -1) {
switch (r) {
case 'A':
t_req.rq_type |= SMARA_LT_MAIL_ACC;
break;
case 'C':
t_req.rq_type = SMARA_LT_CLT_A_ACC;
t_req.rq_flags = SMARA_LFL_IPV4|SMARA_LFL_SUB
|SMARA_LFL_RVRS4|SMARA_LFL_RVACC
|SMARA_LFL_DNSBL;
break;
case 'c':
t_req.rq_flags = SMARA_LFL_CERT;
t_req.rq_type |= SMARA_LT_CERT_RELAY;
pa2 = strdup(optarg);
if (NULL == pa2)
exit(EX_OSERR);
break;
case 'D':
t_req.rq_flags |= SMARA_LFL_PROTIMPLDET;
break;
case 'e':
t_req.rq_rt = RT_S2A_EHLO;
t_req.rq_type |= SMARA_LT_EHLO_ACC;
t_req.rq_flags = SMARA_LFL_STR;
break;
case 'F':
t_req.rq_flags = strtoul(optarg, NULL, 0);
break;
case 'f':
t_req.rq_type = SMARA_LT_CLT_A_ACC|SMARA_LT_SS_SE_CONF;
t_req.rq_flags = SMARA_LFL_IPV4|SMARA_LFL_SUB
|SMARA_LFL_RVRS4|SMARA_LFL_RVACC
|SMARA_LFL_DNSBL;
break;
case 'g':
t_req.rq_flags = SMARA_LFL_IPV4|SMARA_LFL_SUB;
t_req.rq_type = SMARA_LT_GREY|SMARA_LT_CLT_A_ACC;
break;
case 'L':
t_req.rq_type |= SMARA_LT_MAIL_LOCAL;
break;
case 'M':
t_req.rq_type |= SMARA_LT_MAIL_ROUTE;
break;
case 'm':
t_req.rq_flags |= SMARA_LFL_PROTMAP;
break;
case 'p':
t_req.rq_type |= SMARA_LT_RCPT_PROT;
t_req.rq_flags = SMARA_LFL_2821;
pa2 = strdup(optarg);
if (NULL == pa2)
exit(EX_OSERR);
break;
case 'r':
t_req.rq_type |= SMARA_LT_RCPT_ACC;
break;
case 'R':
MaxCount = atoi(optarg);
break;
case 'S':
t_req.rq_flags = SMARA_LFL_IPV4|SMARA_LFL_SUB;
t_req.rq_type = SMARA_LT_CLT_A_ACC|SMARA_LT_SS_SE_CONF;
break;
case 'T':
t_req.rq_type = strtoul(optarg, NULL, 0);
break;
case 'V':
Verbose++;
#if RCBCOMM_DEBUG
rcbcomm_debug++;
#endif
break;
case 'X':
t_req.rq_flags |= SMARA_LFL_MXACC;
break;
default:
usage(argv[0]);
return 1;
}
}
if (0 == t_req.rq_rt)
t_req.rq_rt = RT_S2A_CLT_A;
if (0 == t_req.rq_type)
t_req.rq_type = SMARA_LT_MAIL_ACC;
if (0 == t_req.rq_flags)
t_req.rq_flags = SMARA_LFL_2821;
sm_test_begin(argc, argv, "test access 0");
t_req.rq_count = argc - optind;
h = (char **) sm_malloc(sizeof(char *) * t_req.rq_count);
ptr = h;
SM_TEST(h != NULL);
if (NULL == h)
goto error;
t_req.rq_pa = h;
t_req.rq_qar_com = &rcb_com;
if (pa2 != NULL)
t_req.rq_pa2 = pa2;
else
t_req.rq_pa2 = NULL;
for (r = optind; r < argc; r++) {
*h = argv[r];
++h;
++Requests;
}
testsmar(&t_req);
error:
if (ptr != NULL)
sm_free(ptr);
return sm_test_end();
}
syntax highlighted by Code2HTML, v. 0.9.1