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