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