--- qmail-smtpd-x.0.c	Tue Jun 11 11:45:51 2002
+++ qmail-smtpd-x.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 <pwd.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <stdio.h>
+
+#include "open.h"
+#include "/vpopmail/include/vpopmail.h"
+#include "/vpopmail/include/vauth.h"
+#include "/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();
