|
|
1.1 root 1: /*
2: * Rec'd from Lauren Weinstein, 7-16-84.
3: * Write to another user
4: * on the system.
5: * This is setuid in order to
6: * use execute permission on the
7: * terminal to allow/disallow writes.
8: *
9: * Compile -s -n -i
10: */
11:
12: #include <stdio.h>
13: #include <utmp.h>
14: #include <signal.h>
15: #include <sys/stat.h>
16: #include <sgtty.h>
17:
18: #define FALSE 0
19: #define TRUE 1
20:
21: #define NSYSC 150 /* Maximum system call line */
22: FILE *tf;
23: struct stat sb;
24: struct sgttyb sgttyb, sgttys; /* for user tty modes */
25: struct sgttyb sgttyd; /* for dest tty modes */
26: struct tchars tchars; /* for determining EOF char */
27: char sighup, sigquit, sigint; /* signal change flags */
28: int eofmark; /* EOF marker */
29: char dtty[40] = "/dev/";
30: int conopen; /* TRUE if connection open */
31: int status; /* exit status */
32: int dcrtmode; /* non-zero for dest tty crt mode */
33: int ucrtmode; /* non-zero for user tty crt mode */
34: int istty; /* TRUE if input is a tty */
35: int quit();
36: char *getutmp();
37: char *getlogin();
38: char *ttyname();
39: char crtwarn[] =
40: "Warning: One or both ttys is not a screen-oriented device.\n\
41: Backspacing/character erase will not function properly...\n";
42:
43: main(argc, argv)
44: char **argv;
45: {
46: char *totty, *touname;
47: char *fromtty, *fromuname;
48: char crtmode = 0; /* TRUE if both ttys are crt's */
49: register int c;
50: register int nlf = 1;
51:
52: if (argc == 3)
53: totty = argv[2];
54: else {
55: if (argc != 2)
56: usage();
57: totty = NULL;
58: }
59: touname = argv[1];
60:
61: gtty(0, &sgttyb); /* get tty modes into buffer */
62: if (sgttyb.sg_flags & CRT) /* crt mode on user tty? */
63: ucrtmode++; /* yes */
64: gtty(0, &sgttys); /* save copy of original modes */
65:
66: fromuname = getlogin();
67: totty = getutmp(totty, touname);
68: strcat(dtty, totty); /* build full ttyname */
69:
70: if ((fromtty = ttyname(fileno(stderr))) != NULL) {
71: stat(fromtty, &sb);
72: if ((sb.st_mode & S_IEXEC) == 0)
73: fprintf(stderr, "Warning: no reply possible\n");
74: fromtty += 5; /* Skip over `/dev/' */
75: }
76: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
77: { signal(SIGINT, &quit); /* catch ints */
78: sigint++; /* flag we're catching ints */
79: }
80: if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
81: { signal(SIGHUP, &quit); /* catch hangups */
82: sighup++; /* flag */
83: }
84: if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
85: { signal(SIGQUIT, &quit); /* catch quits */
86: sigquit++;
87: }
88: ioctl(0, TIOCGETC, &tchars); /* get char settings */
89: setup(touname, dtty);
90:
91: if (isatty(0)) /* input a tty? */
92: { istty = TRUE; /* yes */
93: eofmark = tchars.t_eofc; /* set EOF marker */
94: }
95: else
96: eofmark = EOF; /* set EOF marker */
97:
98: if (!(crtmode = dcrtmode&ucrtmode)) /* check for both crt's */
99: if (!ucrtmode && istty) /* input not crt and not tty? */
100: fprintf(stderr, crtwarn); /* yes, warn user */
101:
102: conopen = TRUE; /* flag connection open */
103: sgttyb.sg_flags |= CBREAK; /* want cbreak mode */
104: stty(0, &sgttyb); /* set new mode (no flush) */
105:
106: /*
107: * Turn off setuid privileges.
108: */
109: setuid(getuid());
110: fprintf(tf, "\r\n\7Message from %s (%s) ...\r\n", fromuname, fromtty);
111: printf("\r\nUser %s has been notified ...\r\n", touname);
112: while ((c = getchar()) != eofmark) { /* continue until end of file */
113: if (nlf && c=='!') {
114: callsys();
115: continue;
116: }
117: if (c == '\n')
118: nlf = 1;
119: else
120: nlf = 0;
121: putc(c, tf);
122: if (c == '\b' && crtmode) /* backspace and crt's? */
123: { putc(' ', stdout); /* erase local char */
124: putc('\b', stdout);
125: putc(' ', tf); /* erase dest char */
126: putc('\b', tf);
127: }
128: }
129: quit();
130: }
131:
132: callsys()
133: {
134: char sysline[NSYSC];
135: register char *cp;
136: register int c;
137:
138: cp = sysline;
139: while ((c = getchar()) != '\n')
140: if (cp < &sysline[NSYSC-1])
141: *cp++ = c;
142: *cp = '\0';
143: signal(SIGINT, SIG_IGN); /* ignore ints */
144: signal(SIGHUP, SIG_IGN); /* hups */
145: signal(SIGQUIT, SIG_IGN); /* and quits */
146: stty(0, &sgttys); /* restore original modes */
147: system(sysline); /* fork child command */
148: stty(0, &sgttyb); /* back to special modes */
149: if (sigint) /* restore int status */
150: signal(SIGINT, &quit);
151: if (sighup) /* hup */
152: signal(SIGHUP, &quit);
153: if (sigquit) /* quit */
154: signal(SIGQUIT, &quit);
155: printf("!\n");
156: }
157:
158: /*
159: * Check whether or not writes are
160: * allowed to this terminal.
161: */
162: setup(u, t)
163: char *u, *t;
164: {
165: register char abortf = 0;
166: register char c;
167:
168: if ((tf = fopen(t, "w")) == NULL)
169: fprintf(stderr, "write: cannot open %s\n", t);
170: if (gtty(fileno(tf), &sgttyd) >= 0) /* stat dest tty */
171: if (sgttyd.sg_flags & CRT) /* crt mode on dest tty? */
172: dcrtmode++;
173: if (fstat(fileno(tf), &sb) < 0) {
174: fprintf(stderr, "write: can't write to %s\n", u);
175: quiterr();
176: }
177: if ((sb.st_mode&S_IEXEC) == 0) {
178: if (getuid() == 0) /* is our real uid su? */
179: { fprintf(stderr,
180: "User \"%s\" is denying messages. Override? ", u);
181: if ((c = getchar()) != 'y')
182: abortf++; /* flag abort */
183: while (c != EOF && c != '\n') /* flush remaining input */
184: c = getchar();
185: if ( ! abortf) /* override requested? */
186: return; /* allow write */
187: else
188: quit();
189: }
190: fprintf(stderr, "write: no permission to write to %s\n", u);
191: quiterr();
192: }
193: }
194:
195: /*
196: * Return the tty for the specified
197: * username and possibly tty
198: * from the utmp file.
199: */
200: char *
201: getutmp(t, u)
202: char *t, *u;
203: {
204: register FILE *fp;
205: static struct utmp ut;
206:
207:
208: if ((fp = fopen("/etc/utmp", "r")) == NULL) {
209: fprintf(stderr, "write: /etc/utmp not accessible\n");
210: quiterr();
211: }
212:
213: while (fread(&ut, sizeof ut, 1, fp) == 1) {
214: if (strncmp(ut.ut_name, u, DIRSIZ) != 0)
215: continue;
216: if (t != NULL)
217: if (strncmp(ut.ut_line, t, 8) == 0) {
218: fclose(fp);
219: return (t);
220: } else
221: continue;
222: ut.ut_line[8] == '\0';
223: fclose(fp);
224: return (ut.ut_line);
225: }
226: if (t == NULL)
227: fprintf(stderr, "write: %s not logged in\n", u);
228: else
229: fprintf(stderr, "write: %s not logged onto %s\n", u, t);
230: quiterr();
231: }
232:
233: quit()
234: {
235: if (conopen) /* if connection open */
236: { stty(0, &sgttys); /* normal mode */
237: fprintf(tf, "EOT\n");
238: fclose(tf); /* close connection */
239: }
240: exit(status);
241: }
242:
243: quiterr()
244: {
245: status = 1; /* exit with error status */
246: quit();
247: }
248:
249: usage()
250: {
251: fprintf(stderr, "Usage: write username [ttyname]\n");
252: quit(1);
253: }
254:
255:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.