|
|
1.1 root 1: #include <stdio.h>
2: #include <sys/types.h>
3: #include <signal.h>
4: #include <pwd.h>
5: #include <sys/stat.h>
6: #include <time.h>
7: #include <sys/timeb.h>
8: #include "letter.h"
9: #include "mail.h"
10: #include "string.h"
11:
12:
13: /* configuration */
14: #define DEAD "dead.letter"
15: #define MAILMODE (~0644) /* mode of created mail */
16: #define MAXFORWARD 32
17: #define MAXHOP 5
18:
19: /* imports */
20: extern char *basename();
21: extern int (*signal())();
22: extern char *getsysname();
23: extern char *stringin();
24: extern char *getarg();
25: extern char *getenv();
26: extern char *mailpath();
27: extern char *upaspath();
28: extern void lock();
29: extern void unlock();
30: extern int rewrite();
31: extern int getrules();
32: extern long getunix();
33: extern void putunix();
34: extern void putrfunix();
35: extern FILE *popen();
36: extern char *getlogin();
37: extern char *asctime();
38: extern struct tm *localtime();
39: extern char *timezone();
40:
41: /* exported */
42: char *thissys; /* name of this system */
43: char *network = "uucp"; /* name of network mail is coming from */
44: int onatty;
45: int rmail; /* true if not executed as 'mail' */
46:
47: /* global to this module */
48: #define LETTERNAME 0
49: #define DEVTTY NOFILE-1
50: static int error;
51: static char *myname; /* name of this program */
52:
53: /* predeclared */
54: static void saveletter();
55: static int saveonint(), done();
56: static int send();
57: static int append_to_file();
58: static int pipe_to_cmd();
59: static long getfrom();
60:
61: extern void
62: sendmail(ac, av)
63: int ac;
64: char *av[];
65: {
66: int chkfl; /* check forward list */
67: int ind=1;
68: int (*rc)();
69: char sender[ADDRSIZE];
70: char date[DATESIZE];
71: long bodyoffset;
72: letter *lp;
73:
74: /* avoid hanging dk lines (HACK!!!!!!!!) */
75: close(DEVTTY);
76:
77: myname = basename(av[0]);
78: rmail = chkfl = strcmp(myname, "mail") != 0;
79: onatty = isatty(0);
80: thissys = getsysname();
81:
82: /* make temporary */
83: rc = signal(SIGINT, done);
84: inittmp();
85:
86: /* get network (default uucp) */
87: if (av[1][0] == '-' && av[1][1] == 'N') {
88: if (av[1][2] == '\0') {
89: network = av[2];
90: ind++;
91: } else {
92: network = &(av[1][2]);
93: }
94: ind++;
95: }
96:
97: /* read letter */
98: (void)signal(SIGINT, saveonint);
99: lp = lopen(LETTERNAME, "w");
100: copyto(stdin, lp, onatty, 1);
101: if (ltell(lp) == 0L)
102: done();
103:
104: /* send */
105: if (!error) {
106: (void)getrules();
107: lp = lopen(LETTERNAME, "r");
108: bodyoffset = getfrom(lp, sender, date);
109: (void)signal(SIGINT, rc);
110: for (; ind<ac; ind++) {
111: letseek(lp, bodyoffset);
112: error += send(lp, sender, date, av[ind], chkfl, 0);
113: }
114: }
115: if (error && onatty)
116: saveletter(lp);
117: (void)done();
118: }
119:
120: /* come here on interrupt while reading in letter */
121: static int
122: saveonint() {
123: (void)signal(SIGINT, saveonint);
124: error++;
125: }
126:
127: /* come here to finish up */
128: static int
129: done() {
130: unlock();
131: releasetmp();
132: exit(error);
133: }
134:
135: /* save the letter in dead.letter */
136: static void
137: saveletter(lp)
138: letter *lp;
139: {
140: FILE *malf;
141: char where[PATHSIZE];
142: char *home = getenv("HOME");
143:
144: (void)setgid(getgid());
145: (void)setuid(getuid());
146: if (home != NULL) {
147: strcpy(where, home);
148: strcat(where, "/");
149: } else
150: *where = '\0';
151: strcat(where, DEAD);
152: malf = fopen(where, "w");
153: if (malf == NULL) {
154: fprintf(stderr, "mail: cannot open %s\n", where);
155: return;
156: }
157: letseek(lp, (long)0);
158: copyfrom(lp, malf);
159: fclose(malf);
160: printf("Mail saved in %s\n", where);
161: }
162:
163: /*
164: * Send a letter. Return 0 if all went well.
165: */
166: static int
167: send(lp, sender, date, rcvr, chkfl, hop)
168: letter *lp;
169: char *sender, *date, *rcvr;
170: int chkfl;
171: int hop;
172: {
173: int rv, notinfl;
174: char dest[ADDRSIZE], rest[ADDRSIZE], cmd[CMDSIZE], format[32], sysname[64];
175:
176: if ((notinfl = rewrite(rcvr, sender, chkfl, cmd)) < 0) {
177: fprintf(stderr, "mail: can't understand address %s\n", dest);
178: return 1;
179: }
180: if (cmd[0]=='\0')
181: rv = append_to_file(lp, sender, date, rcvr, chkfl, hop);
182: else
183: rv = pipe_to_cmd(lp, sender, date, rcvr, cmd,
184: chkfl && notinfl);
185: return rv;
186: }
187:
188: /*
189: * Put mail into a mail file in the standard place.
190: */
191: static int
192: append_to_file(lp, sender, date, rcvr, chkfl, hop)
193: letter *lp;
194: char *sender, *date, *rcvr;
195: int hop;
196: {
197: register mask;
198: struct passwd *pw, *getpwnam();
199: struct stat stbuf;
200: char file[PATHSIZE];
201: char sendto[CMDSIZE];
202: int exists;
203: FILE *malf;
204: char *p;
205: int i;
206:
207: if (strcmp(rcvr, "-") == 0)
208: return(1);
209: if (strchr(rcvr, '/') != NULL) {
210: fprintf(stderr, "mail: illegal name %s\n", rcvr);
211: return(0);
212: }
213: strcpy(file, mailpath(rcvr));
214: switch (delivery_status(file, sendto) & MFTYPE) {
215: case MF_NORMAL:
216: /* normal message */
217: break;
218: case MF_FORWARD:
219: /* look for possible forwarding loop */
220: for (i = 0, p = sender-1; p != NULL; p = strchr(p+1, '!'))
221: if (strncmp(thissys, p+1, strlen(thissys))==0)
222: i++;
223: if (i > MAXHOP) {
224: logsend(rcvr, sender, date, "remote-mail-loop-err");
225: fprintf(stderr, "mail: remote mail loop\n");
226: break;
227: }
228:
229: /* forward message */
230: return forward_to(lp, rcvr, sender, date, sendto, hop);
231: case MF_PIPE:
232: /* pipe to a command */
233: (void)stat(file, &stbuf);
234: return pipe_to(lp, rcvr, sender, date, sendto, stbuf.st_uid,
235: stbuf.st_gid);
236: }
237: exists = stat(file, &stbuf);
238: if ((pw = getpwnam(rcvr)) == NULL) {
239: if (exists < 0) {
240: if (chkfl) {
241: refuse(lp,sender, date, rcvr, "addressee unknown.");
242: return(0);
243: }
244: fprintf(stderr, "mail: can't send to %s\n", rcvr);
245: return 1;
246: }
247: } else {
248: stbuf.st_uid = pw->pw_uid;
249: stbuf.st_gid = pw->pw_gid;
250: }
251: mask = umask(MAILMODE);
252: lock(file);
253: malf = fopen(file, "a");
254: umask(mask);
255: if (malf == NULL) {
256: fprintf(stderr, "mail: cannot append to %s\n", file);
257: logsend(rcvr, sender, date, "append-err");
258: return 1;
259: }
260: if (exists < 0)
261: chown(file, stbuf.st_uid, stbuf.st_gid);
262: fprintf(malf, "%s%s %s\n", FROM, sender, date);
263: copyfrom(lp, malf);
264: fputs("\n", malf);
265: fclose(malf);
266: unlock();
267: logsend(rcvr, sender, date, "delivered");
268: notify(rcvr, sender); /* let him know it right away! */
269: return 0;
270: }
271:
272: /*
273: * Pipe the mail into a command. This is either for remote
274: * mail or specially handled mail. Remote mail is distinguished
275: * by a non-null string as the destination.
276: */
277: static int
278: pipe_to_cmd(lp, sender, date, rcvr, cmd, chkfl)
279: letter *lp;
280: char *sender, *date, *rcvr, *cmd;
281: int chkfl;
282: {
283: FILE *fp;
284: char errbuf[CMDSIZE];
285: char reason[2*CMDSIZE];
286: long pos, status;
287:
288: /* check forwarding (what anti-social crap!) */
289: if (chkfl) {
290: if (rewrite(sender, "", chkfl, (char *)NULL) != 0) {
291: refuse(lp, sender, date, rcvr,
292: "forwarding to this system disallowed.");
293: return(0);
294: }
295: }
296:
297: /* do it */
298: if ((fp=popen(cmd, getuid(), getgid())) == NULL) {
299: fprintf(stderr, "mail: can't pipe to network mailer\n");
300: exit(1);
301: }
302: pos = ltell(lp);
303: putrfunix(sender, date, thissys, fp);
304: copyfrom(lp, fp);
305: status = pclose(fp, errbuf, CMDSIZE);
306: if (status==0) {
307: logsend(rcvr, sender, date, "remote");
308: return 0;
309: } else {
310: logsend(rcvr, sender, date, "remote-err");
311: logsend("", cmd, "", "remote-err");
312: sprintf(reason, "\"%s\"\nwas unable to send your mail. It returned the status 0x%x.\nStderr was:\n%s",
313: cmd, status, errbuf);
314: (void)letseek(lp, pos);
315: refuse(lp, sender, date, rcvr, reason);
316: return 0;
317: }
318: }
319:
320:
321: /* return to sender, address unknown, no such number, no such phone... */
322: refuse(lp, sender, date, rcvr, reason)
323: letter *lp;
324: char *sender, *date, *rcvr, *reason;
325: {
326: FILE *pf;
327: char cbuf[CMDSIZE];
328:
329: sprintf(cbuf, "PATH=/bin:/usr/bin mail %s", sender);
330: if ((pf = popen(cbuf, getuid(), getgid())) == NULL)
331: return;
332: fprintf(pf, "Mail to %s failed. %s\nMessage was:\n", rcvr, reason);
333: fprintf(pf, "%s%s %s\n", FROM, sender, date);
334: copyfrom(lp, pf);
335: pclose(pf, 0, 0);
336: logsend(rcvr, sender, date, "refused");
337: }
338:
339: /* forward mail to a list of people */
340: forward_to(lp, rcvr, sender, date, list, hop)
341: letter *lp;
342: char *rcvr, *sender, *date, *list;
343: int hop;
344: {
345: char dest[ADDRSIZE];
346: char *p;
347: int rv=0;
348:
349: if (hop > MAXFORWARD) {
350: fprintf(stderr, "mail: forwarding loop!!\n");
351: logsend(rcvr, sender, date, "forward-loop-err");
352: return 1;
353: }
354: for (p = list; (p = getarg(dest, p)) != NULL; ) {
355: (void)letseek(lp, (long)0);
356: rv += send(lp, sender, date, dest, 0, ++hop);
357: }
358: return rv;
359: }
360:
361: #define SU 0 /* super-duper user uid */
362:
363: /* change uid to the receiver and perform the command */
364: pipe_to(lp, rcvr, sender, date, cmd, uid, gid)
365: letter *lp;
366: char *rcvr, *sender, *date, *cmd;
367: {
368: FILE *fp;
369: int i;
370:
371: /* do it */
372: if ((fp=popen(cmd, uid, gid)) == NULL) {
373: fprintf(stderr, "mail: can't pipe to network mailer\n");
374: return 1;
375: }
376: putunix(sender, date, fp);
377: copyfrom(lp, fp);
378: if ((i=pclose(fp, 0, 0))==0) {
379: logsend(rcvr, sender, date, "pipe_to");
380: return 0;
381: } else {
382: logsend(rcvr, sender, date, "pipe_to_err");
383: logsend("", cmd, "", "pipe_to_err");
384: fprintf(stderr, "mail: Pipe to \"%s\" returns error status %d\n",
385: cmd, i);
386: return 1;
387: }
388: }
389:
390: /* default sender */
391: static void
392: defaultsender(sender, date)
393: char *sender; /* filled by defaultsender */
394: char *date; /* filled by defaultsender */
395: {
396: char *tp, *dp;
397: struct timeb timbuf;
398: struct tm *bp;
399: long thetime;
400:
401: (void)strcpy(sender, getlogin());
402: ftime(&timbuf);
403: thetime = timbuf.time;
404: bp = localtime(&thetime);
405: dp = asctime(bp);
406: tp = timezone(timbuf.timezone, bp->tm_isdst);
407: sprintf(date, "%.16s %.3s %.4s", dp, tp, dp+20);
408: }
409:
410: /* Get/parse a unix header. */
411: static long
412: getfrom(lp, sender, date)
413: letter *lp;
414: char *sender, *date;
415: {
416: char line[FROMLINESIZE];
417: long n=0;
418:
419: defaultsender(sender, date);
420: initgetunix();
421: while (lgets(line, sizeof(line), lp) != NULL) {
422: if (getunix(line, sender, date) == 0)
423: break;
424: n = ltell(lp);
425: }
426:
427: return n;
428: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.