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