home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / src / submit / adr_submit.c next >
Encoding:
C/C++ Source or Header  |  1990-02-28  |  26.5 KB  |  961 lines

  1. #include "util.h"
  2. #include "mmdf.h"
  3.  
  4. #include <sys/stat.h>
  5.  
  6. /*
  7.  *     MULTI-CHANNEL MEMO DISTRIBUTION FACILITY  (MMDF)
  8.  *
  9.  *
  10.  *     Copyright (C) 1979,1980,1981  University of Delaware
  11.  *
  12.  *     Department of Electrical Engineering
  13.  *     University of Delaware
  14.  *     Newark, Delaware  19711
  15.  *
  16.  *     Phone:  (302) 738-1163
  17.  *
  18.  *
  19.  *     This program module was developed as part of the University
  20.  *     of Delaware's Multi-Channel Memo Distribution Facility (MMDF).
  21.  *
  22.  *     Acquisition, use, and distribution of this module and its listings
  23.  *     are subject restricted to the terms of a license agreement.
  24.  *     Documents describing systems using this module must cite its source.
  25.  *
  26.  *     The above statements must be retained with all copies of this
  27.  *     program and may not be removed without the consent of the
  28.  *     University of Delaware.
  29.  *
  30.  *
  31.  *     version  -1    David H. Crocker    March   1979
  32.  *     version   0    David H. Crocker    April   1980
  33.  *     version  v7    David H. Crocker    May     1981
  34.  *     version   1    David H. Crocker    October 1981
  35.  *
  36.  */
  37.  
  38. /*  SUBMIT ADDRESS HANDLING                                             */
  39.  
  40. /*  Apr, 81 Dave Crocker    adr_check able to handle foo<addr> form
  41.  *  Jun, 81 Dave Crocker    adr_check copy test addr, before parsing
  42.  *                          loc_alsrch check for increment to lnk_nadrs
  43.  *                          in case alias entry had no good addresses
  44.  *  Jul 81 Dave Crocker     use separate variable to detect no valid
  45.  *                          alias entries
  46.  *                          fixed alias no-valid-address handling
  47.  *                          lnk_nadrs no longer referenced
  48.  *  May 82 Dave Crocker     adr_ghost use locname, if host field null
  49.  *                          adr_check use chan name as host, if none given
  50.  *                          adr_check added call to loc_gsrch
  51.  *                          loc_g* routines added to use group names as list
  52.  *  Jun 82 Dave Crocker     prevent alias cycling by saving source specs
  53.  *  Aug 82 Dave Crocker     adr_check returns bad user/host distinction
  54.  *  Dec 82 Doug Kingston    fixed error in design of lc_afin(), and lc_gfin().
  55.  *  Feb 83 Doug Kingston    Modified adr_local to recurse through adr_check
  56.  *                          when the local string contains a '%', '.'.
  57.  *  Apr 83 Steve Kille      Add code to transparently deliver between machines
  58.  *                              This uses a table of user to machine matches
  59.  *                              Could use aliases or password instead
  60.  *  May 83 Steve Kille      Change adr_check to handle domain routes
  61.  */
  62.  
  63. #include <pwd.h>
  64. #include "ch.h"
  65. #include "dm.h"
  66. #include "ap.h"
  67.  
  68. #define MAXLOOPS 10
  69.  
  70. extern struct ll_struct *logptr;
  71. extern char *ch_dflnam;
  72. extern char *locname;
  73. extern char *locfullname;
  74. extern char *supportaddr;
  75. extern char *sitesignature;
  76. extern char *locmachine;               /* local machine name           */
  77. extern int mgt_inalias;
  78. extern int ap_outtype;
  79. extern short tracing;
  80.  
  81.                 /* These two names are being retained for
  82.                  * their mnemonic value. */
  83. char *adr_fulldmn;              /* Name of 'full' domain                */
  84. char *adr_fmc;                  /* name of 'full' machie                */
  85. char *adr_orgspec;              /* original mailbox string              */
  86.  
  87. extern char *blt();
  88. extern char *index();
  89. extern char *rindex();
  90. extern char mgt_dlname[];    /* name of the delay channel */
  91. extern char *ap_p2s();
  92.  
  93. /* **************  (adr_) PROCESS A SINGLE ADDRESS  *****************  */
  94.  
  95. LOCVAR char adr_gotone;        /* got at least one valid address     */
  96. LOCVAR char adr_level = 0;    /* Level adr_check/adr_local recursion */
  97.  
  98. adr_check (local, domain, route) /* check & save an address            */
  99.     AP_ptr  local,             /* beginning of local-part */
  100.         domain,            /* basic domain reference */
  101.         route;             /* beginning of 733 forward routing */
  102. {
  103.     extern Domain *dm_v2route ();
  104.     Dmn_route dmrt;
  105.     Dmn_route tmpdmrt;
  106.     AP_ptr hptr;               /* 'next' host */
  107.     Chan   *thechan;
  108.     char    tstline[LINESIZE],
  109.         official[LINESIZE],
  110.         tmpstr[LINESIZE];
  111.     int    i;
  112.     int    nextchan;
  113.     AP_ptr ap;
  114.     char   *cp = (char *)0;
  115.     int loopcnt = 0;
  116.     int retval;
  117.  
  118. #ifdef DEBUG
  119.     ll_log (logptr, LLOGBTR, "adr_check (loc='%s', dom='%s', rt='%s')",
  120.       local -> ap_obvalue,
  121.       domain != (AP_ptr) 0 ? domain -> ap_obvalue : "[NIL]",
  122.       route != (AP_ptr) 0 ? route -> ap_obvalue : "[NIL]");
  123. #endif
  124.  
  125.     /* Limit the number of time we loop looking up routes to domains */
  126.     /* (Sort of a cop-out for foo.bar where foo isn't in the channel table */
  127.     for (thechan = (Chan *) NOTOK; ; loopcnt++)
  128.     {
  129.     if (loopcnt > MAXLOOPS)
  130.         return (RP_BHST);
  131.     /*
  132.      * This if-then-else clause selects the nxt domain to be
  133.      * evaluated or calls adr_local if there are none left.
  134.      */
  135.     if (route != (AP_ptr) 0) {    /* have explicit routing info */
  136.         hptr = route;        /* a list of fields             */
  137.         FOREVER
  138.         {
  139.         switch (route -> ap_ptrtype) {
  140.             case APP_NIL:
  141.             case APP_NXT:
  142.             route = (AP_ptr) 0;
  143.             break;  /* no more route */
  144.  
  145.             case APP_ETC:
  146.             route = route -> ap_chain;
  147.             if(route == (AP_ptr)0)
  148.                 break;
  149.             switch (route -> ap_obtype) {
  150.                 case APV_DLIT:
  151.                 case APV_DOMN:
  152.                 break;
  153.  
  154.                 case APV_CMNT:
  155.                 continue;
  156.  
  157.                 default:
  158.                 route = (AP_ptr) 0;
  159.                 break;  /* no more route */
  160.             }
  161.         }
  162.         break; /* no route */
  163.         }
  164.     }
  165.     else                    /* just use the primary reference */
  166.     if (domain != (AP_ptr) 0) {    /* domain ref is a single field */
  167.         hptr = domain;
  168.         domain = (AP_ptr) 0;
  169.     }
  170.     else {
  171. #ifdef DEBUG
  172.         ll_log (logptr, LLOGFTR, "local address");
  173. #endif
  174.         if(adr_level++ == 0)
  175.         adr_orgspec = NULL;
  176.         retval = adr_local (local -> ap_obvalue);
  177.         adr_level--;
  178.         return (retval);
  179.     }
  180.  
  181. /*
  182.  *  a single domain reference is evaluated
  183.  */
  184. #ifdef DEBUG
  185.     ll_log (logptr, LLOGFTR, "testing '%s'", hptr -> ap_obvalue);
  186. #endif
  187.  
  188.     if (thechan != (Chan *) NOTOK) {
  189.         /* Last time through was channel reference */
  190.         /* Check the specified table this time */
  191. #ifdef DEBUG
  192.         ll_log (logptr, LLOGFTR, "chan specified, checking '%s'",
  193.         thechan -> ch_show);
  194. #endif
  195.         /* SEK if lookup fails, may still be domain */
  196.         /* reference, so fall into code down below */
  197.         retval = tb_k2val(thechan->ch_table,TRUE,hptr->ap_obvalue, tstline);
  198.         if(retval == MAYBE)
  199.         return(RP_NS);
  200.         else if(retval == OK)
  201.         {
  202.         strcpy (tstline, hptr -> ap_obvalue);
  203.         strcpy (official, tstline); /* no domain */
  204.         goto storeit;
  205.         }
  206.     }
  207.  
  208.     if (thechan == (Chan *) NOTOK)
  209.     {
  210.         if (lexequ (hptr -> ap_obvalue, locname) ||
  211.         lexequ (hptr -> ap_obvalue, adr_fulldmn) ||
  212.         lexequ (hptr -> ap_obvalue, locmachine) ||
  213.         lexequ (hptr -> ap_obvalue, adr_fmc)) {
  214. #ifdef DEBUG
  215.          ll_log (logptr, LLOGFTR, "loc ref '%s' found", hptr ->
  216.             ap_obvalue);
  217. #endif
  218.                 /* SEK shortcut normalised address      */
  219.          continue;
  220.         }
  221.     }
  222.  
  223.     switch ((int)dm_v2route (hptr -> ap_obvalue, official, &dmrt)) {
  224.         case MAYBE:
  225.         return (RP_NS);
  226.                   /* obtain a host reference            */
  227.         case OK:              /* 'tis us                            */
  228. #ifdef DEBUG
  229.         ll_log (logptr, LLOGFTR, "local domain reference");
  230. #endif
  231.         continue;         /* go to next domain reference        */
  232.  
  233.         case NOTOK:          /* Not a valid hostname */
  234.                   /* SEK: first check for explicit       */
  235.                   /* channel refs (somehow)              */
  236.         if (cp = rindex(hptr -> ap_obvalue, '#')) {
  237.             *cp = 0;
  238.             if ((thechan = ch_nm2struct (hptr -> ap_obvalue))
  239.                         != (Chan *) NOTOK) {
  240. #ifdef DEBUG
  241.             ll_log (logptr, LLOGFTR, "explicit chan spec '%s'",
  242.                 thechan -> ch_name);
  243. #endif
  244.             cp = 0;
  245.             continue;
  246.             }
  247.         }
  248.         if ((thechan = ch_nm2struct("badhosts")) != (Chan *)NOTOK) {
  249.             strcpy (tstline, thechan->ch_host ? thechan->ch_host : "");
  250.             strcpy (official, hptr -> ap_obvalue);
  251.             goto storeit;
  252.         }
  253.  
  254.         /*
  255.          * Bad name - really not known, and no place to send it.
  256.          */
  257.         return (RP_BHST);
  258.  
  259.         default:
  260.          if (thechan != (Chan *) NOTOK) {
  261. #ifdef DEBUG
  262.             ll_log (logptr, LLOGFTR, "chan specified, checking '%s'",
  263.             thechan -> ch_show);
  264. #endif
  265.             if (dmrt.dm_argc != 1)
  266.             return (RP_BHST);
  267.             switch(tb_k2val (thechan -> ch_table, TRUE,
  268.                 dmrt.dm_argv[0], tstline)) {
  269.             case MAYBE:
  270.             return (RP_NS);
  271.             case OK:
  272.             break;
  273.             default:
  274.             return (RP_BHST);
  275.             }
  276.             strcpy (tstline, dmrt.dm_argv[0]);
  277.             goto storeit;                /* store it */
  278.         }
  279.  
  280.         for (i = 0; i < (dmrt.dm_argc - 1); i++) {
  281.                 /* algorithm - first component in table is */
  282.                 /* last component in route, but before     */
  283.                 /* route in  address.                      */
  284.                 /* Thus take route components from the     */
  285.                 /* left, and add to front of explictit     */
  286.                 /* route                                   */
  287.             if (domain == (AP_ptr) 0) {
  288. #ifdef DEBUG
  289.                ll_log (logptr,LLOGFTR,"Adding local (1) component '%s'",
  290.                     dmrt.dm_argv[i]);
  291. #endif
  292.             domain = ap_new (APV_DOMN, dmrt.dm_argv[i]);
  293.             }
  294.             else {
  295. #ifdef DEBUG
  296.                ll_log (logptr, LLOGFTR, "Adding route component 1 '%s'",
  297.                     dmrt.dm_argv[i]);
  298. #endif
  299.             ap = ap_new (APV_DOMN, dmrt.dm_argv[i]);
  300.             if (route != (AP_ptr) 0)
  301.                 ap -> ap_ptrtype = APP_ETC;
  302.             ap -> ap_chain = route;
  303.             route = ap;
  304.             }
  305.         }
  306. #ifdef DEBUG
  307.         ll_log (logptr, LLOGFTR, "Checking '%s' in channel tables",
  308.                 dmrt.dm_argv [dmrt.dm_argc - 1]);
  309. #endif
  310.         switch ((int)(thechan = ch_h2chan
  311.               (dmrt.dm_argv [dmrt.dm_argc -1], 1)))
  312.         {
  313.             case MAYBE:
  314.                 /* NS failure */
  315.                 return(RP_NS);
  316.             case OK:      /* 'tis us                            */
  317.                 /* SEK first check for self to avoid    */
  318.                 /* loops due to references to           */
  319.                 /* non-existent local subdomains        */
  320.             if (dmrt.dm_argc > 1)
  321.                if (lexequ (dmrt.dm_argv [dmrt.dm_argc - 2],
  322.                 official))
  323.                 {
  324.                 /* Check first to see if previous entry is */
  325.                 /* in channel tables, for handling locmachine */
  326.                 switch ((int)(thechan = ch_h2chan
  327.                   (dmrt.dm_argv [dmrt.dm_argc -2], 1)))
  328.                 {
  329.                     case MAYBE:
  330.                     return(RP_NS);
  331.                     case OK:
  332.                     case NOTOK:
  333. #ifdef DEBUG
  334.                     ll_log (logptr, LLOGTMP,
  335.                       "Found unknown subdomain '%s'",
  336.                       hptr -> ap_obvalue);
  337. #endif
  338.                     return (RP_BHST);
  339.  
  340.                    default:
  341.                     /* Found host ref               */
  342.                     strcpy (tstline, dmrt.dm_argv [dmrt.dm_argc  - 2]);
  343.                     strcpy (official, tstline);
  344.                     /* Now remove first component of */
  345.                     /* route                         */
  346.                     if (route == (AP_ptr) 0) {
  347.                         ap_free (domain);
  348.                         domain = (AP_ptr) 0;
  349.                     }
  350.                     else {
  351.                         ap = route;
  352.                         route = ap -> ap_chain;
  353.                         ap_free (ap);
  354.                     }
  355.                     goto storeit;
  356.                 }
  357.                 }
  358. #ifdef DEBUG
  359.             ll_log (logptr, LLOGFTR, "local host reference");
  360. #endif
  361.             thechan = (Chan *) NOTOK;               /* DPK */
  362.             continue; /* go to next domain reference        */
  363.  
  364.             case NOTOK:   /* hmmm, unknown                      */
  365.             switch((int)dm_v2route (dmrt.dm_argv[dmrt.dm_argc -1],
  366.                 tmpstr, &tmpdmrt)) {
  367.             case NOTOK:
  368.                 return (RP_BHST);
  369.             case MAYBE:
  370.                 return (RP_NS);
  371.             }
  372.             thechan = (Chan *) NOTOK;
  373.             ap = ap_new (APV_DOMN, dmrt.dm_argv[dmrt.dm_argc -1]);
  374.             if (route != (AP_ptr) 0)
  375.                 ap -> ap_ptrtype = APP_ETC;
  376.             ap -> ap_chain = route;
  377.             route = ap;
  378.             continue;
  379.             default:
  380.             strcpy (tstline,
  381.                 dmrt.dm_argv [dmrt.dm_argc - 1]);
  382.             if (dmrt.dm_argc > 1)
  383.                 strcpy(official, tstline);
  384.                 /* make sure official has full domain   */
  385.             goto storeit;
  386.         }
  387.     }
  388.         /*NOTREACHED*/
  389.     }
  390.  
  391. /*
  392.  *  validated non-reflexive address is enqueued
  393.  */
  394. storeit:
  395.  
  396.      if (domain == (AP_ptr) 0)
  397.      {
  398. #ifdef DEBUG
  399.      ll_log (logptr, LLOGFTR, "Adding local (2) component '%s'", official);
  400. #endif
  401.      domain = ap_new (APV_DOMN, official);
  402.      } else {
  403. #ifdef BOTHEND
  404.                 /* SEK - at this point we pay for not */
  405.                 /* ap_normalize earlier, and must clean up */
  406.                 /* set thechan to map any looped local refs */
  407.     if(ap_dmnormalize (domain,  thechan) == MAYBE){
  408.         retval = RP_NS;
  409.         goto bugout;
  410.     }
  411.  
  412.     for(ap = route ; ap != (AP_ptr)0 ; ap = ap->ap_chain){
  413.         switch(ap->ap_obtype){
  414.             case APV_DOMN:
  415.             if(ap_dmnormalize (ap, thechan) == MAYBE){
  416.                 retval = RP_NS;
  417.                 goto bugout;
  418.             }
  419.             case APV_DLIT:
  420.             case APV_CMNT:
  421.             continue;
  422.         }
  423.         break; /* no more route */
  424.     }
  425. #endif /* BOTHEND */
  426. #ifdef DEBUG
  427.     ll_log (logptr, LLOGFTR, "Adding route component 2 '%s'", official);
  428. #endif
  429.     ap = ap_new (APV_DOMN, official);
  430.     if (route != (AP_ptr) 0)
  431.         ap -> ap_ptrtype = APP_ETC;
  432.     ap -> ap_chain = route;
  433.     route = ap;
  434.      }
  435.     /* there should be some code in here to delete spurious extra components
  436.      * in the domain and the route, this can do nasty things on some sites
  437.      */
  438.  
  439.  
  440.     cp = ap_p2s ((AP_ptr) 0, (AP_ptr) 0, local, domain, route);
  441.     if(cp == (char *)MAYBE){
  442.     retval = RP_NS;
  443.     goto bugout;
  444.     }
  445.  
  446.     auth_uinit (cp);
  447.     nextchan = 2;
  448.     retval = RP_OK;
  449.  
  450.     while (mgt_aok (thechan, tstline, cp, "") == 0) {
  451.     if((thechan = ch_h2chan(tstline, nextchan++)) == (Chan *)NOTOK){
  452.         auth_bad();    /* build an error message */
  453.         retval = RP_NAUTH;
  454. #ifdef DEBUG
  455.         ll_log(logptr, LLOGFTR, "No authorized route");
  456. #endif
  457.         break;
  458.     }
  459.     else if(thechan == (Chan *)MAYBE){
  460.         retval = RP_NS;
  461.         break;
  462.     }
  463.     }
  464.  
  465.     if(rp_gval(retval) == RP_OK) {
  466.     free(cp);
  467.  
  468.     /* put the address into a form that can be used */
  469.     i = ap_outtype;                 /* save this setting */
  470.     ap_outtype = thechan -> ch_apout;
  471.     cp = ap_p2s ((AP_ptr) 0, (AP_ptr) 0, local, domain, route);
  472.     ap_outtype = i;
  473.     if(cp != (char *)MAYBE){
  474. #ifdef DEBUG
  475.         ll_log (logptr, LLOGFTR, "linking for chan '%s'",thechan -> ch_name);
  476. #endif
  477.         lnk_adinfo (thechan, tstline, cp);
  478.         adr_gotone = TRUE;
  479.         retval = RP_AOK;
  480.     }
  481.     else
  482.         retval = RP_NS;
  483.     }
  484.  
  485.     auth_uend ();
  486.  
  487. bugout:
  488.     if (domain != (AP_ptr) 0)
  489.     {
  490.     ap_sqdelete (domain, (AP_ptr) 0);
  491.     ap_free (domain);
  492.     }
  493.     if (route != (AP_ptr) 0)
  494.     {
  495.     ap_sqdelete (route, (AP_ptr) 0);
  496.     ap_free (route);
  497.     }
  498.     if (cp && cp != (char *)MAYBE)
  499.     free (cp);
  500.     return (retval);
  501. }
  502. /* */
  503.  
  504. adr_dsubmit(addr)
  505. char    *addr;
  506. {
  507.     Chan    *thechan;
  508.     extern  int mgt_nodelay;
  509.     char    *mgt_dstgen();
  510.     char    *xcp;
  511.  
  512.     if(mgt_nodelay == TRUE) /* can't use the delay channel */
  513.     return(RP_NS);
  514.  
  515.     if(addr == (char *)MAYBE)    /* is this check needed ?? */
  516.     return(RP_NS);
  517.  
  518.     if( (thechan = ch_nm2struct(mgt_dlname)) == (Chan *)NOTOK)
  519.     return(RP_NS);      /* delay channel does not exist */
  520.  
  521. #ifdef DEBUG
  522.     ll_log (logptr, LLOGFTR, "linking for chan '%s'",thechan -> ch_name);
  523. #endif
  524.  
  525.     lnk_adinfo (thechan, (xcp = mgt_dstgen()), addr);
  526.     free(xcp);
  527.     adr_gotone = TRUE;
  528.     return(RP_DOK);
  529. }
  530.  
  531. adr_local (local)                       /* process host-less reference */
  532.     char *local;
  533. {
  534.     Chan *thechan;
  535.     char    qualstr[LINESIZE],
  536.         tmpstr[LINESIZE];
  537.     char    old_gotone;           /* stacked value of adr_gotone        */
  538.     char    *cp;
  539.     int     retval, bypass = 0;
  540.  
  541.     strcpy (tmpstr, local);
  542.  
  543.     /*
  544.      *  Important Note:
  545.      *      The order of the following conditions determines
  546.      *      precedence for the separators @, ., %, and !.
  547.      *      This assumes standard (from K&R) evaluation.
  548.      *      If your compiler is non-standard, you're screwed.
  549.      */
  550.     if ( (cp = rindex (tmpstr, '@')) != 0
  551.       || (cp = rindex (tmpstr, '%')) != 0
  552.       || (cp = index (tmpstr, '!')) != 0
  553. #ifdef LEFTDOTS
  554.       || (cp = rindex (tmpstr, '.')) != 0
  555. #endif
  556.     )
  557.                 /* SEK handle quoted @, and quoted or   */
  558.                 /* unquoted . or %.  If JNT Mail, do not*/
  559.                 /* handle ".".  In this case this is    */
  560.                 /* only needed for quoted @ and %       */
  561.     {
  562.     AP_ptr  adrtree;
  563.     AP_ptr  loctree, domtree, routree;
  564.     int     rtnval;
  565.  
  566. #ifdef DEBUG
  567.     ll_log (logptr, LLOGFTR, "recursing on local part: '%s'", local);
  568. #endif
  569.     /*
  570.      *  We recurse after changing the % to an `@` after
  571.      *  running ap_normalize on the resultant string.
  572.      */
  573.     if (*cp != '!')
  574.         *cp = '@';
  575.     else
  576.     {
  577.         char   tbuf [LINESIZE];
  578.         *cp++ = '\0';
  579.         sprintf (tbuf, "%s@%s", cp, tmpstr);
  580.         strcpy (tmpstr, tbuf);
  581.     }
  582.     if ((adrtree = ap_s2tree (tmpstr)) != (AP_ptr) NOTOK) {
  583.         if(ap_normalize ((char *) 0, (char *) 0, adrtree, (Chan *) 0) ==
  584.                         (AP_ptr)MAYBE){
  585.         ap_sqdelete (adrtree, (AP_ptr) 0);
  586.         ap_free (adrtree);   /* delete full tree */
  587.         return(RP_NS);
  588.         }
  589.         ap_t2parts (adrtree, (AP_ptr *)0, (AP_ptr *)0,
  590.             &loctree, &domtree, &routree);
  591.         rtnval = adr_check( loctree, domtree, routree );  /* RECURSE */
  592.         ap_sqdelete (adrtree, (AP_ptr) 0);
  593.         ap_free (adrtree);   /* delete full tree */
  594.         return( rtnval );
  595.     }
  596.     }
  597.  
  598.     if (ch_dflnam[0] == '\0') /* no local delivery && no hostname   */
  599.     return (RP_BHST);     /*    => address not legal            */
  600.  
  601.     if ((thechan = ch_nm2struct (ch_dflnam)) == (Chan *) NOTOK)
  602.     {
  603.     ll_log (logptr, LLOGFTR, "default channel '%s' unknown",
  604.             ch_dflnam);
  605.     return (RP_BHST);
  606.     }
  607.     strcpy (tmpstr, local);
  608.                 /* local will be untouched version    */
  609.     qualstr[0] = '\0';
  610.     adr_gparm (tmpstr, qualstr);
  611.  
  612.     if (bypass = (local[0] == '~')) {    /* bypass alias search   */
  613.     strcpy (tmpstr, &tmpstr[1]);
  614.     strcpy (local, &local[1]);      /* need both if qualstr     */
  615.     }
  616.  
  617.     old_gotone = adr_gotone;
  618.     if ((retval = lc_search (tmpstr, qualstr, bypass)) != RP_NO)
  619.     {
  620. #ifdef DEBUG
  621.     ll_log (logptr, LLOGFTR, "alias = %s", local);
  622. #endif
  623.     if (adr_gotone)   /* in alias file & has valid addrs    */
  624.         return (RP_AOK);
  625.  
  626.     adr_gotone = old_gotone;
  627.     if (retval == RP_NAUTH) {
  628.         ll_log (logptr, LLOGTMP, "*** No authorized addrs: alias '%s'", tmpstr);
  629.         return (RP_NAUTH);
  630.     }
  631.     if (retval == RP_NS)
  632.         return (RP_NS);
  633.  
  634.     ll_log (logptr, LLOGTMP, "*** No valid addrs: alias '%s'", tmpstr);
  635.     return (RP_USER);
  636.     }
  637.     adr_gotone = old_gotone;
  638.  
  639.     if (lc_pwsrch (tmpstr))    /* not even a login name.  too bad  */
  640.     {
  641. #ifdef DEBUG
  642.     ll_log (logptr, LLOGFTR, "local addr='%s',parm='%s'",
  643.             tmpstr, qualstr);
  644. #endif
  645.     auth_uinit (tmpstr);
  646.     if (qualstr[0] == '\0' && mgt_aok (thechan, "", tmpstr, ""))
  647.     {                       /* try it without the argument      */
  648.         lnk_adinfo (thechan, "", tmpstr);
  649.                 /* acceptable -> insert into list   */
  650.                 /* source string NOT used           */
  651.         adr_gotone = TRUE;
  652.         auth_uend ();
  653.         return (RP_AOK);
  654.     }
  655.     else if (mgt_aok (thechan, "", tmpstr, qualstr))
  656.     {                       /* have to check the parm, too      */
  657.         lnk_adinfo (thechan, "", local);
  658.                 /* acceptable -> insert into list   */
  659.                 /* note that SOURCE string is used  */
  660.         adr_gotone = TRUE;
  661.         auth_uend ();
  662.         return (RP_AOK);
  663.     }
  664.     auth_bad ();
  665.     auth_uend ();
  666.     ll_log (logptr, LLOGFST, "Local address '%s' not authorized",
  667.             tmpstr);
  668.     return (RP_NAUTH);
  669.     }
  670.  
  671.     /*
  672.      *  Last chance:  See if we have a forwarding channel
  673.      */
  674.     if( (thechan = ch_nm2struct("badusers")) != (Chan *)NOTOK) {
  675.     if (!mgt_aok (thechan, "", local, ""))
  676.         return(RP_NO);
  677.  
  678. #ifdef DEBUG
  679.     ll_log (logptr, LLOGFTR, "linking for chan '%s'", thechan -> ch_name);
  680. #endif
  681.  
  682.     lnk_adinfo (thechan,
  683.         thechan->ch_host ? thechan->ch_host : "", local);
  684.     adr_gotone = TRUE;
  685.     return(RP_OK);
  686.     }
  687.  
  688.     ll_log (logptr, LLOGFST, "Unknown user '%s'", tmpstr);
  689.  
  690.     return (RP_USER);         /* bad ref        */
  691. }
  692. /* */
  693.  
  694. adr_gparm (buf, to)               /* get local-mailbox parameter        */
  695.     char   *buf;                  /* the buffer holding the text        */
  696.     char   *to;                   /* put parameter into here            */
  697. {
  698.     register char  *strptr;
  699.  
  700.     for (strptr = buf ;; strptr++)
  701.      switch (*strptr)
  702.      {
  703.         case '\0':
  704.         to[0] = '\0';
  705.         return (FALSE);
  706.  
  707.         case '/':
  708.         case '|':
  709.         case '=':
  710.         strcpy (to, strptr);
  711.         *strptr = '\0'; /* terminate the mailbox portion */
  712.         return (TRUE);
  713.      }
  714.  
  715.      /* NOTREACHED */
  716. }
  717.  
  718. /* *************  (lc_)  LOCAL NAME TABLE SEARCHING  **************** */
  719.  
  720. extern Alias *al_list;            /* list of the aliases tables */
  721.  
  722. LOCVAR
  723. struct lc_alstruct               /* previous aposinfo's are stored on  */
  724. {                                 /*    lc_alsrch's stack when         */
  725.                   /*    lc_alsrch needs to recurse     */
  726.     char   *abufpos;              /* current position in alias buf      */
  727.     char    aliasbuf[LINESIZE];   /* address-part of alias entry        */
  728. }                  *lc_cralias;
  729.  
  730. LOCFUN
  731. lc_afin ()                /* alst_proc input routine for file   */
  732. {                         /* parse already-read line            */
  733.     char    c;
  734.  
  735.     switch (c = *(lc_cralias->abufpos))
  736.     {
  737.     case 0377:
  738.     case 0:
  739.         return( 0 );
  740.  
  741.     case '\n':
  742.         c = ',';
  743.     }
  744.     lc_cralias->abufpos++;
  745.     return ( c );
  746. }
  747. /* */
  748. lc_search (mbox, qualstr, bypass)
  749. char    *mbox;
  750. char    *qualstr;
  751. int    bypass;
  752. {
  753.     register Alias *alp;
  754. #ifdef DOTFORWARD
  755.     Alias tal;
  756. #endif
  757.     struct lc_alstruct *oldalias, newalias;
  758.     char *oldspec;
  759.     int    oldinalias;
  760.     register int retval;
  761.     int badretval = RP_NO;
  762.     char *badlist = (char *) 0;
  763.     char tmpbuf[LINESIZE];
  764.  
  765. #ifdef DEBUG
  766.     ll_log (logptr, LLOGBTR, "lc_search(%s, %d)", mbox, bypass);
  767. #endif
  768.     if ((qualstr[0] != 0) && (qualstr[0] != '='))
  769.     return(RP_NO);  /* Skip the alias search for user/file, user|prog */
  770.  
  771.     if (adr_orgspec != NULL)        /* we have been here before ... */
  772.     if(lexequ(mbox, adr_orgspec))    /* this is getting boring ... */
  773.          return (RP_NO);        /* Pretend we didn't find the alias */
  774.  
  775.     /*
  776.      *  This could almost use the library routine aliasfetch() except
  777.      *  we need the al_flags information down below (AL_TRUSTED?).
  778.      */
  779.     newalias.abufpos = newalias.aliasbuf;
  780.     for (alp = al_list; alp != (Alias *)0; alp = alp->al_next) {
  781.     if (bypass && !(alp->al_flags & AL_NOBYPASS))
  782.         continue;
  783.     if ((retval = tb_k2val (alp->al_table, TRUE, mbox,
  784.                 newalias.abufpos)) == OK)
  785.         break;
  786.     if (retval == MAYBE)
  787.         badretval = RP_NS;    /* NS timeout? */
  788.     }
  789. #ifdef DOTFORWARD
  790.     if (alp == (Alias *)0) {
  791.     if (lc_forward(mbox, newalias.abufpos, bypass, &tal) != OK)
  792.         return (badretval);
  793.     alp = &tal;
  794.     alp->al_flags = AL_TRUSTED;
  795.     }
  796. #else
  797.     if (alp == (Alias *)0)
  798.     return (badretval);
  799. #endif
  800.  
  801.     strcpy (tmpbuf, mbox);
  802.     strcat (tmpbuf, qualstr);
  803.  
  804.     if (lnk_adinfo ((Chan *) 0, "", tmpbuf) == OK) {
  805.     adr_gotone = TRUE;
  806.     return (RP_AOK);       /* already did this alias              */
  807.     }
  808.  
  809. #ifdef DEBUG
  810.     ll_log(logptr, LLOGFTR, "lc_search, newalias '%s'", newalias.abufpos);
  811. #endif
  812.     if (tracing)
  813.     printf("alias: %s => %s\n", mbox, newalias.abufpos);
  814.     if (qualstr[0] != '\0')
  815.     {
  816.     char *p;
  817.                 /* Found alias for username.  If username   */
  818.                 /* was part of "user=foo", check that alias */
  819.                 /* was just a simple username (otherwise    */
  820.                 /* alias=foo will make no sense).           */
  821.     if ((index (newalias.aliasbuf, '|') != 0) ||
  822.         (index (newalias.aliasbuf, '/') != 0) ||
  823.         (index (newalias.aliasbuf, ',') != 0)) {
  824.         ll_log (logptr, LLOGTMP, "Illegal to use = in alias '%s:%s'",
  825.             mbox,  newalias.aliasbuf);
  826.         return (RP_NO);
  827.     }
  828.     if ((p = rindex (newalias.aliasbuf, '@')) == 0)
  829.         strcat (newalias.aliasbuf, qualstr);
  830.     else {
  831.         *p++ = '\0';
  832.         sprintf (tmpbuf, "%s%s@%s", newalias.aliasbuf, qualstr, p);
  833.         strcpy (newalias.aliasbuf, tmpbuf);
  834.     }
  835.     }
  836.  
  837.     /* so save previous info on stack     */
  838.     oldspec = adr_orgspec;
  839.     oldalias = lc_cralias;
  840.     oldinalias = mgt_inalias;
  841.  
  842.     adr_orgspec = mbox;
  843.     lc_cralias = &newalias;  /*   to allow processing new list     */
  844.     mgt_inalias = (alp->al_flags & AL_TRUSTED ? TRUE : FALSE);
  845.  
  846.     adr_gotone = FALSE;
  847.     if (rp_isbad (retval=alst_proc(lc_afin, FALSE, (int (*)()) 0, &badlist))) {
  848.     char        linebuf[LINESIZE];
  849.  
  850.     ll_log (logptr, LLOGTMP, "Bad address in alias %s", mbox);
  851.     if (tracing)
  852.         printf ("Bad address in alias %s\n", mbox);
  853.     sprintf (linebuf, "%s %s", locfullname, sitesignature);
  854.     ml_1adr (NO, NO, linebuf, "Bad address in alias", supportaddr);
  855.     sprintf (linebuf, "Found bad address in alias '%s'.\n", mbox);
  856.     ml_txt (linebuf);
  857.     if (retval == RP_NAUTH)
  858.         ml_txt ("    (Authorization problem with valid address)\n");
  859.     sprintf (linebuf, "The alias was '%s'.\n\n", newalias.aliasbuf);
  860.     ml_txt (linebuf);
  861.     if (badlist) {
  862.         sprintf (linebuf, "There were problems with:\n");
  863.         ml_txt (linebuf);
  864.         ml_txt (badlist);
  865.         free (badlist);
  866.         sprintf (linebuf, 
  867.     "\nThe remaining addresses in the alias were used for submission.\n\n");
  868.         ml_txt (linebuf);
  869.     }
  870.     if (ml_end(OK) != OK)
  871.         ll_log (logptr, LLOGFAT, "Can't send to supportaddr");
  872.     }
  873.     adr_orgspec = oldspec;
  874.     lc_cralias = oldalias;   /* pop previous info off stack        */
  875.     mgt_inalias = oldinalias;
  876.  
  877.     if ((retval == RP_NAUTH) || (retval == RP_NS))
  878.     return (retval);
  879.     return (RP_AOK);
  880. }
  881.  
  882. lc_pwsrch (name)                 /* search login names (password file) */
  883. char  *name;                      /* search key                         */
  884. {
  885.     extern struct passwd *getpwmid ();
  886.     char namebuf[LINESIZE];
  887.     register int ind;
  888.  
  889. #ifdef DEBUG
  890.     ll_log (logptr, LLOGBTR, "lc_pwsrch(%s)", name);
  891. #endif
  892.  
  893.  
  894.     if (getpwmid (name) != NULL)   /* case-independent name search       */
  895.     return (TRUE);            /*   found an entry                   */
  896.  
  897.     if ((ind = strindex ("|", name)) >= 0 ||
  898.     (ind = strindex ("/", name)) >= 0   )
  899.     {                             /* piped msg or stored into file      */
  900.     blt (name, namebuf, ind);
  901.     namebuf[ind] = '\0';
  902. #ifdef DEBUG
  903.     ll_log (logptr, LLOGBTR, "lc_pwsrch base part (%s)", namebuf);
  904. #endif
  905.     return ((getpwmid (namebuf) != NULL) ? TRUE : FALSE);
  906.     }
  907.  
  908.     return (FALSE);               /* return failure                     */
  909. }
  910.  
  911. #ifdef DOTFORWARD
  912. /*
  913.  * See if there's a ~user/.forward file.  If not, return NOTOK.  If so
  914.  * pass that back to our caller in "buf".
  915.  *
  916.  * SECURITY CHECK:  stat() the file and check that it's owned by
  917.  * the user --OR-- owned by one of MMDF's priveledged user-id's.
  918.  * This is a little more lenient than SendMail which only checks
  919.  * the ownership & readability.  But I can see where it might be
  920.  * useful for an administrator to install an alias the luser can't
  921.  * get rid of ...
  922.  *
  923.  * (Our readability check is in the fopen())
  924.  *
  925.  *    -- DSH (suggested by Marc Rouleau <mer6g@virginia.acc.virginia.edu>)
  926.  */
  927. lc_forward(mbox, buf, bypass)
  928.     char *mbox, *buf;
  929.     int bypass;
  930. {
  931.     extern struct passwd *getpwmid();
  932.     struct passwd *pw;
  933.     extern int effecid;
  934.     char dotforward[LINESIZE];
  935.     FILE *fd;
  936.     struct stat sbuf;
  937.  
  938.     if (bypass)
  939.     return (NOTOK);
  940.     if ((pw = getpwmid(mbox)) == NULL)
  941.     return (NOTOK);
  942.     sprintf (dotforward, "%s/.forward", pw->pw_dir);
  943.  
  944.     if (stat(dotforward, &sbuf) == -1)
  945.     return(NOTOK);
  946.     if (pw->pw_uid != sbuf.st_uid && !PRIV_USER(sbuf.st_uid)) {
  947.     ll_log (logptr, LLOGFAT,
  948.         "lc_forward forward file (%s) exists but owned by %d, not %d",
  949.         dotforward, sbuf.st_uid, pw->pw_uid);
  950.     return(NOTOK);
  951.     }
  952.     
  953.     if ((fd = fopen(dotforward, "r")) == NULL)
  954.     return (NOTOK);
  955.     *buf='\0';
  956.     fgets(buf, LINESIZE, fd);
  957.     fclose(fd);
  958.     return(OK);
  959. }
  960. #endif
  961.