1: #define MFDEBUG /* temporarily */ 2: 3: #include "util.h" 4: #include "mmdf.h" 5: #include <pwd.h> 6: #include <signal.h> 7: #include "mf.h" 8: #include "tws.h" 9: 10: /* 11: * R M A I L . C 12: * 13: * Developed from the Berkeley mail program of the same name 14: * by Mike Obrien at RAND to run with the MMDF mail system. 15: * Rewritten by Doug Kingston, US Army Ballistics Research Laboratory 16: * Hacked a lot by Steve Bellovin (smb@unc) 17: * 18: * This program runs SETUID to root so that it can set effective and 19: * real [ug]ids to mmdflogin. 20: * 21: * 27-Oct-82 Marshall T. Rose <mrose%uci@rand-relay> 22: * Support proper munging by using the UCI mail filtering 23: * routines (enabled by #ifdef MF) 24: * Also use ll_log() package (enabled by #ifdef LOG) 25: * 26: * 17-Oct-83 Marshall T. Rose <mrose%uci@rand-relay> 27: * New interfacing. Remove the #ifdef:s 28: */ 29: 30: 31: #define NAMESZ 64 /* Limit on component name size */ 32: 33: #define ADDROK 0 34: #define UUCP 1 35: #define RETURN 2 36: 37: int Syscpy = 1; 38: int Tmpmode = 0600; 39: char *Fromtmp = "/tmp/rml.f.XXXXXX"; 40: char *Msgtmp = "/tmp/rml.m.XXXXXX"; 41: char *Errtmp = "/tmp/rml.e.XXXXXX"; 42: char *Okhosts = "/usr/mmdf/table/rmail.ok"; 43: char *Okdests = "/usr/mmdf/table/rmail.okdests"; 44: 45: extern char cmddfldir[]; 46: extern char logdfldir[]; 47: extern char mmdflogin[]; 48: extern char pathsubmit[]; 49: extern char sitesignature[]; 50: extern char supportaddr[]; 51: extern struct ll_struct chanlog; 52: 53: char *dupfpath (), *index(), *rindex(); 54: struct passwd *getpwnam(), *getpwuid(); 55: FILE *popen(); 56: 57: /* */ 58: 59: struct ll_struct *logptr = &chanlog; 60: 61: FILE *fromf; /* temporary out for colon-less UUCP "From" lines */ 62: FILE *msgf; /* temporary out for message text */ 63: FILE *mmdf; /* filtered mail file */ 64: FILE *pipef; /* output to "submit" or "uux" */ 65: char date[LINESIZE]; /* date of origination from uucp header */ 66: char from[LINESIZE]; /* accumulated path of sender */ 67: char origsys[NAMESZ]; /* originating system */ 68: char origpath[LINESIZE];/* path from us to originating system */ 69: char usrfrm[LINESIZE]; 70: char Mailsys[LINESIZE]; 71: int pbroke; /* broken-pipe flag */ 72: int rtnflag; /* note was sent back */ 73: 74: int brpipe(); 75: 76: /* */ 77: 78: main(argc, argv) 79: char **argv; 80: { 81: char fromwhom[NAMESZ]; /* user on remote system */ 82: char *fromptr; 83: char linebuf[LINESIZE]; /* scratchpad */ 84: char sys[NAMESZ]; /* an element in the uucp path */ 85: char *cp; 86: struct passwd *pw; 87: int error; 88: int cpyback; 89: 90: if (argc < 2) { 91: fprintf(stderr, "Usage: rmail user [user ...]\n"); 92: exit(1); 93: } 94: umask (0); 95: 96: ll_hdinit (logptr, "RM"); 97: logptr -> ll_file = dupfpath (logptr -> ll_file, logdfldir); 98: 99: if ((pw = getpwnam (mmdflogin)) == NULL) { 100: fprintf (stderr, "Cannot find mmdflogin\n"); 101: exit (99); 102: } 103: setgid (pw->pw_gid); 104: setuid (pw->pw_uid); 105: 106: sprintf (Mailsys, "%s <%s@%s>", 107: sitesignature, mmdflogin, LocalName ()); 108: 109: /* */ 110: 111: { /* BE VERY SURE... */ 112: int i; 113: 114: for (i = fileno (stdout); i <= HIGHFD; i++) 115: close (i); 116: } 117: 118: /* create file to hold stderr output. We first open some */ 119: /* null file to make sure stdout is taken. If stdin isn't */ 120: /* open either, we've got so much trouble it isn't even worth */ 121: /* worrying about a little more */ 122: open("/dev/null", 0); 123: mktemp(Errtmp); 124: if (freopen(Errtmp, "w", stderr) == NULL) { 125: fprintf(stderr, "Can't create %s\n", Errtmp); 126: ll_log (logptr, LLOGFAT, "Unable to create '%s'", 127: Errtmp); 128: exit(1); 129: } 130: dup2 (fileno (stderr), fileno (stdout)); 131: 132: /* Create temp file for rest of message */ 133: mktemp (Msgtmp); 134: if ((msgf=fdopen(creat(Msgtmp, Tmpmode), "w")) == NULL) { 135: fprintf(stderr, "Can't create %s\n", Msgtmp); 136: ll_log (logptr, LLOGFAT, "Unable to create '%s'", 137: Msgtmp); 138: exit(1); 139: } 140: 141: /* create temp file for colon-less UUCP "From" lines */ 142: mktemp (Fromtmp); 143: if ((fromf=fdopen(creat(Fromtmp, Tmpmode), "w")) == NULL) { 144: fprintf(stderr, "Can't create %s\n", Fromtmp); 145: ll_log (logptr, LLOGFAT, "Unable to create '%s'", 146: Fromtmp); 147: exit(1); 148: } 149: 150: /* */ 151: 152: for (;;) { 153: if( fgets(linebuf, sizeof linebuf, stdin) == NULL ) 154: break; 155: if( strncmp(linebuf, "From ", 5) 156: && strncmp(linebuf, ">From ", 6) ) 157: break; 158: 159: if (linebuf[0] != '>') 160: fputs (">", fromf); 161: fputs(linebuf, fromf); /* Save, we may forward via UUCP */ 162: cp = index (linebuf, ' '); /* start of name */ 163: fromptr = ++cp; 164: cp = index (cp, ' '); /* cp at end of name */ 165: *cp++ = 0; /* term. name, cp at date */ 166: strcpy (fromwhom, fromptr); 167: strncpy (date, cp, 24); /* Mon Nov 10 23:12:09 1981 */ 168: 169: for (;;) { 170: cp = index(cp+1, 'r'); 171: if (cp == NULL) { 172: cp = rindex(fromwhom, '!'); 173: if (cp != NULL) { 174: char *p; 175: *cp = '\0'; 176: p = rindex(fromwhom, '!'); 177: if (p != NULL) strcpy(origsys, p+1); 178: else strcpy(origsys, fromwhom); 179: strcat(from, fromwhom); 180: strcat(from, "!"); 181: strcpy(fromwhom, cp+1); 182: goto out; 183: } 184: strcpy (sys, SystemName ()); 185: strcat (from, sys); 186: strcpy (origsys, sys); 187: strcat (from, "!"); 188: goto out; 189: } 190: if (strncmp(cp, "remote from ", 12) == 0) 191: break; 192: } 193: 194: sscanf(cp, "remote from %s", sys); 195: strcat(from, sys); 196: strcpy(origsys, sys); /* Save for quick ref. */ 197: strcat(from, "!"); 198: out:; 199: } 200: if( fromwhom[0] == '\0' ) /* No from line, illegal */ 201: exit(99); 202: 203: /* */ 204: 205: strcpy (origpath, from); 206: strcat (from, fromwhom); 207: mf_get_addr (from, usrfrm); 208: if ((cp = rindex (usrfrm, '<')) != NULL) { 209: strcpy (usrfrm, ++cp);/* sigh */ 210: if ((cp = rindex (usrfrm, '>')) != NULL) 211: *cp = NULL; 212: } 213: if (usrfrm[0] == NULL) 214: sprintf (usrfrm, "%s!%s%%%s@%s", 215: SystemName (), from, UucpChan (), LocalName ()); 216: ll_log (logptr, LLOGGEN, "Rmail from '%s' (%s)", from, usrfrm); 217: fputs (linebuf, msgf); 218: if (rp_isbad (txtcpy (stdin, msgf))) 219: fputs ("\n *** Problem during receipt from UUCP ***\n", msgf); 220: 221: freopen (Msgtmp, "r", msgf); 222: freopen (Fromtmp, "r", fromf); 223: unlink (Msgtmp); 224: unlink (Fromtmp); 225: mmdf = NULL; 226: 227: cpyback = 0; 228: for (argv++; --argc > 0; ) { 229: rewind (fromf); 230: rewind (msgf); 231: if (mmdf != NULL) 232: rewind (mmdf); 233: pbroke = 0; 234: rtnflag = 0; 235: signal(SIGPIPE, brpipe); 236: if (rp_isbad(deliver(*argv++)) && !rtnflag) 237: cpyback++; 238: } 239: 240: /* Send back a copy if something nasty happened. For now, we use */ 241: /* a real kludge -- we see if we noted some error, or if we find */ 242: /* anything written to stderr.... */ 243: fflush(stderr); 244: fflush (stdout); 245: 246: if (cpyback) {rcpy();zcpy();} 247: 248: unlink(Errtmp); 249: ll_close (logptr); 250: exit (0); 251: } 252: 253: /* */ 254: 255: /* 256: * deliver() -- Handle all deliveries be they returns, automatic 257: * copies, or the real thing. Based on the address 258: * the letter is accepted or returned with a copy 259: * to the system administrators 260: * 261: * main() has set up the "from" string and the 262: * "date" string. 263: */ 264: char rtnend[] = 265: " --------------- End of Returned Mail ---------------\n"; 266: 267: deliver(to) 268: char *to; 269: { 270: int replyval; 271: int i; 272: char linebuf[LINESIZE]; 273: char tmpbuf[LINESIZE]; 274: 275: switch (adrcheck (to)) { 276: case ADDROK: 277: ll_log (logptr, LLOGGEN, "Rmail to '%s' via MMDF", to); 278: if (rp_isbad (replyval = 279: xsubmit (NULL, usrfrm, NULL, NULL, to))) 280: break; 281: if (mmdf == NULL) 282: if (mf_get_msg () == NOTOK) 283: mmdf = msgf; 284: replyval = txtcpy (mmdf, pipef); 285: #ifndef RUNALON 286: i = (pclose(pipef) >> 8 ) & 0xff; 287: if (rp_isgood(replyval)) replyval = i; 288: #endif 289: break; 290: 291: case UUCP: 292: ll_log (logptr, LLOGGEN, "Rmail to '%s' via UUCP", to); 293: if (rp_isbad (replyval = xuucp(from, to))) 294: break; 295: replyval = txtcpy(msgf, pipef); 296: #ifndef RUNALON 297: i = (pclose(pipef) >> 8 ) & 0xff; 298: if (rp_isgood(replyval)) replyval = (i == 0 ? RP_OK : RP_LIO); 299: #endif 300: break; 301: 302: /* */ 303: 304: case RETURN: 305: rtnflag = 1; 306: ll_log (logptr, LLOGGEN, "Illegal Rmail to '%s'", to); 307: switch (adrcheck (from)) { 308: case ADDROK: 309: case RETURN: 310: replyval = xsubmit (dtimenow (), Mailsys, 311: from, supportaddr, from); 312: rtnmesg(to); 313: txtcpy(fromf, pipef); 314: txtcpy(msgf, pipef); 315: fputs (rtnend, pipef); 316: #ifndef RUNALON 317: i = (pclose(pipef) >> 8 ) & 0xff; 318: if (rp_isgood(replyval)) replyval = i; 319: #endif 320: break; 321: 322: case UUCP: 323: replyval = xuucp (mmdflogin, from); 324: if (rp_isbad (replyval)) 325: break; 326: fprintf (pipef, "To: %s\n", from); 327: fprintf (pipef, "Cc: %s\n", supportaddr); 328: rtnmesg(to); 329: txtcpy(fromf, pipef); 330: txtcpy(msgf, pipef); 331: fputs (rtnend, pipef); 332: #ifndef RUNALON 333: i = (pclose(pipef) >> 8 ) & 0xff; 334: if (rp_isgood(replyval)) 335: replyval = (i == 0 ? RP_OK : RP_LIO); 336: #endif 337: break; 338: } 339: 340: /* And now for the mail overseer's copy */ 341: if (Syscpy) { 342: ll_log (logptr, LLOGGEN, "Notifying %s", supportaddr); 343: rewind (fromf); 344: rewind (msgf); 345: 346: replyval = xsubmit (dtimenow (), Mailsys, 347: usrfrm, supportaddr, supportaddr); 348: if (rp_isbad (replyval)) 349: break; 350: rtnmesg(to); 351: txtcpy (fromf, pipef); 352: txtcpy (msgf, pipef); 353: fputs (rtnend, pipef); 354: #ifndef RUNALON 355: i = (pclose(pipef) >> 8 ) & 0xff; 356: if (rp_isgood(replyval)) replyval = i; 357: #endif 358: } 359: } 360: return (replyval); 361: } 362: 363: /* */ 364: 365: adrcheck (adr) /* Gateway to Arpanet? */ 366: char *adr; 367: { 368: char *cp, 369: err[BUFSIZ], 370: host[BUFSIZ], 371: mbox[BUFSIZ]; 372: struct adrx *adrxp; 373: 374: if ((adrxp = seekadrx (adr)) == NULL) 375: return RETURN; 376: strcpy (err, adrxp -> err ? adrxp -> err : ""); 377: strcpy (host, adrxp -> host ? adrxp -> host : ""); 378: strcpy (mbox, adrxp -> mbox ? adrxp -> mbox : ""); 379: while (seekadrx (NULL)) 380: continue; 381: 382: if (err[0] || mbox[0] == NULL) 383: return RETURN; 384: if (index (mbox, '!') || host[0] == NULL) 385: return UUCP; 386: if (rp_isgood (lookup (origsys, Okhosts))) 387: return ADDROK; 388: if (index (host, '@') || rp_isbad (okhost (host))) 389: return RETURN; 390: 391: return ADDROK; 392: } 393: 394: 395: okhost(host) /* Host permitted to use mail facilities? */ 396: char *host; 397: { 398: if (rp_isgood (lookup (origsys, Okhosts))) 399: return (RP_OK); /* Fully privledged originator */ 400: if (rp_isgood (lookup (host, Okhosts))) 401: return (RP_OK); /* Fully privledged dest */ 402: if (rp_isgood (lookup (host, Okdests))) 403: return (RP_OK); /* Unrestricted Dest. Host, OK */ 404: return(RP_NO); /* Not permitted; must be bad */ 405: } 406: 407: /* */ 408: 409: /* 410: * lookup() -- This lookup function looks for strings which 411: * must be the first string on a line. Sorry Dave (dhc) 412: * but the MMDF channel functions are too specific 413: * to be easily used here without much kludging. 414: */ 415: 416: /***************************************** 417: **** Can this be a call to a MMDF function?? 418: **** Remember I have the RHOSTs table and the OKHOSTS table. 419: ******************************************/ 420: 421: lookup (what, where) 422: char *what, *where; 423: { 424: FILE *lookf; 425: char entry[LINESIZE]; 426: char *cp; 427: 428: if ((lookf = fopen (where, "r")) == NULL) 429: return (RP_NO); /* Unknown problem */ 430: while (fgets (entry, sizeof entry, lookf) != NULL) { 431: cp = entry; 432: while (*cp != '\n' && *cp != ' ' && *cp != '\t') 433: cp++; 434: *cp = 0; 435: if (lexequ (what, entry)) { 436: fclose (lookf); 437: return (RP_OK); 438: } 439: } 440: fclose (lookf); 441: return (RP_NO); 442: } 443: 444: 445: /* */ 446: 447: char *rtnmessage[] = { 448: " Your message has been intercepted trying to access\n", 449: "a restricted access host (e.g. an ARPANET host). A copy\n", 450: "of your message has been sent to the system administrators.\n", 451: "The text of your message follows.\n\n", 452: " --------------- Returned Mail Follows --------------\n", 453: 0 454: }; 455: 456: rtnmesg (badadr) 457: char *badadr; 458: { 459: char **cpp; 460: 461: fprintf (pipef, "Subject: Illegal Address (%s)\n\n", badadr); 462: for (cpp = rtnmessage; *cpp; cpp++) 463: fputs (*cpp, pipef); 464: } 465: 466: txtcpy (frm, to) 467: FILE *frm, *to; 468: { 469: char buffer[BUFSIZ]; 470: int nread; 471: 472: while (!pbroke && (nread = fread (buffer, sizeof (*buffer), BUFSIZ, frm)) > 0) 473: fwrite (buffer, sizeof (*buffer), nread, to); 474: return (ferror (frm) ? RP_LIO : RP_OK ); 475: } 476: 477: /* */ 478: 479: xsubmit (date, from, to, cc, realto) 480: char *date, *from, *to, *cc, *realto; 481: { 482: char cmdstr[LINESIZE], 483: submit[LINESIZE]; 484: 485: getfpath (pathsubmit, cmddfldir, submit); 486: sprintf (cmdstr, "%s '-mlti%s*'", submit, UucpChan ()); 487: 488: #ifndef RUNALON 489: if ((pipef = popen (cmdstr, "w")) == NULL) 490: return (RP_NO); 491: #else 492: pipef = stdout; 493: printf ("%s\n", cmdstr); 494: #endif 495: 496: fprintf (pipef, "%s\n%s\n!\n", from, realto); 497: 498: if (date) { 499: fprintf (pipef, "Date: %s\n", date); 500: fprintf (pipef, "From: %s\n", from); 501: } 502: if (to) { 503: fprintf (pipef, "To: %s", to); 504: if (index (to, '@')) 505: fputc ('\n', pipef);/* Explicit host specified */ 506: else 507: fprintf (pipef, "@%s\n", LocalName ()); 508: } 509: if (cc) { 510: fprintf (pipef, "Cc: %s\n", cc); 511: } 512: 513: return (RP_OK); 514: } 515: 516: /* */ 517: 518: xuucp (from, to) 519: char *from, *to; 520: { 521: char cmdstr[LINESIZE]; 522: 523: sprintf (cmdstr, "/etc/delivermail -r%s -ep -m -s -i %s", from, to); 524: 525: #ifndef RUNALON 526: if ((pipef = popen (cmdstr, "w")) == NULL) 527: return (RP_NO); 528: #else 529: pipef = stdout; 530: printf ("%s\n", cmdstr); 531: #endif 532: 533: return (RP_OK); 534: } 535: 536: /* */ 537: 538: brpipe() /* catch broken-pipe signals */ 539: { 540: signal(SIGPIPE, SIG_IGN); 541: pbroke = 1; 542: } 543: 544: char *oopsmessage[] = { 545: "\n\n\tThe system administrators (%s) have been informed of the\n", 546: "problem, but have not been given a copy of your message.\n", 547: NULL 548: }; 549: 550: /* */ 551: 552: rcpy () { 553: int i; 554: char buffer[BUFSIZ], 555: message[BUFSIZ]; 556: FILE * fp; 557: 558: ll_log (logptr, LLOGGEN, "Advising %s of failure as %s...", from, usrfrm); 559: 560: sprintf (buffer, "Problems sending mail:\n\n"); 561: if (ml_1adr (NO, NO, sitesignature, "Problems sending mail", usrfrm) 562: != OK) 563: goto ml_err; 564: ml_txt (buffer); 565: 566: if ((fp = fopen (Errtmp, "r")) != NULL) { 567: ml_file (fp); 568: if (ftell (fp) == 0L) 569: fprintf (pipef, "\tunknown problem\n"); 570: fclose (fp); 571: } 572: else 573: ml_txt ("\tunknown problem\n"); 574: 575: for (i = 0; oopsmessage[i]; i++) { 576: sprintf (message, oopsmessage[i], supportaddr); 577: ml_txt (message); 578: } 579: fprintf (pipef, "\n\nReturned message follows:\n\n---------------\n\n"); 580: rewind (fromf); 581: ml_file (fromf); 582: rewind (msgf); 583: ml_file (msgf); 584: 585: if (ml_end (OK) != OK) { 586: char *cp; 587: 588: ml_err: ; 589: if (cp = index (buffer, '\n')) 590: *cp = NULL; 591: ll_log (logptr, LLOGFAT, "Unable to post failure notice"); 592: ll_log (logptr, LLOGFAT, "info: %s", buffer); 593: } 594: } 595: 596: /* */ 597: 598: zcpy () { 599: char buffer[BUFSIZ]; 600: FILE * fp; 601: 602: ll_log (logptr, LLOGGEN, "Advising %s of failure...", supportaddr); 603: 604: sprintf (buffer, "Problems sending mail for %s (aka %s):\n\n", 605: from, usrfrm); 606: if (ml_1adr (NO, NO, sitesignature, "Problems sending mail", supportaddr) 607: != OK) 608: goto ml_err; 609: ml_txt (buffer); 610: 611: if ((fp = fopen (Errtmp, "r")) != NULL) { 612: ml_file (fp); 613: if (ftell (fp) == 0L) 614: fprintf (pipef, "\tunknown problem\n"); 615: fclose (fp); 616: } 617: else 618: ml_txt ("\tunable to open error file\n"); 619: 620: if (ml_end (OK) != OK) { 621: char *cp; 622: 623: ml_err: ; 624: if (cp = index (buffer, '\n')) 625: *cp = NULL; 626: ll_log (logptr, LLOGFAT, "Unable to post failure notice"); 627: ll_log (logptr, LLOGFAT, "info: %s", buffer); 628: } 629: } 630: 631: /* */ 632: 633: mf_get_msg () { 634: int i, 635: fd, 636: md, 637: td; 638: char buffer[BUFSIZ], 639: tmpfil[LINESIZE], 640: mmdfil[LINESIZE]; 641: #ifdef MFDEBUG 642: FILE * fp; 643: #endif MFDEBUG 644: FILE * out; 645: 646: strcpy (tmpfil, "/tmp/rmailXXXXXX"); 647: unlink (mktemp (tmpfil)); 648: if ((fd = creat (tmpfil, Tmpmode)) == NOTOK) 649: return NOTOK; 650: close (fd); 651: if ((fd = open (tmpfil, 2)) == NOTOK) 652: return NOTOK; 653: if ((out = fdopen (fd, "w")) == NULL) { 654: close (fd); 655: return NOTOK; 656: } 657: if ((td = dup (fd)) == NOTOK) { 658: close (fd); 659: return NOTOK; 660: } 661: 662: fprintf (out, "From %s %s\n", from, date); 663: if (rp_isbad (txtcpy (msgf, out))) { 664: close (fd); 665: close (td); 666: return NOTOK; 667: } 668: fclose (out); 669: lseek (td, 0L, 0); 670: 671: strcpy (mmdfil, "/tmp/mmdfXXXXXX"); 672: unlink (mktemp (mmdfil)); 673: if ((fd = creat (mmdfil, Tmpmode)) == NOTOK) { 674: close (td); 675: unlink (tmpfil); 676: return NOTOK; 677: } 678: if ((fd = open (mmdfil, 2)) == NOTOK) { 679: close (td); 680: unlink (tmpfil); 681: return NOTOK; 682: } 683: if ((md = dup (fd)) == NOTOK) { 684: close (td); 685: unlink (tmpfil); 686: close (fd); 687: return NOTOK; 688: } 689: 690: /* */ 691: 692: switch (i = uucp_to_mmdf (td, fd, TRUE)) { 693: case OK: 694: lseek (md, 0L, 0); 695: if ((mmdf = fdopen (md, "r")) != NULL) 696: break; 697: 698: default: 699: close (md); 700: 701: sprintf (buffer, "rmail(%d) filtering failed(%d)\n", 702: getpid (), i); 703: if (ml_1adr (NO, NO, sitesignature, "MF Failure", supportaddr) 704: != OK) 705: goto ml_err; 706: ml_txt (buffer); 707: #ifdef MFDEBUG 708: lseek (td, 0L, 0); 709: if ((md = dup (td)) == NOTOK) 710: ml_txt ("unable to dup() descriptor for message copy\n"); 711: else 712: if ((fp = fdopen (md, "r")) == NULL) { 713: ml_txt ("unable to fdopen() descriptor for message copy\n"); 714: close (md); 715: } 716: else { 717: ml_txt ("\n --Message Follows--\n"); 718: ml_file (fp); 719: fclose (fp); 720: } 721: #endif MFDEBUG 722: if (ml_end (OK) != OK) { 723: char *cp; 724: 725: ml_err: ; 726: if (cp = index (buffer, '\n')) 727: *cp = NULL; 728: ll_log (logptr, LLOGFAT, "Unable to post failure notice"); 729: ll_log (logptr, LLOGFAT, "info: %s", buffer); 730: } 731: 732: md = NOTOK; 733: break; 734: } 735: close (td); 736: unlink (tmpfil); 737: close (fd); 738: unlink (mmdfil); 739: 740: return md; 741: } 742: 743: /* */ 744: 745: mf_get_addr (from, to) 746: char *from, 747: *to; 748: { 749: struct adrx *adrxp, 750: *seekadrx (); 751: 752: *to = NULL; 753: if ((adrxp = seekadrx (from)) == NULL) 754: return; 755: addr_convert (adrxp, to, TRUE); 756: while (seekadrx (NULL)) 757: continue; 758: return; 759: }