1 /* spmfilter - mail filtering framework
2 * Copyright (C) 2009-2013 Axel Steiner and SpaceNet AG
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 3 of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #define THIS_MODULE "internal"
19 #define _GNU_SOURCE
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <assert.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <sys/times.h>
28 #include <sys/time.h>
29
30 #include "smf_internal.h"
31 #include "smf_trace.h"
32 #include "smf_dict.h"
33 #include "smf_session.h"
34 #include "smf_lookup.h"
35
smf_internal_string_list_destroy(void * data)36 void smf_internal_string_list_destroy(void *data) {
37 char *s = (char *)data;
38 assert(data);
39 free(s);
40 }
41
smf_internal_dict_list_destroy(void * data)42 void smf_internal_dict_list_destroy(void *data) {
43 assert(data);
44 smf_dict_free((SMFDict_T *)data);
45 }
46
smf_internal_user_data_list_destroy(void * data)47 void smf_internal_user_data_list_destroy(void *data) {
48 assert(data);
49 SMFUserData_T *user_data = (SMFUserData_T *)data;
50 if (user_data->email != NULL)
51 free(user_data->email);
52
53 smf_dict_free(user_data->data);
54 free(data);
55 }
56
smf_internal_user_match(SMFSession_T * session,SMFList_T * result_attributes,SMFDict_T * d,char * addr)57 int smf_internal_user_match(SMFSession_T *session, SMFList_T *result_attributes, SMFDict_T *d, char *addr) {
58 SMFListElem_T *key_elem = NULL;
59 SMFListElem_T *attr_elem = NULL;
60 SMFList_T *keys = smf_dict_get_keys(d);
61 char *attr = NULL;
62 char *lookup_attr = NULL;
63 char *value = NULL;
64
65 key_elem = smf_list_head(keys);
66 while(key_elem != NULL) {
67 attr = (char *)smf_list_data(key_elem);
68 attr_elem = smf_list_head(result_attributes);
69 while(attr_elem != NULL) {
70 lookup_attr = (char *)smf_list_data(attr_elem);
71 if (strcmp(lookup_attr,attr)==0) {
72 value = smf_dict_get(d, attr);
73 if (strstr(value,addr)!=NULL) {
74 STRACE(TRACE_DEBUG,session->id,"found matching entry for address [%s] within attribute [%s]",addr,attr);
75 smf_list_free(keys);
76 return 1;
77 }
78 }
79 attr_elem = attr_elem->next;
80 }
81
82 key_elem = key_elem->next;
83 }
84
85 smf_list_free(keys);
86 return 0;
87 }
88
smf_internal_copy_user_data(SMFDict_T * origin)89 SMFDict_T *smf_internal_copy_user_data(SMFDict_T *origin) {
90 SMFDict_T *d = smf_dict_new();
91 SMFList_T *keys = NULL;
92 SMFListElem_T *e = NULL;
93 char *k = NULL;
94 char *v = NULL;
95
96 if (origin != NULL) {
97 keys = smf_dict_get_keys(origin);
98 e = smf_list_head(keys);
99 while(e != NULL) {
100 k = (char *)smf_list_data(e);
101 v = smf_dict_get(origin,k);
102 smf_dict_set(d,k,v);
103 e = e->next;
104 }
105
106 smf_list_free(keys);
107 }
108 return d;
109 }
110
smf_internal_get_user_result(SMFSettings_T * settings,SMFSession_T * session,SMFList_T * result,char * addr)111 SMFDict_T *smf_internal_get_user_result(SMFSettings_T *settings, SMFSession_T *session, SMFList_T *result, char *addr) {
112 SMFDict_T *d = NULL;
113 SMFListElem_T *e = NULL;
114
115 e = smf_list_head(result);
116
117 #ifdef HAVE_LDAP
118 while(e != NULL) {
119 d = (SMFDict_T *)smf_list_data(e);
120 if (smf_internal_user_match(session,settings->ldap_result_attributes,d,addr)==1)
121 break;
122
123 e = e->next;
124 }
125 #elif defined HAVE_ZDB
126 if (e != NULL)
127 d = (SMFDict_T *)smf_list_data(e);
128 #endif
129
130 return smf_internal_copy_user_data(d);
131 }
132
smf_internal_query_user(SMFSettings_T * settings,SMFSession_T * session,char * addr)133 int smf_internal_query_user(SMFSettings_T *settings, SMFSession_T *session, char *addr) {
134 char *query = NULL;
135 SMFList_T *result = NULL;
136 SMFUserData_T *user_data = NULL;
137
138 if (strlen(addr) == 0)
139 return 0;
140
141 #ifdef HAVE_LDAP
142 if (strcmp(settings->backend,"ldap")==0) {
143 if (smf_core_expand_string(settings->ldap_user_query,addr,&query) == -1) {
144 STRACE(TRACE_ERR, session->id, "failed to expand user query");
145 return -1;
146 }
147
148 result = smf_lookup_ldap_query(settings, session, query);
149 }
150 #endif
151
152 #ifdef HAVE_ZDB
153 if (strcmp(settings->backend,"sql")==0) {
154 if (smf_core_expand_string(settings->sql_user_query,addr,&query) == -1) {
155 STRACE(TRACE_ERR, session->id, "failed to expand user query");
156 return -1;
157 }
158 result = smf_lookup_sql_query(settings, session, query);
159 }
160 #endif
161
162 if (result != NULL) {
163 user_data = (SMFUserData_T *)calloc((size_t)1, sizeof(SMFUserData_T));
164 user_data->email = strdup(addr);
165
166 user_data->data = smf_internal_get_user_result(settings, session, result, addr);
167 smf_list_append(session->local_users, (void *)user_data);
168 smf_list_free(result);
169 }
170
171 if (query != NULL) {
172 free(query);
173 query = NULL;
174 }
175
176 return 0;
177 }
178
smf_internal_build_module_path(const char * libdir,const char * modname)179 char *smf_internal_build_module_path(const char *libdir, const char *modname) {
180 char *path = NULL;
181 char *t = NULL;
182
183 if (strncmp(modname,"lib",3)==0) {
184 #ifdef __APPLE__
185 asprintf(&t,"%s.dylib",modname);
186 #else
187 t = strdup(modname);
188 #endif
189 } else {
190 #ifdef __APPLE__
191 asprintf(&t,"lib%s.dylib", modname);
192 #else
193 asprintf(&t,"lib%s.so",modname);
194 #endif
195 }
196 asprintf(&path,"%s/%s",libdir,t);
197 free(t);
198
199 return path;
200 }
201
smf_internal_strip_email_addr(char * addr)202 char *smf_internal_strip_email_addr(char *addr) {
203 char *p1 = NULL;
204 char *p2 = NULL;
205 char *out = NULL;
206 size_t len1, len2, offset;
207
208 if (*addr == '<')
209 p1 = addr;
210 else
211 p1 = strchr(addr,'<');
212
213 if (p1 != NULL) {
214 len1 = strlen(++p1);
215 if ((p2 = strchr(p1,'>')) != NULL) {
216 len2 = strlen(p2);
217 offset = len1 - len2;
218 out = (char *)calloc(offset + 1, sizeof(char));
219 strncpy(out,p1,offset);
220 out[strlen(out)] = '\0';
221 } else
222 out = strdup(addr);
223 } else
224 out = strdup(addr);
225
226 return out;
227 }
228
smf_internal_readn(int fd,void * buf,size_t nbyte)229 ssize_t smf_internal_readn(int fd, void *buf, size_t nbyte) {
230 size_t n;
231 ssize_t br;
232 char *p = buf;
233
234 for (n = nbyte; n > 0; n -= br, p += br) {
235 if ((br = read(fd,p,n)) < 0) {
236 if (errno == EINTR)
237 br = 0;
238 else
239 return -1;
240 } else if (br == 0)
241 return (nbyte - n);
242 }
243
244 return nbyte;
245 }
246
smf_internal_writen(int fd,const void * buf,size_t nbyte)247 ssize_t smf_internal_writen(int fd, const void *buf, size_t nbyte) {
248 size_t n;
249 ssize_t bw;
250 const char *p = buf;
251
252 for (n = nbyte; n > 0; n -= bw, p += bw) {
253 if ((bw = write(fd,p,n)) < 0) {
254 if (errno == EINTR)
255 bw = 0;
256 else
257 return -1;
258 } else if (bw == 0)
259 return (nbyte - 1);
260 }
261
262 return nbyte;
263 }
264
smf_internal_readline(int fd,void * buf,size_t nbyte,void ** help)265 ssize_t smf_internal_readline(int fd, void *buf, size_t nbyte, void **help) {
266 size_t n;
267 ssize_t br;
268 char c, *ptr = buf;
269 readline_t *rl = *help;
270
271 if (rl == NULL) {
272 if ((rl = malloc(sizeof(readline_t))) == NULL)
273 return -1;
274
275 rl->count = 0;
276 rl->current = rl->buf;
277 *help = rl;
278 }
279
280 for (n = 1; n < nbyte; n++) {
281 if ((br = smf_internal_readcbuf(fd,&c,rl)) < 0)
282 return -1;
283
284 *ptr++ = c;
285 if ((br == 0) || ( c == '\n'))
286 break;
287 }
288
289 if ((br == 0) && (n == 1))
290 return 0;
291
292 *ptr = 0;
293 return n;
294 }
295
smf_internal_readcbuf(int fd,char * buf,readline_t * rl)296 ssize_t smf_internal_readcbuf(int fd, char *buf, readline_t *rl) {
297 while(rl->count < 1) {
298 if ((rl->count = read(fd, rl->buf, sizeof(rl->buf))) < 0) {
299 if (errno == EINTR)
300 rl->count = 0;
301 else
302 return -1;
303 } else if (rl->count == 0)
304 return 0;
305
306 rl->current = rl->buf;
307 }
308
309 *buf = *rl->current++;
310 rl->count--;
311
312 return 1;
313 }
314
smf_internal_init_runtime_stats(void)315 struct tms smf_internal_init_runtime_stats(void) {
316 struct tms start_acct;
317 times(&start_acct);
318
319 return start_acct;
320 }
321
smf_internal_print_runtime_stats(struct tms start_acct,const char * sid)322 void smf_internal_print_runtime_stats(struct tms start_acct, const char *sid) {
323 struct tms end_acct;
324
325 times(&end_acct);
326 STRACE(TRACE_DEBUG,sid,"CPU time (user and system): %0.5f",
327 (float)(end_acct.tms_utime - start_acct.tms_utime) + /* User CPU time */
328 (float)(end_acct.tms_stime - start_acct.tms_stime) + /* System CPU time */
329 (float)(end_acct.tms_cutime - start_acct.tms_cutime) + /* User CPU time of terminated child processes */
330 (float)(end_acct.tms_cstime - start_acct.tms_cstime) /* System CPU time of terminated child processes */
331 );
332
333 return;
334 }
335
smf_internal_determine_linebreak(const char * s)336 char *smf_internal_determine_linebreak(const char *s) {
337 assert(s);
338
339 if (strstr(s,CRLF)!=NULL)
340 return(CRLF);
341 else if(strstr(s,LF)!=NULL)
342 return(LF);
343 else if(strstr(s,CR)!=NULL)
344 return(CR);
345 else
346 return(NULL);
347 }
348
smf_internal_fetch_user_data(SMFSettings_T * settings,SMFSession_T * session)349 int smf_internal_fetch_user_data(SMFSettings_T *settings, SMFSession_T *session) {
350 SMFListElem_T *e1 = NULL;
351 char *addr = NULL;
352
353 if (settings->backend == NULL)
354 return 0;
355
356 if ((strcmp(settings->backend,"ldap")==0) && (settings->ldap_user_query==NULL)) {
357 STRACE(TRACE_WARNING, session->id, "no user_query defined for ldap backend");
358 return 0;
359 }
360
361 if ((strcmp(settings->backend,"sql")==0) && (settings->sql_user_query==NULL)) {
362 STRACE(TRACE_WARNING, session->id, "no user_query defined for sql backend");
363 return 0;
364 }
365
366 e1 = smf_list_head(session->envelope->recipients);
367 while (e1 != NULL) {
368 addr = (char *)smf_list_data(e1);
369 STRACE(TRACE_DEBUG, session->id, "fetching user data for [%s]", addr);
370
371 if(smf_internal_query_user(settings,session,addr)!=0) {
372 STRACE(TRACE_ERR, session->id, "failed to fetch user data for [%s]", addr);
373 }
374 e1 = e1->next;
375 }
376
377 if (session->envelope->sender != NULL) {
378 STRACE(TRACE_DEBUG, session->id, "fetching user data for [%s]", session->envelope->sender);
379 if(smf_internal_query_user(settings,session,session->envelope->sender)!=0) {
380 STRACE(TRACE_ERR, session->id, "failed to fetch user data for [%s]", session->envelope->sender);
381 }
382 }
383
384 return 0;
385 }
386
smf_internal_generate_sid(void)387 char *smf_internal_generate_sid(void) {
388 static const char chars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
389 struct timeval t1;
390 int i;
391 int pos = 0;
392 char *sid = NULL;
393
394 /* generate session id */
395 gettimeofday(&t1, NULL);
396
397 srandom(t1.tv_usec * t1.tv_sec);
398 sid = (char *)calloc(13,sizeof(char));
399 for(i=0; i < 12; i++)
400 sid[pos++] = chars[random() % 36];
401
402 sid[pos] = '\0';
403
404 return sid;
405 }
406
407