X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/ea07b2d2f1d5ccc79feecf80c9ca99dd2e45f9a4..b6aec1fc92db94da1b759d4facad0a16e2a745c7:/usr/src/usr.sbin/sendmail/src/main.c diff --git a/usr/src/usr.sbin/sendmail/src/main.c b/usr/src/usr.sbin/sendmail/src/main.c index 4a6d403b62..f142636e4f 100644 --- a/usr/src/usr.sbin/sendmail/src/main.c +++ b/usr/src/usr.sbin/sendmail/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1983 Eric P. Allman + * Copyright (c) 1983, 1995 Eric P. Allman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * @@ -13,17 +13,15 @@ static char copyright[] = #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)main.c 8.84 (Berkeley) %G%"; +static char sccsid[] = "@(#)main.c 8.123 (Berkeley) %G%"; #endif /* not lint */ #define _DEFINE #include "sendmail.h" -#include #if NAMED_BIND #include #endif -#include # ifdef lint char edata, end; @@ -68,9 +66,6 @@ ENVELOPE BlankEnvelope; /* a "blank" envelope */ ENVELOPE MainEnvelope; /* the envelope around the basic letter */ ADDRESS NullAddress = /* a null address */ { "", "", NULL, "" }; -char *UserEnviron[MAXUSERENVIRON + 2]; - /* saved user environment */ -char RealUserName[256]; /* the actual user id on this host */ char *CommandLineArgs; /* command line args for pid file */ bool Warn_Q_option = FALSE; /* warn about Q option use */ char **SaveArgv; /* argument vector for re-execing */ @@ -93,6 +88,7 @@ ERROR %%%% Cannot have daemon mode without SMTP %%%% ERROR #define MAXCONFIGLEVEL 6 /* highest config version level known */ +int main(argc, argv, envp) int argc; char **argv; @@ -112,15 +108,14 @@ main(argc, argv, envp) bool warn_C_flag = FALSE; char warn_f_flag = '\0'; static bool reenter = FALSE; - char *argv0 = argv[0]; struct passwd *pw; struct stat stb; struct hostent *hp; char jbuf[MAXHOSTNAMELEN]; /* holds MyHostName */ + static char rnamebuf[MAXNAME]; /* holds RealUserName */ extern int DtableSize; extern int optind; extern time_t convtime(); - extern putheader(), putbody(); extern void intsig(); extern struct hostent *myhostname(); extern char *arpadate(); @@ -130,6 +125,7 @@ main(argc, argv, envp) extern char **environ; extern void sigusr1(); extern void sighup(); + extern void initmacros __P((ENVELOPE *)); /* ** Check to see if we reentered. @@ -210,11 +206,12 @@ main(argc, argv, envp) RealUid = getuid(); RealGid = getgid(); - pw = getpwuid(RealUid); + pw = sm_getpwuid(RealUid); if (pw != NULL) - (void) strcpy(RealUserName, pw->pw_name); + (void) strcpy(rnamebuf, pw->pw_name); else - (void) sprintf(RealUserName, "Unknown UID %d", RealUid); + (void) sprintf(rnamebuf, "Unknown UID %d", RealUid); + RealUserName = rnamebuf; /* save command line arguments */ i = 0; @@ -246,6 +243,9 @@ main(argc, argv, envp) #if defined(ultrix) # define OPTIONS "B:b:C:cd:e:F:f:h:IiM:mnO:o:p:q:r:sTtvX:" #endif +#if defined(sony_news) +# define OPTIONS "B:b:C:cd:E:e:F:f:h:IiJ:mnO:o:p:q:r:sTtvX:" +#endif #ifndef OPTIONS # define OPTIONS "B:b:C:cd:e:F:f:h:IimnO:o:p:q:r:sTtvX:" #endif @@ -256,11 +256,68 @@ main(argc, argv, envp) case 'd': tTflag(optarg); setbuf(stdout, (char *) NULL); - printf("Version %s\n", Version); break; } } + if (tTd(0, 1)) + { + int ll; + extern char *CompileOptions[]; + + printf("Version %s\nCompiled with:\t", Version); + av = CompileOptions; + ll = 7; + while (*av != NULL) + { + if (ll + strlen(*av) > 63) + { + putchar('\n'); + ll = 0; + } + if (ll == 0) + { + putchar('\t'); + putchar('\t'); + } + putchar(' '); + printf("%s", *av); + ll += strlen(*av++) + 1; + } + putchar('\n'); + } + if (tTd(0, 10)) + { + int ll; + extern char *OsCompileOptions[]; + + printf("OS Defines:\t", Version); + av = OsCompileOptions; + ll = 7; + while (*av != NULL) + { + if (ll + strlen(*av) > 63) + { + putchar('\n'); + ll = 0; + } + if (ll == 0) + { + putchar('\t'); + putchar('\t'); + } + putchar(' '); + printf("%s", *av); + ll += strlen(*av++) + 1; + } + putchar('\n'); +#ifdef _PATH_UNIX + printf("Unix path:\t %s\n", _PATH_UNIX); +#endif + printf("Config file:\t %s\n", getcfname()); + printf("Proc Id file:\t %s\n", PidFile); + } + InChannel = stdin; OutChannel = stdout; @@ -269,14 +326,15 @@ main(argc, argv, envp) ** the top of memory. */ - for (i = j = 0; j < MAXUSERENVIRON && (p = envp[i]) != NULL; i++) - { - if (strncmp(p, "FS=", 3) == 0 || strncmp(p, "LD_", 3) == 0) - continue; - UserEnviron[j++] = newstr(p); - } - UserEnviron[j] = NULL; - environ = UserEnviron; + for (i = 0; envp[i] != NULL; i++) + continue; + environ = (char **) xalloc(sizeof (char *) * i); + for (i = 0; envp[i] != NULL; i++) + environ[i] = newstr(envp[i]); + environ[i] = NULL; + + /* and prime the child environment */ + setuserenv("AGENT", "sendmail"); /* ** Save start and extent of argv for setproctitle. @@ -298,10 +356,13 @@ main(argc, argv, envp) #if NAMED_BIND if (tTd(8, 8)) + { + res_init(); { res_init(); _res.options |= RES_DEBUG; } + } #endif errno = 0; @@ -309,6 +370,7 @@ main(argc, argv, envp) /* initialize some macros, etc. */ initmacros(CurEnv); + init_vendor_macros(CurEnv); /* version */ define('v', Version, CurEnv); @@ -331,7 +393,6 @@ main(argc, argv, envp) if (p[1] != '\0') { define('m', newstr(&p[1]), CurEnv); - setclass('m', &p[1]); } while (p != NULL && strchr(&p[1], '.') != NULL) { @@ -383,6 +444,9 @@ main(argc, argv, envp) } } + /* probe interfaces and locate any additional names */ + load_if_names(); + /* current time */ define('b', arpadate((char *) NULL), CurEnv); @@ -483,7 +547,7 @@ main(argc, argv, envp) ExitStat = EX_USAGE; break; } - from = newstr(denlstring(optarg)); + from = newstr(denlstring(optarg, TRUE, TRUE)); if (strcmp(RealUserName, from) != 0) warn_f_flag = j; break; @@ -568,6 +632,7 @@ main(argc, argv, envp) break; case 'X': /* traffic log file */ + setgid(RealGid); setuid(RealUid); TrafficLogFile = fopen(optarg, "a"); if (TrafficLogFile == NULL) @@ -610,6 +675,12 @@ main(argc, argv, envp) case 'x': /* random flag that OSF/1 & AIX mailx passes */ break; # endif +# if defined(sony_news) + case 'E': + case 'J': /* ignore flags for Japanese code conversion + impremented on Sony NEWS */ + break; +# endif default: ExitStat = EX_USAGE; @@ -628,7 +699,13 @@ main(argc, argv, envp) #ifdef XDEBUG checkfd012("before readcf"); #endif + vendor_pre_defaults(CurEnv); readcf(getcfname(), safecf, CurEnv); + vendor_post_defaults(CurEnv); + + /* set up the $=m class now, after .cf has a chance to redefine $m */ + expand("\201m", jbuf, sizeof jbuf, CurEnv); + setclass('m', jbuf); if (tTd(0, 1)) { @@ -648,6 +725,15 @@ main(argc, argv, envp) ** Initialize name server if it is going to be used. */ +#if NAMED_BIND + if (!bitset(RES_INIT, _res.options)) + res_init(); +#endif + + /* + ** Initialize name server if it is going to be used. + */ + #if NAMED_BIND if (UseNameServer && !bitset(RES_INIT, _res.options)) res_init(); @@ -660,9 +746,7 @@ main(argc, argv, envp) if (warn_C_flag) auth_warning(CurEnv, "Processed by %s with -C %s", RealUserName, ConfFile); - if (warn_f_flag != '\0' && - ((st = stab(RealUserName, ST_CLASS, ST_FIND)) == NULL || - !bitnset('t', st->s_class))) + if (warn_f_flag != '\0' && !wordinclass(RealUserName, 't')) auth_warning(CurEnv, "%s set sender to %s using -%c", RealUserName, from, warn_f_flag); if (Warn_Q_option) @@ -676,23 +760,8 @@ main(argc, argv, envp) if (TimeZoneSpec == NULL) unsetenv("TZ"); else if (TimeZoneSpec[0] != '\0') - { - char **evp = UserEnviron; - char tzbuf[100]; - - strcpy(tzbuf, "TZ="); - strcpy(&tzbuf[3], TimeZoneSpec); - - while (*evp != NULL && strncmp(*evp, "TZ=", 3) != 0) - evp++; - if (*evp == NULL) - { - *evp++ = newstr(tzbuf); - *evp = NULL; - } - else - *evp++ = newstr(tzbuf); - } + setuserenv("TZ", TimeZoneSpec); + tzset(); if (ConfigLevel > MAXCONFIGLEVEL) { @@ -703,28 +772,12 @@ main(argc, argv, envp) if (MeToo) BlankEnvelope.e_flags |= EF_METOO; -# ifdef QUEUE - if (queuemode && RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags)) - { - struct stat stbuf; - - /* check to see if we own the queue directory */ - if (stat(QueueDir, &stbuf) < 0) - syserr("main: cannot stat %s", QueueDir); - if (stbuf.st_uid != RealUid) - { - /* nope, really a botch */ - usrerr("You do not have permission to process the queue"); - exit (EX_NOPERM); - } - } -# endif /* QUEUE */ - switch (OpMode) { case MD_DAEMON: /* remove things that don't make sense in daemon mode */ FullName = NULL; + GrabTo = FALSE; /* arrange to restart on hangup signal */ setsignal(SIGHUP, sighup); @@ -742,7 +795,7 @@ main(argc, argv, envp) /* full names can't have newlines */ if (FullName != NULL && strchr(FullName, '\n') != NULL) - FullName = newstr(denlstring(FullName)); + FullName = newstr(denlstring(FullName, TRUE, TRUE)); /* do heuristic mode adjustment */ if (Verbose) @@ -760,7 +813,7 @@ main(argc, argv, envp) } /* our name for SMTP codes */ - expand("\201j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv); + expand("\201j", jbuf, sizeof jbuf, CurEnv); MyHostName = jbuf; if (strchr(jbuf, '.') == NULL) message("WARNING: local host name (%s) is not qualified; fix $j in config file", @@ -780,13 +833,19 @@ main(argc, argv, envp) if (st == NULL) syserr("No prog mailer defined"); else + { ProgMailer = st->s_mailer; + clrbitn(M_MUSER, ProgMailer->m_flags); + } st = stab("*file*", ST_MAILER, ST_FIND); if (st == NULL) syserr("No *file* mailer defined"); else + { FileMailer = st->s_mailer; + clrbitn(M_MUSER, FileMailer->m_flags); + } st = stab("*include*", ST_MAILER, ST_FIND); if (st == NULL) @@ -794,9 +853,9 @@ main(argc, argv, envp) else InclMailer = st->s_mailer; - /* heuristic tweaking of local mailer for back compat */ if (ConfigLevel < 6) { + /* heuristic tweaking of local mailer for back compat */ if (LocalMailer != NULL) { setbitn(M_ALIASABLE, LocalMailer->m_flags); @@ -811,8 +870,20 @@ main(argc, argv, envp) setbitn(M_RUNASRCPT, ProgMailer->m_flags); if (FileMailer != NULL) setbitn(M_RUNASRCPT, FileMailer->m_flags); + + /* propogate some envariables into children */ + setuserenv("ISP", NULL); + setuserenv("SYSTYPE", NULL); } + /* MIME Content-Types that cannot be transfer encoded */ + setclass('n', "multipart/signed"); + + /* MIME Content-Transfer-Encodings that can be encoded */ + setclass('e', "7bit"); + setclass('e', "8bit"); + setclass('e', "binary"); + /* operate in queue directory */ if (OpMode != MD_TEST && chdir(QueueDir) < 0) { @@ -820,6 +891,23 @@ main(argc, argv, envp) ExitStat = EX_SOFTWARE; } +# ifdef QUEUE + if (queuemode && RealUid != 0 && bitset(PRIV_RESTRICTQRUN, PrivacyFlags)) + { + struct stat stbuf; + + /* check to see if we own the queue directory */ + if (stat(".", &stbuf) < 0) + syserr("main: cannot stat %s", QueueDir); + if (stbuf.st_uid != RealUid) + { + /* nope, really a botch */ + usrerr("You do not have permission to process the queue"); + exit (EX_NOPERM); + } + } +# endif /* QUEUE */ + /* if we've had errors so far, exit now */ if (ExitStat != EX_OK && OpMode != MD_TEST) { @@ -856,6 +944,7 @@ main(argc, argv, envp) exit(EX_OK); case MD_DAEMON: + case MD_SMTP: /* don't open alias database -- done in srvrsmtp */ break; @@ -868,15 +957,12 @@ main(argc, argv, envp) if (tTd(0, 15)) { /* print configuration table (or at least part of it) */ - printrules(); + if (tTd(0, 90)) + printrules(); for (i = 0; i < MAXMAILERS; i++) { - register struct mailer *m = Mailer[i]; - int j; - - if (m == NULL) - continue; - printmailer(m); + if (Mailer[i] != NULL) + printmailer(Mailer[i]); } } @@ -905,145 +991,19 @@ main(argc, argv, envp) } for (;;) { - register char **pvp; - char *q; - auto char *delimptr; - extern bool invalidaddr(); - extern char *crackaddr(); + extern void testmodeline __P((char *, ENVELOPE *)); if (Verbose) printf("> "); (void) fflush(stdout); if (fgets(buf, sizeof buf, stdin) == NULL) finis(); + p = strchr(buf, '\n'); + if (p != NULL) + *p = '\0'; if (!Verbose) - printf("> %s", buf); - switch (buf[0]) - { - case '#': - continue; - - case '?': /* try crackaddr */ - q = crackaddr(&buf[1]); - xputs(q); - printf("\n"); - continue; - - case '.': /* config-style settings */ - switch (buf[1]) - { - case 'D': - define(buf[2], newstr(&buf[3]), CurEnv); - break; - - case 'C': - setclass(buf[2], &buf[3]); - break; - - case 'S': /* dump rule set */ - { - int rs; - struct rewrite *rw; - char *cp; - STAB *s; - - if ((cp = strchr(buf, '\n')) != NULL) - *cp = '\0'; - if (cp == buf+2) - continue; - s = stab(buf+2, ST_RULESET, ST_FIND); - if (s == NULL) - { - if (!isdigit(buf[2])) - continue; - rs = atoi(buf+2); - } - else - rs = s->s_ruleset; - if (rs < 0 || rs > MAXRWSETS) - continue; - if ((rw = RewriteRules[rs]) == NULL) - continue; - do - { - char **s; - putchar('R'); - s = rw->r_lhs; - while (*s != NULL) - { - xputs(*s++); - putchar(' '); - } - putchar('\t'); - putchar('\t'); - s = rw->r_rhs; - while (*s != NULL) - { - xputs(*s++); - putchar(' '); - } - putchar('\n'); - } while (rw = rw->r_next); - } - break; - - default: - printf("Unknown config command %s", buf); - break; - } - continue; - - case '-': /* set command-line-like opts */ - switch (buf[1]) - { - case 'd': - if (buf[2] == '\n') - tTflag(""); - else - tTflag(&buf[2]); - break; - - default: - printf("Unknown \"-\" command %s", buf); - break; - } - continue; - } - - for (p = buf; isascii(*p) && isspace(*p); p++) - continue; - q = p; - while (*p != '\0' && !(isascii(*p) && isspace(*p))) - p++; - if (*p == '\0') - { - printf("No address!\n"); - continue; - } - *p = '\0'; - if (invalidaddr(p + 1, NULL)) - continue; - do - { - char pvpbuf[PSBUFSIZE]; - - pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf, - &delimptr); - if (pvp == NULL) - continue; - p = q; - while (*p != '\0') - { - int stat; - - stat = rewrite(pvp, atoi(p), 0, CurEnv); - if (stat != EX_OK) - printf("== Ruleset %s status %d\n", - p, stat); - while (*p != '\0' && *p++ != ',') - continue; - } - } while (*(p = delimptr) != '\0'); + printf("> %s\n", buf); + testmodeline(buf, CurEnv); } } @@ -1072,7 +1032,7 @@ main(argc, argv, envp) { char dtype[200]; - if (!tTd(0, 1)) + if (!tTd(52, 100)) { /* put us in background */ i = fork(); @@ -1144,6 +1104,7 @@ main(argc, argv, envp) { CurEnv->e_sendmode = SM_VERIFY; CurEnv->e_errormode = EM_QUIET; + PostMasterCopy = NULL; } else { @@ -1234,9 +1195,14 @@ void finis() { if (tTd(2, 1)) - printf("\n====finis: stat %d e_flags %x, e_id=%s\n", - ExitStat, CurEnv->e_flags, + { + extern void printenvflags(); + + printf("\n====finis: stat %d e_id=%s e_flags=", + ExitStat, CurEnv->e_id == NULL ? "NOQUEUE" : CurEnv->e_id); + printenvflags(CurEnv); + } if (tTd(2, 9)) printopenfds(FALSE); @@ -1257,7 +1223,7 @@ finis() if (LogLevel > 78) syslog(LOG_DEBUG, "finis, pid=%d", getpid()); # endif /* LOG */ - if (ExitStat == EX_TEMPFAIL) + if (ExitStat == EX_TEMPFAIL || CurEnv->e_errormode == EM_BERKNET) ExitStat = EX_OK; /* reset uid for process accounting */ @@ -1335,6 +1301,7 @@ struct metamac MetaMacros[] = '\0' }; +void initmacros(e) register ENVELOPE *e; { @@ -1383,6 +1350,7 @@ initmacros(e) ** the controlling tty. */ +void disconnect(droplev, e) int droplev; register ENVELOPE *e; @@ -1392,7 +1360,7 @@ disconnect(droplev, e) if (tTd(52, 1)) printf("disconnect: In %d Out %d, e=%x\n", fileno(InChannel), fileno(OutChannel), e); - if (tTd(52, 5)) + if (tTd(52, 100)) { printf("don't\n"); return; @@ -1470,7 +1438,11 @@ obsolete(argv) /* skip over options that do have a value */ op = strchr(OPTIONS, ap[1]); if (op != NULL && *++op == ':' && ap[2] == '\0' && - ap[1] != 'd' && argv[1] != NULL && argv[1][0] != '-') + ap[1] != 'd' && +#if defined(sony_news) + ap[1] != 'E' && ap[1] != 'J' && +#endif + argv[1] != NULL && argv[1][0] != '-') { argv++; continue; @@ -1493,6 +1465,16 @@ obsolete(argv) /* if -d doesn't have an argument, use 0-99.1 */ if (ap[1] == 'd' && ap[2] == '\0') *argv = "-d0-99.1"; + +# if defined(sony_news) + /* if -E doesn't have an argument, use -EC */ + if (ap[1] == 'E' && ap[2] == '\0') + *argv = "-EC"; + + /* if -J doesn't have an argument, use -JJ */ + if (ap[1] == 'J' && ap[2] == '\0') + *argv = "-JJ"; +# endif } } /* @@ -1535,7 +1517,64 @@ auth_warning(e, msg, va_alist) vsprintf(p, msg, ap); VA_END; addheader("X-Authentication-Warning", buf, &e->e_header); +#if LOG + if (LogLevel > 3) + syslog(LOG_INFO, "%s: Authentication-Warning: %s", + e->e_id == NULL ? "[NOQUEUE]" : e->e_id, buf); +#endif + } +} + /* +** SETUSERENV -- set an environment in the propogated environment +** +** Parameters: +** envar -- the name of the environment variable. +** value -- the value to which it should be set. If +** null, this is extracted from the incoming +** environment. If that is not set, the call +** to setuserenv is ignored. +** +** Returns: +** none. +*/ + +void +setuserenv(envar, value) + const char *envar; + const char *value; +{ + int i; + char **evp = UserEnviron; + char *p; + + if (value == NULL) + { + value = getenv(envar); + if (value == NULL) + return; + } + + i = strlen(envar); + p = (char *) xalloc(strlen(value) + i + 2); + strcpy(p, envar); + p[i++] = '='; + strcpy(&p[i], value); + + while (*evp != NULL && strncmp(*evp, p, i) != 0) + evp++; + if (*evp != NULL) + { + *evp++ = p; + } + else if (evp < &UserEnviron[MAXUSERENVIRON]) + { + *evp++ = p; + *evp = NULL; } + + /* make sure it is in our environment as well */ + if (putenv(p) < 0) + syserr("setuserenv: putenv(%s) failed", p); } /* ** DUMPSTATE -- dump state @@ -1594,10 +1633,213 @@ sighup() if (LogLevel > 3) syslog(LOG_INFO, "restarting %s on signal", SaveArgv[0]); #endif - execv(SaveArgv[0], SaveArgv); + execv(SaveArgv[0], (ARGV_T) SaveArgv); #ifdef LOG if (LogLevel > 0) syslog(LOG_ALERT, "could not exec %s: %m", SaveArgv[0]); #endif exit(EX_OSFILE); } + /* +** TESTMODELINE -- process a test mode input line +** +** Parameters: +** line -- the input line. +** e -- the current environment. +*/ + +void +testmodeline(line, e) + char *line; + ENVELOPE *e; +{ + register char *p; + char *q; + auto char *delimptr; + int mid; + ADDRESS a; + extern bool invalidaddr(); + extern char *crackaddr(); + + switch (line[0]) + { + case '#': + return; + + case '.': /* config-style settings */ + switch (line[1]) + { + case 'D': + mid = macid(&line[2], &delimptr); + if (mid != '\0') + define(mid, newstr(delimptr), e); + break; + + case 'C': + setclass(line[2], &line[3]); + break; + + case 'S': /* dump rule set */ + { + int rs; + struct rewrite *rw; + STAB *s; + + if (line[2] == '\0') + return; + s = stab(&line[2], ST_RULESET, ST_FIND); + if (s == NULL) + { + if (!isdigit(line[2])) + return; + rs = atoi(line+2); + } + else + rs = s->s_ruleset; + if (rs < 0 || rs > MAXRWSETS) + return; + if ((rw = RewriteRules[rs]) == NULL) + return; + do + { + char **s; + putchar('R'); + s = rw->r_lhs; + while (*s != NULL) + { + xputs(*s++); + putchar(' '); + } + putchar('\t'); + putchar('\t'); + s = rw->r_rhs; + while (*s != NULL) + { + xputs(*s++); + putchar(' '); + } + putchar('\n'); + } while (rw = rw->r_next); + } + break; + + default: + printf("Unknown config command %s", line); + break; + } + return; + + case '-': /* set command-line-like opts */ + switch (line[1]) + { + case 'd': + tTflag(&line[2]); + break; + + default: + printf("Unknown \"-\" command %s", line); + break; + } + return; + + case '$': + mid = macid(&line[1], NULL); + if (mid == '\0') + return; + p = macvalue(mid, e); + if (p == NULL) + printf("Undefined\n"); + else + { + xputs(p); + printf("\n"); + } + return; + + case '/': /* miscellaneous commands */ + p = &line[strlen(line)]; + while (--p >= line && isascii(*p) && isspace(*p)) + *p = '\0'; + p = strpbrk(line, " \t"); + if (p != NULL) + { + while (isascii(*p) && isspace(*p)) + *p++ = '\0'; + } + else + p = ""; + if (strcasecmp(&line[1], "mx") == 0) + { +#if NAMED_BIND + /* look up MX records */ + int nmx; + int i; + auto int rcode; + char *mxhosts[MAXMXHOSTS + 1]; + + nmx = getmxrr(p, mxhosts, FALSE, &rcode); + printf("getmxrr(%s) returns %d value(s):\n", p, nmx); + for (i = 0; i < nmx; i++) + printf("\t%s\n", mxhosts[i]); +#else + printf("No MX code compiled in\n"); +#endif + } + else if (strcasecmp(&line[1], "try") == 0) + { + q = crackaddr(p); + printf("Cracked address = "); + xputs(q); + printf("\n"); + if (parseaddr(p, &a, RF_COPYNONE, '\0', NULL, e) == NULL) + printf("Cannot parse\n"); + else if (a.q_host != NULL && a.q_host[0] != '\0') + printf("mailer %s, host %s, user %s\n", + a.q_mailer->m_name, a.q_host, a.q_user); + else + printf("mailer %s, user %s\n", + a.q_mailer->m_name, a.q_user); + } + else + { + printf("Unknown test command %s\n", line); + } + return; + } + + for (p = line; isascii(*p) && isspace(*p); p++) + continue; + q = p; + while (*p != '\0' && !(isascii(*p) && isspace(*p))) + p++; + if (*p == '\0') + { + printf("No address!\n"); + return; + } + *p = '\0'; + if (invalidaddr(p + 1, NULL)) + return; + do + { + register char **pvp; + char pvpbuf[PSBUFSIZE]; + + pvp = prescan(++p, ',', pvpbuf, sizeof pvpbuf, + &delimptr, NULL); + if (pvp == NULL) + continue; + p = q; + while (*p != '\0') + { + int stat; + + stat = rewrite(pvp, atoi(p), 0, e); + if (stat != EX_OK) + printf("== Ruleset %s status %d\n", + p, stat); + while (*p != '\0' && *p++ != ',') + continue; + } + } while (*(p = delimptr) != '\0'); +}