| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: wall.c,v 1.29 2011/09/06 18:45:21 joerg Exp $ */ | | 1 | /* $NetBSD: wall.c,v 1.30 2015/11/21 14:59:51 christos Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1988, 1990, 1993 | | 4 | * Copyright (c) 1988, 1990, 1993 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -29,27 +29,27 @@ | | | @@ -29,27 +29,27 @@ |
29 | * SUCH DAMAGE. | | 29 | * SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include <sys/cdefs.h> | | 32 | #include <sys/cdefs.h> |
33 | #ifndef lint | | 33 | #ifndef lint |
34 | __COPYRIGHT("@(#) Copyright (c) 1988, 1990, 1993\ | | 34 | __COPYRIGHT("@(#) Copyright (c) 1988, 1990, 1993\ |
35 | The Regents of the University of California. All rights reserved."); | | 35 | The Regents of the University of California. All rights reserved."); |
36 | #endif /* not lint */ | | 36 | #endif /* not lint */ |
37 | | | 37 | |
38 | #ifndef lint | | 38 | #ifndef lint |
39 | #if 0 | | 39 | #if 0 |
40 | static char sccsid[] = "@(#)wall.c 8.2 (Berkeley) 11/16/93"; | | 40 | static char sccsid[] = "@(#)wall.c 8.2 (Berkeley) 11/16/93"; |
41 | #endif | | 41 | #endif |
42 | __RCSID("$NetBSD: wall.c,v 1.29 2011/09/06 18:45:21 joerg Exp $"); | | 42 | __RCSID("$NetBSD: wall.c,v 1.30 2015/11/21 14:59:51 christos Exp $"); |
43 | #endif /* not lint */ | | 43 | #endif /* not lint */ |
44 | | | 44 | |
45 | /* | | 45 | /* |
46 | * This program is not related to David Wall, whose Stanford Ph.D. thesis | | 46 | * This program is not related to David Wall, whose Stanford Ph.D. thesis |
47 | * is entitled "Mechanisms for Broadcast and Selective Broadcast". | | 47 | * is entitled "Mechanisms for Broadcast and Selective Broadcast". |
48 | */ | | 48 | */ |
49 | | | 49 | |
50 | #include <sys/param.h> | | 50 | #include <sys/param.h> |
51 | #include <sys/stat.h> | | 51 | #include <sys/stat.h> |
52 | #include <sys/time.h> | | 52 | #include <sys/time.h> |
53 | #include <sys/uio.h> | | 53 | #include <sys/uio.h> |
54 | | | 54 | |
55 | #include <ctype.h> | | 55 | #include <ctype.h> |
| @@ -58,83 +58,80 @@ __RCSID("$NetBSD: wall.c,v 1.29 2011/09/ | | | @@ -58,83 +58,80 @@ __RCSID("$NetBSD: wall.c,v 1.29 2011/09/ |
58 | #include <errno.h> | | 58 | #include <errno.h> |
59 | #include <paths.h> | | 59 | #include <paths.h> |
60 | #include <pwd.h> | | 60 | #include <pwd.h> |
61 | #include <stdio.h> | | 61 | #include <stdio.h> |
62 | #include <stdlib.h> | | 62 | #include <stdlib.h> |
63 | #include <string.h> | | 63 | #include <string.h> |
64 | #include <unistd.h> | | 64 | #include <unistd.h> |
65 | #include <util.h> | | 65 | #include <util.h> |
66 | | | 66 | |
67 | #include "utmpentry.h" | | 67 | #include "utmpentry.h" |
68 | #include "term_chk.h" | | 68 | #include "term_chk.h" |
69 | | | 69 | |
70 | static void addgroup(char *); | | 70 | static void addgroup(char *); |
71 | static void makemsg(const char *); | | 71 | static void makemsg(struct iovec *, const char *, int); |
72 | __dead static void usage(void); | | 72 | __dead static void usage(void); |
73 | | | 73 | |
74 | static struct wallgroup { | | 74 | static struct wallgroup { |
75 | gid_t gid; | | 75 | gid_t gid; |
76 | char *name; | | 76 | char *name; |
77 | char **mem; | | 77 | char **mem; |
78 | struct wallgroup *next; | | 78 | struct wallgroup *next; |
79 | } *grouplist; | | 79 | } *grouplist; |
80 | | | 80 | |
81 | static int nobanner; | | | |
82 | static size_t mbufsize; | | | |
83 | static char *mbuf; | | | |
84 | | | | |
85 | /* ARGSUSED */ | | | |
86 | int | | 81 | int |
87 | main(int argc, char **argv) | | 82 | main(int argc, char **argv) |
88 | { | | 83 | { |
89 | int ch; | | 84 | int ch; |
90 | struct iovec iov; | | 85 | struct iovec iov; |
91 | char *p, **mem; | | 86 | char *p, **mem; |
92 | struct utmpentry *ep; | | 87 | struct utmpentry *ep; |
93 | gid_t egid; | | 88 | gid_t egid; |
94 | struct wallgroup *wg; | | 89 | struct wallgroup *wg; |
95 | struct passwd *pw; | | 90 | struct passwd *pw; |
| | | 91 | int nobanner; |
96 | | | 92 | |
97 | setprogname(argv[0]); | | 93 | setprogname(argv[0]); |
98 | egid = getegid(); | | 94 | egid = getegid(); |
99 | if (setegid(getgid()) == -1) | | 95 | if (setegid(getgid()) == -1) |
100 | err(1, "setegid"); | | 96 | err(EXIT_FAILURE, "setegid"); |
101 | pw = getpwnam("nobody"); | | 97 | pw = getpwnam("nobody"); |
| | | 98 | if (pw == NULL) |
| | | 99 | errx(EXIT_FAILURE, "Can't find passwd entry for `nobody'"); |
102 | | | 100 | |
103 | (void)check_sender(NULL, getuid(), egid); | | 101 | (void)check_sender(NULL, getuid(), egid); |
104 | | | 102 | |
| | | 103 | nobanner = 0; |
105 | while ((ch = getopt(argc, argv, "g:n")) != -1) | | 104 | while ((ch = getopt(argc, argv, "g:n")) != -1) |
106 | switch (ch) { | | 105 | switch (ch) { |
107 | case 'n': | | 106 | case 'n': |
108 | /* undoc option for shutdown: suppress banner */ | | 107 | /* undoc option for shutdown: suppress banner */ |
109 | if (geteuid() == 0 || (pw && getuid() == pw->pw_uid)) | | 108 | if (geteuid() == 0 || (pw && getuid() == pw->pw_uid)) |
110 | nobanner = 1; | | 109 | nobanner = 1; |
111 | break; | | 110 | break; |
112 | case 'g': | | 111 | case 'g': |
113 | addgroup(optarg); | | 112 | addgroup(optarg); |
114 | break; | | 113 | break; |
115 | case '?': | | 114 | case '?': |
116 | default: | | 115 | default: |
117 | usage(); | | 116 | usage(); |
118 | } | | 117 | } |
119 | argc -= optind; | | 118 | argc -= optind; |
120 | argv += optind; | | 119 | argv += optind; |
121 | if (argc > 1) | | 120 | if (argc > 1) |
122 | usage(); | | 121 | usage(); |
123 | | | 122 | |
124 | makemsg(*argv); | | 123 | makemsg(&iov, *argv, nobanner); |
125 | | | 124 | |
126 | iov.iov_base = mbuf; | | | |
127 | iov.iov_len = mbufsize; | | | |
128 | (void)getutentries(NULL, &ep); | | 125 | (void)getutentries(NULL, &ep); |
129 | (void)setegid(egid); | | 126 | (void)setegid(egid); |
130 | for (; ep; ep = ep->next) { | | 127 | for (; ep; ep = ep->next) { |
131 | if (grouplist) { | | 128 | if (grouplist) { |
132 | int ingroup; | | 129 | int ingroup; |
133 | | | 130 | |
134 | ingroup = 0; | | 131 | ingroup = 0; |
135 | pw = getpwnam(ep->name); | | 132 | pw = getpwnam(ep->name); |
136 | if (!pw) | | 133 | if (!pw) |
137 | continue; | | 134 | continue; |
138 | for (wg = grouplist; wg && !ingroup; wg = wg->next) { | | 135 | for (wg = grouplist; wg && !ingroup; wg = wg->next) { |
139 | if (wg->gid == pw->pw_gid) | | 136 | if (wg->gid == pw->pw_gid) |
140 | ingroup = 1; | | 137 | ingroup = 1; |
| @@ -143,133 +140,144 @@ main(int argc, char **argv) | | | @@ -143,133 +140,144 @@ main(int argc, char **argv) |
143 | ingroup = 1; | | 140 | ingroup = 1; |
144 | } | | 141 | } |
145 | if (ingroup == 0) | | 142 | if (ingroup == 0) |
146 | continue; | | 143 | continue; |
147 | } | | 144 | } |
148 | | | 145 | |
149 | /* skip [xgk]dm/xserver entries (":0", ":1", etc.) */ | | 146 | /* skip [xgk]dm/xserver entries (":0", ":1", etc.) */ |
150 | if (ep->line[0] == ':' && isdigit((unsigned char)ep->line[1])) | | 147 | if (ep->line[0] == ':' && isdigit((unsigned char)ep->line[1])) |
151 | continue; | | 148 | continue; |
152 | | | 149 | |
153 | if ((p = ttymsg(&iov, 1, ep->line, 60*5)) != NULL) | | 150 | if ((p = ttymsg(&iov, 1, ep->line, 60*5)) != NULL) |
154 | warnx("%s", p); | | 151 | warnx("%s", p); |
155 | } | | 152 | } |
156 | exit(0); | | 153 | return EXIT_SUCCESS; |
157 | } | | 154 | } |
158 | | | 155 | |
159 | static void | | 156 | static void |
160 | addgroup(char *name) | | 157 | addgroup(char *name) |
161 | { | | 158 | { |
162 | int i; | | 159 | size_t i; |
163 | struct group *grp; | | 160 | struct group *grp; |
164 | struct wallgroup *g; | | 161 | struct wallgroup *g; |
165 | | | 162 | |
166 | grp = getgrnam(name); | | 163 | grp = getgrnam(name); |
167 | if ((grp = getgrnam(name)) == NULL) | | 164 | if ((grp = getgrnam(name)) == NULL) |
168 | errx(1, "unknown group `%s'", name); | | 165 | errx(EXIT_FAILURE, "unknown group `%s'", name); |
169 | for (i = 0; grp->gr_mem[i]; i++) | | 166 | for (i = 0; grp->gr_mem[i]; i++) |
170 | continue; | | 167 | continue; |
171 | | | 168 | |
172 | g = (struct wallgroup *)malloc(sizeof *g); | | 169 | g = malloc(sizeof(*g)); |
173 | if (g == NULL) | | 170 | if (g == NULL) |
174 | err(1, "malloc"); | | 171 | err(EXIT_FAILURE, "malloc"); |
175 | g->gid = grp->gr_gid; | | 172 | g->gid = grp->gr_gid; |
176 | g->name = name; | | 173 | g->name = name; |
177 | g->mem = (char **)malloc(i + 1); | | 174 | g->mem = calloc(i + 1, sizeof(*g->mem)); |
178 | if (g->mem == NULL) | | 175 | if (g->mem == NULL) |
179 | err(1, "malloc"); | | 176 | err(EXIT_FAILURE, "calloc"); |
180 | for (i = 0; grp->gr_mem[i] != NULL; i++) { | | 177 | for (i = 0; grp->gr_mem[i] != NULL; i++) { |
181 | g->mem[i] = strdup(grp->gr_mem[i]); | | 178 | g->mem[i] = strdup(grp->gr_mem[i]); |
182 | if (g->mem[i] == NULL) | | 179 | if (g->mem[i] == NULL) |
183 | err(1, "malloc"); | | 180 | err(EXIT_FAILURE, "strdup"); |
184 | } | | 181 | } |
185 | g->mem[i] = NULL; | | 182 | g->mem[i] = NULL; |
186 | g->next = grouplist; | | 183 | g->next = grouplist; |
187 | grouplist = g; | | 184 | grouplist = g; |
188 | } | | 185 | } |
189 | | | 186 | |
190 | static void | | 187 | static void |
191 | makemsg(const char *fname) | | 188 | makebanner(FILE *fp) |
192 | { | | 189 | { |
193 | int ch, cnt; | | 190 | const char *whom, *tty; |
| | | 191 | char hostname[MAXHOSTNAMELEN + 1], lbuf[100]; |
| | | 192 | time_t now; |
194 | struct tm *lt; | | 193 | struct tm *lt; |
195 | struct passwd *pw; | | 194 | struct passwd *pw; |
| | | 195 | |
| | | 196 | if (!(whom = getlogin())) |
| | | 197 | whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???"; |
| | | 198 | (void)gethostname(hostname, sizeof(hostname)); |
| | | 199 | hostname[sizeof(hostname) - 1] = '\0'; |
| | | 200 | (void)time(&now); |
| | | 201 | lt = localtime(&now); |
| | | 202 | |
| | | 203 | /* |
| | | 204 | * all this stuff is to blank out a square for the message; |
| | | 205 | * we wrap message lines at column 79, not 80, because some |
| | | 206 | * terminals wrap after 79, some do not, and we can't tell. |
| | | 207 | * Which means that we may leave a non-blank character |
| | | 208 | * in column 80, but that can't be helped. |
| | | 209 | */ |
| | | 210 | (void)fprintf(fp, "\r%79s\r\n", " "); |
| | | 211 | (void)snprintf(lbuf, sizeof lbuf, |
| | | 212 | "Broadcast Message from %s@%s", whom, hostname); |
| | | 213 | (void)fprintf(fp, "%-79.79s\007\007\r\n", lbuf); |
| | | 214 | tty = ttyname(STDERR_FILENO); |
| | | 215 | if (tty == NULL) |
| | | 216 | tty = "??"; |
| | | 217 | (void)snprintf(lbuf, sizeof lbuf, " (%s) at %d:%02d %s...", tty, |
| | | 218 | lt->tm_hour, lt->tm_min, lt->tm_zone); |
| | | 219 | (void)fprintf(fp, "%-79.79s\r\n", lbuf); |
| | | 220 | } |
| | | 221 | |
| | | 222 | static void |
| | | 223 | makemsg(struct iovec *iov, const char *fname, int nobanner) |
| | | 224 | { |
| | | 225 | int ch, cnt; |
196 | struct stat sbuf; | | 226 | struct stat sbuf; |
197 | time_t now; | | | |
198 | FILE *fp; | | 227 | FILE *fp; |
199 | int fd; | | 228 | int fd; |
200 | const char *whom, *tty; | | 229 | char *p, tmpname[MAXPATHLEN], lbuf[100]; |
201 | char *p, tmpname[MAXPATHLEN], lbuf[100], | | 230 | size_t mbufsize; |
202 | hostname[MAXHOSTNAMELEN+1]; | | 231 | char *mbuf; |
203 | | | 232 | |
204 | (void)snprintf(tmpname, sizeof tmpname, "%s/wall.XXXXXX", _PATH_TMP); | | 233 | (void)snprintf(tmpname, sizeof tmpname, "%s/wall.XXXXXX", _PATH_TMP); |
205 | if ((fd = mkstemp(tmpname)) == -1) | | 234 | if ((fd = mkstemp(tmpname)) == -1) |
206 | err(1, "can't open temporary file"); | | 235 | err(EXIT_FAILURE, "can't open temporary file"); |
207 | (void)unlink(tmpname); | | 236 | (void)unlink(tmpname); |
208 | if (!(fp = fdopen(fd, "r+"))) | | 237 | if (!(fp = fdopen(fd, "r+"))) |
209 | err(1, "can't open temporary file"); | | 238 | err(EXIT_FAILURE, "can't open temporary file"); |
| | | 239 | |
| | | 240 | if (!nobanner) |
| | | 241 | makebanner(fp); |
210 | | | 242 | |
211 | if (!nobanner) { | | | |
212 | if (!(whom = getlogin())) | | | |
213 | whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???"; | | | |
214 | (void)gethostname(hostname, sizeof(hostname)); | | | |
215 | hostname[sizeof(hostname) - 1] = '\0'; | | | |
216 | (void)time(&now); | | | |
217 | lt = localtime(&now); | | | |
218 | | | | |
219 | /* | | | |
220 | * all this stuff is to blank out a square for the message; | | | |
221 | * we wrap message lines at column 79, not 80, because some | | | |
222 | * terminals wrap after 79, some do not, and we can't tell. | | | |
223 | * Which means that we may leave a non-blank character | | | |
224 | * in column 80, but that can't be helped. | | | |
225 | */ | | | |
226 | (void)fprintf(fp, "\r%79s\r\n", " "); | | | |
227 | (void)snprintf(lbuf, sizeof lbuf, | | | |
228 | "Broadcast Message from %s@%s", whom, hostname); | | | |
229 | (void)fprintf(fp, "%-79.79s\007\007\r\n", lbuf); | | | |
230 | tty = ttyname(STDERR_FILENO); | | | |
231 | if (tty == NULL) | | | |
232 | tty = "??"; | | | |
233 | (void)snprintf(lbuf, sizeof lbuf, | | | |
234 | " (%s) at %d:%02d %s...", tty, | | | |
235 | lt->tm_hour, lt->tm_min, lt->tm_zone); | | | |
236 | (void)fprintf(fp, "%-79.79s\r\n", lbuf); | | | |
237 | } | | | |
238 | (void)fprintf(fp, "%79s\r\n", " "); | | 243 | (void)fprintf(fp, "%79s\r\n", " "); |
239 | | | 244 | |
240 | if (fname && !(freopen(fname, "r", stdin))) | | 245 | if (fname && !(freopen(fname, "r", stdin))) |
241 | err(1, "can't read %s", fname); | | 246 | err(EXIT_FAILURE, "can't read %s", fname); |
| | | 247 | |
242 | while (fgets(lbuf, sizeof(lbuf), stdin)) | | 248 | while (fgets(lbuf, sizeof(lbuf), stdin)) |
243 | for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) { | | 249 | for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) { |
244 | if (cnt == 79 || ch == '\n') { | | 250 | if (cnt == 79 || ch == '\n') { |
245 | for (; cnt < 79; ++cnt) | | 251 | for (; cnt < 79; ++cnt) |
246 | putc(' ', fp); | | 252 | putc(' ', fp); |
247 | putc('\r', fp); | | 253 | putc('\r', fp); |
248 | putc('\n', fp); | | 254 | putc('\n', fp); |
249 | cnt = -1; | | 255 | cnt = -1; |
250 | } | | 256 | } |
251 | if (ch != '\n') | | 257 | if (ch != '\n') |
252 | putc(ch, fp); | | 258 | putc(ch, fp); |
253 | } | | 259 | } |
254 | (void)fprintf(fp, "%79s\r\n", " "); | | 260 | (void)fprintf(fp, "%79s\r\n", " "); |
255 | rewind(fp); | | 261 | rewind(fp); |
256 | | | 262 | |
257 | if (fstat(fd, &sbuf)) | | 263 | if (fstat(fd, &sbuf) == -1) |
258 | err(1, "can't stat temporary file"); | | 264 | err(EXIT_FAILURE, "can't stat temporary file"); |
259 | if ((uint64_t)sbuf.st_size > SIZE_T_MAX) | | 265 | if ((uint64_t)sbuf.st_size > SIZE_T_MAX) |
260 | errx(1, "file too big"); | | 266 | errx(EXIT_FAILURE, "file too big"); |
261 | mbufsize = sbuf.st_size; | | 267 | mbufsize = (size_t)sbuf.st_size; |
262 | if (!(mbuf = malloc(mbufsize))) | | 268 | if (!(mbuf = malloc(mbufsize))) |
263 | err(1, "malloc"); | | 269 | err(EXIT_FAILURE, "malloc"); |
264 | if (fread(mbuf, 1, mbufsize, fp) != mbufsize) | | 270 | if (fread(mbuf, 1, mbufsize, fp) != mbufsize) |
265 | err(1, "can't read temporary file"); | | 271 | err(EXIT_FAILURE, "can't read temporary file"); |
266 | (void)fclose(fp); | | 272 | (void)fclose(fp); |
| | | 273 | iov->iov_base = mbuf; |
| | | 274 | iov->iov_len = mbufsize; |
267 | } | | 275 | } |
268 | | | 276 | |
269 | static void | | 277 | static void |
270 | usage(void) | | 278 | usage(void) |
271 | { | | 279 | { |
272 | | | 280 | |
273 | (void)fprintf(stderr, "usage: %s [-g group] [file]\n", getprogname()); | | 281 | (void)fprintf(stderr, "Usage: %s [-g group] [file]\n", getprogname()); |
274 | exit(1); | | 282 | exit(EXIT_FAILURE); |
275 | } | | 283 | } |