Index: dspam/CHANGE diff -c dspam/CHANGE:1.1.1.12 dspam/CHANGE:1.1.1.12.2.1 *** dspam/CHANGE:1.1.1.12 Sat Nov 8 13:55:54 2003 --- dspam/CHANGE Sat Nov 15 18:34:58 2003 *************** *** 1,3 **** --- 1,16 ---- + Version NEXT + ------------ + + [20031113.1938] jonz: corrected DSM_CLASSIFY bug in libdspam + + corrected two bugs in libdspam regarding the DSM_CLASSIFY mode: + + 1. CTX->signature would overwrite the provided signature with a new signature + resulting in a potential memory leak + + 2. If no signature was provided, DSM_CLASSIFY would segfault instead of create + a new signature + Version 2.8-beta-2 ------------------ Index: dspam/addspam.sh diff -c /dev/null dspam/addspam.sh:1.2.4.1 *** /dev/null Sat Nov 15 20:45:12 2003 --- dspam/addspam.sh Sat Nov 15 20:40:53 2003 *************** *** 0 **** --- 1,26 ---- + #!/bin/sh + + die() { + echo `date '+%b%d %H:%M:%S'` "$*" >&2 + exit 1 + } + + log() { + echo `date '+%b%d %H:%M:%S'` "$*" >&2 + } + + action="--`basename $0 .sh`" + log dspam -d $user $action + + exec >>/var/log/dspam.log 2>&1 + + read from || die "No input" + set - $from + envfrom="$2" + IFS="@" + set - $envfrom + user="$1" + domain="$2" + [ "$domain" = "yourcompany.com" ] || die "Invalid source domain: $domain" + log dspam -d $user $action + /usr/local/bin/dspam -d $user $action || die "DSPAM error" Index: dspam/decode.c diff -c dspam/decode.c:1.1.1.3 dspam/decode.c:1.1.1.3.2.1 *** dspam/decode.c:1.1.1.3 Thu Oct 23 17:25:44 2003 --- dspam/decode.c Sat Nov 15 18:34:58 2003 *************** *** 118,130 **** { /* If we see two boundaries converged on top of one another */ ! if (_ds_match_boundary (boundaries, line)) { /* Add the boundary as the terminating boundary */ current_block->terminating_boundary = strdup (line + 2); current_block->original_encoding = current_block->encoding; ! current_block = _ds_create_message_block (); ! if (current_block == NULL) { LOG (LOG_CRIT, ERROR_MEM_ALLOC); --- 118,131 ---- { /* If we see two boundaries converged on top of one another */ ! if (_ds_match_boundary (boundaries, line)) ! { /* Add the boundary as the terminating boundary */ current_block->terminating_boundary = strdup (line + 2); current_block->original_encoding = current_block->encoding; ! current_block = _ds_create_message_block (); ! if (current_block == NULL) { LOG (LOG_CRIT, ERROR_MEM_ALLOC); *************** *** 133,142 **** nt_destroy (boundaries); return NULL; } ! if (nt_add (out->components, (void *) current_block) == NULL) LOG (LOG_CRIT, ERROR_MEM_ALLOC); ! block_position = BP_HEADER; } --- 134,143 ---- nt_destroy (boundaries); return NULL; } ! if (nt_add (out->components, (void *) current_block) == NULL) LOG (LOG_CRIT, ERROR_MEM_ALLOC); ! block_position = BP_HEADER; } *************** *** 188,194 **** { /* Check for multipart boundary definition */ ! if (!strncasecmp (line, "Content-Type", 12) || ((line[0] == 32 || line[0] == 9) && in_content)) { char *h = strdup (line); --- 189,196 ---- { /* Check for multipart boundary definition */ ! if (!strncasecmp (line, "Content-Type", 12) ! || ((line[0] == 32 || line[0] == 9) && in_content)) { char *h = strdup (line); *************** *** 206,212 **** char *x; long pos, len; ! if (strchr(h, '=') && strchr(h, '"')) { x = strtok (strstr (h, "boundary"), "\""); x = strtok (NULL, "\""); --- 208,214 ---- char *x; long pos, len; ! if (strchr (h, '=') && strchr (h, '"')) { x = strtok (strstr (h, "boundary"), "\""); x = strtok (NULL, "\""); *************** *** 217,223 **** } /* Copy the case sensitive version back */ ! if (x != (char *) 1) { pos = x - h; len = strlen (x); memcpy (x, line + pos, len); --- 219,226 ---- } /* Copy the case sensitive version back */ ! if (x != (char *) 1) ! { pos = x - h; len = strlen (x); memcpy (x, line + pos, len); *************** *** 230,236 **** } } free (h); ! } else { in_content = 0; } } --- 233,241 ---- } } free (h); ! } ! else ! { in_content = 0; } } *************** *** 404,410 **** { LOG (LOG_CRIT, ERROR_MEM_ALLOC); } ! else { original = new_alloc; strcat (original, rest); --- 409,415 ---- { LOG (LOG_CRIT, ERROR_MEM_ALLOC); } ! else { original = new_alloc; strcat (original, rest); *************** *** 429,441 **** { LOG (LOG_CRIT, ERROR_MEM_ALLOC); } ! else { original = new_alloc; strcat (original, rest); } } ! free(data); data = original; } else --- 434,446 ---- { LOG (LOG_CRIT, ERROR_MEM_ALLOC); } ! else { original = new_alloc; strcat (original, rest); } } ! free (data); data = original; } else *************** *** 492,498 **** block->media_type = MT_MESSAGE; if (!strncasecmp (header->data + 8, "rfc822", 6)) block->media_subtype = MST_RFC822; ! else if (!strncasecmp(header->data + 8, "inoculation", 11)) block->media_subtype = MST_INOCULATION; else block->media_subtype = MST_OTHER; --- 497,503 ---- block->media_type = MT_MESSAGE; if (!strncasecmp (header->data + 8, "rfc822", 6)) block->media_subtype = MST_RFC822; ! else if (!strncasecmp (header->data + 8, "inoculation", 11)) block->media_subtype = MST_INOCULATION; else block->media_subtype = MST_OTHER; *************** *** 525,531 **** char *x; long pos, len; ! if (strchr (h, '=') && strchr(h, '"')) { x = strtok (strstr (h, "boundary"), "\""); x = strtok (NULL, "\""); --- 530,536 ---- char *x; long pos, len; ! if (strchr (h, '=') && strchr (h, '"')) { x = strtok (strstr (h, "boundary"), "\""); x = strtok (NULL, "\""); *************** *** 814,822 **** buffer_cat (out, "\n"); /* Assemble the bodies */ ! if (block->original_signed_body != NULL) buffer_cat (out, block->original_signed_body->data); ! else buffer_cat (out, block->body->data); if (block->terminating_boundary != NULL) --- 819,827 ---- buffer_cat (out, "\n"); /* Assemble the bodies */ ! if (block->original_signed_body != NULL) buffer_cat (out, block->original_signed_body->data); ! else buffer_cat (out, block->body->data); if (block->terminating_boundary != NULL) Index: dspam/dspam.c diff -c dspam/dspam.c:1.1.1.11 dspam/dspam.c:1.1.1.11.2.1 *** dspam/dspam.c:1.1.1.11 Mon Nov 3 17:41:19 2003 --- dspam/dspam.c Sat Nov 15 18:34:58 2003 *************** *** 63,69 **** { char mailer_args[256]; /* Args passed to MLOCAL */ char spam_args[256]; /* Args passed for spam delivery */ ! char managed_group[256]; /* Managed Group (if any) */ int mode = DSM_PROCESS; /* Processing mode */ #ifdef TRUSTED_USER_SECURITY int trusted_user = 0; /* Trusted User? */ --- 63,69 ---- { char mailer_args[256]; /* Args passed to MLOCAL */ char spam_args[256]; /* Args passed for spam delivery */ ! char managed_group[256]; /* Managed Group (if any) */ int mode = DSM_PROCESS; /* Processing mode */ #ifdef TRUSTED_USER_SECURITY int trusted_user = 0; /* Trusted User? */ *************** *** 81,97 **** char filename[MAX_FILENAME_LENGTH]; #ifdef DEBUG ! char debug_args[1024]; /* Report on all arguments passed in */ #endif ! int user_flag = 0; /* Next argument(s) are users */ ! int flags = 0; /* Agent (DAF) flags passed to process_message() */ ! int deliver_fp = 0; /* Deliver FPs? (Commandline) ! Only need to specify when configuring with ! --enable-spam-delivery */ ! int deliver_spam = 0; /* Deliver Spams? (Commandline) */ int i; int line = 1; --- 81,97 ---- char filename[MAX_FILENAME_LENGTH]; #ifdef DEBUG ! char debug_args[1024]; /* Report on all arguments passed in */ #endif ! int user_flag = 0; /* Next argument(s) are users */ ! int flags = 0; /* Agent (DAF) flags passed to process_message() */ ! int deliver_fp = 0; /* Deliver FPs? (Commandline) ! * Only need to specify when configuring with ! * --enable-spam-delivery */ ! int deliver_spam = 0; /* Deliver Spams? (Commandline) */ int i; int line = 1; *************** *** 140,148 **** if (!trusted_user) { ! LOG (LOG_INFO, ! "forcing username for untrusted user %s", ! p->pw_name); nt_add (users, p->pw_name); } #endif --- 140,146 ---- if (!trusted_user) { ! LOG (LOG_INFO, "forcing username for untrusted user %s", p->pw_name); nt_add (users, p->pw_name); } #endif *************** *** 213,221 **** if (!strcmp (argv[i], "--inoculate")) { ! if (!(flags & DAF_INOCULATE)) { #ifdef VERBOSE ! LOGDEBUG("setting flag DAF_INOCULATE"); #endif flags = flags ^ DAF_INOCULATE; } --- 211,220 ---- if (!strcmp (argv[i], "--inoculate")) { ! if (!(flags & DAF_INOCULATE)) ! { #ifdef VERBOSE ! LOGDEBUG ("setting flag DAF_INOCULATE"); #endif flags = flags ^ DAF_INOCULATE; } *************** *** 224,232 **** if (!strcmp (argv[i], "--corpus")) { ! if (!(flags & DAF_CORPUS)) { #ifdef VERBOSE ! LOGDEBUG("setting flag DAF_CORPUS"); #endif flags = flags ^ DAF_CORPUS; } --- 223,232 ---- if (!strcmp (argv[i], "--corpus")) { ! if (!(flags & DAF_CORPUS)) ! { #ifdef VERBOSE ! LOGDEBUG ("setting flag DAF_CORPUS"); #endif flags = flags ^ DAF_CORPUS; } *************** *** 239,245 **** continue; } ! /* backward compatibility */ if (!strcmp (argv[i], "--deliver-fp") || !strcmp (argv[i], "--deliver")) { deliver_fp = 1; --- 239,245 ---- continue; } ! /* backward compatibility */ if (!strcmp (argv[i], "--deliver-fp") || !strcmp (argv[i], "--deliver")) { deliver_fp = 1; *************** *** 253,259 **** continue; } ! if (!strcmp(argv[i], "--deliver-spam")) { deliver_spam = 1; continue; --- 253,259 ---- continue; } ! if (!strcmp (argv[i], "--deliver-spam")) { deliver_spam = 1; continue; *************** *** 325,331 **** /* Read in the message */ while ((fgets (buff, sizeof (buff), stdin)) != NULL) { ! if (line>1 || strncmp(buff, "From QUARANTINE", 15)) { if (buffer_cat (message, buff)) { LOG (LOG_CRIT, ERROR_MEM_ALLOC); --- 325,332 ---- /* Read in the message */ while ((fgets (buff, sizeof (buff), stdin)) != NULL) { ! if (line > 1 || strncmp (buff, "From QUARANTINE", 15)) ! { if (buffer_cat (message, buff)) { LOG (LOG_CRIT, ERROR_MEM_ALLOC); *************** *** 334,352 **** } /* Use the original user id if we are reversing a false positive */ ! if (mode == DSM_FALSEPOSITIVE && !strncasecmp(buff, "X-DSPAM-User: ", 14) && managed_group[0] != 0) { char user[MAX_USERNAME_LENGTH]; ! strlcpy(user, buff+14, sizeof(user)); ! chomp(user); ! LOGDEBUG("X-DSPAM-User: %s", user); ! nt_destroy(users); ! users = nt_create(NT_CHAR); ! if (users == NULL) { report_error (ERROR_MEM_ALLOC); exit (EXIT_FAILURE); } ! nt_add(users, user); } line++; --- 335,355 ---- } /* Use the original user id if we are reversing a false positive */ ! if (mode == DSM_FALSEPOSITIVE ! && !strncasecmp (buff, "X-DSPAM-User: ", 14) && managed_group[0] != 0) { char user[MAX_USERNAME_LENGTH]; ! strlcpy (user, buff + 14, sizeof (user)); ! chomp (user); ! LOGDEBUG ("X-DSPAM-User: %s", user); ! nt_destroy (users); ! users = nt_create (NT_CHAR); ! if (users == NULL) ! { report_error (ERROR_MEM_ALLOC); exit (EXIT_FAILURE); } ! nt_add (users, user); } line++; *************** *** 358,366 **** exit (EXIT_SUCCESS); } ! if (dspam_init_driver()) { ! LOG(LOG_WARNING, "unable to initialize storage driver"); ! exit(EXIT_FAILURE); } /* Process message for each user */ --- 361,370 ---- exit (EXIT_SUCCESS); } ! if (dspam_init_driver ()) ! { ! LOG (LOG_WARNING, "unable to initialize storage driver"); ! exit (EXIT_FAILURE); } /* Process message for each user */ *************** *** 387,425 **** if (!stat (filename, &s)) #endif { ! if (!(flags & DAF_CORPUS)) { ! retcode = deliver_message (message->data, (flags & DAF_STDOUT) ? NULL : mailer_args, node_nt->ptr, mode); ! if (retcode && exitcode == EXIT_SUCCESS) exitcode = retcode; } } else { ! result = process_message (managed_group, sizeof(managed_group), message, node_nt->ptr, mode, flags); ! if (mode == DSM_CLASSIFY) { ! if (result == DSR_ISSPAM) ! printf("SPAM\n"); else ! printf("HAM\n"); node_nt = c_nt_next (users, &c_nt); continue; } if (result != DSR_ISSPAM) { ! if (result != DSR_ISINNOCENT) { LOG (LOG_WARNING, "process_message returned error %d. delivering message.", result); } #ifdef DELIVER_SPAM ! if (mode != DSM_FALSEPOSITIVE && !deliver_fp) { #endif LOGDEBUG ("delivering message"); ! if (!(flags & DAF_CORPUS)) { ! retcode = deliver_message (message->data, (flags & DAF_STDOUT) ? NULL : mailer_args, node_nt->ptr, mode); if (retcode) exitcode = retcode; } --- 391,442 ---- if (!stat (filename, &s)) #endif { ! if (!(flags & DAF_CORPUS)) ! { ! retcode = ! deliver_message (message->data, ! (flags & DAF_STDOUT) ! ? NULL : mailer_args, node_nt->ptr, mode); ! if (retcode && exitcode == EXIT_SUCCESS) exitcode = retcode; } } else { ! result = process_message (managed_group, ! sizeof (managed_group), ! message, node_nt->ptr, mode, flags); ! if (mode == DSM_CLASSIFY) ! { ! if (result == DSR_ISSPAM) ! printf ("SPAM\n"); else ! printf ("HAM\n"); node_nt = c_nt_next (users, &c_nt); continue; } if (result != DSR_ISSPAM) { ! if (result != DSR_ISINNOCENT) ! { LOG (LOG_WARNING, "process_message returned error %d. delivering message.", result); } #ifdef DELIVER_SPAM ! if (mode != DSM_FALSEPOSITIVE && !deliver_fp) ! { #endif LOGDEBUG ("delivering message"); ! if (!(flags & DAF_CORPUS)) ! { ! retcode = ! deliver_message ! (message->data, ! (flags & DAF_STDOUT) ? NULL : mailer_args, node_nt->ptr, mode); if (retcode) exitcode = retcode; } *************** *** 434,460 **** { if (spam_args[0] != 0) { ! retcode = deliver_message (message->data, (flags & DAF_STDOUT) ? NULL : spam_args, node_nt->ptr, mode); if (retcode) exitcode = retcode; } else { ! if (!(flags & DAF_CORPUS)) { #ifdef DELIVER_SPAM ! retcode = deliver_message ! (message->data, (flags & DAF_STDOUT) ? NULL : mailer_args, node_nt->ptr, mode); if (retcode) exitcode = retcode; #else ! if (deliver_spam) { ! retcode = deliver_message (message->data, (flags & DAF_STDOUT) ? NULL : mailer_args, node_nt->ptr, mode); if (retcode) exitcode = retcode; ! } else { if (managed_group[0] == 0) quarantine_message (message->data, node_nt->ptr); ! else quarantine_message (message->data, managed_group); } #endif --- 451,493 ---- { if (spam_args[0] != 0) { ! retcode = ! deliver_message ! (message->data, ! (flags & DAF_STDOUT) ? NULL : spam_args, node_nt->ptr, mode); if (retcode) exitcode = retcode; } else { ! if (!(flags & DAF_CORPUS)) ! { #ifdef DELIVER_SPAM ! retcode = ! deliver_message ! (message-> ! data, ! (flags & ! DAF_STDOUT) ? NULL : mailer_args, node_nt->ptr, mode); if (retcode) exitcode = retcode; #else ! if (deliver_spam) ! { ! retcode = ! deliver_message ! (message-> ! data, ! (flags ! & DAF_STDOUT) ? NULL : mailer_args, node_nt->ptr, mode); if (retcode) exitcode = retcode; ! } ! else ! { if (managed_group[0] == 0) quarantine_message (message->data, node_nt->ptr); ! else quarantine_message (message->data, managed_group); } #endif *************** *** 466,472 **** node_nt = c_nt_next (users, &c_nt); } ! dspam_shutdown_driver(); LOGDEBUG ("DSPAM Agent Shutdown. Exit Code: %d", exitcode); exit (exitcode); } --- 499,505 ---- node_nt = c_nt_next (users, &c_nt); } ! dspam_shutdown_driver (); LOGDEBUG ("DSPAM Agent Shutdown. Exit Code: %d", exitcode); exit (exitcode); } *************** *** 480,490 **** */ int ! process_message (char *r_group, size_t size, buffer * message, const char *username, int mode, int flags) { ! DSPAM_CTX *CTX; /* dspam context */ struct _ds_message *components; ! struct _ds_spam_signature SIG; /* signature object */ char ctx_group[128]; struct nt_node *node_nt; --- 513,524 ---- */ int ! process_message (char *r_group, size_t size, buffer * message, ! const char *username, int mode, int flags) { ! DSPAM_CTX *CTX; /* dspam context */ struct _ds_message *components; ! struct _ds_spam_signature SIG; /* signature object */ char ctx_group[128]; struct nt_node *node_nt; *************** *** 501,515 **** int result; int i = 0; ! struct nt *inoc_users; /* inoculate list */ ! struct nt *classify_users; /* classify list */ ctx_group[0] = 0; #ifdef DEBUG { FILE *f; char m[MAX_FILENAME_LENGTH]; ! snprintf(m, sizeof(m), "%s/dspam.messages", USERDIR); f = fopen (m, "a"); if (f != NULL) { --- 535,549 ---- int result; int i = 0; ! struct nt *inoc_users; /* inoculate list */ ! struct nt *classify_users; /* classify list */ ctx_group[0] = 0; #ifdef DEBUG { FILE *f; char m[MAX_FILENAME_LENGTH]; ! snprintf (m, sizeof (m), "%s/dspam.messages", USERDIR); f = fopen (m, "a"); if (f != NULL) { *************** *** 519,533 **** } #endif ! inoc_users = nt_create(NT_CHAR); ! if (inoc_users == NULL) { ! LOG(LOG_CRIT, ERROR_MEM_ALLOC); return EUNKNOWN; } ! classify_users = nt_create(NT_CHAR); ! if (classify_users == NULL) { ! LOG(LOG_CRIT, ERROR_MEM_ALLOC); return EUNKNOWN; } --- 553,569 ---- } #endif ! inoc_users = nt_create (NT_CHAR); ! if (inoc_users == NULL) ! { ! LOG (LOG_CRIT, ERROR_MEM_ALLOC); return EUNKNOWN; } ! classify_users = nt_create (NT_CHAR); ! if (classify_users == NULL) ! { ! LOG (LOG_CRIT, ERROR_MEM_ALLOC); return EUNKNOWN; } *************** *** 544,557 **** int do_inoculate = 0; char *type, *list; chomp (buffer); ! list = strdup(buffer); group = strtok (buffer, ":"); if (group != NULL) { ! type = strtok(NULL, ":"); user = strtok (NULL, ","); ! ! if (!strcasecmp(type, "INOCULATION") && mode == DSM_ADDSPAM && (!(flags & DAF_CORPUS) || flags & DAF_INOCULATE)) do_inoculate = 1; while (user != NULL) --- 580,595 ---- int do_inoculate = 0; char *type, *list; chomp (buffer); ! list = strdup (buffer); group = strtok (buffer, ":"); if (group != NULL) { ! type = strtok (NULL, ":"); user = strtok (NULL, ","); ! ! if (!strcasecmp (type, "INOCULATION") ! && mode == DSM_ADDSPAM ! && (!(flags & DAF_CORPUS) || flags & DAF_INOCULATE)) do_inoculate = 1; while (user != NULL) *************** *** 560,605 **** { /* If we're reporting a spam, report it as a spam to all other ! users in the inoculation group */ ! if (do_inoculate) { char *l = list, *u; ! u = strsep(&l, ":"); ! u = strsep(&l, ":"); ! u = strsep(&l, ","); ! while(u != NULL) { ! if (strcmp(u, username)) { ! LOGDEBUG("adding user %s to inoculation group %s", u, group); ! nt_add(inoc_users, u); } ! u = strsep(&l, ","); } ! } else if (!strncasecmp(type, "SHARED", 6)) { strlcpy (ctx_group, group, sizeof (ctx_group)); LOGDEBUG ("assigning user %s to group %s", username, group); ! if (!strncasecmp(type+6, ",MANAGED", 8)) strlcpy (r_group, ctx_group, size); ! ! } else if (!strcasecmp(type, "CLASSIFICATION")) { char *l = list, *u; ! u = strsep(&l, ":"); ! u = strsep(&l, ":"); ! u = strsep(&l, ","); ! while(u != NULL) { ! if (strcmp(u, username)) { ! LOGDEBUG("adding user %s to classification group %s", u, group); ! nt_add(classify_users, u); } ! u = strsep(&l, ","); } ! } } user = strtok (NULL, ","); } } ! free(list); } fclose (file); } --- 598,654 ---- { /* If we're reporting a spam, report it as a spam to all other ! * users in the inoculation group */ ! if (do_inoculate) ! { char *l = list, *u; ! u = strsep (&l, ":"); ! u = strsep (&l, ":"); ! u = strsep (&l, ","); ! while (u != NULL) ! { ! if (strcmp (u, username)) ! { ! LOGDEBUG ("adding user %s to inoculation group %s", u, ! group); ! nt_add (inoc_users, u); } ! u = strsep (&l, ","); } ! } ! else if (!strncasecmp (type, "SHARED", 6)) ! { strlcpy (ctx_group, group, sizeof (ctx_group)); LOGDEBUG ("assigning user %s to group %s", username, group); ! if (!strncasecmp (type + 6, ",MANAGED", 8)) strlcpy (r_group, ctx_group, size); ! ! } ! else if (!strcasecmp (type, "CLASSIFICATION")) ! { char *l = list, *u; ! u = strsep (&l, ":"); ! u = strsep (&l, ":"); ! u = strsep (&l, ","); ! while (u != NULL) ! { ! if (strcmp (u, username)) ! { ! LOGDEBUG ("adding user %s to classification group %s", u, ! group); ! nt_add (classify_users, u); } ! u = strsep (&l, ","); } ! } } user = strtok (NULL, ","); } } ! free (list); } fclose (file); } *************** *** 614,620 **** CTX = dspam_init (username, ctx_group, mode, DSF_CHAINED | DSF_SIGNATURE | f_corpus | f_inoculate); #else ! CTX = dspam_init (username, ctx_group, mode, DSF_SIGNATURE | f_corpus | f_inoculate); #endif --- 663,669 ---- CTX = dspam_init (username, ctx_group, mode, DSF_CHAINED | DSF_SIGNATURE | f_corpus | f_inoculate); #else ! CTX = dspam_init (username, ctx_group, mode, DSF_SIGNATURE | f_corpus | f_inoculate); #endif *************** *** 636,650 **** /* If this message is an inoculation, authenticate and process it */ /* per Internet-Draft draft-spamfilt-inoculation-01.txt ! "The Versatile Language Inoculation Message Format" ! ! UNDER DEVELOPMENT... ! current caveats: ! ! - only md5 authentication is supported ! - only the message/inoculation MIME type is supported ! - outgoing inoculation messages are not supported ! */ #ifdef EXPERIMENTAL --- 685,699 ---- /* If this message is an inoculation, authenticate and process it */ /* per Internet-Draft draft-spamfilt-inoculation-01.txt ! * "The Versatile Language Inoculation Message Format" ! * ! * UNDER DEVELOPMENT... ! * current caveats: ! * ! * - only md5 authentication is supported ! * - only the message/inoculation MIME type is supported ! * - outgoing inoculation messages are not supported ! */ #ifdef EXPERIMENTAL *************** *** 655,773 **** int auth_user = 0, auth_checksum = 0; char *inoc_message = NULL; FILE *file; ! ! node_nt = c_nt_first(CTX->message->components, &c_nt); ! if (node_nt != NULL) { struct _ds_message_block *block; block = (struct _ds_message_block *) node_nt->ptr; ! if (block->media_type == MT_MESSAGE && block->media_subtype == MST_INOCULATION) { struct _ds_header_field *header; char *sender = NULL, *checksum = NULL, *inoculation_type = NULL; int auth_type = IAT_UNKNOWN; long content_length = 0; ! LOGDEBUG("validating inoculation"); /* Read the inoculation headers */ ! node_hnt = c_nt_first(block->headers, &c_nt); ! while(node_hnt != NULL) { header = (struct _ds_header_field *) node_hnt->ptr; ! if (header != NULL) { ! if (!strcasecmp(header->heading, "Content-Length")) ! content_length = strtol(header->data, NULL, 0); ! else if (!strcasecmp(header->heading, "Inoculation-Sender")) sender = header->data; ! else if (!strcasecmp(header->heading, "Inoculation-Authentication")) { ! if (!strncasecmp(header->data, "md5", 3)) { ! char *d = strdup(header->data); auth_type = IAT_MD5; ! if (strchr(header->data, '"')) { ! checksum = strtok(d, "\""); ! checksum = strdup(strtok(NULL, "\"")); ! } else { ! checksum = strtok(d, "="); ! checksum = strdup(strtok(NULL, "=")); } ! free(d); ! } else if (!strncasecmp(header->data, "signed", 6)) { auth_type = IAT_SIGNED; ! } else if (!strncasecmp(header->data, "none", 4)) { auth_type = IAT_NONE; } } ! else if (!strcasecmp(header->heading, "Inoculation-Type")) inoculation_type = header->data; } ! node_hnt = c_nt_next(block->headers, &c_nt); } /* Verify the inoculation */ ! if (sender != NULL && checksum != NULL && inoculation_type != NULL) { ! char *s = NULL, *v = NULL; /* s = sender, v = validation code */ ! /* Verify the sender, get the validation code */ ! strcpy(filename, _ds_userdir_path(username, "inoc")); ! file = fopen(filename, "r"); ! if (file != NULL) { char buf[1024]; ! while(fgets(buf, sizeof(buf), file) != NULL) { ! s = strdup(strtok(buf, ":")); ! v = strdup(strtok(NULL, ":")); ! if (!strcmp(s, sender)) { ! LOGDEBUG("sender verified"); ! auth_user = 1; ! } else { ! free(s); ! free(v); } } ! fclose(file); } /* Verify the Checksum */ ! if (auth_user) { ! if (auth_type == IAT_MD5) { unsigned char digest[17]; char a_digest[33]; char x[3]; MD5_CTX MTX; if (content_length == 0) ! content_length = strlen(block->body->data)-1; ! MD5Init(&MTX); ! MD5Update(&MTX, v, strlen(v)); /* Verification Code */ ! MD5Update(&MTX, block->body->data, content_length); ! MD5Final(digest, &MTX); a_digest[0] = 0; ! for(i=0;i<16;i++) { ! snprintf(x, 3, "%02x", digest[i]); ! strcat(a_digest, x); } ! if (!strcmp(a_digest, checksum)) { ! LOGDEBUG("inoculation validated"); auth_checksum = 1; ! inoc_message = strdup(block->body->data); ! } else { ! LOGDEBUG("inoculation invalid. ignoring"); return 0; } } } } ! free(checksum); } } /* Process the inoculation */ ! if (auth_user && auth_checksum) { ! inoculate_user(username, NULL, inoc_message); ! free(inoc_message); return DSR_ISSPAM; } } --- 704,849 ---- int auth_user = 0, auth_checksum = 0; char *inoc_message = NULL; FILE *file; ! ! node_nt = c_nt_first (CTX->message->components, &c_nt); ! if (node_nt != NULL) ! { struct _ds_message_block *block; block = (struct _ds_message_block *) node_nt->ptr; ! if (block->media_type == MT_MESSAGE ! && block->media_subtype == MST_INOCULATION) ! { struct _ds_header_field *header; char *sender = NULL, *checksum = NULL, *inoculation_type = NULL; int auth_type = IAT_UNKNOWN; long content_length = 0; ! LOGDEBUG ("validating inoculation"); /* Read the inoculation headers */ ! node_hnt = c_nt_first (block->headers, &c_nt); ! while (node_hnt != NULL) ! { header = (struct _ds_header_field *) node_hnt->ptr; ! if (header != NULL) ! { ! if (!strcasecmp (header->heading, "Content-Length")) ! content_length = strtol (header->data, NULL, 0); ! else if (!strcasecmp (header->heading, "Inoculation-Sender")) sender = header->data; ! else if (!strcasecmp ! (header->heading, "Inoculation-Authentication")) { ! if (!strncasecmp (header->data, "md5", 3)) ! { ! char *d = strdup (header->data); auth_type = IAT_MD5; ! if (strchr (header->data, '"')) ! { ! checksum = strtok (d, "\""); ! checksum = strdup (strtok (NULL, "\"")); } ! else ! { ! checksum = strtok (d, "="); ! checksum = strdup (strtok (NULL, "=")); ! } ! free (d); ! } ! else if (!strncasecmp (header->data, "signed", 6)) ! { auth_type = IAT_SIGNED; ! } ! else if (!strncasecmp (header->data, "none", 4)) ! { auth_type = IAT_NONE; } } ! else if (!strcasecmp (header->heading, "Inoculation-Type")) inoculation_type = header->data; } ! node_hnt = c_nt_next (block->headers, &c_nt); } /* Verify the inoculation */ ! if (sender != NULL && checksum != NULL && inoculation_type != NULL) ! { ! char *s = NULL, *v = NULL; /* s = sender, v = validation code */ ! /* Verify the sender, get the validation code */ ! strcpy (filename, _ds_userdir_path (username, "inoc")); ! file = fopen (filename, "r"); ! if (file != NULL) ! { char buf[1024]; ! while (fgets (buf, sizeof (buf), file) != NULL) ! { ! s = strdup (strtok (buf, ":")); ! v = strdup (strtok (NULL, ":")); ! if (!strcmp (s, sender)) ! { ! LOGDEBUG ("sender verified"); ! auth_user = 1; ! } ! else ! { ! free (s); ! free (v); } } ! fclose (file); } /* Verify the Checksum */ ! if (auth_user) ! { ! if (auth_type == IAT_MD5) ! { unsigned char digest[17]; char a_digest[33]; char x[3]; MD5_CTX MTX; if (content_length == 0) ! content_length = strlen (block->body->data) - 1; ! MD5Init (&MTX); ! MD5Update (&MTX, v, strlen (v)); /* Verification Code */ ! MD5Update (&MTX, block->body->data, content_length); ! MD5Final (digest, &MTX); a_digest[0] = 0; ! for (i = 0; i < 16; i++) ! { ! snprintf (x, 3, "%02x", digest[i]); ! strcat (a_digest, x); } ! if (!strcmp (a_digest, checksum)) ! { ! LOGDEBUG ("inoculation validated"); auth_checksum = 1; ! inoc_message = strdup (block->body->data); ! } ! else ! { ! LOGDEBUG ("inoculation invalid. ignoring"); return 0; } } } } ! free (checksum); } } /* Process the inoculation */ ! if (auth_user && auth_checksum) ! { ! inoculate_user (username, NULL, inoc_message); ! free (inoc_message); return DSR_ISSPAM; } } *************** *** 956,963 **** while (node_hnt != NULL) { field = (struct _ds_header_field *) node_hnt->ptr; ! if (field != NULL && field->heading != NULL ! && field->data != NULL) if (!strncasecmp (field->heading, "Content-Disposition", 19)) if (!strncasecmp (field->data, "attachment", 10)) is_attachment = 1; --- 1032,1039 ---- while (node_hnt != NULL) { field = (struct _ds_header_field *) node_hnt->ptr; ! if (field != NULL ! && field->heading != NULL && field->data != NULL) if (!strncasecmp (field->heading, "Content-Disposition", 19)) if (!strncasecmp (field->data, "attachment", 10)) is_attachment = 1; *************** *** 987,994 **** node_header = c_nt_first (block->headers, &c2); while (node_header != NULL) { ! struct _ds_header_field ! *header = (struct _ds_header_field *) node_header->ptr; if (!strcasecmp (header->heading, "Content-Transfer-Encoding")) { --- 1063,1070 ---- node_header = c_nt_first (block->headers, &c2); while (node_header != NULL) { ! struct _ds_header_field *header = ! (struct _ds_header_field *) node_header->ptr; if (!strcasecmp (header->heading, "Content-Transfer-Encoding")) { *************** *** 1071,1088 **** } } ! if (!have_signature && mode != DSM_PROCESS) { CTX->flags = CTX->flags ^ DSF_SIGNATURE; CTX->signature = NULL; } ! if (have_signature && mode != DSM_PROCESS) { #ifdef TEST_COND_TRAINING int do_train = 1, iter = 0, ck_result = 0; /* train until test conditions are met, 5 iterations max */ ! while(do_train && iter < 5) { DSPAM_CTX *CLX; int match = (CTX->mode == DSM_ADDSPAM) ? DSR_ISSPAM : DSR_ISINNOCENT; --- 1147,1166 ---- } } ! if (!have_signature && mode != DSM_PROCESS) { CTX->flags = CTX->flags ^ DSF_SIGNATURE; CTX->signature = NULL; } ! if (have_signature && mode != DSM_PROCESS) ! { #ifdef TEST_COND_TRAINING int do_train = 1, iter = 0, ck_result = 0; /* train until test conditions are met, 5 iterations max */ ! while (do_train && iter < 5) ! { DSPAM_CTX *CLX; int match = (CTX->mode == DSM_ADDSPAM) ? DSR_ISSPAM : DSR_ISINNOCENT; *************** *** 1092,1131 **** result = dspam_process (CTX, NULL); #ifdef TEST_COND_TRAINING ! if (iter > 1) { ! if (match == DSR_ISSPAM) { CTX->totals.spam_misclassified--; CTX->totals.total_spam--; ! } else { CTX->totals.innocent_misclassified--; CTX->totals.total_innocent--; } } ! LOGDEBUG("reclassifying iteration %d result: %d", iter, result); /* only attempt test-conditional training on a mature corpus */ if (CTX->totals.total_innocent < 4000 && CTX->mode == DSM_ADDSPAM) do_train = 0; ! else { /* CLX = Classify Context */ #ifdef CHAINED_TOKENS ! CLX = dspam_init (CTX->username, CTX->group, DSM_CLASSIFY, ! DSF_CHAINED | DSF_SIGNATURE); #else ! CLX = dspam_init (CTX->username, CTX->group, DSM_CLASSIFY, ! DSF_SIGNATURE); #endif ! if (!CLX) { do_train = 0; break; } CLX->signature = &SIG; ck_result = dspam_process (CLX, NULL); ! if (ck_result || CLX->result == match) do_train = 0; CLX->signature = NULL; ! dspam_destroy(CLX); } } #endif --- 1170,1215 ---- result = dspam_process (CTX, NULL); #ifdef TEST_COND_TRAINING ! if (iter > 1) ! { ! if (match == DSR_ISSPAM) ! { CTX->totals.spam_misclassified--; CTX->totals.total_spam--; ! } ! else ! { CTX->totals.innocent_misclassified--; CTX->totals.total_innocent--; } } ! LOGDEBUG ("reclassifying iteration %d result: %d", iter, result); /* only attempt test-conditional training on a mature corpus */ if (CTX->totals.total_innocent < 4000 && CTX->mode == DSM_ADDSPAM) do_train = 0; ! else ! { /* CLX = Classify Context */ #ifdef CHAINED_TOKENS ! CLX = dspam_init (CTX->username, CTX->group, ! DSM_CLASSIFY, DSF_CHAINED | DSF_SIGNATURE); #else ! CLX = dspam_init (CTX->username, CTX->group, ! DSM_CLASSIFY, DSF_SIGNATURE); #endif ! if (!CLX) ! { do_train = 0; break; } CLX->signature = &SIG; ck_result = dspam_process (CLX, NULL); ! if (ck_result || CLX->result == match) do_train = 0; CLX->signature = NULL; ! dspam_destroy (CLX); } } #endif *************** *** 1140,1164 **** result = CTX->result; ! if (result != DSR_ISSPAM && mode == DSM_PROCESS && CTX->confidence < 0.65) { struct nt_node *node_int; struct nt_c c_i; - - node_int = c_nt_first(classify_users, &c_i); - while(node_int != NULL && result != DSR_ISSPAM) { - LOGDEBUG("checking result for user %s", (const char *) node_int->ptr); - result = user_classify((const char *) node_int->ptr, CTX->signature, NULL); - if (result == DSR_ISSPAM) { - LOGDEBUG("CLASSIFY CATCH: %s", (const char *) node_int->ptr); - CTX->result = result; - } ! node_int = c_nt_next(classify_users, &c_i); } /* Add as spam */ ! if (result == DSR_ISSPAM) { CTX->mode = DSM_ADDSPAM; dspam_process (CTX, NULL); CTX->totals.spam_misclassified--; --- 1224,1253 ---- result = CTX->result; ! if (result != DSR_ISSPAM && mode == DSM_PROCESS && CTX->confidence < 0.65) ! { struct nt_node *node_int; struct nt_c c_i; ! node_int = c_nt_first (classify_users, &c_i); ! while (node_int != NULL && result != DSR_ISSPAM) ! { ! LOGDEBUG ("checking result for user %s", (const char *) node_int->ptr); ! result = user_classify ((const char *) node_int->ptr, ! CTX->signature, NULL); ! if (result == DSR_ISSPAM) ! { ! LOGDEBUG ("CLASSIFY CATCH: %s", (const char *) node_int->ptr); ! CTX->result = result; ! } ! ! node_int = c_nt_next (classify_users, &c_i); } /* Add as spam */ ! if (result == DSR_ISSPAM) ! { CTX->mode = DSM_ADDSPAM; dspam_process (CTX, NULL); CTX->totals.spam_misclassified--; *************** *** 1167,1193 **** } /* Inoculate other users: Signature */ ! if (have_signature && mode == DSM_ADDSPAM && inoc_users->items>0) { struct nt_node *node_int; ! struct nt_c c_i; ! node_int = c_nt_first(inoc_users, &c_i); ! while(node_int != NULL) { ! inoculate_user((const char *) node_int->ptr, &SIG, NULL); ! node_int = c_nt_next(inoc_users, &c_i); } } /* Inoculate other users: Corpus */ ! if (!have_signature && mode == DSM_ADDSPAM && flags & DAF_INOCULATE && inoc_users->items>0) { struct nt_node *node_int; struct nt_c c_i; ! node_int = c_nt_first(inoc_users, &c_i); ! while(node_int != NULL) { ! inoculate_user((const char *) node_int->ptr, NULL, message->data); ! node_int = c_nt_next(inoc_users, &c_i); } ! inoculate_user(username, NULL, message->data); return DSR_ISSPAM; } --- 1256,1287 ---- } /* Inoculate other users: Signature */ ! if (have_signature && mode == DSM_ADDSPAM && inoc_users->items > 0) ! { struct nt_node *node_int; ! struct nt_c c_i; ! node_int = c_nt_first (inoc_users, &c_i); ! while (node_int != NULL) ! { ! inoculate_user ((const char *) node_int->ptr, &SIG, NULL); ! node_int = c_nt_next (inoc_users, &c_i); } } /* Inoculate other users: Corpus */ ! if (!have_signature && mode == DSM_ADDSPAM && flags & DAF_INOCULATE ! && inoc_users->items > 0) ! { struct nt_node *node_int; struct nt_c c_i; ! node_int = c_nt_first (inoc_users, &c_i); ! while (node_int != NULL) ! { ! inoculate_user ((const char *) node_int->ptr, NULL, message->data); ! node_int = c_nt_next (inoc_users, &c_i); } ! inoculate_user (username, NULL, message->data); return DSR_ISSPAM; } *************** *** 1205,1211 **** valid = 1; } ! LOGDEBUG("saved signature as %s", session); #ifdef SIGNATURE_ATTACHMENTS --- 1299,1305 ---- valid = 1; } ! LOGDEBUG ("saved signature as %s", session); #ifdef SIGNATURE_ATTACHMENTS *************** *** 1632,1638 **** #endif } ! write_web_stats ((CTX->group == NULL) ? username : CTX->group, &CTX->totals); LOGDEBUG ("libdspam returned probability of %f, message result: %s", CTX->probability, (result != DSR_ISSPAM) ? "NOT SPAM" : "SPAM"); --- 1726,1733 ---- #endif } ! write_web_stats ((CTX->group == NULL) ? username : CTX->group, ! &CTX->totals); LOGDEBUG ("libdspam returned probability of %f, message result: %s", CTX->probability, (result != DSR_ISSPAM) ? "NOT SPAM" : "SPAM"); *************** *** 1693,1699 **** else LOG (LOG_CRIT, ERROR_MEM_ALLOC); ! if (result == DSR_ISSPAM) { head = malloc (sizeof (struct _ds_header_field)); if (head != NULL) { --- 1788,1795 ---- else LOG (LOG_CRIT, ERROR_MEM_ALLOC); ! if (result == DSR_ISSPAM) ! { head = malloc (sizeof (struct _ds_header_field)); if (head != NULL) { *************** *** 1746,1755 **** { block = (struct _ds_message_block *) node_nt->ptr; ! if (block-> ! terminating_boundary != ! NULL && !strcmp (block->terminating_boundary, term) ! && term[0] != 0) { struct nt_node *old; free (block->terminating_boundary); --- 1842,1849 ---- { block = (struct _ds_message_block *) node_nt->ptr; ! if (block->terminating_boundary != NULL ! && !strcmp (block->terminating_boundary, term) && term[0] != 0) { struct nt_node *old; free (block->terminating_boundary); *************** *** 1777,1784 **** char term[512]; char scratch[128]; ! snprintf (scratch, sizeof (scratch), "%s%s%s\n", SIGNATURE_BEGIN, ! session, SIGNATURE_END); /* Create new message block */ newblock = --- 1871,1878 ---- char term[512]; char scratch[128]; ! snprintf (scratch, sizeof (scratch), ! "%s%s%s\n", SIGNATURE_BEGIN, session, SIGNATURE_END); /* Create new message block */ newblock = *************** *** 1809,1816 **** newblock->body = buffer_create (scratch); newblock->original_signed_body = NULL; ! field = ! (struct _ds_header_field *) malloc (sizeof (struct _ds_header_field)); if (field == NULL) { --- 1903,1909 ---- newblock->body = buffer_create (scratch); newblock->original_signed_body = NULL; ! field = (struct _ds_header_field *) malloc (sizeof (struct _ds_header_field)); if (field == NULL) { *************** *** 1822,1829 **** field->data = strdup ("text/plain; name=\"dspam.txt\""); nt_add (newblock->headers, field); ! field = ! (struct _ds_header_field *) malloc (sizeof (struct _ds_header_field)); if (field == NULL) { --- 1915,1921 ---- field->data = strdup ("text/plain; name=\"dspam.txt\""); nt_add (newblock->headers, field); ! field = (struct _ds_header_field *) malloc (sizeof (struct _ds_header_field)); if (field == NULL) { *************** *** 1944,1950 **** { char ip[32]; char mta_whitelist[MAX_FILENAME_LENGTH]; ! snprintf(mta_whitelist, MAX_FILENAME_LENGTH, "%s/mta.whitelist", USERDIR); if (!dspam_getsource (CTX, ip, sizeof (ip), mta_whitelist)) { --- 2036,2043 ---- { char ip[32]; char mta_whitelist[MAX_FILENAME_LENGTH]; ! snprintf (mta_whitelist, MAX_FILENAME_LENGTH, ! "%s/mta.whitelist", USERDIR); if (!dspam_getsource (CTX, ip, sizeof (ip), mta_whitelist)) { *************** *** 1964,1971 **** _ds_destroy_message (CTX->message); dspam_destroy (CTX); ! nt_destroy(inoc_users); ! nt_destroy(classify_users); return result; } --- 2057,2064 ---- _ds_destroy_message (CTX->message); dspam_destroy (CTX); ! nt_destroy (inoc_users); ! nt_destroy (classify_users); return result; } *************** *** 1981,1988 **** FILE *file; int rc; ! if (mailer_args == NULL) { ! fputs(message, stdout); return 0; } --- 2074,2082 ---- FILE *file; int rc; ! if (mailer_args == NULL) ! { ! fputs (message, stdout); return 0; } *************** *** 2057,2071 **** char filename[MAX_FILENAME_LENGTH]; FILE *file; int line = 1; ! char *x, *msg = strdup(message); ! if (msg == NULL) { ! LOG(LOG_CRIT, ERROR_MEM_ALLOC); return EUNKNOWN; } ! if (quarantine_lock (username)) { ! free(msg); return EFILE; } --- 2151,2167 ---- char filename[MAX_FILENAME_LENGTH]; FILE *file; int line = 1; ! char *x, *msg = strdup (message); ! if (msg == NULL) ! { ! LOG (LOG_CRIT, ERROR_MEM_ALLOC); return EUNKNOWN; } ! if (quarantine_lock (username)) ! { ! free (msg); return EFILE; } *************** *** 2075,2081 **** { file_error (ERROR_FILE_WRITE, filename, strerror (errno)); quarantine_unlock (username); ! free(msg); return EFILE; } --- 2171,2177 ---- { file_error (ERROR_FILE_WRITE, filename, strerror (errno)); quarantine_unlock (username); ! free (msg); return EFILE; } *************** *** 2089,2109 **** fputs (head, file); } ! x = strsep(&msg, "\n"); ! while(x != NULL) { ! if (!strncmp(x, "From ", 5) && line != 1) ! fputs(">", file); ! fputs(x, file); ! fputs("\n", file); line++; ! x = strsep(&msg, "\n"); } fputs ("\n\n", file); fclose (file); quarantine_unlock (username); ! free(msg); return 0; } --- 2185,2206 ---- fputs (head, file); } ! x = strsep (&msg, "\n"); ! while (x != NULL) ! { ! if (!strncmp (x, "From ", 5) && line != 1) ! fputs (">", file); ! fputs (x, file); ! fputs ("\n", file); line++; ! x = strsep (&msg, "\n"); } fputs ("\n\n", file); fclose (file); quarantine_unlock (username); ! free (msg); return 0; } *************** *** 2128,2140 **** return EFILE; } ! fprintf (file, "%ld,%ld,%ld,%ld,%ld,%ld\n", ! totals->total_spam - (totals->spam_misclassified + totals->spam_corpusfed), ! totals->total_innocent - (totals->innocent_misclassified + totals->innocent_corpusfed), ! totals->spam_misclassified, ! totals->innocent_misclassified, ! totals->spam_corpusfed, ! totals->innocent_corpusfed); fclose (file); return 0; } --- 2225,2237 ---- return EFILE; } ! fprintf (file, "%ld,%ld,%ld,%ld,%ld,%ld\n", ! totals->total_spam - (totals->spam_misclassified + ! totals->spam_corpusfed), ! totals->total_innocent - (totals->innocent_misclassified + ! totals->innocent_corpusfed), ! totals->spam_misclassified, totals->innocent_misclassified, ! totals->spam_corpusfed, totals->innocent_corpusfed); fclose (file); return 0; } *************** *** 2282,2345 **** parameters: only SIG _OR_ message should be passed. the other should be left NULL depending on whether we have a signature or a message ! */ int ! inoculate_user (const char *username, struct _ds_spam_signature *SIG, const char *message) { DSPAM_CTX *INOC; int do_inoc = 1, result = 0; ! LOGDEBUG("checking to see if user %s requires this inoculation", username); ! /* First see if the user needs to be inoculated */ #ifdef CHAINED_TOKENS INOC = dspam_init (username, NULL, DSM_CLASSIFY, DSF_CHAINED); #else INOC = dspam_init (username, NULL, DSM_CLASSIFY, 0); #endif ! if (INOC) { ! if (SIG) { INOC->flags = INOC->flags ^ DSF_SIGNATURE; INOC->signature = SIG; result = dspam_process (INOC, NULL); ! } else { INOC->flags = INOC->flags ^ DSF_CORPUS; result = dspam_process (INOC, message); } ! if (!result && INOC->result == DSR_ISSPAM) do_inoc = 0; if (SIG) INOC->signature = NULL; ! dspam_destroy(INOC); } ! ! if (!do_inoc) { ! LOGDEBUG("skipping user %s: doesn't require inoculation", username); return EFAILURE; ! } else { ! LOGDEBUG("inoculating user %s", username); #ifdef CHAINED_TOKENS INOC = dspam_init (username, NULL, DSM_ADDSPAM, DSF_CHAINED | DSF_INOCULATE); #else INOC = dspam_init (username, NULL, DSM_ADDSPAM, DSF_INOCULATE); #endif ! if (INOC) { ! if (SIG) { INOC->flags = INOC->flags ^ DSF_SIGNATURE; INOC->signature = SIG; result = dspam_process (INOC, NULL); ! } else { INOC->flags = INOC->flags ^ DSF_CORPUS; result = dspam_process (INOC, message); } if (SIG) INOC->signature = NULL; ! dspam_destroy(INOC); } } --- 2379,2454 ---- parameters: only SIG _OR_ message should be passed. the other should be left NULL depending on whether we have a signature or a message ! */ int ! inoculate_user (const char *username, struct _ds_spam_signature *SIG, ! const char *message) { DSPAM_CTX *INOC; int do_inoc = 1, result = 0; ! LOGDEBUG ("checking to see if user %s requires this inoculation", username); ! /* First see if the user needs to be inoculated */ #ifdef CHAINED_TOKENS INOC = dspam_init (username, NULL, DSM_CLASSIFY, DSF_CHAINED); #else INOC = dspam_init (username, NULL, DSM_CLASSIFY, 0); #endif ! if (INOC) ! { ! if (SIG) ! { INOC->flags = INOC->flags ^ DSF_SIGNATURE; INOC->signature = SIG; result = dspam_process (INOC, NULL); ! } ! else ! { INOC->flags = INOC->flags ^ DSF_CORPUS; result = dspam_process (INOC, message); } ! if (!result && INOC->result == DSR_ISSPAM) do_inoc = 0; if (SIG) INOC->signature = NULL; ! dspam_destroy (INOC); } ! ! if (!do_inoc) ! { ! LOGDEBUG ("skipping user %s: doesn't require inoculation", username); return EFAILURE; ! } ! else ! { ! LOGDEBUG ("inoculating user %s", username); #ifdef CHAINED_TOKENS INOC = dspam_init (username, NULL, DSM_ADDSPAM, DSF_CHAINED | DSF_INOCULATE); #else INOC = dspam_init (username, NULL, DSM_ADDSPAM, DSF_INOCULATE); #endif ! if (INOC) ! { ! if (SIG) ! { INOC->flags = INOC->flags ^ DSF_SIGNATURE; INOC->signature = SIG; result = dspam_process (INOC, NULL); ! } ! else ! { INOC->flags = INOC->flags ^ DSF_CORPUS; result = dspam_process (INOC, message); } if (SIG) INOC->signature = NULL; ! dspam_destroy (INOC); } } *************** *** 2354,2376 **** int ! user_classify (const char *username, struct _ds_spam_signature *SIG, const char *message) { DSPAM_CTX *CLX; int result = 0; ! /* First see if the user needs to be inoculated */ #ifdef CHAINED_TOKENS CLX = dspam_init (username, NULL, DSM_CLASSIFY, DSF_CHAINED); #else CLX = dspam_init (username, NULL, DSM_CLASSIFY, 0); #endif ! if (CLX) { ! if (SIG) { CLX->flags = CLX->flags ^ DSF_SIGNATURE; CLX->signature = SIG; result = dspam_process (CLX, NULL); ! } else { CLX->flags = CLX->flags ^ DSF_CORPUS; result = dspam_process (CLX, message); } --- 2463,2490 ---- int ! user_classify (const char *username, struct _ds_spam_signature *SIG, ! const char *message) { DSPAM_CTX *CLX; int result = 0; ! /* First see if the user needs to be inoculated */ #ifdef CHAINED_TOKENS CLX = dspam_init (username, NULL, DSM_CLASSIFY, DSF_CHAINED); #else CLX = dspam_init (username, NULL, DSM_CLASSIFY, 0); #endif ! if (CLX) ! { ! if (SIG) ! { CLX->flags = CLX->flags ^ DSF_SIGNATURE; CLX->signature = SIG; result = dspam_process (CLX, NULL); ! } ! else ! { CLX->flags = CLX->flags ^ DSF_CORPUS; result = dspam_process (CLX, message); } *************** *** 2378,2391 **** if (SIG) CLX->signature = NULL; ! if (result) { ! LOGDEBUG("user_classify() returned error %d", result); result = 0; } else result = CLX->result; ! ! dspam_destroy(CLX); } return result; --- 2492,2506 ---- if (SIG) CLX->signature = NULL; ! if (result) ! { ! LOGDEBUG ("user_classify() returned error %d", result); result = 0; } else result = CLX->result; ! ! dspam_destroy (CLX); } return result; Index: dspam/dspam.h diff -c dspam/dspam.h:1.1.1.4 dspam/dspam.h:1.1.1.4.2.1 *** dspam/dspam.h:1.1.1.4 Fri Oct 31 15:34:14 2003 --- dspam/dspam.h Sat Nov 15 18:34:58 2003 *************** *** 53,66 **** /* Public agent functions */ int deliver_message (const char *message, const char *mailer_args, const char *username, int mode); ! int process_message (char *group, size_t size, buffer * message, const char *username, int mode, int flags); int write_web_stats (const char *username, struct _ds_spam_totals *totals); int quarantine_message (const char *message, const char *username); int quarantine_unlock (const char *username); int quarantine_lock (const char *username); ! int inoculate_user (const char *username, struct _ds_spam_signature *SIG, const char *message); ! int user_classify (const char *username, struct _ds_spam_signature *SIG, const char *message); /* DO NOT MODIFY BELOW THIS LINE */ --- 53,68 ---- /* Public agent functions */ int deliver_message (const char *message, const char *mailer_args, const char *username, int mode); ! int process_message (char *group, size_t size, buffer * message, const char *username, int mode, int flags); int write_web_stats (const char *username, struct _ds_spam_totals *totals); int quarantine_message (const char *message, const char *username); int quarantine_unlock (const char *username); int quarantine_lock (const char *username); ! int inoculate_user (const char *username, struct _ds_spam_signature *SIG, ! const char *message); ! int user_classify (const char *username, struct _ds_spam_signature *SIG, ! const char *message); /* DO NOT MODIFY BELOW THIS LINE */ Index: dspam/dspam.spec diff -c /dev/null dspam/dspam.spec:1.49.4.2 *** /dev/null Sat Nov 15 20:45:12 2003 --- dspam/dspam.spec Sat Nov 15 20:40:53 2003 *************** *** 0 **** --- 1,292 ---- + %ifos Linux + %define sendmailcf /usr/share/sendmail-cf + %define cgibin /var/www/cgi-bin + %define htmldir /var/www/html + %else + %define sendmailcf /usr/lib/sendmail-cf + %define cgibin /usr/local/www/cgi-bin + %define htmldir /Public + %endif + + Summary: A library and Mail Delivery Agent for Bayesian spam filtering + Name: dspam + Version: 2.8.beta.2 + Release: 1 + Copyright: GPL + URL: http://www.networkdweebs.com/software/dspam/ + Group: System Environment/Daemons + Source: http://bmsi.com/linux/dspam-%{version}.tar.gz + Source1: dspam.m4 + Patch: dspam-2.8.patch + Buildroot: /var/tmp/dspam-root + %ifos Linux + BuildRequires: db3-devel patch + Requires: /usr/sbin/useradd + %else + %ifos aix4.1 + BuildRequires: db3-devel patch + %else + BuildRequires: db4-devel patch + %endif + %endif + + %package devel + Summary: Developers library for custom access to dspam + Group: Development/Libraries + + %description + DSPAM (as in De-Spam) is an open-source project to create a new kind of + anti-spam mechanism, and is currently effective as both a server-side agent + for UNIX email servers and a developer's library for mail clients, other + anti-spam tools, and similar projects requiring drop-in spam filtering. + + The DSPAM agent masquerades as the email server's local delivery agent and + filters/learns spams using an advanced Bayesian statistical approach (based on + Baye's theorem of combined probabilities) which provides an administratively + maintenance-free, easy-learning Anti-Spam service custom tailored to each + individual user's behavior. Advanced because on top of standard Bayesian + filtering is also incorporated the use of Chained Tokens, de-obfuscation, and + other enhancements. DSPAM works great with Sendmail and Exim, and should work + well with any other MTA that supports an external local delivery agent + (postfix, qmail, etc.) + + %description devel + DSPAM has had its core engine moved into a separate library, libdspam. + This library can be used by developers to provide 'drop-in' spam filtering for + their mail client applications, other anti-spam tools, or similar projects. + + %prep + %setup -q + %patch -p0 + #%patch1 -p1 + + %build + %ifos aix4.1 + export CC="gcc -mthreads" + LDFLAGS="-Wl,-blibpath:/lib:/usr/local/lib" + %else + LDFLAGS=-s + %endif + CFLAGS="$RPM_OPT_FLAGS" + export CFLAGS LDFLAGS + ./configure --with-userdir=/var/lib/dspam \ + --with-userdir-owner=none \ + --with-userdir-group=none \ + --with-dspam-owner=none \ + --with-dspam-group=none \ + %ifos aix4.1 + --with-local-delivery-agent=/bin/bellmail \ + %endif + --with-storage-driver=libdb3_drv \ + --disable-dependency-tracking + + make + mv dspam dspam.optout + rm dspam.o + make dspam CPPFLAGS=-DOPT_IN + ln dspam dspam.optin + + %install + rm -rf $RPM_BUILD_ROOT + make install DESTDIR=$RPM_BUILD_ROOT + + # include both optin and optout version of dspam + cp dspam.optout $RPM_BUILD_ROOT/usr/local/bin + cd $RPM_BUILD_ROOT/usr/local/bin + mv dspam dspam.optin + ln -s dspam.optout dspam + cd - + + # allow others to query stats + chmod g+s $RPM_BUILD_ROOT/usr/local/bin/dspam_stats + + # manually copy include files needed for devel package + INCDIR="$RPM_BUILD_ROOT/usr/local/include" + mkdir -p $INCDIR + cp -p libdspam.h libdspam_objects.h lht.h nodetree.h $INCDIR + + # provide maintenance scripts + ETCDIR="$RPM_BUILD_ROOT/etc" + mkdir -p $ETCDIR/cron.hourly + mkdir -p $ETCDIR/cron.daily + mkdir -p $ETCDIR/cron.weekly + cat >$ETCDIR/cron.daily/dspam <<'EOF' + #!/bin/sh + /usr/local/bin/dspam_clean + EOF + chmod a+x $ETCDIR/cron.daily/dspam + cat >$ETCDIR/cron.weekly/dspam <<'EOF' + #!/bin/sh + /usr/local/bin/dspam_purge + EOF + chmod a+x $ETCDIR/cron.weekly/dspam + cat >$ETCDIR/cron.hourly/dspam <<'EOF' + #!/bin/sh + cd /var/lib/dspam + exec >>reprocess.log 2>&1 + /usr/local/bin/pydspam_process *.spam *.fp + EOF + chmod a+x $ETCDIR/cron.hourly/dspam + + # install script for optional smart spam alias + cp -p addspam.sh $RPM_BUILD_ROOT/usr/local/bin/addspam + cd $RPM_BUILD_ROOT/usr/local/bin + ln addspam falsepositive + cd - + mkdir -p $RPM_BUILD_ROOT/var/log + touch $RPM_BUILD_ROOT/var/log/dspam.log + + # allow dspam in /etc/smrsh + mkdir -p $ETCDIR/smrsh + ln -sf /usr/local/bin/dspam $ETCDIR/smrsh + ln -sf /usr/local/bin/addspam $ETCDIR/smrsh + + # install sendmail mailer + mkdir -p $RPM_BUILD_ROOT%{sendmailcf}/mailer + cp -p %{SOURCE1} $RPM_BUILD_ROOT%{sendmailcf}/mailer + + # install CGI script + CGIDIR="$RPM_BUILD_ROOT%{cgibin}" + HTMLDIR="$RPM_BUILD_ROOT%{htmldir}" + mkdir -p $HTMLDIR/dspam + mkdir -p $CGIDIR + mkdir -p $RPM_BUILD_ROOT/etc/mail + ln -sf /var/lib/dspam $RPM_BUILD_ROOT/etc/mail/dspam + cp -p cgi/* $HTMLDIR/dspam + %ifos aix4.1 + # No suexec on our AIX installs + cat >$CGIDIR/dspam.cgi <<'EOF' + #!/bin/sh + cd %{htmldir}/dspam + exec /usr/local/bin/perl dspam.cgi + EOF + %else + # Use suexec to run CGI + cat >$CGIDIR/dspam.cgi <<'EOF' + #!/bin/sh + cd %{htmldir}/dspam + exec /usr/sbin/suexec dspam dspam dspam.cgi + EOF + %endif + chmod 0755 $HTMLDIR/dspam $HTMLDIR/dspam/dspam.cgi + + %clean + rm -rf $RPM_BUILD_ROOT + + %ifos linux + %pre + /usr/sbin/useradd -G mail -d /var/lib/dspam -c "Dspam agent" -s /dev/null \ + dspam >/dev/null 2>&1 || : + + %post + if grep '^/usr/local/lib$' /etc/ld.so.conf >/dev/null; then + : + else + echo "/usr/local/lib" >>/etc/ld.so.conf + fi + /sbin/ldconfig + %endif + %ifos aix4.1 + %pre + mkuser -a pgrp=mail home=/var/lib/dspam \ + gecos="DSpam mail filter" dspam 2>/dev/null || : + %endif + + %files + %defattr(-,root,root) + %doc README CHANGE CHANGE.sdg dspam-button.gif + %ifnos aix4.1 + /usr/local/lib/libdspam.so.3.0.0 + /usr/local/lib/libdspam.so.3 + %endif + %attr(02511,root,mail)/usr/local/bin/dspam.optin + %attr(02511,root,mail)/usr/local/bin/dspam.optout + %attr(-,root,mail)/usr/local/bin/dspam + %attr(-,root,mail)/usr/local/bin/dspam_clean + %attr(-,root,mail)/usr/local/bin/dspam_convert + %attr(-,root,mail)/usr/local/bin/dspam_crc + %attr(-,root,mail)/usr/local/bin/dspam_dump + %attr(-,root,mail)/usr/local/bin/dspam_purge + %attr(-,root,mail)/usr/local/bin/dspam_stats + /usr/local/bin/dspam_corpus + /usr/local/bin/dspam_genaliases + %attr(0775,root,mail) /var/lib/dspam + /etc/cron.daily/dspam + /etc/cron.weekly/dspam + /etc/smrsh/dspam + /etc/smrsh/addspam + %{sendmailcf}/mailer/* + %attr(-,dspam,dspam)%{htmldir}/dspam + %attr(0755,root,root)%{cgibin}/dspam.cgi + /etc/mail/dspam + %config %attr(0755,root,mail)/usr/local/bin/addspam + %config %attr(0755,root,mail)/usr/local/bin/falsepositive + %attr(0664,root,mail)/var/log/addspam + + %files devel + %defattr(-,root,root) + %ifnos aix4.1 + /usr/local/lib/libdspam.so + %endif + /usr/local/lib/libdspam.la + /usr/local/lib/libdspam.a + /usr/local/include/* + + %changelog + * Sat Nov 15 2003 Stuart Gathman 2.8.beta.2-1 + - remove python subpackage, moved to pydspam RPM + - Support 2.8 + * Tue Oct 21 2003 Stuart Gathman 2.6.5.2-4 + - pydspam-1.1.4 + - run pydspam_process on the hour + - Count signature spam corpus as miss + - Remove "Delete All" from CGI and default messages to checked. + * Wed Sep 10 2003 Stuart Gathman + - Fix memory leaks + - Increase lock timeout + - Make dspam sgid and a+x so that generic addspam works + - Install optin and optout versions. + * Sat Sep 06 2003 Stuart Gathman + - Merge dspam-2.6.5.2 + - Move cgi to /var/www/html/dspam. logo and css weren't getting + - found under cgi-bin. + * Fri Sep 05 2003 Stuart Gathman + - Modify tbt.c to use parent pointer and eliminate recursion which + - was overflowing thread stack on AIX + * Tue Sep 02 2003 Stuart Gathman + - Merge changes for release 2.6.5 + - use pydspam 1.1.1 + * Wed Aug 27 2003 Stuart Gathman + - Tweak for AIX + * Thu Aug 18 2003 Stuart Gathman + - Merge changes for 2.6.4.01 + - empty input patch + - Include smart spam alias + * Thu Aug 14 2003 Stuart Gathman + - Merge changes for 2.6.4 + * Mon Aug 04 2003 Stuart Gathman + - Install CGI script to run as dspam user + * Thu Jul 31 2003 Stuart Gathman + - Make building python package optional + - OK, OK, so maybe it should be a separate RPM + * Wed Jul 30 2003 Stuart Gathman + - Fix dspam_stats bug for release 2 + * Wed Jul 30 2003 Stuart Gathman + - Move python source to pydspam project + - merge dspam-2.6.2.02 from networkdweebs + * Fri Jul 11 2003 Stuart Gathman + - Move python support to sub package + - fix CORPUS bug + * Thu Jul 10 2003 Stuart Gathman + - Bug fixes, python support. + * Thu Jul 03 2003 Stuart Gathman + - Merge with 2.6.2 stable + * Wed Jul 02 2003 Stuart Gathman + - Fix bugs in DSF_CLASSIFY + * Mon Jun 30 2003 Stuart Gathman + - Fix bugs in dspam.c and libdspam.c + * Thu Jun 26 2003 Stuart Gathman + - Add dspam to /etc/smrsh + - Add dspam mailer to sendmail-cf + * Wed Jun 25 2003 Stuart Gathman + - Linux RPM Index: dspam/error.c diff -c dspam/error.c:1.1.1.4 dspam/error.c:1.1.1.4.2.1 *** dspam/error.c:1.1.1.4 Fri Oct 17 16:08:03 2003 --- dspam/error.c Sat Nov 15 18:34:58 2003 *************** *** 98,104 **** char ct[128]; char fn[MAX_FILENAME_LENGTH]; ! snprintf(fn, sizeof(fn), "%s/dspam.debug", USERDIR); tm = time (NULL); snprintf (ct, sizeof (ct), "%s", ctime (&tm)); --- 98,104 ---- char ct[128]; char fn[MAX_FILENAME_LENGTH]; ! snprintf (fn, sizeof (fn), "%s/dspam.debug", USERDIR); tm = time (NULL); snprintf (ct, sizeof (ct), "%s", ctime (&tm)); Index: dspam/example.c diff -c dspam/example.c:1.1.1.4 dspam/example.c:1.1.1.4.2.1 *** dspam/example.c:1.1.1.4 Fri Oct 24 14:53:10 2003 --- dspam/example.c Sat Nov 15 18:34:58 2003 *************** *** 20,27 **** struct _ds_spam_signature SIG; /* Example signature */ /* Performs any driver-specific startup functions ! (such as initializing internal lock tables) */ ! dspam_init_driver(); /* read in the message from stdin */ message[0] = 0; --- 20,27 ---- struct _ds_spam_signature SIG; /* Example signature */ /* Performs any driver-specific startup functions ! * (such as initializing internal lock tables) */ ! dspam_init_driver (); /* read in the message from stdin */ message[0] = 0; *************** *** 210,216 **** } /* Performs any driver-specific shutdown functions */ ! dspam_shutdown_driver(); exit (EXIT_SUCCESS); --- 210,216 ---- } /* Performs any driver-specific shutdown functions */ ! dspam_shutdown_driver (); exit (EXIT_SUCCESS); Index: dspam/libdb3_drv.c diff -c dspam/libdb3_drv.c:1.1.1.1 dspam/libdb3_drv.c:1.1.1.1.2.1 *** dspam/libdb3_drv.c:1.1.1.1 Mon Nov 3 09:57:27 2003 --- dspam/libdb3_drv.c Sat Nov 15 18:34:58 2003 *************** *** 59,66 **** int dspam_init_driver (void) { ! _libdb3_drv_locks = nt_create(NT_PTR); ! if (_libdb3_drv_locks == NULL) return EUNKNOWN; return 0; --- 59,66 ---- int dspam_init_driver (void) { ! _libdb3_drv_locks = nt_create (NT_PTR); ! if (_libdb3_drv_locks == NULL) return EUNKNOWN; return 0; *************** *** 69,75 **** int dspam_shutdown_driver (void) { ! nt_destroy(_libdb3_drv_locks); return 0; } --- 69,75 ---- int dspam_shutdown_driver (void) { ! nt_destroy (_libdb3_drv_locks); return 0; } *************** *** 94,112 **** ret = (*s->db->get) (s->db, NULL, &key, &data, 0); if (ret) { ! if (ret == DB_RUNRECOVERY) { ! if (! _libdb3_drv_recover(CTX, 1)) { return _libdb3_drv_get_spamtotals (CTX); ! } else { return EUNKNOWN; } ! } else { LOGDEBUG ("_ds_get_totals: db->get failed: %s", db_strerror (ret)); return EFAILURE; } } ! memset(&CTX->totals, 0, sizeof(struct _ds_spam_totals)); memcpy (&CTX->totals, data.data, data.size); return 0; --- 94,118 ---- ret = (*s->db->get) (s->db, NULL, &key, &data, 0); if (ret) { ! if (ret == DB_RUNRECOVERY) ! { ! if (!_libdb3_drv_recover (CTX, 1)) ! { return _libdb3_drv_get_spamtotals (CTX); ! } ! else ! { return EUNKNOWN; } ! } ! else ! { LOGDEBUG ("_ds_get_totals: db->get failed: %s", db_strerror (ret)); return EFAILURE; } } ! memset (&CTX->totals, 0, sizeof (struct _ds_spam_totals)); memcpy (&CTX->totals, data.data, data.size); return 0; *************** *** 141,153 **** ret = (*s->db->put) (s->db, NULL, &key, &data, 0); if (ret) { ! if (ret == DB_RUNRECOVERY) { ! if (! _libdb3_drv_recover(CTX, 1)) { return _libdb3_drv_set_spamtotals (CTX); ! } else { return EUNKNOWN; } ! } else { LOGDEBUG ("_ds_set_totals: db->set failed: %s", db_strerror (ret)); return EFAILURE; } --- 147,165 ---- ret = (*s->db->put) (s->db, NULL, &key, &data, 0); if (ret) { ! if (ret == DB_RUNRECOVERY) ! { ! if (!_libdb3_drv_recover (CTX, 1)) ! { return _libdb3_drv_set_spamtotals (CTX); ! } ! else ! { return EUNKNOWN; } ! } ! else ! { LOGDEBUG ("_ds_set_totals: db->set failed: %s", db_strerror (ret)); return EFAILURE; } *************** *** 234,247 **** ret = (*s->db->get) (s->db, NULL, &key, &data, 0); ! if (ret) { ! if (ret == DB_RUNRECOVERY) { ! if (! _libdb3_drv_recover(CTX, 1)) { return _ds_get_spamrecord (CTX, token, stat); ! } else { return EUNKNOWN; } ! } else { return EFAILURE; } } --- 246,266 ---- ret = (*s->db->get) (s->db, NULL, &key, &data, 0); ! if (ret) ! { ! if (ret == DB_RUNRECOVERY) ! { ! if (!_libdb3_drv_recover (CTX, 1)) ! { return _ds_get_spamrecord (CTX, token, stat); ! } ! else ! { return EUNKNOWN; } ! } ! else ! { return EFAILURE; } } *************** *** 298,310 **** if (ret) { ! if (ret == DB_RUNRECOVERY) { ! if (! _libdb3_drv_recover(CTX, 1)) { return _ds_set_spamrecord (CTX, token, stat); ! } else { return EUNKNOWN; } ! } else { LOGDEBUG ("_ds_set_spamrecord: db->put failed: %s", db_strerror (ret)); return EFAILURE; } --- 317,335 ---- if (ret) { ! if (ret == DB_RUNRECOVERY) ! { ! if (!_libdb3_drv_recover (CTX, 1)) ! { return _ds_set_spamrecord (CTX, token, stat); ! } ! else ! { return EUNKNOWN; } ! } ! else ! { LOGDEBUG ("_ds_set_spamrecord: db->put failed: %s", db_strerror (ret)); return EFAILURE; } *************** *** 343,350 **** } else { ! LOGDEBUG("entering recovery mode"); ! free(CTX->storage); s = malloc (sizeof (struct _libdb3_drv_storage)); if (s == NULL) { --- 368,375 ---- } else { ! LOGDEBUG ("entering recovery mode"); ! free (CTX->storage); s = malloc (sizeof (struct _libdb3_drv_storage)); if (s == NULL) { *************** *** 352,358 **** LOG (LOG_CRIT, ERROR_MEM_ALLOC); return EUNKNOWN; } ! s->db = NULL; s->sig = NULL; s->env = NULL; --- 377,383 ---- LOG (LOG_CRIT, ERROR_MEM_ALLOC); return EUNKNOWN; } ! s->db = NULL; s->sig = NULL; s->env = NULL; *************** *** 395,426 **** } */ ! if (!recovery) { CTX->result = ! s->env->open (s->env, db_home, DB_CREATE | DB_INIT_LOCK | ! DB_INIT_MPOOL, 0); ! } else if (recovery == 1) { CTX->result = s->env->open (s->env, db_home, ! DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_RECOVER_FATAL, 0); ! } else { CTX->result = s->env->open (s->env, db_home, ! DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_RECOVER, 0); } ! if (CTX->result) { if (recovery || CTX->result != DB_RUNRECOVERY) { ! LOG (LOG_WARNING, "DB_ENV->open failed: %s", db_strerror (CTX->result)); return EFAILURE; } else { ! recovery = 1; ! return _ds_init_storage (CTX); } } --- 420,458 ---- } */ ! if (!recovery) ! { CTX->result = ! s->env->open (s->env, db_home, DB_CREATE | DB_INIT_LOCK | ! DB_INIT_MPOOL, 0); ! } ! else if (recovery == 1) ! { CTX->result = s->env->open (s->env, db_home, ! DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_RECOVER_FATAL, 0); ! } ! else ! { CTX->result = s->env->open (s->env, db_home, ! DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_RECOVER, 0); } ! if (CTX->result) ! { if (recovery || CTX->result != DB_RUNRECOVERY) { ! LOG (LOG_WARNING, "DB_ENV->open failed: %s", ! db_strerror (CTX->result)); return EFAILURE; } else { ! recovery = 1; ! return _ds_init_storage (CTX); } } *************** *** 445,451 **** else { recovery = 1; ! s->env->close(s->env, 0); return _ds_init_storage (CTX); } --- 477,483 ---- else { recovery = 1; ! s->env->close (s->env, 0); return _ds_init_storage (CTX); } *************** *** 474,530 **** else { recovery = 1; ! s->db->close(s->db, 0); ! s->env->close(s->env, 0); return _ds_init_storage (CTX); } } /* Obtain a lock for this user */ ! lock_result = _libdb3_drv_lock_get(CTX->username); ! if (lock_result < 0) { ! LOGDEBUG("locking subsystem returned error"); return EUNKNOWN; } ! ! if (lock_result > 0) { int i = 0; ! LOGDEBUG("acquiring lock"); /* Run two instances of lock detection */ ! lock_detect(s->env, 0, DB_LOCK_OLDEST, NULL); ! lock_detect(s->env, 0, DB_LOCK_OLDEST, NULL); s->locker = 0; if ((CTX->result = lock_id (s->env, &s->locker)) != 0) { LOG (LOG_WARNING, "unable to get a locker id for %s: %s", ! CTX->username, db_strerror (CTX->result)); return EUNKNOWN; } dbt.data = CTX->username; dbt.size = strlen (CTX->username); while ((CTX->result = ! lock_get (s->env, s->locker, DB_LOCK_NOWAIT, &dbt, ! DB_LOCK_WRITE, &s->lock)) != 0 && i<120) { ! LOGDEBUG("spinning lock %d/120", i); i++; ! lock_detect(s->env, 0, DB_LOCK_OLDEST, NULL); ! lock_detect(s->env, 0, DB_LOCK_OLDEST, NULL); ! sleep(1); } ! if (CTX->result) { ! if (!recovery) { recovery = 2; ! return _ds_init_storage(CTX); ! } else { LOG (LOG_WARNING, ! "unable to obtain database lock for user %s: %s", CTX->username, db_strerror (CTX->result)); return EUNKNOWN; } --- 506,568 ---- else { recovery = 1; ! s->db->close (s->db, 0); ! s->env->close (s->env, 0); return _ds_init_storage (CTX); } } /* Obtain a lock for this user */ ! lock_result = _libdb3_drv_lock_get (CTX->username); ! if (lock_result < 0) ! { ! LOGDEBUG ("locking subsystem returned error"); return EUNKNOWN; } ! ! if (lock_result > 0) ! { int i = 0; ! LOGDEBUG ("acquiring lock"); /* Run two instances of lock detection */ ! lock_detect (s->env, 0, DB_LOCK_OLDEST, NULL); ! lock_detect (s->env, 0, DB_LOCK_OLDEST, NULL); s->locker = 0; if ((CTX->result = lock_id (s->env, &s->locker)) != 0) { LOG (LOG_WARNING, "unable to get a locker id for %s: %s", ! CTX->username, db_strerror (CTX->result)); return EUNKNOWN; } dbt.data = CTX->username; dbt.size = strlen (CTX->username); while ((CTX->result = ! lock_get (s->env, s->locker, DB_LOCK_NOWAIT, &dbt, ! DB_LOCK_WRITE, &s->lock)) != 0 && i < 120) { ! LOGDEBUG ("spinning lock %d/120", i); i++; ! lock_detect (s->env, 0, DB_LOCK_OLDEST, NULL); ! lock_detect (s->env, 0, DB_LOCK_OLDEST, NULL); ! sleep (1); } ! if (CTX->result) ! { ! if (!recovery) ! { recovery = 2; ! return _ds_init_storage (CTX); ! } ! else ! { LOG (LOG_WARNING, ! "unable to obtain database lock for user %s: %s", CTX->username, db_strerror (CTX->result)); return EUNKNOWN; } *************** *** 555,564 **** memset (&CTX->totals, 0, sizeof (struct _ds_spam_totals)); } ! if (recovery) { recovery = 0; ! _ds_shutdown_storage(CTX); ! return _ds_init_storage(CTX); } return 0; --- 593,603 ---- memset (&CTX->totals, 0, sizeof (struct _ds_spam_totals)); } ! if (recovery) ! { recovery = 0; ! _ds_shutdown_storage (CTX); ! return _ds_init_storage (CTX); } return 0; *************** *** 599,612 **** { int lock_result; ! lock_result = _libdb3_drv_lock_put(CTX->username); ! if (lock_result < 0) { ! LOGDEBUG("locking subsystem returned error"); return EUNKNOWN; } ! if (lock_result > 0) { ! LOGDEBUG("freeing lock"); lock_put (s->env, &s->lock); } ret = s->db->close (s->db, 0); --- 638,653 ---- { int lock_result; ! lock_result = _libdb3_drv_lock_put (CTX->username); ! if (lock_result < 0) ! { ! LOGDEBUG ("locking subsystem returned error"); return EUNKNOWN; } ! if (lock_result > 0) ! { ! LOGDEBUG ("freeing lock"); lock_put (s->env, &s->lock); } ret = s->db->close (s->db, 0); *************** *** 623,629 **** ret = s->env->close (s->env, 0); } ! if (!ret) { free (CTX->storage); CTX->storage = NULL; --- 664,670 ---- ret = s->env->close (s->env, 0); } ! if (!ret) { free (CTX->storage); CTX->storage = NULL; *************** *** 1044,1074 **** */ int ! _libdb3_drv_lock_get (const char *username) { struct nt_node *node; struct nt_c c; struct _libdb3_drv_lock *lock; ! node = c_nt_first(_libdb3_drv_locks, &c); ! while(node != NULL) { lock = (struct _libdb3_drv_lock *) node->ptr; ! if (lock != NULL && !strcmp(username, lock->username)) { lock->readers++; ! if (lock->readers==1) return 1; return 0; } ! node = c_nt_next(_libdb3_drv_locks, &c); } ! lock = malloc(sizeof(struct _libdb3_drv_lock)); ! if (lock == NULL) return EUNKNOWN; ! strcpy(lock->username, username); lock->readers = 1; ! nt_add(_libdb3_drv_locks, (void *) lock); return 1; } --- 1085,1117 ---- */ int ! _libdb3_drv_lock_get (const char *username) { struct nt_node *node; struct nt_c c; struct _libdb3_drv_lock *lock; ! node = c_nt_first (_libdb3_drv_locks, &c); ! while (node != NULL) ! { lock = (struct _libdb3_drv_lock *) node->ptr; ! if (lock != NULL && !strcmp (username, lock->username)) ! { lock->readers++; ! if (lock->readers == 1) return 1; return 0; } ! node = c_nt_next (_libdb3_drv_locks, &c); } ! lock = malloc (sizeof (struct _libdb3_drv_lock)); ! if (lock == NULL) return EUNKNOWN; ! strcpy (lock->username, username); lock->readers = 1; ! nt_add (_libdb3_drv_locks, (void *) lock); return 1; } *************** *** 1076,1098 **** 1: Free lock */ int ! _libdb3_drv_lock_put (const char *username) { struct nt_node *node; struct nt_c c; struct _libdb3_drv_lock *lock; ! ! node = c_nt_first(_libdb3_drv_locks, &c); ! while(node != NULL) { lock = (struct _libdb3_drv_lock *) node->ptr; ! if (lock != NULL && !strcmp(username, lock->username)) { lock->readers--; if (lock->readers == 0) return 1; return 0; } ! node = c_nt_next(_libdb3_drv_locks, &c); } return EFAILURE; --- 1119,1143 ---- 1: Free lock */ int ! _libdb3_drv_lock_put (const char *username) { struct nt_node *node; struct nt_c c; struct _libdb3_drv_lock *lock; ! ! node = c_nt_first (_libdb3_drv_locks, &c); ! while (node != NULL) ! { lock = (struct _libdb3_drv_lock *) node->ptr; ! if (lock != NULL && !strcmp (username, lock->username)) ! { lock->readers--; if (lock->readers == 0) return 1; return 0; } ! node = c_nt_next (_libdb3_drv_locks, &c); } return EFAILURE; *************** *** 1106,1114 **** int dbflag = DB_CREATE; int lock_result; ! _ds_shutdown_storage(CTX); ! LOGDEBUG("recovering database"); s = malloc (sizeof (struct _libdb3_drv_storage)); if (s == NULL) { --- 1151,1159 ---- int dbflag = DB_CREATE; int lock_result; ! _ds_shutdown_storage (CTX); ! LOGDEBUG ("recovering database"); s = malloc (sizeof (struct _libdb3_drv_storage)); if (s == NULL) { *************** *** 1116,1122 **** LOG (LOG_CRIT, ERROR_MEM_ALLOC); return EUNKNOWN; } ! s->db = NULL; s->sig = NULL; s->env = NULL; --- 1161,1167 ---- LOG (LOG_CRIT, ERROR_MEM_ALLOC); return EUNKNOWN; } ! s->db = NULL; s->sig = NULL; s->env = NULL; *************** *** 1124,1130 **** if (CTX->username != NULL) { char db_home[MAX_FILENAME_LENGTH]; ! if (CTX->group == NULL) { strcpy (s->dictionary, _ds_userdir_path (CTX->username, "dict")); --- 1169,1175 ---- if (CTX->username != NULL) { char db_home[MAX_FILENAME_LENGTH]; ! if (CTX->group == NULL) { strcpy (s->dictionary, _ds_userdir_path (CTX->username, "dict")); *************** *** 1147,1184 **** return EFAILURE; } ! if (fatal) { CTX->result = s->env->open (s->env, db_home, ! DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_RECOVER_FATAL, 0); ! } else { CTX->result = s->env->open (s->env, db_home, DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_RECOVER, 0); } ! if (CTX->result) { ! LOG (LOG_WARNING, "DB_ENV->open failed: %s", db_strerror (CTX->result)); ! return EFAILURE; } if ((CTX->result = db_create (&s->db, s->env, 0)) != 0) { LOG (LOG_WARNING, "db_create failed: %s", db_strerror (CTX->result)); s->db = NULL; ! return EFAILURE; } if ((CTX->result = s->db->DBOPEN (s->db, NULL, s->dictionary, NULL, DB_BTREE, dbflag, 0)) != 0) ! { ! LOG (LOG_WARNING, "db->open failed on error %d: %s: %s", ! CTX->result, s->dictionary, db_strerror (CTX->result)); ! s->db = NULL; ! return EFILE; } if ((CTX->result = db_create (&s->sig, s->env, 0)) != 0) --- 1192,1233 ---- return EFAILURE; } ! if (fatal) ! { CTX->result = s->env->open (s->env, db_home, ! DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_RECOVER_FATAL, 0); ! } ! else ! { CTX->result = s->env->open (s->env, db_home, DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_RECOVER, 0); } ! if (CTX->result) ! { ! LOG (LOG_WARNING, "DB_ENV->open failed: %s", db_strerror (CTX->result)); ! return EFAILURE; } if ((CTX->result = db_create (&s->db, s->env, 0)) != 0) { LOG (LOG_WARNING, "db_create failed: %s", db_strerror (CTX->result)); s->db = NULL; ! return EFAILURE; } if ((CTX->result = s->db->DBOPEN (s->db, NULL, s->dictionary, NULL, DB_BTREE, dbflag, 0)) != 0) ! { ! LOG (LOG_WARNING, "db->open failed on error %d: %s: %s", ! CTX->result, s->dictionary, db_strerror (CTX->result)); ! s->db = NULL; ! return EFILE; } if ((CTX->result = db_create (&s->sig, s->env, 0)) != 0) *************** *** 1193,1249 **** s->sig->DBOPEN (s->sig, NULL, s->signature, NULL, DB_BTREE, DB_CREATE, 0)) != 0) { ! LOG (LOG_WARNING, "db->open failed on error %d: %s: %s", ! CTX->result, s->signature, db_strerror (CTX->result)); ! s->sig = NULL; ! _ds_shutdown_storage (CTX); ! return EFILE; } /* Obtain a lock for this user */ ! lock_result = _libdb3_drv_lock_get(CTX->username); ! if (lock_result < 0) { ! LOGDEBUG("locking subsystem returned error"); return EUNKNOWN; } ! ! if (lock_result > 0) { DBT dbt; int i = 0; ! LOGDEBUG("acquiring lock"); ! /* Run two instances of lock detection */ ! lock_detect(s->env, 0, DB_LOCK_OLDEST, NULL); ! lock_detect(s->env, 0, DB_LOCK_OLDEST, NULL); ! s->locker = 0; if ((CTX->result = lock_id (s->env, &s->locker)) != 0) { LOG (LOG_WARNING, "unable to get a locker id for %s: %s", ! CTX->username, db_strerror (CTX->result)); return EUNKNOWN; } ! dbt.data = CTX->username; dbt.size = strlen (CTX->username); while ((CTX->result = ! lock_get (s->env, s->locker, DB_LOCK_NOWAIT, &dbt, ! DB_LOCK_WRITE, &s->lock)) != 0 && i<15) { ! LOGDEBUG("spinning lock %d/15", i); i++; ! lock_detect(s->env, 0, DB_LOCK_OLDEST, NULL); ! lock_detect(s->env, 0, DB_LOCK_OLDEST, NULL); ! sleep(1); } ! ! if (CTX->result) { ! LOG (LOG_WARNING, ! "unable to obtain database lock for user %s: %s", ! CTX->username, db_strerror (CTX->result)); ! return EUNKNOWN; } } } --- 1242,1301 ---- s->sig->DBOPEN (s->sig, NULL, s->signature, NULL, DB_BTREE, DB_CREATE, 0)) != 0) { ! LOG (LOG_WARNING, "db->open failed on error %d: %s: %s", ! CTX->result, s->signature, db_strerror (CTX->result)); ! s->sig = NULL; ! _ds_shutdown_storage (CTX); ! return EFILE; } /* Obtain a lock for this user */ ! lock_result = _libdb3_drv_lock_get (CTX->username); ! if (lock_result < 0) ! { ! LOGDEBUG ("locking subsystem returned error"); return EUNKNOWN; } ! ! if (lock_result > 0) ! { DBT dbt; int i = 0; ! LOGDEBUG ("acquiring lock"); ! /* Run two instances of lock detection */ ! lock_detect (s->env, 0, DB_LOCK_OLDEST, NULL); ! lock_detect (s->env, 0, DB_LOCK_OLDEST, NULL); ! s->locker = 0; if ((CTX->result = lock_id (s->env, &s->locker)) != 0) { LOG (LOG_WARNING, "unable to get a locker id for %s: %s", ! CTX->username, db_strerror (CTX->result)); return EUNKNOWN; } ! dbt.data = CTX->username; dbt.size = strlen (CTX->username); while ((CTX->result = ! lock_get (s->env, s->locker, DB_LOCK_NOWAIT, &dbt, ! DB_LOCK_WRITE, &s->lock)) != 0 && i < 15) { ! LOGDEBUG ("spinning lock %d/15", i); i++; ! lock_detect (s->env, 0, DB_LOCK_OLDEST, NULL); ! lock_detect (s->env, 0, DB_LOCK_OLDEST, NULL); ! sleep (1); } ! ! if (CTX->result) ! { ! LOG (LOG_WARNING, ! "unable to obtain database lock for user %s: %s", ! CTX->username, db_strerror (CTX->result)); ! return EUNKNOWN; } } } *************** *** 1253,1259 **** s->sig = NULL; s->env = NULL; } ! s->c = NULL; s->dir_handles = nt_create (NT_INDEX); CTX->storage = s; --- 1305,1311 ---- s->sig = NULL; s->env = NULL; } ! s->c = NULL; s->dir_handles = nt_create (NT_INDEX); CTX->storage = s; *************** *** 1271,1277 **** memset (&CTX->totals, 0, sizeof (struct _ds_spam_totals)); } ! _ds_shutdown_storage(CTX); ! _ds_init_storage(CTX); return 0; } --- 1323,1329 ---- memset (&CTX->totals, 0, sizeof (struct _ds_spam_totals)); } ! _ds_shutdown_storage (CTX); ! _ds_init_storage (CTX); return 0; } Index: dspam/libdb4_drv.c diff -c dspam/libdb4_drv.c:1.1.1.1 dspam/libdb4_drv.c:1.1.1.1.2.1 *** dspam/libdb4_drv.c:1.1.1.1 Mon Nov 3 09:57:07 2003 --- dspam/libdb4_drv.c Sat Nov 15 18:34:58 2003 *************** *** 63,70 **** int dspam_init_driver (void) { ! _libdb4_drv_locks = nt_create(NT_PTR); ! if (_libdb4_drv_locks == NULL) return EUNKNOWN; return 0; --- 63,70 ---- int dspam_init_driver (void) { ! _libdb4_drv_locks = nt_create (NT_PTR); ! if (_libdb4_drv_locks == NULL) return EUNKNOWN; return 0; *************** *** 73,79 **** int dspam_shutdown_driver (void) { ! nt_destroy(_libdb4_drv_locks); return 0; } --- 73,79 ---- int dspam_shutdown_driver (void) { ! nt_destroy (_libdb4_drv_locks); return 0; } *************** *** 98,116 **** ret = (*s->db->get) (s->db, NULL, &key, &data, 0); if (ret) { ! if (ret == DB_RUNRECOVERY) { ! if (! _libdb4_drv_recover(CTX, 1)) { return _libdb4_drv_get_spamtotals (CTX); ! } else { return EUNKNOWN; } ! } else { LOGDEBUG ("_ds_get_totals: db->get failed: %s", db_strerror (ret)); return EFAILURE; } } ! memset(&CTX->totals, 0, sizeof(struct _ds_spam_totals)); memcpy (&CTX->totals, data.data, data.size); return 0; --- 98,122 ---- ret = (*s->db->get) (s->db, NULL, &key, &data, 0); if (ret) { ! if (ret == DB_RUNRECOVERY) ! { ! if (!_libdb4_drv_recover (CTX, 1)) ! { return _libdb4_drv_get_spamtotals (CTX); ! } ! else ! { return EUNKNOWN; } ! } ! else ! { LOGDEBUG ("_ds_get_totals: db->get failed: %s", db_strerror (ret)); return EFAILURE; } } ! memset (&CTX->totals, 0, sizeof (struct _ds_spam_totals)); memcpy (&CTX->totals, data.data, data.size); return 0; *************** *** 145,157 **** ret = (*s->db->put) (s->db, NULL, &key, &data, 0); if (ret) { ! if (ret == DB_RUNRECOVERY) { ! if (! _libdb4_drv_recover(CTX, 1)) { return _libdb4_drv_set_spamtotals (CTX); ! } else { return EUNKNOWN; } ! } else { LOGDEBUG ("_ds_set_totals: db->set failed: %s", db_strerror (ret)); return EFAILURE; } --- 151,169 ---- ret = (*s->db->put) (s->db, NULL, &key, &data, 0); if (ret) { ! if (ret == DB_RUNRECOVERY) ! { ! if (!_libdb4_drv_recover (CTX, 1)) ! { return _libdb4_drv_set_spamtotals (CTX); ! } ! else ! { return EUNKNOWN; } ! } ! else ! { LOGDEBUG ("_ds_set_totals: db->set failed: %s", db_strerror (ret)); return EFAILURE; } *************** *** 238,251 **** ret = (*s->db->get) (s->db, NULL, &key, &data, 0); ! if (ret) { ! if (ret == DB_RUNRECOVERY) { ! if (! _libdb4_drv_recover(CTX, 1)) { return _ds_get_spamrecord (CTX, token, stat); ! } else { return EUNKNOWN; } ! } else { return EFAILURE; } } --- 250,270 ---- ret = (*s->db->get) (s->db, NULL, &key, &data, 0); ! if (ret) ! { ! if (ret == DB_RUNRECOVERY) ! { ! if (!_libdb4_drv_recover (CTX, 1)) ! { return _ds_get_spamrecord (CTX, token, stat); ! } ! else ! { return EUNKNOWN; } ! } ! else ! { return EFAILURE; } } *************** *** 302,314 **** if (ret) { ! if (ret == DB_RUNRECOVERY) { ! if (! _libdb4_drv_recover(CTX, 1)) { return _ds_set_spamrecord (CTX, token, stat); ! } else { return EUNKNOWN; } ! } else { LOGDEBUG ("_ds_set_spamrecord: db->put failed: %s", db_strerror (ret)); return EFAILURE; } --- 321,339 ---- if (ret) { ! if (ret == DB_RUNRECOVERY) ! { ! if (!_libdb4_drv_recover (CTX, 1)) ! { return _ds_set_spamrecord (CTX, token, stat); ! } ! else ! { return EUNKNOWN; } ! } ! else ! { LOGDEBUG ("_ds_set_spamrecord: db->put failed: %s", db_strerror (ret)); return EFAILURE; } *************** *** 347,354 **** } else { ! LOGDEBUG("entering recovery mode"); ! free(CTX->storage); s = malloc (sizeof (struct _libdb4_drv_storage)); if (s == NULL) { --- 372,379 ---- } else { ! LOGDEBUG ("entering recovery mode"); ! free (CTX->storage); s = malloc (sizeof (struct _libdb4_drv_storage)); if (s == NULL) { *************** *** 356,367 **** LOG (LOG_CRIT, ERROR_MEM_ALLOC); return EUNKNOWN; } ! s->db = NULL; s->sig = NULL; s->env = NULL; ! _libdb4_drv_lock_set_readers((CTX->group == NULL) ? CTX->username : CTX->group, 0); } if (CTX->username != NULL) --- 381,393 ---- LOG (LOG_CRIT, ERROR_MEM_ALLOC); return EUNKNOWN; } ! s->db = NULL; s->sig = NULL; s->env = NULL; ! _libdb4_drv_lock_set_readers ((CTX->group == ! NULL) ? CTX->username : CTX->group, 0); } if (CTX->username != NULL) *************** *** 401,432 **** } */ ! if (!recovery) { CTX->result = ! s->env->open (s->env, db_home, DB_CREATE | DB_INIT_LOCK | ! DB_INIT_MPOOL, 0); ! } else if (recovery == 1) { CTX->result = s->env->open (s->env, db_home, ! DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_RECOVER_FATAL, 0); ! } else { CTX->result = s->env->open (s->env, db_home, ! DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_RECOVER, 0); } ! if (CTX->result) { if (recovery || CTX->result != DB_RUNRECOVERY) { ! LOG (LOG_WARNING, "DB_ENV->open failed: %s", db_strerror (CTX->result)); return EFAILURE; } else { ! recovery = 1; ! return _ds_init_storage (CTX); } } --- 427,465 ---- } */ ! if (!recovery) ! { CTX->result = ! s->env->open (s->env, db_home, DB_CREATE | DB_INIT_LOCK | ! DB_INIT_MPOOL, 0); ! } ! else if (recovery == 1) ! { CTX->result = s->env->open (s->env, db_home, ! DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_RECOVER_FATAL, 0); ! } ! else ! { CTX->result = s->env->open (s->env, db_home, ! DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_RECOVER, 0); } ! if (CTX->result) ! { if (recovery || CTX->result != DB_RUNRECOVERY) { ! LOG (LOG_WARNING, "DB_ENV->open failed: %s", ! db_strerror (CTX->result)); return EFAILURE; } else { ! recovery = 1; ! return _ds_init_storage (CTX); } } *************** *** 454,460 **** s->env->lock_put (s->env, &s->lock); s->env->lock_id_free (s->env, s->locker); ! s->env->close(s->env, 0); return _ds_init_storage (CTX); } --- 487,493 ---- s->env->lock_put (s->env, &s->lock); s->env->lock_id_free (s->env, s->locker); ! s->env->close (s->env, 0); return _ds_init_storage (CTX); } *************** *** 483,544 **** else { recovery = 1; ! s->db->close(s->db, 0); ! s->env->lock_put (s->env, &s->lock); s->env->lock_id_free (s->env, s->locker); ! s->env->close(s->env, 0); return _ds_init_storage (CTX); } } /* Obtain a lock for this user */ ! lock_result = _libdb4_drv_lock_get((CTX->group == NULL) ? CTX->username : CTX->group); ! if (lock_result < 0) { ! LOGDEBUG("locking subsystem returned error"); return EUNKNOWN; } ! ! if (lock_result > 0) { int i = 0; ! LOGDEBUG("acquiring lock"); /* Run two instances of lock detection */ ! s->env->lock_detect(s->env, 0, DB_LOCK_OLDEST, NULL); s->locker = 0; if ((CTX->result = s->env->lock_id (s->env, &s->locker)) != 0) { LOG (LOG_WARNING, "unable to get a locker id for %s: %s", ! CTX->username, db_strerror (CTX->result)); return EUNKNOWN; } dbt.data = CTX->username; dbt.size = strlen (CTX->username); CTX->result = ! s->env->lock_get (s->env, s->locker, DB_LOCK_NOWAIT, &dbt, ! DB_LOCK_WRITE, &s->lock); ! while(CTX->result != 0 && i<120) { ! LOGDEBUG("spinning lock %d/120", i); i++; ! s->env->lock_detect(s->env, 0, DB_LOCK_OLDEST, NULL); ! sleep(1); CTX->result = ! s->env->lock_get (s->env, s->locker, DB_LOCK_NOWAIT, &dbt, ! DB_LOCK_WRITE, &s->lock); } ! if (CTX->result) { ! if (!recovery) { recovery = 2; ! return _ds_init_storage(CTX); ! } else { LOG (LOG_WARNING, ! "unable to obtain database lock for user %s: %s", CTX->username, db_strerror (CTX->result)); return EUNKNOWN; } --- 516,586 ---- else { recovery = 1; ! s->db->close (s->db, 0); ! s->env->lock_put (s->env, &s->lock); s->env->lock_id_free (s->env, s->locker); ! s->env->close (s->env, 0); return _ds_init_storage (CTX); } } /* Obtain a lock for this user */ ! lock_result = ! _libdb4_drv_lock_get ((CTX->group == ! NULL) ? CTX->username : CTX->group); ! if (lock_result < 0) ! { ! LOGDEBUG ("locking subsystem returned error"); return EUNKNOWN; } ! ! if (lock_result > 0) ! { int i = 0; ! LOGDEBUG ("acquiring lock"); /* Run two instances of lock detection */ ! s->env->lock_detect (s->env, 0, DB_LOCK_OLDEST, NULL); s->locker = 0; if ((CTX->result = s->env->lock_id (s->env, &s->locker)) != 0) { LOG (LOG_WARNING, "unable to get a locker id for %s: %s", ! CTX->username, db_strerror (CTX->result)); return EUNKNOWN; } dbt.data = CTX->username; dbt.size = strlen (CTX->username); CTX->result = ! s->env->lock_get (s->env, s->locker, DB_LOCK_NOWAIT, &dbt, ! DB_LOCK_WRITE, &s->lock); ! while (CTX->result != 0 && i < 120) ! { ! LOGDEBUG ("spinning lock %d/120", i); i++; ! s->env->lock_detect (s->env, 0, DB_LOCK_OLDEST, NULL); ! sleep (1); CTX->result = ! s->env->lock_get (s->env, s->locker, DB_LOCK_NOWAIT, &dbt, ! DB_LOCK_WRITE, &s->lock); } ! if (CTX->result) ! { ! if (!recovery) ! { recovery = 2; ! return _ds_init_storage (CTX); ! } ! else ! { LOG (LOG_WARNING, ! "unable to obtain database lock for user %s: %s", CTX->username, db_strerror (CTX->result)); return EUNKNOWN; } *************** *** 569,578 **** memset (&CTX->totals, 0, sizeof (struct _ds_spam_totals)); } ! if (recovery) { recovery = 0; ! _ds_shutdown_storage(CTX); ! return _ds_init_storage(CTX); } return 0; } --- 611,621 ---- memset (&CTX->totals, 0, sizeof (struct _ds_spam_totals)); } ! if (recovery) ! { recovery = 0; ! _ds_shutdown_storage (CTX); ! return _ds_init_storage (CTX); } return 0; } *************** *** 612,625 **** { int lock_result; ! lock_result = _libdb4_drv_lock_put((CTX->group == NULL) ? CTX->username : CTX->group); ! if (lock_result < 0) { ! LOGDEBUG("locking subsystem returned error"); return EUNKNOWN; } ! if (lock_result > 0) { ! LOGDEBUG("freeing lock"); s->env->lock_put (s->env, &s->lock); s->env->lock_id_free (s->env, s->locker); } --- 655,672 ---- { int lock_result; ! lock_result = ! _libdb4_drv_lock_put ((CTX->group == ! NULL) ? CTX->username : CTX->group); ! if (lock_result < 0) ! { ! LOGDEBUG ("locking subsystem returned error"); return EUNKNOWN; } ! if (lock_result > 0) ! { ! LOGDEBUG ("freeing lock"); s->env->lock_put (s->env, &s->lock); s->env->lock_id_free (s->env, s->locker); } *************** *** 637,643 **** ret = s->env->close (s->env, 0); } ! if (!ret) { free (CTX->storage); CTX->storage = NULL; --- 684,690 ---- ret = s->env->close (s->env, 0); } ! if (!ret) { free (CTX->storage); CTX->storage = NULL; *************** *** 1058,1089 **** */ int ! _libdb4_drv_lock_get (const char *username) { struct nt_node *node; struct nt_c c; struct _libdb4_drv_lock *lock; ! node = c_nt_first(_libdb4_drv_locks, &c); ! while(node != NULL) { lock = (struct _libdb4_drv_lock *) node->ptr; ! if (lock != NULL && !strcmp(username, lock->username)) { lock->readers++; ! if (lock->readers==1) return 1; return 0; } ! node = c_nt_next(_libdb4_drv_locks, &c); } ! lock = malloc(sizeof(struct _libdb4_drv_lock)); ! if (lock == NULL) return EUNKNOWN; ! strcpy(lock->username, username); lock->readers = 1; ! nt_add(_libdb4_drv_locks, (void *) lock); return 1; } --- 1105,1138 ---- */ int ! _libdb4_drv_lock_get (const char *username) { struct nt_node *node; struct nt_c c; struct _libdb4_drv_lock *lock; ! node = c_nt_first (_libdb4_drv_locks, &c); ! while (node != NULL) ! { lock = (struct _libdb4_drv_lock *) node->ptr; ! if (lock != NULL && !strcmp (username, lock->username)) ! { lock->readers++; ! if (lock->readers == 1) return 1; return 0; } ! node = c_nt_next (_libdb4_drv_locks, &c); } ! lock = malloc (sizeof (struct _libdb4_drv_lock)); ! if (lock == NULL) return EUNKNOWN; ! strcpy (lock->username, username); lock->readers = 1; ! nt_add (_libdb4_drv_locks, (void *) lock); return 1; } *************** *** 1091,1107 **** 1: Free lock */ int ! _libdb4_drv_lock_put (const char *username) { struct nt_node *node; struct nt_c c; struct _libdb4_drv_lock *lock; ! ! node = c_nt_first(_libdb4_drv_locks, &c); ! while(node != NULL) { lock = (struct _libdb4_drv_lock *) node->ptr; ! if (lock != NULL && !strcmp(username, lock->username)) { ! if (lock->readers>0) { lock->readers--; if (lock->readers == 0) return 1; --- 1140,1159 ---- 1: Free lock */ int ! _libdb4_drv_lock_put (const char *username) { struct nt_node *node; struct nt_c c; struct _libdb4_drv_lock *lock; ! ! node = c_nt_first (_libdb4_drv_locks, &c); ! while (node != NULL) ! { lock = (struct _libdb4_drv_lock *) node->ptr; ! if (lock != NULL && !strcmp (username, lock->username)) ! { ! if (lock->readers > 0) ! { lock->readers--; if (lock->readers == 0) return 1; *************** *** 1109,1115 **** return 0; } ! node = c_nt_next(_libdb4_drv_locks, &c); } return EFAILURE; --- 1161,1167 ---- return 0; } ! node = c_nt_next (_libdb4_drv_locks, &c); } return EFAILURE; *************** *** 1123,1138 **** struct nt_c c; struct _libdb4_drv_lock *lock; ! node = c_nt_first(_libdb4_drv_locks, &c); ! while(node != NULL) { lock = (struct _libdb4_drv_lock *) node->ptr; ! if (lock != NULL && !strcmp(username, lock->username)) { ! lock->readers=readers; return 0; } ! node = c_nt_next(_libdb4_drv_locks, &c); } ! return EFAILURE; } --- 1175,1192 ---- struct nt_c c; struct _libdb4_drv_lock *lock; ! node = c_nt_first (_libdb4_drv_locks, &c); ! while (node != NULL) ! { lock = (struct _libdb4_drv_lock *) node->ptr; ! if (lock != NULL && !strcmp (username, lock->username)) ! { ! lock->readers = readers; return 0; } ! node = c_nt_next (_libdb4_drv_locks, &c); } ! return EFAILURE; } *************** *** 1142,1159 **** struct _libdb4_drv_storage *s = NULL; int dbflag = DB_CREATE; ! LOGDEBUG("recovering database"); ! if (CTX == NULL) return EINVAL; ! if (fatal) ! _libdb4_drv_lock_set_readers((CTX->group == NULL) ? CTX->username : CTX->group, 1); else ! _libdb4_drv_lock_set_readers((CTX->group == NULL) ? CTX->username : CTX->group, 0); ! _ds_shutdown_storage(CTX); ! _libdb4_drv_lock_set_readers((CTX->group == NULL) ? CTX->username : CTX->group, 0); s = malloc (sizeof (struct _libdb4_drv_storage)); if (s == NULL) --- 1196,1216 ---- struct _libdb4_drv_storage *s = NULL; int dbflag = DB_CREATE; ! LOGDEBUG ("recovering database"); ! if (CTX == NULL) return EINVAL; ! if (fatal) ! _libdb4_drv_lock_set_readers ((CTX->group == ! NULL) ? CTX->username : CTX->group, 1); else ! _libdb4_drv_lock_set_readers ((CTX->group == ! NULL) ? CTX->username : CTX->group, 0); ! _ds_shutdown_storage (CTX); ! _libdb4_drv_lock_set_readers ((CTX->group == ! NULL) ? CTX->username : CTX->group, 0); s = malloc (sizeof (struct _libdb4_drv_storage)); if (s == NULL) *************** *** 1162,1168 **** LOG (LOG_CRIT, ERROR_MEM_ALLOC); return EUNKNOWN; } ! s->db = NULL; s->sig = NULL; s->env = NULL; --- 1219,1225 ---- LOG (LOG_CRIT, ERROR_MEM_ALLOC); return EUNKNOWN; } ! s->db = NULL; s->sig = NULL; s->env = NULL; *************** *** 1170,1176 **** if (CTX->username != NULL) { char db_home[MAX_FILENAME_LENGTH]; ! if (CTX->group == NULL) { strcpy (s->dictionary, _ds_userdir_path (CTX->username, "dict")); --- 1227,1233 ---- if (CTX->username != NULL) { char db_home[MAX_FILENAME_LENGTH]; ! if (CTX->group == NULL) { strcpy (s->dictionary, _ds_userdir_path (CTX->username, "dict")); *************** *** 1193,1230 **** return EFAILURE; } ! if (fatal) { CTX->result = s->env->open (s->env, db_home, ! DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_RECOVER_FATAL, 0); ! } else { CTX->result = s->env->open (s->env, db_home, DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_RECOVER, 0); } ! if (CTX->result) { ! LOG (LOG_WARNING, "DB_ENV->open failed: %s", db_strerror (CTX->result)); ! return EFAILURE; } if ((CTX->result = db_create (&s->db, s->env, 0)) != 0) { LOG (LOG_WARNING, "db_create failed: %s", db_strerror (CTX->result)); s->db = NULL; ! return EFAILURE; } if ((CTX->result = s->db->DBOPEN (s->db, NULL, s->dictionary, NULL, DB_BTREE, dbflag, 0)) != 0) ! { ! LOG (LOG_WARNING, "db->open failed on error %d: %s: %s", ! CTX->result, s->dictionary, db_strerror (CTX->result)); ! s->db = NULL; ! return EFILE; } if ((CTX->result = db_create (&s->sig, s->env, 0)) != 0) --- 1250,1291 ---- return EFAILURE; } ! if (fatal) ! { CTX->result = s->env->open (s->env, db_home, ! DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_RECOVER_FATAL, 0); ! } ! else ! { CTX->result = s->env->open (s->env, db_home, DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_RECOVER, 0); } ! if (CTX->result) ! { ! LOG (LOG_WARNING, "DB_ENV->open failed: %s", db_strerror (CTX->result)); ! return EFAILURE; } if ((CTX->result = db_create (&s->db, s->env, 0)) != 0) { LOG (LOG_WARNING, "db_create failed: %s", db_strerror (CTX->result)); s->db = NULL; ! return EFAILURE; } if ((CTX->result = s->db->DBOPEN (s->db, NULL, s->dictionary, NULL, DB_BTREE, dbflag, 0)) != 0) ! { ! LOG (LOG_WARNING, "db->open failed on error %d: %s: %s", ! CTX->result, s->dictionary, db_strerror (CTX->result)); ! s->db = NULL; ! return EFILE; } if ((CTX->result = db_create (&s->sig, s->env, 0)) != 0) *************** *** 1239,1249 **** s->sig->DBOPEN (s->sig, NULL, s->signature, NULL, DB_BTREE, DB_CREATE, 0)) != 0) { ! LOG (LOG_WARNING, "db->open failed on error %d: %s: %s", ! CTX->result, s->signature, db_strerror (CTX->result)); ! s->sig = NULL; ! _ds_shutdown_storage (CTX); ! return EFILE; } } --- 1300,1310 ---- s->sig->DBOPEN (s->sig, NULL, s->signature, NULL, DB_BTREE, DB_CREATE, 0)) != 0) { ! LOG (LOG_WARNING, "db->open failed on error %d: %s: %s", ! CTX->result, s->signature, db_strerror (CTX->result)); ! s->sig = NULL; ! _ds_shutdown_storage (CTX); ! return EFILE; } } *************** *** 1253,1264 **** s->sig = NULL; s->env = NULL; } ! s->c = NULL; s->dir_handles = nt_create (NT_INDEX); CTX->storage = s; ! _ds_shutdown_storage(CTX); ! _ds_init_storage(CTX); return 0; } --- 1314,1325 ---- s->sig = NULL; s->env = NULL; } ! s->c = NULL; s->dir_handles = nt_create (NT_INDEX); CTX->storage = s; ! _ds_shutdown_storage (CTX); ! _ds_init_storage (CTX); return 0; } Index: dspam/libdspam.c diff -c dspam/libdspam.c:1.1.1.13 dspam/libdspam.c:1.1.1.13.2.2 *** dspam/libdspam.c:1.1.1.13 Fri Oct 31 22:00:37 2003 --- dspam/libdspam.c Sat Nov 15 20:04:15 2003 *************** *** 95,100 **** --- 95,103 ---- if (!_ds_init_storage (CTX)) return CTX; + free (CTX->username); + free (CTX->group); + free (CTX); return NULL; } *************** *** 156,163 **** CTX->_process_start = time (NULL); ! if (CTX->mode != DSM_PROCESS && CTX->mode != DSM_CLASSIFY ! && (CTX->flags & DSF_SIGNATURE)) return _ds_process_signature (CTX); header = buffer_create (NULL); --- 159,166 ---- CTX->_process_start = time (NULL); ! if (CTX->mode != DSM_PROCESS && CTX->mode != DSM_CLASSIFY ! && (CTX->flags & DSF_SIGNATURE)) return _ds_process_signature (CTX); header = buffer_create (NULL); *************** *** 175,196 **** CTX->message = _ds_actualize_message (message); /* Skip this section is signature was provided for classification */ ! if (! (CTX->flags & DSF_SIGNATURE && CTX->mode == DSM_CLASSIFY)) { ! if (CTX->message == NULL) { LOG (LOG_WARNING, "_ds_actualize_message() failed"); return EUNKNOWN; } ! /* Iterate through each component and create large header/body buffers */ ! node_nt = c_nt_first (CTX->message->components, &c_nt); while (node_nt != NULL) { struct _ds_message_block *block = (struct _ds_message_block *) node_nt->ptr; ! #ifdef VERBOSE LOGDEBUG ("Processing component %d", i); #endif --- 178,200 ---- CTX->message = _ds_actualize_message (message); /* Skip this section is signature was provided for classification */ ! if (!(CTX->flags & DSF_SIGNATURE && CTX->mode == DSM_CLASSIFY && CTX->signature != NULL)) ! { ! if (CTX->message == NULL) { LOG (LOG_WARNING, "_ds_actualize_message() failed"); return EUNKNOWN; } ! /* Iterate through each component and create large header/body buffers */ ! node_nt = c_nt_first (CTX->message->components, &c_nt); while (node_nt != NULL) { struct _ds_message_block *block = (struct _ds_message_block *) node_nt->ptr; ! #ifdef VERBOSE LOGDEBUG ("Processing component %d", i); #endif *************** *** 198,204 **** if (block->media_type == MT_MULTIPART && block->media_subtype == MST_SIGNED) is_signed = 1; ! if (block->headers == NULL || block->headers->items == 0) { #ifdef VERBOSE --- 202,208 ---- if (block->media_type == MT_MULTIPART && block->media_subtype == MST_SIGNED) is_signed = 1; ! if (block->headers == NULL || block->headers->items == 0) { #ifdef VERBOSE *************** *** 210,216 **** else if (block->media_type == MT_TEXT || block->media_type == MT_MESSAGE || i == 0) { ! /* Accumulate the headers */ node_header = c_nt_first (block->headers, &c_nt2); while (node_header != NULL) --- 214,220 ---- else if (block->media_type == MT_TEXT || block->media_type == MT_MESSAGE || i == 0) { ! /* Accumulate the headers */ node_header = c_nt_first (block->headers, &c_nt2); while (node_header != NULL) *************** *** 218,247 **** struct _ds_header_field *current_header = (struct _ds_header_field *) node_header->ptr; snprintf (heading, sizeof (heading), ! "%s: %s\n", current_header->heading, current_header->data); buffer_cat (header, heading); node_header = c_nt_next (block->headers, &c_nt2); } ! decode = block->body->data; ! /* Accumulate the bodies */ if ((block->encoding == EN_BASE64 || block->encoding == EN_QUOTED_PRINTABLE) && (!is_signed || block-> ! original_signed_body ! == NULL)) { struct _ds_header_field *field; int is_attachment = 0; struct nt_node *node_hnt; struct nt_c c_hnt; ! node_hnt = c_nt_first (block->headers, &c_hnt); while (node_hnt != NULL) { field = (struct _ds_header_field *) node_hnt->ptr; ! if (field != NULL && field->heading != NULL && field->data != NULL) if (!strncasecmp (field->heading, "Content-Disposition", 19)) if (!strncasecmp (field->data, "attachment", 10)) is_attachment = 1; --- 222,253 ---- struct _ds_header_field *current_header = (struct _ds_header_field *) node_header->ptr; snprintf (heading, sizeof (heading), ! "%s: %s\n", current_header->heading, ! current_header->data); buffer_cat (header, heading); node_header = c_nt_next (block->headers, &c_nt2); } ! decode = block->body->data; ! /* Accumulate the bodies */ if ((block->encoding == EN_BASE64 || block->encoding == EN_QUOTED_PRINTABLE) && (!is_signed || block-> ! original_signed_body ! == NULL)) { struct _ds_header_field *field; int is_attachment = 0; struct nt_node *node_hnt; struct nt_c c_hnt; ! node_hnt = c_nt_first (block->headers, &c_hnt); while (node_hnt != NULL) { field = (struct _ds_header_field *) node_hnt->ptr; ! if (field != NULL && field->heading != NULL ! && field->data != NULL) if (!strncasecmp (field->heading, "Content-Disposition", 19)) if (!strncasecmp (field->data, "attachment", 10)) is_attachment = 1; *************** *** 262,268 **** buffer_cat (body, decode); if (decode != block->body->data) { ! if (is_signed) { LOGDEBUG --- 268,274 ---- buffer_cat (body, decode); if (decode != block->body->data) { ! if (is_signed) { LOGDEBUG *************** *** 275,284 **** block->encoding = EN_7BIT; buffer_destroy (block->body); } ! block->body = buffer_create (decode); free (decode); ! if (!is_signed) { /* Rewrite the actual header */ --- 281,290 ---- block->encoding = EN_7BIT; buffer_destroy (block->body); } ! block->body = buffer_create (decode); free (decode); ! if (!is_signed) { /* Rewrite the actual header */ *************** *** 287,293 **** { struct _ds_header_field *header = (struct _ds_header_field *) node_header->ptr; ! if (!strcasecmp (header->heading, "Content-Transfer-Encoding")) { free (header->data); header->data = strdup ("7bit"); --- 293,300 ---- { struct _ds_header_field *header = (struct _ds_header_field *) node_header->ptr; ! if (!strcasecmp ! (header->heading, "Content-Transfer-Encoding")) { free (header->data); header->data = strdup ("7bit"); *************** *** 411,417 **** */ int ! dspam_getsource (DSPAM_CTX * CTX, char *buf, size_t size, const char *whitelist) { struct _ds_message_block *current_block; struct _ds_header_field *current_heading = NULL; --- 418,425 ---- */ int ! dspam_getsource (DSPAM_CTX * CTX, char *buf, size_t size, ! const char *whitelist) { struct _ds_message_block *current_block; struct _ds_header_field *current_heading = NULL; *************** *** 443,469 **** { int whitelisted = 0; FILE *file; ! tok = strtok (NULL, "]"); ! if (tok != NULL) { ! if (!strcmp(tok, "127.0.0.1")) whitelisted = 1; ! if (whitelist != NULL) { ! file = fopen(whitelist, "r"); ! if (file != NULL) { char buffer[128]; ! while(fgets(buffer, sizeof(buffer), file)!=NULL) { ! chomp(buffer); ! LOGDEBUG("checking whitelist %s <> %s", tok, buffer); ! if (!strcmp(tok, buffer)) ! whitelisted = 1; } ! fclose(file); } } ! if (! whitelisted) { strlcpy (buf, tok, size); free (data); --- 451,481 ---- { int whitelisted = 0; FILE *file; ! tok = strtok (NULL, "]"); ! if (tok != NULL) ! { ! if (!strcmp (tok, "127.0.0.1")) whitelisted = 1; ! if (whitelist != NULL) ! { ! file = fopen (whitelist, "r"); ! if (file != NULL) ! { char buffer[128]; ! while (fgets (buffer, sizeof (buffer), file) != NULL) ! { ! chomp (buffer); ! LOGDEBUG ("checking whitelist %s <> %s", tok, buffer); ! if (!strcmp (tok, buffer)) ! whitelisted = 1; } ! fclose (file);