1 # include <pwd.h> 2 # include "sendmail.h" 3 # include <sys/stat.h> 4 5 SCCSID(@(#)recipient.c 3.46 11/18/82); 6 7 /* 8 ** SENDTO -- Designate a send list. 9 ** 10 ** The parameter is a comma-separated list of people to send to. 11 ** This routine arranges to send to all of them. 12 ** 13 ** Parameters: 14 ** list -- the send list. 15 ** ctladdr -- the address template for the person to 16 ** send to -- effective uid/gid are important. 17 ** This is typically the alias that caused this 18 ** expansion. 19 ** sendq -- a pointer to the head of a queue to put 20 ** these people into. 21 ** 22 ** Returns: 23 ** none 24 ** 25 ** Side Effects: 26 ** none. 27 */ 28 29 # define MAXRCRSN 10 30 31 sendto(list, ctladdr, sendq) 32 char *list; 33 ADDRESS *ctladdr; 34 ADDRESS **sendq; 35 { 36 register char *p; 37 register ADDRESS *al; /* list of addresses to send to */ 38 bool firstone; /* set on first address sent */ 39 bool selfref; /* set if this list includes ctladdr */ 40 41 # ifdef DEBUG 42 if (tTd(25, 1)) 43 { 44 printf("sendto: %s\n ctladdr=", list); 45 printaddr(ctladdr, FALSE); 46 } 47 # endif DEBUG 48 49 /* heuristic to determine old versus new style addresses */ 50 if (ctladdr == NULL && 51 (index(list, ',') != NULL || index(list, ';') != NULL || 52 index(list, '<') != NULL || index(list, '(') != NULL)) 53 CurEnv->e_oldstyle = FALSE; 54 55 firstone = TRUE; 56 selfref = FALSE; 57 al = NULL; 58 59 for (p = list; *p != '\0'; ) 60 { 61 register ADDRESS *a; 62 extern char *DelimChar; /* defined in prescan */ 63 64 /* parse the address */ 65 while (isspace(*p) || *p == ',') 66 p++; 67 a = parse(p, (ADDRESS *) NULL, 1); 68 p = DelimChar; 69 if (a == NULL) 70 continue; 71 a->q_next = al; 72 a->q_alias = ctladdr; 73 74 /* see if this should be marked as a primary address */ 75 if (ctladdr == NULL || 76 (firstone && *p == '\0' && bitset(QPRIMARY, ctladdr->q_flags))) 77 a->q_flags |= QPRIMARY; 78 79 /* put on send queue or suppress self-reference */ 80 if (ctladdr != NULL && sameaddr(ctladdr, a, FALSE)) 81 selfref = TRUE; 82 else 83 al = a; 84 firstone = FALSE; 85 } 86 87 /* if this alias doesn't include itself, delete ctladdr */ 88 if (!selfref && ctladdr != NULL) 89 ctladdr->q_flags |= QDONTSEND; 90 91 /* arrange to send to everyone on the local send list */ 92 while (al != NULL) 93 { 94 register ADDRESS *a = al; 95 96 al = a->q_next; 97 recipient(a, sendq); 98 99 /* arrange to inherit full name */ 100 if (a->q_fullname == NULL && ctladdr != NULL) 101 a->q_fullname = ctladdr->q_fullname; 102 } 103 104 CurEnv->e_to = NULL; 105 } 106 /* 107 ** RECIPIENT -- Designate a message recipient 108 ** 109 ** Saves the named person for future mailing. 110 ** 111 ** Parameters: 112 ** a -- the (preparsed) address header for the recipient. 113 ** sendq -- a pointer to the head of a queue to put the 114 ** recipient in. Duplicate supression is done 115 ** in this queue. 116 ** 117 ** Returns: 118 ** none. 119 ** 120 ** Side Effects: 121 ** none. 122 */ 123 124 recipient(a, sendq) 125 register ADDRESS *a; 126 register ADDRESS **sendq; 127 { 128 register ADDRESS *q; 129 ADDRESS **pq; 130 register struct mailer *m; 131 register char *p; 132 bool quoted = FALSE; /* set if the addr has a quote bit */ 133 char buf[MAXNAME]; /* unquoted image of the user name */ 134 extern ADDRESS *getctladdr(); 135 extern bool safefile(); 136 137 CurEnv->e_to = a->q_paddr; 138 m = a->q_mailer; 139 errno = 0; 140 # ifdef DEBUG 141 if (tTd(26, 1)) 142 { 143 printf("\nrecipient: "); 144 printaddr(a, FALSE); 145 } 146 # endif DEBUG 147 148 /* break aliasing loops */ 149 if (AliasLevel > MAXRCRSN) 150 { 151 usrerr("aliasing/forwarding loop broken"); 152 return; 153 } 154 155 /* 156 ** Finish setting up address structure. 157 */ 158 159 a->q_timeout = TimeOut; 160 161 (void) strcpy(buf, a->q_user); 162 for (p = buf; *p != '\0' && !quoted; p++) 163 { 164 if (!isascii(*p) && (*p & 0377) != (SpaceSub & 0377)) 165 quoted = TRUE; 166 } 167 stripquotes(buf, TRUE); 168 169 /* do sickly crude mapping for program mailing, etc. */ 170 if (m == LocalMailer && buf[0] == '|') 171 { 172 a->q_mailer = m = ProgMailer; 173 a->q_user++; 174 if (a->q_alias == NULL && !tTd(0, 1) && !QueueRun && !ForceMail) 175 { 176 usrerr("Cannot mail directly to programs"); 177 a->q_flags |= QDONTSEND; 178 } 179 } 180 181 /* 182 ** Look up this person in the recipient list. 183 ** If they are there already, return, otherwise continue. 184 ** If the list is empty, just add it. Notice the cute 185 ** hack to make from addresses suppress things correctly: 186 ** the QDONTSEND bit will be set in the send list. 187 ** [Please note: the emphasis is on "hack."] 188 */ 189 190 for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 191 { 192 if (!ForceMail && sameaddr(q, a, FALSE)) 193 { 194 # ifdef DEBUG 195 if (tTd(26, 1)) 196 { 197 printf("%s in sendq: ", a->q_paddr); 198 printaddr(q, FALSE); 199 } 200 # endif DEBUG 201 if (!bitset(QDONTSEND, a->q_flags)) 202 message(Arpa_Info, "duplicate suppressed"); 203 if (!bitset(QPRIMARY, q->q_flags)) 204 q->q_flags |= a->q_flags; 205 return; 206 } 207 } 208 209 /* add address on list */ 210 *pq = a; 211 a->q_next = NULL; 212 if (DontSend) 213 a->q_flags |= QDONTSEND; 214 215 /* 216 ** Alias the name and handle :include: specs. 217 */ 218 219 if (m == LocalMailer && !bitset(QDONTSEND, a->q_flags)) 220 { 221 if (strncmp(a->q_user, ":include:", 9) == 0) 222 { 223 a->q_flags |= QDONTSEND; 224 if (a->q_alias == NULL && !tTd(0, 1) && !QueueRun && !ForceMail) 225 usrerr("Cannot mail directly to :include:s"); 226 else 227 { 228 message(Arpa_Info, "including file %s", &a->q_user[9]); 229 include(&a->q_user[9], " sending", a, sendq); 230 } 231 } 232 else 233 alias(a, sendq); 234 } 235 236 /* 237 ** If the user is local and still being sent, verify that 238 ** the address is good. If it is, try to forward. 239 ** If the address is already good, we have a forwarding 240 ** loop. This can be broken by just sending directly to 241 ** the user (which is probably correct anyway). 242 */ 243 244 if (!bitset(QDONTSEND, a->q_flags) && m == LocalMailer) 245 { 246 struct stat stb; 247 extern bool writable(); 248 249 /* see if this is to a file */ 250 if (buf[0] == '/') 251 { 252 p = rindex(buf, '/'); 253 /* check if writable or creatable */ 254 if (a->q_alias == NULL && !tTd(0, 1) && !QueueRun && !ForceMail) 255 { 256 usrerr("Cannot mail directly to files"); 257 a->q_flags |= QDONTSEND; 258 } 259 else if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) : 260 (*p = '\0', !safefile(buf, getruid(), S_IWRITE|S_IEXEC))) 261 { 262 a->q_flags |= QBADADDR; 263 giveresponse(EX_CANTCREAT, TRUE, m); 264 } 265 } 266 else 267 { 268 register struct passwd *pw; 269 extern struct passwd *finduser(); 270 271 /* warning -- finduser may trash buf */ 272 pw = finduser(buf); 273 if (pw == NULL) 274 { 275 a->q_flags |= QBADADDR; 276 giveresponse(EX_NOUSER, TRUE, m); 277 } 278 else 279 { 280 char nbuf[MAXNAME]; 281 282 if (strcmp(a->q_user, pw->pw_name) != 0) 283 { 284 a->q_user = newstr(pw->pw_name); 285 (void) strcpy(buf, pw->pw_name); 286 } 287 a->q_home = newstr(pw->pw_dir); 288 a->q_uid = pw->pw_uid; 289 a->q_gid = pw->pw_gid; 290 a->q_flags |= QGOODUID; 291 buildfname(pw->pw_gecos, pw->pw_name, nbuf); 292 if (nbuf[0] != '\0') 293 a->q_fullname = newstr(nbuf); 294 if (!quoted) 295 forward(a, sendq); 296 } 297 } 298 } 299 } 300 /* 301 ** FINDUSER -- find the password entry for a user. 302 ** 303 ** This looks a lot like getpwnam, except that it may want to 304 ** do some fancier pattern matching in /etc/passwd. 305 ** 306 ** Parameters: 307 ** name -- the name to match against. 308 ** 309 ** Returns: 310 ** A pointer to a pw struct. 311 ** NULL if name is unknown or ambiguous. 312 ** 313 ** Side Effects: 314 ** may modify name. 315 */ 316 317 struct passwd * 318 finduser(name) 319 char *name; 320 { 321 extern struct passwd *getpwent(); 322 register struct passwd *pw; 323 register char *p; 324 325 /* 326 ** Make name canonical. 327 */ 328 329 for (p = name; *p != '\0'; p++) 330 { 331 if (*p == (SpaceSub & 0177) || *p == '_') 332 *p = ' '; 333 } 334 335 setpwent(); 336 while ((pw = getpwent()) != NULL) 337 { 338 char buf[MAXNAME]; 339 extern bool sameword(); 340 341 if (strcmp(pw->pw_name, name) == 0) 342 return (pw); 343 buildfname(pw->pw_gecos, pw->pw_name, buf); 344 if (index(buf, ' ') != NULL && sameword(buf, name)) 345 { 346 message(Arpa_Info, "sending to login name %s", pw->pw_name); 347 return (pw); 348 } 349 } 350 return (NULL); 351 } 352 /* 353 ** WRITABLE -- predicate returning if the file is writable. 354 ** 355 ** This routine must duplicate the algorithm in sys/fio.c. 356 ** Unfortunately, we cannot use the access call since we 357 ** won't necessarily be the real uid when we try to 358 ** actually open the file. 359 ** 360 ** Notice that ANY file with ANY execute bit is automatically 361 ** not writable. This is also enforced by mailfile. 362 ** 363 ** Parameters: 364 ** s -- pointer to a stat struct for the file. 365 ** 366 ** Returns: 367 ** TRUE -- if we will be able to write this file. 368 ** FALSE -- if we cannot write this file. 369 ** 370 ** Side Effects: 371 ** none. 372 */ 373 374 bool 375 writable(s) 376 register struct stat *s; 377 { 378 int euid, egid; 379 int bits; 380 381 if (bitset(0111, s->st_mode)) 382 return (FALSE); 383 euid = getruid(); 384 egid = getrgid(); 385 if (geteuid() == 0) 386 { 387 if (bitset(S_ISUID, s->st_mode)) 388 euid = s->st_uid; 389 if (bitset(S_ISGID, s->st_mode)) 390 egid = s->st_gid; 391 } 392 393 if (euid == 0) 394 return (TRUE); 395 bits = S_IWRITE; 396 if (euid != s->st_uid) 397 { 398 bits >>= 3; 399 if (egid != s->st_gid) 400 bits >>= 3; 401 } 402 return ((s->st_mode & bits) != 0); 403 } 404 /* 405 ** INCLUDE -- handle :include: specification. 406 ** 407 ** Parameters: 408 ** fname -- filename to include. 409 ** msg -- message to print in verbose mode. 410 ** ctladdr -- address template to use to fill in these 411 ** addresses -- effective user/group id are 412 ** the important things. 413 ** sendq -- a pointer to the head of the send queue 414 ** to put these addresses in. 415 ** 416 ** Returns: 417 ** none. 418 ** 419 ** Side Effects: 420 ** reads the :include: file and sends to everyone 421 ** listed in that file. 422 */ 423 424 include(fname, msg, ctladdr, sendq) 425 char *fname; 426 char *msg; 427 ADDRESS *ctladdr; 428 ADDRESS **sendq; 429 { 430 char buf[MAXLINE]; 431 register FILE *fp; 432 char *oldto = CurEnv->e_to; 433 434 fp = fopen(fname, "r"); 435 if (fp == NULL) 436 { 437 usrerr("Cannot open %s", fname); 438 return; 439 } 440 if (getctladdr(ctladdr) == NULL) 441 { 442 struct stat st; 443 444 if (fstat(fileno(fp), &st) < 0) 445 syserr("Cannot fstat %s!", fname); 446 ctladdr->q_uid = st.st_uid; 447 ctladdr->q_gid = st.st_gid; 448 ctladdr->q_flags |= QGOODUID; 449 } 450 451 /* read the file -- each line is a comma-separated list. */ 452 while (fgets(buf, sizeof buf, fp) != NULL) 453 { 454 register char *p = index(buf, '\n'); 455 456 if (p != NULL) 457 *p = '\0'; 458 if (buf[0] == '\0') 459 continue; 460 CurEnv->e_to = oldto; 461 message(Arpa_Info, "%s to %s", msg, buf); 462 AliasLevel++; 463 sendto(buf, ctladdr, sendq); 464 AliasLevel--; 465 } 466 467 (void) fclose(fp); 468 } 469 /* 470 ** SENDTOARGV -- send to an argument vector. 471 ** 472 ** Parameters: 473 ** argv -- argument vector to send to. 474 ** 475 ** Returns: 476 ** none. 477 ** 478 ** Side Effects: 479 ** puts all addresses on the argument vector onto the 480 ** send queue. 481 */ 482 483 sendtoargv(argv) 484 register char **argv; 485 { 486 register char *p; 487 extern bool sameword(); 488 489 while ((p = *argv++) != NULL) 490 { 491 if (argv[0] != NULL && argv[1] != NULL && sameword(argv[0], "at")) 492 { 493 char nbuf[MAXNAME]; 494 495 if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf) 496 usrerr("address overflow"); 497 else 498 { 499 (void) strcpy(nbuf, p); 500 (void) strcat(nbuf, "@"); 501 (void) strcat(nbuf, argv[1]); 502 p = newstr(nbuf); 503 argv += 2; 504 } 505 } 506 sendto(p, (ADDRESS *) NULL, &CurEnv->e_sendqueue); 507 } 508 } 509 /* 510 ** GETCTLADDR -- get controlling address from an address header. 511 ** 512 ** If none, get one corresponding to the effective userid. 513 ** 514 ** Parameters: 515 ** a -- the address to find the controller of. 516 ** 517 ** Returns: 518 ** the controlling address. 519 ** 520 ** Side Effects: 521 ** none. 522 */ 523 524 ADDRESS * 525 getctladdr(a) 526 register ADDRESS *a; 527 { 528 while (a != NULL && !bitset(QGOODUID, a->q_flags)) 529 a = a->q_alias; 530 return (a); 531 } 532