source: npl/mailserver/dspam/dspam-3.10.2/src/agent_shared.c @ c5c522c

gcc484ntopperl-5.22
Last change on this file since c5c522c was c5c522c, checked in by Edwin Eefting <edwin@datux.nl>, 8 years ago

initial commit, transferred from cleaned syn3 svn tree

  • Property mode set to 100644
File size: 22.2 KB
Line 
1/* $Id: agent_shared.c,v 1.86 2011/07/11 22:05:48 sbajic Exp $ */
2
3/*
4 DSPAM
5 COPYRIGHT (C) 2002-2012 DSPAM PROJECT
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU Affero General Public License as
9 published by the Free Software Foundation, either version 3 of the
10 License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU Affero General Public License for more details.
16
17 You should have received a copy of the GNU Affero General Public License
18 along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
20*/
21
22/*
23 * agent_shared.c - shared agent-based components
24 *
25 * DESCRIPTION
26 *   agent-based components shared between the full dspam agent (dspam)
27 *   and the lightweight client agent (dspamc)
28 */
29
30#ifdef HAVE_CONFIG_H
31#include <auto-config.h>
32#endif
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <ctype.h>
38#include <errno.h>
39#ifdef HAVE_UNISTD_H
40#include <unistd.h>
41#include <pwd.h>
42#endif
43#include <sys/types.h>
44#include <signal.h>
45#include <sys/stat.h>
46#ifdef _WIN32
47#include <io.h>
48#include <process.h>
49#define WIDEXITED(x) 1
50#define WEXITSTATUS(x) (x)
51#include <windows.h>
52#else
53#include <sys/wait.h>
54#include <sys/param.h>
55#endif
56#include "util.h"
57#include "read_config.h"
58#ifdef DAEMON
59#include "daemon.h"
60#include "dspam.h"
61#endif
62
63#ifdef TIME_WITH_SYS_TIME
64#   include <sys/time.h>
65#   include <time.h>
66#else
67#   ifdef HAVE_SYS_TIME_H
68#       include <sys/time.h>
69#   else
70#       include <time.h>
71#   endif
72#endif
73
74#include "agent_shared.h"
75#include "language.h"
76#include "buffer.h"
77
78char * __pw_name = NULL;
79uid_t  __pw_uid;
80
81/*
82 * initialize_atx(AGENT_CTX *)
83 *
84 * DESCRIPTION
85 *  initializes an existing agent context
86 *
87 * INPUT ARGUMENTS
88 *  ATX    agent context to initialize
89 *
90 * RETURN VALUES
91 *   returns 0 on success
92 */
93
94int initialize_atx(AGENT_CTX *ATX) {
95  memset(ATX, 0, sizeof(AGENT_CTX));
96  ATX->training_buffer = 0;
97  ATX->train_pristine  = 0;
98  ATX->classification  = DSR_NONE;
99  ATX->source          = DSS_NONE;
100  ATX->operating_mode  = DSM_PROCESS;
101  ATX->fork            = 1;
102  ATX->users           = nt_create (NT_CHAR);
103
104  if (ATX->users == NULL) {
105    LOG(LOG_CRIT, ERR_MEM_ALLOC);
106    return EUNKNOWN;
107  }
108
109#ifdef TRUSTED_USER_SECURITY
110  if (!__pw_name) {
111    LOG(LOG_ERR, ERR_AGENT_RUNTIME_USER);
112    exit(EXIT_FAILURE);
113  }
114
115  LOGDEBUG("checking trusted user list for %s(%d)", __pw_name, __pw_uid);
116
117  if (__pw_uid == 0)
118    ATX->trusted = 1;
119  else
120    ATX->trusted = _ds_match_attribute(agent_config, "Trust", __pw_name);
121
122  if (!ATX->trusted)
123    nt_add (ATX->users, __pw_name);
124#endif
125
126  return 0;
127}
128
129/*
130 * process_arguments(AGENT_CTX *, int argc, char *argv[])
131 *
132 * DESCRIPTION
133 *   master commandline argument process loop
134 *
135 * INPUT ARGUMENTS
136 *      ATX     agent context
137 *      argc    number of arguments provided
138 *      argv    array of arguments
139 *
140 * RETURN VALUES
141 *  returns 0 on success, EINVAL when invalid options specified
142 */
143
144int process_arguments(AGENT_CTX *ATX, int argc, char **argv) {
145  int flag_u = 0, flag_r = 0;
146  int client = (_ds_read_attribute(agent_config, "ClientHost") != NULL);
147  char *ptrptr;
148  int i;
149
150#ifdef DEBUG
151  ATX->debug_args[0] = 0;
152#endif
153  ATX->client_args[0] = 0;
154
155  for (i=0; i<argc; i++)
156  {
157
158#ifdef DEBUG
159    strlcat (ATX->debug_args, argv[i], sizeof (ATX->debug_args));
160    strlcat (ATX->debug_args, " ", sizeof (ATX->debug_args));
161#endif
162
163    /* Terminate user/rcpt lists */
164
165    if ((flag_u || flag_r) &&
166        (argv[i][0] == '-' || argv[i][0] == 0 || !strcmp(argv[i], "--")))
167    {
168       flag_u = flag_r = 0;
169       if (!strcmp(argv[i], "--"))
170         continue;
171    }
172
173    if (!strcmp (argv[i], "--user")) {
174      flag_u = 1;
175      continue;
176    }
177
178    if (!strcmp (argv[i], "--rcpt-to"))
179    {
180      if (!ATX->recipients) {
181        ATX->recipients = nt_create(NT_CHAR);
182        if (ATX->recipients == NULL) {
183          LOG(LOG_CRIT, ERR_MEM_ALLOC);
184          return EUNKNOWN;
185        }
186      }
187      flag_r = 1;
188      continue;
189    }
190
191    /* Build arg list to pass to server (when in client/server mode) */
192 
193    if (client && !flag_u && !flag_r && i>0)
194    {
195      if (argv[i][0] == 0)
196        strlcat(ATX->client_args, "\"", sizeof(ATX->client_args));
197      strlcat (ATX->client_args, argv[i], sizeof(ATX->client_args));
198      if (argv[i][0] == 0)
199        strlcat(ATX->client_args, "\"", sizeof(ATX->client_args));
200      strlcat (ATX->client_args, " ", sizeof(ATX->client_args));
201    }
202
203    if (!strcmp (argv[i], "--debug"))
204    {
205#ifdef DEBUG
206      if (DO_DEBUG == 0)
207        DO_DEBUG = 1;
208#endif
209      continue;
210    }
211
212#if defined(DAEMON) && !defined(_DSPAMC_H)
213
214    if (!strcmp (argv[i], "--client")) {
215      ATX->client_mode = 1;
216      continue;
217    }
218
219#ifdef TRUSTED_USER_SECURITY
220    if (!strcmp (argv[i], "--daemon") && ATX->trusted)
221#else
222    if (!strcmp (argv[i], "--daemon"))
223#endif
224    {
225      ATX->operating_mode = DSM_DAEMON;
226      continue;
227    }
228#endif
229 
230    if (!strcmp (argv[i], "--nofork")) {
231      ATX->fork = 0;
232      continue;
233    }
234
235    if (!strncmp (argv[i], "--mode=", 7))
236    {
237      char *mode = strchr(argv[i], '=')+1;
238      if (process_mode(ATX, mode))
239        return EINVAL;
240      ATX->flags |= DAF_FIXED_TR_MODE;
241      continue;
242    }
243
244    /* Build RCPT TO list */
245
246    if (flag_r)
247    {
248      if (argv[i] != NULL && strlen (argv[i]) < MAX_USERNAME_LENGTH)
249      {
250        char user[MAX_USERNAME_LENGTH];
251
252        if (_ds_match_attribute(agent_config, "Broken", "case"))
253          lc(user, argv[i]);
254        else
255          strcpy(user, argv[i]);
256
257#ifdef TRUSTED_USER_SECURITY
258        if (!ATX->trusted && strcmp(user, __pw_name)) {
259          LOG(LOG_ERR, ERR_TRUSTED_USER, __pw_uid, __pw_name);
260          return EINVAL;
261        }
262
263        if (ATX->trusted) {
264#endif
265          if (_ds_validate_address(user) == 1) {
266            nt_add (ATX->recipients, user);
267          } else {
268            LOG(LOG_ERR, "Invalid email address: %s", user);
269            return EINVAL;
270          }
271#ifdef TRUSTED_USER_SECURITY
272        }
273#endif
274      }
275      continue;
276    }
277
278    /* Build process user list */
279
280    if (flag_u)
281    {
282      if (argv[i] != NULL && strlen (argv[i]) < MAX_USERNAME_LENGTH)
283      {
284        if (strstr(argv[i], "../") != NULL || strstr(argv[i], "..\\") != NULL) {
285          LOG(LOG_ERR, "Illegal username ('../' or '..\\' not allowed in username)");
286          return EINVAL;
287        } else {
288          char user[MAX_USERNAME_LENGTH];
289
290          if (_ds_match_attribute(agent_config, "Broken", "case"))
291            lc(user, argv[i]);
292          else
293            strcpy(user, argv[i]);
294
295#ifdef TRUSTED_USER_SECURITY
296          if (!ATX->trusted && strcmp(user, __pw_name)) {
297            LOG(LOG_ERR, ERR_TRUSTED_USER, __pw_uid, __pw_name);
298            return EINVAL;
299          }
300
301          if (ATX->trusted)
302#endif
303            nt_add (ATX->users, user);
304        }
305      }
306      continue;
307    }
308
309    if (!strncmp (argv[i], "--mail-from=", 12))
310    {
311      strlcpy(ATX->mailfrom, strchr(argv[i], '=')+1, sizeof(ATX->mailfrom));
312      LOGDEBUG("MAIL FROM: %s", ATX->mailfrom);
313      continue;
314    } 
315
316    if (!strncmp (argv[i], "--profile=", 10))
317    {
318#ifdef TRUSTED_USER_SECURITY
319      if (!ATX->trusted) {
320        LOG(LOG_ERR, ERR_TRUSTED_PRIV, "--profile",
321            __pw_uid, __pw_name);
322        return EINVAL;
323      }
324#endif
325      if (!_ds_match_attribute(agent_config, "Profile", argv[i]+10)) {
326        LOG(LOG_ERR,ERR_AGENT_NO_SUCH_PROFILE, argv[i]+10);
327        return EINVAL;
328      } else {
329        _ds_overwrite_attribute(agent_config, "DefaultProfile", argv[i]+10);
330      }
331      continue;
332    }
333
334    if (!strncmp (argv[i], "--signature=", 12))
335    {
336      strlcpy(ATX->signature, strchr(argv[i], '=')+1, sizeof(ATX->signature));
337      continue;
338    }
339
340    if (!strncmp (argv[i], "--class=", 8))
341    {
342      char *ptr = strchr(argv[i], '=')+1;
343      char *spam = _ds_read_attribute(agent_config, "ClassAliasSpam");
344      char *nonspam = _ds_read_attribute(agent_config, "ClassAliasNonspam");
345      if (!strcmp(ptr, "spam") || (spam && !strcmp(ptr, spam)))
346      {
347        ATX->classification = DSR_ISSPAM;
348      } else if (!strcmp(ptr, "innocent") || !strcmp(ptr, "nonspam") ||
349                 (nonspam && !strcmp(ptr, nonspam)))
350      {
351        ATX->classification = DSR_ISINNOCENT;
352      }
353      else
354      {
355        LOG(LOG_ERR, ERR_AGENT_NO_SUCH_CLASS, ptr);
356        return EINVAL;
357      }
358      continue;
359    }
360
361    if (!strncmp (argv[i], "--source=", 9))
362    {
363      char *ptr = strchr(argv[i], '=')+1;
364
365      if (!strcmp(ptr, "corpus"))
366        ATX->source = DSS_CORPUS;
367      else if (!strcmp(ptr, "inoculation"))
368        ATX->source = DSS_INOCULATION;
369      else if (!strcmp(ptr, "error"))
370        ATX->source = DSS_ERROR;
371      else
372      {
373        LOG(LOG_ERR, ERR_AGENT_NO_SUCH_SOURCE, ptr);
374        return EINVAL;
375      }
376      continue;
377    }
378
379    if (!strcmp (argv[i], "--classify"))
380    {
381      ATX->operating_mode = DSM_CLASSIFY;
382      ATX->training_mode = DST_NOTRAIN;
383      continue;
384    }
385
386    if (!strcmp (argv[i], "--process"))
387    {
388      ATX->operating_mode = DSM_PROCESS;
389      continue;
390    }
391
392    if (!strncmp (argv[i], "--deliver=", 10))
393    {
394      char *dup = strdup(strchr(argv[i], '=')+1);
395      char *ptr;
396      if (dup == NULL) {
397        LOG(LOG_CRIT, ERR_MEM_ALLOC);
398        return EUNKNOWN;
399      }
400
401      ptr = strtok_r(dup, ",", &ptrptr);
402      while(ptr != NULL) {
403        if (!strcmp(ptr, "stdout")) {
404          ATX->flags |= DAF_DELIVER_SPAM;
405          ATX->flags |= DAF_DELIVER_INNOCENT;
406          ATX->flags |= DAF_STDOUT;
407        }
408        else if (!strcmp(ptr, "spam"))
409          ATX->flags |= DAF_DELIVER_SPAM;
410        else if (!strcmp(ptr, "innocent") || !strcmp(ptr, "nonspam"))
411          ATX->flags |= DAF_DELIVER_INNOCENT;
412        else if (!strcmp(ptr, "summary"))
413          ATX->flags |= DAF_SUMMARY;
414        else
415        {
416          LOG(LOG_ERR, ERR_AGENT_NO_SUCH_DELIVER, ptr);
417          free(dup);
418          return EINVAL;
419        }
420     
421        ptr = strtok_r(NULL, ",", &ptrptr);
422      }
423      free(dup);
424      continue;
425    }
426
427    if (!strncmp (argv[i], "--feature=", 10))
428    {
429      ATX->feature = 1;
430      process_features(ATX, strchr(argv[i], '=')+1);
431      continue;
432    }
433
434    if (!strcmp (argv[i], "--stdout"))
435    {
436      ATX->flags |= DAF_STDOUT;
437      continue;
438    }
439
440    if (!strcmp (argv[i], "--help"))
441    {
442      fprintf (stderr, "%s\n", SYNTAX);
443      exit(EXIT_SUCCESS);
444    }
445
446    if (!strcmp (argv[i], "--version"))
447    {
448      printf ("\nDSPAM Anti-Spam Suite %s (agent/library)\n\n", VERSION);
449      printf ("Copyright (C) 2002-2012 DSPAM Project\n");
450      printf ("http://dspam.sourceforge.net.\n\n");
451      printf ("DSPAM may be copied only under the terms of the GNU Affero General Public\n");
452      printf ("License, a copy of which can be found with the DSPAM distribution kit.\n\n");
453#ifdef TRUSTED_USER_SECURITY
454      if (ATX->trusted) {
455#endif
456        printf("Configuration parameters: %s\n\n", CONFIGURE_ARGS);
457#ifdef TRUSTED_USER_SECURITY
458      }
459#endif
460      exit (EXIT_SUCCESS);
461    }
462
463    /* Append all unknown arguments as mailer args */
464
465    if (i>0
466#ifdef TRUSTED_USER_SECURITY
467        && ATX->trusted
468#endif
469    )
470    {
471      if (argv[i][0] == 0)
472        strlcat (ATX->mailer_args, "\"\"", sizeof (ATX->mailer_args));
473      else
474        strlcat (ATX->mailer_args, argv[i], sizeof (ATX->mailer_args));
475      strlcat (ATX->mailer_args, " ", sizeof (ATX->mailer_args));
476    }
477  }
478 
479  return 0;
480}
481
482
483/*
484 * process_features(AGENT_CTX *, const char *)
485 *
486 * DESCRIPTION
487 *   convert --feature= stdin into agent context values
488 *
489 * INPUT ARGUMENTS
490 *      ATX     agent context
491 *      in      remainder of --feature= stdin
492 *
493 * RETURN VALUES
494 *   returns 0 on success, EINVAL when invalid options specified
495 *   
496 */
497
498int process_features(AGENT_CTX *ATX, const char *in) {
499  char *ptr, *dup, *ptrptr;
500  int ret = 0;
501
502  if (!in || in[0]==0)
503    return 0;
504
505  dup = strdup(in);
506  if (dup == NULL) {
507    LOG(LOG_CRIT, ERR_MEM_ALLOC);
508    return EUNKNOWN;
509  }
510
511  ptr = strtok_r(dup, ",", &ptrptr);
512  while(ptr != NULL) {
513    if (!strncmp(ptr, "no",2))
514      ATX->flags |= DAF_NOISE;
515    else if (!strncmp(ptr, "wh", 2))
516      ATX->flags |= DAF_WHITELIST;
517    else if (!strncmp(ptr, "tb=", 3)) {
518      ATX->training_buffer = atoi(strchr(ptr, '=')+1);
519
520      if (ATX->training_buffer < 0 || ATX->training_buffer > 10) {
521        LOG(LOG_ERR, ERR_AGENT_TB_INVALID);
522        ret = EINVAL;
523      }
524    }
525    else {
526      LOG(LOG_ERR, ERR_AGENT_NO_SUCH_FEATURE, ptr);
527      ret = EINVAL;
528    }
529
530    ptr = strtok_r(NULL, ",", &ptrptr);
531  }
532  free(dup);
533  return ret;
534}
535
536/*
537 * process_mode(AGENT_CTX *, const char *)
538 *
539 * DESCRIPTION
540 *   convert --mode= stdin into training mode
541 *
542 * INPUT ARGUMENTS
543 *      ATX     agent context
544 *      mode    remainder of --mode= stdin
545 *
546 * RETURN VALUES
547 *   returns 0 on success, EINVAL when invalid mode specified
548 */
549
550int process_mode(AGENT_CTX *ATX, const char *mode) {
551
552  if (!mode)
553    return EINVAL;
554
555  if (!strcmp(mode, "toe"))
556    ATX->training_mode = DST_TOE;
557  else if (!strcmp(mode, "teft"))
558    ATX->training_mode = DST_TEFT;
559  else if (!strcmp(mode, "tum"))
560    ATX->training_mode = DST_TUM;
561  else if (!strcmp(mode, "notrain"))
562    ATX->training_mode = DST_NOTRAIN;
563  else if (!strcmp(mode, "unlearn")) {
564    ATX->training_mode = DST_TEFT;
565    ATX->flags |= DAF_UNLEARN;
566  } else {
567    LOG(LOG_ERR, ERR_AGENT_TR_MODE_INVALID, mode);
568    return EINVAL;
569  }
570
571  return 0;
572}
573
574/*
575 * apply_defaults(AGENT_CTX *)
576 *
577 * DESCRIPTION
578 *   apply default values from dspam.conf in absence of other options
579 *
580 * INPUT ARGUMENTS
581 *      ATX     agent context
582 *
583 * RETURN VALUES
584 *   returns 0 on success
585 */
586
587int apply_defaults(AGENT_CTX *ATX) {
588
589  /* Training mode */
590
591  if (!(ATX->flags & DAF_FIXED_TR_MODE)) {
592    char *v = _ds_read_attribute(agent_config, "TrainingMode");
593    if (process_mode(ATX, v)) {
594      LOG(LOG_ERR, ERR_AGENT_NO_TR_MODE);
595      return EINVAL;
596    }
597  }
598
599  /* Default delivery agent */
600
601  if ( ! (ATX->flags & DAF_STDOUT)
602    && ATX->operating_mode != DSM_CLASSIFY
603    && (ATX->flags & DAF_DELIVER_INNOCENT || ATX->flags & DAF_DELIVER_SPAM))
604  {
605    char key[32];
606#ifdef TRUSTED_USER_SECURITY
607    if (!ATX->trusted)
608      strcpy(key, "UntrustedDeliveryAgent");
609    else
610#endif
611      strcpy(key, "TrustedDeliveryAgent");
612
613    char *value = _ds_read_attribute(agent_config, key);
614
615    if (value) {
616      char *trimmed_value = ALLTRIM(strdup(value));
617      if (trimmed_value && *trimmed_value == '\0') {
618        LOG(LOG_ERR, ERR_AGENT_NO_AGENT, key);
619        free(trimmed_value);
620        return EINVAL;
621      }
622      if (trimmed_value) free(trimmed_value);
623      char fmt[sizeof(ATX->mailer_args)];
624      snprintf(fmt, sizeof(fmt), "%s ", value);
625#ifdef TRUSTED_USER_SECURITY
626      if (ATX->trusted)
627#endif
628        strlcat(fmt, ATX->mailer_args, sizeof(fmt));
629      strcpy(ATX->mailer_args, fmt);
630    } else if (!_ds_read_attribute(agent_config, "DeliveryHost")) {
631      LOG(LOG_ERR, ERR_AGENT_NO_AGENT, key);
632      return EINVAL;
633    }
634  }
635
636  /* Default quarantine agent */
637
638  if (_ds_read_attribute(agent_config, "QuarantineAgent")) {
639    snprintf(ATX->spam_args, sizeof(ATX->spam_args), "%s ",
640             _ds_read_attribute(agent_config, "QuarantineAgent"));
641  } else {
642    LOGDEBUG("No QuarantineAgent option found. Using standard quarantine.");
643  }
644
645  /* Features */
646
647  if (!ATX->feature && _ds_find_attribute(agent_config, "Feature")) {
648    attribute_t attrib = _ds_find_attribute(agent_config, "Feature");
649
650    while(attrib != NULL) {
651      process_features(ATX, attrib->value);
652      attrib = attrib->next;
653    }
654  }
655
656  return 0;
657}
658
659/*
660 * check_configuration(AGENT_CTX *)
661 *
662 * DESCRIPTION
663 *   sanity-check agent configuration
664 *
665 * INPUT ARGUMENTS
666 *      ATX     agent context
667 *
668 * RETURN VALUES
669 *   returns 0 on success, EINVAL on invalid configuration
670*/
671
672int check_configuration(AGENT_CTX *ATX) {
673
674  if (ATX->classification != DSR_NONE && ATX->operating_mode == DSM_CLASSIFY)
675  {
676    LOG(LOG_ERR, ERR_AGENT_CLASSIFY_CLASS);
677    return EINVAL;
678  }
679
680  if (ATX->classification != DSR_NONE && ATX->source == DSS_NONE &&
681     !(ATX->flags & DAF_UNLEARN))
682  {
683    LOG(LOG_ERR, ERR_AGENT_NO_SOURCE);
684    return EINVAL;
685  }
686
687  if (ATX->source != DSS_NONE && ATX->classification == DSR_NONE)
688  {
689    LOG(LOG_ERR, ERR_AGENT_NO_CLASS);
690    return EINVAL;
691  }
692
693  if (ATX->operating_mode == DSM_NONE)
694  {
695    LOG(LOG_ERR, ERR_AGENT_NO_OP_MODE);
696    return EINVAL;
697  }
698
699  if (!_ds_match_attribute(agent_config, "ParseToHeaders", "on")) {
700
701    if (ATX->users->items == 0)
702    {
703      LOG(LOG_ERR, ERR_AGENT_USER_UNDEFINED);
704      return EINVAL;
705    }
706  }
707
708  return 0;
709}
710
711/*
712 * read_stdin(AGENT_CTX *)
713 *
714 * DESCRIPTION
715 *   read message from stdin and perform any inline configuration
716 *   (such as servicing 'ParseToHeaders' functions)
717 *
718 * INPUT ARGUMENTS
719 *      ATX     agent context
720 *
721 * RETURN VALUES
722 *   buffer structure containing the message
723 */
724
725buffer * read_stdin(AGENT_CTX *ATX) {
726  int body = 0, line = 1;
727  char buf[1024];
728  buffer *msg;
729
730  msg = buffer_create(NULL);
731  if (msg == NULL) {
732    LOG(LOG_CRIT, ERR_MEM_ALLOC);
733    return NULL;
734  }
735
736  if (_ds_match_attribute(agent_config, "DataSource", "document")) {
737    buffer_cat(msg, ": \n\n");
738    body = 1;
739  }
740
741  /* Only read the message if no signature was provided on commandline */
742
743  if (ATX->signature[0] == 0) {
744    while ((fgets (buf, sizeof (buf), stdin)) != NULL)
745    {
746      /* Strip CR/LFs for admittedly broken mail servers */
747
748      if (_ds_match_attribute(agent_config, "Broken", "lineStripping")) {
749        size_t len = strlen(buf);
750        while (len>1 && buf[len-2]==13) {
751          buf[len-2] = buf[len-1];
752          buf[len-1] = 0;
753          len--;
754        }
755      }
756
757      /*
758       *  Don't include first line of message if it's a quarantine header added
759       *  by dspam at time of quarantine
760       */
761
762      if (line==1 && !strncmp(buf, "From QUARANTINE", 15))
763        continue;
764
765      /*
766       *  Parse the "To" headers and adjust the operating mode and user when
767       *  an email is sent to spam-* or notspam-* address. Behavior must be
768       *  configured in dspam.conf
769       */
770
771      if (_ds_match_attribute(agent_config, "ParseToHeaders", "on")) {
772        if (buf[0] == 0)
773          body = 1;
774
775        if (!body && !strncasecmp(buf, "To: ", 4))
776          process_parseto(ATX, buf);
777      }
778
779      if (buffer_cat (msg, buf))
780      {
781        LOG (LOG_CRIT, ERR_MEM_ALLOC);
782        goto bail;
783      }
784 
785      /*
786       *  Use the original user id if we are reversing a false positive
787       *  (this is only necessary when using shared,managed groups
788       */
789
790      if (!strncasecmp (buf, "X-DSPAM-User: ", 14) &&
791          ATX->operating_mode == DSM_PROCESS    &&
792          ATX->classification == DSR_ISINNOCENT &&
793          ATX->source         == DSS_ERROR)
794      {
795        char user[MAX_USERNAME_LENGTH];
796        strlcpy (user, buf + 14, sizeof (user));
797        chomp (user);
798        nt_destroy (ATX->users);
799        ATX->users = nt_create (NT_CHAR);
800        if (ATX->users == NULL) {
801          LOG(LOG_CRIT, ERR_MEM_ALLOC);
802          goto bail;
803        }
804        LOGDEBUG("found username %s in X-DSPAM-User header", user);
805        nt_add (ATX->users, user);
806      }
807 
808      line++;
809    }
810  }
811
812  if (!msg->used)
813  {
814    if (ATX->signature[0] != 0) {
815      buffer_cat(msg, "\n\n");
816    }
817    else {
818      LOG (LOG_INFO, "empty message (no data received)");
819      goto bail;
820    }
821  }
822
823  return msg;
824
825bail:
826  LOGDEBUG("read_stdin() failure");
827  buffer_destroy(msg);
828  return NULL;
829}
830
831/*
832 * process_parseto(AGENT_CTX *, const char *)
833 *
834 * DESCRIPTION
835 *   processes the To: line of a message to provide parseto services
836 *
837 * INPUT ARGUMENTS
838 *      ATX     agent context
839 *      buf     To: line
840 *
841 * RETURN VALUES
842 *   returns 0 on success
843 */
844
845int process_parseto(AGENT_CTX *ATX, const char *buf) {
846  char *y = NULL;
847  char *x;
848  char *h = NULL;
849  char *buffer;
850  char *ptrptr;
851
852  if (!buf || strncmp(buf+2,":",1) != 0)
853    return EINVAL;
854
855  buffer = strdup (buf+3);
856  h = strtok_r (buffer, "\n", &ptrptr);
857  while (h != NULL) {
858    /* check for spam alias */
859    x = strstr(h, "<spam-");
860    if (!x) x = strstr(h, " spam-");
861    if (!x) x = strstr(h, "\tspam-");
862    if (!x) x = strstr(h, ",spam-");
863    if (!x) x = strstr(h, ":spam-");
864    if (x != NULL) {
865      y = strdup(x+6);
866      if (_ds_match_attribute(agent_config, "ChangeModeOnParse", "on")) {
867        ATX->classification = DSR_ISSPAM;
868        ATX->source = DSS_ERROR;
869      }
870    } else {
871      /* check for nonspam alias */
872      x = strstr(h, "<notspam-");
873      if (!x) x = strstr(h, " notspam-");
874      if (!x) x = strstr(h, "\tnotspam-");
875      if (!x) x = strstr(h, ",notspam-");
876      if (!x) x = strstr(h, ":notspam-");
877      if (x && strlen(x) >= 9) {
878        y = strdup(x+9);
879        if (_ds_match_attribute(agent_config, "ChangeModeOnParse", "on")) {
880          ATX->classification = DSR_ISINNOCENT;
881          ATX->source = DSS_ERROR;
882        }
883      }
884    }
885    /* do not continue if we found a spam/nonspam alias */
886    if (y) break;
887
888    /* get next line from 'To' header */
889    h = strtok_r (NULL, "\n", &ptrptr);
890    if (h && h[0] != 32 && h[0] != 9) {
891      /* we are not any more in the 'To' header */
892      break;
893    }
894  }
895
896  free (buffer);
897
898  if (y && (_ds_match_attribute(agent_config,
899                                "ChangeUserOnParse", "on") ||
900            _ds_match_attribute(agent_config,
901                               "ChangeUserOnParse", "full") ||
902            _ds_match_attribute(agent_config,
903                                "ChangeUserOnParse", "user")))
904  {
905    char *z;
906
907    if (_ds_match_attribute(agent_config,
908                            "ChangeUserOnParse", "full"))
909    {
910      z = strtok_r(y, ">, \t\r\n", &ptrptr);
911    } else {
912      if (strstr(x, "@"))
913        z = strtok_r(y, "@", &ptrptr);
914      else
915        z = NULL;
916    }
917
918    if (z) {
919      nt_destroy(ATX->users);
920      ATX->users = nt_create(NT_CHAR);
921      if (!ATX->users) {
922        LOG(LOG_CRIT, ERR_MEM_ALLOC);
923        return EUNKNOWN;
924      }
925      nt_add (ATX->users, z);
926    }
927  }
928
929  if (y) free(y);
930  return 0;
931}
932
933int
934init_pwent_cache(void)
935{
936  struct passwd *pwent;
937  pwent = getpwuid(getuid());
938  if (pwent == NULL) {
939    return 0;
940  }
941  else {
942     __pw_name = strdup(pwent->pw_name);
943     __pw_uid  = pwent->pw_uid;
944  }
945  return 1;
946}
Note: See TracBrowser for help on using the repository browser.