|
|
1.1 root 1: /*
2: * Copyright (c) 1989 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * Jef Poskanzer and Craig Leres of the Lawrence Berkeley Laboratory.
7: *
8: * Redistribution and use in source and binary forms are permitted provided
9: * that: (1) source distributions retain this entire copyright notice and
10: * comment, and (2) distributions including binaries display the following
11: * acknowledgement: ``This product includes software developed by the
12: * University of California, Berkeley and its contributors'' in the
13: * documentation or other materials provided with the distribution and in
14: * all advertising materials mentioning features or use of this software.
15: * Neither the name of the University nor the names of its contributors may
16: * be used to endorse or promote products derived from this software without
17: * specific prior written permission.
18: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
19: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
20: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21: */
22:
23: #ifndef lint
24: char copyright[] =
25: "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
26: All rights reserved.\n";
27: #endif /* not lint */
28:
29: #ifndef lint
30: static char sccsid[] = "@(#)write.c 4.22 (Berkeley) 6/1/90";
31: #endif /* not lint */
32:
33: #include <sys/param.h>
34: #include <sys/signal.h>
35: #include <sys/stat.h>
36: #include <sys/file.h>
37: #include <sys/time.h>
38: #include <utmp.h>
39: #include <ctype.h>
40: #include <pwd.h>
41: #include <stdio.h>
42: #include <string.h>
43:
44: extern int errno;
45:
46: main(argc, argv)
47: int argc;
48: char **argv;
49: {
50: register char *cp;
51: time_t atime;
52: uid_t myuid;
53: int msgsok, myttyfd;
54: char tty[MAXPATHLEN], *mytty, *ttyname();
55: void done();
56:
57: /* check that sender has write enabled */
58: if (isatty(fileno(stdin)))
59: myttyfd = fileno(stdin);
60: else if (isatty(fileno(stdout)))
61: myttyfd = fileno(stdout);
62: else if (isatty(fileno(stderr)))
63: myttyfd = fileno(stderr);
64: else {
65: (void)fprintf(stderr, "write: can't find your tty\n");
66: exit(1);
67: }
68: if (!(mytty = ttyname(myttyfd))) {
69: (void)fprintf(stderr, "write: can't find your tty's name\n");
70: exit(1);
71: }
72: if (cp = rindex(mytty, '/'))
73: mytty = cp + 1;
74: if (term_chk(mytty, &msgsok, &atime, 1))
75: exit(1);
76: if (!msgsok) {
77: (void)fprintf(stderr,
78: "write: you have write permission turned off.\n");
79: exit(1);
80: }
81:
82: myuid = getuid();
83:
84: /* check args */
85: switch (argc) {
86: case 2:
87: search_utmp(argv[1], tty, mytty, myuid);
88: do_write(tty, mytty, myuid);
89: break;
90: case 3:
91: if (!strncmp(argv[2], "/dev/", 5))
92: argv[2] += 5;
93: if (utmp_chk(argv[1], argv[2])) {
94: (void)fprintf(stderr,
95: "write: %s is not logged in on %s.\n",
96: argv[1], argv[2]);
97: exit(1);
98: }
99: if (term_chk(argv[2], &msgsok, &atime, 1))
100: exit(1);
101: if (myuid && !msgsok) {
102: (void)fprintf(stderr,
103: "write: %s has messages disabled on %s\n",
104: argv[1], argv[2]);
105: exit(1);
106: }
107: do_write(argv[2], mytty, myuid);
108: break;
109: default:
110: (void)fprintf(stderr, "usage: write user [tty]\n");
111: exit(1);
112: }
113: done();
114: /* NOTREACHED */
115: }
116:
117: /*
118: * utmp_chk - checks that the given user is actually logged in on
119: * the given tty
120: */
121: utmp_chk(user, tty)
122: char *user, *tty;
123: {
124: struct utmp u;
125: int ufd;
126:
127: if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0)
128: return(0); /* ignore error, shouldn't happen anyway */
129:
130: while (read(ufd, (char *) &u, sizeof(u)) == sizeof(u))
131: if (strncmp(user, u.ut_name, sizeof(u.ut_name)) == 0 &&
132: strncmp(tty, u.ut_line, sizeof(u.ut_line)) == 0) {
133: (void)close(ufd);
134: return(0);
135: }
136:
137: (void)close(ufd);
138: return(1);
139: }
140:
141: /*
142: * search_utmp - search utmp for the "best" terminal to write to
143: *
144: * Ignores terminals with messages disabled, and of the rest, returns
145: * the one with the most recent access time. Returns as value the number
146: * of the user's terminals with messages enabled, or -1 if the user is
147: * not logged in at all.
148: *
149: * Special case for writing to yourself - ignore the terminal you're
150: * writing from, unless that's the only terminal with messages enabled.
151: */
152: search_utmp(user, tty, mytty, myuid)
153: char *user, *tty, *mytty;
154: uid_t myuid;
155: {
156: struct utmp u;
157: time_t bestatime, atime;
158: int ufd, nloggedttys, nttys, msgsok, user_is_me;
159: char atty[UT_LINESIZE + 1];
160:
161: if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0) {
162: perror("utmp");
163: exit(1);
164: }
165:
166: nloggedttys = nttys = 0;
167: bestatime = 0;
168: user_is_me = 0;
169: while (read(ufd, (char *) &u, sizeof(u)) == sizeof(u))
170: if (strncmp(user, u.ut_name, sizeof(u.ut_name)) == 0) {
171: ++nloggedttys;
172: (void)strncpy(atty, u.ut_line, UT_LINESIZE);
173: atty[UT_LINESIZE] = '\0';
174: if (term_chk(atty, &msgsok, &atime, 0))
175: continue; /* bad term? skip */
176: if (myuid && !msgsok)
177: continue; /* skip ttys with msgs off */
178: if (strcmp(atty, mytty) == 0) {
179: user_is_me = 1;
180: continue; /* don't write to yourself */
181: }
182: ++nttys;
183: if (atime > bestatime) {
184: bestatime = atime;
185: (void)strcpy(tty, atty);
186: }
187: }
188:
189: (void)close(ufd);
190: if (nloggedttys == 0) {
191: (void)fprintf(stderr, "write: %s is not logged in\n", user);
192: exit(1);
193: }
194: if (nttys == 0) {
195: if (user_is_me) { /* ok, so write to yourself! */
196: (void)strcpy(tty, mytty);
197: return;
198: }
199: (void)fprintf(stderr,
200: "write: %s has messages disabled\n", user);
201: exit(1);
202: } else if (nttys > 1) {
203: (void)fprintf(stderr,
204: "write: %s is logged in more than once; writing to %s\n",
205: user, tty);
206: }
207: }
208:
209: /*
210: * term_chk - check that a terminal exists, and get the message bit
211: * and the access time
212: */
213: term_chk(tty, msgsokP, atimeP, showerror)
214: char *tty;
215: int *msgsokP, showerror;
216: time_t *atimeP;
217: {
218: struct stat s;
219: char path[MAXPATHLEN];
220:
221: (void)sprintf(path, "/dev/%s", tty);
222: if (stat(path, &s) < 0) {
223: if (showerror)
224: (void)fprintf(stderr,
225: "write: %s: %s\n", path, strerror(errno));
226: return(1);
227: }
228: *msgsokP = (s.st_mode & (S_IWRITE >> 3)) != 0; /* group write bit */
229: *atimeP = s.st_atime;
230: return(0);
231: }
232:
233: /*
234: * do_write - actually make the connection
235: */
236: do_write(tty, mytty, myuid)
237: char *tty, *mytty;
238: uid_t myuid;
239: {
240: register char *login, *nows;
241: register struct passwd *pwd;
242: time_t now, time();
243: char *getlogin(), path[MAXPATHLEN], host[MAXHOSTNAMELEN], line[512];
244: void done();
245:
246: /* Determine our login name before the we reopen() stdout */
247: if ((login = getlogin()) == NULL)
248: if (pwd = getpwuid(myuid))
249: login = pwd->pw_name;
250: else
251: login = "???";
252:
253: (void)sprintf(path, "/dev/%s", tty);
254: if ((freopen(path, "w", stdout)) == NULL) {
255: (void)fprintf(stderr, "write: %s: %s\n", path, strerror(errno));
256: exit(1);
257: }
258:
259: (void)signal(SIGINT, done);
260: (void)signal(SIGHUP, done);
261:
262: /* print greeting */
263: if (gethostname(host, sizeof(host)) < 0)
264: (void)strcpy(host, "???");
265: now = time((time_t *)NULL);
266: nows = ctime(&now);
267: nows[16] = '\0';
268: (void)printf("\r\n\007\007\007Message from %s@%s on %s at %s ...\r\n",
269: login, host, mytty, nows + 11);
270:
271: while (fgets(line, sizeof(line), stdin) != NULL)
272: wr_fputs(line);
273: }
274:
275: /*
276: * done - cleanup and exit
277: */
278: void
279: done()
280: {
281: (void)printf("EOF\r\n");
282: exit(0);
283: }
284:
285: /*
286: * wr_fputs - like fputs(), but makes control characters visible and
287: * turns \n into \r\n
288: */
289: wr_fputs(s)
290: register char *s;
291: {
292: register char c;
293:
294: #define PUTC(c) if (putchar(c) == EOF) goto err;
295:
296: for (; *s != '\0'; ++s) {
297: c = toascii(*s);
298: if (c == '\n') {
299: PUTC('\r');
300: PUTC('\n');
301: } else if (!isprint(c) && !isspace(c) && c != '\007') {
302: PUTC('^');
303: PUTC(c^0x40); /* DEL to ?, others to alpha */
304: } else
305: PUTC(c);
306: }
307: return;
308:
309: err: (void)fprintf(stderr, "write: %s\n", strerror(errno));
310: exit(1);
311: #undef PUTC
312: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.