Print this page
3124 Remove any existing references to utmp, use utmpx instead
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/wall/wall.c
+++ new/usr/src/cmd/wall/wall.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License, Version 1.0 only
6 6 * (the "License"). You may not use this file except in compliance
7 7 * with the License.
8 8 *
9 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 * or http://www.opensolaris.org/os/licensing.
11 11 * See the License for the specific language governing permissions
12 12 * and limitations under the License.
13 13 *
14 14 * When distributing Covered Code, include this CDDL HEADER in each
15 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 16 * If applicable, add the following below this CDDL HEADER, with the
17 17 * fields enclosed by brackets "[]" replaced with your own identifying
18 18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 19 *
20 20 * CDDL HEADER END
21 21 */
22 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23 23 /* All Rights Reserved */
24 24
25 25
26 26
27 27 /*
28 28 * Copyright 1988-2003 Sun Microsystems, Inc. All rights reserved.
29 29 * Use is subject to license terms.
30 30 */
31 31
32 32 /*
33 33 * Copyright 2012 Joyent, Inc. All rights reserved.
34 34 *
35 35 * Copyright (c) 2013 Gary Mills
36 36 */
37 37
38 38 #include <signal.h>
39 39 #include <stdio.h>
40 40 #include <stdlib.h>
41 41 #include <grp.h>
42 42 #include <sys/types.h>
43 43 #include <unistd.h>
44 44 #include <string.h>
45 45 #include <ctype.h>
46 46 #include <sys/stat.h>
47 47 #include <utmpx.h>
48 48 #include <sys/utsname.h>
49 49 #include <dirent.h>
50 50 #include <pwd.h>
51 51 #include <fcntl.h>
52 52 #include <time.h>
53 53 #include <errno.h>
54 54 #include <locale.h>
55 55 #include <syslog.h>
56 56 #include <sys/wait.h>
57 57 #include <limits.h>
58 58 #include <libzonecfg.h>
59 59 #include <zone.h>
60 60 #include <sys/contract/process.h>
61 61 #include <libcontract.h>
62 62 #include <sys/ctfs.h>
63 63
64 64 /*
65 65 * Use the full lengths from utmpx for user and line.
66 66 */
67 67 #define NMAX (sizeof (((struct utmpx *)0)->ut_user))
68 68 #define LMAX (sizeof (((struct utmpx *)0)->ut_line))
69 69
70 70 static char mesg[3000];
71 71 static char *infile;
72 72 static int gflag;
73 73 static struct group *pgrp;
74 74 static char *grpname;
75 75 static char line[MAXNAMLEN+1] = "???";
76 76 static char systm[MAXNAMLEN+1];
77 77 static time_t tloc;
78 78 static struct utsname utsn;
79 79 static char who[NMAX+1] = "???";
80 80 static char time_buf[50];
81 81 #define DATE_FMT "%a %b %e %H:%M:%S"
82 82
83 83 static void sendmes(struct utmpx *, zoneid_t);
84 84 static void sendmes_tozone(zoneid_t, int);
85 85 static int chkgrp(char *);
86 86 static char *copy_str_till(char *, char *, char, int);
87 87
88 88 static int init_template(void);
89 89 int contract_abandon_id(ctid_t);
90 90
91 91 int
92 92 main(int argc, char *argv[])
93 93 {
94 94 FILE *f;
95 95 char *ptr, *start;
96 96 struct passwd *pwd;
97 97 char *term_name;
98 98 int c;
99 99 int aflag = 0;
100 100 int errflg = 0;
101 101 int zflg = 0;
102 102 int Zflg = 0;
103 103
104 104 char *zonename = NULL;
105 105 zoneid_t *zoneidlist = NULL;
106 106 uint_t nzids_saved, nzids = 0;
107 107
108 108 (void) setlocale(LC_ALL, "");
109 109
110 110 while ((c = getopt(argc, argv, "g:az:Z")) != EOF)
111 111 switch (c) {
112 112 case 'a':
113 113 aflag++;
114 114 break;
115 115 case 'g':
116 116 if (gflag) {
117 117 (void) fprintf(stderr,
118 118 "Only one group allowed\n");
119 119 return (1);
120 120 }
121 121 if ((pgrp = getgrnam(grpname = optarg)) == NULL) {
122 122 (void) fprintf(stderr, "Unknown group %s\n",
123 123 grpname);
124 124 return (1);
125 125 }
126 126 gflag++;
127 127 break;
128 128 case 'z':
129 129 zflg++;
130 130 zonename = optarg;
131 131 if (getzoneidbyname(zonename) == -1) {
132 132 (void) fprintf(stderr, "Specified zone %s "
133 133 "is invalid", zonename);
134 134 return (1);
135 135 }
136 136 break;
137 137 case 'Z':
138 138 Zflg++;
139 139 break;
140 140 case '?':
141 141 errflg++;
142 142 break;
143 143 }
144 144
145 145 if (errflg) {
146 146 (void) fprintf(stderr,
147 147 "Usage: wall [-a] [-g group] [-z zone] [-Z] [files...]\n");
148 148 return (1);
149 149 }
150 150
151 151 if (zflg && Zflg) {
152 152 (void) fprintf(stderr, "Cannot use -z with -Z\n");
153 153 return (1);
154 154 }
155 155
156 156 if (optind < argc)
157 157 infile = argv[optind];
158 158
159 159 if (uname(&utsn) == -1) {
160 160 (void) fprintf(stderr, "wall: uname() failed, %s\n",
161 161 strerror(errno));
162 162 return (2);
163 163 }
164 164 (void) strcpy(systm, utsn.nodename);
165 165
166 166 /*
167 167 * Get the name of the terminal wall is running from.
168 168 */
169 169
170 170 if ((term_name = ttyname(fileno(stderr))) != NULL) {
171 171 /*
172 172 * skip the leading "/dev/" in term_name
173 173 */
174 174 (void) strncpy(line, &term_name[5], sizeof (line) - 1);
175 175 }
176 176
177 177 if (who[0] == '?') {
178 178 if (pwd = getpwuid(getuid()))
179 179 (void) strncpy(&who[0], pwd->pw_name, sizeof (who));
180 180 }
181 181
182 182 f = stdin;
183 183 if (infile) {
184 184 f = fopen(infile, "r");
185 185 if (f == NULL) {
186 186 (void) fprintf(stderr, "Cannot open %s\n", infile);
187 187 return (1);
188 188 }
189 189 }
190 190
191 191 start = &mesg[0];
192 192 ptr = start;
193 193 while ((ptr - start) < 3000) {
194 194 size_t n;
195 195
196 196 if (fgets(ptr, &mesg[sizeof (mesg)] - ptr, f) == NULL)
197 197 break;
198 198 if ((n = strlen(ptr)) == 0)
199 199 break;
200 200 ptr += n;
201 201 }
202 202 (void) fclose(f);
203 203
204 204 /*
205 205 * If the request is from the rwall daemon then use the caller's
206 206 * name and host. We determine this if all of the following is true:
207 207 * 1) First 5 characters are "From "
208 208 * 2) Next non-white characters are of the form "name@host:"
209 209 */
210 210 if (strcmp(line, "???") == 0) {
211 211 char rwho[MAXNAMLEN+1];
212 212 char rsystm[MAXNAMLEN+1];
213 213 char *cp;
214 214
215 215 if (strncmp(mesg, "From ", 5) == 0) {
216 216 cp = &mesg[5];
217 217 cp = copy_str_till(rwho, cp, '@', MAXNAMLEN + 1);
218 218 if (rwho[0] != '\0') {
219 219 cp = copy_str_till(rsystm, ++cp, ':',
220 220 MAXNAMLEN + 1);
221 221 if (rsystm[0] != '\0') {
222 222 (void) strcpy(systm, rsystm);
223 223 (void) strncpy(rwho, who,
224 224 sizeof (who));
225 225 (void) strcpy(line, "rpc.rwalld");
226 226 }
227 227 }
228 228 }
229 229 }
230 230 (void) time(&tloc);
231 231 (void) strftime(time_buf, sizeof (time_buf),
232 232 DATE_FMT, localtime(&tloc));
233 233
234 234 if (zflg != 0) {
235 235 if ((zoneidlist =
236 236 malloc(sizeof (zoneid_t))) == NULL ||
237 237 (*zoneidlist = getzoneidbyname(zonename)) == -1)
238 238 return (errno);
239 239 nzids = 1;
240 240 } else if (Zflg != 0) {
241 241 if (zone_list(NULL, &nzids) != 0)
242 242 return (errno);
243 243 again:
244 244 nzids *= 2;
245 245 if ((zoneidlist = malloc(nzids * sizeof (zoneid_t))) == NULL)
246 246 exit(errno);
247 247 nzids_saved = nzids;
248 248 if (zone_list(zoneidlist, &nzids) != 0) {
249 249 (void) free(zoneidlist);
250 250 return (errno);
251 251 }
252 252 if (nzids > nzids_saved) {
253 253 free(zoneidlist);
254 254 goto again;
255 255 }
256 256 }
257 257 if (zflg || Zflg) {
258 258 for (; nzids > 0; --nzids)
259 259 sendmes_tozone(zoneidlist[nzids-1], aflag);
260 260 free(zoneidlist);
261 261 } else
262 262 sendmes_tozone(getzoneid(), aflag);
263 263
264 264 return (0);
265 265 }
266 266
267 267 /*
268 268 * Copy src to destination upto but not including the delim.
269 269 * Leave dst empty if delim not found or whitespace encountered.
270 270 * Return pointer to next character (delim, whitespace, or '\0')
271 271 */
272 272 static char *
273 273 copy_str_till(char *dst, char *src, char delim, int len)
274 274 {
275 275 int i = 0;
276 276
277 277 while (*src != '\0' && i < len) {
278 278 if (isspace(*src)) {
279 279 dst[0] = '\0';
280 280 return (src);
281 281 }
282 282 if (*src == delim) {
283 283 dst[i] = '\0';
284 284 return (src);
285 285 }
286 286 dst[i++] = *src++;
287 287 }
288 288 dst[0] = '\0';
289 289 return (src);
290 290 }
291 291
292 292 static void
293 293 sendmes_tozone(zoneid_t zid, int aflag) {
294 294 int i = 0;
295 295 char zonename[ZONENAME_MAX], root[MAXPATHLEN];
296 296 struct utmpx *p;
297 297
298 298 if (zid != getzoneid()) {
299 299 root[0] = '\0';
300 300 (void) getzonenamebyid(zid, zonename, ZONENAME_MAX);
301 301 (void) zone_get_rootpath(zonename, root, sizeof (root));
302 302 (void) strlcat(root, UTMPX_FILE, sizeof (root));
303 303 if (!utmpxname(root)) {
304 304 (void) fprintf(stderr, "Cannot open %s\n", root);
305 305 return;
306 306 }
↓ open down ↓ |
306 lines elided |
↑ open up ↑ |
307 307 } else {
308 308 (void) utmpxname(UTMPX_FILE);
309 309 }
310 310 setutxent();
311 311 while ((p = getutxent()) != NULL) {
312 312 if (p->ut_type != USER_PROCESS)
313 313 continue;
314 314 /*
315 315 * if (-a option OR NOT pty window login), send the message
316 316 */
317 - if (aflag || !nonuser(*p))
317 + if (aflag || !nonuserx(*p))
318 318 sendmes(p, zid);
319 319 }
320 320 endutxent();
321 321
322 322 (void) alarm(60);
323 323 do {
324 324 i = (int)wait((int *)0);
325 325 } while (i != -1 || errno != ECHILD);
326 326
327 327 }
328 328
329 329 /*
330 330 * Note to future maintainers: with the change of wall to use the
331 331 * getutxent() API, the forked children (created by this function)
332 332 * must call _exit as opposed to exit. This is necessary to avoid
333 333 * unwanted fflushing of getutxent's stdio stream (caused by atexit
334 334 * processing).
335 335 */
336 336 static void
337 337 sendmes(struct utmpx *p, zoneid_t zid)
338 338 {
339 339 int i;
340 340 char *s;
341 341 static char device[LMAX + 6];
342 342 char *bp;
343 343 int ibp;
344 344 FILE *f;
345 345 int fd, tmpl_fd;
346 346 boolean_t zoneenter = B_FALSE;
347 347
348 348 if (zid != getzoneid()) {
349 349 zoneenter = B_TRUE;
350 350 tmpl_fd = init_template();
351 351 if (tmpl_fd == -1) {
352 352 (void) fprintf(stderr, "Could not initialize "
353 353 "process contract");
354 354 return;
355 355 }
356 356 }
357 357
358 358 while ((i = (int)fork()) == -1) {
359 359 (void) alarm(60);
360 360 (void) wait((int *)0);
361 361 (void) alarm(0);
362 362 }
363 363
364 364 if (i)
365 365 return;
366 366
367 367 if (zoneenter && zone_enter(zid) == -1) {
368 368 char zonename[ZONENAME_MAX];
369 369 (void) getzonenamebyid(zid, zonename, ZONENAME_MAX);
370 370 (void) fprintf(stderr, "Could not enter zone "
371 371 "%s\n", zonename);
372 372 }
373 373 if (zoneenter)
374 374 (void) ct_tmpl_clear(tmpl_fd);
375 375
376 376 if (gflag)
377 377 if (!chkgrp(p->ut_user))
378 378 _exit(0);
379 379
380 380 (void) signal(SIGHUP, SIG_IGN);
381 381 (void) alarm(60);
382 382 s = &device[0];
383 383 (void) snprintf(s, sizeof (device), "/dev/%.*s", LMAX, p->ut_line);
384 384
385 385 /* check if the device is really a tty */
386 386 if ((fd = open(s, O_WRONLY|O_NOCTTY|O_NONBLOCK)) == -1) {
387 387 (void) fprintf(stderr, "Cannot send to %.*s on %s\n",
388 388 NMAX, p->ut_user, s);
389 389 perror("open");
390 390 (void) fflush(stderr);
391 391 _exit(1);
392 392 } else {
393 393 if (!isatty(fd)) {
394 394 (void) fprintf(stderr,
395 395 "Cannot send to device %.*s %s\n",
396 396 LMAX, p->ut_line,
397 397 "because it's not a tty");
398 398 openlog("wall", 0, LOG_AUTH);
399 399 syslog(LOG_CRIT, "%.*s in utmpx is not a tty\n",
400 400 LMAX, p->ut_line);
401 401 closelog();
402 402 (void) fflush(stderr);
403 403 _exit(1);
404 404 }
405 405 }
406 406 #ifdef DEBUG
407 407 (void) close(fd);
408 408 f = fopen("wall.debug", "a");
409 409 #else
410 410 f = fdopen(fd, "w");
411 411 #endif
412 412 if (f == NULL) {
413 413 (void) fprintf(stderr, "Cannot send to %-.*s on %s\n",
414 414 NMAX, &p->ut_user[0], s);
415 415 perror("open");
416 416 (void) fflush(stderr);
417 417 _exit(1);
418 418 }
419 419 (void) fprintf(f,
420 420 "\07\07\07Broadcast Message from %s (%s) on %s %19.19s",
421 421 who, line, systm, time_buf);
422 422 if (gflag)
423 423 (void) fprintf(f, " to group %s", grpname);
424 424 (void) fprintf(f, "...\n");
425 425 #ifdef DEBUG
426 426 (void) fprintf(f, "DEBUG: To %.*s on %s\n", NMAX, p->ut_user, s);
427 427 #endif
428 428 i = strlen(mesg);
429 429 for (bp = mesg; --i >= 0; bp++) {
430 430 ibp = (unsigned int)((unsigned char) *bp);
431 431 if (*bp == '\n')
432 432 (void) putc('\r', f);
433 433 if (isprint(ibp) || *bp == '\r' || *bp == '\013' ||
434 434 *bp == ' ' || *bp == '\t' || *bp == '\n' || *bp == '\007') {
435 435 (void) putc(*bp, f);
436 436 } else {
437 437 if (!isascii(*bp)) {
438 438 (void) fputs("M-", f);
439 439 *bp = toascii(*bp);
440 440 }
441 441 if (iscntrl(*bp)) {
442 442 (void) putc('^', f);
443 443 (void) putc(*bp + 0100, f);
444 444 }
445 445 else
446 446 (void) putc(*bp, f);
447 447 }
448 448
449 449 if (*bp == '\n')
450 450 (void) fflush(f);
451 451
452 452 if (ferror(f) || feof(f)) {
453 453 (void) printf("\n\007Write failed\n");
454 454 (void) fflush(stdout);
455 455 _exit(1);
456 456 }
457 457 }
458 458 (void) fclose(f);
459 459 (void) close(fd);
460 460 _exit(0);
461 461 }
462 462
463 463
464 464 static int
465 465 chkgrp(char *name)
466 466 {
467 467 int i;
468 468 char user[NMAX + 1];
469 469
470 470 (void) strlcpy(user, name, sizeof (user));
471 471 for (i = 0; pgrp->gr_mem[i] && pgrp->gr_mem[i][0]; i++) {
472 472 if (strcmp(user, pgrp->gr_mem[i]) == 0)
473 473 return (1);
474 474 }
475 475
476 476 return (0);
477 477 }
478 478
479 479 static int
480 480 init_template(void) {
481 481 int fd = 0;
482 482 int err = 0;
483 483
484 484 fd = open64(CTFS_ROOT "/process/template", O_RDWR);
485 485 if (fd == -1)
486 486 return (-1);
487 487
488 488 err |= ct_tmpl_set_critical(fd, 0);
489 489 err |= ct_tmpl_set_informative(fd, 0);
490 490 err |= ct_pr_tmpl_set_fatal(fd, CT_PR_EV_HWERR);
491 491 err |= ct_pr_tmpl_set_param(fd, CT_PR_PGRPONLY | CT_PR_REGENT);
492 492 if (err || ct_tmpl_activate(fd)) {
493 493 (void) close(fd);
494 494 return (-1);
495 495 }
496 496
497 497 return (fd);
498 498 }
↓ open down ↓ |
171 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX