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.13 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 a->q_home = newstr(pw->pw_dir); 225 a->q_uid = pw->pw_uid; 226 if (strcmp(buf, a->q_user) == 0) 227 forward(a); 228 } 229 } 230 } 231 } 232 /* 233 ** FINDUSER -- find the password entry for a user. 234 ** 235 ** This looks a lot like getpwnam, except that it may want to 236 ** do some fancier pattern matching in /etc/passwd. 237 ** 238 ** Parameters: 239 ** name -- the name to match against. 240 ** 241 ** Returns: 242 ** A pointer to a pw struct. 243 ** NULL if name is unknown or ambiguous. 244 ** 245 ** Side Effects: 246 ** none. 247 */ 248 249 struct passwd * 250 finduser(name) 251 char *name; 252 { 253 extern struct passwd *getpwnam(); 254 255 return (getpwnam(name)); 256 } 257 /* 258 ** WRITABLE -- predicate returning if the file is writable. 259 ** 260 ** This routine must duplicate the algorithm in sys/fio.c. 261 ** Unfortunately, we cannot use the access call since we 262 ** won't necessarily be the real uid when we try to 263 ** actually open the file. 264 ** 265 ** Notice that ANY file with ANY execute bit is automatically 266 ** not writable. This is also enforced by mailfile. 267 ** 268 ** Parameters: 269 ** s -- pointer to a stat struct for the file. 270 ** 271 ** Returns: 272 ** TRUE -- if we will be able to write this file. 273 ** FALSE -- if we cannot write this file. 274 ** 275 ** Side Effects: 276 ** none. 277 */ 278 279 bool 280 writable(s) 281 register struct stat *s; 282 { 283 int euid, egid; 284 int bits; 285 286 if (bitset(0111, s->st_mode)) 287 return (FALSE); 288 euid = getruid(); 289 egid = getrgid(); 290 if (geteuid() == 0) 291 { 292 if (bitset(S_ISUID, s->st_mode)) 293 euid = s->st_uid; 294 if (bitset(S_ISGID, s->st_mode)) 295 egid = s->st_gid; 296 } 297 298 if (euid == 0) 299 return (TRUE); 300 bits = S_IWRITE; 301 if (euid != s->st_uid) 302 { 303 bits >>= 3; 304 if (egid != s->st_gid) 305 bits >>= 3; 306 } 307 return ((s->st_mode & bits) != 0); 308 } 309 /* 310 ** INCLUDE -- handle :include: specification. 311 ** 312 ** Parameters: 313 ** fname -- filename to include. 314 ** msg -- message to print in verbose mode. 315 ** 316 ** Returns: 317 ** none. 318 ** 319 ** Side Effects: 320 ** reads the :include: file and sends to everyone 321 ** listed in that file. 322 */ 323 324 include(fname, msg) 325 char *fname; 326 char *msg; 327 { 328 char buf[MAXLINE]; 329 register FILE *fp; 330 char *oldto = To; 331 332 fp = fopen(fname, "r"); 333 if (fp == NULL) 334 { 335 usrerr("Cannot open %s", fname); 336 return; 337 } 338 339 /* read the file -- each line is a comma-separated list. */ 340 while (fgets(buf, sizeof buf, fp) != NULL) 341 { 342 register char *p = index(buf, '\n'); 343 344 if (p != NULL) 345 *p = '\0'; 346 if (buf[0] == '\0') 347 continue; 348 To = oldto; 349 if (Verbose) 350 message(Arpa_Info, "%s to %s", msg, buf); 351 AliasLevel++; 352 sendto(buf, 1); 353 AliasLevel--; 354 } 355 356 (void) fclose(fp); 357 } 358 /* 359 ** SENDTOARGV -- send to an argument vector. 360 ** 361 ** Parameters: 362 ** argv -- argument vector to send to. 363 ** 364 ** Returns: 365 ** none. 366 ** 367 ** Side Effects: 368 ** puts all addresses on the argument vector onto the 369 ** send queue. 370 */ 371 372 sendtoargv(argv) 373 register char **argv; 374 { 375 register char *p; 376 extern bool sameword(); 377 378 while ((p = *argv++) != NULL) 379 { 380 if (argv[0] != NULL && argv[1] != NULL && sameword(argv[0], "at")) 381 { 382 char nbuf[MAXNAME]; 383 384 if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf) 385 usrerr("address overflow"); 386 else 387 { 388 (void) strcpy(nbuf, p); 389 (void) strcat(nbuf, "@"); 390 (void) strcat(nbuf, argv[1]); 391 p = newstr(nbuf); 392 argv += 2; 393 } 394 } 395 sendto(p, 0); 396 } 397 } 398