/*--------------------------------------------------------------------*/ /* a d d r e s s . c */ /* */ /* Address parsing routines for UUPC/extended */ /*--------------------------------------------------------------------*/ #include #include #include #include #include #include "lib.h" #include "hlib.h" #include "address.h" #include "hostable.h" #include "security.h" /*--------------------------------------------------------------------*/ /* Global variables */ /*--------------------------------------------------------------------*/ currentfile(); /*--------------------------------------------------------------------*/ /* Local function prototypes */ /*--------------------------------------------------------------------*/ static char *rfc_route( char *tptr, char **nptr, char **pptr ); /*--------------------------------------------------------------------*/ /* u s e r _ a t _ n o d e */ /* */ /* break a UUCP path or RFC-822 address into the basic user and */ /* node components */ /* */ /* Note: This routine assume an address of the form */ /* path!node1!user@node2 is for a user@node1 routed via */ /* node2 and then path. */ /*--------------------------------------------------------------------*/ void user_at_node(const char *raddress, char *hispath, char *hisnode, char *hisuser) { static char *saveaddr = NULL; static char *savepath; static char *savenode; static char *saveuser; char *uptr; /* Pointer to his user id */ char *nptr; /* Pointer to his node id */ char *pptr; /* Pointer to next node in path to him */ char *tptr; /* Temporary token pointer */ char *wptr; /* Work pointer (not used between steps */ char *address; struct HostTable *Hptr = NULL; /* Pointer to host name table */ if ( strlen( raddress ) >= MAXADDR ) { printmsg(0,"Unable to process %d length address: %s", strlen(raddress) , raddress ); panic(); } /*--------------------------------------------------------------------*/ /* Determine if local address */ /*--------------------------------------------------------------------*/ if (!strpbrk(raddress,"!@")) /* Any host delimiters? */ { /* No --> report local data */ strcpy(hisuser,raddress); strcpy(hisnode,E_nodename); strcpy(hispath,E_nodename); strcpy(hisuser,raddress); printmsg(5,"user_at_node: Address '%s' is local",raddress); return; } /*--------------------------------------------------------------------*/ /* If the current address is the same as the last processed remote */ /* address, then return the same information as what we determined */ /* last time. */ /*--------------------------------------------------------------------*/ if ((saveaddr != NULL) && equal(raddress,saveaddr)) { strcpy(hispath,savepath); strcpy(hisnode,savenode); strcpy(hisuser,saveuser); return; } /*--------------------------------------------------------------------*/ /* The address is different; save the new address and then proceed */ /* to parse it. */ /*--------------------------------------------------------------------*/ address = strdup(raddress); /* Copy address for parsing */ checkref(address); /* Verify allocation worked */ if (saveaddr != NULL) /* Was the data previously allocated? */ { /* Yes --> Free it */ free(saveaddr); } saveaddr = strdup(address); /* Remember address for next pass */ nptr = nil(char); /* No known node for user */ pptr = E_mailserv; /* Default routing via mail server */ tptr = address; /* Remember start of address */ /*--------------------------------------------------------------------*/ /* The address may be RFC-822 syntax; attempt to parse that format */ /*--------------------------------------------------------------------*/ uptr = tptr = rfc_route( tptr, &nptr, &pptr ); /*--------------------------------------------------------------------*/ /* If the user had an RFC-822 path, then the pointer to the path is */ /* now initialized, and the remainder of the path has been dropped */ /* from *tptr; otherwise, the entire address is found via *tptr */ /*--------------------------------------------------------------------*/ wptr = strrchr(tptr,'@'); /* Get last at sign, since it's right to left scan (more or less) */ /*--------------------------------------------------------------------*/ /* Translation of following: If the at-sign (@) is not the */ /* first character and the character preceding the at-sign is */ /* not a bang (!), then break the address down into user and */ /* node. */ /*--------------------------------------------------------------------*/ if (( wptr > tptr ) && ( strchr("!:",*(wptr-1)) == NULL)) { uptr = tptr; /* Get user part of userid @node */ *wptr++ = '\0'; /* Terminate user portion */ tptr = wptr; /* Get node part of userid @node */ } if (tptr != NULL) /* Did we get a node? */ { /* Yes --> Save it */ nptr = tptr; pptr = HostPath( nptr, pptr); } /* if */ /*--------------------------------------------------------------------*/ /* Now, we will try stripping off any uucp path that the address */ /* may have acquired; we'll assume the last node is the addressee's */ /* node. */ /*--------------------------------------------------------------------*/ uptr = strtok(uptr,"!"); tptr = strtok(NULL,""); while ( tptr != NULL ) { nptr = uptr; /* First token is node */ if (*tptr == '@') /* Explicit RFC-822 route? */ { /* Yes --> Examine in detail */ uptr = strtok( rfc_route( tptr, &nptr, &pptr ), "!"); /* Second token, or what's left of it, is user id */ tptr = strtok(NULL,""); /* Save rest of string */ } /* if (*tptr == '@') */ else { uptr = strtok(tptr,"!"); /* Second token is user id */ tptr = strtok(NULL,""); /* Save rest of string */ pptr = HostPath( nptr, pptr); } /* else */ } /* while */ /*--------------------------------------------------------------------*/ /* Finally, we parse off any internet mail that used the infamous % */ /* hack (user%node1@gatewayb) */ /*--------------------------------------------------------------------*/ while ((tptr = strrchr(uptr,'%')) != NULL) /* Get last percent */ { *tptr = '@'; /* Make it an RFC-822 address */ uptr = strtok(uptr,"@"); /* Get user part of userid @node */ nptr = strtok(NULL,"@"); /* Get node part of userid @node */ pptr = HostPath(nptr, pptr); /* Old node is new path */ } /* while */ /*--------------------------------------------------------------------*/ /* If the last known hop in the path is via our own system, but the */ /* target node is not our own system, route the message via our */ /* default mail server. */ /*--------------------------------------------------------------------*/ nptr = HostAlias( nptr ); if (equali(pptr,E_nodename)) /* Is mail routed via our local system? */ { /* Yes --> Determine if destined for us */ Hptr = checkname(nptr); /* Locate the system */ if (Hptr == BADHOST) /* System known? */ { /* No --> Route default */ printmsg(5, "user_at_node: Routing mail for \"%s\" via default mail server", nptr); pptr = E_mailserv; } /* if */ else nptr = E_nodename; /* Must be local delivery */ } /* if */ /*--------------------------------------------------------------------*/ /* Print our results */ /*--------------------------------------------------------------------*/ printmsg(9, "user_at_node: Address \"%s\" is \"%s\" at \"%s\" via \"%s\"", raddress, uptr, nptr, pptr); /*--------------------------------------------------------------------*/ /* We have parsed the address. Fill in the information for caller */ /*--------------------------------------------------------------------*/ strcpy(hispath,pptr); strcpy(hisnode,nptr); strcpy(hisuser,uptr); /*--------------------------------------------------------------------*/ /* Save the parsed information along with the original address we */ /* were passed in. This could save breaking it down again. */ /*--------------------------------------------------------------------*/ savepath = newstr(hispath); savenode = newstr(hisnode); saveuser = newstr(hisuser); free(address); } /* user_at_node */ /*--------------------------------------------------------------------*/ /* r f c _ r o u t e */ /* */ /* Strip off explicit RFC-822 routing from an address */ /*--------------------------------------------------------------------*/ static char *rfc_route( char *tptr, char **nptr, char **pptr ) { /*--------------------------------------------------------------------*/ /* Loop as long as we have an explicit RFC-822 path */ /*--------------------------------------------------------------------*/ while (*tptr == '@') /* Explicit RFC 822 path? */ { *nptr = strtok(++tptr,",:"); /* First token is path/node */ tptr = strtok(NULL,""); /* Second has rest, including user id */ *pptr = HostPath( *nptr , *pptr ); /* Determine actual path */ printmsg(9,"rfc_route: RFC-822 explicit path: " "\"%s\" routed via \"%s\" is via \"%s\"", tptr, *nptr, *pptr); } /* while */ /*--------------------------------------------------------------------*/ /* At this point, *nptr is last node in list, *pptr is path to */ /* *nptr, and *tptr is the rest of the string (userid?) */ /*--------------------------------------------------------------------*/ return tptr; } /* rfc_route */ /*--------------------------------------------------------------------*/ /* H o s t A l i a s */ /* */ /* Resolve a host alias to its real canonized name */ /*--------------------------------------------------------------------*/ char *HostAlias( char *input) { struct HostTable *hostp; hostp = checkname(input); /*--------------------------------------------------------------------*/ /* If nothing else to look at, return original data to caller */ /*--------------------------------------------------------------------*/ if (hostp == BADHOST) return input; if ( hostp->hostname[0] == '*') /* Ignore wildcards */ return input; /*--------------------------------------------------------------------*/ /* If we already chased this chain, return result to caller */ /*--------------------------------------------------------------------*/ if (hostp->aliased) { if ( hostp->realname == NULL ) { printmsg(0,"Alias table loop detected with host %s", hostp->hostname); } return hostp->realname; } /* if */ hostp->aliased = TRUE; /* Prevent limitless recursion */ /*--------------------------------------------------------------------*/ /* Determine next host in the chain */ /*--------------------------------------------------------------------*/ if ( hostp->realname == NULL) /* End of the line? */ hostp->realname = hostp->hostname; else hostp->realname = HostAlias(hostp->realname); /*--------------------------------------------------------------------*/ /* Announce our results */ /*--------------------------------------------------------------------*/ printmsg( 5 , "HostAlias: \"%s\" is alias of \"%s\"",input,hostp->realname); return hostp->realname; } /* HostAlias */ /*--------------------------------------------------------------------*/ /* H o s t P a t h */ /* */ /* Determine the path to a host */ /*--------------------------------------------------------------------*/ char *HostPath( char *input, char *best) { struct HostTable *hostp; hostp = checkname( input ); /*--------------------------------------------------------------------*/ /* If nothing else to look at, return original data to caller */ /*--------------------------------------------------------------------*/ if (hostp == BADHOST) return best; if (hostp->hstatus == gatewayed) /* Gatewayed? */ return hostp->hostname; /* Yes --> Use name for path */ /*--------------------------------------------------------------------*/ /* If we already chased this chain, return result to caller */ /*--------------------------------------------------------------------*/ if (hostp->routed) { if ( hostp->via == NULL ) { printmsg(0,"Routing table loop discovered at host %s", hostp->hostname); panic(); } return hostp->via; } hostp->routed = TRUE; /* Prevent limitless recursion */ /*--------------------------------------------------------------------*/ /* Determine next host in the chain */ /*--------------------------------------------------------------------*/ if ( hostp->via == NULL ) { char *alias = HostAlias( hostp->hostname ); if (equal(hostp->hostname,alias)) { if (hostp->hstatus == localhost) /* Ourself? */ hostp->via = E_nodename; /* Yes --> Deliver local */ else if ( checkreal( hostp->hostname ) == BADHOST ) /* Unknown system? */ hostp->via = best; /* Yes --> Use default */ else hostp->via = hostp->hostname; /* Known --> route to it */ } /* if ( hostp->via == NULL ) */ else hostp->via = HostPath( alias, best); } /* if ( hostp->via == NULL ) */ hostp->via = HostPath( hostp->hostname, hostp->via ); printmsg( 5 ,"HostPath: \"%s\" routed via \"%s\"", input, hostp->via); return hostp->via; } /* HostPath */ /*--------------------------------------------------------------------*/ /* E x t r a c t A d d r e s s */ /* */ /* Returns the user name (if available and requested or */ /* E-mail address of the user */ /* */ /* Written by ahd 15 July 1989 */ /*--------------------------------------------------------------------*/ char *ExtractAddress(char *result, const char *input , FULLNAME fullname) { char *nonblank = NULL; char *column = (char *) input; char name[BUFSIZ]; /* User full name */ char *nameptr = name; char addr[BUFSIZ]; /* User e-mail address */ char *addrptr = addr; char state = 'A'; /* State = skip whitespace */ char newstate = 'A'; /* Next state to process */ int bananas = 0; /* No () being processed now */ int len; boolean quoted = FALSE; /*--------------------------------------------------------------------*/ /* Begin loop to copy the input field into the address and or the */ /* user name. We will begin by copying both (ignoring whitespace */ /* for addresses) because we won't know if the input field is an */ /* address or a name until we hit either a special character of */ /* some sort. */ /*--------------------------------------------------------------------*/ while ((*column != '\0') && (state != ',')) { switch (state) { case 'A': if (isspace(*column)) /* Found first non-blank? */ break; /* No --> keep looking */ nonblank = column; state = 'B'; /* ... and fall through */ case 'B': case ')': newstate = *column; switch(*column) { case '(': bananas++; break; case '"': break; case '<': addrptr = addr; /* Start address over */ nameptr = name; /* Start name over again */ column = nonblank - 1; /* Re-scan in new state */ newstate = '>'; /* Proc all-non <> as name */ break; /* Begin addr over again */ case ',': break; /* Terminates address */ case '>': case ')': printmsg(0,"Invalid RFC-822 address: %s",nonblank); panic(); /* Ooops, funky address */ break; default: newstate = state; /* stay in this state */ if (!isspace(*column)) *(addrptr++) = *column; } /* switch(*column) */ break; case '<': if (*column == '>') newstate = '>'; else if (!isspace(*column)) *(addrptr++) = *column; break; case '>': if (*column == '<') newstate = '<'; else switch( *column ) { case ')': if (quoted) *(nameptr++) = *column; else bananas--; break; case '(': if (quoted) *(nameptr++) = *column; else bananas++; break; case '"': if (bananas == 0) { quoted = !quoted; break; } /* else fall through */ default: *(nameptr++) = *column; } /* switch */ break; case '(': if (*column == '(') ++bananas; else if (*column == ')') { if (--bananas == 0) { newstate = ')'; break; } } else *(nameptr++) = *column; break; case '"': if (*column == '"') newstate = ')'; else *(nameptr++) = *column; break; default: panic(); /* Logic error, bad state */ break; } /* switch (state) */ state = newstate; column++; } /* while */ /*--------------------------------------------------------------------*/ /* Verify we retrieved an address */ /*--------------------------------------------------------------------*/ if (state == 'A') { printmsg(0, "ExtractAddress: Could not find address in \"%s\"", column); panic(); } /*--------------------------------------------------------------------*/ /* Fill in the results for the caller */ /*--------------------------------------------------------------------*/ *addrptr = '\0'; *nameptr = '\0'; *result = '\0'; len = strlen( addr ); if ((fullname == ADDRESSONLY) || ((fullname == FULLADDRESS) && (state == 'B'))) { if ( len >= MAXADDR ) { printmsg(0,"ExtractAddress: Address exceeds %d characters: %s", MAXADDR, addr ); panic(); } strcpy(result,addr); /* Return the full address */ } else if (state != 'B') { while (--nameptr >= name) { if (isspace(*nameptr)) *nameptr = '\0'; else break; } /*--------------------------------------------------------------------*/ /* Strip leading blanks from the address */ /*--------------------------------------------------------------------*/ nameptr = name; while (isspace(*nameptr)) nameptr++; if ( strlen( nameptr ) >= MAXADDR ) { printmsg(0,"ExtractAddress: Truncating name %s" , nameptr); nameptr[ MAXADDR - 1 ] = '\0'; } if ( fullname == FULLADDRESS ) { if ( len >= (MAXADDR-6) ) { printmsg(0,"ExtractAddress: Address exceeds %d characters: %s", MAXADDR-6, addr ); panic(); } nameptr[ MAXADDR - len - 6] = '\0'; sprintf( result , "\"%s\" <%s>", nameptr, addr ); } else strncpy(result,nameptr, MAXADDR); } /* else */ printmsg(4,"ExtractAddress: %s into <%s> \"%s\"", nonblank,addr,(fullname) ? result : name); /*--------------------------------------------------------------------*/ /* Return the position of the next address, if any, to the caller */ /*--------------------------------------------------------------------*/ if ( *column == '\0') return NULL; else return column + 1; } /*ExtractAddress*/