Commit | Line | Data |
---|---|---|
b2a81223 | 1 | /* |
dc45ba8c | 2 | * Copyright (c) 1983 Eric P. Allman |
c1f0acb8 KB |
3 | * Copyright (c) 1988, 1993 |
4 | * The Regents of the University of California. All rights reserved. | |
bee79b64 | 5 | * |
ad787160 C |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions | |
8 | * are met: | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * 3. All advertising materials mentioning features or use of this software | |
15 | * must display the following acknowledgement: | |
16 | * This product includes software developed by the University of | |
17 | * California, Berkeley and its contributors. | |
18 | * 4. Neither the name of the University nor the names of its contributors | |
19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
32 | * SUCH DAMAGE. | |
bee79b64 | 33 | */ |
b2a81223 DF |
34 | |
35 | #ifndef lint | |
ed554bc5 | 36 | static char sccsid[] = "@(#)recipient.c 8.44 (Berkeley) 2/28/94"; |
bee79b64 | 37 | #endif /* not lint */ |
b2a81223 | 38 | |
72041f93 | 39 | # include "sendmail.h" |
6eefe4f6 | 40 | # include <pwd.h> |
6eefe4f6 | 41 | |
6eefe4f6 | 42 | /* |
811a6cf3 | 43 | ** SENDTOLIST -- Designate a send list. |
6eefe4f6 EA |
44 | ** |
45 | ** The parameter is a comma-separated list of people to send to. | |
46 | ** This routine arranges to send to all of them. | |
47 | ** | |
48 | ** Parameters: | |
49 | ** list -- the send list. | |
1bf7c76b EA |
50 | ** ctladdr -- the address template for the person to |
51 | ** send to -- effective uid/gid are important. | |
d4f42161 EA |
52 | ** This is typically the alias that caused this |
53 | ** expansion. | |
54 | ** sendq -- a pointer to the head of a queue to put | |
55 | ** these people into. | |
118e6693 | 56 | ** e -- the envelope in which to add these recipients. |
6eefe4f6 EA |
57 | ** |
58 | ** Returns: | |
ad787160 | 59 | ** The number of addresses actually on the list. |
6eefe4f6 EA |
60 | ** |
61 | ** Side Effects: | |
62 | ** none. | |
63 | */ | |
64 | ||
65 | # define MAXRCRSN 10 | |
66 | ||
ad787160 | 67 | sendtolist(list, ctladdr, sendq, e) |
6eefe4f6 | 68 | char *list; |
1bf7c76b | 69 | ADDRESS *ctladdr; |
4e5e456f | 70 | ADDRESS **sendq; |
a4076aed | 71 | register ENVELOPE *e; |
6eefe4f6 EA |
72 | { |
73 | register char *p; | |
7b955214 | 74 | register ADDRESS *al; /* list of addresses to send to */ |
92f12b98 | 75 | bool firstone; /* set on first address sent */ |
d3f52e20 | 76 | char delimiter; /* the address delimiter */ |
1c7897ef | 77 | int naddrs; |
d1147db7 | 78 | char *oldto = e->e_to; |
d6b27179 | 79 | |
5aec60fc EA |
80 | if (list == NULL) |
81 | { | |
82 | syserr("sendtolist: null list"); | |
83 | return 0; | |
84 | } | |
85 | ||
9678c96d | 86 | if (tTd(25, 1)) |
331b7c9f EA |
87 | { |
88 | printf("sendto: %s\n ctladdr=", list); | |
89 | printaddr(ctladdr, FALSE); | |
90 | } | |
6eefe4f6 | 91 | |
7b955214 | 92 | /* heuristic to determine old versus new style addresses */ |
a2983993 | 93 | if (ctladdr == NULL && |
f3d8f6d6 EA |
94 | (strchr(list, ',') != NULL || strchr(list, ';') != NULL || |
95 | strchr(list, '<') != NULL || strchr(list, '(') != NULL)) | |
a4076aed | 96 | e->e_flags &= ~EF_OLDSTYLE; |
d3f52e20 | 97 | delimiter = ' '; |
a4076aed | 98 | if (!bitset(EF_OLDSTYLE, e->e_flags) || ctladdr != NULL) |
d3f52e20 | 99 | delimiter = ','; |
7b955214 | 100 | |
92f12b98 | 101 | firstone = TRUE; |
d6b27179 | 102 | al = NULL; |
1c7897ef | 103 | naddrs = 0; |
7b955214 | 104 | |
506fc377 | 105 | for (p = list; *p != '\0'; ) |
6eefe4f6 | 106 | { |
9e2cf26f | 107 | auto char *delimptr; |
506fc377 | 108 | register ADDRESS *a; |
6eefe4f6 EA |
109 | |
110 | /* parse the address */ | |
2bee003d | 111 | while ((isascii(*p) && isspace(*p)) || *p == ',') |
506fc377 | 112 | p++; |
28f94061 | 113 | a = parseaddr(p, NULLADDR, RF_COPYALL, delimiter, &delimptr, e); |
9e2cf26f | 114 | p = delimptr; |
b9fadd5b EA |
115 | if (a == NULL) |
116 | continue; | |
d6b27179 | 117 | a->q_next = al; |
1bf7c76b | 118 | a->q_alias = ctladdr; |
331b7c9f EA |
119 | |
120 | /* see if this should be marked as a primary address */ | |
92f12b98 | 121 | if (ctladdr == NULL || |
506fc377 | 122 | (firstone && *p == '\0' && bitset(QPRIMARY, ctladdr->q_flags))) |
92f12b98 | 123 | a->q_flags |= QPRIMARY; |
331b7c9f | 124 | |
7338e3d4 | 125 | if (ctladdr != NULL && sameaddr(ctladdr, a)) |
5d41b806 | 126 | ctladdr->q_flags |= QSELFREF; |
78bbbc48 | 127 | al = a; |
92f12b98 | 128 | firstone = FALSE; |
d6b27179 EA |
129 | } |
130 | ||
131 | /* arrange to send to everyone on the local send list */ | |
132 | while (al != NULL) | |
133 | { | |
134 | register ADDRESS *a = al; | |
135 | ||
136 | al = a->q_next; | |
ad787160 | 137 | a = recipient(a, sendq, e); |
abae7b2d | 138 | |
e804469b C |
139 | /* arrange to inherit full name */ |
140 | if (a->q_fullname == NULL && ctladdr != NULL) | |
141 | a->q_fullname = ctladdr->q_fullname; | |
ad787160 | 142 | naddrs++; |
6eefe4f6 | 143 | } |
d6b27179 | 144 | |
d1147db7 | 145 | e->e_to = oldto; |
1c7897ef | 146 | return (naddrs); |
6eefe4f6 EA |
147 | } |
148 | \f/* | |
149 | ** RECIPIENT -- Designate a message recipient | |
150 | ** | |
151 | ** Saves the named person for future mailing. | |
152 | ** | |
153 | ** Parameters: | |
154 | ** a -- the (preparsed) address header for the recipient. | |
d4f42161 EA |
155 | ** sendq -- a pointer to the head of a queue to put the |
156 | ** recipient in. Duplicate supression is done | |
157 | ** in this queue. | |
78bbbc48 | 158 | ** e -- the current envelope. |
6eefe4f6 EA |
159 | ** |
160 | ** Returns: | |
0f4556f1 C |
161 | ** The actual address in the queue. This will be "a" if |
162 | ** the address is not a duplicate, else the original address. | |
6eefe4f6 EA |
163 | ** |
164 | ** Side Effects: | |
165 | ** none. | |
166 | */ | |
167 | ||
abae7b2d | 168 | ADDRESS * |
a4076aed | 169 | recipient(a, sendq, e) |
6eefe4f6 | 170 | register ADDRESS *a; |
d4f42161 | 171 | register ADDRESS **sendq; |
a4076aed | 172 | register ENVELOPE *e; |
6eefe4f6 EA |
173 | { |
174 | register ADDRESS *q; | |
74c5fe7c | 175 | ADDRESS **pq; |
6eefe4f6 | 176 | register struct mailer *m; |
98f46225 EA |
177 | register char *p; |
178 | bool quoted = FALSE; /* set if the addr has a quote bit */ | |
7f0fd60b | 179 | int findusercount = 0; |
98f46225 | 180 | char buf[MAXNAME]; /* unquoted image of the user name */ |
118e6693 | 181 | extern int safefile(); |
6eefe4f6 | 182 | |
a4076aed | 183 | e->e_to = a->q_paddr; |
179c1218 | 184 | m = a->q_mailer; |
6eefe4f6 | 185 | errno = 0; |
9678c96d | 186 | if (tTd(26, 1)) |
331b7c9f EA |
187 | { |
188 | printf("\nrecipient: "); | |
189 | printaddr(a, FALSE); | |
190 | } | |
6eefe4f6 | 191 | |
e4a5cf08 EA |
192 | /* if this is primary, add it to the original recipient list */ |
193 | if (a->q_alias == NULL) | |
194 | { | |
195 | if (e->e_origrcpt == NULL) | |
196 | e->e_origrcpt = a->q_paddr; | |
197 | else if (e->e_origrcpt != a->q_paddr) | |
198 | e->e_origrcpt = ""; | |
199 | } | |
200 | ||
6eefe4f6 EA |
201 | /* break aliasing loops */ |
202 | if (AliasLevel > MAXRCRSN) | |
203 | { | |
b6edea3d | 204 | usrerr("554 aliasing/forwarding loop broken"); |
0f4556f1 | 205 | return (a); |
6eefe4f6 EA |
206 | } |
207 | ||
208 | /* | |
ed45aae1 | 209 | ** Finish setting up address structure. |
6eefe4f6 EA |
210 | */ |
211 | ||
0fe3917f | 212 | /* set the queue timeout */ |
c2bdb1dd | 213 | a->q_timeout = TimeOuts.to_q_return; |
ed45aae1 | 214 | |
0fe3917f | 215 | /* get unquoted user for file, program or user.name check */ |
98f46225 EA |
216 | (void) strcpy(buf, a->q_user); |
217 | for (p = buf; *p != '\0' && !quoted; p++) | |
218 | { | |
3eb4fac4 | 219 | if (*p == '\\') |
98f46225 EA |
220 | quoted = TRUE; |
221 | } | |
85c61679 | 222 | stripquotes(buf); |
98f46225 | 223 | |
98e5062b | 224 | /* check for direct mailing to restricted mailers */ |
78a504b0 | 225 | if (m == ProgMailer) |
6eefe4f6 | 226 | { |
78a504b0 EA |
227 | if (a->q_alias == NULL) |
228 | { | |
229 | a->q_flags |= QBADADDR; | |
230 | usrerr("550 Cannot mail directly to programs"); | |
231 | } | |
232 | else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) | |
233 | { | |
234 | a->q_flags |= QBADADDR; | |
235 | usrerr("550 User %s@%s doesn't have a valid shell for mailing to programs", | |
236 | a->q_alias->q_ruser, MyHostName); | |
237 | } | |
238 | else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) | |
239 | { | |
240 | a->q_flags |= QBADADDR; | |
241 | usrerr("550 Address %s is unsafe for mailing to programs", | |
242 | a->q_alias->q_paddr); | |
243 | } | |
6eefe4f6 EA |
244 | } |
245 | ||
246 | /* | |
b9ca6d11 EA |
247 | ** Look up this person in the recipient list. |
248 | ** If they are there already, return, otherwise continue. | |
249 | ** If the list is empty, just add it. Notice the cute | |
250 | ** hack to make from addresses suppress things correctly: | |
251 | ** the QDONTSEND bit will be set in the send list. | |
252 | ** [Please note: the emphasis is on "hack."] | |
6eefe4f6 EA |
253 | */ |
254 | ||
d4f42161 | 255 | for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) |
6eefe4f6 | 256 | { |
35943e55 | 257 | if (sameaddr(q, a)) |
6eefe4f6 | 258 | { |
9678c96d | 259 | if (tTd(26, 1)) |
331b7c9f EA |
260 | { |
261 | printf("%s in sendq: ", a->q_paddr); | |
262 | printaddr(q, FALSE); | |
263 | } | |
34bc9a9c | 264 | if (!bitset(QPRIMARY, q->q_flags)) |
f7eca811 | 265 | { |
34bc9a9c | 266 | if (!bitset(QDONTSEND, a->q_flags)) |
b6edea3d | 267 | message("duplicate suppressed"); |
34bc9a9c | 268 | q->q_flags |= a->q_flags; |
f7eca811 | 269 | } |
34bc9a9c EA |
270 | else if (bitset(QSELFREF, q->q_flags)) |
271 | q->q_flags |= a->q_flags & ~QDONTSEND; | |
ed554bc5 C |
272 | a = q; |
273 | goto testselfdestruct; | |
6eefe4f6 | 274 | } |
6eefe4f6 | 275 | } |
74c5fe7c EA |
276 | |
277 | /* add address on list */ | |
278 | *pq = a; | |
6eefe4f6 EA |
279 | a->q_next = NULL; |
280 | ||
281 | /* | |
98e5062b | 282 | ** Alias the name and handle special mailer types. |
6eefe4f6 EA |
283 | */ |
284 | ||
7f0fd60b | 285 | trylocaluser: |
42450b5a EA |
286 | if (tTd(29, 7)) |
287 | printf("at trylocaluser %s\n", a->q_user); | |
288 | ||
bc854e30 | 289 | if (bitset(QDONTSEND|QBADADDR|QVERIFIED, a->q_flags)) |
d1147db7 | 290 | goto testselfdestruct; |
98e5062b EA |
291 | |
292 | if (m == InclMailer) | |
6eefe4f6 | 293 | { |
98e5062b | 294 | a->q_flags |= QDONTSEND; |
46361811 | 295 | if (a->q_alias == NULL) |
6eefe4f6 | 296 | { |
bc854e30 | 297 | a->q_flags |= QBADADDR; |
b6edea3d | 298 | usrerr("550 Cannot mail directly to :include:s"); |
6eefe4f6 EA |
299 | } |
300 | else | |
8a12fae4 | 301 | { |
d50bcc17 | 302 | int ret; |
118e6693 | 303 | |
b6edea3d | 304 | message("including file %s", a->q_user); |
d50bcc17 EA |
305 | ret = include(a->q_user, FALSE, a, sendq, e); |
306 | if (transienterror(ret)) | |
307 | { | |
308 | #ifdef LOG | |
309 | if (LogLevel > 2) | |
24ba7f88 | 310 | syslog(LOG_ERR, "%s: include %s: transient error: %s", |
1db90aeb EA |
311 | e->e_id == NULL ? "NOQUEUE" : e->e_id, |
312 | a->q_user, errstring(ret)); | |
d50bcc17 | 313 | #endif |
c069e0df | 314 | a->q_flags |= QQUEUEUP; |
4281694e | 315 | a->q_flags &= ~QDONTSEND; |
d50bcc17 EA |
316 | usrerr("451 Cannot open %s: %s", |
317 | a->q_user, errstring(ret)); | |
318 | } | |
319 | else if (ret != 0) | |
320 | { | |
32c83608 | 321 | a->q_flags |= QBADADDR; |
d50bcc17 EA |
322 | usrerr("550 Cannot open %s: %s", |
323 | a->q_user, errstring(ret)); | |
d50bcc17 | 324 | } |
8a12fae4 | 325 | } |
98e5062b | 326 | } |
6e99f903 | 327 | else if (m == FileMailer) |
6eefe4f6 | 328 | { |
a0554f81 | 329 | extern bool writable(); |
6eefe4f6 | 330 | |
d13779b1 | 331 | /* check if writable or creatable */ |
46361811 | 332 | if (a->q_alias == NULL) |
6eefe4f6 | 333 | { |
bc854e30 | 334 | a->q_flags |= QBADADDR; |
b6edea3d | 335 | usrerr("550 Cannot mail directly to files"); |
d13779b1 | 336 | } |
78a504b0 EA |
337 | else if (bitset(QBOGUSSHELL, a->q_alias->q_flags)) |
338 | { | |
339 | a->q_flags |= QBADADDR; | |
340 | usrerr("550 User %s@%s doesn't have a valid shell for mailing to files", | |
341 | a->q_alias->q_ruser, MyHostName); | |
342 | } | |
343 | else if (bitset(QUNSAFEADDR, a->q_alias->q_flags)) | |
344 | { | |
345 | a->q_flags |= QBADADDR; | |
346 | usrerr("550 Address %s is unsafe for mailing to files", | |
347 | a->q_alias->q_paddr); | |
348 | } | |
75cdfff0 | 349 | else if (!writable(buf, getctladdr(a), SFF_ANYFILE)) |
d13779b1 | 350 | { |
bc854e30 | 351 | a->q_flags |= QBADADDR; |
5c18c358 | 352 | giveresponse(EX_CANTCREAT, m, NULL, a->q_alias, e); |
d13779b1 | 353 | } |
d13779b1 EA |
354 | } |
355 | ||
98e5062b | 356 | if (m != LocalMailer) |
6e99f903 EA |
357 | { |
358 | if (!bitset(QDONTSEND, a->q_flags)) | |
359 | e->e_nrcpts++; | |
d1147db7 | 360 | goto testselfdestruct; |
6e99f903 | 361 | } |
98e5062b EA |
362 | |
363 | /* try aliasing */ | |
364 | alias(a, sendq, e); | |
365 | ||
366 | # ifdef USERDB | |
367 | /* if not aliased, look it up in the user database */ | |
ebd4f543 | 368 | if (!bitset(QDONTSEND|QNOTREMOTE|QVERIFIED, a->q_flags)) |
98e5062b EA |
369 | { |
370 | extern int udbexpand(); | |
371 | ||
372 | if (udbexpand(a, sendq, e) == EX_TEMPFAIL) | |
373 | { | |
c069e0df | 374 | a->q_flags |= QQUEUEUP; |
98e5062b EA |
375 | if (e->e_message == NULL) |
376 | e->e_message = newstr("Deferred: user database error"); | |
377 | # ifdef LOG | |
68f7099c | 378 | if (LogLevel > 8) |
3f0792d1 | 379 | syslog(LOG_INFO, "%s: deferred: udbexpand: %s", |
1db90aeb EA |
380 | e->e_id == NULL ? "NOQUEUE" : e->e_id, |
381 | errstring(errno)); | |
98e5062b | 382 | # endif |
73f6752a EA |
383 | message("queued (user database error): %s", |
384 | errstring(errno)); | |
6e99f903 | 385 | e->e_nrcpts++; |
d1147db7 | 386 | goto testselfdestruct; |
98e5062b EA |
387 | } |
388 | } | |
389 | # endif | |
390 | ||
391 | /* if it was an alias or a UDB expansion, just return now */ | |
118e6693 | 392 | if (bitset(QDONTSEND|QQUEUEUP|QVERIFIED, a->q_flags)) |
d1147db7 | 393 | goto testselfdestruct; |
98e5062b | 394 | |
d13779b1 EA |
395 | /* |
396 | ** If we have a level two config file, then pass the name through | |
397 | ** Ruleset 5 before sending it off. Ruleset 5 has the right | |
398 | ** to send rewrite it to another mailer. This gives us a hook | |
399 | ** after local aliasing has been done. | |
400 | */ | |
401 | ||
402 | if (tTd(29, 5)) | |
403 | { | |
404 | printf("recipient: testing local? cl=%d, rr5=%x\n\t", | |
405 | ConfigLevel, RewriteRules[5]); | |
406 | printaddr(a, FALSE); | |
407 | } | |
408 | if (!bitset(QNOTREMOTE, a->q_flags) && ConfigLevel >= 2 && | |
409 | RewriteRules[5] != NULL) | |
410 | { | |
a4076aed | 411 | maplocaluser(a, sendq, e); |
d13779b1 EA |
412 | } |
413 | ||
414 | /* | |
415 | ** If it didn't get rewritten to another mailer, go ahead | |
416 | ** and deliver it. | |
417 | */ | |
418 | ||
118e6693 | 419 | if (!bitset(QDONTSEND|QQUEUEUP, a->q_flags)) |
d13779b1 | 420 | { |
42450b5a | 421 | auto bool fuzzy; |
d13779b1 EA |
422 | register struct passwd *pw; |
423 | extern struct passwd *finduser(); | |
424 | ||
425 | /* warning -- finduser may trash buf */ | |
42450b5a | 426 | pw = finduser(buf, &fuzzy); |
d13779b1 EA |
427 | if (pw == NULL) |
428 | { | |
bc854e30 | 429 | a->q_flags |= QBADADDR; |
5c18c358 | 430 | giveresponse(EX_NOUSER, m, NULL, a->q_alias, e); |
6eefe4f6 EA |
431 | } |
432 | else | |
433 | { | |
d13779b1 | 434 | char nbuf[MAXNAME]; |
ff3e3c1c | 435 | |
42450b5a | 436 | if (fuzzy) |
6eefe4f6 | 437 | { |
7f0fd60b | 438 | /* name was a fuzzy match */ |
d13779b1 | 439 | a->q_user = newstr(pw->pw_name); |
7f0fd60b EA |
440 | if (findusercount++ > 3) |
441 | { | |
bc854e30 | 442 | a->q_flags |= QBADADDR; |
b6edea3d | 443 | usrerr("554 aliasing/forwarding loop for %s broken", |
7f0fd60b EA |
444 | pw->pw_name); |
445 | return (a); | |
446 | } | |
447 | ||
448 | /* see if it aliases */ | |
d13779b1 | 449 | (void) strcpy(buf, pw->pw_name); |
7f0fd60b | 450 | goto trylocaluser; |
6eefe4f6 | 451 | } |
c841d671 EA |
452 | if (strcmp(pw->pw_dir, "/") == 0) |
453 | a->q_home = ""; | |
454 | else | |
455 | a->q_home = newstr(pw->pw_dir); | |
d13779b1 EA |
456 | a->q_uid = pw->pw_uid; |
457 | a->q_gid = pw->pw_gid; | |
61cbea4c | 458 | a->q_ruser = newstr(pw->pw_name); |
d13779b1 EA |
459 | a->q_flags |= QGOODUID; |
460 | buildfname(pw->pw_gecos, pw->pw_name, nbuf); | |
461 | if (nbuf[0] != '\0') | |
462 | a->q_fullname = newstr(nbuf); | |
1ee33f7d EA |
463 | if (pw->pw_shell != NULL && pw->pw_shell[0] != '\0' && |
464 | !usershellok(pw->pw_shell)) | |
52d85a9d | 465 | { |
1ee33f7d | 466 | a->q_flags |= QBOGUSSHELL; |
52d85a9d | 467 | } |
d13779b1 | 468 | if (!quoted) |
a4076aed | 469 | forward(a, sendq, e); |
6eefe4f6 EA |
470 | } |
471 | } | |
6e99f903 EA |
472 | if (!bitset(QDONTSEND, a->q_flags)) |
473 | e->e_nrcpts++; | |
d1147db7 EA |
474 | |
475 | testselfdestruct: | |
cd361139 | 476 | if (tTd(26, 8)) |
d1147db7 | 477 | { |
cd361139 EA |
478 | printf("testselfdestruct: "); |
479 | printaddr(a, TRUE); | |
480 | } | |
481 | if (a->q_alias == NULL && a != &e->e_from && | |
482 | bitset(QDONTSEND, a->q_flags)) | |
483 | { | |
484 | q = *sendq; | |
0fc3fb21 | 485 | while (q != NULL && bitset(QDONTSEND, q->q_flags)) |
d1147db7 | 486 | q = q->q_next; |
cd361139 | 487 | if (q == NULL) |
d1147db7 EA |
488 | { |
489 | a->q_flags |= QBADADDR; | |
490 | usrerr("554 aliasing/forwarding loop broken"); | |
491 | } | |
492 | } | |
d344c0b7 | 493 | return (a); |
6eefe4f6 EA |
494 | } |
495 | \f/* | |
ff3e3c1c EA |
496 | ** FINDUSER -- find the password entry for a user. |
497 | ** | |
498 | ** This looks a lot like getpwnam, except that it may want to | |
499 | ** do some fancier pattern matching in /etc/passwd. | |
500 | ** | |
7338e3d4 EA |
501 | ** This routine contains most of the time of many sendmail runs. |
502 | ** It deserves to be optimized. | |
503 | ** | |
ff3e3c1c EA |
504 | ** Parameters: |
505 | ** name -- the name to match against. | |
42450b5a EA |
506 | ** fuzzyp -- an outarg that is set to TRUE if this entry |
507 | ** was found using the fuzzy matching algorithm; | |
508 | ** set to FALSE otherwise. | |
ff3e3c1c EA |
509 | ** |
510 | ** Returns: | |
511 | ** A pointer to a pw struct. | |
512 | ** NULL if name is unknown or ambiguous. | |
513 | ** | |
514 | ** Side Effects: | |
29c33ff6 | 515 | ** may modify name. |
ff3e3c1c EA |
516 | */ |
517 | ||
518 | struct passwd * | |
42450b5a | 519 | finduser(name, fuzzyp) |
ff3e3c1c | 520 | char *name; |
42450b5a | 521 | bool *fuzzyp; |
ff3e3c1c | 522 | { |
2b5e3c25 | 523 | register struct passwd *pw; |
29c33ff6 | 524 | register char *p; |
f74d8dce EA |
525 | extern struct passwd *getpwent(); |
526 | extern struct passwd *getpwnam(); | |
29c33ff6 | 527 | |
42450b5a EA |
528 | if (tTd(29, 4)) |
529 | printf("finduser(%s): ", name); | |
530 | ||
42450b5a | 531 | *fuzzyp = FALSE; |
ff3e3c1c | 532 | |
06b7bf4a EA |
533 | /* DEC Hesiod getpwnam accepts numeric strings -- short circuit it */ |
534 | for (p = name; *p != '\0'; p++) | |
535 | if (!isascii(*p) || !isdigit(*p)) | |
536 | break; | |
537 | if (*p == '\0') | |
538 | { | |
539 | if (tTd(29, 4)) | |
540 | printf("failed (numeric input)\n"); | |
541 | return NULL; | |
542 | } | |
543 | ||
639d8b98 | 544 | /* look up this login name using fast path */ |
77b16ff1 | 545 | if ((pw = getpwnam(name)) != NULL) |
42450b5a EA |
546 | { |
547 | if (tTd(29, 4)) | |
548 | printf("found (non-fuzzy)\n"); | |
77b16ff1 | 549 | return (pw); |
42450b5a | 550 | } |
77b16ff1 | 551 | |
7f0fd60b EA |
552 | #ifdef MATCHGECOS |
553 | /* see if fuzzy matching allowed */ | |
554 | if (!MatchGecos) | |
42450b5a EA |
555 | { |
556 | if (tTd(29, 4)) | |
557 | printf("not found (fuzzy disabled)\n"); | |
7f0fd60b | 558 | return NULL; |
42450b5a | 559 | } |
7f0fd60b | 560 | |
77b16ff1 | 561 | /* search for a matching full name instead */ |
639d8b98 EA |
562 | for (p = name; *p != '\0'; p++) |
563 | { | |
564 | if (*p == (SpaceSub & 0177) || *p == '_') | |
565 | *p = ' '; | |
566 | } | |
03388044 | 567 | (void) setpwent(); |
2b5e3c25 EA |
568 | while ((pw = getpwent()) != NULL) |
569 | { | |
abae7b2d | 570 | char buf[MAXNAME]; |
2b5e3c25 | 571 | |
e804469b | 572 | buildfname(pw->pw_gecos, pw->pw_name, buf); |
f3d8f6d6 | 573 | if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name)) |
36292825 | 574 | { |
42450b5a EA |
575 | if (tTd(29, 4)) |
576 | printf("fuzzy matches %s\n", pw->pw_name); | |
ad787160 C |
577 | message("sending to login name %s", pw->pw_name); |
578 | *fuzzyp = TRUE; | |
2b5e3c25 | 579 | return (pw); |
36292825 | 580 | } |
2b5e3c25 | 581 | } |
42450b5a EA |
582 | if (tTd(29, 4)) |
583 | printf("no fuzzy match found\n"); | |
70ce33b6 EA |
584 | #else |
585 | if (tTd(29, 4)) | |
586 | printf("not found (fuzzy disabled)\n"); | |
587 | #endif | |
2b5e3c25 | 588 | return (NULL); |
ff3e3c1c EA |
589 | } |
590 | \f/* | |
a0554f81 EA |
591 | ** WRITABLE -- predicate returning if the file is writable. |
592 | ** | |
593 | ** This routine must duplicate the algorithm in sys/fio.c. | |
594 | ** Unfortunately, we cannot use the access call since we | |
595 | ** won't necessarily be the real uid when we try to | |
596 | ** actually open the file. | |
597 | ** | |
598 | ** Notice that ANY file with ANY execute bit is automatically | |
599 | ** not writable. This is also enforced by mailfile. | |
600 | ** | |
601 | ** Parameters: | |
c9bddda6 | 602 | ** filename -- the file name to check. |
75cdfff0 | 603 | ** ctladdr -- the controlling address for this file. |
c9bddda6 | 604 | ** flags -- SFF_* flags to control the function. |
a0554f81 EA |
605 | ** |
606 | ** Returns: | |
607 | ** TRUE -- if we will be able to write this file. | |
608 | ** FALSE -- if we cannot write this file. | |
609 | ** | |
610 | ** Side Effects: | |
611 | ** none. | |
612 | */ | |
613 | ||
614 | bool | |
75cdfff0 | 615 | writable(filename, ctladdr, flags) |
793aec0f | 616 | char *filename; |
75cdfff0 | 617 | ADDRESS *ctladdr; |
c9bddda6 | 618 | int flags; |
a0554f81 | 619 | { |
44967af8 EA |
620 | uid_t euid; |
621 | gid_t egid; | |
a0554f81 | 622 | int bits; |
fce21cb9 EA |
623 | register char *p; |
624 | char *uname; | |
625 | struct stat stb; | |
626 | extern char RealUserName[]; | |
a0554f81 | 627 | |
793aec0f | 628 | if (tTd(29, 5)) |
c9bddda6 | 629 | printf("writable(%s, %x)\n", filename, flags); |
fce21cb9 EA |
630 | |
631 | #ifdef HASLSTAT | |
c9bddda6 EA |
632 | if ((bitset(SFF_NOSLINK, flags) ? lstat(filename, &stb) |
633 | : stat(filename, &stb)) < 0) | |
fce21cb9 EA |
634 | #else |
635 | if (stat(filename, &stb) < 0) | |
636 | #endif | |
637 | { | |
638 | /* file does not exist -- see if directory is safe */ | |
639 | p = strrchr(filename, '/'); | |
640 | if (p == NULL) | |
fce21cb9 | 641 | { |
7763037f | 642 | errno = ENOTDIR; |
fce21cb9 EA |
643 | return FALSE; |
644 | } | |
7763037f EA |
645 | *p = '\0'; |
646 | errno = safefile(filename, RealUid, RealGid, RealUserName, | |
647 | SFF_MUSTOWN, S_IWRITE|S_IEXEC); | |
fce21cb9 | 648 | *p = '/'; |
7763037f | 649 | return errno == 0; |
fce21cb9 EA |
650 | } |
651 | ||
d2865fc3 EA |
652 | #ifdef SUID_ROOT_FILES_OK |
653 | /* really ought to be passed down -- and not a good idea */ | |
654 | flags |= SFF_ROOTOK; | |
655 | #endif | |
656 | ||
fce21cb9 EA |
657 | /* |
658 | ** File does exist -- check that it is writable. | |
659 | */ | |
660 | ||
661 | if (bitset(0111, stb.st_mode)) | |
5b2e1a5c EA |
662 | { |
663 | if (tTd(29, 5)) | |
664 | printf("failed (mode %o: x bits)\n", stb.st_mode); | |
7763037f | 665 | errno = EPERM; |
a0554f81 | 666 | return (FALSE); |
5b2e1a5c | 667 | } |
fce21cb9 | 668 | |
75cdfff0 | 669 | if (ctladdr != NULL && geteuid() == 0) |
fce21cb9 | 670 | { |
75cdfff0 EA |
671 | euid = ctladdr->q_uid; |
672 | egid = ctladdr->q_gid; | |
673 | uname = ctladdr->q_user; | |
674 | } | |
675 | else | |
676 | { | |
677 | euid = RealUid; | |
678 | egid = RealGid; | |
679 | uname = RealUserName; | |
fce21cb9 | 680 | } |
0aa35b96 EA |
681 | if (euid == 0) |
682 | { | |
683 | euid = DefUid; | |
684 | uname = DefUser; | |
685 | } | |
686 | if (egid == 0) | |
687 | egid = DefGid; | |
a0554f81 EA |
688 | if (geteuid() == 0) |
689 | { | |
d2865fc3 EA |
690 | if (bitset(S_ISUID, stb.st_mode) && |
691 | (stb.st_uid != 0 || bitset(SFF_ROOTOK, flags))) | |
fce21cb9 EA |
692 | { |
693 | euid = stb.st_uid; | |
694 | uname = NULL; | |
695 | } | |
d2865fc3 EA |
696 | if (bitset(S_ISGID, stb.st_mode) && |
697 | (stb.st_gid != 0 || bitset(SFF_ROOTOK, flags))) | |
fce21cb9 | 698 | egid = stb.st_gid; |
a0554f81 EA |
699 | } |
700 | ||
793aec0f EA |
701 | if (tTd(29, 5)) |
702 | printf("\teu/gid=%d/%d, st_u/gid=%d/%d\n", | |
fce21cb9 | 703 | euid, egid, stb.st_uid, stb.st_gid); |
793aec0f | 704 | |
7763037f EA |
705 | errno = safefile(filename, euid, egid, uname, flags, S_IWRITE); |
706 | return errno == 0; | |
a0554f81 EA |
707 | } |
708 | \f/* | |
6eefe4f6 EA |
709 | ** INCLUDE -- handle :include: specification. |
710 | ** | |
711 | ** Parameters: | |
712 | ** fname -- filename to include. | |
a90a7c55 EA |
713 | ** forwarding -- if TRUE, we are reading a .forward file. |
714 | ** if FALSE, it's a :include: file. | |
1bf7c76b EA |
715 | ** ctladdr -- address template to use to fill in these |
716 | ** addresses -- effective user/group id are | |
717 | ** the important things. | |
d4f42161 EA |
718 | ** sendq -- a pointer to the head of the send queue |
719 | ** to put these addresses in. | |
6eefe4f6 EA |
720 | ** |
721 | ** Returns: | |
e0136832 | 722 | ** open error status |
6eefe4f6 EA |
723 | ** |
724 | ** Side Effects: | |
725 | ** reads the :include: file and sends to everyone | |
726 | ** listed in that file. | |
247efdd6 EA |
727 | ** |
728 | ** Security Note: | |
729 | ** If you have restricted chown (that is, you can't | |
730 | ** give a file away), it is reasonable to allow programs | |
731 | ** and files called from this :include: file to be to be | |
732 | ** run as the owner of the :include: file. This is bogus | |
733 | ** if there is any chance of someone giving away a file. | |
734 | ** We assume that pre-POSIX systems can give away files. | |
735 | ** | |
736 | ** There is an additional restriction that if you | |
737 | ** forward to a :include: file, it will not take on | |
738 | ** the ownership of the :include: file. This may not | |
739 | ** be necessary, but shouldn't hurt. | |
6eefe4f6 EA |
740 | */ |
741 | ||
a90a7c55 | 742 | static jmp_buf CtxIncludeTimeout; |
e6cb9fc4 | 743 | static int includetimeout(); |
a90a7c55 | 744 | |
78a504b0 EA |
745 | #ifndef S_IWOTH |
746 | # define S_IWOTH (S_IWRITE >> 6) | |
747 | #endif | |
748 | ||
e0136832 | 749 | int |
a4076aed | 750 | include(fname, forwarding, ctladdr, sendq, e) |
6eefe4f6 | 751 | char *fname; |
a90a7c55 | 752 | bool forwarding; |
1bf7c76b | 753 | ADDRESS *ctladdr; |
d4f42161 | 754 | ADDRESS **sendq; |
a4076aed | 755 | ENVELOPE *e; |
6eefe4f6 | 756 | { |
a2cdf9f6 | 757 | register FILE *fp = NULL; |
a4076aed | 758 | char *oldto = e->e_to; |
7338e3d4 EA |
759 | char *oldfilename = FileName; |
760 | int oldlinenumber = LineNumber; | |
a90a7c55 | 761 | register EVENT *ev = NULL; |
1c7897ef | 762 | int nincludes; |
a614cf3b EA |
763 | register ADDRESS *ca; |
764 | uid_t saveduid, uid; | |
765 | gid_t savedgid, gid; | |
2b9924bc | 766 | char *uname; |
a614cf3b | 767 | int rval = 0; |
c9bddda6 | 768 | int sfflags = forwarding ? SFF_MUSTOWN : SFF_ANYFILE; |
78a504b0 | 769 | struct stat st; |
117c4023 | 770 | char buf[MAXLINE]; |
247efdd6 | 771 | #ifdef _POSIX_CHOWN_RESTRICTED |
117c4023 EA |
772 | # if _POSIX_CHOWN_RESTRICTED == -1 |
773 | # define safechown FALSE | |
774 | # else | |
775 | # define safechown TRUE | |
776 | # endif | |
777 | #else | |
778 | # ifdef _PC_CHOWN_RESTRICTED | |
247efdd6 | 779 | bool safechown; |
117c4023 EA |
780 | # else |
781 | # ifdef BSD | |
782 | # define safechown TRUE | |
783 | # else | |
784 | # define safechown FALSE | |
785 | # endif | |
786 | # endif | |
247efdd6 | 787 | #endif |
117c4023 | 788 | extern bool chownsafe(); |
a90a7c55 | 789 | |
b21ec539 EA |
790 | if (tTd(27, 2)) |
791 | printf("include(%s)\n", fname); | |
ba6514e2 EA |
792 | if (tTd(27, 4)) |
793 | printf(" ruid=%d euid=%d\n", getuid(), geteuid()); | |
5d32a96c EA |
794 | if (tTd(27, 14)) |
795 | { | |
796 | printf("ctladdr "); | |
797 | printaddr(ctladdr, FALSE); | |
798 | } | |
b21ec539 | 799 | |
a614cf3b EA |
800 | if (tTd(27, 9)) |
801 | printf("include: old uid = %d/%d\n", getuid(), geteuid()); | |
a90a7c55 | 802 | |
5d32a96c EA |
803 | ca = getctladdr(ctladdr); |
804 | if (ca == NULL) | |
2b9924bc | 805 | { |
f161b3d2 EA |
806 | uid = DefUid; |
807 | gid = DefGid; | |
808 | uname = DefUser; | |
a614cf3b | 809 | saveduid = -1; |
2b9924bc | 810 | } |
5d32a96c | 811 | else |
2b9924bc | 812 | { |
5d32a96c | 813 | uid = ca->q_uid; |
2b9924bc EA |
814 | gid = ca->q_gid; |
815 | uname = ca->q_user; | |
a614cf3b EA |
816 | #ifdef HASSETREUID |
817 | saveduid = geteuid(); | |
818 | savedgid = getegid(); | |
819 | if (saveduid == 0) | |
820 | { | |
821 | initgroups(uname, gid); | |
822 | if (uid != 0) | |
823 | (void) setreuid(0, uid); | |
824 | } | |
825 | #endif | |
2b9924bc | 826 | } |
5d32a96c | 827 | |
a614cf3b EA |
828 | if (tTd(27, 9)) |
829 | printf("include: new uid = %d/%d\n", getuid(), geteuid()); | |
830 | ||
831 | /* | |
832 | ** If home directory is remote mounted but server is down, | |
833 | ** this can hang or give errors; use a timeout to avoid this | |
834 | */ | |
835 | ||
a90a7c55 EA |
836 | if (setjmp(CtxIncludeTimeout) != 0) |
837 | { | |
c069e0df | 838 | ctladdr->q_flags |= QQUEUEUP; |
a90a7c55 | 839 | errno = 0; |
92f2b65e EA |
840 | |
841 | /* return pseudo-error code */ | |
a614cf3b EA |
842 | rval = EOPENTIMEOUT; |
843 | goto resetuid; | |
a90a7c55 EA |
844 | } |
845 | ev = setevent((time_t) 60, includetimeout, 0); | |
846 | ||
5d32a96c | 847 | /* the input file must be marked safe */ |
fce21cb9 | 848 | rval = safefile(fname, uid, gid, uname, sfflags, S_IREAD); |
09beeadc | 849 | if (rval != 0) |
a90a7c55 | 850 | { |
a614cf3b | 851 | /* don't use this :include: file */ |
b21ec539 | 852 | if (tTd(27, 4)) |
118e6693 | 853 | printf("include: not safe (uid=%d): %s\n", |
09beeadc | 854 | uid, errstring(rval)); |
a90a7c55 | 855 | } |
78a504b0 | 856 | else |
962c3fb2 | 857 | { |
78a504b0 EA |
858 | fp = fopen(fname, "r"); |
859 | if (fp == NULL) | |
5d41b806 | 860 | { |
09beeadc | 861 | rval = errno; |
78a504b0 EA |
862 | if (tTd(27, 4)) |
863 | printf("include: open: %s\n", errstring(rval)); | |
a2cdf9f6 | 864 | } |
962c3fb2 | 865 | } |
a90a7c55 EA |
866 | clrevent(ev); |
867 | ||
a2cdf9f6 EA |
868 | resetuid: |
869 | ||
870 | #ifdef HASSETREUID | |
871 | if (saveduid == 0) | |
872 | { | |
873 | if (uid != 0) | |
874 | if (setreuid(-1, 0) < 0 || setreuid(RealUid, 0) < 0) | |
875 | syserr("setreuid(%d, 0) failure (real=%d, eff=%d)", | |
876 | RealUid, getuid(), geteuid()); | |
877 | setgid(savedgid); | |
878 | } | |
879 | #endif | |
880 | ||
881 | if (tTd(27, 9)) | |
882 | printf("include: reset uid = %d/%d\n", getuid(), geteuid()); | |
883 | ||
34bc9a9c EA |
884 | if (rval == EOPENTIMEOUT) |
885 | usrerr("451 open timeout on %s", fname); | |
886 | ||
a2cdf9f6 EA |
887 | if (fp == NULL) |
888 | return rval; | |
889 | ||
78a504b0 EA |
890 | if (fstat(fileno(fp), &st) < 0) |
891 | { | |
892 | rval = errno; | |
893 | syserr("Cannot fstat %s!", fname); | |
894 | return rval; | |
895 | } | |
896 | ||
117c4023 EA |
897 | #ifndef safechown |
898 | safechown = chownsafe(fileno(fp)); | |
899 | #endif | |
247efdd6 | 900 | if (ca == NULL && safechown) |
78a504b0 EA |
901 | { |
902 | ctladdr->q_uid = st.st_uid; | |
903 | ctladdr->q_gid = st.st_gid; | |
904 | ctladdr->q_flags |= QGOODUID; | |
905 | } | |
906 | if (ca != NULL && ca->q_uid == st.st_uid) | |
907 | { | |
908 | /* optimization -- avoid getpwuid if we already have info */ | |
909 | ctladdr->q_flags |= ca->q_flags & QBOGUSSHELL; | |
910 | ctladdr->q_ruser = ca->q_ruser; | |
911 | } | |
912 | else | |
913 | { | |
247efdd6 | 914 | char *sh; |
78a504b0 EA |
915 | register struct passwd *pw; |
916 | ||
247efdd6 | 917 | sh = "/SENDMAIL/ANY/SHELL/"; |
78a504b0 | 918 | pw = getpwuid(st.st_uid); |
247efdd6 | 919 | if (pw != NULL) |
78a504b0 EA |
920 | { |
921 | ctladdr->q_ruser = newstr(pw->pw_name); | |
247efdd6 EA |
922 | if (safechown) |
923 | sh = pw->pw_shell; | |
247efdd6 EA |
924 | } |
925 | if (pw == NULL) | |
78a504b0 | 926 | ctladdr->q_flags |= QBOGUSSHELL; |
247efdd6 EA |
927 | else if(!usershellok(sh)) |
928 | { | |
247efdd6 EA |
929 | if (safechown) |
930 | ctladdr->q_flags |= QBOGUSSHELL; | |
931 | else | |
247efdd6 | 932 | ctladdr->q_flags |= QUNSAFEADDR; |
78a504b0 EA |
933 | } |
934 | } | |
935 | ||
8f48def8 EA |
936 | if (bitset(EF_VRFYONLY, e->e_flags)) |
937 | { | |
938 | /* don't do any more now */ | |
5f6654cf | 939 | ctladdr->q_flags |= QVERIFIED; |
a7dc53bd | 940 | e->e_nrcpts++; |
bc854e30 | 941 | xfclose(fp, "include", fname); |
a2cdf9f6 | 942 | return rval; |
8f48def8 EA |
943 | } |
944 | ||
78a504b0 EA |
945 | /* |
946 | ** Check to see if some bad guy can write this file | |
947 | ** | |
948 | ** This should really do something clever with group | |
949 | ** permissions; currently we just view world writable | |
950 | ** as unsafe. Also, we don't check for writable | |
951 | ** directories in the path. We've got to leave | |
952 | ** something for the local sysad to do. | |
953 | */ | |
954 | ||
955 | if (bitset(S_IWOTH, st.st_mode)) | |
956 | ctladdr->q_flags |= QUNSAFEADDR; | |
957 | ||
6eefe4f6 | 958 | /* read the file -- each line is a comma-separated list. */ |
7338e3d4 EA |
959 | FileName = fname; |
960 | LineNumber = 0; | |
1c7897ef EA |
961 | ctladdr->q_flags &= ~QSELFREF; |
962 | nincludes = 0; | |
6eefe4f6 EA |
963 | while (fgets(buf, sizeof buf, fp) != NULL) |
964 | { | |
f3d8f6d6 | 965 | register char *p = strchr(buf, '\n'); |
6eefe4f6 | 966 | |
dd0758e5 | 967 | LineNumber++; |
6eefe4f6 EA |
968 | if (p != NULL) |
969 | *p = '\0'; | |
b21ec539 | 970 | if (buf[0] == '#' || buf[0] == '\0') |
af04f6e4 | 971 | continue; |
51d9cc47 | 972 | e->e_to = NULL; |
b6edea3d | 973 | message("%s to %s", |
a90a7c55 | 974 | forwarding ? "forwarding" : "sending", buf); |
aa102c71 | 975 | #ifdef LOG |
68f7099c | 976 | if (forwarding && LogLevel > 9) |
aa102c71 | 977 | syslog(LOG_INFO, "%s: forward %s => %s", |
1db90aeb EA |
978 | e->e_id == NULL ? "NOQUEUE" : e->e_id, |
979 | oldto, buf); | |
aa102c71 EA |
980 | #endif |
981 | ||
23008226 | 982 | AliasLevel++; |
ad787160 | 983 | nincludes += sendtolist(buf, ctladdr, sendq, e); |
23008226 | 984 | AliasLevel--; |
6eefe4f6 | 985 | } |
ba6514e2 EA |
986 | |
987 | if (ferror(fp) && tTd(27, 3)) | |
988 | printf("include: read error: %s\n", errstring(errno)); | |
1c7897ef | 989 | if (nincludes > 0 && !bitset(QSELFREF, ctladdr->q_flags)) |
f7eca811 EA |
990 | { |
991 | if (tTd(27, 5)) | |
992 | { | |
993 | printf("include: QDONTSEND "); | |
994 | printaddr(ctladdr, FALSE); | |
995 | } | |
996 | ctladdr->q_flags |= QDONTSEND; | |
997 | } | |
6eefe4f6 | 998 | |
bc854e30 | 999 | (void) xfclose(fp, "include", fname); |
7338e3d4 EA |
1000 | FileName = oldfilename; |
1001 | LineNumber = oldlinenumber; | |
d1147db7 | 1002 | e->e_to = oldto; |
a614cf3b | 1003 | return rval; |
6eefe4f6 | 1004 | } |
a90a7c55 EA |
1005 | |
1006 | static | |
1007 | includetimeout() | |
1008 | { | |
1009 | longjmp(CtxIncludeTimeout, 1); | |
1010 | } | |
d6b27179 EA |
1011 | \f/* |
1012 | ** SENDTOARGV -- send to an argument vector. | |
1013 | ** | |
1014 | ** Parameters: | |
1015 | ** argv -- argument vector to send to. | |
118e6693 | 1016 | ** e -- the current envelope. |
d6b27179 EA |
1017 | ** |
1018 | ** Returns: | |
1019 | ** none. | |
1020 | ** | |
1021 | ** Side Effects: | |
1022 | ** puts all addresses on the argument vector onto the | |
1023 | ** send queue. | |
1024 | */ | |
1025 | ||
a4076aed | 1026 | sendtoargv(argv, e) |
d6b27179 | 1027 | register char **argv; |
a4076aed | 1028 | register ENVELOPE *e; |
d6b27179 EA |
1029 | { |
1030 | register char *p; | |
d6b27179 EA |
1031 | |
1032 | while ((p = *argv++) != NULL) | |
1033 | { | |
ed554bc5 | 1034 | (void) sendtolist(p, NULLADDR, &e->e_sendqueue, e); |
d6b27179 EA |
1035 | } |
1036 | } | |
1bf7c76b EA |
1037 | \f/* |
1038 | ** GETCTLADDR -- get controlling address from an address header. | |
1039 | ** | |
1040 | ** If none, get one corresponding to the effective userid. | |
1041 | ** | |
1042 | ** Parameters: | |
1043 | ** a -- the address to find the controller of. | |
1044 | ** | |
1045 | ** Returns: | |
1046 | ** the controlling address. | |
1047 | ** | |
1048 | ** Side Effects: | |
1049 | ** none. | |
1050 | */ | |
1051 | ||
1052 | ADDRESS * | |
1053 | getctladdr(a) | |
1054 | register ADDRESS *a; | |
1055 | { | |
2c1457f0 | 1056 | while (a != NULL && !bitset(QGOODUID, a->q_flags)) |
1bf7c76b | 1057 | a = a->q_alias; |
1bf7c76b EA |
1058 | return (a); |
1059 | } |