diff -ur sendmail-8.9.3/cf/m4/cfhead.m4 sendmail_phmap-8.9.3/cf/m4/cfhead.m4 --- sendmail-8.9.3/cf/m4/cfhead.m4 Tue Dec 29 11:42:08 1998 +++ sendmail_phmap-8.9.3/cf/m4/cfhead.m4 Thu Feb 11 14:06:07 1999 @@ -100,6 +100,10 @@ POPDIVERT`'dnl`'') define(`RELAY_DOMAIN_FILE', `PUSHDIVERT(5)FR$1 POPDIVERT`'dnl`'') +define(`PH_DOMAIN_MAP',`define(`PH_DOMAIN_LIST',ifdef(`PH_DOMAIN_LIST',`PH_DOMAIN_LIST $1',`$1'))PUSHDIVERT(5) +# PH map for $1 domain +K translit($1, `.', `_') ph -h "$2" -T +POPDIVERT`'dnl`'') define(`_OPTINS', `ifdef(`$1', `$2$1$3')') m4wrap(`include(_CF_DIR_`m4/proto.m4')') diff -ur sendmail-8.9.3/cf/m4/proto.m4 sendmail_phmap-8.9.3/cf/m4/proto.m4 --- sendmail-8.9.3/cf/m4/proto.m4 Tue Feb 2 17:21:30 1999 +++ sendmail_phmap-8.9.3/cf/m4/proto.m4 Thu Feb 11 14:06:07 1999 @@ -196,6 +196,14 @@ ')CE root undivert(5)dnl +ifdef(`PH_DOMAIN_LIST',`dnl +# dot to underscore translation (used to map domains to PH maps) +Kdot_to_underscore regex -s1,2 -d_ (.*)\.([^\.]*)$ + +# PH domain class +C{PH_DOMAINS} PH_DOMAIN_LIST', +`dnl') + # who I masquerade as (null for no masquerading) (see also $=M) DM`'ifdef(`MASQUERADE_NAME', MASQUERADE_NAME) @@ -759,6 +767,21 @@ R$* < @ [ $+ ] > $* $: $>98 $1 < @ [ $2 ] > $3 numeric internet spec R$* < @ [ $+ ] > $* $#_SMTP_ $@ [$2] $: $1 < @ [$2] > $3 still numeric: send', `dnl') + +ifdef(`PH_DOMAIN_LIST',`dnl +# do PH server lookup where applicable +R$+ <@$={PH_DOMAINS} .> $: PH: $1 <@ $2 > only process ph domains +RPH: $=L <@ $=w > $: $1 <@ $2 .> weed out local users, +# in case Cw contains a ph domain +RPH: $+ <@ $+.$+ > PH: $1 <@ $(dot_to_underscore $2 . $3 $) > +# map for "uiuc.edu" is "uiuc_edu" +RPH: $+ + $+ <@ $*> $: PH: $1 <@ $3 > + $2 handle user+list syntax +RPH: $+ <@ $* > $* $: PH: $( $2 $1 $: PH_ERROR $) $3 +# do actual ph map lookup +RPH:PH_ERROR $* $# error $: email address lookup in campus directory failed +RPH: $+ @ $+ + $+ $: PH: $1 + $3 @ $2 add original user+list +RPH: $+ @ $+ $: $1 <@ $2 .> keep new address for processing +',`dnl') ifdef(`VIRTUSER_TABLE', `dnl # handle virtual users diff -ur sendmail-8.9.3/src/conf.c sendmail_phmap-8.9.3/src/conf.c --- sendmail-8.9.3/src/conf.c Tue Jan 26 18:15:52 1999 +++ sendmail_phmap-8.9.3/src/conf.c Thu Feb 11 14:31:26 1999 @@ -395,6 +395,12 @@ ldap_map_lookup, null_map_store); #endif +#ifdef PH_MAP + MAPDEF("ph", NULL, 0, + ph_map_parseargs, ph_map_open, ph_map_close, + ph_map_lookup, null_map_store); +#endif + #ifdef HESIOD MAPDEF("hesiod", NULL, MCF_ALIASOK|MCF_ALIASONLY, map_parseargs, hes_map_open, null_map_close, @@ -4740,6 +4746,9 @@ #endif #if HES_GETMAILHOST "HES_GETMAILHOST", +#endif +#ifdef PH_MAP + "PH_MAP", #endif #ifdef LDAPMAP "LDAPMAP", diff -ur sendmail-8.9.3/src/map.c sendmail_phmap-8.9.3/src/map.c --- sendmail-8.9.3/src/map.c Tue Feb 2 14:10:21 1999 +++ sendmail_phmap-8.9.3/src/map.c Thu Feb 11 16:47:59 1999 @@ -2583,6 +2583,43 @@ ** Get your support from him. */ +/* +** LDAP_MAP_DEQUOTE - helper routine for ldap_map_parseargs +*/ + +#if defined(LDAPMAP) || defined(PH_MAP) + +#ifdef PH_MAP +# define ph_map_dequote ldap_map_dequote +#endif + +char * +ldap_map_dequote(str) + char *str; +{ + char *p; + char *start; + p = str; + + if (*p == '"') + { + start = ++p; + /* Should probably swallow initial whitespace here */ + } + else + { + return(str); + } + while (*p != '"' && *p != '\0') + { + p++; + } + if (*p != '\0') + *p = '\0'; + return start; +} +#endif /* LDAPMAP || PH_MAP */ + #ifdef LDAPMAP # undef NEEDGETOPT /* used for something else in LDAP */ @@ -2943,36 +2980,6 @@ /* -** LDAP_MAP_DEQUOTE - helper routine for ldap_map_parseargs -*/ - -char * -ldap_map_dequote(str) - char *str; -{ - char *p; - char *start; - p = str; - - if (*p == '"') - { - start = ++p; - /* Should probably swallow initial whitespace here */ - } - else - { - return(str); - } - while (*p != '"' && *p != '\0') - { - p++; - } - if (*p != '\0') - *p = '\0'; - return start; -} - -/* ** LDAP_MAP_PARSEARGS -- parse ldap map definition args. */ @@ -3235,6 +3242,337 @@ } #endif /* LDAP Modules */ + + +#ifdef PH_MAP + +/* Support for the CCSO Nameserver (ph/qi). + This code is intended to replace the so-called "ph mailer". + Contributed by Mark D. Roth . */ + +#include +#include + +struct ph_map_struct +{ + /* currently connected to PH server? */ + bool connected; + + /* list of ph servers */ + char *ph_servers; + + /* list of fields to search for match */ + char *field_list; + + /* file descriptors */ + FILE *to_server; + FILE *from_server; +}; +typedef struct ph_map_struct PH_MAP_STRUCT; + +#define DEFAULT_PH_MAP_FIELDS "alias callsign name" + + +/* parse arguments */ +bool +ph_map_parseargs(map, args) + MAP *map; + char *args; +{ + PH_MAP_STRUCT *pmap = NULL; + register char *p = args; + register int done; + int i; + + pmap = (PH_MAP_STRUCT *)xalloc(sizeof(PH_MAP_STRUCT)); + + /* defaults */ + pmap->connected = FALSE; + pmap->ph_servers = NULL; + pmap->field_list = NULL; + pmap->to_server = NULL; + pmap->from_server = NULL; + + map->map_mflags |= MF_TRY0NULL | MF_TRY1NULL; + for (;;) + { + while (isascii(*p) && isspace(*p)) + p++; + if (*p != '-') + break; + switch (*++p) + { + case 'N': + map->map_mflags |= MF_INCLNULL; + map->map_mflags &= ~MF_TRY0NULL; + break; + + case 'O': + map->map_mflags &= ~MF_TRY1NULL; + break; + + case 'o': + map->map_mflags |= MF_OPTIONAL; + break; + + case 'f': + map->map_mflags |= MF_NOFOLDCASE; + break; + + case 'm': + map->map_mflags |= MF_MATCHONLY; + break; + + case 'A': + map->map_mflags |= MF_APPEND; + break; + + case 'q': + map->map_mflags |= MF_KEEPQUOTES; + break; + + case 't': + map->map_mflags |= MF_NODEFER; + break; + + case 'a': + map->map_app = ++p; + break; + + case 'T': + map->map_tapp = ++p; + break; + + case 'h': /* PH server list */ + while (isascii(*++p) && isspace(*p)) + continue; + pmap->ph_servers = p; + break; + + case 'v': /* fields to search for */ + while (isascii(*++p) && isspace(*p)) + continue; + pmap->field_list = p; + break; + + default: + syserr("ph_map_parseargs: unknown option -%c\n",*p); + } + + /* try to account for quoted strings */ + done = isascii(*p) && isspace(*p); + while (*p != '\0' && !done) + { + if (*p == '"') + { + while (*++p != '"' && *p != '\0') + { + continue; + } + if (*p != '\0') + p++; + } + else + { + p++; + } + done = isascii(*p) && isspace(*p); + } + + if (*p != '\0') + *p++ = '\0'; + } + + if (map->map_app != NULL) + map->map_app = newstr(ph_map_dequote(map->map_app)); + if (map->map_tapp != NULL) + map->map_tapp = newstr(ph_map_dequote(map->map_tapp)); + + if (pmap->field_list != NULL) + pmap->field_list = newstr(ph_map_dequote(pmap->field_list)); + else + pmap->field_list = DEFAULT_PH_MAP_FIELDS; + + if (pmap->ph_servers != NULL) + pmap->ph_servers = newstr(ph_map_dequote(pmap->ph_servers)); + else + { + syserr("ph_map_parseargs: -h flag is required"); + return FALSE; + } + + map->map_db1 = (ARBPTR_T) pmap; + return TRUE; +} + +/* don't really open the map until we need to look something up */ +bool +ph_map_open(map, mode) + MAP *map; + int mode; +{ + mode &= O_ACCMODE; + if (mode != O_RDONLY) + { + /* issue a pseudo-error message */ +#ifdef ENOSYS + errno = ENOSYS; +#else +# ifdef EFTYPE + errno = EFTYPE; +# else + errno = ENXIO; +# endif +#endif + return FALSE; + } + return TRUE; +} + +/* open the connection to the ph server */ +bool +ph_map_really_open(map) + MAP *map; +{ + int j; + QIR *server_data = NULL; + char *hostlist, *tmp; + PH_MAP_STRUCT *pmap; + + pmap = (PH_MAP_STRUCT *)map->map_db1; + + hostlist = newstr(pmap->ph_servers); + tmp = strtok(hostlist," "); + do { + if (OpenQi(tmp, &(pmap->to_server), &(pmap->from_server)) >= 0) + { + if (fprintf(pmap->to_server, "id sendmail+phmap\n") < 0 || fflush(pmap->to_server) < 0 || !(server_data = ReadQi(pmap->from_server, &j)) || server_data->code != 200) + continue; + + if (server_data) + free(server_data); + free(hostlist); + pmap->connected = TRUE; + return TRUE; + } + } while (tmp = strtok(NULL," ")); + + syserr("%sph_map_really_open: cannot connect to ph server(s)", bitset(MF_NODEFER,map->map_mflags) ? "" : "451 "); + free(hostlist); + return FALSE; +} + +/* close the connection to the ph server */ +void +ph_map_close(map) + MAP *map; +{ + PH_MAP_STRUCT *pmap; + + pmap = (PH_MAP_STRUCT *)map->map_db1; + pmap->connected = FALSE; + CloseQi(pmap->to_server, pmap->from_server); + pmap->to_server = NULL; + pmap->from_server = NULL; +} + +/* look up key from ph server */ +char * +ph_map_lookup(map, key, args, pstat) + MAP *map; + char *key; + char **args; + int *pstat; +{ + int numtries; + int j; + size_t sz; + QIR *server_data; + PH_MAP_STRUCT *pmap; + char *message; + char *tmp, *field; + + pmap = (PH_MAP_STRUCT *)map->map_db1; + + /* check all relevant fields */ + tmp = pmap->field_list; + do { + while (isascii(*tmp) && isspace(*tmp)) + tmp++; + if (*tmp == '\0') + break; + sz = strcspn(tmp, " "); + field = xalloc(sz + 1); + strncpy(field,tmp,sz); + field[sz] = '\0'; + tmp += sz; + + /* retry twice, then fail */ + for (numtries = 0; numtries < 2; numtries++) + { + /* connect to server, if not already connected */ + if (! pmap->connected && !ph_map_really_open(map, O_RDONLY) && !bitset(MF_OPTIONAL, map->map_mflags)) + { + free(field); + *pstat = EX_TEMPFAIL; + return NULL; + } + + j = 0; + + if (LogLevel > 9) + sm_syslog(LOG_NOTICE,NULL,"ph_map_lookup: query %s=%s return email", field, key); + if (fprintf(pmap->to_server, "query %s=%s return email\n", field, key) < 0) + message = "ph_map_lookup: qi query command failed"; + else if (fflush(pmap->to_server) < 0) + message = "ph_map_lookup: qi fflush failed"; + else if (!(server_data = ReadQi(pmap->from_server, &j))) + message = "ph_map_lookup: ReadQi() returned NULL"; + else + break; + + if (LogLevel > 9) + sm_syslog(LOG_NOTICE,NULL,"%s - trying to reconnect to PH server",message); + ph_map_close(map); + } + + free(field); + + if (server_data->code >= 400 && server_data->code < 500) + { + /* temporary failure */ + *pstat = EX_TEMPFAIL; + return NULL; + } + + /* if we found a single match, break out. + otherwise, try the next field. */ + if (j == 1) + break; + } while (*tmp != '\0'); + + /* if no field had a single match, bail out */ + if (j != 1) + { + *pstat = EX_UNAVAILABLE; + return NULL; + } + + if (tTd(38,20)) + printf("ph_map_lookup: %s => %s\n",key,server_data->message); + + if (bitset(MF_MATCHONLY, map->map_mflags)) + return map_rewrite(map, key, strlen(key), NULL); + + message = map_rewrite(map, server_data->message, strlen(server_data->message), args); + free(server_data); + return message; +} + +#endif /* PH_MAP */ + + + /* ** syslog map */