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