diff -ur sendmail-8.9.3/cf/m4/cfhead.m4 sendmail-8.9.3+phquery/cf/m4/cfhead.m4 --- sendmail-8.9.3/cf/m4/cfhead.m4 Tue Dec 29 11:42:08 1998 +++ sendmail-8.9.3+phquery/cf/m4/cfhead.m4 Mon Feb 8 13:10:20 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-8.9.3+phquery/cf/m4/proto.m4 --- sendmail-8.9.3/cf/m4/proto.m4 Tue Feb 2 17:21:30 1999 +++ sendmail-8.9.3+phquery/cf/m4/proto.m4 Wed Feb 10 09:56:36 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-8.9.3+phquery/src/conf.c --- sendmail-8.9.3/src/conf.c Tue Jan 26 18:15:52 1999 +++ sendmail-8.9.3+phquery/src/conf.c Sat Feb 6 18:55:38 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, diff -ur sendmail-8.9.3/src/map.c sendmail-8.9.3+phquery/src/map.c --- sendmail-8.9.3/src/map.c Tue Feb 2 14:10:21 1999 +++ sendmail-8.9.3+phquery/src/map.c Mon Feb 8 11:54:44 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,308 @@ } #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 +{ + /* for ph_open */ + char *ph_server; + int ph_port; + + /* list of fields to search for match */ + char *field_list[4]; + + /* file descriptors */ + FILE *to_server; + FILE *from_server; +}; +typedef struct ph_map_struct PH_MAP_STRUCT; + +#define DEFAULT_PH_MAP_SERVICE "ns" +#define DEFAULT_PH_MAP_PORT 105 + + +/* 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->ph_server = NULL; + pmap->ph_port = 0; + pmap->field_list[0] = "alias"; + pmap->field_list[1] = "callsign"; + pmap->field_list[2] = "name"; + pmap->field_list[3] = ""; + 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 */ + while (isascii(*++p) && isspace(*p)) + continue; + pmap->ph_server = p; + break; + + case 'p': /* PH port */ + while (isascii(*++p) && isspace(*p)) + continue; + pmap->ph_port = atoi(p); + break; + + case 'v': /* field to return */ + while (isascii(*++p) && isspace(*p)) + continue; + pmap->field_list[0] = p; + pmap->field_list[1] = ""; + 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)); + + for (i = 0; pmap->field_list[i][0] != '\0'; i++) + pmap->field_list[i] = newstr(ph_map_dequote(pmap->field_list[i])); + + if (pmap->ph_server != NULL) + pmap->ph_server = newstr(ph_map_dequote(pmap->ph_server)); + else + { + syserr("ph_map_parseargs: -h flag is required"); + return FALSE; + } + + map->map_db1 = (ARBPTR_T) pmap; + return TRUE; +} + +/* open the connection to the ph server */ +bool +ph_map_open(map, mode) + MAP *map; + int mode; +{ + char *hostlist, *tmp; + PH_MAP_STRUCT *pmap; + + 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; + } + + pmap = (PH_MAP_STRUCT *)map->map_db1; + + hostlist = newstr(pmap->ph_server); + tmp = strtok(hostlist," "); + do { + if (OpenQi(tmp, &(pmap->to_server), &(pmap->from_server)) >= 0) + { + free(hostlist); + return TRUE; + } + } while (tmp = strtok(NULL," ")); + + syserr("ph_map_open: cannot connect to ph server(s)"); + 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; + 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 i, j; + QIR *server_data; + PH_MAP_STRUCT *pmap; + char *message; + + pmap = (PH_MAP_STRUCT *)map->map_db1; + + /* check all relevant fields */ + for (i = 0; pmap->field_list[i][0] != '\0'; i++) + { + while (1) + { + j = 0; + if (fprintf(pmap->to_server, "query %s=%s return email\n", pmap->field_list[i], key) < 0) + message = "ph_map_lookup: qi query"; + else if (fflush(pmap->to_server) < 0) + message = "ph_map_lookup: qi fflush"; + else if (!(server_data = ReadQi(pmap->from_server, &j))) + message = "ph_map_lookup: ReadQi() returned NULL"; + else + break; + + /* try to reopen the connection */ + sm_syslog(LOG_NOTICE,NULL,"%s; trying to reconnect to server",message); + ph_map_close(map); + if (!ph_map_open(map, O_RDONLY) && !bitset(MF_OPTIONAL, map->map_mflags)) + { + syserr("%serror communicating with PH directory server", bitset(MF_NODEFER, map->map_mflags) ? "" : "451 "); + *pstat = EX_TEMPFAIL; + return NULL; + } + } + + if (server_data->code >= 400 && server_data->code < 500) + { + /* temporary failure */ + *pstat = EX_TEMPFAIL; + return NULL; + } + else if (server_data->code > 0) + { + /* permanent error - assume no such user */ + *pstat = EX_UNAVAILABLE; + return NULL; + } + + /* if we found a single match, break out. + otherwise, try the next field. */ + if (j == 1) + break; + } + + /* if no field had a single match, bail out */ + if (j != 1) + { + *pstat = EX_UNAVAILABLE; + return NULL; + } + + if (bitset(MF_MATCHONLY, map->map_mflags)) + return map_rewrite(map, key, strlen(key), NULL); + else + return map_rewrite(map, server_data->message, strlen(server_data->message), args); +} + +#endif /* PH_MAP */ + + + /* ** syslog map */