1 /* $Id: dspam_merge.c,v 1.158 2011/06/28 00:13:48 sbajic Exp $ */
2 
3 /*
4  DSPAM
5  COPYRIGHT (C) 2002-2012 DSPAM PROJECT
6 
7  This program is free software: you can redistribute it and/or modify
8  it under the terms of the GNU Affero General Public License as
9  published by the Free Software Foundation, either version 3 of the
10  License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  GNU Affero General Public License for more details.
16 
17  You should have received a copy of the GNU Affero General Public License
18  along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 
20 */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <auto-config.h>
24 #endif
25 
26 #define DEBUG	1
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <fcntl.h>
32 #include <dirent.h>
33 #include <ctype.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <errno.h>
37 #include <signal.h>
38 #include <sys/param.h>
39 #include "config.h"
40 #include "util.h"
41 
42 #include "libdspam.h"
43 #include "language.h"
44 #include "read_config.h"
45 #include "config_api.h"
46 
47 #define TSYNTAX	"syntax: dspam_merge [user1] [user2] ... [userN] [-o user]"
48 
49 DSPAM_CTX *open_ctx, *open_mtx;
50 void dieout (int signal);
51 
52 int
main(int argc,char ** argv)53 main (int argc, char **argv)
54 {
55   char destuser[MAX_USERNAME_LENGTH];
56   struct nt *users = NULL;
57   struct nt_node *node_nt;
58   struct nt_c c_nt;
59   struct _ds_storage_record *token;
60   ds_diction_t merge1 = NULL;
61   ds_diction_t merge2 = NULL;
62   DSPAM_CTX *CTX, *MTX;
63   ds_term_t ds_term;
64   ds_cursor_t ds_c;
65   long i;
66 #ifndef _WIN32
67 #ifdef TRUSTED_USER_SECURITY
68   struct passwd *p = getpwuid (getuid ());
69 
70 #endif
71 #endif
72 
73  /* Read dspam.conf */
74 
75   agent_config = read_config(NULL);
76   if (!agent_config) {
77     LOG(LOG_ERR, ERR_AGENT_READ_CONFIG);
78     fprintf (stderr, ERR_AGENT_READ_CONFIG "\n");
79     exit(EXIT_FAILURE);
80   }
81 
82   if (!_ds_read_attribute(agent_config, "Home")) {
83     LOG(LOG_ERR, ERR_AGENT_DSPAM_HOME);
84     fprintf (stderr, ERR_AGENT_DSPAM_HOME "\n");
85     _ds_destroy_config(agent_config);
86     exit(EXIT_FAILURE);
87   }
88 
89   if (libdspam_init(_ds_read_attribute(agent_config, "StorageDriver")) != 0) {
90     LOG(LOG_ERR, ERR_DRV_INIT);
91     fprintf (stderr, ERR_DRV_INIT "\n");
92     _ds_destroy_config(agent_config);
93     exit(EXIT_FAILURE);
94   }
95 
96 #ifndef _WIN32
97 #ifdef TRUSTED_USER_SECURITY
98   if (!_ds_match_attribute(agent_config, "Trust", p->pw_name) && p->pw_uid) {
99     fprintf(stderr, ERR_TRUSTED_MODE "\n");
100     _ds_destroy_config(agent_config);
101     goto bail;
102   }
103 #endif
104 #endif
105 
106   if (argc < 4)
107   {
108     printf ("%s\n", TSYNTAX);
109     _ds_destroy_config(agent_config);
110     goto bail;
111   }
112 
113   open_ctx = open_mtx = NULL;
114   signal (SIGINT, dieout);
115   signal (SIGPIPE, dieout);
116   signal (SIGTERM, dieout);
117 
118   dspam_init_driver (NULL);
119   users = nt_create (NT_CHAR);
120 
121   if (users == NULL)
122   {
123     fprintf (stderr, ERR_MEM_ALLOC);
124     goto bail;
125   }
126 
127   for (i = 1; i < argc; i++)
128   {
129 
130     if (!strncmp (argv[i], "--profile=", 10))
131     {
132       if (!_ds_match_attribute(agent_config, "Profile", argv[i]+10)) {
133         LOG(LOG_ERR, ERR_AGENT_NO_SUCH_PROFILE, argv[i]+10);
134         fprintf (stderr, ERR_AGENT_NO_SUCH_PROFILE "\n", argv[i]+10);
135         goto bail;
136       } else {
137         _ds_overwrite_attribute(agent_config, "DefaultProfile", argv[i]+10);
138       }
139       continue;
140     }
141 
142     if (!strcmp (argv[i], "-o"))
143     {
144       strlcpy (destuser, argv[i + 1], sizeof (destuser));
145       i += 1;
146       continue;
147     }
148     nt_add (users, argv[i]);
149   }
150 
151 #ifdef DEBUG
152   fprintf(stderr, "Destination user: %s\n", destuser);
153 #endif
154 
155   CTX = dspam_create (destuser, NULL, _ds_read_attribute(agent_config, "Home"), DSM_PROCESS, 0);
156   open_ctx = CTX;
157   if (CTX == NULL)
158   {
159     fprintf (stderr, "unable to initialize context: %s\n", strerror (errno));
160     goto bail;
161   }
162 
163   set_libdspam_attributes(CTX);
164   if (dspam_attach(CTX, NULL)) {
165     LOG (LOG_WARNING, "unable to attach dspam context");
166     fprintf (stderr, "Unable to attach DSPAM context\n");
167     goto bail;
168   }
169 
170   node_nt = c_nt_first (users, &c_nt);
171   while (node_nt != NULL)
172   {
173 #ifdef DEBUG
174     printf ("Merging user: %s\n", (const char *) node_nt->ptr);
175 #endif
176     merge1 = ds_diction_create(196613);
177     merge2 = ds_diction_create(196613);
178 
179     if (users == NULL || merge1 == NULL || merge2 == NULL)
180     {
181       fprintf (stderr, ERR_MEM_ALLOC);
182       goto bail;
183     }
184 
185     MTX = dspam_create ((const char *) node_nt->ptr, NULL, _ds_read_attribute(agent_config, "Home"), DSM_CLASSIFY, 0);
186     open_mtx = MTX;
187     if (MTX == NULL)
188     {
189       fprintf (stderr, "unable to initialize context: %s\n",
190                strerror (errno));
191       node_nt = c_nt_next (users, &c_nt);
192       continue;
193     }
194 
195     set_libdspam_attributes(MTX);
196     if (dspam_attach(MTX, NULL)) {
197       LOG (LOG_WARNING, "unable to attach dspam context");
198       fprintf (stderr, "Unable to attach DSPAM context\n");
199       goto bail;
200     }
201 
202     CTX->totals.spam_learned       += MTX->totals.spam_learned;
203     CTX->totals.innocent_learned   += MTX->totals.innocent_learned;
204 
205     token = _ds_get_nexttoken (MTX);
206     while (token != NULL)
207     {
208       char tok[128];
209       snprintf(tok, 128, "%llu", token->token);
210       ds_diction_touch (merge1, token->token, tok, 0);
211       ds_diction_touch (merge2, token->token, tok, 0);
212       token = _ds_get_nexttoken (MTX);
213     }
214 
215     _ds_getall_spamrecords(CTX, merge1);
216     _ds_getall_spamrecords(MTX, merge2);
217 
218     ds_c = ds_diction_cursor(merge2);
219     ds_term = ds_diction_next(ds_c);
220     i = 0;
221     while(ds_term) {
222       ds_term_t target = ds_diction_find(merge1, ds_term->key);
223       if (target) {
224         target->s.spam_hits += ds_term->s.spam_hits;
225         target->s.innocent_hits += ds_term->s.innocent_hits;
226         target->s.status |= TST_DIRTY;
227         _ds_set_spamrecord(CTX, target->key, &target->s);
228       }
229       ds_term = ds_diction_next(ds_c);
230       i++;
231     }
232 #ifdef DEBUG
233     printf ("processed %ld tokens\n", i);
234 #endif
235     node_nt = c_nt_next (users, &c_nt);
236     ds_diction_destroy(merge1);
237     ds_diction_destroy(merge2);
238     dspam_destroy (MTX);
239     open_mtx = NULL;
240   }
241 
242 #ifdef DEBUG
243   printf ("storing merged tokens...\n");
244 #endif
245 #ifdef DEBUG
246   printf ("completed.\n");
247 #endif
248   nt_destroy (users);
249   dspam_destroy (CTX);
250   open_ctx = NULL;
251   dspam_shutdown_driver (NULL);
252   _ds_destroy_config(agent_config);
253   libdspam_shutdown();
254   exit (EXIT_SUCCESS);
255 
256 bail:
257   if (merge1 != NULL)
258     ds_diction_destroy(merge1);
259   if (merge2 != NULL)
260     ds_diction_destroy(merge2);
261   if (open_ctx != NULL)
262     dspam_destroy (open_ctx);
263   if (open_mtx != NULL)
264     dspam_destroy (open_mtx);
265   dspam_shutdown_driver (NULL);
266   if (users != NULL)
267     nt_destroy(users);
268   _ds_destroy_config(agent_config);
269   libdspam_shutdown();
270   exit (EXIT_FAILURE);
271 }
272 
273 void
dieout(int signal)274 dieout (int signal)
275 {
276   signal = signal; /* Keep compile happy */
277   fprintf (stderr, "terminated.\n");
278   if (open_ctx != NULL)
279     dspam_destroy (open_ctx);
280   if (open_mtx != NULL)
281     dspam_destroy (open_mtx);
282   _ds_destroy_config(agent_config);
283   exit (EXIT_SUCCESS);
284 }
285