Great Circle Associates List-Managers
(December 1992)

Indexed By Date: [Previous] [Next] Indexed By Thread: [Previous] [Next]

Subject: A "bozo" list...
From: bahainvs!johnw @ cs . UMD . EDU (John Wiegley)
Date: Tue, 15 Dec 92 17:01:07 EST
To: "List Managers" <list-managers @ GreatCircle . COM>

> > Something that I've been thinking about adding into majordomo is a
> > way to have a list of addreses to check before adding them to the
> > list.  If the address is in the bozo list, the request will be
> > denied with some message (possibly) until the list maintainer has
> > been notified that the bozo address has been corrected in a way suitable
> > to both parties.  There are some addresses that keep popping up bad
> > and the user keeps sending in subscribe me messages just to stay on the
> > list, even though his address, or something, is flakey at best.

For such a bozo list to really work is going to take a bit of programming..
I've written the code in 'C' to do address validation, but I don't think it
will work for Majordomo.  The reason is this:

Consider the following series of operations (this was sent by a friend, who
was helping me to debug the security validator in my database server):

/usr/jtidwell> telnet 25
Trying ...
Connected to
Escape character is '^]'.
220 mimsy.cs.UMD.EDU Sendmail 5.61/UMIACS-0.9/04-05-88 ready at Wed, 11 Nov 92  
11:40:14 -0500
mail from:
250 Sender ok
rcpt to: bahainvs!johnw
250 bahainvs!johnw... Recipient ok
           <I put message text here>

This effectively got a piece of mail into my database server from
""  It could also be set to any name you wish.

Now, the "bozo" list couldn't possible handle every possible option that
I could type it, and so, with Majordomo's facility of letting you change
the receipt address (necessary for those whose outbound address differs
from their inbound address), it make the efficacy of such a security
measure on Majordomo equal about nil.

NOTE: the above hack will also change the "From:" address, and the "From ",
      however, it will not alter the "Received:" address.  This became useful,
      because I could scan the Received fields to make absolutely sure that
      the mail sent from "" was actually received by
      the domain "".  If not, then it must be a bogus address.

Hope this helps you to design your implementation!

Good Luck,

P.S.  Here is a C program called "verify.c".  It usage is as follows:

      created an address list called "addtable" (address table).  Then
      execute "verify" from the same directory with the format:

        verify [address]

      It will show you the progress of its address analysis, and then
      tell you whether "[address]" is in addtable or not.

      NOTE: this version of "verify.c" does NOT implement "Received:"
            or "From " field checking.  This is a rather simple one
      that only check the "From:" field.  The more advanced one
      is being coding into a larger project, and so wasn't easily
      divorceable from the rest of the code.

      (also, in reading the output: step 1 is domain name processing,
       step 2 is user name processing, and step 3 is sub-domain name
       processing.  It will take apart any kind of address, and will
       ignore sub-sub-domains and the like..)

---[ verify.c ]---
#include <stdio.h>
#include <string.h>
#include <ctype.h>

struct address_template address_deconstruct(char *address);
int verifyname(char *name);
char *strtoupper(char *string);

struct address_template {
  char user[33];
  char subsubdomain[101];
  char subdomain[33];
  char domain[33];

main(int argc, char *argv[])
  if (verifyname(argv[1]))
    printf("Name (%s) is VALID\n", argv[1]);
    printf("Name (%s) is NOT valid\n", argv[1]);

int verifyname(char *name)
  FILE *file_ptr;
  char buffer[501];
  struct address_template query, check;

  query = address_deconstruct(name);

  printf("Address (%s) deconstructed to...\n", name);
  printf("        user: %s\n", query.user);
  printf("   subdomain: %s\n", query.subdomain);
  printf("      domain: %s\n", query.domain);

  file_ptr = fopen("addtable", "r");

  do {
    memset(buffer, 0, sizeof(buffer));
    if (!fgets(buffer, 500, file_ptr))
    printf("address read is (%s)\n", buffer);
    buffer[strlen(buffer) - 1] = (char) NULL;
    printf("modified address read is (%s)\n", buffer);
    check = address_deconstruct(buffer);
    if (!strcasecmp(strtoupper(query.user), strtoupper(check.user)))
      if (!strcasecmp(strtoupper(query.subdomain), strtoupper(check.subdomain)))
        if (!strcasecmp(strtoupper(query.domain), strtoupper(query.domain)))
          return (1);
  } while (!feof(file_ptr));


struct address_template address_deconstruct(char *address)
  int i, step = 0, j, uucp = 0;
  struct address_template temp;

  temp.domain[0] = (char) NULL;

  /* First things first, find the proper domain name IF '@' exists */

  for (i = strlen(address); i >= 0; i--)
    if (address[i] == '@')
      strcpy(temp.domain, &address[i + 1]);

/* DEBUG */
  if (temp.domain[0])
    printf("a_d: domain obtained, step 1: (%s)\n", temp.domain);

  /* If there are NO '@' signs, then it must be UUCP, and we know that user is  
last */

  if (!temp.domain[0]) {
    printf("a_d: parsing in UUCP mode, '@' not found..\n");
    for (i = 0; i < strlen(address); i++)
      if (address[i] == '!') {
        strncpy(temp.domain, address, i);
        printf("a_d: first '!' found, for domain, step 1: (%s)\n", temp.domain);
    for (i = strlen(address); i >= 0; i--)
      if (address[i] == '!') {
        strcpy(temp.user, &address[i + 1]);
        printf("a_d: last '!' found, for user, step 2: (%s)\n", temp.user);
    for (; i >= 0; i--)
      if (address[i] == '!') {
        strncpy(temp.subdomain, &address[i + 1], strlen(address) -  
strlen(temp.user) - i);
        printf("a_d: second to last '!' found, for subdomain, step 3: (%s)\n",  
        if (!strcasecmp(temp.subdomain, temp.domain))
          memset(temp.subdomain, 0, sizeof(temp.subdomain));
          printf("a_d: subdomain and domain are disparate! ergo, subdomain is  
  }       /* if there WAS an '@', then come in from the left.  '%' or '@' again  
means INET. */
  else {
    printf("a_d: parsing in INET mode, '@' found..\n");
    i = j = 0;
    while (1) {  /* since we know there's an '@', infinite loop till we come to  
it */
      j = i;
      for (; i < strlen(address); i++)
        if (address[i] == '%' || address[i] == '@') {
           strncpy(temp.user, &address[j], i++ - j);
          printf("a_d: first '%%' or '@' was found, user obtained, step 2:  
(%s)\n", temp.user);
          if (uucp) {
            printf("a_d: we're in UUCP/INET, step 3.  subdomain = last  
subsubdomain: (%s)\n", temp.subsubdomain);
            strcpy(temp.subdomain, temp.subsubdomain); /* last name before '!'  
was machine name */
            goto outtahere;
          else {
            j = i;
            for (; i < strlen(address); i++)
              if (address[i] == '@') {
                strncpy(temp.subdomain, &address[j], i - j);
                printf("a_d: name between the two '@' or '@ && %%' is subdomain,  
step 3: (%s)\n", temp.subdomain);
            goto outtahere;
        else if (address[i] == '!') {
          printf("a_d: hey! we found a '!', moving into INET/UUCP mode..\n");
          uucp = 1;  /* note that we processed a bit of UUCP info */
          strncpy(temp.subsubdomain, &address[j], i++ - j);  /* note: this could  
be the subdomain..! */
          printf("a_d: temp-shoving into subsubdomain: (%s)\n",  
      return(temp);  /* a good whole structure pass never hurt any midnight  
coder! */

char *strtoupper(char *string)
  char temp[81];
  int i;

  strcpy(temp, string);
  for (i = 0; i < strlen(temp); i++)
    temp[i] = toupper(temp[i]);

  strcpy(string, temp);

Indexed By Date Previous: Re: Nominations for Most Stupid Way of Gatewaying Mail
From: bahainvs!johnw@cs.UMD.EDU (John Wiegley)
Next: Re: Nominations for Most Stupid Way of Gatewaying Mail
From: "Kenton A. Hoover" <>
Indexed By Thread Previous: Re: Nominations for Most Stupid Way of Gatewaying Mail
From: "Michael H. Morse" <>
Next: Re: Writing a daemon
From: bahainvs!johnw@cs.UMD.EDU (John Wiegley)

Search Internet Search