Commit | Line | Data |
---|---|---|
b2a81223 | 1 | /* |
dc45ba8c | 2 | * Copyright (c) 1983 Eric P. Allman |
bee79b64 KB |
3 | * Copyright (c) 1988 Regents of the University of California. |
4 | * All rights reserved. | |
5 | * | |
417f7a11 | 6 | * %sccs.include.redist.c% |
bee79b64 | 7 | */ |
b2a81223 DF |
8 | |
9 | #ifndef lint | |
0df908a9 | 10 | static char sccsid[] = "@(#)recipient.c 5.19 (Berkeley) %G%"; |
bee79b64 | 11 | #endif /* not lint */ |
b2a81223 | 12 | |
611050b6 KB |
13 | # include <sys/types.h> |
14 | # include <sys/stat.h> | |
6eefe4f6 | 15 | # include <pwd.h> |
6eefe4f6 | 16 | # include "sendmail.h" |
6eefe4f6 | 17 | |
6eefe4f6 | 18 | /* |
811a6cf3 | 19 | ** SENDTOLIST -- Designate a send list. |
6eefe4f6 EA |
20 | ** |
21 | ** The parameter is a comma-separated list of people to send to. | |
22 | ** This routine arranges to send to all of them. | |
23 | ** | |
abae7b2d EA |
24 | ** The `ctladdr' is the address that expanded to be this one, |
25 | ** e.g., in an alias expansion. This is used for a number of | |
26 | ** purposed, most notably inheritance of uid/gid for protection | |
27 | ** purposes. It is also used to detect self-reference in group | |
28 | ** expansions and the like. | |
29 | ** | |
6eefe4f6 EA |
30 | ** Parameters: |
31 | ** list -- the send list. | |
1bf7c76b EA |
32 | ** ctladdr -- the address template for the person to |
33 | ** send to -- effective uid/gid are important. | |
d4f42161 EA |
34 | ** This is typically the alias that caused this |
35 | ** expansion. | |
36 | ** sendq -- a pointer to the head of a queue to put | |
37 | ** these people into. | |
abae7b2d | 38 | ** qflags -- special flags to set in the q_flags field. |
6eefe4f6 EA |
39 | ** |
40 | ** Returns: | |
abae7b2d | 41 | ** pointer to chain of addresses. |
6eefe4f6 EA |
42 | ** |
43 | ** Side Effects: | |
44 | ** none. | |
45 | */ | |
46 | ||
47 | # define MAXRCRSN 10 | |
48 | ||
abae7b2d EA |
49 | ADDRESS * |
50 | sendto(list, copyf, ctladdr, qflags) | |
6eefe4f6 | 51 | char *list; |
1bf7c76b | 52 | ADDRESS *ctladdr; |
4e5e456f | 53 | ADDRESS **sendq; |
abae7b2d | 54 | u_short qflags; |
6eefe4f6 EA |
55 | { |
56 | register char *p; | |
7b955214 | 57 | register ADDRESS *al; /* list of addresses to send to */ |
92f12b98 | 58 | bool firstone; /* set on first address sent */ |
331b7c9f | 59 | bool selfref; /* set if this list includes ctladdr */ |
d3f52e20 | 60 | char delimiter; /* the address delimiter */ |
abae7b2d EA |
61 | ADDRESS *sibl; /* sibling pointer in tree */ |
62 | ADDRESS *prev; /* previous sibling */ | |
d6b27179 | 63 | |
9678c96d | 64 | if (tTd(25, 1)) |
331b7c9f EA |
65 | { |
66 | printf("sendto: %s\n ctladdr=", list); | |
67 | printaddr(ctladdr, FALSE); | |
68 | } | |
6eefe4f6 | 69 | |
7b955214 | 70 | /* heuristic to determine old versus new style addresses */ |
a2983993 EA |
71 | if (ctladdr == NULL && |
72 | (index(list, ',') != NULL || index(list, ';') != NULL || | |
73 | index(list, '<') != NULL || index(list, '(') != NULL)) | |
e6f08ab1 | 74 | CurEnv->e_flags &= ~EF_OLDSTYLE; |
d3f52e20 EA |
75 | delimiter = ' '; |
76 | if (!bitset(EF_OLDSTYLE, CurEnv->e_flags) || ctladdr != NULL) | |
77 | delimiter = ','; | |
7b955214 | 78 | |
92f12b98 | 79 | firstone = TRUE; |
331b7c9f | 80 | selfref = FALSE; |
d6b27179 | 81 | al = NULL; |
7b955214 | 82 | |
506fc377 | 83 | for (p = list; *p != '\0'; ) |
6eefe4f6 | 84 | { |
506fc377 EA |
85 | register ADDRESS *a; |
86 | extern char *DelimChar; /* defined in prescan */ | |
6eefe4f6 EA |
87 | |
88 | /* parse the address */ | |
506fc377 EA |
89 | while (isspace(*p) || *p == ',') |
90 | p++; | |
d3f52e20 | 91 | a = parseaddr(p, (ADDRESS *) NULL, 1, delimiter); |
506fc377 | 92 | p = DelimChar; |
b9fadd5b EA |
93 | if (a == NULL) |
94 | continue; | |
d6b27179 | 95 | a->q_next = al; |
1bf7c76b | 96 | a->q_alias = ctladdr; |
abae7b2d EA |
97 | if (ctladdr != NULL) |
98 | a->q_flags |= ctladdr->q_flags & ~QPRIMARY; | |
99 | a->q_flags |= qflags; | |
331b7c9f EA |
100 | |
101 | /* see if this should be marked as a primary address */ | |
92f12b98 | 102 | if (ctladdr == NULL || |
506fc377 | 103 | (firstone && *p == '\0' && bitset(QPRIMARY, ctladdr->q_flags))) |
92f12b98 | 104 | a->q_flags |= QPRIMARY; |
331b7c9f EA |
105 | |
106 | /* put on send queue or suppress self-reference */ | |
7338e3d4 | 107 | if (ctladdr != NULL && sameaddr(ctladdr, a)) |
331b7c9f EA |
108 | selfref = TRUE; |
109 | else | |
110 | al = a; | |
92f12b98 | 111 | firstone = FALSE; |
d6b27179 EA |
112 | } |
113 | ||
331b7c9f EA |
114 | /* if this alias doesn't include itself, delete ctladdr */ |
115 | if (!selfref && ctladdr != NULL) | |
116 | ctladdr->q_flags |= QDONTSEND; | |
117 | ||
d6b27179 | 118 | /* arrange to send to everyone on the local send list */ |
abae7b2d EA |
119 | prev = sibl = NULL; |
120 | if (ctladdr != NULL) | |
121 | prev = ctladdr->q_child; | |
d6b27179 EA |
122 | while (al != NULL) |
123 | { | |
124 | register ADDRESS *a = al; | |
abae7b2d | 125 | extern ADDRESS *recipient(); |
d344c0b7 | 126 | extern ADDRESS *recipient(); |
d6b27179 EA |
127 | |
128 | al = a->q_next; | |
3fbc69d6 | 129 | setctladdr(a); |
abae7b2d EA |
130 | sibl = recipient(a); |
131 | if (sibl != NULL) | |
132 | { | |
133 | extern ADDRESS *addrref(); | |
134 | ||
135 | /* inherit full name */ | |
136 | if (sibl->q_fullname == NULL && ctladdr != NULL) | |
137 | sibl->q_fullname = ctladdr->q_fullname; | |
138 | ||
139 | /* link tree together (but only if the node is new) */ | |
140 | if (sibl == a) | |
141 | { | |
142 | sibl->q_sibling = prev; | |
143 | prev = sibl; | |
144 | } | |
145 | } | |
6eefe4f6 | 146 | } |
d6b27179 | 147 | |
2654b031 | 148 | CurEnv->e_to = NULL; |
abae7b2d EA |
149 | if (ctladdr != NULL) |
150 | ctladdr->q_child = prev; | |
151 | return (prev); | |
152 | } | |
153 | \f/* | |
154 | ** ADDRREF -- return pointer to address that references another address. | |
155 | ** | |
156 | ** Parameters: | |
157 | ** a -- address to check. | |
158 | ** r -- reference to find. | |
159 | ** | |
160 | ** Returns: | |
161 | ** address of node in tree rooted at 'a' that references | |
162 | ** 'r'. | |
163 | ** NULL if no such node exists. | |
164 | ** | |
165 | ** Side Effects: | |
166 | ** none. | |
167 | */ | |
168 | ||
169 | ADDRESS * | |
170 | addrref(a, r) | |
171 | register ADDRESS *a; | |
172 | register ADDRESS *r; | |
173 | { | |
174 | register ADDRESS *q; | |
175 | ||
176 | while (a != NULL) | |
177 | { | |
178 | if (a->q_child == r || a->q_sibling == r) | |
179 | return (a); | |
180 | q = addrref(a->q_child, r); | |
181 | if (q != NULL) | |
182 | return (q); | |
183 | a = a->q_sibling; | |
184 | } | |
185 | return (NULL); | |
6eefe4f6 EA |
186 | } |
187 | \f/* | |
188 | ** RECIPIENT -- Designate a message recipient | |
189 | ** | |
190 | ** Saves the named person for future mailing. | |
191 | ** | |
192 | ** Parameters: | |
193 | ** a -- the (preparsed) address header for the recipient. | |
d4f42161 EA |
194 | ** sendq -- a pointer to the head of a queue to put the |
195 | ** recipient in. Duplicate supression is done | |
196 | ** in this queue. | |
6eefe4f6 EA |
197 | ** |
198 | ** Returns: | |
abae7b2d | 199 | ** pointer to address actually inserted in send list. |
6eefe4f6 EA |
200 | ** |
201 | ** Side Effects: | |
202 | ** none. | |
203 | */ | |
204 | ||
0df908a9 KB |
205 | extern ADDRESS *getctladdr(); |
206 | ||
d344c0b7 | 207 | ADDRESS * |
abae7b2d | 208 | ADDRESS * |
d4f42161 | 209 | recipient(a, sendq) |
6eefe4f6 | 210 | register ADDRESS *a; |
d4f42161 | 211 | register ADDRESS **sendq; |
6eefe4f6 EA |
212 | { |
213 | register ADDRESS *q; | |
74c5fe7c | 214 | ADDRESS **pq; |
6eefe4f6 | 215 | register struct mailer *m; |
98f46225 EA |
216 | register char *p; |
217 | bool quoted = FALSE; /* set if the addr has a quote bit */ | |
218 | char buf[MAXNAME]; /* unquoted image of the user name */ | |
ed45aae1 | 219 | extern bool safefile(); |
6eefe4f6 | 220 | |
2654b031 | 221 | CurEnv->e_to = a->q_paddr; |
179c1218 | 222 | m = a->q_mailer; |
6eefe4f6 | 223 | errno = 0; |
9678c96d | 224 | if (tTd(26, 1)) |
331b7c9f EA |
225 | { |
226 | printf("\nrecipient: "); | |
227 | printaddr(a, FALSE); | |
228 | } | |
6eefe4f6 EA |
229 | |
230 | /* break aliasing loops */ | |
231 | if (AliasLevel > MAXRCRSN) | |
232 | { | |
233 | usrerr("aliasing/forwarding loop broken"); | |
abae7b2d | 234 | return (NULL); |
6eefe4f6 EA |
235 | } |
236 | ||
237 | /* | |
ed45aae1 | 238 | ** Finish setting up address structure. |
6eefe4f6 EA |
239 | */ |
240 | ||
0fe3917f | 241 | /* set the queue timeout */ |
ed45aae1 EA |
242 | a->q_timeout = TimeOut; |
243 | ||
0fe3917f EA |
244 | /* map user & host to lower case if requested on non-aliases */ |
245 | if (a->q_alias == NULL) | |
246 | loweraddr(a); | |
247 | ||
248 | /* get unquoted user for file, program or user.name check */ | |
98f46225 EA |
249 | (void) strcpy(buf, a->q_user); |
250 | for (p = buf; *p != '\0' && !quoted; p++) | |
251 | { | |
252 | if (!isascii(*p) && (*p & 0377) != (SpaceSub & 0377)) | |
253 | quoted = TRUE; | |
254 | } | |
255 | stripquotes(buf, TRUE); | |
256 | ||
ed45aae1 | 257 | /* do sickly crude mapping for program mailing, etc. */ |
98f46225 | 258 | if (m == LocalMailer && buf[0] == '|') |
6eefe4f6 | 259 | { |
98f46225 EA |
260 | a->q_mailer = m = ProgMailer; |
261 | a->q_user++; | |
2b95e89d | 262 | if (a->q_alias == NULL && !QueueRun && !ForceMail) |
6eefe4f6 | 263 | { |
315314bd | 264 | a->q_flags |= QDONTSEND|QBADADDR; |
4c34b183 | 265 | usrerr("Cannot mail directly to programs"); |
6eefe4f6 EA |
266 | } |
267 | } | |
268 | ||
269 | /* | |
b9ca6d11 EA |
270 | ** Look up this person in the recipient list. |
271 | ** If they are there already, return, otherwise continue. | |
272 | ** If the list is empty, just add it. Notice the cute | |
273 | ** hack to make from addresses suppress things correctly: | |
274 | ** the QDONTSEND bit will be set in the send list. | |
275 | ** [Please note: the emphasis is on "hack."] | |
6eefe4f6 EA |
276 | */ |
277 | ||
d4f42161 | 278 | for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) |
6eefe4f6 | 279 | { |
7338e3d4 | 280 | if (!ForceMail && sameaddr(q, a)) |
6eefe4f6 | 281 | { |
9678c96d | 282 | if (tTd(26, 1)) |
331b7c9f EA |
283 | { |
284 | printf("%s in sendq: ", a->q_paddr); | |
285 | printaddr(q, FALSE); | |
286 | } | |
abae7b2d | 287 | if (Verbose && !bitset(QDONTSEND|QPSEUDO, a->q_flags)) |
d6b27179 | 288 | message(Arpa_Info, "duplicate suppressed"); |
92f12b98 EA |
289 | if (!bitset(QPRIMARY, q->q_flags)) |
290 | q->q_flags |= a->q_flags; | |
abae7b2d EA |
291 | if (!bitset(QPSEUDO, a->q_flags)) |
292 | q->q_flags &= ~QPSEUDO; | |
293 | return (q); | |
6eefe4f6 | 294 | } |
6eefe4f6 | 295 | } |
74c5fe7c EA |
296 | |
297 | /* add address on list */ | |
298 | *pq = a; | |
6eefe4f6 | 299 | a->q_next = NULL; |
06ddddfc | 300 | CurEnv->e_nrcpts++; |
6eefe4f6 EA |
301 | |
302 | /* | |
303 | ** Alias the name and handle :include: specs. | |
304 | */ | |
305 | ||
98f46225 | 306 | if (m == LocalMailer && !bitset(QDONTSEND, a->q_flags)) |
6eefe4f6 EA |
307 | { |
308 | if (strncmp(a->q_user, ":include:", 9) == 0) | |
309 | { | |
310 | a->q_flags |= QDONTSEND; | |
2b95e89d | 311 | if (a->q_alias == NULL && !QueueRun && !ForceMail) |
315314bd EA |
312 | { |
313 | a->q_flags |= QBADADDR; | |
1bf7c76b | 314 | usrerr("Cannot mail directly to :include:s"); |
315314bd | 315 | } |
1bf7c76b EA |
316 | else |
317 | { | |
91f69adf | 318 | message(Arpa_Info, "including file %s", &a->q_user[9]); |
d4f42161 | 319 | include(&a->q_user[9], " sending", a, sendq); |
1bf7c76b | 320 | } |
6eefe4f6 EA |
321 | } |
322 | else | |
d4f42161 | 323 | alias(a, sendq); |
6eefe4f6 EA |
324 | } |
325 | ||
326 | /* | |
327 | ** If the user is local and still being sent, verify that | |
328 | ** the address is good. If it is, try to forward. | |
329 | ** If the address is already good, we have a forwarding | |
330 | ** loop. This can be broken by just sending directly to | |
331 | ** the user (which is probably correct anyway). | |
332 | */ | |
333 | ||
98f46225 | 334 | if (!bitset(QDONTSEND, a->q_flags) && m == LocalMailer) |
6eefe4f6 | 335 | { |
a0554f81 EA |
336 | struct stat stb; |
337 | extern bool writable(); | |
6eefe4f6 EA |
338 | |
339 | /* see if this is to a file */ | |
d4d03212 | 340 | if (buf[0] == '/') |
6eefe4f6 | 341 | { |
d4d03212 | 342 | p = rindex(buf, '/'); |
9d3b45b8 | 343 | /* check if writable or creatable */ |
2b95e89d | 344 | if (a->q_alias == NULL && !QueueRun && !ForceMail) |
1bf7c76b | 345 | { |
315314bd | 346 | a->q_flags |= QDONTSEND|QBADADDR; |
4c34b183 | 347 | usrerr("Cannot mail directly to files"); |
1bf7c76b EA |
348 | } |
349 | else if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) : | |
f6a0cc15 | 350 | (*p = '\0', !safefile(buf, getruid(), S_IWRITE|S_IEXEC))) |
6eefe4f6 EA |
351 | { |
352 | a->q_flags |= QBADADDR; | |
baa0c390 | 353 | giveresponse(EX_CANTCREAT, m, CurEnv); |
6eefe4f6 EA |
354 | } |
355 | } | |
356 | else | |
357 | { | |
358 | register struct passwd *pw; | |
ff3e3c1c EA |
359 | extern struct passwd *finduser(); |
360 | ||
29c33ff6 | 361 | /* warning -- finduser may trash buf */ |
ff3e3c1c | 362 | pw = finduser(buf); |
6eefe4f6 EA |
363 | if (pw == NULL) |
364 | { | |
365 | a->q_flags |= QBADADDR; | |
baa0c390 | 366 | giveresponse(EX_NOUSER, m, CurEnv); |
6eefe4f6 EA |
367 | } |
368 | else | |
369 | { | |
abae7b2d EA |
370 | char nbuf[MAXNAME]; |
371 | ||
f77d50ee EA |
372 | char nbuf[MAXNAME]; |
373 | ||
2b5e3c25 EA |
374 | if (strcmp(a->q_user, pw->pw_name) != 0) |
375 | { | |
376 | a->q_user = newstr(pw->pw_name); | |
f9566d23 | 377 | (void) strcpy(buf, pw->pw_name); |
2b5e3c25 | 378 | } |
6eefe4f6 | 379 | a->q_home = newstr(pw->pw_dir); |
9c3f729b | 380 | a->q_uid = pw->pw_uid; |
1bf7c76b | 381 | a->q_gid = pw->pw_gid; |
2c1457f0 | 382 | a->q_flags |= QGOODUID; |
f77d50ee EA |
383 | buildfname(pw->pw_gecos, pw->pw_name, nbuf); |
384 | if (nbuf[0] != '\0') | |
385 | a->q_fullname = newstr(nbuf); | |
abae7b2d EA |
386 | fullname(pw, nbuf); |
387 | if (nbuf[0] != '\0') | |
388 | a->q_fullname = newstr(nbuf); | |
1bf7c76b | 389 | if (!quoted) |
d4f42161 | 390 | forward(a, sendq); |
6eefe4f6 EA |
391 | } |
392 | } | |
393 | } | |
d344c0b7 | 394 | return (a); |
abae7b2d EA |
395 | |
396 | return (a); | |
6eefe4f6 EA |
397 | } |
398 | \f/* | |
ff3e3c1c EA |
399 | ** FINDUSER -- find the password entry for a user. |
400 | ** | |
401 | ** This looks a lot like getpwnam, except that it may want to | |
402 | ** do some fancier pattern matching in /etc/passwd. | |
403 | ** | |
7338e3d4 EA |
404 | ** This routine contains most of the time of many sendmail runs. |
405 | ** It deserves to be optimized. | |
406 | ** | |
ff3e3c1c EA |
407 | ** Parameters: |
408 | ** name -- the name to match against. | |
409 | ** | |
410 | ** Returns: | |
411 | ** A pointer to a pw struct. | |
412 | ** NULL if name is unknown or ambiguous. | |
413 | ** | |
414 | ** Side Effects: | |
29c33ff6 | 415 | ** may modify name. |
ff3e3c1c EA |
416 | */ |
417 | ||
418 | struct passwd * | |
419 | finduser(name) | |
420 | char *name; | |
421 | { | |
2b5e3c25 | 422 | register struct passwd *pw; |
29c33ff6 | 423 | register char *p; |
f74d8dce EA |
424 | extern struct passwd *getpwent(); |
425 | extern struct passwd *getpwnam(); | |
29c33ff6 | 426 | |
639d8b98 | 427 | /* map upper => lower case */ |
29c33ff6 EA |
428 | for (p = name; *p != '\0'; p++) |
429 | { | |
639d8b98 | 430 | if (isascii(*p) && isupper(*p)) |
577bce94 | 431 | *p = tolower(*p); |
29c33ff6 | 432 | } |
ff3e3c1c | 433 | |
639d8b98 | 434 | /* look up this login name using fast path */ |
77b16ff1 EA |
435 | if ((pw = getpwnam(name)) != NULL) |
436 | return (pw); | |
437 | ||
438 | /* search for a matching full name instead */ | |
639d8b98 EA |
439 | for (p = name; *p != '\0'; p++) |
440 | { | |
441 | if (*p == (SpaceSub & 0177) || *p == '_') | |
442 | *p = ' '; | |
443 | } | |
03388044 | 444 | (void) setpwent(); |
2b5e3c25 EA |
445 | while ((pw = getpwent()) != NULL) |
446 | { | |
abae7b2d | 447 | char buf[MAXNAME]; |
2b5e3c25 | 448 | |
abae7b2d | 449 | fullname(pw, buf); |
ed73ef1d | 450 | if (index(buf, ' ') != NULL && !strcasecmp(buf, name)) |
36292825 | 451 | { |
abae7b2d EA |
452 | message(Arpa_Info, "sending to %s <%s>", |
453 | buf, pw->pw_name); | |
2b5e3c25 | 454 | return (pw); |
36292825 | 455 | } |
2b5e3c25 EA |
456 | } |
457 | return (NULL); | |
ff3e3c1c EA |
458 | } |
459 | \f/* | |
a0554f81 EA |
460 | ** WRITABLE -- predicate returning if the file is writable. |
461 | ** | |
462 | ** This routine must duplicate the algorithm in sys/fio.c. | |
463 | ** Unfortunately, we cannot use the access call since we | |
464 | ** won't necessarily be the real uid when we try to | |
465 | ** actually open the file. | |
466 | ** | |
467 | ** Notice that ANY file with ANY execute bit is automatically | |
468 | ** not writable. This is also enforced by mailfile. | |
469 | ** | |
470 | ** Parameters: | |
471 | ** s -- pointer to a stat struct for the file. | |
472 | ** | |
473 | ** Returns: | |
474 | ** TRUE -- if we will be able to write this file. | |
475 | ** FALSE -- if we cannot write this file. | |
476 | ** | |
477 | ** Side Effects: | |
478 | ** none. | |
479 | */ | |
480 | ||
481 | bool | |
482 | writable(s) | |
483 | register struct stat *s; | |
484 | { | |
485 | int euid, egid; | |
486 | int bits; | |
487 | ||
488 | if (bitset(0111, s->st_mode)) | |
489 | return (FALSE); | |
490 | euid = getruid(); | |
491 | egid = getrgid(); | |
492 | if (geteuid() == 0) | |
493 | { | |
494 | if (bitset(S_ISUID, s->st_mode)) | |
495 | euid = s->st_uid; | |
496 | if (bitset(S_ISGID, s->st_mode)) | |
497 | egid = s->st_gid; | |
498 | } | |
499 | ||
500 | if (euid == 0) | |
501 | return (TRUE); | |
502 | bits = S_IWRITE; | |
503 | if (euid != s->st_uid) | |
504 | { | |
505 | bits >>= 3; | |
506 | if (egid != s->st_gid) | |
507 | bits >>= 3; | |
508 | } | |
509 | return ((s->st_mode & bits) != 0); | |
510 | } | |
511 | \f/* | |
6eefe4f6 EA |
512 | ** INCLUDE -- handle :include: specification. |
513 | ** | |
514 | ** Parameters: | |
515 | ** fname -- filename to include. | |
23008226 | 516 | ** msg -- message to print in verbose mode. |
1bf7c76b EA |
517 | ** ctladdr -- address template to use to fill in these |
518 | ** addresses -- effective user/group id are | |
519 | ** the important things. | |
d4f42161 EA |
520 | ** sendq -- a pointer to the head of the send queue |
521 | ** to put these addresses in. | |
6eefe4f6 EA |
522 | ** |
523 | ** Returns: | |
524 | ** none. | |
525 | ** | |
526 | ** Side Effects: | |
527 | ** reads the :include: file and sends to everyone | |
528 | ** listed in that file. | |
529 | */ | |
530 | ||
d4f42161 | 531 | include(fname, msg, ctladdr, sendq) |
6eefe4f6 | 532 | char *fname; |
23008226 | 533 | char *msg; |
1bf7c76b | 534 | ADDRESS *ctladdr; |
d4f42161 | 535 | ADDRESS **sendq; |
6eefe4f6 EA |
536 | { |
537 | char buf[MAXLINE]; | |
538 | register FILE *fp; | |
2654b031 | 539 | char *oldto = CurEnv->e_to; |
7338e3d4 EA |
540 | char *oldfilename = FileName; |
541 | int oldlinenumber = LineNumber; | |
6eefe4f6 | 542 | |
6eefe4f6 EA |
543 | fp = fopen(fname, "r"); |
544 | if (fp == NULL) | |
545 | { | |
546 | usrerr("Cannot open %s", fname); | |
547 | return; | |
548 | } | |
962c3fb2 EA |
549 | if (getctladdr(ctladdr) == NULL) |
550 | { | |
551 | struct stat st; | |
552 | ||
553 | if (fstat(fileno(fp), &st) < 0) | |
554 | syserr("Cannot fstat %s!", fname); | |
555 | ctladdr->q_uid = st.st_uid; | |
556 | ctladdr->q_gid = st.st_gid; | |
557 | ctladdr->q_flags |= QGOODUID; | |
558 | } | |
6eefe4f6 EA |
559 | |
560 | /* read the file -- each line is a comma-separated list. */ | |
7338e3d4 EA |
561 | FileName = fname; |
562 | LineNumber = 0; | |
6eefe4f6 EA |
563 | while (fgets(buf, sizeof buf, fp) != NULL) |
564 | { | |
565 | register char *p = index(buf, '\n'); | |
566 | ||
dd0758e5 | 567 | LineNumber++; |
6eefe4f6 EA |
568 | if (p != NULL) |
569 | *p = '\0'; | |
570 | if (buf[0] == '\0') | |
571 | continue; | |
2654b031 | 572 | CurEnv->e_to = oldto; |
91f69adf | 573 | message(Arpa_Info, "%s to %s", msg, buf); |
23008226 | 574 | AliasLevel++; |
abae7b2d | 575 | sendto(buf, 1, ctladdr, 0); |
23008226 | 576 | AliasLevel--; |
6eefe4f6 EA |
577 | } |
578 | ||
74c5fe7c | 579 | (void) fclose(fp); |
7338e3d4 EA |
580 | FileName = oldfilename; |
581 | LineNumber = oldlinenumber; | |
6eefe4f6 | 582 | } |
d6b27179 EA |
583 | \f/* |
584 | ** SENDTOARGV -- send to an argument vector. | |
585 | ** | |
586 | ** Parameters: | |
587 | ** argv -- argument vector to send to. | |
588 | ** | |
589 | ** Returns: | |
590 | ** none. | |
591 | ** | |
592 | ** Side Effects: | |
593 | ** puts all addresses on the argument vector onto the | |
594 | ** send queue. | |
595 | */ | |
596 | ||
597 | sendtoargv(argv) | |
598 | register char **argv; | |
599 | { | |
600 | register char *p; | |
d6b27179 EA |
601 | |
602 | while ((p = *argv++) != NULL) | |
603 | { | |
ed73ef1d | 604 | if (argv[0] != NULL && argv[1] != NULL && !strcasecmp(argv[0], "at")) |
d6b27179 EA |
605 | { |
606 | char nbuf[MAXNAME]; | |
607 | ||
608 | if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf) | |
609 | usrerr("address overflow"); | |
610 | else | |
611 | { | |
612 | (void) strcpy(nbuf, p); | |
613 | (void) strcat(nbuf, "@"); | |
614 | (void) strcat(nbuf, argv[1]); | |
615 | p = newstr(nbuf); | |
616 | argv += 2; | |
617 | } | |
618 | } | |
abae7b2d | 619 | sendto(p, 0, (ADDRESS *) NULL, 0); |
d6b27179 EA |
620 | } |
621 | } | |
1bf7c76b EA |
622 | \f/* |
623 | ** GETCTLADDR -- get controlling address from an address header. | |
624 | ** | |
625 | ** If none, get one corresponding to the effective userid. | |
626 | ** | |
627 | ** Parameters: | |
628 | ** a -- the address to find the controller of. | |
629 | ** | |
630 | ** Returns: | |
631 | ** the controlling address. | |
632 | ** | |
633 | ** Side Effects: | |
634 | ** none. | |
635 | */ | |
636 | ||
637 | ADDRESS * | |
638 | getctladdr(a) | |
639 | register ADDRESS *a; | |
640 | { | |
2c1457f0 | 641 | while (a != NULL && !bitset(QGOODUID, a->q_flags)) |
1bf7c76b | 642 | a = a->q_alias; |
1bf7c76b EA |
643 | return (a); |
644 | } |