--- qmail-smtpd.c Tue Jun 11 11:45:51 2002 +++ qmail-smtpd.c Tue Jun 11 15:46:00 2002 @@ -1,3 +1,13 @@ + +/* + * + * Patch 'qmail-smtpd-chkusr' v.1.0 + * for qmail 1.0.3 and vpopmail 5.x.x + * + * Antonio Nati tonix@interazioni.it + * + */ + #include "sig.h" #include "readwrite.h" #include "stralloc.h" @@ -24,6 +34,17 @@ #include "timeoutread.h" #include "timeoutwrite.h" #endif +#include +#include +#include +#include +#include + +#include "open.h" +#include "/home/vpopmail/include/vpopmail.h" +#include "/home/vpopmail/include/vauth.h" +#include "/home/vpopmail/include/vpopmail_config.h" + #include "commands.h" #include "wait.h" #include "fd.h" @@ -78,7 +99,6 @@ return r; } #endif - int safewrite(fd,buf,len) int fd; char *buf; int len; { int r; @@ -189,7 +209,7 @@ if (bmfok == -1) die_control(); if (bmfok) if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem(); - + if (control_readint(&databytes,"control/databytes") == -1) die_control(); x = env_get("DATABYTES"); if (x) { scan_ulong(x,&u); databytes = u; } @@ -281,6 +301,182 @@ return 1; } + +void err_realrcpt() { out("550 sorry, no mailbox here by that name (#5.1.1 - chkusr)\r\n"); } + +int realrcpt_check() +{ + stralloc user = {0}; + stralloc domain = {0}; + stralloc domain_path = {0}; + stralloc bounce_path = {0}; + stralloc alias_name = {0}; + stralloc alias_path = {0}; + stralloc mailing_path = {0}; + int count; + int retstat = 0; + struct vqpasswd *user_passwd = NULL; + int fd_file = -1; + int read_char; + DIR *dir_file = NULL; + int offset; + char read_buf[1024]; + +/* if not local rcpthost we cannot control mailbox */ + + if (!addrallowed()) { return 1; } + +/* Set up our variables */ + +/* Search the '@' character */ + count = byte_rchr(addr.s,addr.len,'@'); + +/* + * Give extra room to variables used often or used outside stralloc_x calls + * This should make all safer and even faster + * (when these fields are used by stralloc_x routines) +*/ + if (!stralloc_ready (&domain, 200)) die_nomem(); + if (!stralloc_ready (&domain_path, 200)) die_nomem(); + + if (count < addr.len) { + if (!stralloc_copyb (&user, addr.s, count)) die_nomem(); + if (!stralloc_0 (&user)) die_nomem(); + if (!stralloc_copys (&domain, addr.s + count + 1)) die_nomem(); + if (!stralloc_0 (&domain)) die_nomem(); + } + else { + if (!stralloc_copys (&user, addr.s)) die_nomem(); + if (!stralloc_0 (&user)) die_nomem(); + if (!stralloc_copys (&domain, DEFAULT_DOMAIN)) die_nomem(); + if (!stralloc_0 (&domain)) die_nomem(); + } + +/* My personal control: continue only if a domain (default or not) is specified */ + + if (domain.len == 1) + return 0; + + case_lowers (user.s); + case_lowers (domain.s); + +/* Check if domain is a real domain */ + + if (!stralloc_0 (&domain)) die_nomem(); + vget_real_domain(domain.s, domain.a); + + domain.len = strlen (domain.s); + if (domain.len > (domain.a - 1)) die_nomem(); + +/* Let's get domain's real path */ + vget_assign(domain.s, domain_path.s, 156, NULL, NULL); + + domain_path.len = strlen (domain_path.s); + +/* Now Let's start the test suite */ + + switch (0) { + + case 0: +/* Check if domain has bouncing enabled */ + + /* Allocate room for bounce_path */ + if (!stralloc_ready (&bounce_path, 200)) die_nomem(); + if (!stralloc_copy (&bounce_path, &domain_path)) die_nomem(); + if (!stralloc_cats (&bounce_path, "/.qmail-default")) die_nomem(); + if (!stralloc_0 (&bounce_path)) die_nomem(); + + read_char = 0; + fd_file = open_read (bounce_path.s); + if (fd_file != -1) { + read_char = read (fd_file, read_buf, sizeof(read_buf) - 1); + close (fd_file); + if (read_char < 0) read_char = 0; + } + read_buf[read_char] = 0; + + if ( strstr(read_buf, "bounce-no-mailbox") == NULL ) { + retstat = 1; + break; + } + + case 1: +/* User control: check the existance of a real user */ + + user_passwd = vauth_getpw (user.s, domain.s); + if (user_passwd != NULL) { + + /* If user exists check if he has BOUNCE_MAIL flag set */ + + if (user_passwd->pw_gid & BOUNCE_MAIL) + retstat = 0; + else + retstat = 1; + break; + } + + case 2: +/* Check for aliases/forwards - valias*/ + + if (valias_select (user.s, domain.s) != NULL) { + retstat = 1; + break; + } + + case 3: +/* Check for aliases/forwards - .qmail.x files */ + + /* Allocate room for alias_path */ + if (!stralloc_ready (&alias_path, 200)) die_nomem(); + if (!stralloc_copy (&alias_name, &user)) die_nomem(); + + /* Change all '.' in ':' before continuing on aliases */ + for (count = 0; count < alias_name.len; ++count) + if (*(alias_name.s + count) == '.') *(alias_name.s + count) = ':'; + + if (!stralloc_copy (&alias_path, &domain_path)) die_nomem(); + if (!stralloc_cats (&alias_path, "/.qmail-")) die_nomem(); + if (!stralloc_cats (&alias_path, alias_name.s)) die_nomem(); + if (!stralloc_0 (&alias_path)) die_nomem(); + + /* access executes anyway as real (vpopmail:vchkpw), that's ok */ + if (access (alias_path.s, F_OK) == 0) { + retstat = 1; + break; + } + + case 4: +/* Let's check for mailing lists */ + + /* Allocate room for mailing_path */ + if (!stralloc_ready (&mailing_path, 300)) die_nomem(); + + /* Search for the outer '-' character */ + for (offset = user.len - 1; offset > 0; --offset) + if (*(user.s + offset) == '-') { + if (!stralloc_copy (&mailing_path, &domain_path)) die_nomem(); + if (!stralloc_cats (&mailing_path, "/")) die_nomem(); + if (!stralloc_catb (&mailing_path, user.s, offset)) die_nomem(); + if (!stralloc_cats (&mailing_path, "/mailinglist")) die_nomem(); + if (!stralloc_0 (&mailing_path)) die_nomem(); + /* access executes anyway as real (vpopmail:vchkpw), that's ok */ + if (access (mailing_path.s, F_OK) == 0) { + retstat = 1; + break; + } + } + +/* + * Add this code if another case is following + if (retstat == 1) + break; +*/ + + } /* end switch */ + + return retstat; +} + int bmfcheck() { int j; @@ -429,6 +625,7 @@ else { err_nogateway(); return; } } #endif + if (!realrcpt_check()) { err_realrcpt(); return; } if (!stralloc_cats(&rcptto,"T")) die_nomem(); if (!stralloc_cats(&rcptto,addr.s)) die_nomem(); if (!stralloc_0(&rcptto)) die_nomem();