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