Main Page | Class List | Directories | File List | Class Members | File Members

spamc.c

Go to the documentation of this file.
00001 /* <@LICENSE>
00002  * Licensed to the Apache Software Foundation (ASF) under one or more
00003  * contributor license agreements.  See the NOTICE file distributed with
00004  * this work for additional information regarding copyright ownership.
00005  * The ASF licenses this file to you under the Apache License, Version 2.0
00006  * (the "License"); you may not use this file except in compliance with
00007  * the License.  You may obtain a copy of the License at:
00008  * 
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  * 
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  * </@LICENSE>
00017  */
00018 
00019 #include "config.h"
00020 #include "version.h"
00021 #include "libspamc.h"
00022 #include "utils.h"
00023 #include "spamc.h"
00024 
00025 #include <stdlib.h>
00026 #include <stdio.h>
00027 #include <string.h>
00028 
00029 #include "getopt.h"
00030 
00031 #ifdef _WIN32
00032 #include <io.h>
00033 #include <fcntl.h>
00034 #include <process.h>
00035 #else
00036 #include <syslog.h>
00037 #include <unistd.h>
00038 #include <netdb.h>
00039 #include <sys/types.h>
00040 #include <sys/socket.h>
00041 #include <netinet/in.h>
00042 #include <netinet/tcp.h>
00043 #include <arpa/inet.h>
00044 #endif
00045 
00046 #ifdef SPAMC_SSL
00047 #include <openssl/crypto.h>
00048 #ifndef OPENSSL_VERSION_TEXT
00049 #define OPENSSL_VERSION_TEXT "OpenSSL"
00050 #endif
00051 #endif
00052 
00053 #ifdef HAVE_SYSEXITS_H
00054 #include <sysexits.h>
00055 #endif
00056 #ifdef HAVE_ERRNO_H
00057 #include <errno.h>
00058 #endif
00059 #ifdef HAVE_SYS_ERRNO_H
00060 #include <sys/errno.h>
00061 #endif
00062 #ifdef HAVE_TIME_H
00063 #include <time.h>
00064 #endif
00065 #ifdef HAVE_SYS_TIME_H
00066 #include <sys/time.h>
00067 #endif
00068 #ifdef HAVE_SIGNAL_H
00069 #include <signal.h>
00070 #endif
00071 #ifdef HAVE_PWD_H
00072 #include <pwd.h>
00073 #endif
00074 
00075 /* SunOS 4.1.4 patch from Tom Lipkis <tal@pss.com> */
00076 #if (defined(__sun__) && defined(__sparc__) && !defined(__svr4__)) /* SunOS */ \
00077      || (defined(__sgi))  /* IRIX */ \
00078      || (defined(__osf__)) /* Digital UNIX */ \
00079      || (defined(hpux) || defined(__hpux)) /* HPUX */ \
00080      || (defined(__CYGWIN__))   /* CygWin, Win32 */
00081 
00082 extern int spamc_optind;
00083 extern char *spamc_optarg;
00084 
00085 #endif
00086 
00087 #ifdef _WIN32
00088 char *__progname = "spamc";
00089 #endif
00090 
00091 
00092 /* safe fallback defaults to on now - CRH */
00093 int flags = SPAMC_RAW_MODE | SPAMC_SAFE_FALLBACK;
00094 
00095 /* global to control whether we should exit(0)/exit(1) on ham/spam */
00096 int use_exit_code = 0;
00097 
00098 /* Aug 14, 2002 bj: global to hold -e command */
00099 char **exec_argv;
00100 
00101 static int timeout = 600;
00102 
00103 
00104 void
00105 check_malloc (void *ptr)
00106 {
00107     if(ptr == NULL) {
00108         libspamc_log(flags, LOG_ERR,
00109                       "Error allocating memory using malloc\n");
00110         /* this is really quite serious.  we can't do anything. die */
00111         exit(EX_OSERR);
00112     }
00113 }
00114 
00115 void
00116 print_version(void)
00117 {
00118     printf("%s version %s\n", "SpamAssassin Client", VERSION_STRING);
00119 #ifdef SPAMC_SSL
00120     printf("  compiled with SSL support (%s)\n", OPENSSL_VERSION_TEXT);
00121 #endif
00122 }
00123 
00124 static void
00125 usg(char *str)
00126 {
00127     printf("%s", str);
00128 }
00129 
00130 void
00131 print_usage(void)
00132 {
00133     print_version();
00134     usg("\n");
00135     usg("Usage: spamc [options] [-e command [args]] < message\n");
00136     usg("\n");
00137     usg("Options:\n");
00138 
00139     usg("  -d, --dest host[,host2]\n"
00140         "                      Specify one or more hosts to connect to.\n"
00141         "                      [default: localhost]\n");
00142     usg("  -H , --randomize    Randomize IP addresses for the looked-up\n"
00143         "                      hostname.\n");
00144     usg("  -p, --port port     Specify port for connection to spamd.\n"
00145         "                      [default: 783]\n");
00146 #ifdef SPAMC_SSL
00147     usg("  -S, --ssl           Use SSL to talk to spamd.\n");
00148 #endif
00149 #ifndef _WIN32
00150     usg("  -U, --socket path   Connect to spamd via UNIX domain sockets.\n");
00151 #endif
00152     usg("  -F, --config path   Use this configuration file.\n");
00153     usg("  -t, --timeout timeout\n"
00154         "                      Timeout in seconds for communications to\n"
00155         "                      spamd. [default: 600]\n");
00156     usg("  --connect-retries retries\n"
00157         "                      Try connecting to spamd this many times\n"
00158         "                      [default: 3]\n");
00159     usg("  --retry-sleep sleep Sleep for this time between attempts to\n"
00160         "                      connect to spamd, in seconds [default: 1]\n");
00161     usg("  -s, --max-size size Specify maximum message size, in bytes.\n"
00162         "                      [default: 500k]\n");
00163     usg("  -u, --username username\n"
00164         "                      User for spamd to process this message under.\n"
00165         "                      [default: current user]\n");
00166 
00167     usg("  -L, --learntype learntype\n"
00168         "                      Learn message as spam, ham or forget to\n"
00169         "                      forget or unlearn the message.\n");
00170 
00171     usg("  -C, --reporttype reporttype\n"
00172         "                      Report message to collaborative filtering\n"
00173         "                      databases.  Report type should be 'report' for\n"
00174         "                      spam or 'revoke' for ham.\n");
00175 
00176     usg("  -B, --bsmtp         Assume input is a single BSMTP-formatted\n"
00177         "                      message.\n");
00178 
00179     usg("  -c, --check         Just print the summary line and set an exit\n"
00180         "                      code.\n");
00181     usg("  -y, --tests         Just print the names of the tests hit.\n");
00182     usg("  -r, --full-spam     Print full report for messages identified as\n"
00183         "                      spam.\n");
00184     usg("  -R, --full          Print full report for all messages.\n");
00185     usg("  --headers           Rewrite only the message headers.\n");
00186     usg("  -E, --exitcode      Filter as normal, and set an exit code.\n");
00187 
00188     usg("  -x, --no-safe-fallback\n"
00189         "                      Don't fallback safely.\n");
00190     usg("  -l, --log-to-stderr Log errors and warnings to stderr.\n");
00191 #ifndef _WIN32
00192     usg("  -e, --pipe-to command [args]\n"
00193         "                      Pipe the output to the given command instead\n"
00194         "                      of stdout. This must be the last option.\n");
00195 #endif
00196     usg("  -h, --help          Print this help message and exit.\n");
00197     usg("  -V, --version       Print spamc version and exit.\n");
00198     usg("  -K                  Keepalive check of spamd.\n");
00199 #ifdef HAVE_ZLIB_H
00200     usg("  -z                  Compress mail message sent to spamd.\n");
00201 #endif
00202     usg("  -f                  (Now default, ignored.)\n");
00203 
00204     usg("\n");
00205 }
00206 
00214 int
00215 read_args(int argc, char **argv,
00216           int *max_size, char **username, int *extratype,
00217           struct transport *ptrn)
00218 {
00219 #ifndef _WIN32
00220     const char *opts = "-BcrRd:e:fyp:t:s:u:L:C:xzSHU:ElhVKF:0:1:2";
00221 #else
00222     const char *opts = "-BcrRd:fyp:t:s:u:L:C:xzSHElhVKF:0:1:2";
00223 #endif
00224     int opt;
00225     int ret = EX_OK;
00226     int longind = 1;
00227 
00228     static struct option longoptions[] = {
00229        { "dest" , required_argument, 0, 'd' },
00230        { "randomize", no_argument, 0, 'H' },
00231        { "port", required_argument, 0, 'p' },
00232        { "ssl", optional_argument, 0, 'S' },
00233        { "socket", required_argument, 0, 'U' },
00234        { "config", required_argument, 0, 'F' },
00235        { "timeout", required_argument, 0, 't' },
00236        { "connect-retries", required_argument, 0, 0 },
00237        { "retry-sleep", required_argument, 0, 1 },
00238        { "max-size", required_argument, 0, 's' },
00239        { "username", required_argument, 0, 'u' },
00240        { "learntype", required_argument, 0, 'L' },
00241        { "reporttype", required_argument, 0, 'C' },
00242        { "bsmtp", no_argument, 0, 'B' },
00243        { "check", no_argument, 0, 'c' },
00244        { "tests", no_argument, 0, 'y' },
00245        { "full-spam", no_argument, 0, 'r' },
00246        { "full", no_argument, 0, 'R' },
00247        { "headers", no_argument, 0, 2 },
00248        { "exitcode", no_argument, 0, 'E' },
00249        { "no-safe-fallback", no_argument, 0, 'x' },
00250        { "log-to-stderr", no_argument, 0, 'l' },
00251        { "pipe-to", required_argument, 0, 'e' },
00252        { "help", no_argument, 0, 'h' },
00253        { "version", no_argument, 0, 'V' },
00254        { "compress", no_argument, 0, 'z' },
00255        { 0, 0, 0, 0} /* last element _must_ be all zeroes */
00256     };
00257     
00258     while ((opt = spamc_getopt_long(argc, argv, opts, longoptions, 
00259                 &longind)) != -1)
00260     {
00261         switch (opt)
00262         {
00263             case 'B':
00264             {
00265                 flags = (flags & ~SPAMC_MODE_MASK) | SPAMC_BSMTP_MODE;
00266                 break;
00267             }
00268             case 'c':
00269             {
00270                 flags |= SPAMC_CHECK_ONLY;
00271                 break;
00272             }
00273             case 'd':
00274             {
00275                 ptrn->type = TRANSPORT_TCP;
00276                 ptrn->hostname = spamc_optarg;        /* fix the ptr to point to this string */
00277                 break;
00278             }
00279 #ifndef _WIN32
00280             case 'e':
00281             {
00282                 int i, j;
00283                 
00284                 /* Allocate memory for the necessary pointers needed to 
00285                  * store the remaining arguments.
00286                  */
00287                 exec_argv = malloc(sizeof(*exec_argv) * (argc - spamc_optind + 2));
00288                 if (exec_argv == NULL) {
00289                     return EX_OSERR;
00290                 }
00291                 
00292                 for (i = 0, j = spamc_optind - 1; j < argc; i++, j++) {
00293                     exec_argv[i] = argv[j];
00294                 }
00295                 exec_argv[i] = NULL;
00296                 
00297                 return EX_OK;
00298             }
00299 #endif
00300             case 'f':
00301             {
00302                 /* obsolete, backwards compat */
00303                 break;
00304             }
00305             case 'K':
00306             {
00307                 flags |= SPAMC_PING;
00308                 break;
00309             }
00310             case 'l':
00311             {
00312                 flags |= SPAMC_LOG_TO_STDERR;
00313                 break;
00314             }
00315             case 'H':
00316             {
00317                 flags |= SPAMC_RANDOMIZE_HOSTS;
00318                 break;
00319             }
00320             case 'p':
00321             {
00322                 ptrn->port = (unsigned short)atoi(spamc_optarg);
00323                 break;
00324             }
00325             case 'r':
00326             {
00327                 flags |= SPAMC_REPORT_IFSPAM;
00328                 break;
00329             }
00330             case 'E':
00331             {
00332                 use_exit_code = 1;
00333                 break;
00334             }
00335             case 'R':
00336             {
00337                 flags |= SPAMC_REPORT;
00338                 break;
00339             }
00340             case 's':
00341             {
00342                 *max_size = atoi(spamc_optarg);
00343                 break;
00344             }
00345 #ifdef SPAMC_SSL
00346             case 'S':
00347             {
00348                 flags |= SPAMC_USE_SSL;
00349                 if (!spamc_optarg || (strcmp(spamc_optarg,"sslv23") == 0)) {
00350                   /* this is the default */
00351                 }
00352                 else if (strcmp(spamc_optarg,"sslv2") == 0) {
00353                   flags |= SPAMC_SSLV2;
00354                 }
00355                 else if (strcmp(spamc_optarg,"sslv3") == 0) {
00356                   flags |= SPAMC_SSLV3;
00357                 }
00358                 else if (strcmp(spamc_optarg,"tlsv1") == 0) {
00359                   flags |= (SPAMC_SSLV2 | SPAMC_SSLV3);
00360                 }
00361                 else {
00362                     libspamc_log(flags, LOG_ERR, "Please specifiy a legal ssl version (%s)", spamc_optarg);
00363                     ret = EX_USAGE;
00364                 }
00365                 break;
00366             }
00367 #endif
00368             case 't':
00369             {
00370                 timeout = atoi(spamc_optarg);
00371                 break;
00372             }
00373             case 'u':
00374             {
00375                 *username = spamc_optarg;
00376                 break;
00377             }
00378             case 'L':
00379             {
00380                 flags |= SPAMC_LEARN;
00381                 if (strcmp(spamc_optarg,"spam") == 0) {
00382                     *extratype = 0;
00383                 }
00384                 else if (strcmp(spamc_optarg,"ham") == 0) {
00385                     *extratype = 1;
00386                 }
00387                 else if (strcmp(spamc_optarg,"forget") == 0) {
00388                     *extratype = 2;
00389                 }
00390                 else {
00391                     libspamc_log(flags, LOG_ERR, "Please specifiy a legal learn type");
00392                     ret = EX_USAGE;
00393                 }
00394                 break;
00395             }
00396         case 'C':
00397             {
00398                 flags |= SPAMC_REPORT_MSG;
00399                 if (strcmp(spamc_optarg,"report") == 0) {
00400                     *extratype = 0;
00401                 }
00402                 else if (strcmp(spamc_optarg,"revoke") == 0) {
00403                     *extratype = 1;
00404                 }
00405                 else {
00406                     libspamc_log(flags, LOG_ERR, "Please specifiy a legal report type");
00407                     ret = EX_USAGE;
00408                 }
00409                 break;
00410             }
00411 #ifndef _WIN32
00412             case 'U':
00413             {
00414                 ptrn->type = TRANSPORT_UNIX;
00415                 ptrn->socketpath = spamc_optarg;
00416                 break;
00417             }
00418 #endif
00419             case 'x':
00420             {
00421                 flags &= (~SPAMC_SAFE_FALLBACK);
00422                 break;
00423             }
00424             case 'y':
00425             {
00426                 flags |= SPAMC_SYMBOLS;
00427                 break;
00428             }
00429             
00430             case '?':
00431             case ':':
00432             {
00433                 libspamc_log(flags, LOG_ERR, "invalid usage");
00434                 ret = EX_USAGE;
00435                 /* FALLTHROUGH */
00436             }
00437             case 'h':
00438             {
00439                 print_usage();
00440                 if (ret == EX_OK)
00441                     ret = EX_TEMPFAIL;
00442                 return(ret);
00443             }
00444             case 'V':
00445             {
00446                 print_version();
00447                 return(EX_TEMPFAIL);
00448             }
00449             case 'z':
00450             {
00451 #ifdef HAVE_ZLIB_H
00452                 flags |= SPAMC_USE_ZLIB;
00453 #else
00454                 libspamc_log(flags, LOG_ERR, "spamc -z support not available");
00455                 ret = EX_USAGE;
00456 #endif
00457                 break;
00458             }
00459             case 0:
00460             {
00461                 ptrn->connect_retries = atoi(spamc_optarg);
00462                 break;
00463             }
00464             case 1:
00465             {
00466                 ptrn->retry_sleep = atoi(spamc_optarg);
00467                 break;
00468             }
00469             case 2:
00470             {
00471                 flags |= SPAMC_HEADERS;
00472                 break;
00473             }
00474         }
00475     }
00476 
00477     if (*max_size > SPAMC_MAX_MESSAGE_LEN) {
00478         libspamc_log(flags, LOG_ERR, "-s parameter is beyond max of %d",
00479                         SPAMC_MAX_MESSAGE_LEN);
00480         ret = EX_USAGE;
00481     }
00482 
00483     /* learning action has to block some parameters */
00484     if (flags & SPAMC_LEARN) {
00485         if (flags & SPAMC_CHECK_ONLY) {
00486             libspamc_log(flags, LOG_ERR, "Learning excludes check only");
00487             ret = EX_USAGE;
00488         }
00489         if (flags & SPAMC_PING) {
00490             libspamc_log(flags, LOG_ERR, "Learning excludes ping");
00491             ret = EX_USAGE;
00492         }
00493         if (flags & SPAMC_REPORT_IFSPAM) {
00494             libspamc_log(flags, LOG_ERR, "Learning excludes report if spam");
00495             ret = EX_USAGE;
00496         }
00497         if (flags & SPAMC_REPORT) {
00498             libspamc_log(flags, LOG_ERR, "Learning excludes report");
00499             ret = EX_USAGE;
00500         }
00501         if (flags & SPAMC_SYMBOLS) {
00502             libspamc_log(flags, LOG_ERR, "Learning excludes symbols");
00503             ret = EX_USAGE;
00504         }
00505         if (flags & SPAMC_REPORT_MSG) {
00506             libspamc_log(flags, LOG_ERR, "Learning excludes reporting to collaborative filtering databases");
00507             ret = EX_USAGE;
00508         }
00509     }
00510     return ret;
00511 }
00512 
00513 /* combine_args() :: parses spamc.conf for options, and combines those
00514  * with options passed via command line
00515  *
00516  * lines beginning with # or blank lines are ignored
00517  *
00518  * returns EX_OK on success, EX_CONFIG on failure
00519  */
00520 int
00521 combine_args(char *config_file, int argc, char **argv,
00522              int *combo_argc, char **combo_argv)
00523 {
00524     FILE *config;
00525     char option[100];
00526     int i, count = 0;
00527     char *tok = NULL;
00528     int is_user_defined_p = 1;
00529 
00530     if (config_file == NULL) {
00531       config_file = CONFIG_FILE;
00532       is_user_defined_p = 0;
00533     }
00534 
00535     if((config = fopen(config_file, "r")) == NULL) {
00536         if (is_user_defined_p == 1) { /* if the config file was user defined we should issue an error */
00537             fprintf(stderr,"Failed to open config file: %s\n", config_file);
00538         }
00539         return EX_CONFIG;
00540     }
00541 
00542     while(!(feof(config)) && (fgets(option, 100, config))) {
00543 
00544         count++; /* increment the line counter */
00545 
00546         if(option[0] == '#' || option[0] == '\n') {
00547             continue;
00548         }
00549 
00550         tok = option;
00551         while((tok = strtok(tok, " ")) != NULL) {
00552        if(tok[0] == '\n')
00553           break;
00554             for(i=strlen(tok); i>0; i--) {
00555                 if(tok[i] == '\n')
00556                     tok[i] = '\0';
00557             }
00558             combo_argv[*combo_argc] = strdup(tok);
00559             check_malloc(combo_argv[*combo_argc]);
00560             /* TODO: leaked.  not a big deal since spamc exits quickly */
00561             tok = NULL;
00562             *combo_argc+=1;
00563         }
00564     }
00565 
00566     fclose(config);
00567 
00568     /* note: not starting at 0, that's the command name */
00569     for(i=1; i<argc; i++) {
00570         combo_argv[*combo_argc] = strdup(argv[i]);
00571         check_malloc(combo_argv[*combo_argc]);
00572         /* TODO: leaked.  not a big deal since spamc exits quickly */
00573         *combo_argc+=1;
00574     }
00575     return EX_OK;
00576 }
00577 
00578 void
00579 get_output_fd(int *fd)
00580 {
00581 #ifndef _WIN32
00582     int pipe_fds[2];
00583     pid_t pid;
00584 #endif
00585 
00586     if (*fd != -1)
00587         return;
00588     
00589     /* If we aren't told to feed our output to an external app, we simply
00590      * write to stdout.
00591      */
00592     if (exec_argv == NULL) {
00593         *fd = STDOUT_FILENO;
00594         return;
00595     }
00596     
00597 #ifndef _WIN32
00598     /* Create a pipe for communication between child and parent. */
00599     if (pipe(pipe_fds)) {
00600         libspamc_log(flags, LOG_ERR, "pipe creation failed: %m");
00601         exit(EX_OSERR);
00602     }
00603     
00604     pid = fork();
00605     if (pid < 0) {
00606         libspamc_log(flags, LOG_ERR, "fork failed: %m");
00607         exit(EX_OSERR);
00608     }
00609     else if (pid == 0) {
00610         /* This is the child process:
00611          * Normally you'd expect the parent process here, however that would
00612          * screw up an invoker waiting on the death of the parent. So instead,
00613          * we fork a child to feed the data and have the parent exec the new
00614          * program.
00615          */
00616         close(pipe_fds[0]);
00617         *fd = pipe_fds[1];
00618         return;
00619     }
00620     
00621     /* This is the parent process (see above) */
00622     close(pipe_fds[1]);
00623     if (dup2(pipe_fds[0], STDIN_FILENO)) {
00624         libspamc_log(flags, LOG_ERR, "redirection of stdin failed: %m");
00625         exit(EX_OSERR);
00626     }
00627     /* No point in leaving extra fds lying around. */
00628     close(pipe_fds[0]);
00629     
00630     /* Now execute the command specified. */
00631     execv(exec_argv[0], exec_argv);
00632     
00633     /* Whoa, something failed... */
00634     libspamc_log(flags, LOG_ERR, "exec failed: %m");
00635 #else
00636     libspamc_log(flags, LOG_CRIT, "THIS MUST NOT HAPPEN AS -e IS NOT SUPPORTED UNDER WINDOWS.");
00637 #endif
00638     exit(EX_OSERR);
00639 }
00640 
00641 
00652 int
00653 get_current_user(char **username)
00654 {
00655 #ifndef _WIN32
00656     struct passwd *curr_user;
00657 #endif
00658 
00659     if (*username != NULL) {
00660         *username = strdup(*username);
00661         if (username == NULL)
00662             goto fail;
00663         goto pass;
00664     }
00665 
00666 #ifndef _WIN32
00667     
00668     /* Get the passwd information for the effective uid spamc is running
00669      * under. Setting errno to zero is recommended in the manpage.
00670      */
00671     errno = 0;
00672     curr_user = getpwuid(geteuid());
00673     if (curr_user == NULL) {
00674         perror("getpwuid() failed");
00675         goto fail;
00676     }
00677     
00678     /* Since "curr_user" points to static library data, we don't wish to
00679      * risk some other part of the system overwriting it, so we copy the 
00680      * username to our own buffer -- then this won't arise as a problem.
00681      */
00682     *username = strdup(curr_user->pw_name);
00683     if (*username == NULL) {
00684         goto fail;
00685     }
00686 
00687 #endif
00688 
00689 pass:
00690     return EX_OK;
00691     
00692 fail:
00693     /* FIXME: The handling of SPAMC_CHECK_ONLY should probably be moved to 
00694      *        the end of main()
00695      */
00696     if (flags & SPAMC_CHECK_ONLY) {
00697         printf("0/0\n");
00698         return EX_NOTSPAM;
00699     }
00700     return EX_OSERR;
00701 }
00702 
00703 
00704 int
00705 main(int argc, char *argv[])
00706 {
00707     int max_size;
00708     char *username;
00709     struct transport trans;
00710     struct message m;
00711     int out_fd = -1;
00712     int result = EX_SOFTWARE;
00713     int ret = EX_SOFTWARE;
00714     int extratype = 0;
00715     int islearned = 0;
00716     int isreported = 0;
00717 
00718     /* these are to hold CLI and config options combined, to be passed
00719      * to read_args() */
00720     char *combo_argv[24];
00721     int combo_argc;
00722 
00723     int i;
00724     char *config_file = NULL;
00725 
00726     transport_init(&trans);
00727 
00728 #ifdef LIBSPAMC_UNIT_TESTS
00729     /* unit test support; divert execution.  will not return */
00730     do_libspamc_unit_tests();
00731 #endif
00732 
00733 #ifndef _WIN32
00734     openlog("spamc", LOG_CONS | LOG_PID, LOG_MAIL);
00735     signal(SIGPIPE, SIG_IGN);
00736 #endif
00737 
00738     /* set some defaults */
00739     max_size = 500 * 1024;
00740     username = NULL;
00741  
00742     combo_argc = 1;
00743     combo_argv[0] = strdup(argv[0]);
00744     check_malloc(combo_argv[0]);
00745     /* TODO: leaked.  not a big deal since spamc exits quickly */
00746  
00747     for(i=0; i<argc; i++) {
00748        if(strncmp(argv[i], "-F", 2) == 0) {
00749           config_file = argv[i+1];
00750           break;
00751        }
00752     }
00753  
00754     if((combine_args(config_file, argc, argv, &combo_argc, combo_argv)) == EX_OK)
00755     {
00756       /* Parse the combined arguments of command line and config file */
00757       if ((ret = read_args(combo_argc, combo_argv, &max_size, &username, 
00758                           &extratype, &trans)) != EX_OK)
00759       {
00760         if (ret == EX_TEMPFAIL)
00761          ret = EX_OK;
00762         goto finish;
00763       }
00764     }
00765     else {
00766       /* parse only command line arguments (default behaviour) */
00767       if((ret = read_args(argc, argv, &max_size, &username, 
00768                          &extratype, &trans)) != EX_OK)
00769       {
00770         if(ret == EX_TEMPFAIL)
00771          ret = EX_OK;
00772         goto finish;
00773       }
00774     }
00775  
00776     ret = get_current_user(&username);
00777     if (ret != EX_OK)
00778         goto finish;
00779         
00780     if ((flags & SPAMC_RANDOMIZE_HOSTS) != 0) {
00781         /* we don't need strong randomness; this is just so we pick
00782          * a random host for loadbalancing.
00783          */
00784         srand(getpid() ^ time(NULL));
00785     }
00786 
00787     /**********************************************************************
00788      * SET UP TRANSPORT
00789      *
00790      * This takes the user parameters and digs up what it can about how
00791      * we connect to the spam daemon. Mainly this involves lookup up the
00792      * hostname and getting the IP addresses to connect to.
00793      */
00794     m.type = MESSAGE_NONE;
00795     m.out = NULL;
00796     m.outbuf = NULL;
00797     m.raw = NULL;
00798     m.priv = NULL;
00799     m.max_len = max_size;
00800     m.timeout = timeout;
00801     m.is_spam = EX_NOHOST;      /* default err code if can't reach the daemon */
00802 #ifdef _WIN32
00803     setmode(STDIN_FILENO, O_BINARY);
00804     setmode(STDOUT_FILENO, O_BINARY);
00805 #endif
00806     ret = transport_setup(&trans, flags);
00807 
00808     if (ret == EX_OK) {
00809 
00810         ret = message_read(STDIN_FILENO, flags, &m);
00811 
00812         if (ret == EX_OK) {
00813 
00814             if (flags & SPAMC_LEARN) {
00815               int msg_class = 0;
00816               unsigned int tellflags = 0;
00817               unsigned int didtellflags = 0;
00818 
00819               if ((extratype == 0) || (extratype == 1)) {
00820                 if (extratype == 0) {
00821                   msg_class = SPAMC_MESSAGE_CLASS_SPAM;
00822                 }
00823                 else {
00824                   msg_class = SPAMC_MESSAGE_CLASS_HAM;
00825                 }
00826                 tellflags |= SPAMC_SET_LOCAL;
00827               }
00828               else {
00829                 tellflags |= SPAMC_REMOVE_LOCAL;
00830               }
00831 
00832               ret = message_tell(&trans, username, flags, &m, msg_class,
00833                                  tellflags, &didtellflags);
00834 
00835               if (ret == EX_OK) {
00836                 if ((extratype == 0) || (extratype == 1)) {
00837                   if (didtellflags & SPAMC_SET_LOCAL) {
00838                     islearned = 1;
00839                   }
00840                 }
00841                 else {
00842                   if (didtellflags & SPAMC_REMOVE_LOCAL) {
00843                     islearned = 1;
00844                   }
00845                 }
00846               }
00847             }
00848             else if (flags & SPAMC_REPORT_MSG) {
00849               int msg_class = 0;
00850               unsigned int tellflags = 0;
00851               unsigned int didtellflags = 0;
00852 
00853               if (extratype == 0) {
00854                 msg_class = SPAMC_MESSAGE_CLASS_SPAM;
00855                 tellflags |= SPAMC_SET_REMOTE;
00856                 tellflags |= SPAMC_SET_LOCAL;
00857               }
00858               else {
00859                 msg_class = SPAMC_MESSAGE_CLASS_HAM;
00860                 tellflags |= SPAMC_SET_LOCAL;
00861                 tellflags |= SPAMC_REMOVE_REMOTE;
00862               }
00863 
00864               ret = message_tell(&trans, username, flags, &m, msg_class,
00865                                  tellflags, &didtellflags);
00866 
00867               if (ret == EX_OK) {
00868                 if (extratype == 0) {
00869                   if (didtellflags & SPAMC_SET_REMOTE) {
00870                     isreported = 1;
00871                   }
00872                 }
00873                 else {
00874                   if (didtellflags & SPAMC_REMOVE_REMOTE) {
00875                     isreported = 1;
00876                   }
00877                 }
00878               }
00879             }
00880             else {
00881               ret = message_filter(&trans, username, flags, &m);
00882             }
00883 
00884             free(username); username = NULL;
00885             
00886             if (ret == EX_OK) {
00887 
00888                 get_output_fd(&out_fd);
00889 
00890                 if (flags & SPAMC_LEARN) {
00891                     if (islearned == 1) {
00892                         printf("Message successfully un/learned\n");
00893                     }
00894                     else {
00895                         printf("Message was already un/learned\n");
00896                     }
00897                     message_cleanup(&m);
00898                     goto finish;
00899                 }
00900                 else if (flags & SPAMC_REPORT_MSG) {
00901                     if (isreported == 1) {
00902                         printf("Message successfully reported/revoked\n");
00903                     }
00904                     else {
00905                         printf("Unable to report/revoke message\n");
00906                     }
00907                     message_cleanup(&m);
00908                     goto finish;
00909                 }
00910                 else if (message_write(out_fd, &m) >= 0) {
00911                     result = m.is_spam;
00912                     if ((flags & SPAMC_CHECK_ONLY) && result != EX_TOOBIG) {
00913                         message_cleanup(&m);
00914                         ret = result;
00915                     }
00916                     else {
00917                         message_cleanup(&m);
00918                         if (use_exit_code && result != EX_TOOBIG) {
00919                             ret = result;
00920                         }
00921                     }
00922                     goto finish;
00923                 }
00924             }
00925         }
00926     }
00927     free(username);
00928 
00929 /* FAIL: */
00930 #if 1
00931     result = m.is_spam;
00932     if (ret != EX_OK) {
00933         result = ret;
00934     }
00935 #endif
00936     if (flags & (SPAMC_LEARN|SPAMC_PING) ) {
00937         get_output_fd(&out_fd);
00938         message_cleanup(&m);
00939     }
00940     else {
00941         if (flags & (SPAMC_CHECK_ONLY | SPAMC_REPORT | SPAMC_REPORT_IFSPAM)) {
00942             get_output_fd(&out_fd);
00943             full_write(out_fd, 1, "0/0\n", 4);
00944         }
00945         else if (flags & SPAMC_SYMBOLS) {
00946             /* bug 4991: -y should only output a blank line on connection failure */
00947             get_output_fd(&out_fd);
00948             full_write(out_fd, 1, "\n", 1);
00949         }
00950         else {
00951             /* bug 5412: spamc -x should not output the message on error */
00952             if ((flags & SPAMC_SAFE_FALLBACK) || result == EX_TOOBIG) {
00953                 get_output_fd(&out_fd);
00954                 message_dump(STDIN_FILENO, out_fd, &m);
00955             }
00956             /* else, do NOT get_output_fd() (bug 5478) */
00957         }
00958 
00959         message_cleanup(&m);
00960         if (ret == EX_TOOBIG) {
00961             ret = EX_OK;    /* too big always means exit(0) -- bug 5412 */
00962         }
00963         else if (flags & SPAMC_SAFE_FALLBACK) {
00964             ret = EX_OK;
00965         }
00966         else if (use_exit_code) {
00967             ret = result;
00968         }
00969     }
00970     
00971 finish:
00972 #ifdef _WIN32
00973     WSACleanup();
00974 #endif
00975     return ret;
00976 }

© sourcejam.com 2005-2008