1*fc23d32cSchristos /* $NetBSD: wall.c,v 1.25 2004/10/27 17:49:19 christos Exp $ */ 2a8bfd3d1Sjtc 361f28255Scgd /* 4a8bfd3d1Sjtc * Copyright (c) 1988, 1990, 1993 5a8bfd3d1Sjtc * The Regents of the University of California. All rights reserved. 661f28255Scgd * 761f28255Scgd * Redistribution and use in source and binary forms, with or without 861f28255Scgd * modification, are permitted provided that the following conditions 961f28255Scgd * are met: 1061f28255Scgd * 1. Redistributions of source code must retain the above copyright 1161f28255Scgd * notice, this list of conditions and the following disclaimer. 1261f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright 1361f28255Scgd * notice, this list of conditions and the following disclaimer in the 1461f28255Scgd * documentation and/or other materials provided with the distribution. 1589aaa1bbSagc * 3. Neither the name of the University nor the names of its contributors 1661f28255Scgd * may be used to endorse or promote products derived from this software 1761f28255Scgd * without specific prior written permission. 1861f28255Scgd * 1961f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2061f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2161f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2261f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2361f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2461f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2561f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2661f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2761f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2861f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2961f28255Scgd * SUCH DAMAGE. 3061f28255Scgd */ 3161f28255Scgd 32c897d730Schristos #include <sys/cdefs.h> 3361f28255Scgd #ifndef lint 34c897d730Schristos __COPYRIGHT("@(#) Copyright (c) 1988, 1990, 1993\n\ 35c897d730Schristos The Regents of the University of California. All rights reserved.\n"); 3661f28255Scgd #endif /* not lint */ 3761f28255Scgd 3861f28255Scgd #ifndef lint 39a8bfd3d1Sjtc #if 0 40a8bfd3d1Sjtc static char sccsid[] = "@(#)wall.c 8.2 (Berkeley) 11/16/93"; 41a8bfd3d1Sjtc #endif 42*fc23d32cSchristos __RCSID("$NetBSD: wall.c,v 1.25 2004/10/27 17:49:19 christos Exp $"); 4361f28255Scgd #endif /* not lint */ 4461f28255Scgd 4561f28255Scgd /* 4661f28255Scgd * This program is not related to David Wall, whose Stanford Ph.D. thesis 4761f28255Scgd * is entitled "Mechanisms for Broadcast and Selective Broadcast". 4861f28255Scgd */ 4961f28255Scgd 5061f28255Scgd #include <sys/param.h> 5161f28255Scgd #include <sys/stat.h> 5261f28255Scgd #include <sys/time.h> 5361f28255Scgd #include <sys/uio.h> 54a8bfd3d1Sjtc 55a6f32a1dSlukem #include <err.h> 56b6a63b16Slukem #include <grp.h> 572abe3770Sitojun #include <errno.h> 58a8bfd3d1Sjtc #include <paths.h> 5961f28255Scgd #include <pwd.h> 6061f28255Scgd #include <stdio.h> 6161f28255Scgd #include <stdlib.h> 62f7c6bf57Sjtc #include <string.h> 63f7c6bf57Sjtc #include <unistd.h> 64c897d730Schristos #include <util.h> 65a8bfd3d1Sjtc 66c020d65eSchristos #include "utmpentry.h" 6745aed1fbSchristos #include "term_chk.h" 68c020d65eSchristos 69b6a63b16Slukem void addgroup(char *); 70c5775359Smjl void makemsg(const char *); 71c5775359Smjl int main(int, char **); 72b6a63b16Slukem void usage(void); 73b6a63b16Slukem 74b6a63b16Slukem struct wallgroup { 75b6a63b16Slukem gid_t gid; 76b6a63b16Slukem char *name; 77b6a63b16Slukem char **mem; 78b6a63b16Slukem struct wallgroup *next; 79b6a63b16Slukem } *grouplist; 8061f28255Scgd 8161f28255Scgd int nobanner; 822abe3770Sitojun size_t mbufsize; 8361f28255Scgd char *mbuf; 8461f28255Scgd 8561f28255Scgd /* ARGSUSED */ 86f7c6bf57Sjtc int 87c5775359Smjl main(int argc, char **argv) 8861f28255Scgd { 8961f28255Scgd int ch; 9061f28255Scgd struct iovec iov; 91b6a63b16Slukem char *p, **mem; 92c020d65eSchristos struct utmpentry *ep; 932abe3770Sitojun gid_t egid; 94b6a63b16Slukem struct wallgroup *wg; 95b6a63b16Slukem struct passwd *pw; 962abe3770Sitojun 97b6a63b16Slukem setprogname(argv[0]); 982abe3770Sitojun egid = getegid(); 992abe3770Sitojun if (setegid(getgid()) == -1) 1002abe3770Sitojun err(1, "setegid"); 101b6a63b16Slukem pw = getpwnam("nobody"); 10261f28255Scgd 103*fc23d32cSchristos (void)check_sender(NULL, getuid(), egid); 10445aed1fbSchristos 105b6a63b16Slukem while ((ch = getopt(argc, argv, "g:n")) != -1) 10661f28255Scgd switch (ch) { 10761f28255Scgd case 'n': 10861f28255Scgd /* undoc option for shutdown: suppress banner */ 109b6a63b16Slukem if (geteuid() == 0 || (pw && getuid() == pw->pw_uid)) 11061f28255Scgd nobanner = 1; 11161f28255Scgd break; 112b6a63b16Slukem case 'g': 113b6a63b16Slukem addgroup(optarg); 114b6a63b16Slukem break; 11561f28255Scgd case '?': 11661f28255Scgd default: 117b6a63b16Slukem usage(); 11861f28255Scgd } 11961f28255Scgd argc -= optind; 12061f28255Scgd argv += optind; 12161f28255Scgd if (argc > 1) 122b6a63b16Slukem usage(); 12361f28255Scgd 12461f28255Scgd makemsg(*argv); 12561f28255Scgd 12661f28255Scgd iov.iov_base = mbuf; 12761f28255Scgd iov.iov_len = mbufsize; 128c020d65eSchristos (void)getutentries(NULL, &ep); 1292abe3770Sitojun (void)setegid(egid); 130b6a63b16Slukem for (; ep; ep = ep->next) { 131b6a63b16Slukem if (grouplist) { 132b6a63b16Slukem int ingroup; 133b6a63b16Slukem 134b6a63b16Slukem ingroup = 0; 135b6a63b16Slukem pw = getpwnam(ep->name); 136b6a63b16Slukem if (!pw) 137b6a63b16Slukem continue; 138b6a63b16Slukem for (wg = grouplist; wg && !ingroup; wg = wg->next) { 139b6a63b16Slukem if (wg->gid == pw->pw_gid) 140b6a63b16Slukem ingroup = 1; 141b6a63b16Slukem for (mem = wg->mem; *mem && !ingroup; mem++) 142b6a63b16Slukem if (strcmp(ep->name, *mem) == 0) 143b6a63b16Slukem ingroup = 1; 144b6a63b16Slukem } 145b6a63b16Slukem if (ingroup == 0) 146b6a63b16Slukem continue; 147b6a63b16Slukem } 148c020d65eSchristos if ((p = ttymsg(&iov, 1, ep->line, 60*5)) != NULL) 149a6f32a1dSlukem warnx("%s", p); 150b6a63b16Slukem } 15161f28255Scgd exit(0); 15261f28255Scgd } 15361f28255Scgd 154f7c6bf57Sjtc void 155b6a63b16Slukem addgroup(char *name) 156b6a63b16Slukem { 157b6a63b16Slukem int i; 158b6a63b16Slukem struct group *grp; 159b6a63b16Slukem struct wallgroup *g; 160b6a63b16Slukem 161aff92a77Slukem grp = getgrnam(name); 162aff92a77Slukem if ((grp = getgrnam(name)) == NULL) 163aff92a77Slukem errx(1, "unknown group `%s'", name); 164b6a63b16Slukem for (i = 0; grp->gr_mem[i]; i++) 165b6a63b16Slukem continue; 166b6a63b16Slukem 167b6a63b16Slukem g = (struct wallgroup *)malloc(sizeof *g); 168b6a63b16Slukem if (g == NULL) 169b6a63b16Slukem err(1, "malloc"); 170b6a63b16Slukem g->gid = grp->gr_gid; 171b6a63b16Slukem g->name = name; 172b6a63b16Slukem g->mem = (char **)malloc(i + 1); 173b6a63b16Slukem if (g->mem == NULL) 174b6a63b16Slukem err(1, "malloc"); 175b6a63b16Slukem for (i = 0; grp->gr_mem[i] != NULL; i++) { 176b6a63b16Slukem g->mem[i] = strdup(grp->gr_mem[i]); 177b6a63b16Slukem if (g->mem[i] == NULL) 178b6a63b16Slukem err(1, "malloc"); 179b6a63b16Slukem } 180b6a63b16Slukem g->mem[i] = NULL; 181b6a63b16Slukem g->next = grouplist; 182b6a63b16Slukem grouplist = g; 183b6a63b16Slukem } 184b6a63b16Slukem 185b6a63b16Slukem void 186c5775359Smjl makemsg(const char *fname) 18761f28255Scgd { 1882abe3770Sitojun int ch, cnt; 18961f28255Scgd struct tm *lt; 19061f28255Scgd struct passwd *pw; 19161f28255Scgd struct stat sbuf; 192c897d730Schristos time_t now; 19361f28255Scgd FILE *fp; 19461f28255Scgd int fd; 195af26acbcSmycroft const char *whom; 196b6a63b16Slukem char *p, *tty, tmpname[MAXPATHLEN], lbuf[100], 197b6a63b16Slukem hostname[MAXHOSTNAMELEN+1]; 19861f28255Scgd 19923768a9eSmrg (void)snprintf(tmpname, sizeof tmpname, "%s/wall.XXXXXX", _PATH_TMP); 2002abe3770Sitojun if ((fd = mkstemp(tmpname)) == -1) 201a6f32a1dSlukem err(1, "can't open temporary file"); 20261f28255Scgd (void)unlink(tmpname); 2032abe3770Sitojun if (!(fp = fdopen(fd, "r+"))) 2042abe3770Sitojun err(1, "can't open temporary file"); 20561f28255Scgd 20661f28255Scgd if (!nobanner) { 20761f28255Scgd if (!(whom = getlogin())) 20861f28255Scgd whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???"; 20961f28255Scgd (void)gethostname(hostname, sizeof(hostname)); 210ed666575Smrg hostname[sizeof(hostname) - 1] = '\0'; 21161f28255Scgd (void)time(&now); 21261f28255Scgd lt = localtime(&now); 21361f28255Scgd 21461f28255Scgd /* 21561f28255Scgd * all this stuff is to blank out a square for the message; 21661f28255Scgd * we wrap message lines at column 79, not 80, because some 21761f28255Scgd * terminals wrap after 79, some do not, and we can't tell. 21861f28255Scgd * Which means that we may leave a non-blank character 21961f28255Scgd * in column 80, but that can't be helped. 22061f28255Scgd */ 22161f28255Scgd (void)fprintf(fp, "\r%79s\r\n", " "); 22223768a9eSmrg (void)snprintf(lbuf, sizeof lbuf, 22323768a9eSmrg "Broadcast Message from %s@%s", whom, hostname); 22461f28255Scgd (void)fprintf(fp, "%-79.79s\007\007\r\n", lbuf); 22599ebb803Staca tty = ttyname(STDERR_FILENO); 22699ebb803Staca if (tty == NULL) 22720117cd1Staca tty = "??"; 22899ebb803Staca (void)snprintf(lbuf, sizeof lbuf, 229b6a63b16Slukem " (%s) at %d:%02d %s...", tty, 230b6a63b16Slukem lt->tm_hour, lt->tm_min, lt->tm_zone); 23161f28255Scgd (void)fprintf(fp, "%-79.79s\r\n", lbuf); 23261f28255Scgd } 23361f28255Scgd (void)fprintf(fp, "%79s\r\n", " "); 23461f28255Scgd 235a6f32a1dSlukem if (fname && !(freopen(fname, "r", stdin))) 236a6f32a1dSlukem err(1, "can't read %s", fname); 23761f28255Scgd while (fgets(lbuf, sizeof(lbuf), stdin)) 238a8bfd3d1Sjtc for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) { 23961f28255Scgd if (cnt == 79 || ch == '\n') { 24061f28255Scgd for (; cnt < 79; ++cnt) 24161f28255Scgd putc(' ', fp); 24261f28255Scgd putc('\r', fp); 24361f28255Scgd putc('\n', fp); 244f90eda1cSmycroft cnt = -1; 245f90eda1cSmycroft } 246f90eda1cSmycroft if (ch != '\n') 24761f28255Scgd putc(ch, fp); 24861f28255Scgd } 24961f28255Scgd (void)fprintf(fp, "%79s\r\n", " "); 25061f28255Scgd rewind(fp); 25161f28255Scgd 252a6f32a1dSlukem if (fstat(fd, &sbuf)) 253a6f32a1dSlukem err(1, "can't stat temporary file"); 2542abe3770Sitojun if (sbuf.st_size > SIZE_T_MAX) 2552abe3770Sitojun errx(1, "file too big"); 25661f28255Scgd mbufsize = sbuf.st_size; 2572abe3770Sitojun if (!(mbuf = malloc(mbufsize))) 258a6f32a1dSlukem err(1, "malloc"); 2592abe3770Sitojun if (fread(mbuf, 1, mbufsize, fp) != mbufsize) 260a6f32a1dSlukem err(1, "can't read temporary file"); 2612abe3770Sitojun (void)fclose(fp); 26261f28255Scgd } 263b6a63b16Slukem 264b6a63b16Slukem void 265b6a63b16Slukem usage(void) 266b6a63b16Slukem { 267b6a63b16Slukem 268b6a63b16Slukem (void)fprintf(stderr, "usage: %s [-g group] [file]\n", getprogname()); 269b6a63b16Slukem exit(1); 270b6a63b16Slukem } 271