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