Exemple #1
0
void
ds_diction_destroy (ds_diction_t diction)
{
  ds_term_t term, next;
  ds_cursor_t cur;

  if (!diction) return;

  cur = ds_diction_cursor(diction);
  if (!cur) {
    perror("ds_diction_destroy: ds_diction_cursor() failed");
    return;
  } 

  term = ds_diction_next(cur);
  while(term)
  {
    next = ds_diction_next(cur);
    ds_diction_delete(diction, term->key);
    term = next;
  }
  ds_diction_close(cur);

  nt_destroy(diction->order);
  nt_destroy(diction->chained_order);
  free(diction->tbl);
  free(diction); 
  return;
}
Exemple #2
0
//这个函数停止重叠网络, 当接收到信号SIGINT时, 该函数被调用.
//它关闭所有的连接, 释放所有动态分配的内存.
void son_stop() {
	close(sip_conn);
	sip_conn = -1;
	nt_destroy(nt);
	printf("[SON] stop!\n");
	exit(1);
}
Exemple #3
0
//这个函数停止重叠网络, 当接收到信号SIGINT时, 该函数被调用.
//它关闭所有的连接, 释放所有动态分配的内存.
void son_stop() {
	// close sip connect
	close(sip_conn);
	printf("MSG: close sip_conn ok\n");
	nt_destroy(nt);
	printf("MSG: destroy nbr table ok\n");
	exit(1);
}
Exemple #4
0
ds_diction_t
ds_diction_create (unsigned long size)
{
  ds_diction_t diction = (ds_diction_t) calloc(1, sizeof(struct _ds_diction));
  int i = 0;

  if (!diction) {
    perror("ds_diction_create: calloc() failed");
    return NULL;
  }

  while (_ds_prime_list[i] < size) 
    { i++; }

  diction->size = _ds_prime_list[i];
  diction->items = 0;
  diction->tbl =
    (struct _ds_term **) calloc(diction->size, sizeof (struct _ds_term *));
  if (!diction->tbl)
  {
    perror("ds_diction_create: calloc() failed");
    free(diction);
    return NULL;
  }

  diction->order = nt_create(NT_INDEX);
  diction->chained_order = nt_create(NT_INDEX);
  if (!diction->order || !diction->chained_order) {
    nt_destroy(diction->order);
    nt_destroy(diction->chained_order);
    free(diction->tbl);
    free(diction);
    return NULL;
  }

  return diction;
}
Exemple #5
0
int
process_sigs (DSPAM_CTX * CTX, int age)
{
  struct _ds_storage_signature *ss;
  struct nt *del;
  struct nt_node *node;
  int delta;

  del = nt_create(NT_CHAR);
  if (del == NULL)
    return -1;

#ifdef DEBUG
    printf ("Processing sigs; age: %d\n", age);
#endif

  ss = _ds_get_nextsignature (CTX);
  while (ss != NULL)
  {
#ifdef DEBUG
    printf ("Signature: %s\n    Created: %s\n", ss->signature,
            ctime (&ss->created_on));
#endif
    delta = (((time (NULL) - ss->created_on) / 60) / 60) / 24;
    if (age == 0 || delta > age)
    {
#ifdef DEBUG
      printf ("    DELETED!\n");
#endif
      nt_add(del, ss->signature);
    }
    free(ss->data);
    free(ss);
    ss = _ds_get_nextsignature (CTX);
  }

  node = del->first;
  while(node != NULL) {
    _ds_delete_signature (CTX, node->ptr);
    node = node->next; 
  }
  nt_destroy(del);

  return 0;
}
Exemple #6
0
int
_ds_shutdown_storage (DSPAM_CTX * CTX)
{
  struct _hash_drv_storage *s;
  struct nt_node *node_nt;
  struct nt_c c_nt;
  int lock_result;

  if (!CTX || !CTX->storage)
    return EINVAL;

  s  = (struct _hash_drv_storage *) CTX->storage;

  /* Close open file handles to directories (iteration functions) */

  node_nt = c_nt_first (s->dir_handles, &c_nt);
  while (node_nt != NULL)
  {
    DIR *dir;
    dir = (DIR *) node_nt->ptr;
    closedir (dir);
    node_nt = c_nt_next (s->dir_handles, &c_nt);
  }
  nt_destroy (s->dir_handles);

  if (CTX->operating_mode != DSM_CLASSIFY)
    _hash_drv_set_spamtotals (CTX);

  /* Close connection to hash database only if we're not concurrent */

  if (!s->dbh_attached) {
    _hash_drv_close(s->map);
    free(s->map);
    lock_result =
      _hash_drv_lock_free (s, (CTX->group) ? CTX->group : CTX->username);
    if (lock_result < 0)
      return EUNKNOWN;
  }

  free (CTX->storage);
  CTX->storage = NULL;

  return 0;
}
Exemple #7
0
int
_ds_shutdown_storage (DSPAM_CTX * CTX)
{
  struct _sqlite_drv_storage *s = (struct _sqlite_drv_storage *) CTX->storage;
  struct nt_node *node_nt;
  struct nt_c c_nt;

  if (s->dbh == NULL)
  {
    LOGDEBUG ("_ds_shutdown_storage: invalid database handle (NULL)");
    return EINVAL;
  }

  node_nt = c_nt_first (s->dir_handles, &c_nt);
  while (node_nt != NULL)
  {
    DIR *dir;
    dir = (DIR *) node_nt->ptr;
    closedir (dir);
    node_nt = c_nt_next (s->dir_handles, &c_nt);
  }
                                                                                
  nt_destroy (s->dir_handles);


  /* Store spam totals on shutdown */
  if (CTX->username != NULL && CTX->operating_mode != DSM_CLASSIFY)
  {
      _sqlite_drv_set_spamtotals (CTX);
  }

  if (!s->dbh_attached)
    sqlite_close(s->dbh);

  s->dbh = NULL;

  free(s);
  CTX->storage = NULL;

  return 0;
}
Exemple #8
0
//这个函数停止重叠网络, 当接收到信号SIGINT时, 该函数被调用.
//它关闭所有的连接, 释放所有动态分配的内存.
void son_stop() {
	//你需要编写这里的代码.
	nt_destroy(nt);
	close(sip_conn);
	exit(0);
}
Exemple #9
0
int _ds_tokenize_ngram(
  DSPAM_CTX *CTX,
  char *headers,
  char *body,
  ds_diction_t diction)
{
  char *token;				/* current token */
  char *previous_token = NULL;		/* used for bigrams (chained tokens) */
  char *line = NULL;			/* header broken up into lines */
  char *ptrptr;
  char heading[128];			/* current heading */
  int l, tokenizer = CTX->tokenizer;

  struct nt *header = NULL;
  struct nt_node *node_nt;
  struct nt_c c_nt;

  /* Tokenize URLs in message */

  if (_ds_match_attribute(CTX->config->attributes, "ProcessorURLContext", "on"))  {
    _ds_url_tokenize(diction, body, "http://");
    _ds_url_tokenize(diction, body, "www.");
    _ds_url_tokenize(diction, body, "href=");
  }

  /*
   * Header Tokenization
   */
 
  header = nt_create (NT_CHAR);
  if (header == NULL)
  {
    LOG (LOG_CRIT, ERR_MEM_ALLOC);
    return EUNKNOWN;
  }

  line = strtok_r (headers, "\n", &ptrptr);
  while (line) {
    nt_add (header, line);
    line = strtok_r (NULL, "\n", &ptrptr);
  }

  node_nt = c_nt_first (header, &c_nt);
  heading[0] = 0;
  while (node_nt) {
    int multiline;

#ifdef VERBOSE
    LOGDEBUG("processing line: %s", node_nt->ptr);
#endif

    line = node_nt->ptr;
    token = strtok_r (line, ":", &ptrptr);
    if (token && token[0] != 32 && token[0] != 9 && !strstr (token, " "))
    {
      multiline = 0;
      strlcpy (heading, token, 128);
      previous_token = NULL;
    } else {
      multiline = 1;
    }

#ifdef VERBOSE
    LOGDEBUG ("Reading '%s' header from: '%s'", heading, line);
#endif

    if (CTX->flags & DSF_WHITELIST) {
      /* Use the entire From: line for auto-whitelisting */

      if (!strcmp(heading, "From")) {
        char wl[256];
        char *fromline = line + 5;
        unsigned long long whitelist_token;

        if (fromline[0] == 32) 
          fromline++;
        snprintf(wl, sizeof(wl), "%s*%s", heading, fromline);
        whitelist_token = _ds_getcrc64(wl);
        ds_diction_touch(diction, whitelist_token, wl, 0);
        diction->whitelist_token = whitelist_token;
      }
    }

    /* Received headers use a different set of delimiters to preserve things
       like ip addresses */

    token = strtok_r ((multiline) ? line : NULL, DELIMITERS_HEADING, &ptrptr);

    while (token)
    {
      l = strlen(token);

      if (l >= 1 && l < 50)
      {
#ifdef VERBOSE
        LOGDEBUG ("Processing '%s' token in '%s' header", token, heading);
#endif

        /* Process "current" token */
        if (!_ds_process_header_token
            (CTX, token, previous_token, diction, heading) && 
            (tokenizer == DSZ_CHAIN))
        {
          previous_token = token;
        }
      }

      token = strtok_r (NULL, DELIMITERS_HEADING, &ptrptr);
    }

    previous_token = NULL;
    node_nt = c_nt_next (header, &c_nt);
  }

  nt_destroy (header);

  /*
   * Body Tokenization
   */

#ifdef VERBOSE
  LOGDEBUG("parsing message body");
#endif

  token = strtok_r (body, DELIMITERS, &ptrptr);
  while (token != NULL)
  {
    l = strlen (token);
    if (l >= 1 && l < 50)
    {
#ifdef VERBOSE
        LOGDEBUG ("Processing body token '%s'", token);
#endif

      /* Process "current" token */
      if ( !_ds_process_body_token(CTX, token, previous_token, diction)
        && tokenizer == DSZ_CHAIN)
      {
        previous_token = token;
      }
    }
    token = strtok_r (NULL, DELIMITERS, &ptrptr);
  }

#ifdef VERBOSE
  LOGDEBUG("Finished tokenizing (ngram) message");
#endif

  /* Final token reassembly (anything left in the buffer) */

  return 0;
}
Exemple #10
0
int _ds_tokenize_sparse(
  DSPAM_CTX *CTX,
  char *headers,
  char *body,
  ds_diction_t diction)
{
  int i;
  char *token;				/* current token */
  char *previous_tokens[SPARSE_WINDOW_SIZE];	/* sparse chain */

  char *line = NULL;			/* header broken up into lines */
  char *ptrptr;
  char *bitpattern;

  char heading[128];			/* current heading */
  int l;

  struct nt *header = NULL;
  struct nt_node *node_nt;
  struct nt_c c_nt;

  for(i=0;i<SPARSE_WINDOW_SIZE;i++)
    previous_tokens[i] = NULL;

  bitpattern = _ds_generate_bitpattern(_ds_pow2(SPARSE_WINDOW_SIZE));

  /* Tokenize URLs in message */

  if (_ds_match_attribute(CTX->config->attributes, "ProcessorURLContext", "on"))
  {
    _ds_url_tokenize(diction, body, "http://");
    _ds_url_tokenize(diction, body, "www.");
    _ds_url_tokenize(diction, body, "href=");
  }

  /*
   * Header Tokenization 
   */
 
  header = nt_create (NT_CHAR);
  if (header == NULL)
  {
    LOG (LOG_CRIT, ERR_MEM_ALLOC);
    free(bitpattern);
    return EUNKNOWN;
  }

  line = strtok_r (headers, "\n", &ptrptr);
  while (line) {
    nt_add (header, line);
    line = strtok_r (NULL, "\n", &ptrptr);
  }

  node_nt = c_nt_first (header, &c_nt);
  heading[0] = 0;
  while (node_nt) {
    int multiline;

#ifdef VERBOSE
    LOGDEBUG("processing line: %s", node_nt->ptr);
#endif

    _ds_sparse_clear(previous_tokens);

    line = node_nt->ptr;
    token = strtok_r (line, ":", &ptrptr);
    if (token && token[0] != 32 && token[0] != 9 && !strstr (token, " "))
    {
      multiline = 0;
      strlcpy (heading, token, 128);
      _ds_sparse_clear(previous_tokens);
    } else {
      multiline = 1;
    }

#ifdef VERBOSE
    LOGDEBUG ("Reading '%s' header from: '%s'", heading, line);
#endif

    if (CTX->flags & DSF_WHITELIST) {
      /* Use the entire From: line for auto-whitelisting */

      if (!strcmp(heading, "From")) {
        char wl[256];
        char *fromline = line + 5;
        unsigned long long whitelist_token;

        if (fromline[0] == 32) 
          fromline++;
        snprintf(wl, sizeof(wl), "%s*%s", heading, fromline);
        whitelist_token = _ds_getcrc64(wl); 
        ds_diction_touch(diction, whitelist_token, wl, 0);
        diction->whitelist_token = whitelist_token;
      }
    }

    /* Received headers use a different set of delimiters to preserve things
       like ip addresses */

    token = strtok_r ((multiline) ? line : NULL, SPARSE_DELIMITERS_HEADING, &ptrptr);

    while (token)
    {
      l = strlen(token);

      if (l > 0 && l < 50)
      {
#ifdef VERBOSE
        LOGDEBUG ("Processing '%s' token in '%s' header", token, heading);
#endif
        _ds_map_header_token (CTX, token, previous_tokens, diction, heading, bitpattern);
      }

      token = strtok_r (NULL, SPARSE_DELIMITERS_HEADING, &ptrptr);
    }

    for(i=0;i<SPARSE_WINDOW_SIZE;i++) {
      _ds_map_header_token(CTX, NULL, previous_tokens, diction, heading, bitpattern);
    }

    _ds_sparse_clear(previous_tokens);
    node_nt = c_nt_next (header, &c_nt);
  }
  nt_destroy (header);

  /*
   * Body Tokenization
   */

#ifdef VERBOSE
  LOGDEBUG("parsing message body");
#endif

  token = strtok_r (body, SPARSE_DELIMITERS, &ptrptr);
  while (token != NULL)
  {
    l = strlen (token);
    if (l > 0 && l < 50)
    {
#ifdef VERBOSE
        LOGDEBUG ("Processing body token '%s'", token);
#endif

      /* Process "current" token */
      _ds_map_body_token (CTX, token, previous_tokens, diction, bitpattern);
    }
    token = strtok_r (NULL, SPARSE_DELIMITERS, &ptrptr);
  }

  for(i=0;i<SPARSE_WINDOW_SIZE;i++) {
    _ds_map_body_token(CTX, NULL, previous_tokens, diction, bitpattern);
  }

  _ds_sparse_clear(previous_tokens);

  free(bitpattern);

#ifdef VERBOSE
  LOGDEBUG("Finished tokenizing (sparse) message");
#endif

  return 0;
}
Exemple #11
0
//这个函数停止重叠网络, 当接收到信号SIGINT时, 该函数被调用.
//它关闭所有的连接, 释放所有动态分配的内存.
void son_stop() {
    nt_destroy(nt);
}
Exemple #12
0
buffer * read_sock(THREAD_CTX *TTX, AGENT_CTX *ATX) {
    buffer *message;
    int body = 0, line = 1;
    char *buf;
    int strip = _ds_match_attribute(agent_config, "Broken", "lineStripping");
    int parseto = _ds_match_attribute(agent_config, "ParseToHeaders", "on");

    message = buffer_create(NULL);
    if (message == NULL) {
        LOG(LOG_CRIT, ERR_MEM_ALLOC);
        return NULL;
    }

    if (_ds_match_attribute(agent_config, "DataSource", "document")) {
        buffer_cat(message, ".\n\n");
        body = 1;
    }

    while ((buf = daemon_getline(TTX, 300))!=NULL) {
        chomp(buf);

        if (!strcmp(buf, ".")) {
            free(buf);
            return message;
        }

        if (strip) {
            size_t len = strlen(buf);

            while (len>1 && buf[len-2]==13) {
                buf[len-2] = buf[len-1];
                buf[len-1] = 0;
                len--;
            }
        }

        if (line > 1 || strncmp (buf, "From QUARANTINE", 15))
        {
            if (parseto) {
                if (buf[0] == 0)
                    body = 1;
                if (!body && !strncasecmp(buf, "To: ", 4))
                    process_parseto(ATX, buf);
            }

            if (buffer_cat (message, buf) || buffer_cat(message, "\n"))
            {
                LOG (LOG_CRIT, ERR_MEM_ALLOC);
                goto bail;
            }
        }

        /* Use the original user id if we are reversing a false positive */
        if (ATX->source         == DSS_ERROR      &&
                ATX->classification == DSR_ISINNOCENT &&
                ATX->operating_mode == DSM_PROCESS    &&
                !strncasecmp (buf, "X-DSPAM-User: ", 14))
        {
            char user[MAX_USERNAME_LENGTH];
            strlcpy (user, buf + 14, sizeof (user));
            chomp (user);
            nt_destroy (ATX->users);
            ATX->users = nt_create (NT_CHAR);
            if (ATX->users == NULL)
            {
                LOG(LOG_CRIT, ERR_MEM_ALLOC);
                goto bail;
            }
            nt_add (ATX->users, user);
        }

        free(buf);
        line++;
    }

    return NULL;

bail:
    buffer_destroy(message);
    return NULL;
}
Exemple #13
0
void *process_connection(void *ptr) {
    char *server_ident = _ds_read_attribute(agent_config, "ServerIdent");
    THREAD_CTX *TTX = (THREAD_CTX *) ptr;
    AGENT_CTX *ATX = NULL;
    char *input, *cmdline = NULL, *token, *ptrptr;
    buffer *message = NULL;
    char *parms=NULL, *p=NULL;
    int i, locked = -1, invalid = 0;
    int server_mode = SSM_DSPAM;
    char *argv[64];
    char buf[1024];
    int tries = 0;
    int argc = 0;
    FILE *fd = 0;

    if (_ds_read_attribute(agent_config, "ServerMode") &&
            !strcasecmp(_ds_read_attribute(agent_config, "ServerMode"), "standard"))
    {
        server_mode = SSM_STANDARD;
    }

    if (_ds_read_attribute(agent_config, "ServerMode") &&
            !strcasecmp(_ds_read_attribute(agent_config, "ServerMode"), "auto"))
    {
        server_mode = SSM_AUTO;
    }

    /* Initialize a file descriptor hook for dspam to use as stdout */

    fd = fdopen(TTX->sockfd, "w");
    if (!fd) {
        close(TTX->sockfd);
        goto CLOSE;
    }
    setbuf(fd, NULL);

    TTX->packet_buffer = buffer_create(NULL);
    if (TTX->packet_buffer == NULL)
        goto CLOSE;

    /*
     *  Send greeting banner
     *  in auto mode, we want to look like a regular LMTP server so we don't
     *  cause any compatibility problems. in dspam mode, we can change this.
     */

    snprintf(buf, sizeof(buf), "%d DSPAM %sLMTP %s %s",
             LMTP_GREETING,
             (server_mode == SSM_DSPAM) ? "D" : "",
             VERSION,
             (server_mode == SSM_DSPAM) ? "Authentication Required" : "Ready");
    if (send_socket(TTX, buf)<=0)
        goto CLOSE;

    TTX->authenticated = 0;

    /* LHLO */

    input = daemon_expect(TTX, "LHLO");
    if (input == NULL)
        goto CLOSE;
    if (server_mode == SSM_AUTO && input[4]) {
        char buff[128];

        /*
         *  Auto-detect the server mode based on whether or not the ident is
         *  assigned a password in dspam.conf
         */

        snprintf(buff, sizeof(buff), "ServerPass.%s", input + 5);
        chomp(buff);
        if (_ds_read_attribute(agent_config, buff))
            server_mode = SSM_DSPAM;
        else
            server_mode = SSM_STANDARD;
    }
    free(input);

    /* Advertise extensions */

    if (daemon_extension(TTX, (server_ident) ? server_ident :
                         "localhost.localdomain")<=0)
        goto CLOSE;

    if (daemon_extension(TTX, "PIPELINING")<=0)
        goto CLOSE;

    if (daemon_extension(TTX, "ENHANCEDSTATUSCODES")<=0)
        goto CLOSE;

    if (server_mode == SSM_DSPAM)
        if (daemon_extension(TTX, "DSPAMPROCESSMODE")<=0)
            goto CLOSE;

    if (daemon_extension(TTX, "8BITMIME")<=0)
        goto CLOSE;

    if (daemon_reply(TTX, LMTP_OK, "", "SIZE")<=0)
        goto CLOSE;

    /* Main protocol loop */

    while(1) {
        char processmode[256];
        parms = NULL;

        /* Configure a new agent context for each pass */

        ATX = calloc(1, sizeof(AGENT_CTX));
        if (ATX == NULL) {
            LOG(LOG_CRIT, ERR_MEM_ALLOC);
            daemon_reply(TTX, LMTP_TEMP_FAIL, "4.3.0", ERR_MEM_ALLOC);
            goto CLOSE;
        }

        if (initialize_atx(ATX)) {
            LOG(LOG_ERR, ERR_AGENT_INIT_ATX);
            daemon_reply(TTX, LMTP_BAD_CMD, "5.3.0", ERR_AGENT_INIT_ATX);
            goto CLOSE;
        }

        /* MAIL FROM (and authentication, if SSM_DSPAM) */

        processmode[0] = 0;
        while(!TTX->authenticated) {
            input = daemon_expect(TTX, "MAIL FROM");

            if (RSET(input))
                goto RSET;

            if (input == NULL)
                goto CLOSE;
            else {
                char *pass, *ident;
                chomp(input);

                if (server_mode == SSM_STANDARD) {
                    TTX->authenticated = 1;

                    ATX->mailfrom[0] = 0;
                    _ds_extract_address(ATX->mailfrom, input, sizeof(ATX->mailfrom));

                    if (daemon_reply(TTX, LMTP_OK, "2.1.0", "OK")<=0) {
                        free(input);
                        goto CLOSE;
                    }
                } else {
                    char id[256];
                    pass = ident = NULL;
                    id[0] = 0;
                    if (!_ds_extract_address(id, input, sizeof(id))) {
                        pass = strtok_r(id, "@", &ptrptr);
                        ident = strtok_r(NULL, "@", &ptrptr);
                    }

                    if (pass && ident) {
                        char *serverpass;
                        char *ptr, *ptr2, *ptr3;

                        snprintf(buf, sizeof(buf), "ServerPass.%s", ident);
                        serverpass = _ds_read_attribute(agent_config, buf);

                        snprintf(buf, sizeof(buf), "ServerPass.%s", ident);
                        if (serverpass && !strcmp(pass, serverpass)) {
                            TTX->authenticated = 1;

                            /* Parse PROCESSMODE service tag */

                            ptr = strstr(input, "DSPAMPROCESSMODE=\"");
                            if (ptr) {
                                char *mode;
                                int i;
                                ptr2 = strchr(ptr, '"')+1;
                                mode = ptr2;
                                while((ptr3 = strstr(ptr2, "\\\"")))
                                    ptr2 = ptr3+2;
                                ptr3 = strchr(ptr2+2, '"');
                                if (ptr3)
                                    ptr3[0] = 0;
                                strlcpy(processmode, mode, sizeof(processmode));

                                ptr = processmode;
                                for(i=0; ptr[i]; i++) {
                                    if (ptr[i] == '\\' && ptr[i+1] == '"') {
                                        strcpy(ptr+i, ptr+i+1);
                                    }
                                }
                                LOGDEBUG("process mode: '%s'", processmode);
                            }

                            if (daemon_reply(TTX, LMTP_OK, "2.1.0", "OK")<=0) {
                                free(input);
                                goto CLOSE;
                            }
                        }
                    }
                }

                free(input);
                if (!TTX->authenticated) {
                    LOGDEBUG("fd %d authentication failure.", TTX->sockfd);

                    if (daemon_reply(TTX, LMTP_AUTH_ERROR, "5.1.0",
                                     "Authentication Required")<=0)
                    {
                        free(input);
                        goto CLOSE;
                    }

                    tries++;
                    if (tries>=3) {
                        struct timeval tv;
                        tv.tv_sec = 5;
                        tv.tv_usec = 0;
                        select(0, NULL, NULL, NULL, &tv);
                        goto CLOSE;
                    }
                }
            }
        }

        /* MAIL FROM response */

        snprintf(buf, sizeof(buf), "%d OK", LMTP_OK);

        argc = 1;
        argv[0] = "dspam";
        argv[1] = 0;

        /* Load open-LMTP configuration parameters */

        if (server_mode == SSM_STANDARD) {
            parms = _ds_read_attribute(agent_config, "ServerParameters");
            if (parms) {
                p = strdup(parms);
                if (p) {
                    token = strtok_r(p, " ", &ptrptr);
                    while(token != NULL && argc<63) {
                        argv[argc] = token;
                        argc++;
                        argv[argc] = 0;
                        token = strtok_r(NULL, " ", &ptrptr);
                    }
                }
            }
        }

        /* RCPT TO */

        while(ATX->users->items == 0 || invalid) {
            free(cmdline);
            cmdline = daemon_getline(TTX, 300);

            while(cmdline &&
                    (!strncasecmp(cmdline, "RCPT TO:", 8) ||
                     !strncasecmp(cmdline, "RSET", 4)))
            {
                char username[256];
                char *at = NULL;

                if (!strncasecmp(cmdline, "RSET", 4)) {
                    snprintf(buf, sizeof(buf), "%d OK", LMTP_OK);
                    if (send_socket(TTX, buf)<=0)
                        goto CLOSE;
                    goto RSET;
                }

                if (_ds_extract_address(username, cmdline, sizeof(username)) ||
                        username[0] == 0 || username[0] == '-' || username[0] == '@')
                {
                    if ((server_mode == SSM_DSPAM) || (server_mode == SSM_STANDARD && _ds_validate_address(username) == 0)) {
                        daemon_reply(TTX, LMTP_BAD_CMD, "5.1.2", ERR_LMTP_BAD_RCPT);
                        goto GETCMD;
                    }
                }

                if (_ds_match_attribute(agent_config, "Broken", "case"))
                    lc(username, username);

                /* Chop of @.* from the recipient */
                if (_ds_match_attribute(agent_config, "StripRcptDomain", "on")) {
                    at = strchr(username, '@');
                    if (at != NULL)
                        *at = '\0';
                }

                if (server_mode == SSM_DSPAM) {
                    nt_add(ATX->users, username);
                }
                else {
                    if (!parms || !strstr(parms, "--user "))
                        nt_add(ATX->users, username);

                    if (!ATX->recipients) {
                        ATX->recipients = nt_create(NT_CHAR);
                        if (ATX->recipients == NULL) {
                            LOG(LOG_CRIT, ERR_MEM_ALLOC);
                            goto CLOSE;
                        }
                    }
                    if (at != NULL)
                        *at = '@'; /* always add complete address (user@domain) to recipient list */
                    nt_add(ATX->recipients, username);
                }

                if (daemon_reply(TTX, LMTP_OK, "2.1.5", "OK")<=0)
                    goto CLOSE;

GETCMD:
                free(cmdline);
                cmdline = daemon_getline(TTX, 300);
            }

            if (cmdline == NULL)
                goto CLOSE;

            if (!strncasecmp(cmdline, "RSET", 4)) {
                snprintf(buf, sizeof(buf), "%d OK", LMTP_OK);
                if (send_socket(TTX, buf)<=0)
                    goto CLOSE;
                goto RSET;
            }

            if (!strncasecmp(cmdline, "quit", 4)) {
                daemon_reply(TTX, LMTP_OK, "2.0.0", "OK");
                goto CLOSE;
            }

            /* Parse DSPAMPROCESSMODE input and set up process arguments */

            if (server_mode == SSM_DSPAM && processmode[0] != 0) {
                token = strtok_r(processmode, " ", &ptrptr);
                while(token != NULL && argc<63) {
                    argv[argc] = token;
                    argc++;
                    argv[argc] = 0;
                    token = strtok_r(NULL, " ", &ptrptr);
                }
            }

            invalid = 0;
            if (process_arguments(ATX, argc, argv) || apply_defaults(ATX))
            {
                LOG(LOG_ERR, ERR_AGENT_INIT_ATX);
                daemon_reply(TTX, LMTP_NO_RCPT, "5.1.0", ERR_AGENT_INIT_ATX);
                invalid = 1;
            } else if (ATX->users->items == 0) {
                daemon_reply(TTX, LMTP_NO_RCPT, "5.1.1", ERR_AGENT_USER_UNDEFINED);
            }
        }

        ATX->sockfd = fd;
        ATX->sockfd_output = 0;

        /* Something's terribly misconfigured */

        if (check_configuration(ATX)) {
            LOG(LOG_ERR, ERR_AGENT_MISCONFIGURED);
            daemon_reply(TTX, LMTP_BAD_CMD, "5.3.5", ERR_AGENT_MISCONFIGURED);
            goto CLOSE;
        }

        /* DATA */

        if (cmdline != NULL) {
            if (strncasecmp(cmdline, "DATA", 4)) {
                if (daemon_reply(TTX, LMTP_BAD_CMD, "5.0.0", "Need DATA Here")<0)
                    goto CLOSE;
                input = daemon_expect(TTX, "DATA");
                if (input == NULL)
                    goto CLOSE;
                if (RSET(input))
                    goto RSET;
            }
        }

        if (daemon_reply(TTX, LMTP_DATA, "", INFO_LMTP_DATA)<=0)
            goto CLOSE;

        /*
         *  Read in the message from a DATA. I personally like to just hang up on
         *  a client stupid enough to pass in a NULL message for DATA, but you're
         *  welcome to do whatever you want.
         */

        message = read_sock(TTX, ATX);
        if (message == NULL || message->data == NULL || message->used == 0) {
            daemon_reply(TTX, LMTP_FAILURE, "5.2.0", ERR_LMTP_MSG_NULL);
            goto CLOSE;
        }

        /*
         *  Lock a database handle. We currently use the modulus of the socket
         *  id against the number of database connections in the cache. This
         *  seems to work rather well, as we would need to lock up the entire
         *  cache to wrap back around. And if we do wrap back around, that means
         *  we're busy enough to justify spinning on the current lock (vs. seeking
         *  out a free handle, which there likely are none).
         */

        i = (TTX->sockfd % TTX->DTX->connection_cache);
        LOGDEBUG("using database handle id %d", i);
        if (TTX->DTX->flags & DRF_RWLOCK) {
            if (ATX->operating_mode == DSM_CLASSIFY ||
                    ATX->training_mode == DST_NOTRAIN   ||
                    (ATX->training_mode == DST_TOE && ATX->classification == DSR_NONE))
            {
                pthread_rwlock_rdlock(&TTX->DTX->connections[i]->rwlock);
            } else {
                pthread_rwlock_wrlock(&TTX->DTX->connections[i]->rwlock);
            }
        } else {
            pthread_mutex_lock(&TTX->DTX->connections[i]->lock);
        }
        LOGDEBUG("handle locked");
        ATX->dbh = TTX->DTX->connections[i]->dbh;
        locked = i;

        /* Process the message by tying back into the agent functions */

        ATX->results = nt_create(NT_PTR);
        if (ATX->results == NULL) {
            LOG(LOG_CRIT, ERR_MEM_ALLOC);
            goto CLOSE;
        }
        process_users(ATX, message);

        /*
         *  Unlock the database handle as soon as we're done. We also need to
         *  refresh our handle index with a new handle if for some reason we
         *  had to re-establish a dewedged connection.
         */

        if (TTX->DTX->connections[locked]->dbh != ATX->dbh)
            TTX->DTX->connections[locked]->dbh = ATX->dbh;

        if (TTX->DTX->flags & DRF_RWLOCK) {
            pthread_rwlock_unlock(&TTX->DTX->connections[locked]->rwlock);
        } else {
            pthread_mutex_unlock(&TTX->DTX->connections[locked]->lock);
        }
        locked = -1;

        /* Send a terminating '.' if --stdout in 'dspam' mode */

        if (ATX->sockfd_output) {
            if (send_socket(TTX, ".")<=0)
                goto CLOSE;

            /* Otherwise, produce standard delivery results */

        } else {
            struct nt_node *node_nt, *node_res = NULL;
            struct nt_c c_nt;
            if (ATX->recipients)
                node_nt = c_nt_first(ATX->recipients, &c_nt);
            else
                node_nt = c_nt_first(ATX->users, &c_nt);

            if (ATX->results)
                node_res = ATX->results->first;

            while(node_res && node_nt != NULL) {
                agent_result_t result = (agent_result_t) node_res->ptr;

                if (result != NULL && result->exitcode == ERC_SUCCESS)
                {
                    if (server_mode == SSM_DSPAM) {
                        snprintf(buf, sizeof(buf),
                                 "%d 2.6.0 <%s> Message accepted for delivery: %s",
                                 LMTP_OK, (char *) node_nt->ptr,
                                 (result->classification == DSR_ISSPAM) ? "SPAM" : "INNOCENT");
                    } else {
                        snprintf(buf, sizeof(buf),
                                 "%d 2.6.0 <%s> Message accepted for delivery",
                                 LMTP_OK, (char *) node_nt->ptr);
                    }
                }
                else
                {
                    if (result != NULL && result->exitcode == ERC_PERMANENT_DELIVERY) {
                        snprintf(buf, sizeof(buf), "%d 5.3.0 <%s> %s",
                                 LMTP_FAILURE, (char *) node_nt->ptr,
                                 (result->text[0]) ? result->text : "Permanent error occured");
                    } else {
                        if (result != NULL && result->text[0]) {
                            snprintf(buf, sizeof(buf),
                                     "%d 4.3.0 <%s> %s",
                                     LMTP_TEMP_FAIL, (char *) node_nt->ptr, result->text);
                        } else {
                            snprintf(buf, sizeof(buf),
                                     "%d 4.3.0 <%s> Error occured during %s",
                                     LMTP_TEMP_FAIL, (char *) node_nt->ptr,
                                     (result != NULL && result->exitcode == ERC_DELIVERY) ? "delivery" : "processing");
                        }
                    }
                }

                if (send_socket(TTX, buf)<=0)
                    goto CLOSE;
                if (ATX->recipients)
                    node_nt = c_nt_next(ATX->recipients, &c_nt);
                else
                    node_nt = c_nt_next(ATX->users, &c_nt);
                if (node_res)
                    node_res = node_res->next;
            }
        }

        /* Cleanup and get ready for another message */

RSET:
        fflush(fd);

        buffer_destroy(message);
        message = NULL;
        if (ATX != NULL) {
            nt_destroy(ATX->users);
            nt_destroy(ATX->recipients);
            nt_destroy(ATX->results);
            free(ATX);
            ATX = NULL;
            free(cmdline);
            cmdline = NULL;
            TTX->authenticated = 0;
            /* argc = 0; */
        }

        free(p);
        p = NULL;

    } /* while(1) */

    /* Close connection and return */

CLOSE:
    if (locked>=0)
        pthread_mutex_unlock(&TTX->DTX->connections[locked]->lock);
    if (fd)
        fclose(fd);
    buffer_destroy(TTX->packet_buffer);
    if (message)
        buffer_destroy(message);
    if (ATX != NULL) {
        nt_destroy(ATX->users);
        nt_destroy(ATX->recipients);
        nt_destroy(ATX->results);
    }
    free(ATX);
    free(cmdline);
    free(TTX);
    decrement_thread_count();
    pthread_exit(0);
    return 0;
}
Exemple #14
0
int
main (int argc, char *argv[])
{
  AGENT_CTX ATX;
  int exitcode = EXIT_SUCCESS;
  buffer *message = NULL;       /* input Message */
  int agent_init = 0;		/* agent is initialized */

  setbuf (stdout, NULL);	/* unbuffered output */
#ifdef DEBUG
  DO_DEBUG = 0;
#endif

  srand ((long) time << (long) getpid());
  umask (006);

#ifndef DAEMON
  LOG(LOG_ERR, ERR_DAEMON_NO_SUPPORT);
  exit(EXIT_FAILURE);
#endif

  /* Read dspam.conf into global config structure (ds_config_t) */

  agent_config = read_config(NULL);
  if (!agent_config) {
    LOG(LOG_ERR, ERR_AGENT_READ_CONFIG);
    exitcode = EXIT_FAILURE;
    goto BAIL;
  }

  if (!_ds_read_attribute(agent_config, "Home")) {
    LOG(LOG_ERR, ERR_AGENT_DSPAM_HOME);
    exitcode = EXIT_FAILURE;
    goto BAIL;
  }

  /* Set up agent context to define behavior of processor */

  if (initialize_atx(&ATX)) {
    LOG(LOG_ERR, ERR_AGENT_INIT_ATX);
    exitcode = EXIT_FAILURE;
    goto BAIL;
  } else {
    agent_init = 1;
  }

  if (process_arguments(&ATX, argc, argv)) {
    LOG(LOG_ERR, ERR_AGENT_INIT_ATX);
    exitcode = EXIT_FAILURE;
    goto BAIL;
  }

  if (apply_defaults(&ATX)) {
    LOG(LOG_ERR, ERR_AGENT_INIT_ATX);
    exitcode = EXIT_FAILURE;
    goto BAIL;
  }

  if (check_configuration(&ATX)) {
    LOG(LOG_ERR, ERR_AGENT_MISCONFIGURED);
    exitcode = EXIT_FAILURE;
    goto BAIL;
  }

  /* Read the message in and apply ParseTo services */

  message = read_stdin(&ATX);
  if (message == NULL) {
    exitcode = EXIT_FAILURE;
    goto BAIL;
  }

  if (ATX.users->items == 0)
  {
    LOG (LOG_ERR, ERR_AGENT_USER_UNDEFINED);
    fprintf (stderr, "%s\n", SYNTAX);
    exitcode = EXIT_FAILURE;
    goto BAIL;
  }

  /* Perform client-based processing */

#ifdef DAEMON
  if (_ds_read_attribute(agent_config, "ClientIdent") &&
      (_ds_read_attribute(agent_config, "ClientHost") ||
       _ds_read_attribute(agent_config, "ServerDomainSocketPath")))
  {
    exitcode = client_process(&ATX, message);
  } else {
    LOG(LOG_ERR, ERR_CLIENT_INVALID_CONFIG);
    exitcode = EINVAL;
  }
#endif

BAIL:

  if (message)
    buffer_destroy(message);

  if (agent_init)
    nt_destroy(ATX.users);

  if (agent_config)
    _ds_destroy_config(agent_config);

  exit (exitcode);
}
Exemple #15
0
int
main (int argc, char *argv[])
{
  DSPAM_CTX *CTX = NULL, *CTX2;
  char *user;
  int do_sigs   = 0;
  int do_probs  = 0;
  int do_unused = 0;
  int age_sigs   = 14;
  int age_probs  = 30;
  int age_unused[4] = { 90, 30, 15, 15 };
  int i, help = 0;
  struct nt *users = NULL;
  struct nt_node *node = NULL;
#ifndef _WIN32
#ifdef TRUSTED_USER_SECURITY
  struct passwd *p = getpwuid (getuid ());

#endif
#endif

 /* Read dspam.conf */
                                                                                
  agent_config = read_config(NULL);
  if (!agent_config) {
    LOG(LOG_ERR, ERR_AGENT_READ_CONFIG);
    fprintf (stderr, ERR_AGENT_READ_CONFIG "\n");
    exit(EXIT_FAILURE);
  }
                                                                                
  if (!_ds_read_attribute(agent_config, "Home")) {
    LOG(LOG_ERR, ERR_AGENT_DSPAM_HOME);
    fprintf (stderr, ERR_AGENT_DSPAM_HOME "\n");
    goto bail;
  }
                                                                                
  if (libdspam_init(_ds_read_attribute(agent_config, "StorageDriver")) != 0) {
    LOG(LOG_ERR, ERR_DRV_INIT);
    fprintf (stderr, ERR_DRV_INIT "\n");
    _ds_destroy_config(agent_config);
    exit(EXIT_FAILURE);
  }

#ifndef _WIN32
#ifdef TRUSTED_USER_SECURITY
  if (!_ds_match_attribute(agent_config, "Trust", p->pw_name) && p->pw_uid) {
    fprintf(stderr, ERR_TRUSTED_MODE "\n");
    goto bail;
  }
#endif
#endif

  for(i=0;i<argc;i++) {
                                                                                
    if (!strncmp (argv[i], "--profile=", 10))
    {
      if (!_ds_match_attribute(agent_config, "Profile", argv[i]+10)) {
        LOG(LOG_ERR, ERR_AGENT_NO_SUCH_PROFILE, argv[i]+10);
        fprintf (stderr, ERR_AGENT_NO_SUCH_PROFILE "\n", argv[i]+10);
        goto bail;
      } else {
        _ds_overwrite_attribute(agent_config, "DefaultProfile", argv[i]+10);
      }
      break;
    }
  }

#ifdef DEBUG
  fprintf (stdout, "dspam_clean starting\n");
#endif

  if (_ds_read_attribute(agent_config, "PurgeSignatures") &&
      !_ds_match_attribute(agent_config, "PurgeSignatures", "off"))  
  {
    do_sigs = 1;
    age_sigs = atoi(_ds_read_attribute(agent_config, "PurgeSignatures"));
  }
  
  if (_ds_read_attribute(agent_config, "PurgeNeutral") &&
      !_ds_match_attribute(agent_config, "PurgeNeutral", "off"))
  {
    do_probs = 1;
    age_probs = atoi(_ds_read_attribute(agent_config, "PurgeNeutral"));
  }

  if (_ds_read_attribute(agent_config, "PurgeUnused") &&
      !_ds_match_attribute(agent_config, "PurgeUnused", "off"))
  {
    int i;

    do_unused = 1;
    age_unused[0] = atoi(_ds_read_attribute(agent_config, "PurgeUnused"));
    age_unused[1] = atoi(_ds_read_attribute(agent_config, "PurgeHapaxes"));
    age_unused[2] = atoi(_ds_read_attribute(agent_config, "PurgeHits1S"));
    age_unused[3] = atoi(_ds_read_attribute(agent_config, "PurgeHits1I"));

    for(i=0;i<4;i++) 
      if (age_unused[i]==0)
        do_unused = 0;
  }

  users = nt_create(NT_CHAR);
  if (users == NULL) {
    fprintf(stderr, "%s", ERR_MEM_ALLOC);
    goto bail;
  }

  for(i=0;i<argc;i++) {
    if (!strncmp(argv[i], "-p", 2)) {
      do_probs = 1;
      if (strlen(argv[i])>2)
        age_probs = atoi(argv[i]+2);
    }
    else if (!strncmp(argv[i], "-s", 2)) {
      do_sigs = 1;
      if (strlen(argv[i])>2)
        age_sigs = atoi(argv[i]+2);
    } else if (!strncmp(argv[i], "-u", 2)) {
      do_unused = 1;
      if (strlen(argv[i])>2) {
        char *c = strdup(argv[i]+2);
        char *d = strtok(c, ",");
        int j = 0;
        while(d != NULL && j<4) {
          age_unused[j] = atoi(d);
          j++;
          d = strtok(NULL, ",");
        }
        free(c);
      }
    }
    else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help"))
      help = 1;
    else if (i>0) 
      nt_add(users, argv[i]);
  }

  if (help || (!do_probs && !do_sigs && !do_unused)) {
    fprintf(stderr, "%s", CLEANSYNTAX);
    _ds_destroy_config(agent_config);
    nt_destroy(users);
    libdspam_shutdown();
    if (help) {
      exit(EXIT_SUCCESS);
    }
    exit(EXIT_FAILURE);
  }
      
  open_ctx = open_mtx = NULL;

  signal (SIGINT, dieout);
  signal (SIGPIPE, dieout);
  signal (SIGTERM, dieout);

  dspam_init_driver (NULL);

  if (users->items == 0) {
    CTX = dspam_create (NULL, NULL, _ds_read_attribute(agent_config, "Home"), DSM_TOOLS, 0);
    open_ctx = CTX;
    if (CTX == NULL)
    {
      fprintf (stderr, "Could not initialize context: %s\n", strerror (errno));
      dspam_shutdown_driver (NULL);
      goto bail;
    }

    set_libdspam_attributes(CTX);
    if (dspam_attach(CTX, NULL)) {
      LOG (LOG_WARNING, "unable to attach dspam context");
      fprintf (stderr, "Unable to attach DSPAM context\n");
      goto bail;
    }

    user = _ds_get_nextuser (CTX);
  } else {
    node = users->first;
    if (node != NULL)
      user = node->ptr;
    else 
      goto bail;
  }

  while (user != NULL)
  {
#ifdef DEBUG
    printf ("PROCESSING USER: %s\n", user);
#endif
    CTX2 = dspam_create (user, NULL,  _ds_read_attribute(agent_config, "Home"), DSM_TOOLS, 0);
    open_mtx = CTX2;

    if (CTX2 == NULL)
    {
      fprintf (stderr, "Could not initialize context: %s\n",
               strerror (errno));
      return EUNKNOWN;
    }

    set_libdspam_attributes(CTX2);
    if (dspam_attach(CTX2, NULL)) {
      LOG (LOG_WARNING, "unable to attach dspam context");
      fprintf (stderr, "Unable to attach DSPAM context\n");
      goto bail;
    }

    if (do_sigs)
      process_sigs(CTX2, age_sigs);
    if (do_probs)
      process_probs(CTX2, age_probs);
    if (do_unused)
      process_unused(CTX2, age_unused[0], age_unused[1], age_unused[2], age_unused[3]);
    dspam_destroy (CTX2);
    open_mtx = NULL;

    if (users->items == 0) {
      user = _ds_get_nextuser (CTX);
    } else {
      if (node == NULL || node->next == NULL) {
        node = NULL;
        user = NULL;
      } else {
        node = node->next;
        user = node->ptr;
      }
    }
  }

  if (users->items == 0) {
    dspam_destroy (CTX);
    open_ctx = NULL;
  }

  dspam_shutdown_driver (NULL);
  _ds_destroy_config(agent_config);
  nt_destroy(users);
  libdspam_shutdown();
  exit (EXIT_SUCCESS);

bail:

  if (open_ctx)
    dspam_destroy(open_ctx);
  if (open_mtx)
    dspam_destroy(open_mtx);
  _ds_destroy_config(agent_config);
  nt_destroy(users);
  libdspam_shutdown();
  exit(EXIT_FAILURE);
}