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