void cpool_init(struct optstruct *opts) { const struct optstruct *opt; int failed = 0; if(!(cp=calloc(sizeof(*cp), 1))) { logg("!Out of memory while initializing the connection pool"); return; } cp->local_cpe = NULL; if((opt = optget(opts, "ClamdSocket"))->enabled) { while(opt) { char *socktype = opt->strarg; if(addslot()) return; if(!strncasecmp(socktype, "unix:", 5)) { failed = cpool_addunix(socktype+5); } else if(!strncasecmp(socktype, "tcp:", 4)) { char *port = strrchr(socktype+4, ':'); if(port) { *port='\0'; port++; } failed = cpool_addtcp(socktype+4, port); } else { logg("!Failed to parse ClamdSocket directive '%s'\n", socktype); failed = 1; } if(failed) break; opt = opt->nextarg; } if(failed) { cpool_free(); return; } } if(!cp->entries) { logg("!No ClamdSocket specified\n"); cpool_free(); return; } quitting = 0; pthread_create(&probe_th, NULL, cpool_mon, NULL); srand(time(NULL)); }
static int addslot(void) { struct CP_ENTRY *cpe; if(!(cpe = realloc(cp->pool, (cp->entries + 1) * sizeof(struct CP_ENTRY)))) { logg("!Out of memory while initializing the connection pool\n"); cpool_free(); return 1; } if(cp->local_cpe) cp->local_cpe = (struct CP_ENTRY *)((char *)cp->local_cpe + ((char *)cpe - (char *)cp->pool)); memset(&cpe[cp->entries], 0, sizeof(*cpe)); cp->pool = cpe; cp->entries++; return 0; }
static int test_cpool(void) { test_start("cpool"); cpool_t p; cpool_init(&p, 1, 10240); for (int i = 1; i < 10240; i+=2) { int v = cpool_alloc(&p); test_assert(v >= 1 && v <= 10240); test_assert(cpool_check(&p, v) == false); } cpool_free(&p, 1); int v = cpool_alloc(&p); test_assert(v == 1); cpool_release(&p); return test_success(); }
int coat_free(coat_t *t, int id) { assert(t); if (cpool_check(&t->pool, id)) { // Free but should have been allocated. return -EBADF; } if (t->oat_delete) { cvector_item_t obj = coat_get(t, id); if (!obj) { // No such object. return -EBADF; } t->oat_delete(t, obj); } cvector_set(&t->table, id, (cvector_item_t) NULL); cpool_free(&t->pool, id); return 0; }
int coat_alloc(coat_t *t, uint32_t arg[COAT_ARGS], cvector_item_t *out_obj) { assert(t); // Allocate new ID. int id = cpool_alloc(&t->pool); if (!id || id == COAT_INVALID_ID) { goto error; } // Potentially expand ID table vector. while (cvector_count(&t->table) <= id) { if (t->oat_expand) { t->oat_expand(&t->table); continue; } // Defaults to adding NULL pointers to fill ID table. cvector_add(&t->table, (cvector_item_t) NULL); } cvector_item_t obj = cvector_get(&t->table, id); if (!obj && t->oat_create) { // Create object structure and store it. obj = t->oat_create(t, id, arg); if (!obj) { goto error; } cvector_set(&t->table, id, obj); } if (out_obj) { (*out_obj) = obj; } return id; error: if (id) cpool_free(&t->pool, id); return COAT_INVALID_ID; }
static void milter_exit(int sig) { const struct optstruct *opt; logg("*clamav-milter: milter_exit, signal %d\n", sig); #ifndef _WIN32 if((opt = optget(opts, "MilterSocket"))) { if(unlink(opt->strarg) == -1) logg("!Can't unlink the socket file %s\n", opt->strarg); else logg("Socket file removed.\n"); } #endif logg("clamav-milter: stopped\n"); optfree(opts); logg_close(); cpool_free(); localnets_free(); whitelist_free(); }
int main(int argc, char **argv) { char *my_socket, *pt; const struct optstruct *opt; struct optstruct *opts; time_t currtime; mode_t umsk; int ret; cl_initialize_crypto(); memset(&descr, 0, sizeof(struct smfiDesc)); descr.xxfi_name = "ClamAV"; /* filter name */ descr.xxfi_version = SMFI_VERSION; /* milter version */ descr.xxfi_flags = SMFIF_QUARANTINE; /* flags */ descr.xxfi_connect = clamfi_connect; /* connection info filter */ descr.xxfi_envfrom = clamfi_envfrom; /* envelope sender filter */ descr.xxfi_envrcpt = clamfi_envrcpt; /* envelope recipient filter */ descr.xxfi_header = clamfi_header; /* header filter */ descr.xxfi_body = clamfi_body; /* body block */ descr.xxfi_eom = clamfi_eom; /* end of message */ descr.xxfi_abort = clamfi_abort; /* message aborted */ opts = optparse(NULL, argc, argv, 1, OPT_MILTER, 0, NULL); if (!opts) { mprintf("!Can't parse command line options\n"); return 1; } if(optget(opts, "help")->enabled) { printf("Usage: %s [-c <config-file>]\n\n", argv[0]); printf(" --help -h Show this help\n"); printf(" --version -V Show version and exit\n"); printf(" --config-file <file> -c Read configuration from file\n\n"); optfree(opts); return 0; } if(opts->filename) { int x; for(x = 0; opts->filename[x]; x++) mprintf("^Ignoring option %s\n", opts->filename[x]); } if(optget(opts, "version")->enabled) { printf("clamav-milter %s\n", get_version()); optfree(opts); return 0; } pt = strdup(optget(opts, "config-file")->strarg); if (pt == NULL) { printf("Unable to allocate memory for config file\n"); return 1; } if((opts = optparse(pt, 0, NULL, 1, OPT_MILTER, 0, opts)) == NULL) { printf("%s: cannot parse config file %s\n", argv[0], pt); free(pt); return 1; } free(pt); if((opt = optget(opts, "Chroot"))->enabled) { if(chdir(opt->strarg) != 0) { logg("!Cannot change directory to %s\n", opt->strarg); return 1; } if(chroot(opt->strarg) != 0) { logg("!chroot to %s failed. Are you root?\n", opt->strarg); return 1; } } pt = optget(opts, "AddHeader")->strarg; if (strcasecmp(pt, "No")) { char myname[255]; if (((opt = optget(opts, "ReportHostname"))->enabled && strncpy(myname, opt->strarg, sizeof(myname))) || !gethostname(myname, sizeof(myname))) { myname[sizeof(myname)-1] = '\0'; snprintf(xvirushdr, sizeof(xvirushdr), "clamav-milter %s at %s", get_version(), myname); } else { snprintf(xvirushdr, sizeof(xvirushdr), "clamav-milter %s", get_version()); } xvirushdr[sizeof(xvirushdr)-1] = '\0'; descr.xxfi_flags |= SMFIF_ADDHDRS; if (strcasecmp(pt, "Add")) { /* Replace or Yes */ descr.xxfi_flags |= SMFIF_CHGHDRS; addxvirus = 1; } else { /* Add */ addxvirus = 2; } } if(!(my_socket = optget(opts, "MilterSocket")->strarg)) { logg("!Please configure the MilterSocket directive\n"); logg_close(); optfree(opts); return 1; } if(smfi_setconn(my_socket) == MI_FAILURE) { logg("!smfi_setconn failed\n"); logg_close(); optfree(opts); return 1; } if(smfi_register(descr) == MI_FAILURE) { logg("!smfi_register failed\n"); logg_close(); optfree(opts); return 1; } opt = optget(opts, "FixStaleSocket"); umsk = umask(0777); /* socket is created with 000 to avoid races */ if(smfi_opensocket(opt->enabled) == MI_FAILURE) { logg("!Failed to create socket %s\n", my_socket); logg_close(); optfree(opts); return 1; } umask(umsk); /* restore umask */ if(strncmp(my_socket, "inet:", 5) && strncmp(my_socket, "inet6:", 6)) { /* set group ownership and perms on the local socket */ char *sock_name = my_socket; mode_t sock_mode; if(!strncmp(my_socket, "unix:", 5)) sock_name += 5; if(!strncmp(my_socket, "local:", 6)) sock_name += 6; if(*my_socket == ':') sock_name ++; if(optget(opts, "MilterSocketGroup")->enabled) { char *gname = optget(opts, "MilterSocketGroup")->strarg, *end; gid_t sock_gid = strtol(gname, &end, 10); if(*end) { struct group *pgrp = getgrnam(gname); if(!pgrp) { logg("!Unknown group %s\n", gname); logg_close(); optfree(opts); return 1; } sock_gid = pgrp->gr_gid; } if(chown(sock_name, -1, sock_gid)) { logg("!Failed to change socket ownership to group %s\n", gname); logg_close(); optfree(opts); return 1; } } if ((opt = optget(opts, "User"))->enabled) { struct passwd *user; if ((user = getpwnam(opt->strarg)) == NULL) { logg("ERROR: Can't get information about user %s.\n", opt->strarg); logg_close(); optfree(opts); return 1; } if(chown(sock_name, user->pw_uid, -1)) { logg("!Failed to change socket ownership to user %s\n", user->pw_name); optfree(opts); logg_close(); return 1; } } if(optget(opts, "MilterSocketMode")->enabled) { char *end; sock_mode = strtol(optget(opts, "MilterSocketMode")->strarg, &end, 8); if(*end) { logg("!Invalid MilterSocketMode %s\n", optget(opts, "MilterSocketMode")->strarg); logg_close(); optfree(opts); return 1; } } else sock_mode = 0777 & ~umsk; if(chmod(sock_name, sock_mode & 0666)) { logg("!Cannot set milter socket permission to %s\n", optget(opts, "MilterSocketMode")->strarg); logg_close(); optfree(opts); return 1; } } if(geteuid() == 0 && (opt = optget(opts, "User"))->enabled) { struct passwd *user = NULL; if((user = getpwnam(opt->strarg)) == NULL) { fprintf(stderr, "ERROR: Can't get information about user %s.\n", opt->strarg); optfree(opts); return 1; } if(optget(opts, "AllowSupplementaryGroups")->enabled) { #ifdef HAVE_INITGROUPS if(initgroups(opt->strarg, user->pw_gid)) { fprintf(stderr, "ERROR: initgroups() failed.\n"); optfree(opts); return 1; } #else mprintf("!AllowSupplementaryGroups: initgroups() is not available, please disable AllowSupplementaryGroups\n"); optfree(opts); return 1; #endif } else { #ifdef HAVE_SETGROUPS if(setgroups(1, &user->pw_gid)) { fprintf(stderr, "ERROR: setgroups() failed.\n"); optfree(opts); return 1; } #endif } if(setgid(user->pw_gid)) { fprintf(stderr, "ERROR: setgid(%d) failed.\n", (int) user->pw_gid); optfree(opts); return 1; } if(setuid(user->pw_uid)) { fprintf(stderr, "ERROR: setuid(%d) failed.\n", (int) user->pw_uid); optfree(opts); return 1; } } logg_lock = !optget(opts, "LogFileUnlock")->enabled; logg_time = optget(opts, "LogTime")->enabled; logg_size = optget(opts, "LogFileMaxSize")->numarg; logg_verbose = mprintf_verbose = optget(opts, "LogVerbose")->enabled; if (logg_size) logg_rotate = optget(opts, "LogRotate")->enabled; if((opt = optget(opts, "LogFile"))->enabled) { logg_file = opt->strarg; if(!cli_is_abspath(logg_file)) { fprintf(stderr, "ERROR: LogFile requires full path.\n"); logg_close(); optfree(opts); return 1; } } else logg_file = NULL; #if defined(USE_SYSLOG) && !defined(C_AIX) if(optget(opts, "LogSyslog")->enabled) { int fac; opt = optget(opts, "LogFacility"); if((fac = logg_facility(opt->strarg)) == -1) { logg("!LogFacility: %s: No such facility.\n", opt->strarg); logg_close(); optfree(opts); return 1; } openlog("clamav-milter", LOG_PID, fac); logg_syslog = 1; } #endif time(&currtime); if(logg("#+++ Started at %s", ctime(&currtime))) { fprintf(stderr, "ERROR: Can't initialize the internal logger\n"); logg_close(); optfree(opts); return 1; } if((opt = optget(opts, "TemporaryDirectory"))->enabled) tempdir = opt->strarg; if(localnets_init(opts) || init_actions(opts)) { logg_close(); optfree(opts); return 1; } if((opt = optget(opts, "Whitelist"))->enabled && whitelist_init(opt->strarg)) { localnets_free(); logg_close(); optfree(opts); return 1; } if((opt = optget(opts, "SkipAuthenticated"))->enabled && smtpauth_init(opt->strarg)) { localnets_free(); whitelist_free(); logg_close(); optfree(opts); return 1; } multircpt = optget(opts, "SupportMultipleRecipients")->enabled; if(!optget(opts, "Foreground")->enabled) { if(daemonize() == -1) { logg("!daemonize() failed\n"); localnets_free(); whitelist_free(); cpool_free(); logg_close(); optfree(opts); return 1; } if(chdir("/") == -1) logg("^Can't change current working directory to root\n"); } maxfilesize = optget(opts, "MaxFileSize")->numarg; if(!maxfilesize) { logg("^Invalid MaxFileSize, using default (%d)\n", CLI_DEFAULT_MAXFILESIZE); maxfilesize = CLI_DEFAULT_MAXFILESIZE; } readtimeout = optget(opts, "ReadTimeout")->numarg; cpool_init(opts); if (!cp) { logg("!Failed to init the socket pool\n"); localnets_free(); whitelist_free(); logg_close(); optfree(opts); return 1; } if((opt = optget(opts, "PidFile"))->enabled) { FILE *fd; mode_t old_umask = umask(0002); if((fd = fopen(opt->strarg, "w")) == NULL) { logg("!Can't save PID in file %s\n", opt->strarg); } else { if (fprintf(fd, "%u\n", (unsigned int)getpid())<0) { logg("!Can't save PID in file %s\n", opt->strarg); } fclose(fd); } umask(old_umask); } ret = smfi_main(); optfree(opts); logg_close(); cpool_free(); localnets_free(); whitelist_free(); return ret; }
int main(int argc, char **argv) { char *my_socket, *pt; const struct optstruct *opt; struct optstruct *opts; time_t currtime; int ret; memset(&descr, 0, sizeof(struct smfiDesc)); descr.xxfi_name = "ClamAV"; /* filter name */ descr.xxfi_version = SMFI_VERSION; /* milter version */ descr.xxfi_flags = SMFIF_QUARANTINE; /* flags */ descr.xxfi_connect = clamfi_connect; /* connection info filter */ descr.xxfi_envfrom = clamfi_envfrom; /* envelope sender filter */ descr.xxfi_envrcpt = clamfi_envrcpt; /* envelope recipient filter */ descr.xxfi_header = clamfi_header; /* header filter */ descr.xxfi_body = clamfi_body; /* body block */ descr.xxfi_eom = clamfi_eom; /* end of message */ descr.xxfi_abort = clamfi_abort; /* message aborted */ opts = optparse(NULL, argc, argv, 1, OPT_MILTER, 0, NULL); if (!opts) { mprintf("!Can't parse command line options\n"); return 1; } if(optget(opts, "help")->enabled) { printf("Usage: %s [-c <config-file>]\n\n", argv[0]); printf(" --help -h Show this help\n"); printf(" --version -V Show version and exit\n"); printf(" --config-file <file> -c Read configuration from file\n\n"); optfree(opts); return 0; } if(opts->filename) { int x; for(x = 0; opts->filename[x]; x++) mprintf("^Ignoring option %s\n", opts->filename[x]); } if(optget(opts, "version")->enabled) { printf("clamav-milter %s\n", get_version()); optfree(opts); return 0; } pt = strdup(optget(opts, "config-file")->strarg); if((opts = optparse(pt, 0, NULL, 1, OPT_MILTER, 0, opts)) == NULL) { printf("%s: cannot parse config file %s\n", argv[0], pt); free(pt); return 1; } free(pt); if((opt = optget(opts, "Chroot"))->enabled) { if(chdir(opt->strarg) != 0) { logg("!Cannot change directory to %s\n", opt->strarg); return 1; } if(chroot(opt->strarg) != 0) { logg("!chroot to %s failed. Are you root?\n", opt->strarg); return 1; } } if(geteuid() == 0 && (opt = optget(opts, "User"))->enabled) { struct passwd *user = NULL; if((user = getpwnam(opt->strarg)) == NULL) { fprintf(stderr, "ERROR: Can't get information about user %s.\n", opt->strarg); optfree(opts); return 1; } if(optget(opts, "AllowSupplementaryGroups")->enabled) { #ifdef HAVE_INITGROUPS if(initgroups(opt->strarg, user->pw_gid)) { fprintf(stderr, "ERROR: initgroups() failed.\n"); optfree(opts); return 1; } #else mprintf("!AllowSupplementaryGroups: initgroups() is not available, please disable AllowSupplementaryGroups\n"); optfree(opts); return 1; #endif } else { #ifdef HAVE_SETGROUPS if(setgroups(1, &user->pw_gid)) { fprintf(stderr, "ERROR: setgroups() failed.\n"); optfree(opts); return 1; } #endif } if(setgid(user->pw_gid)) { fprintf(stderr, "ERROR: setgid(%d) failed.\n", (int) user->pw_gid); optfree(opts); return 1; } if(setuid(user->pw_uid)) { fprintf(stderr, "ERROR: setuid(%d) failed.\n", (int) user->pw_uid); optfree(opts); return 1; } } logg_lock = !optget(opts, "LogFileUnlock")->enabled; logg_time = optget(opts, "LogTime")->enabled; logg_size = optget(opts, "LogFileMaxSize")->numarg; logg_verbose = mprintf_verbose = optget(opts, "LogVerbose")->enabled; if((opt = optget(opts, "LogFile"))->enabled) { logg_file = opt->strarg; if(strlen(logg_file) < 2 || logg_file[0] != '/') { fprintf(stderr, "ERROR: LogFile requires full path.\n"); logg_close(); optfree(opts); return 1; } } else logg_file = NULL; #if defined(USE_SYSLOG) && !defined(C_AIX) if(optget(opts, "LogSyslog")->enabled) { int fac; opt = optget(opts, "LogFacility"); if((fac = logg_facility(opt->strarg)) == -1) { logg("!LogFacility: %s: No such facility.\n", opt->strarg); logg_close(); optfree(opts); return 1; } openlog("clamav-milter", LOG_PID, fac); logg_syslog = 1; } #endif time(&currtime); if(logg("#+++ Started at %s", ctime(&currtime))) { fprintf(stderr, "ERROR: Can't initialize the internal logger\n"); logg_close(); optfree(opts); return 1; } if((opt = optget(opts, "TemporaryDirectory"))->enabled) tempdir = opt->strarg; if(localnets_init(opts) || init_actions(opts)) { logg_close(); optfree(opts); return 1; } if((opt = optget(opts, "Whitelist"))->enabled && whitelist_init(opt->strarg)) { localnets_free(); logg_close(); optfree(opts); return 1; } if((opt = optget(opts, "SkipAuthenticated"))->enabled && smtpauth_init(opt->strarg)) { localnets_free(); whitelist_free(); logg_close(); optfree(opts); return 1; } pt = optget(opts, "AddHeader")->strarg; if(strcasecmp(pt, "No")) { char myname[255]; if(!gethostname(myname, sizeof(myname))) { myname[sizeof(myname)-1] = '\0'; snprintf(xvirushdr, sizeof(xvirushdr), "clamav-milter %s at %s", get_version(), myname); xvirushdr[sizeof(xvirushdr)-1] = '\0'; } else { snprintf(xvirushdr, sizeof(xvirushdr), "clamav-milter %s", get_version()); xvirushdr[sizeof(xvirushdr)-1] = '\0'; } descr.xxfi_flags |= SMFIF_ADDHDRS; if(strcasecmp(pt, "Add")) { /* Replace or Yes */ descr.xxfi_flags |= SMFIF_CHGHDRS; addxvirus = 1; } else { /* Add */ addxvirus = 2; } } if(!(my_socket = optget(opts, "MilterSocket")->strarg)) { logg("!Please configure the MilterSocket directive\n"); localnets_free(); whitelist_free(); logg_close(); optfree(opts); return 1; } if(!optget(opts, "Foreground")->enabled) { if(daemonize() == -1) { logg("!daemonize() failed\n"); localnets_free(); whitelist_free(); cpool_free(); logg_close(); optfree(opts); return 1; } if(chdir("/") == -1) logg("^Can't change current working directory to root\n"); } if(smfi_setconn(my_socket) == MI_FAILURE) { logg("!smfi_setconn failed\n"); localnets_free(); whitelist_free(); logg_close(); optfree(opts); return 1; } if(smfi_register(descr) == MI_FAILURE) { logg("!smfi_register failed\n"); localnets_free(); whitelist_free(); logg_close(); optfree(opts); return 1; } opt = optget(opts, "FixStaleSocket"); if(smfi_opensocket(opt->enabled) == MI_FAILURE) { logg("!Failed to create socket %s\n", my_socket); localnets_free(); whitelist_free(); logg_close(); optfree(opts); return 1; } maxfilesize = optget(opts, "MaxFileSize")->numarg; readtimeout = optget(opts, "ReadTimeout")->numarg; cpool_init(opts); if (!cp) { logg("!Failed to init the socket pool\n"); localnets_free(); whitelist_free(); logg_close(); optfree(opts); return 1; } if((opt = optget(opts, "PidFile"))->enabled) { FILE *fd; mode_t old_umask = umask(0006); if((fd = fopen(opt->strarg, "w")) == NULL) { logg("!Can't save PID in file %s\n", opt->strarg); } else { if (fprintf(fd, "%u", (unsigned int)getpid())<0) { logg("!Can't save PID in file %s\n", opt->strarg); } fclose(fd); } umask(old_umask); } ret = smfi_main(); optfree(opts); logg_close(); cpool_free(); localnets_free(); whitelist_free(); return ret; }