void menubar_create(menubar_t *m) { memset(m,0,sizeof(menubar_t)); m->info.type = G_MENUBAR; m->info.x = 0; m->info.y = 0; m->info.w = 256; m->info.h = 14; m->info.draw = (drawfunc_t)menubar_draw; m->info.event = (eventfunc_t)menubar_event; //this needs to be configurable, passed thru in a struct menu_create(&m->menus[0],"\x1",4,recentitems); menu_create(&m->menus[1],"Game",m->menus[0].info.x + m->menus[0].info.w + 4,gameitems); menu_create(&m->menus[2],"Config",m->menus[1].info.x + m->menus[1].info.w + 4,configitems); menu_create(&m->menus[3],"Cheat",m->menus[2].info.x + m->menus[2].info.w + 4,miscitems); menu_create(&m->menus[4],"Debug",m->menus[3].info.x + m->menus[3].info.w + 4,debugitems); button_create(&m->buttons[0],"x",(256 - 9) - 3,3,click_quit); button_create(&m->buttons[1],"\x9",(256 - 33) - 1,3,click_minimize); button_create(&m->buttons[2],"\x8",(256 - 21) - 3,3,click_togglefullscreen); load_create(&m->load); video_create(&m->video); input_create(&m->input); gui_input_create(&m->guiinput); sound_create(&m->sound); devices_create(&m->devices); palette_create(&m->palette); options_create(&m->options); mappers_create(&m->mappers); paths_create(&m->paths); supported_mappers_create(&m->supported_mappers); rom_info_create(&m->rom_info); tracer_create(&m->tracer); memory_viewer_create(&m->memory_viewer); nt_create(&m->nametable_viewer); pt_create(&m->patterntable_viewer); about_create(&m->about); m->menus[0].click = click_recent; m->menus[1].click = click_game; m->menus[2].click = click_config; m->menus[3].click = click_debug; m->menus[4].click = click_misc; m->menus[0].user = m; m->menus[1].user = m; m->menus[2].user = m; m->menus[3].user = m; m->menus[4].user = m; //'hack' to update the 'freeze data' caption click_freezedata(); click_freezedata(); }
int main() { //启动重叠网络初始化工作 printf("Overlay network: Node %d initializing...\n",topology_getMyNodeID()); //创建一个邻居表 nt = nt_create(); //将sip_conn初始化为-1, 即还未与SIP进程连接 sip_conn = -1; //注册一个信号句柄, 用于终止进程 signal(SIGINT, son_stop); //打印所有邻居 int nbrNum = topology_getNbrNum(); int i; for(i=0;i<nbrNum;i++) { printf("Overlay network: neighbor %d:%d\n",i+1,nt[i].nodeID); } //启动waitNbrs线程, 等待节点ID比自己大的所有邻居的进入连接 pthread_t waitNbrs_thread; pthread_create(&waitNbrs_thread,NULL,waitNbrs,(void*)0); //等待其他节点启动 sleep(SON_START_DELAY); //连接到节点ID比自己小的所有邻居 connectNbrs(); //等待waitNbrs线程返回 pthread_join(waitNbrs_thread,NULL); //此时, 所有与邻居之间的连接都建立好了 for (i = 0; i < nbrNum; i++){ printf("id:%d, socket:%d\n", nt[i].nodeID, nt[i].conn); } //创建线程监听所有邻居 for(i=0;i<nbrNum;i++) { int* idx = (int*)malloc(sizeof(int)); *idx = i; pthread_t nbr_listen_thread; pthread_create(&nbr_listen_thread,NULL,listen_to_neighbor,(void*)idx); } printf("Overlay network: node initialized...\n"); printf("Overlay network: waiting for connection from SIP process...\n"); //等待来自SIP进程的连接 waitSIP(); }
ds_diction_t ds_diction_create (unsigned long size) { ds_diction_t diction = (ds_diction_t) calloc(1, sizeof(struct _ds_diction)); int i = 0; if (!diction) { perror("ds_diction_create: calloc() failed"); return NULL; } while (_ds_prime_list[i] < size) { i++; } diction->size = _ds_prime_list[i]; diction->items = 0; diction->tbl = (struct _ds_term **) calloc(diction->size, sizeof (struct _ds_term *)); if (!diction->tbl) { perror("ds_diction_create: calloc() failed"); free(diction); return NULL; } diction->order = nt_create(NT_INDEX); diction->chained_order = nt_create(NT_INDEX); if (!diction->order || !diction->chained_order) { nt_destroy(diction->order); nt_destroy(diction->chained_order); free(diction->tbl); free(diction); return NULL; } return diction; }
int process_sigs (DSPAM_CTX * CTX, int age) { struct _ds_storage_signature *ss; struct nt *del; struct nt_node *node; int delta; del = nt_create(NT_CHAR); if (del == NULL) return -1; #ifdef DEBUG printf ("Processing sigs; age: %d\n", age); #endif ss = _ds_get_nextsignature (CTX); while (ss != NULL) { #ifdef DEBUG printf ("Signature: %s\n Created: %s\n", ss->signature, ctime (&ss->created_on)); #endif delta = (((time (NULL) - ss->created_on) / 60) / 60) / 24; if (age == 0 || delta > age) { #ifdef DEBUG printf (" DELETED!\n"); #endif nt_add(del, ss->signature); } free(ss->data); free(ss); ss = _ds_get_nextsignature (CTX); } node = del->first; while(node != NULL) { _ds_delete_signature (CTX, node->ptr); node = node->next; } nt_destroy(del); return 0; }
int _ds_tokenize_ngram( DSPAM_CTX *CTX, char *headers, char *body, ds_diction_t diction) { char *token; /* current token */ char *previous_token = NULL; /* used for bigrams (chained tokens) */ char *line = NULL; /* header broken up into lines */ char *ptrptr; char heading[128]; /* current heading */ int l, tokenizer = CTX->tokenizer; struct nt *header = NULL; struct nt_node *node_nt; struct nt_c c_nt; /* Tokenize URLs in message */ if (_ds_match_attribute(CTX->config->attributes, "ProcessorURLContext", "on")) { _ds_url_tokenize(diction, body, "http://"); _ds_url_tokenize(diction, body, "www."); _ds_url_tokenize(diction, body, "href="); } /* * Header Tokenization */ header = nt_create (NT_CHAR); if (header == NULL) { LOG (LOG_CRIT, ERR_MEM_ALLOC); return EUNKNOWN; } line = strtok_r (headers, "\n", &ptrptr); while (line) { nt_add (header, line); line = strtok_r (NULL, "\n", &ptrptr); } node_nt = c_nt_first (header, &c_nt); heading[0] = 0; while (node_nt) { int multiline; #ifdef VERBOSE LOGDEBUG("processing line: %s", node_nt->ptr); #endif line = node_nt->ptr; token = strtok_r (line, ":", &ptrptr); if (token && token[0] != 32 && token[0] != 9 && !strstr (token, " ")) { multiline = 0; strlcpy (heading, token, 128); previous_token = NULL; } else { multiline = 1; } #ifdef VERBOSE LOGDEBUG ("Reading '%s' header from: '%s'", heading, line); #endif if (CTX->flags & DSF_WHITELIST) { /* Use the entire From: line for auto-whitelisting */ if (!strcmp(heading, "From")) { char wl[256]; char *fromline = line + 5; unsigned long long whitelist_token; if (fromline[0] == 32) fromline++; snprintf(wl, sizeof(wl), "%s*%s", heading, fromline); whitelist_token = _ds_getcrc64(wl); ds_diction_touch(diction, whitelist_token, wl, 0); diction->whitelist_token = whitelist_token; } } /* Received headers use a different set of delimiters to preserve things like ip addresses */ token = strtok_r ((multiline) ? line : NULL, DELIMITERS_HEADING, &ptrptr); while (token) { l = strlen(token); if (l >= 1 && l < 50) { #ifdef VERBOSE LOGDEBUG ("Processing '%s' token in '%s' header", token, heading); #endif /* Process "current" token */ if (!_ds_process_header_token (CTX, token, previous_token, diction, heading) && (tokenizer == DSZ_CHAIN)) { previous_token = token; } } token = strtok_r (NULL, DELIMITERS_HEADING, &ptrptr); } previous_token = NULL; node_nt = c_nt_next (header, &c_nt); } nt_destroy (header); /* * Body Tokenization */ #ifdef VERBOSE LOGDEBUG("parsing message body"); #endif token = strtok_r (body, DELIMITERS, &ptrptr); while (token != NULL) { l = strlen (token); if (l >= 1 && l < 50) { #ifdef VERBOSE LOGDEBUG ("Processing body token '%s'", token); #endif /* Process "current" token */ if ( !_ds_process_body_token(CTX, token, previous_token, diction) && tokenizer == DSZ_CHAIN) { previous_token = token; } } token = strtok_r (NULL, DELIMITERS, &ptrptr); } #ifdef VERBOSE LOGDEBUG("Finished tokenizing (ngram) message"); #endif /* Final token reassembly (anything left in the buffer) */ return 0; }
int _ds_tokenize_sparse( DSPAM_CTX *CTX, char *headers, char *body, ds_diction_t diction) { int i; char *token; /* current token */ char *previous_tokens[SPARSE_WINDOW_SIZE]; /* sparse chain */ char *line = NULL; /* header broken up into lines */ char *ptrptr; char *bitpattern; char heading[128]; /* current heading */ int l; struct nt *header = NULL; struct nt_node *node_nt; struct nt_c c_nt; for(i=0;i<SPARSE_WINDOW_SIZE;i++) previous_tokens[i] = NULL; bitpattern = _ds_generate_bitpattern(_ds_pow2(SPARSE_WINDOW_SIZE)); /* Tokenize URLs in message */ if (_ds_match_attribute(CTX->config->attributes, "ProcessorURLContext", "on")) { _ds_url_tokenize(diction, body, "http://"); _ds_url_tokenize(diction, body, "www."); _ds_url_tokenize(diction, body, "href="); } /* * Header Tokenization */ header = nt_create (NT_CHAR); if (header == NULL) { LOG (LOG_CRIT, ERR_MEM_ALLOC); free(bitpattern); return EUNKNOWN; } line = strtok_r (headers, "\n", &ptrptr); while (line) { nt_add (header, line); line = strtok_r (NULL, "\n", &ptrptr); } node_nt = c_nt_first (header, &c_nt); heading[0] = 0; while (node_nt) { int multiline; #ifdef VERBOSE LOGDEBUG("processing line: %s", node_nt->ptr); #endif _ds_sparse_clear(previous_tokens); line = node_nt->ptr; token = strtok_r (line, ":", &ptrptr); if (token && token[0] != 32 && token[0] != 9 && !strstr (token, " ")) { multiline = 0; strlcpy (heading, token, 128); _ds_sparse_clear(previous_tokens); } else { multiline = 1; } #ifdef VERBOSE LOGDEBUG ("Reading '%s' header from: '%s'", heading, line); #endif if (CTX->flags & DSF_WHITELIST) { /* Use the entire From: line for auto-whitelisting */ if (!strcmp(heading, "From")) { char wl[256]; char *fromline = line + 5; unsigned long long whitelist_token; if (fromline[0] == 32) fromline++; snprintf(wl, sizeof(wl), "%s*%s", heading, fromline); whitelist_token = _ds_getcrc64(wl); ds_diction_touch(diction, whitelist_token, wl, 0); diction->whitelist_token = whitelist_token; } } /* Received headers use a different set of delimiters to preserve things like ip addresses */ token = strtok_r ((multiline) ? line : NULL, SPARSE_DELIMITERS_HEADING, &ptrptr); while (token) { l = strlen(token); if (l > 0 && l < 50) { #ifdef VERBOSE LOGDEBUG ("Processing '%s' token in '%s' header", token, heading); #endif _ds_map_header_token (CTX, token, previous_tokens, diction, heading, bitpattern); } token = strtok_r (NULL, SPARSE_DELIMITERS_HEADING, &ptrptr); } for(i=0;i<SPARSE_WINDOW_SIZE;i++) { _ds_map_header_token(CTX, NULL, previous_tokens, diction, heading, bitpattern); } _ds_sparse_clear(previous_tokens); node_nt = c_nt_next (header, &c_nt); } nt_destroy (header); /* * Body Tokenization */ #ifdef VERBOSE LOGDEBUG("parsing message body"); #endif token = strtok_r (body, SPARSE_DELIMITERS, &ptrptr); while (token != NULL) { l = strlen (token); if (l > 0 && l < 50) { #ifdef VERBOSE LOGDEBUG ("Processing body token '%s'", token); #endif /* Process "current" token */ _ds_map_body_token (CTX, token, previous_tokens, diction, bitpattern); } token = strtok_r (NULL, SPARSE_DELIMITERS, &ptrptr); } for(i=0;i<SPARSE_WINDOW_SIZE;i++) { _ds_map_body_token(CTX, NULL, previous_tokens, diction, bitpattern); } _ds_sparse_clear(previous_tokens); free(bitpattern); #ifdef VERBOSE LOGDEBUG("Finished tokenizing (sparse) message"); #endif return 0; }
int _ds_init_storage (DSPAM_CTX * CTX, void *dbh) { struct _sqlite_drv_storage *s; FILE *file; char buff[1024]; char filename[MAX_FILENAME_LENGTH]; char *err=NULL; struct stat st; int noexist; buff[0] = 0; if (CTX == NULL) return EINVAL; if (!CTX->home) { LOG(LOG_ERR, ERR_AGENT_DSPAM_HOME); return EINVAL; } if (CTX->flags & DSF_MERGED) { LOG(LOG_ERR, ERR_DRV_NO_MERGED); return EINVAL; } /* don't init if we're already initted */ if (CTX->storage != NULL) { LOGDEBUG ("_ds_init_storage: storage already initialized"); return EINVAL; } s = malloc (sizeof (struct _sqlite_drv_storage)); if (s == NULL) { LOG (LOG_CRIT, ERR_MEM_ALLOC); return EUNKNOWN; } s->dbh = NULL; s->control_token = 0; s->iter_token = NULL; s->iter_sig = NULL; s->control_token = 0; s->control_sh = 0; s->control_ih = 0; s->dbh_attached = (dbh) ? 1 : 0; if (CTX->group == NULL || CTX->group[0] == 0) _ds_userdir_path (filename, CTX->home, CTX->username, "sdb"); else _ds_userdir_path (filename, CTX->home, CTX->group, "sdb"); _ds_prepare_path_for (filename); noexist = stat(filename, &st); if (dbh) s->dbh = dbh; else s->dbh = sqlite_open(filename, 0660, &err); if (s->dbh == NULL) { LOGDEBUG ("_ds_init_storage: sqlite_open: unable to initialize database: %s", err); return EUNKNOWN; } /* Commit timeout of 20 minutes */ sqlite_busy_timeout(s->dbh, 1000 * 60 * 20); /* Create database objects */ if (noexist) { sqlite_exec(s->dbh, "create table dspam_token_data (token char(20) primary key, " "spam_hits int, innocent_hits int, last_hit date)", NULL, NULL, &err); sqlite_exec(s->dbh, "create index id_token_data_02 on dspam_token_data" "(innocent_hits)", NULL, NULL, &err); sqlite_exec(s->dbh, "create table dspam_signature_data (" "signature char(128) primary key, data blob, created_on date)", NULL, NULL, &err); sqlite_exec(s->dbh, "create table dspam_stats (dspam_stat_id int primary key, " "spam_learned int, innocent_learned int, " "spam_misclassified int, innocent_misclassified int, " "spam_corpusfed int, innocent_corpusfed int, " "spam_classified int, innocent_classified int)", NULL, NULL, &err); } if (_ds_read_attribute(CTX->config->attributes, "SQLitePragma")) { char pragma[1024]; attribute_t t = _ds_find_attribute(CTX->config->attributes, "SQLitePragma"); while(t != NULL) { snprintf(pragma, sizeof(pragma), "PRAGMA %s", t->value); if ((sqlite_exec(s->dbh, pragma, NULL, NULL, &err))!=SQLITE_OK) { LOG(LOG_WARNING, "sqlite.pragma function error: %s: %s", err, pragma); _sqlite_drv_query_error (err, pragma); } t = t->next; } } else if (CTX->home) { snprintf(filename, MAX_FILENAME_LENGTH, "%s/sqlite.pragma", CTX->home); file = fopen(filename, "r"); if (file != NULL) { while((fgets(buff, sizeof(buff), file))!=NULL) { chomp(buff); if ((sqlite_exec(s->dbh, buff, NULL, NULL, &err))!=SQLITE_OK) { LOG(LOG_WARNING, "sqlite.pragma function error: %s: %s", err, buff); _sqlite_drv_query_error (err, buff); } } fclose(file); } } CTX->storage = s; s->dir_handles = nt_create (NT_INDEX); s->control_token = 0; s->control_ih = 0; s->control_sh = 0; /* get spam totals on successful init */ if (CTX->username != NULL) { if (_sqlite_drv_get_spamtotals (CTX)) { LOGDEBUG ("unable to load totals. using zero values."); } } else { memset (&CTX->totals, 0, sizeof (struct _ds_spam_totals)); memset (&s->control_totals, 0, sizeof (struct _ds_spam_totals)); } return 0; }
buffer * read_sock(THREAD_CTX *TTX, AGENT_CTX *ATX) { buffer *message; int body = 0, line = 1; char *buf; int strip = _ds_match_attribute(agent_config, "Broken", "lineStripping"); int parseto = _ds_match_attribute(agent_config, "ParseToHeaders", "on"); message = buffer_create(NULL); if (message == NULL) { LOG(LOG_CRIT, ERR_MEM_ALLOC); return NULL; } if (_ds_match_attribute(agent_config, "DataSource", "document")) { buffer_cat(message, ".\n\n"); body = 1; } while ((buf = daemon_getline(TTX, 300))!=NULL) { chomp(buf); if (!strcmp(buf, ".")) { free(buf); return message; } if (strip) { size_t len = strlen(buf); while (len>1 && buf[len-2]==13) { buf[len-2] = buf[len-1]; buf[len-1] = 0; len--; } } if (line > 1 || strncmp (buf, "From QUARANTINE", 15)) { if (parseto) { if (buf[0] == 0) body = 1; if (!body && !strncasecmp(buf, "To: ", 4)) process_parseto(ATX, buf); } if (buffer_cat (message, buf) || buffer_cat(message, "\n")) { LOG (LOG_CRIT, ERR_MEM_ALLOC); goto bail; } } /* Use the original user id if we are reversing a false positive */ if (ATX->source == DSS_ERROR && ATX->classification == DSR_ISINNOCENT && ATX->operating_mode == DSM_PROCESS && !strncasecmp (buf, "X-DSPAM-User: ", 14)) { char user[MAX_USERNAME_LENGTH]; strlcpy (user, buf + 14, sizeof (user)); chomp (user); nt_destroy (ATX->users); ATX->users = nt_create (NT_CHAR); if (ATX->users == NULL) { LOG(LOG_CRIT, ERR_MEM_ALLOC); goto bail; } nt_add (ATX->users, user); } free(buf); line++; } return NULL; bail: buffer_destroy(message); return NULL; }
void *process_connection(void *ptr) { char *server_ident = _ds_read_attribute(agent_config, "ServerIdent"); THREAD_CTX *TTX = (THREAD_CTX *) ptr; AGENT_CTX *ATX = NULL; char *input, *cmdline = NULL, *token, *ptrptr; buffer *message = NULL; char *parms=NULL, *p=NULL; int i, locked = -1, invalid = 0; int server_mode = SSM_DSPAM; char *argv[64]; char buf[1024]; int tries = 0; int argc = 0; FILE *fd = 0; if (_ds_read_attribute(agent_config, "ServerMode") && !strcasecmp(_ds_read_attribute(agent_config, "ServerMode"), "standard")) { server_mode = SSM_STANDARD; } if (_ds_read_attribute(agent_config, "ServerMode") && !strcasecmp(_ds_read_attribute(agent_config, "ServerMode"), "auto")) { server_mode = SSM_AUTO; } /* Initialize a file descriptor hook for dspam to use as stdout */ fd = fdopen(TTX->sockfd, "w"); if (!fd) { close(TTX->sockfd); goto CLOSE; } setbuf(fd, NULL); TTX->packet_buffer = buffer_create(NULL); if (TTX->packet_buffer == NULL) goto CLOSE; /* * Send greeting banner * in auto mode, we want to look like a regular LMTP server so we don't * cause any compatibility problems. in dspam mode, we can change this. */ snprintf(buf, sizeof(buf), "%d DSPAM %sLMTP %s %s", LMTP_GREETING, (server_mode == SSM_DSPAM) ? "D" : "", VERSION, (server_mode == SSM_DSPAM) ? "Authentication Required" : "Ready"); if (send_socket(TTX, buf)<=0) goto CLOSE; TTX->authenticated = 0; /* LHLO */ input = daemon_expect(TTX, "LHLO"); if (input == NULL) goto CLOSE; if (server_mode == SSM_AUTO && input[4]) { char buff[128]; /* * Auto-detect the server mode based on whether or not the ident is * assigned a password in dspam.conf */ snprintf(buff, sizeof(buff), "ServerPass.%s", input + 5); chomp(buff); if (_ds_read_attribute(agent_config, buff)) server_mode = SSM_DSPAM; else server_mode = SSM_STANDARD; } free(input); /* Advertise extensions */ if (daemon_extension(TTX, (server_ident) ? server_ident : "localhost.localdomain")<=0) goto CLOSE; if (daemon_extension(TTX, "PIPELINING")<=0) goto CLOSE; if (daemon_extension(TTX, "ENHANCEDSTATUSCODES")<=0) goto CLOSE; if (server_mode == SSM_DSPAM) if (daemon_extension(TTX, "DSPAMPROCESSMODE")<=0) goto CLOSE; if (daemon_extension(TTX, "8BITMIME")<=0) goto CLOSE; if (daemon_reply(TTX, LMTP_OK, "", "SIZE")<=0) goto CLOSE; /* Main protocol loop */ while(1) { char processmode[256]; parms = NULL; /* Configure a new agent context for each pass */ ATX = calloc(1, sizeof(AGENT_CTX)); if (ATX == NULL) { LOG(LOG_CRIT, ERR_MEM_ALLOC); daemon_reply(TTX, LMTP_TEMP_FAIL, "4.3.0", ERR_MEM_ALLOC); goto CLOSE; } if (initialize_atx(ATX)) { LOG(LOG_ERR, ERR_AGENT_INIT_ATX); daemon_reply(TTX, LMTP_BAD_CMD, "5.3.0", ERR_AGENT_INIT_ATX); goto CLOSE; } /* MAIL FROM (and authentication, if SSM_DSPAM) */ processmode[0] = 0; while(!TTX->authenticated) { input = daemon_expect(TTX, "MAIL FROM"); if (RSET(input)) goto RSET; if (input == NULL) goto CLOSE; else { char *pass, *ident; chomp(input); if (server_mode == SSM_STANDARD) { TTX->authenticated = 1; ATX->mailfrom[0] = 0; _ds_extract_address(ATX->mailfrom, input, sizeof(ATX->mailfrom)); if (daemon_reply(TTX, LMTP_OK, "2.1.0", "OK")<=0) { free(input); goto CLOSE; } } else { char id[256]; pass = ident = NULL; id[0] = 0; if (!_ds_extract_address(id, input, sizeof(id))) { pass = strtok_r(id, "@", &ptrptr); ident = strtok_r(NULL, "@", &ptrptr); } if (pass && ident) { char *serverpass; char *ptr, *ptr2, *ptr3; snprintf(buf, sizeof(buf), "ServerPass.%s", ident); serverpass = _ds_read_attribute(agent_config, buf); snprintf(buf, sizeof(buf), "ServerPass.%s", ident); if (serverpass && !strcmp(pass, serverpass)) { TTX->authenticated = 1; /* Parse PROCESSMODE service tag */ ptr = strstr(input, "DSPAMPROCESSMODE=\""); if (ptr) { char *mode; int i; ptr2 = strchr(ptr, '"')+1; mode = ptr2; while((ptr3 = strstr(ptr2, "\\\""))) ptr2 = ptr3+2; ptr3 = strchr(ptr2+2, '"'); if (ptr3) ptr3[0] = 0; strlcpy(processmode, mode, sizeof(processmode)); ptr = processmode; for(i=0; ptr[i]; i++) { if (ptr[i] == '\\' && ptr[i+1] == '"') { strcpy(ptr+i, ptr+i+1); } } LOGDEBUG("process mode: '%s'", processmode); } if (daemon_reply(TTX, LMTP_OK, "2.1.0", "OK")<=0) { free(input); goto CLOSE; } } } } free(input); if (!TTX->authenticated) { LOGDEBUG("fd %d authentication failure.", TTX->sockfd); if (daemon_reply(TTX, LMTP_AUTH_ERROR, "5.1.0", "Authentication Required")<=0) { free(input); goto CLOSE; } tries++; if (tries>=3) { struct timeval tv; tv.tv_sec = 5; tv.tv_usec = 0; select(0, NULL, NULL, NULL, &tv); goto CLOSE; } } } } /* MAIL FROM response */ snprintf(buf, sizeof(buf), "%d OK", LMTP_OK); argc = 1; argv[0] = "dspam"; argv[1] = 0; /* Load open-LMTP configuration parameters */ if (server_mode == SSM_STANDARD) { parms = _ds_read_attribute(agent_config, "ServerParameters"); if (parms) { p = strdup(parms); if (p) { token = strtok_r(p, " ", &ptrptr); while(token != NULL && argc<63) { argv[argc] = token; argc++; argv[argc] = 0; token = strtok_r(NULL, " ", &ptrptr); } } } } /* RCPT TO */ while(ATX->users->items == 0 || invalid) { free(cmdline); cmdline = daemon_getline(TTX, 300); while(cmdline && (!strncasecmp(cmdline, "RCPT TO:", 8) || !strncasecmp(cmdline, "RSET", 4))) { char username[256]; char *at = NULL; if (!strncasecmp(cmdline, "RSET", 4)) { snprintf(buf, sizeof(buf), "%d OK", LMTP_OK); if (send_socket(TTX, buf)<=0) goto CLOSE; goto RSET; } if (_ds_extract_address(username, cmdline, sizeof(username)) || username[0] == 0 || username[0] == '-' || username[0] == '@') { if ((server_mode == SSM_DSPAM) || (server_mode == SSM_STANDARD && _ds_validate_address(username) == 0)) { daemon_reply(TTX, LMTP_BAD_CMD, "5.1.2", ERR_LMTP_BAD_RCPT); goto GETCMD; } } if (_ds_match_attribute(agent_config, "Broken", "case")) lc(username, username); /* Chop of @.* from the recipient */ if (_ds_match_attribute(agent_config, "StripRcptDomain", "on")) { at = strchr(username, '@'); if (at != NULL) *at = '\0'; } if (server_mode == SSM_DSPAM) { nt_add(ATX->users, username); } else { if (!parms || !strstr(parms, "--user ")) nt_add(ATX->users, username); if (!ATX->recipients) { ATX->recipients = nt_create(NT_CHAR); if (ATX->recipients == NULL) { LOG(LOG_CRIT, ERR_MEM_ALLOC); goto CLOSE; } } if (at != NULL) *at = '@'; /* always add complete address (user@domain) to recipient list */ nt_add(ATX->recipients, username); } if (daemon_reply(TTX, LMTP_OK, "2.1.5", "OK")<=0) goto CLOSE; GETCMD: free(cmdline); cmdline = daemon_getline(TTX, 300); } if (cmdline == NULL) goto CLOSE; if (!strncasecmp(cmdline, "RSET", 4)) { snprintf(buf, sizeof(buf), "%d OK", LMTP_OK); if (send_socket(TTX, buf)<=0) goto CLOSE; goto RSET; } if (!strncasecmp(cmdline, "quit", 4)) { daemon_reply(TTX, LMTP_OK, "2.0.0", "OK"); goto CLOSE; } /* Parse DSPAMPROCESSMODE input and set up process arguments */ if (server_mode == SSM_DSPAM && processmode[0] != 0) { token = strtok_r(processmode, " ", &ptrptr); while(token != NULL && argc<63) { argv[argc] = token; argc++; argv[argc] = 0; token = strtok_r(NULL, " ", &ptrptr); } } invalid = 0; if (process_arguments(ATX, argc, argv) || apply_defaults(ATX)) { LOG(LOG_ERR, ERR_AGENT_INIT_ATX); daemon_reply(TTX, LMTP_NO_RCPT, "5.1.0", ERR_AGENT_INIT_ATX); invalid = 1; } else if (ATX->users->items == 0) { daemon_reply(TTX, LMTP_NO_RCPT, "5.1.1", ERR_AGENT_USER_UNDEFINED); } } ATX->sockfd = fd; ATX->sockfd_output = 0; /* Something's terribly misconfigured */ if (check_configuration(ATX)) { LOG(LOG_ERR, ERR_AGENT_MISCONFIGURED); daemon_reply(TTX, LMTP_BAD_CMD, "5.3.5", ERR_AGENT_MISCONFIGURED); goto CLOSE; } /* DATA */ if (cmdline != NULL) { if (strncasecmp(cmdline, "DATA", 4)) { if (daemon_reply(TTX, LMTP_BAD_CMD, "5.0.0", "Need DATA Here")<0) goto CLOSE; input = daemon_expect(TTX, "DATA"); if (input == NULL) goto CLOSE; if (RSET(input)) goto RSET; } } if (daemon_reply(TTX, LMTP_DATA, "", INFO_LMTP_DATA)<=0) goto CLOSE; /* * Read in the message from a DATA. I personally like to just hang up on * a client stupid enough to pass in a NULL message for DATA, but you're * welcome to do whatever you want. */ message = read_sock(TTX, ATX); if (message == NULL || message->data == NULL || message->used == 0) { daemon_reply(TTX, LMTP_FAILURE, "5.2.0", ERR_LMTP_MSG_NULL); goto CLOSE; } /* * Lock a database handle. We currently use the modulus of the socket * id against the number of database connections in the cache. This * seems to work rather well, as we would need to lock up the entire * cache to wrap back around. And if we do wrap back around, that means * we're busy enough to justify spinning on the current lock (vs. seeking * out a free handle, which there likely are none). */ i = (TTX->sockfd % TTX->DTX->connection_cache); LOGDEBUG("using database handle id %d", i); if (TTX->DTX->flags & DRF_RWLOCK) { if (ATX->operating_mode == DSM_CLASSIFY || ATX->training_mode == DST_NOTRAIN || (ATX->training_mode == DST_TOE && ATX->classification == DSR_NONE)) { pthread_rwlock_rdlock(&TTX->DTX->connections[i]->rwlock); } else { pthread_rwlock_wrlock(&TTX->DTX->connections[i]->rwlock); } } else { pthread_mutex_lock(&TTX->DTX->connections[i]->lock); } LOGDEBUG("handle locked"); ATX->dbh = TTX->DTX->connections[i]->dbh; locked = i; /* Process the message by tying back into the agent functions */ ATX->results = nt_create(NT_PTR); if (ATX->results == NULL) { LOG(LOG_CRIT, ERR_MEM_ALLOC); goto CLOSE; } process_users(ATX, message); /* * Unlock the database handle as soon as we're done. We also need to * refresh our handle index with a new handle if for some reason we * had to re-establish a dewedged connection. */ if (TTX->DTX->connections[locked]->dbh != ATX->dbh) TTX->DTX->connections[locked]->dbh = ATX->dbh; if (TTX->DTX->flags & DRF_RWLOCK) { pthread_rwlock_unlock(&TTX->DTX->connections[locked]->rwlock); } else { pthread_mutex_unlock(&TTX->DTX->connections[locked]->lock); } locked = -1; /* Send a terminating '.' if --stdout in 'dspam' mode */ if (ATX->sockfd_output) { if (send_socket(TTX, ".")<=0) goto CLOSE; /* Otherwise, produce standard delivery results */ } else { struct nt_node *node_nt, *node_res = NULL; struct nt_c c_nt; if (ATX->recipients) node_nt = c_nt_first(ATX->recipients, &c_nt); else node_nt = c_nt_first(ATX->users, &c_nt); if (ATX->results) node_res = ATX->results->first; while(node_res && node_nt != NULL) { agent_result_t result = (agent_result_t) node_res->ptr; if (result != NULL && result->exitcode == ERC_SUCCESS) { if (server_mode == SSM_DSPAM) { snprintf(buf, sizeof(buf), "%d 2.6.0 <%s> Message accepted for delivery: %s", LMTP_OK, (char *) node_nt->ptr, (result->classification == DSR_ISSPAM) ? "SPAM" : "INNOCENT"); } else { snprintf(buf, sizeof(buf), "%d 2.6.0 <%s> Message accepted for delivery", LMTP_OK, (char *) node_nt->ptr); } } else { if (result != NULL && result->exitcode == ERC_PERMANENT_DELIVERY) { snprintf(buf, sizeof(buf), "%d 5.3.0 <%s> %s", LMTP_FAILURE, (char *) node_nt->ptr, (result->text[0]) ? result->text : "Permanent error occured"); } else { if (result != NULL && result->text[0]) { snprintf(buf, sizeof(buf), "%d 4.3.0 <%s> %s", LMTP_TEMP_FAIL, (char *) node_nt->ptr, result->text); } else { snprintf(buf, sizeof(buf), "%d 4.3.0 <%s> Error occured during %s", LMTP_TEMP_FAIL, (char *) node_nt->ptr, (result != NULL && result->exitcode == ERC_DELIVERY) ? "delivery" : "processing"); } } } if (send_socket(TTX, buf)<=0) goto CLOSE; if (ATX->recipients) node_nt = c_nt_next(ATX->recipients, &c_nt); else node_nt = c_nt_next(ATX->users, &c_nt); if (node_res) node_res = node_res->next; } } /* Cleanup and get ready for another message */ RSET: fflush(fd); buffer_destroy(message); message = NULL; if (ATX != NULL) { nt_destroy(ATX->users); nt_destroy(ATX->recipients); nt_destroy(ATX->results); free(ATX); ATX = NULL; free(cmdline); cmdline = NULL; TTX->authenticated = 0; /* argc = 0; */ } free(p); p = NULL; } /* while(1) */ /* Close connection and return */ CLOSE: if (locked>=0) pthread_mutex_unlock(&TTX->DTX->connections[locked]->lock); if (fd) fclose(fd); buffer_destroy(TTX->packet_buffer); if (message) buffer_destroy(message); if (ATX != NULL) { nt_destroy(ATX->users); nt_destroy(ATX->recipients); nt_destroy(ATX->results); } free(ATX); free(cmdline); free(TTX); decrement_thread_count(); pthread_exit(0); return 0; }
int _ds_init_storage (DSPAM_CTX * CTX, void *dbh) { struct _hash_drv_storage *s = NULL; hash_drv_map_t map = NULL; int ret; if (CTX == NULL) return EINVAL; if (!CTX->home) { LOG(LOG_ERR, ERR_AGENT_DSPAM_HOME); return EINVAL; } if (CTX->flags & DSF_MERGED) { LOG(LOG_ERR, ERR_DRV_NO_MERGED); return EINVAL; } if (CTX->storage) return EINVAL; /* Persistent driver storage */ s = calloc (1, sizeof (struct _hash_drv_storage)); if (s == NULL) { LOG(LOG_CRIT, ERR_MEM_ALLOC); return EUNKNOWN; } /* If running in HashConcurrentUser mode, use existing hash mapping */ if (dbh) { map = dbh; s->dbh_attached = 1; } else { map = calloc(1, sizeof(struct _hash_drv_map)); if (!map) { LOG(LOG_CRIT, ERR_MEM_ALLOC); free(s); return EUNKNOWN; } s->dbh_attached = 0; } s->map = map; /* Mapping defaults */ s->hash_rec_max = HASH_REC_MAX; s->max_seek = HASH_SEEK_MAX; s->max_extents = 0; s->extent_size = HASH_EXTENT_MAX; s->pctincrease = 0; s->flags = HMAP_AUTOEXTEND; if (READ_ATTRIB("HashRecMax")) s->hash_rec_max = strtol(READ_ATTRIB("HashRecMax"), NULL, 0); if (READ_ATTRIB("HashExtentSize")) s->extent_size = strtol(READ_ATTRIB("HashExtentSize"), NULL, 0); if (READ_ATTRIB("HashMaxExtents")) s->max_extents = strtol(READ_ATTRIB("HashMaxExtents"), NULL, 0); if (!MATCH_ATTRIB("HashAutoExtend", "on")) s->flags = 0; if (READ_ATTRIB("HashPctIncrease")) { s->pctincrease = atoi(READ_ATTRIB("HashPctIncrease")); if (s->pctincrease > 100) { LOG(LOG_ERR, "HashPctIncrease out of range; ignoring"); s->pctincrease = 0; } } if (READ_ATTRIB("HashMaxSeek")) s->max_seek = strtol(READ_ATTRIB("HashMaxSeek"), NULL, 0); if (!dbh && CTX->username != NULL) { char db[MAX_FILENAME_LENGTH]; int lock_result; if (CTX->group == NULL) _ds_userdir_path(db, CTX->home, CTX->username, "css"); else _ds_userdir_path(db, CTX->home, CTX->group, "css"); lock_result = _hash_drv_lock_get (CTX, s, (CTX->group) ? CTX->group : CTX->username); if (lock_result < 0) goto BAIL; ret = _hash_drv_open(db, s->map, s->hash_rec_max, s->max_seek, s->max_extents, s->extent_size, s->pctincrease, s->flags); if (ret) { _hash_drv_close(s->map); free(s); return EFAILURE; } } CTX->storage = s; s->dir_handles = nt_create (NT_INDEX); if (_hash_drv_get_spamtotals (CTX)) { LOGDEBUG ("unable to load totals. using zero values."); memset (&CTX->totals, 0, sizeof (struct _ds_spam_totals)); } return 0; BAIL: free(s); return EFAILURE; }
int main (int argc, char *argv[]) { DSPAM_CTX *CTX = NULL, *CTX2; char *user; int do_sigs = 0; int do_probs = 0; int do_unused = 0; int age_sigs = 14; int age_probs = 30; int age_unused[4] = { 90, 30, 15, 15 }; int i, help = 0; struct nt *users = NULL; struct nt_node *node = NULL; #ifndef _WIN32 #ifdef TRUSTED_USER_SECURITY struct passwd *p = getpwuid (getuid ()); #endif #endif /* Read dspam.conf */ agent_config = read_config(NULL); if (!agent_config) { LOG(LOG_ERR, ERR_AGENT_READ_CONFIG); fprintf (stderr, ERR_AGENT_READ_CONFIG "\n"); exit(EXIT_FAILURE); } if (!_ds_read_attribute(agent_config, "Home")) { LOG(LOG_ERR, ERR_AGENT_DSPAM_HOME); fprintf (stderr, ERR_AGENT_DSPAM_HOME "\n"); goto bail; } if (libdspam_init(_ds_read_attribute(agent_config, "StorageDriver")) != 0) { LOG(LOG_ERR, ERR_DRV_INIT); fprintf (stderr, ERR_DRV_INIT "\n"); _ds_destroy_config(agent_config); exit(EXIT_FAILURE); } #ifndef _WIN32 #ifdef TRUSTED_USER_SECURITY if (!_ds_match_attribute(agent_config, "Trust", p->pw_name) && p->pw_uid) { fprintf(stderr, ERR_TRUSTED_MODE "\n"); goto bail; } #endif #endif for(i=0;i<argc;i++) { if (!strncmp (argv[i], "--profile=", 10)) { if (!_ds_match_attribute(agent_config, "Profile", argv[i]+10)) { LOG(LOG_ERR, ERR_AGENT_NO_SUCH_PROFILE, argv[i]+10); fprintf (stderr, ERR_AGENT_NO_SUCH_PROFILE "\n", argv[i]+10); goto bail; } else { _ds_overwrite_attribute(agent_config, "DefaultProfile", argv[i]+10); } break; } } #ifdef DEBUG fprintf (stdout, "dspam_clean starting\n"); #endif if (_ds_read_attribute(agent_config, "PurgeSignatures") && !_ds_match_attribute(agent_config, "PurgeSignatures", "off")) { do_sigs = 1; age_sigs = atoi(_ds_read_attribute(agent_config, "PurgeSignatures")); } if (_ds_read_attribute(agent_config, "PurgeNeutral") && !_ds_match_attribute(agent_config, "PurgeNeutral", "off")) { do_probs = 1; age_probs = atoi(_ds_read_attribute(agent_config, "PurgeNeutral")); } if (_ds_read_attribute(agent_config, "PurgeUnused") && !_ds_match_attribute(agent_config, "PurgeUnused", "off")) { int i; do_unused = 1; age_unused[0] = atoi(_ds_read_attribute(agent_config, "PurgeUnused")); age_unused[1] = atoi(_ds_read_attribute(agent_config, "PurgeHapaxes")); age_unused[2] = atoi(_ds_read_attribute(agent_config, "PurgeHits1S")); age_unused[3] = atoi(_ds_read_attribute(agent_config, "PurgeHits1I")); for(i=0;i<4;i++) if (age_unused[i]==0) do_unused = 0; } users = nt_create(NT_CHAR); if (users == NULL) { fprintf(stderr, "%s", ERR_MEM_ALLOC); goto bail; } for(i=0;i<argc;i++) { if (!strncmp(argv[i], "-p", 2)) { do_probs = 1; if (strlen(argv[i])>2) age_probs = atoi(argv[i]+2); } else if (!strncmp(argv[i], "-s", 2)) { do_sigs = 1; if (strlen(argv[i])>2) age_sigs = atoi(argv[i]+2); } else if (!strncmp(argv[i], "-u", 2)) { do_unused = 1; if (strlen(argv[i])>2) { char *c = strdup(argv[i]+2); char *d = strtok(c, ","); int j = 0; while(d != NULL && j<4) { age_unused[j] = atoi(d); j++; d = strtok(NULL, ","); } free(c); } } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) help = 1; else if (i>0) nt_add(users, argv[i]); } if (help || (!do_probs && !do_sigs && !do_unused)) { fprintf(stderr, "%s", CLEANSYNTAX); _ds_destroy_config(agent_config); nt_destroy(users); libdspam_shutdown(); if (help) { exit(EXIT_SUCCESS); } exit(EXIT_FAILURE); } open_ctx = open_mtx = NULL; signal (SIGINT, dieout); signal (SIGPIPE, dieout); signal (SIGTERM, dieout); dspam_init_driver (NULL); if (users->items == 0) { CTX = dspam_create (NULL, NULL, _ds_read_attribute(agent_config, "Home"), DSM_TOOLS, 0); open_ctx = CTX; if (CTX == NULL) { fprintf (stderr, "Could not initialize context: %s\n", strerror (errno)); dspam_shutdown_driver (NULL); goto bail; } set_libdspam_attributes(CTX); if (dspam_attach(CTX, NULL)) { LOG (LOG_WARNING, "unable to attach dspam context"); fprintf (stderr, "Unable to attach DSPAM context\n"); goto bail; } user = _ds_get_nextuser (CTX); } else { node = users->first; if (node != NULL) user = node->ptr; else goto bail; } while (user != NULL) { #ifdef DEBUG printf ("PROCESSING USER: %s\n", user); #endif CTX2 = dspam_create (user, NULL, _ds_read_attribute(agent_config, "Home"), DSM_TOOLS, 0); open_mtx = CTX2; if (CTX2 == NULL) { fprintf (stderr, "Could not initialize context: %s\n", strerror (errno)); return EUNKNOWN; } set_libdspam_attributes(CTX2); if (dspam_attach(CTX2, NULL)) { LOG (LOG_WARNING, "unable to attach dspam context"); fprintf (stderr, "Unable to attach DSPAM context\n"); goto bail; } if (do_sigs) process_sigs(CTX2, age_sigs); if (do_probs) process_probs(CTX2, age_probs); if (do_unused) process_unused(CTX2, age_unused[0], age_unused[1], age_unused[2], age_unused[3]); dspam_destroy (CTX2); open_mtx = NULL; if (users->items == 0) { user = _ds_get_nextuser (CTX); } else { if (node == NULL || node->next == NULL) { node = NULL; user = NULL; } else { node = node->next; user = node->ptr; } } } if (users->items == 0) { dspam_destroy (CTX); open_ctx = NULL; } dspam_shutdown_driver (NULL); _ds_destroy_config(agent_config); nt_destroy(users); libdspam_shutdown(); exit (EXIT_SUCCESS); bail: if (open_ctx) dspam_destroy(open_ctx); if (open_mtx) dspam_destroy(open_mtx); _ds_destroy_config(agent_config); nt_destroy(users); libdspam_shutdown(); exit(EXIT_FAILURE); }