Line 0
Link Here
|
|
|
1 |
|
2 |
/* |
3 |
* |
4 |
* 'chkuser.c' v.2.0.8 |
5 |
* for qmail/netqmail > 1.0.3 and vpopmail > 5.3.x |
6 |
* |
7 |
* Author: Antonio Nati tonix@interazioni.it |
8 |
* All rights on this software and |
9 |
* the identifying words chkusr and chkuser kept by the author |
10 |
* |
11 |
* This software may be freely used, modified and distributed, |
12 |
* but this lines must be kept in every original or derived version. |
13 |
* Original author "Antonio Nati" and the web URL |
14 |
* "http://www.interazioni.it/opensource" |
15 |
* must be indicated in every related work or web page |
16 |
* |
17 |
*/ |
18 |
|
19 |
#include <pwd.h> |
20 |
|
21 |
/* required by vpopmail */ |
22 |
#include <stdio.h> |
23 |
|
24 |
#include <stdlib.h> |
25 |
#include <string.h> |
26 |
#include <unistd.h> |
27 |
|
28 |
#include "dns.h" |
29 |
#include "env.h" |
30 |
#include "ipme.h" |
31 |
#include "now.h" |
32 |
#include "open.h" |
33 |
#include "subfd.h" |
34 |
#include "substdio.h" |
35 |
#include "stralloc.h" |
36 |
|
37 |
#include "vpopmail.h" |
38 |
#include "vauth.h" |
39 |
#include "vpopmail_config.h" |
40 |
|
41 |
#include "chkuser.h" |
42 |
#include "chkuser_settings.h" |
43 |
|
44 |
#if defined _exit |
45 |
#undef _exit |
46 |
#endif |
47 |
|
48 |
extern void flush(); |
49 |
extern void out (char *s); |
50 |
|
51 |
extern char *remotehost; |
52 |
extern char *remoteip; |
53 |
extern char *remoteinfo; |
54 |
extern char *relayclient; |
55 |
extern char *fakehelo; |
56 |
|
57 |
extern void die_nomem(); |
58 |
|
59 |
#define DIE_NOMEM() die_nomem() |
60 |
|
61 |
#if defined CHKUSER_DEBUG |
62 |
|
63 |
#if defined CHKUSER_DEBUG_STDERR |
64 |
|
65 |
#define CHKUSER_DBG(a) write (STDERR_FILENO, a, strlen (a)) |
66 |
#define CHKUSER_DBG_INT(a) { int x; char str[30]; sprintf (str, "%d", a); write (STDERR_FILENO, str, strlen (str));} |
67 |
|
68 |
#else |
69 |
|
70 |
#define CHKUSER_DBG(a) write (STDOUT_FILENO, a, strlen (a)) |
71 |
#define CHKUSER_DBG_INT(a) { int x; char str[30]; sprintf (str, "%d", a); write (STDOUT_FILENO, str, strlen (str));} |
72 |
|
73 |
#endif |
74 |
#else |
75 |
|
76 |
#define CHKUSER_DBG(a) /* DBG dummy */ |
77 |
#define CHKUSER_DBG_INT(a) /* DBG dummy */ |
78 |
|
79 |
#endif |
80 |
|
81 |
static int INTRUSION_threshold_reached = 0; |
82 |
static int first_time_init_flag = 1; |
83 |
|
84 |
static int recipients = 0; |
85 |
static int wrong_recipients = 0; |
86 |
|
87 |
static stralloc user = {0}; |
88 |
static stralloc domain = {0}; |
89 |
static stralloc domain_path = {0}; |
90 |
static stralloc tmp_path = {0}; |
91 |
static stralloc alias_path = {0}; |
92 |
|
93 |
#if defined CHKUSER_IDENTIFY_REMOTE_VARIABLE |
94 |
static char *identify_remote; |
95 |
#endif |
96 |
|
97 |
#if defined CHKUSER_ENABLE_EXTENSIONS |
98 |
#define CHKUSER_ENABLE_USERS_EXTENSIONS |
99 |
#endif |
100 |
|
101 |
#if defined CHKUSER_ENABLE_LISTS |
102 |
#define CHKUSER_ENABLE_EZMLM_LISTS |
103 |
#endif |
104 |
|
105 |
#if defined CHKUSER_EXTENSION_DASH |
106 |
#define CHKUSER_USERS_DASH CHKUSER_EXTENSION_DASH |
107 |
#endif |
108 |
|
109 |
|
110 |
#if defined CHKUSER_ENABLE_VAUTH_OPEN |
111 |
static int db_already_open = 0; |
112 |
#endif |
113 |
|
114 |
#if !defined CHKUSER_ALWAYS_ON && defined CHKUSER_STARTING_VARIABLE |
115 |
static char *starting_string = 0; |
116 |
static int starting_value = -1; |
117 |
#endif |
118 |
|
119 |
#if defined CHKUSER_RCPT_LIMIT_VARIABLE |
120 |
static char *maxrcpt_string = 0; |
121 |
static int maxrcpt_limit = 0; |
122 |
static int maxrcpt_limit_reached = 0; |
123 |
#endif |
124 |
|
125 |
#if defined CHKUSER_WRONGRCPT_LIMIT_VARIABLE |
126 |
static char *maxwrongrcpt_string = 0; |
127 |
static int maxwrongrcpt_limit = 0; |
128 |
static int maxwrongrcpt_limit_reached = 0; |
129 |
#endif |
130 |
|
131 |
#if defined CHKUSER_MBXQUOTA_VARIABLE |
132 |
static char *maxmbxquota_string = 0; |
133 |
static int maxmbxquota_limit = 0; |
134 |
#endif |
135 |
|
136 |
#if defined CHKUSER_SENDER_NOCHECK_VARIABLE |
137 |
|
138 |
static unsigned int sender_nocheck = 0; |
139 |
|
140 |
#endif |
141 |
|
142 |
#if defined CHKUSER_SENDER_FORMAT || defined CHKUSER_SENDER_MX |
143 |
static stralloc sender_user = {0}; |
144 |
static stralloc sender_domain = {0}; |
145 |
#endif |
146 |
|
147 |
|
148 |
#if defined CHKUSER_ERROR_DELAY |
149 |
|
150 |
static int chkuser_delay_interval = CHKUSER_ERROR_DELAY * 1000; |
151 |
|
152 |
#define CHKUSER_DELAY() chkuser_delay() |
153 |
|
154 |
void chkuser_delay (void) { |
155 |
|
156 |
usleep (chkuser_delay_interval); |
157 |
|
158 |
#if defined CHKUSER_ERROR_DELAY_INCREASE |
159 |
chkuser_delay_interval += CHKUSER_ERROR_DELAY_INCREASE * 1000; |
160 |
#endif |
161 |
} |
162 |
|
163 |
#if defined CHKUSER_RCPT_DELAY_ANYERROR |
164 |
#define CHKUSER_RCPT_DELAY_ANY() chkuser_delay() |
165 |
#else |
166 |
#define CHKUSER_RCPT_DELAY_ANY() /* no delay for any error */ |
167 |
#endif |
168 |
|
169 |
#if defined CHKUSER_SENDER_DELAY_ANYERROR |
170 |
#define CHKUSER_SENDER_DELAY_ANY() chkuser_delay() |
171 |
#else |
172 |
#define CHKUSER_SENDER_DELAY_ANY() /* no delay for any error */ |
173 |
#endif |
174 |
|
175 |
|
176 |
#else |
177 |
#define CHKUSER_DELAY() /* no delay */ |
178 |
#define CHKUSER_RCPT_DELAY_ANY() /* no delay */ |
179 |
#define CHKUSER_SENDER_DELAY_ANY() /* no delay */ |
180 |
#endif |
181 |
|
182 |
#if defined CHKUSER_ENABLE_LOGGING |
183 |
|
184 |
static stralloc logstr = { 0 }; |
185 |
|
186 |
static void chkuser_commonlog (char *sender, char *rcpt, char *title, char *description) { |
187 |
|
188 |
substdio_puts (subfderr, "CHKUSER "); |
189 |
substdio_puts (subfderr, title); |
190 |
substdio_puts (subfderr, ": from <"); |
191 |
substdio_puts (subfderr, sender); |
192 |
substdio_puts (subfderr, ":" ); |
193 |
if (remoteinfo) { |
194 |
substdio_puts (subfderr, remoteinfo); |
195 |
} |
196 |
substdio_puts (subfderr, ":" ); |
197 |
#if defined CHKUSER_IDENTIFY_REMOTE_VARIABLE |
198 |
if (identify_remote) substdio_puts (subfderr, identify_remote); |
199 |
#endif |
200 |
substdio_puts (subfderr, "> remote <"); |
201 |
if (fakehelo) substdio_puts (subfderr, fakehelo); |
202 |
substdio_puts (subfderr, ":" ); |
203 |
if (remotehost) substdio_puts (subfderr, remotehost); |
204 |
substdio_puts (subfderr, ":" ); |
205 |
if (remoteip) substdio_puts (subfderr, remoteip); |
206 |
substdio_puts (subfderr, "> rcpt <"); |
207 |
substdio_puts (subfderr, rcpt); |
208 |
substdio_puts (subfderr, "> : "); |
209 |
substdio_puts (subfderr, description); |
210 |
substdio_puts (subfderr, "\n"); |
211 |
substdio_flush (subfderr); |
212 |
} |
213 |
|
214 |
#else |
215 |
#define chkuser_commonlog(a,b,c,d) /* no log */ |
216 |
#endif |
217 |
|
218 |
#if defined CHKUSER_SENDER_FORMAT |
219 |
|
220 |
static int check_sender_address_format (stralloc *user, stralloc *domain) { |
221 |
|
222 |
int x; |
223 |
|
224 |
for (x = 0; x < (user->len -1); ++x) { |
225 |
if ((!isalnum (user->s[x])) |
226 |
|
227 |
#if defined CHKUSER_ALLOW_SENDER_SRS |
228 |
&& (user->s[x] != '#') |
229 |
&& (user->s[x] != '+') |
230 |
#endif |
231 |
#if defined CHKUSER_ALLOW_SENDER_CHAR_1 |
232 |
&& (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_1) |
233 |
#endif |
234 |
#if defined CHKUSER_ALLOW_SENDER_CHAR_2 |
235 |
&& (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_2) |
236 |
#endif |
237 |
#if defined CHKUSER_ALLOW_SENDER_CHAR_3 |
238 |
&& (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_3) |
239 |
#endif |
240 |
#if defined CHKUSER_ALLOW_SENDER_CHAR_4 |
241 |
&& (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_4) |
242 |
#endif |
243 |
#if defined CHKUSER_ALLOW_SENDER_CHAR_5 |
244 |
&& (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_5) |
245 |
#endif |
246 |
&& (user->s[x] != '_') && (user->s[x] != '-') && (user->s[x] != '.') && (user->s[x] != '=')) { |
247 |
return 0; |
248 |
} |
249 |
} |
250 |
|
251 |
/* |
252 |
* Be careful, this is a base check |
253 |
* Minimum is x.xx + ending \0 |
254 |
* Minimum characters needed are 5 |
255 |
*/ |
256 |
#if defined CHKUSER_MIN_DOMAIN_LEN |
257 |
if (domain->len < (CHKUSER_MIN_DOMAIN_LEN +1)) { |
258 |
return 0; |
259 |
} |
260 |
#endif |
261 |
|
262 |
/* |
263 |
* This is a safety check |
264 |
*/ |
265 |
#if defined CHKUSER_MIN_DOMAIN_LEN |
266 |
if (domain->len < 2) { |
267 |
return 0; |
268 |
} |
269 |
#endif |
270 |
|
271 |
for (x = 0; x < (domain->len -1); ++x) { |
272 |
if ((!isalnum (domain->s[x])) && (domain->s[x] != '-') && (domain->s[x] != '.')) { |
273 |
return 0; |
274 |
} |
275 |
} |
276 |
|
277 |
if ((domain->s[0] == '-') || (domain->s[domain->len -2] == '-') || (domain->s[0] == '.') || (domain->s[domain->len -2] == '.')) { |
278 |
return 0; |
279 |
} |
280 |
if (strstr (domain->s, "..") != NULL) { |
281 |
return 0; |
282 |
} |
283 |
if (strncmp (domain->s, "xn--", 4) == 0) { |
284 |
if (strstr (&domain->s[4], "--") != NULL) |
285 |
return 0; |
286 |
} else { |
287 |
if (strstr (domain->s, "--") != NULL) |
288 |
return 0; |
289 |
} |
290 |
if (strstr (domain->s, ".-") != NULL) { |
291 |
return 0; |
292 |
} |
293 |
if (strstr (domain->s, "-.") != NULL) { |
294 |
return 0; |
295 |
} |
296 |
if (strchr (domain->s, '.') == NULL) { |
297 |
return 0; |
298 |
} |
299 |
|
300 |
return 1; |
301 |
} |
302 |
|
303 |
#endif |
304 |
|
305 |
#if defined CHKUSER_RCPT_FORMAT |
306 |
|
307 |
static int check_rcpt_address_format (stralloc *user, stralloc *domain) { |
308 |
|
309 |
int x; |
310 |
|
311 |
for (x = 0; x < (user->len -1); ++x) { |
312 |
if ((!isalnum (user->s[x])) |
313 |
#if defined CHKUSER_ALLOW_RCPT_SRS |
314 |
&& (user->s[x] != '#') |
315 |
&& (user->s[x] != '+') |
316 |
#endif |
317 |
#if defined CHKUSER_ALLOW_RCPT_CHAR_1 |
318 |
&& (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_1) |
319 |
#endif |
320 |
#if defined CHKUSER_ALLOW_RCPT_CHAR_2 |
321 |
&& (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_2) |
322 |
#endif |
323 |
#if defined CHKUSER_ALLOW_RCPT_CHAR_3 |
324 |
&& (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_3) |
325 |
#endif |
326 |
#if defined CHKUSER_ALLOW_RCPT_CHAR_4 |
327 |
&& (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_4) |
328 |
#endif |
329 |
#if defined CHKUSER_ALLOW_RCPT_CHAR_5 |
330 |
&& (user->s[x] != CHKUSER_ALLOW_SENDER_CHAR_5) |
331 |
#endif |
332 |
|
333 |
&& (user->s[x] != '_') && (user->s[x] != '-') && (user->s[x] != '.') && (user->s[x] != '=')) { |
334 |
return 0; |
335 |
} |
336 |
} |
337 |
|
338 |
/* |
339 |
* Be careful, this is a base check |
340 |
* Minimum is x.xx + ending \0 |
341 |
* Minimum characters needed are 5 |
342 |
*/ |
343 |
#if defined CHKUSER_MIN_DOMAIN_LEN |
344 |
if (domain->len < (CHKUSER_MIN_DOMAIN_LEN +1)) { |
345 |
return 0; |
346 |
} |
347 |
#endif |
348 |
|
349 |
/* |
350 |
* This is a safety check |
351 |
*/ |
352 |
#if defined CHKUSER_MIN_DOMAIN_LEN |
353 |
if (domain->len < 2) { |
354 |
return 0; |
355 |
} |
356 |
#endif |
357 |
for (x = 0; x < (domain->len -1); ++x) { |
358 |
if ((!isalnum (domain->s[x])) && (domain->s[x] != '-') && (domain->s[x] != '.')) { |
359 |
return 0; |
360 |
} |
361 |
} |
362 |
|
363 |
if ((domain->s[0] == '-') || (domain->s[domain->len -2] == '-') || (domain->s[0] == '.') || (domain->s[domain->len -2] == '.')) { |
364 |
return 0; |
365 |
} |
366 |
if (strstr (domain->s, "..") != NULL) { |
367 |
return 0; |
368 |
} |
369 |
if (strncmp (domain->s, "xn--", 4) == 0) { |
370 |
if (strstr (&domain->s[4], "--") != NULL) |
371 |
return 0; |
372 |
} else { |
373 |
if (strstr (domain->s, "--") != NULL) |
374 |
return 0; |
375 |
} |
376 |
if (strstr (domain->s, ".-") != NULL) { |
377 |
return 0; |
378 |
} |
379 |
if (strstr (domain->s, "-.") != NULL) { |
380 |
return 0; |
381 |
} |
382 |
if (strchr (domain->s, '.') == NULL) { |
383 |
return 0; |
384 |
} |
385 |
|
386 |
return 1; |
387 |
} |
388 |
|
389 |
#endif |
390 |
|
391 |
#if defined CHKUSER_SENDER_MX || defined CHKUSER_RCPT_MX |
392 |
|
393 |
static unsigned long mx_random; |
394 |
static ipalloc mx_ip = {0}; |
395 |
|
396 |
static int chkuser_mx_lookup (stralloc *domain) { |
397 |
|
398 |
int status; |
399 |
|
400 |
mx_random = now() + getpid(); |
401 |
dns_init(0); |
402 |
status = dns_mxip (&mx_ip, domain, mx_random); |
403 |
|
404 |
if (status == DNS_MEM) DIE_NOMEM(); |
405 |
|
406 |
return status; |
407 |
} |
408 |
|
409 |
#endif |
410 |
|
411 |
|
412 |
void chkuser_cleanup (int exit_value) { |
413 |
|
414 |
#if defined CHKUSER_DB_CLEANUP |
415 |
vclose (); |
416 |
#endif |
417 |
_exit (exit_value); |
418 |
} |
419 |
|
420 |
static void first_time_init (void) { |
421 |
|
422 |
char * temp_string; |
423 |
|
424 |
#if !defined CHKUSER_ALWAYS_ON && defined CHKUSER_STARTING_VARIABLE |
425 |
starting_string = env_get (CHKUSER_STARTING_VARIABLE); |
426 |
if (starting_string) { |
427 |
if (strcasecmp(starting_string, "ALWAYS") == 0) { |
428 |
starting_value = 1; |
429 |
} else if (strcasecmp(starting_string, "DOMAIN") == 0) { |
430 |
starting_value = 0; |
431 |
} |
432 |
} else { |
433 |
starting_string = ""; |
434 |
} |
435 |
#endif |
436 |
|
437 |
#if defined CHKUSER_RCPT_LIMIT_VARIABLE |
438 |
maxrcpt_string = env_get (CHKUSER_RCPT_LIMIT_VARIABLE); |
439 |
if (maxrcpt_string) { |
440 |
maxrcpt_limit = atoi (maxrcpt_string); |
441 |
if (maxrcpt_limit < 1) { |
442 |
maxrcpt_limit = 0; |
443 |
} |
444 |
} else { |
445 |
maxrcpt_string = "";; |
446 |
} |
447 |
#endif |
448 |
|
449 |
#if defined CHKUSER_WRONGRCPT_LIMIT_VARIABLE |
450 |
maxwrongrcpt_string = env_get (CHKUSER_WRONGRCPT_LIMIT_VARIABLE); |
451 |
if (maxwrongrcpt_string) { |
452 |
maxwrongrcpt_limit = atoi (maxwrongrcpt_string); |
453 |
if (maxwrongrcpt_limit < 1) { |
454 |
maxwrongrcpt_limit = 0; |
455 |
} |
456 |
} else { |
457 |
maxwrongrcpt_string = ""; |
458 |
} |
459 |
#endif |
460 |
|
461 |
#if defined CHKUSER_MBXQUOTA_VARIABLE |
462 |
maxmbxquota_string = env_get (CHKUSER_MBXQUOTA_VARIABLE); |
463 |
if (maxmbxquota_string) { |
464 |
maxmbxquota_limit = atoi (maxmbxquota_string); |
465 |
if (maxmbxquota_limit < 1) { |
466 |
maxmbxquota_limit = 0; |
467 |
} |
468 |
} else { |
469 |
maxmbxquota_string = ""; |
470 |
} |
471 |
#endif |
472 |
|
473 |
#if defined CHKUSER_SENDER_NOCHECK_VARIABLE |
474 |
|
475 |
temp_string = env_get (CHKUSER_SENDER_NOCHECK_VARIABLE); |
476 |
if (temp_string) { |
477 |
sender_nocheck = 1; |
478 |
} else { |
479 |
sender_nocheck = 0; |
480 |
} |
481 |
|
482 |
#endif |
483 |
|
484 |
#if defined CHKUSER_IDENTIFY_REMOTE_VARIABLE |
485 |
|
486 |
identify_remote = env_get (CHKUSER_IDENTIFY_REMOTE_VARIABLE); |
487 |
if (identify_remote) { |
488 |
} |
489 |
|
490 |
#endif |
491 |
|
492 |
if (!stralloc_ready (&user, 300)) DIE_NOMEM(); |
493 |
if (!stralloc_ready (&domain, 500)) DIE_NOMEM(); |
494 |
if (!stralloc_ready (&domain_path, 1000)) DIE_NOMEM(); |
495 |
if (!stralloc_ready (&tmp_path, 1000)) DIE_NOMEM(); |
496 |
if (!stralloc_ready (&alias_path, 1000)) DIE_NOMEM(); |
497 |
|
498 |
first_time_init_flag = 0; |
499 |
|
500 |
} |
501 |
|
502 |
/* |
503 |
* realrcpt () |
504 |
* |
505 |
* Returns: |
506 |
* |
507 |
* CHKUSER_OK = 1 = Ok, recipients does exists |
508 |
* |
509 |
* 0 = Not in rcpthosts |
510 |
* |
511 |
* < 0 various errors |
512 |
* |
513 |
* |
514 |
* Parameters: |
515 |
* stralloc *sender = sender address |
516 |
* stralloc *rcpt = rcpt address to check |
517 |
* |
518 |
* |
519 |
*/ |
520 |
|
521 |
static int realrcpt (stralloc *sender, stralloc *rcpt) |
522 |
{ |
523 |
int count; |
524 |
int retstat = CHKUSER_KO; |
525 |
struct vqpasswd *user_passwd = NULL; |
526 |
int fd_file = -1; |
527 |
int read_char; |
528 |
int offset; |
529 |
char read_buf[1024]; |
530 |
|
531 |
#if defined CHKUSER_ENABLE_UIDGID |
532 |
uid_t eff_uid; |
533 |
gid_t eff_gid; |
534 |
#endif |
535 |
|
536 |
#if !defined CHKUSER_ALWAYS_ON && defined CHKUSER_STARTING_VARIABLE |
537 |
if (starting_value == -1) { |
538 |
if (addrallowed()) { |
539 |
return CHKUSER_OK; |
540 |
} else { |
541 |
if (relayclient) { |
542 |
return CHKUSER_RELAYING; |
543 |
} |
544 |
|
545 |
return CHKUSER_NORCPTHOSTS; |
546 |
} |
547 |
} |
548 |
#endif |
549 |
|
550 |
if (INTRUSION_threshold_reached == 1) { |
551 |
return CHKUSER_ERR_INTRUSION_THRESHOLD; |
552 |
} |
553 |
|
554 |
#if defined CHKUSER_RCPT_LIMIT_VARIABLE |
555 |
|
556 |
++recipients; |
557 |
if ((maxrcpt_limit > 0) && (recipients >= maxrcpt_limit)) { |
558 |
chkuser_commonlog (sender->s, rcpt->s, "intrusion threshold", "max number of allowed rcpt"); |
559 |
INTRUSION_threshold_reached = 1; |
560 |
return CHKUSER_ERR_MAXRCPT; |
561 |
} |
562 |
#endif |
563 |
|
564 |
/* Search the '@' character */ |
565 |
count = byte_rchr(rcpt->s,rcpt->len,'@'); |
566 |
|
567 |
if (count < rcpt->len) { |
568 |
if (!stralloc_copyb (&user, rcpt->s, count)) DIE_NOMEM(); |
569 |
if (!stralloc_copys (&domain, rcpt->s + count + 1)) DIE_NOMEM(); |
570 |
} |
571 |
else { |
572 |
if (!stralloc_copys (&user, rcpt->s)) DIE_NOMEM(); |
573 |
domain.len = 0; |
574 |
} |
575 |
if (!stralloc_0 (&user)) DIE_NOMEM(); |
576 |
if (!stralloc_0 (&domain)) DIE_NOMEM(); |
577 |
|
578 |
#if defined CHKUSER_ENABLE_UIDGID |
579 |
|
580 |
/* qmail-smtpd is running now as (effective) qmaild:nofiles */ |
581 |
/* Save the effective UID & GID (qmaild:nofiles) */ |
582 |
eff_uid = geteuid (); |
583 |
eff_gid = getegid (); |
584 |
|
585 |
/* Now set new effective UID & GID, getting it from real UID & GID (vpopmail:vchkpw) */ |
586 |
setegid (getgid()); |
587 |
seteuid (getuid()); |
588 |
|
589 |
/* qmail-smtpd is running now as effective vpopmail:vchkpw */ |
590 |
#endif |
591 |
|
592 |
|
593 |
/* |
594 |
* |
595 |
* Now let's start the test/setting suite |
596 |
* |
597 |
**/ |
598 |
|
599 |
switch (0) { |
600 |
|
601 |
case 0: |
602 |
/* These are some preliminary settings */ |
603 |
case_lowers (user.s); |
604 |
case_lowers (domain.s); |
605 |
|
606 |
case 1: |
607 |
|
608 |
if (domain.len == 1) { |
609 |
#if defined CHKUSER_DOMAIN_WANTED |
610 |
retstat = CHKUSER_ERR_DOMAIN_MISSING; |
611 |
break; |
612 |
#else |
613 |
if (!stralloc_copys (&domain, DEFAULT_DOMAIN)) DIE_NOMEM(); |
614 |
if (!stralloc_0 (&domain)) DIE_NOMEM(); |
615 |
#endif |
616 |
} |
617 |
|
618 |
case 2: |
619 |
|
620 |
#if defined CHKUSER_RCPT_FORMAT |
621 |
|
622 |
if (check_rcpt_address_format (&user, &domain) == 0) { |
623 |
retstat = CHKUSER_ERR_RCPT_FORMAT; |
624 |
break; |
625 |
} |
626 |
#endif |
627 |
|
628 |
case 3: |
629 |
|
630 |
if (!addrallowed()) { |
631 |
|
632 |
#if defined CHKUSER_RCPT_MX |
633 |
switch (chkuser_mx_lookup(&domain)) { |
634 |
|
635 |
case DNS_HARD: |
636 |
retstat = CHKUSER_ERR_RCPT_MX; |
637 |
break; |
638 |
|
639 |
case DNS_SOFT: |
640 |
retstat = CHKUSER_ERR_RCPT_MX_TMP; |
641 |
break; |
642 |
} |
643 |
|
644 |
if (retstat != CHKUSER_KO) { |
645 |
break; |
646 |
} |
647 |
#endif |
648 |
|
649 |
if (relayclient) { |
650 |
retstat = CHKUSER_RELAYING; |
651 |
break; |
652 |
} |
653 |
|
654 |
retstat = CHKUSER_NORCPTHOSTS; |
655 |
break; |
656 |
} |
657 |
|
658 |
case 4: |
659 |
|
660 |
#if defined CHKUSER_ENABLE_VAUTH_OPEN |
661 |
if (db_already_open != 1) { |
662 |
if (vauth_open () == 0) { |
663 |
db_already_open == 1; |
664 |
} else { |
665 |
retstat = CHKUSER_ERR_AUTH_RESOURCE; |
666 |
} |
667 |
}; |
668 |
#endif |
669 |
|
670 |
case 5: |
671 |
|
672 |
#if defined CHKUSER_ENABLE_VGET_REAL_DOMAIN |
673 |
/* Check if domain is a real domain */ |
674 |
|
675 |
vget_real_domain(domain.s, domain.a); |
676 |
|
677 |
domain.len = strlen (domain.s) +1; |
678 |
if (domain.len > (domain.a - 1)) DIE_NOMEM(); |
679 |
#endif |
680 |
|
681 |
/* Let's get domain's real path */ |
682 |
if (vget_assign(domain.s, domain_path.s, domain_path.a -1, NULL, NULL) == NULL) { |
683 |
retstat = CHKUSER_OK; |
684 |
break; |
685 |
} |
686 |
|
687 |
domain_path.len = strlen (domain_path.s); |
688 |
|
689 |
case 6: |
690 |
|
691 |
/* Check if domain has bouncing enabled */ |
692 |
|
693 |
#if !defined CHKUSER_ALWAYS_ON |
694 |
|
695 |
#if defined CHKUSER_STARTING_VARIABLE |
696 |
if (starting_value == 0) { |
697 |
#endif |
698 |
|
699 |
if (!stralloc_copy (&tmp_path, &domain_path)) DIE_NOMEM(); |
700 |
|
701 |
#if defined CHKUSER_SPECIFIC_BOUNCING |
702 |
if (!stralloc_cats (&tmp_path, "/")) DIE_NOMEM(); |
703 |
if (!stralloc_cats (&tmp_path, CHKUSER_SPECIFIC_BOUNCING)) DIE_NOMEM(); |
704 |
if (!stralloc_0 (&tmp_path)) DIE_NOMEM(); |
705 |
fd_file = open_read (tmp_path.s); |
706 |
if (fd_file != -1) { |
707 |
close (fd_file); |
708 |
} else { |
709 |
retstat = CHKUSER_OK; |
710 |
break; |
711 |
} |
712 |
#else |
713 |
if (!stralloc_cats (&tmp_path, "/.qmail-default")) DIE_NOMEM(); |
714 |
if (!stralloc_0 (&tmp_path)) DIE_NOMEM(); |
715 |
|
716 |
read_char = 0; |
717 |
fd_file = open_read (tmp_path.s); |
718 |
if (fd_file != -1) { |
719 |
read_char = read (fd_file, read_buf, sizeof(read_buf) - 1); |
720 |
close (fd_file); |
721 |
if (read_char < 0) read_char = 0; |
722 |
} |
723 |
read_buf[read_char] = 0; |
724 |
|
725 |
if ( strstr(read_buf, CHKUSER_BOUNCE_STRING) == NULL ) { |
726 |
retstat = CHKUSER_OK; |
727 |
break; |
728 |
} |
729 |
#endif |
730 |
#if defined CHKUSER_STARTING_VARIABLE |
731 |
} |
732 |
#endif |
733 |
#endif |
734 |
|
735 |
case 7: |
736 |
#if defined VALIAS |
737 |
/* Check for aliases/forwards - valias*/ |
738 |
|
739 |
if (valias_select (user.s, domain.s) != NULL) { |
740 |
retstat = CHKUSER_OK; |
741 |
break; |
742 |
} |
743 |
#endif |
744 |
|
745 |
case 8: |
746 |
#if defined CHKUSER_ENABLE_ALIAS |
747 |
/* Check for aliases/forwards - .qmail.x files */ |
748 |
|
749 |
if (!stralloc_copy (&tmp_path, &user)) DIE_NOMEM(); |
750 |
/* Change all '.' in ':' before continuing on aliases */ |
751 |
for (count = 0; count < tmp_path.len; ++count) |
752 |
if (*(tmp_path.s + count) == '.') *(tmp_path.s + count) = ':'; |
753 |
|
754 |
if (!stralloc_copy (&alias_path, &domain_path)) DIE_NOMEM(); |
755 |
if (!stralloc_cats (&alias_path, "/.qmail-")) DIE_NOMEM(); |
756 |
if (!stralloc_cats (&alias_path, tmp_path.s)) DIE_NOMEM(); |
757 |
if (!stralloc_0 (&alias_path)) DIE_NOMEM(); |
758 |
|
759 |
fd_file = open_read (alias_path.s); |
760 |
if (fd_file != -1) { |
761 |
close (fd_file); |
762 |
retstat = CHKUSER_OK; |
763 |
break; |
764 |
} |
765 |
#endif |
766 |
|
767 |
case 9: |
768 |
|
769 |
#if defined CHKUSER_ENABLE_ALIAS_DEFAULT |
770 |
|
771 |
if (!stralloc_copy (&tmp_path, &user)) DIE_NOMEM(); |
772 |
/* Change all '.' in ':' before continuing on aliases */ |
773 |
for (count = 0; count < tmp_path.len; ++count) |
774 |
if (*(tmp_path.s + count) == '.') *(tmp_path.s + count) = ':'; |
775 |
|
776 |
/* Search for the outer '-' character */ |
777 |
for (offset = user.len - 1; offset > 0; --offset) |
778 |
if (*(user.s + offset) == CHKUSER_USERS_DASH) { |
779 |
if (!stralloc_copy (&alias_path, &domain_path)) die_nomem(); |
780 |
if (!stralloc_cats (&alias_path, "/.qmail-")) die_nomem(); |
781 |
if (!stralloc_catb (&alias_path, user.s, offset)) die_nomem(); |
782 |
if (!stralloc_cats (&alias_path, "-default")) die_nomem(); |
783 |
if (!stralloc_0 (&alias_path)) die_nomem(); |
784 |
|
785 |
fd_file = open_read (alias_path.s); |
786 |
if (fd_file != -1) { |
787 |
close (fd_file); |
788 |
retstat = CHKUSER_OK; |
789 |
break; |
790 |
} |
791 |
} |
792 |
|
793 |
if (retstat != CHKUSER_KO) { |
794 |
break; |
795 |
} |
796 |
|
797 |
#endif |
798 |
|
799 |
case 10: |
800 |
#if defined CHKUSER_ENABLE_USERS |
801 |
/* User control: check the existance of a real user */ |
802 |
|
803 |
user_passwd = vauth_getpw (user.s, domain.s); |
804 |
|
805 |
#if defined CHKUSER_ENABLE_USERS_EXTENSIONS |
806 |
if (user_passwd == NULL) { |
807 |
count = 0; |
808 |
while ((count < (user.len -1)) && (user_passwd == NULL)) { |
809 |
count += byte_chr(&user.s[count], user.len - count, CHKUSER_USERS_DASH); |
810 |
if (count < user.len) { |
811 |
if (!stralloc_copyb (&tmp_path, user.s, count)) DIE_NOMEM(); |
812 |
if (!stralloc_0 (&tmp_path)) DIE_NOMEM(); |
813 |
user_passwd = vauth_getpw (tmp_path.s, domain.s); |
814 |
++count; |
815 |
} |
816 |
} |
817 |
} |
818 |
|
819 |
#endif |
820 |
if (user_passwd != NULL) { |
821 |
|
822 |
/* If user exists check if he has BOUNCE_MAIL flag set */ |
823 |
|
824 |
if (user_passwd->pw_gid & BOUNCE_MAIL) |
825 |
retstat = CHKUSER_KO; |
826 |
else { |
827 |
retstat = CHKUSER_OK; |
828 |
#if defined CHKUSER_MBXQUOTA_VARIABLE |
829 |
if ((maxmbxquota_limit > 0) && (strcasecmp(user_passwd->pw_shell, "NOQUOTA") != 0)) { |
830 |
if (!stralloc_copys (&tmp_path, user_passwd->pw_dir)) DIE_NOMEM(); |
831 |
if (!stralloc_cats (&tmp_path, "/Maildir")) DIE_NOMEM(); |
832 |
if (!stralloc_0 (&tmp_path)) DIE_NOMEM(); |
833 |
|
834 |
if (vmaildir_readquota(tmp_path.s,format_maildirquota(user_passwd->pw_shell)) |
835 |
>= maxmbxquota_limit) { |
836 |
retstat = CHKUSER_ERR_MBXFULL; |
837 |
} |
838 |
} |
839 |
#endif |
840 |
} |
841 |
break; |
842 |
} |
843 |
#endif |
844 |
|
845 |
case 11: |
846 |
#if defined CHKUSER_ENABLE_EZMLM_LISTS |
847 |
/* Let's check for mailing lists */ |
848 |
|
849 |
/* Search for the outer CHKUSER_EZMLM_DASH character */ |
850 |
for (offset = user.len - 2; offset > 0; --offset) { |
851 |
if (*(user.s + offset) == CHKUSER_EZMLM_DASH) { |
852 |
if (!stralloc_copy (&tmp_path, &domain_path)) DIE_NOMEM(); |
853 |
if (!stralloc_cats (&tmp_path, "/")) DIE_NOMEM(); |
854 |
if (!stralloc_catb (&tmp_path, user.s, offset)) DIE_NOMEM(); |
855 |
if (!stralloc_cats (&tmp_path, "/mailinglist")) DIE_NOMEM(); |
856 |
if (!stralloc_0 (&tmp_path)) DIE_NOMEM(); |
857 |
fd_file = open_read (tmp_path.s); |
858 |
if (fd_file != -1) { |
859 |
close (fd_file); |
860 |
retstat = CHKUSER_OK; |
861 |
break; |
862 |
} |
863 |
} |
864 |
} |
865 |
if (retstat != CHKUSER_KO) { |
866 |
break; |
867 |
} |
868 |
#endif |
869 |
|
870 |
case 12: |
871 |
#if defined CHKUSER_ENABLE_MAILMAN_LISTS |
872 |
/* Let's check for mailing lists */ |
873 |
|
874 |
/* Search for the outer CHKUSER_MAILMAN_DASH character */ |
875 |
for (offset = user.len - 2; offset > 0; --offset) { |
876 |
if (*(user.s + offset) == CHKUSER_MAILMAN_DASH) { |
877 |
if (!stralloc_copy (&tmp_path, &domain_path)) DIE_NOMEM(); |
878 |
if (!stralloc_cats (&tmp_path, "/")) DIE_NOMEM(); |
879 |
if (!stralloc_cats (&alias_path, "/.qmail-")) DIE_NOMEM(); |
880 |
if (!stralloc_catb (&tmp_path, user.s, offset)) DIE_NOMEM(); |
881 |
if (!stralloc_0 (&tmp_path)) DIE_NOMEM(); |
882 |
fd_file = open_read (tmp_path.s); |
883 |
read_char = 0; |
884 |
if (fd_file != -1) { |
885 |
read_char = read (fd_file, read_buf, sizeof(read_buf) - 1); |
886 |
close (fd_file); |
887 |
if (read_char < 0) read_char = 0; |
888 |
} |
889 |
read_buf[read_char] = 0; |
890 |
|
891 |
if ( strstr(read_buf, CHKUSER_MAILMAN_STRING) == NULL ) { |
892 |
retstat = CHKUSER_OK; |
893 |
break; |
894 |
} |
895 |
|
896 |
} |
897 |
} |
898 |
if (retstat != CHKUSER_KO) { |
899 |
break; |
900 |
} |
901 |
#endif |
902 |
|
903 |
/* |
904 |
* Add this code if another case is following |
905 |
case xx: |
906 |
code .... |
907 |
code .... |
908 |
code .... |
909 |
code .... |
910 |
|
911 |
if (xxxxxxxx) { |
912 |
retstat != CHKUSER_KO) |
913 |
break; |
914 |
} |
915 |
*/ |
916 |
|
917 |
default: |
918 |
retstat = CHKUSER_KO; |
919 |
|
920 |
} /* end switch */ |
921 |
|
922 |
#if defined CHKUSER_ENABLE_UIDGID |
923 |
/* Now switch back effective to saved UID & GID (qmaild:nofiles) */ |
924 |
|
925 |
setegid (eff_gid); |
926 |
seteuid (eff_uid); |
927 |
|
928 |
/* qmail-smtpd is running again as (effective) qmaild:nofiles */ |
929 |
#endif |
930 |
|
931 |
return retstat; |
932 |
|
933 |
} |
934 |
|
935 |
|
936 |
|
937 |
/* |
938 |
* chkuser_realrcpt () |
939 |
* |
940 |
* Returns a simple status: |
941 |
* |
942 |
* CHKUSER_OK = 1 = Ok, recipients does exists |
943 |
* |
944 |
* CHKUSER_NORCPTHOSTS = Not in rcpthosts |
945 |
* |
946 |
* CHKUSER_KO = ERROR |
947 |
* |
948 |
* |
949 |
* Parameters: |
950 |
* stralloc *sender = sender address |
951 |
* stralloc *rcpt = rcpt address to check |
952 |
* |
953 |
* |
954 |
*/ |
955 |
|
956 |
int chkuser_realrcpt (stralloc *sender, stralloc *rcpt) { |
957 |
|
958 |
int retstat; |
959 |
|
960 |
if (first_time_init_flag) { |
961 |
first_time_init (); |
962 |
} |
963 |
|
964 |
retstat = realrcpt (sender, rcpt); |
965 |
|
966 |
switch (retstat) { |
967 |
|
968 |
case CHKUSER_OK: |
969 |
#if defined CHKUSER_LOG_VALID_RCPT |
970 |
chkuser_commonlog (sender->s, rcpt->s, "accepted rcpt", "found existing recipient"); |
971 |
#endif |
972 |
return CHKUSER_OK; |
973 |
break; |
974 |
|
975 |
case CHKUSER_RELAYING: |
976 |
#if defined CHKUSER_LOG_VALID_RCPT |
977 |
chkuser_commonlog (sender->s, rcpt->s, "relaying rcpt", "client allowed to relay"); |
978 |
#endif |
979 |
return CHKUSER_RELAYING; |
980 |
break; |
981 |
|
982 |
case CHKUSER_NORCPTHOSTS: |
983 |
chkuser_commonlog (sender->s, rcpt->s, "rejected relaying", "client not allowed to relay"); |
984 |
CHKUSER_RCPT_DELAY_ANY(); |
985 |
out(CHKUSER_NORELAY_STRING); |
986 |
break; |
987 |
|
988 |
case CHKUSER_KO: |
989 |
chkuser_commonlog (sender->s, rcpt->s, "rejected rcpt", "not existing recipient"); |
990 |
CHKUSER_DELAY(); |
991 |
out(CHKUSER_NORCPT_STRING); |
992 |
break; |
993 |
|
994 |
case CHKUSER_ERR_AUTH_RESOURCE: |
995 |
chkuser_commonlog (sender->s, rcpt->s, "no auth resource", "no auth resource available"); |
996 |
CHKUSER_RCPT_DELAY_ANY(); |
997 |
out(CHKUSER_RESOURCE_STRING); |
998 |
break; |
999 |
|
1000 |
case CHKUSER_ERR_MBXFULL: |
1001 |
chkuser_commonlog (sender->s, rcpt->s, "mbx overquota", "rcpt mailbox is overquota"); |
1002 |
CHKUSER_RCPT_DELAY_ANY(); |
1003 |
out(CHKUSER_MBXFULL_STRING); |
1004 |
break; |
1005 |
|
1006 |
case CHKUSER_ERR_MAXRCPT: |
1007 |
chkuser_commonlog (sender->s, rcpt->s, "rejected rcpt", "max number of recipients"); |
1008 |
CHKUSER_DELAY (); |
1009 |
out(CHKUSER_MAXRCPT_STRING); |
1010 |
break; |
1011 |
|
1012 |
case CHKUSER_ERR_MAXWRONGRCPT: |
1013 |
chkuser_commonlog (sender->s, rcpt->s, "rejected rcpt", "max number of invalid recipients"); |
1014 |
CHKUSER_DELAY (); |
1015 |
out(CHKUSER_MAXWRONGRCPT_STRING); |
1016 |
break; |
1017 |
|
1018 |
case CHKUSER_ERR_INTRUSION_THRESHOLD: |
1019 |
chkuser_commonlog (sender->s, rcpt->s, "rejected intrusion", "rcpt ignored, session over INTRUSION threshold"); |
1020 |
CHKUSER_DELAY (); |
1021 |
out(CHKUSER_INTRUSIONTHRESHOLD_STRING); |
1022 |
break; |
1023 |
|
1024 |
case CHKUSER_ERR_DOMAIN_MISSING: |
1025 |
CHKUSER_DELAY (); |
1026 |
out(CHKUSER_DOMAINMISSING_STRING); |
1027 |
break; |
1028 |
|
1029 |
case CHKUSER_ERR_RCPT_FORMAT: |
1030 |
chkuser_commonlog (sender->s, rcpt->s, "rejected rcpt", "invalid rcpt address format"); |
1031 |
CHKUSER_RCPT_DELAY_ANY(); |
1032 |
out(CHKUSER_RCPTFORMAT_STRING); |
1033 |
break; |
1034 |
|
1035 |
case CHKUSER_ERR_RCPT_MX: |
1036 |
chkuser_commonlog (sender->s, rcpt->s, "rejected rcpt", "invalid rcpt MX domain"); |
1037 |
CHKUSER_RCPT_DELAY_ANY(); |
1038 |
out(CHKUSER_RCPTMX_STRING); |
1039 |
break; |
1040 |
|
1041 |
case CHKUSER_ERR_RCPT_MX_TMP: |
1042 |
chkuser_commonlog (sender->s, rcpt->s, "rejected rcpt", "temporary DNS problem"); |
1043 |
CHKUSER_RCPT_DELAY_ANY(); |
1044 |
out(CHKUSER_RCPTMX_TMP_STRING); |
1045 |
break; |
1046 |
} |
1047 |
|
1048 |
|
1049 |
|
1050 |
#if defined CHKUSER_WRONGRCPT_LIMIT_VARIABLE |
1051 |
if ((retstat == CHKUSER_KO) || (retstat == CHKUSER_ERR_DOMAIN_MISSING)) { |
1052 |
++wrong_recipients; |
1053 |
if ((INTRUSION_threshold_reached == 0) && (maxwrongrcpt_limit > 0) && (wrong_recipients >= maxwrongrcpt_limit)) { |
1054 |
chkuser_commonlog (sender->s, rcpt->s, "intrusion threshold", "max number of allowed invalid rcpt"); |
1055 |
INTRUSION_threshold_reached = 1; |
1056 |
} |
1057 |
} |
1058 |
#endif |
1059 |
|
1060 |
return CHKUSER_KO; |
1061 |
} |
1062 |
|
1063 |
|
1064 |
/* |
1065 |
* |
1066 |
* This routine checks for sender format and MX |
1067 |
* |
1068 |
*/ |
1069 |
|
1070 |
|
1071 |
int chkuser_sender (stralloc *sender) { |
1072 |
|
1073 |
int count; |
1074 |
|
1075 |
if (first_time_init_flag) { |
1076 |
first_time_init (); |
1077 |
} |
1078 |
|
1079 |
#if !defined CHKUSER_ALWAYS_ON && defined CHKUSER_STARTING_VARIABLE |
1080 |
if (starting_value == -1) { |
1081 |
return CHKUSER_OK; |
1082 |
} |
1083 |
#endif |
1084 |
|
1085 |
#if defined CHKUSER_SENDER_FORMAT || defined CHKUSER_SENDER_MX |
1086 |
|
1087 |
#if defined CHKUSER_SENDER_NOCHECK_VARIABLE |
1088 |
|
1089 |
if (sender_nocheck == 1) { |
1090 |
return CHKUSER_OK; |
1091 |
} |
1092 |
#endif |
1093 |
|
1094 |
if (sender->len <= 1) { |
1095 |
#if defined CHKUSER_LOG_VALID_SENDER |
1096 |
chkuser_commonlog (sender->s, "", "accepted null sender", "accepted null sender always"); |
1097 |
#endif |
1098 |
return CHKUSER_OK; |
1099 |
} |
1100 |
|
1101 |
count = byte_rchr(sender->s,sender->len,'@'); |
1102 |
if (count < sender->len) { |
1103 |
if (!stralloc_copyb (&sender_user, sender->s, count)) DIE_NOMEM(); |
1104 |
if (!stralloc_copys (&sender_domain, sender->s + count + 1)) DIE_NOMEM(); |
1105 |
} else { |
1106 |
if (!stralloc_copys (&sender_user, sender->s)) DIE_NOMEM(); |
1107 |
sender_domain.len = 0; |
1108 |
} |
1109 |
if (!stralloc_0 (&sender_user)) DIE_NOMEM(); |
1110 |
if (!stralloc_0 (&sender_domain)) DIE_NOMEM(); |
1111 |
|
1112 |
#if defined CHKUSER_SENDER_FORMAT |
1113 |
if (check_sender_address_format (&sender_user, &sender_domain) == 0) { |
1114 |
chkuser_commonlog (sender->s, "", "rejected sender", "invalid sender address format"); |
1115 |
CHKUSER_SENDER_DELAY_ANY(); |
1116 |
out(CHKUSER_SENDERFORMAT_STRING); |
1117 |
return CHKUSER_ERR_SENDER_FORMAT; |
1118 |
} |
1119 |
|
1120 |
#endif |
1121 |
|
1122 |
#if defined CHKUSER_SENDER_MX |
1123 |
|
1124 |
switch (chkuser_mx_lookup(&sender_domain)) { |
1125 |
|
1126 |
case DNS_HARD: |
1127 |
CHKUSER_SENDER_DELAY_ANY(); |
1128 |
out(CHKUSER_SENDERMX_STRING); |
1129 |
chkuser_commonlog (sender->s, "", "rejected sender", "invalid sender MX domain"); |
1130 |
return CHKUSER_ERR_SENDER_MX; |
1131 |
break; |
1132 |
|
1133 |
case DNS_SOFT: |
1134 |
CHKUSER_SENDER_DELAY_ANY(); |
1135 |
out(CHKUSER_SENDERMX_TMP_STRING); |
1136 |
chkuser_commonlog (sender->s, "", "rejected sender", "temporary DNS problem"); |
1137 |
return CHKUSER_ERR_SENDER_MX_TMP; |
1138 |
break; |
1139 |
} |
1140 |
|
1141 |
#if defined CHKUSER_LOG_VALID_SENDER |
1142 |
chkuser_commonlog (sender->s, "", "accepted sender", "sender accepted"); |
1143 |
#endif |
1144 |
|
1145 |
return CHKUSER_OK; |
1146 |
#endif |
1147 |
|
1148 |
#else |
1149 |
|
1150 |
return CHKUSER_OK; |
1151 |
|
1152 |
#endif |
1153 |
|
1154 |
} |
1155 |
|
1156 |
|