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