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