1 /* spmfilter - mail filtering framework
2  * Copyright (C) 2009-2012 Axel Steiner, Sebastian Jäkel 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 _GNU_SOURCE
19 #define THIS_MODULE "core"
20 
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <assert.h>
24 #include <ctype.h>
25 #include <fcntl.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <errno.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <sys/time.h>
33 #include <sys/param.h>
34 
35 #include "smf_core.h"
36 #include "smf_md5.h"
37 
38 #define GETTIMEOFDAY(t) gettimeofday(t,(struct timezone *) 0)
39 
smf_core_strstrip(char * s)40 char *smf_core_strstrip(char *s) {
41     int start, end = strlen(s);
42     for (start = 0; s[start] && isspace(s[start]); ++start) {}
43     if (s[start]) {
44         while (end > 0 && isspace(s[end-1]))
45             --end;
46     }
47     memmove(s, &s[start], end - start);
48     s[end - start] = '\0';
49 
50     return s;
51 }
52 
53 
smf_core_strlwc(char * s)54 char *smf_core_strlwc(char *s) {
55     char *p;
56 
57     assert(s);
58 
59     p = s;
60 
61     while (*p) {
62         *p = tolower(*p);
63         p++;
64     }
65     return s;
66 }
67 
smf_core_strcat_printf(char ** s,const char * fmt,...)68 char *smf_core_strcat_printf(char **s, const char *fmt, ...) {
69     va_list ap;
70     va_start(ap, fmt);
71     char *tmp = NULL;
72 
73     assert((*s));
74 
75     vasprintf(&tmp,fmt,ap);
76     va_end(ap);
77     (*s) = (char *)realloc((*s),strlen((*s)) + strlen(tmp) + sizeof(char));
78     strcat((*s),tmp);
79     free(tmp);
80     return (*s);
81 }
82 
smf_core_strsplit(const char * s,char * sep,int * nelems)83 char **smf_core_strsplit(const char *s, char *sep, int *nelems) {
84     char **sl = NULL;
85     char *cp = NULL;
86     char *tf = NULL;
87     char *tmp = NULL;
88     int count = 0;
89 
90     assert(s);
91     assert(sep);
92 
93     tf = cp = strdup(s);
94 
95     while ((tmp = strsep(&cp, sep)) != NULL) {
96         sl = (char**)realloc(sl, (sizeof(*sl) * (count+2)));
97         sl[count] = strdup(tmp);
98         count++;
99     }
100     free(tf);
101     sl[count] = '\0';
102 
103     if (nelems != NULL)
104         *nelems = count;
105 
106     return(sl);
107 }
108 
smf_core_strsplit_free(char ** parts)109 static void smf_core_strsplit_free(char **parts) {
110     char **t = parts;
111 
112     while (*t != NULL) {
113         free(*t);
114         t++;
115     }
116 
117     free(parts);
118 }
119 
smf_core_gen_queue_file(const char * queue_dir,char ** tempname,const char * sid)120 int smf_core_gen_queue_file(const char *queue_dir, char **tempname, const char *sid) {
121     int fd;
122 
123     asprintf(&(*tempname),"%s/%s.XXXXXX",queue_dir,sid);
124     if ((fd = mkstemp(*tempname)) == -1)
125         return -1;
126     close(fd);
127 
128     return 0;
129 }
130 
smf_core_md5sum(const char * data)131 char *smf_core_md5sum(const char *data) {
132     md5_state_t state;
133     md5_byte_t digest[16];
134     int offset = 0;
135     char *hex = (char *)calloc(16*2+1,sizeof(char));
136 
137     md5_init(&state);
138     md5_append(&state, (const md5_byte_t *)data, strlen(data));
139     md5_finish(&state, digest);
140 
141     for(offset=0; offset<16; offset++) {
142         sprintf(hex + offset * 2, "%02x", digest[offset]);
143     }
144 
145     return(hex);
146 }
147 
smf_core_get_maildir_filename(void)148 char *smf_core_get_maildir_filename(void) {
149     char *filename;
150     char *hostname = NULL;
151     struct timeval starttime;
152 
153     GETTIMEOFDAY(&starttime);
154     hostname = (char *)malloc(MAXHOSTNAMELEN);
155     gethostname(hostname,MAXHOSTNAMELEN);
156 
157     asprintf(&filename,"%lu.V%lu.%s",
158         (unsigned long) starttime.tv_sec,
159         (unsigned long) starttime.tv_usec,
160         hostname);
161 
162     free(hostname);
163     return filename;
164 }
165 
smf_core_expand_string(const char * format,const char * addr,char ** buf)166 int smf_core_expand_string(const char *format, const char *addr, char **buf) {
167     int rep_made = 0;
168     int nelems;
169     char **parts = smf_core_strsplit(addr, "@", &nelems);
170     char *out;
171     size_t out_size;
172     int offs;
173 
174     assert(format != NULL);
175     assert(addr != NULL);
176     assert(buf != NULL);
177 
178     out_size = strlen(format) + 1;
179 	if ((out = malloc(out_size)) == NULL)  {
180 		return -1;
181 	}
182 
183     // Prepare the result with the format.
184     // The '%<x>'-expressions are replaced later.
185     strncpy(out, format, out_size);
186     out[out_size - 1] = '\0';
187     offs = 0;
188 
189     while(out[offs] != '\0') {
190         if(out[offs] == '%') {
191             const char *insert = NULL;
192 
193             switch(out[offs + 1]) {
194                 case 's':
195                     insert = addr;
196                     break;
197                 case 'u':
198                     insert = parts[0];
199                     break;
200                 case 'd':
201                     if (nelems < 2) {
202                         smf_core_strsplit_free(parts);
203                         free(out);
204                         return -1;
205                     }
206 
207                     insert = parts[1];
208                     break;
209                 default:
210                     smf_core_strsplit_free(parts);
211                     free(out);
212                     return(-2);
213                     break; /* never reached */
214             }
215 
216             // Replace the both option-characters with the "insert"-string
217             if (insert != NULL) {
218                 // New size of out: size of insert-string but without the two option-characters
219                 const size_t insert_len = strlen(insert);
220                 out_size += (insert_len - 2);
221                 out = realloc(out, out_size);
222 
223                 // First move everything behind the option-characters
224                 memmove(out + offs + insert_len, out + offs + 2, strlen(out + offs + 2) + 1);
225                 // Now insert the "insert"-string at the current position
226                 memcpy(out + offs, insert, insert_len);
227             }
228 
229             offs++;
230             rep_made++;
231         }
232 
233         offs++;
234     }
235 
236     *buf = out;
237     smf_core_strsplit_free(parts);
238 
239     return(rep_made);
240 }
241 
smf_core_copy_file(const char * source,const char * dest)242 int smf_core_copy_file(const char *source, const char *dest) {
243     int out, result;
244 
245 	if ((out = open(dest, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR)) == -1)
246         return 0;
247 
248     result = smf_core_copy_to_fd(source, out);
249     close(out);
250 
251     return result;
252 }
253 
smf_core_copy_to_fd(const char * source,int dest)254 int smf_core_copy_to_fd(const char *source, int dest) {
255     char buf[512];
256     int in_fd;
257     ssize_t nread;
258     size_t nbytes = 0;
259 
260     if ((in_fd = open(source, O_RDONLY)) == -1)
261         return -1;
262 
263 	while ((nread = read(in_fd, buf, sizeof(buf))) != 0) {
264 	    ssize_t nwritten = 0;
265 
266 	    if (nread == -1) {
267             close(in_fd);
268             return -1;
269         }
270 
271         while (nwritten < nread) {
272             ssize_t n;
273 
274             if ((n = write(dest, buf, nread)) == -1) {
275                 close(in_fd);
276                 return -1;
277             }
278 
279             nwritten += n;
280             nbytes += n;
281         }
282 	}
283 
284     close(in_fd);
285 
286     return nbytes;
287 }
288 
289