chkusr 1.0 commented
This version of chkusr has been substituted by chkuser 2.0, that you find at this page.
qmail-smtpd-chkusr V. 1.0
> > /* > * > * Patch 'qmail-smtpd-chkusr' v.1.0 > * for qmail 1.03 and vpopmail 5.3.3 > * > * Antonio Nati tonix@interazioni.it > * > */ > include files needed for patch to work > #include <pwd.h> > #include <sys/types.h> > #include <unistd.h> > #include <dirent.h> > #include <stdio.h> > Change the following lines to point at your real directories. open.h is in the qmail source directory and should remains as is. vauth.h, vpopmail.h and vpopmail_config.h should be in the vpopmail include dir. > > #include "open.h" > #include "/vpopmail/include/vpopmail.h" > #include "/vpopmail/include/vauth.h" > #include "/vpopmail/include/vpopmail_config.h" > Routine emetting chkusr error > > void err_realrcpt() { out("550 sorry, no mailbox here by that name (#5.1.1 - chkusr)\r\n"); } > The complete routine handling all the chkusr stuff > > 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; > uid_t eff_uid; > gid_t eff_gid; > int offset; > char read_buf[1024]; > > /* if not local rcpthost we cannot control mailbox */ > > if (!addrallowed()) { return 1; } > > /* Set up our variables */ > Let's save the effective UID & GID, in order to use them later to set back the original effective UID & GID > /* qmail-smtpd is running now as (effective) qmaild:nofiles */ > /* Save the effective UID & GID (qmaild:nofiles) */ > eff_uid = geteuid (); > eff_gid = getegid (); > > /* Search the '@' character */ > count = byte_rchr(addr.s,addr.len,'@'); > > /* The following lines could interest people using # instead of @ in e-mail address */ > /* If '@' not found search the '%' character */ > /* > if (count >= addr.len) { > count = byte_rchr(addr.s,addr.len,'%'); > } > */ > Let's use Dan string routines to allocate the needed space on variable modified by vpopmail or other calls external to qmail > /* > * 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; > Let's set the new effective UID & GID. Note carefully that now we cannot exit from the routine until we've switched back to original UID & GID. > /* Now set new effective UID & GID, getting it from real UID & GID (vpopmail:vchkpw) */ > > setegid (getgid()); > seteuid (getuid()); > > /* qmail-smtpd is running now as effective vpopmail:vchkpw */ > > case_lowers (user.s); > case_lowers (domain.s); > If domain is an alias domain, let's get the real domain > /* 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 the domain's path, using vpopmail call vget_assign. > /* 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 the switch cascading suite of tests. I've preferred this way of cascade checks, because is much more readable and manageable than nested if (too much if to be used!) > /* Now Let's start the test suite */ > > switch (0) { > Check if domain has bouncing enabled > 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; > } > Check if vpopmail user exists > case 1: > /* User control: check the existence 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; > } > Check aliases in the valias format > case 2: > /* Check for aliases/forwards - valias*/ > > if (valias_select (user.s, domain.s) != NULL) { > retstat = 1; > break; > } > Check aliases/forwards/robots in the .qmail-xxxx format > 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; > } > Check for mailing list existence > 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; > } > } > The following code is necessary, in order to break the switch sequence, only if someone adds other cases below. > /* > * Add this code if another case is following > if (retstat == 1) > break; > */ > > } /* end switch */ > Resume original UID and GID > /* Now switch back effective to saved UID & GID (qmaild:nofiles) */ > > setegid (eff_gid); > seteuid (eff_uid); > > /* qmail-smtpd is running again as (effective) qmaild:nofiles */ > Exits the routine returning the result > return retstat; > } > Calling the checking user routine, within the existing addrallowed function. int addrallowed() { ......................... ......................... else if (!addrallowed()) { err_nogateway(); return; } + 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();
Document info
Page created on 5 march 2002, last modified on 5 march 2002.