int _ds_ff_pref_set ( config_t config, const char *username, const char *home, const char *preference, const char *value, void *ignore) { char filename[MAX_FILENAME_LENGTH]; FILE *out_file; config = config; /* Keep compiler happy */ ignore = ignore; /* Keep compiler happy */ if (username == NULL) { snprintf(filename, MAX_FILENAME_LENGTH, "%s/default.prefs", home); } else { _ds_userdir_path (filename, home, username, "prefs"); } out_file = _ds_ff_pref_prepare_file(filename, preference, NULL); if (out_file == NULL) return EFAILURE; fprintf(out_file, "%s=%s\n", preference, value); return _ds_ff_pref_commit(filename, out_file); }
int _ds_ff_pref_del ( config_t config, const char *username, const char *home, const char *preference, void *ignore) { char filename[MAX_FILENAME_LENGTH]; FILE *out_file; int nlines; config = config; /* Keep compiler happy */ ignore = ignore; /* Keep compiler happy */ if (username == NULL) { snprintf(filename, MAX_FILENAME_LENGTH, "%s/default.prefs", home); } else { _ds_userdir_path (filename, home, username, "prefs"); } out_file = _ds_ff_pref_prepare_file(filename, preference, &nlines); if (out_file == NULL) return EFAILURE; if (!nlines) { char backup[MAX_FILENAME_LENGTH]; fclose(out_file); snprintf(backup, sizeof(backup), "%s.bak", filename); unlink(backup); return unlink(filename); } return _ds_ff_pref_commit(filename, out_file); }
int _ds_set_signature (DSPAM_CTX * CTX, struct _ds_spam_signature *SIG, const char *signature) { char filename[MAX_FILENAME_LENGTH]; char scratch[128]; FILE *file; _ds_userdir_path(filename, CTX->home, (CTX->group) ? CTX->group : CTX->username, "sig"); snprintf(scratch, sizeof(scratch), "/%s.sig", signature); strlcat(filename, scratch, sizeof(filename)); _ds_prepare_path_for(filename); file = fopen(filename, "w"); if (!file) { LOG(LOG_ERR, ERR_IO_FILE_WRITE, filename, strerror(errno)); return EFAILURE; } if(fwrite(SIG->data, SIG->length, 1, file)!=1) { fclose(file); unlink(filename); LOG(LOG_ERR, ERR_IO_FILE_WRITING, filename, strerror(errno)); return(EFAILURE); } fclose(file); return 0; }
agent_pref_t _ds_ff_pref_load( config_t config, const char *user, const char *home, void *ignore) { char filename[MAX_FILENAME_LENGTH]; agent_pref_t PTX = malloc(sizeof(agent_attrib_t )*PREF_MAX); char buff[258]; FILE *file; char *p, *q, *bufptr; int i = 0; UNUSED(config); UNUSED(ignore); if (PTX == NULL) { LOG(LOG_CRIT, ERR_MEM_ALLOC); return NULL; } PTX[0] = NULL; if (user == NULL) { snprintf(filename, MAX_FILENAME_LENGTH, "%s/default.prefs", home); } else { _ds_userdir_path (filename, home, user, "prefs"); } file = fopen(filename, "r"); /* Apply default preferences from dspam.conf */ if (file != NULL) { char *ptrptr; while(i<(PREF_MAX-1) && fgets(buff, sizeof(buff), file)!=NULL) { if (buff[0] == '#' || buff[0] == 0) continue; chomp(buff); bufptr = buff; p = strtok_r(buff, "=", &ptrptr); if (p == NULL) continue; q = p + strlen(p)+1; LOGDEBUG("Loading preference '%s' = '%s'", p, q); PTX[i] = _ds_pref_new(p, q); PTX[i+1] = NULL; i++; } fclose(file); } else { free(PTX); return NULL; } return PTX; }
int _ds_delete_signature (DSPAM_CTX * CTX, const char *signature) { char filename[MAX_FILENAME_LENGTH]; char scratch[128]; _ds_userdir_path(filename, CTX->home, (CTX->group) ? CTX->group : CTX->username, "sig"); snprintf(scratch, sizeof(scratch), "/%s.sig", signature); strlcat(filename, scratch, sizeof(filename)); return unlink(filename); }
int _ds_verify_signature (DSPAM_CTX * CTX, const char *signature) { char filename[MAX_FILENAME_LENGTH]; char scratch[128]; struct stat statbuf; _ds_userdir_path(filename, CTX->home, (CTX->group) ? CTX->group : CTX->username, "sig"); snprintf(scratch, sizeof(scratch), "/%s.sig", signature); strlcat(filename, scratch, sizeof(filename)); if (stat (filename, &statbuf)) return 1; return 0; }
int _ds_get_signature (DSPAM_CTX * CTX, struct _ds_spam_signature *SIG, const char *signature) { char filename[MAX_FILENAME_LENGTH]; char scratch[128]; FILE *file; struct stat statbuf; _ds_userdir_path(filename, CTX->home, (CTX->group) ? CTX->group : CTX->username, "sig"); snprintf(scratch, sizeof(scratch), "/%s.sig", signature); strlcat(filename, scratch, sizeof(filename)); if (stat (filename, &statbuf)) { LOG(LOG_ERR, ERR_IO_FILE_OPEN, filename, strerror(errno)); return EFAILURE; }; SIG->data = malloc(statbuf.st_size); if (!SIG->data) { LOG(LOG_CRIT, ERR_MEM_ALLOC); return EUNKNOWN; } file = fopen(filename, "r"); if (!file) { LOG(LOG_ERR, ERR_IO_FILE_OPEN, filename, strerror(errno)); return EFAILURE; } fread(SIG->data, statbuf.st_size, 1, file); SIG->length = statbuf.st_size; fclose(file); return 0; }
int _hash_drv_lock_get ( DSPAM_CTX *CTX, struct _hash_drv_storage *s, const char *username) { char filename[MAX_FILENAME_LENGTH]; int r; _ds_userdir_path(filename, CTX->home, username, "lock"); _ds_prepare_path_for(filename); s->lock = fopen(filename, "a"); if (s->lock == NULL) { LOG(LOG_ERR, ERR_IO_FILE_WRITE, filename, strerror(errno)); return EFAILURE; } r = _ds_get_fcntl_lock(fileno(s->lock)); if (r) { fclose(s->lock); LOG(LOG_ERR, ERR_IO_LOCK, filename, r, strerror(errno)); } return r; }
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; }
int dspam_init_driver (DRIVER_CTX *DTX) { DSPAM_CTX *CTX; char *HashConcurrentUser; #ifdef DAEMON unsigned long connection_cache = 1; #endif if (DTX == NULL) return 0; CTX = DTX->CTX; HashConcurrentUser = READ_ATTRIB("HashConcurrentUser"); #ifdef DAEMON /* * Stateful concurrent hash databases are preloaded into memory and * shared using a reader-writer lock. At the present moment, only a single * user can be loaded into any instance of the daemon, so it is only useful * if you are running with a system-wide filtering user. */ if (DTX->flags & DRF_STATEFUL) { char filename[MAX_FILENAME_LENGTH]; hash_drv_map_t map; unsigned long hash_rec_max = HASH_REC_MAX; unsigned long max_seek = HASH_SEEK_MAX; unsigned long max_extents = 0; unsigned long extent_size = HASH_EXTENT_MAX; int pctincrease = 0; int flags = HMAP_AUTOEXTEND; int ret, i; if (READ_ATTRIB("HashConnectionCache") && !HashConcurrentUser) connection_cache = strtol(READ_ATTRIB("HashConnectionCache"), NULL, 0); DTX->connection_cache = connection_cache; if (READ_ATTRIB("HashRecMax")) hash_rec_max = strtol(READ_ATTRIB("HashRecMax"), NULL, 0); if (READ_ATTRIB("HashExtentSize")) extent_size = strtol(READ_ATTRIB("HashExtentSize"), NULL, 0); if (READ_ATTRIB("HashMaxExtents")) max_extents = strtol(READ_ATTRIB("HashMaxExtents"), NULL, 0); if (!MATCH_ATTRIB("HashAutoExtend", "on")) flags = 0; if (READ_ATTRIB("HashPctIncrease")) { pctincrease = atoi(READ_ATTRIB("HashPctIncrease")); if (pctincrease > 100) { LOG(LOG_ERR, "HashPctIncrease out of range; ignoring"); pctincrease = 0; } } if (READ_ATTRIB("HashMaxSeek")) max_seek = strtol(READ_ATTRIB("HashMaxSeek"), NULL, 0); /* Connection array (just one single connection for hash_drv) */ DTX->connections = calloc(1, sizeof(struct _ds_drv_connection *) * connection_cache); if (DTX->connections == NULL) goto memerr; /* Initialize Connections */ for(i=0;i<connection_cache;i++) { DTX->connections[i] = calloc(1, sizeof(struct _ds_drv_connection)); if (DTX->connections[i] == NULL) goto memerr; /* Our connection's storage structure */ if (HashConcurrentUser) { DTX->connections[i]->dbh = calloc(1, sizeof(struct _hash_drv_map)); if (DTX->connections[i]->dbh == NULL) goto memerr; pthread_rwlock_init(&DTX->connections[i]->rwlock, NULL); } else { DTX->connections[i]->dbh = NULL; pthread_mutex_init(&DTX->connections[i]->lock, NULL); } } /* Load concurrent database into resident memory */ if (HashConcurrentUser) { map = (hash_drv_map_t) DTX->connections[0]->dbh; /* Tell the server our connection lock will be reader/writer based */ if (!(DTX->flags & DRF_RWLOCK)) DTX->flags |= DRF_RWLOCK; _ds_userdir_path(filename, DTX->CTX->home, HashConcurrentUser, "css"); _ds_prepare_path_for(filename); LOGDEBUG("preloading %s into memory via mmap()", filename); ret = _hash_drv_open(filename, map, hash_rec_max, max_seek, max_extents, extent_size, pctincrease, flags); if (ret) { LOG(LOG_CRIT, "_hash_drv_open(%s) failed on error %d: %s", filename, ret, strerror(errno)); free(DTX->connections[0]->dbh); free(DTX->connections[0]); free(DTX->connections); return EFAILURE; } } } #endif return 0; #ifdef DAEMON memerr: if (DTX) { if (DTX->connections) { int i; for(i=0;i<connection_cache;i++) { if (DTX->connections[i]) free(DTX->connections[i]->dbh); free(DTX->connections[i]); } } free(DTX->connections); } LOG(LOG_CRIT, ERR_MEM_ALLOC); return EUNKNOWN; #endif }
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; }