12341Scsgr/*
22341Scsgr * Copyright (c) 1993 Christopher G. Demetriou
32341Scsgr * All rights reserved.
42341Scsgr *
52341Scsgr * Redistribution and use in source and binary forms, with or without
62341Scsgr * modification, are permitted provided that the following conditions
72341Scsgr * are met:
82341Scsgr * 1. Redistributions of source code must retain the above copyright
92341Scsgr *    notice, this list of conditions and the following disclaimer.
102341Scsgr * 2. Redistributions in binary form must reproduce the above copyright
112341Scsgr *    notice, this list of conditions and the following disclaimer in the
122341Scsgr *    documentation and/or other materials provided with the distribution.
132341Scsgr * 3. The name of the author may not be used to endorse or promote
142341Scsgr *    products derived from this software without specific prior written
152341Scsgr *    permission.
162341Scsgr *
172341Scsgr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
182341Scsgr * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
192341Scsgr * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
202341Scsgr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
212341Scsgr * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
222341Scsgr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
232341Scsgr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
242341Scsgr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
252341Scsgr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
262341Scsgr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
272341Scsgr * SUCH DAMAGE.
282341Scsgr */
292341Scsgr
30216560Scharnier#include <sys/cdefs.h>
31216560Scharnier__FBSDID("$FreeBSD$");
322341Scsgr
3331488Scharnier#include <err.h>
342341Scsgr#include <pwd.h>
3531488Scharnier#include <signal.h>
362341Scsgr#include <stdio.h>
3731488Scharnier#include <stdlib.h>
382341Scsgr#include <string.h>
3931488Scharnier#include <syslog.h>
4090868Smike#include <arpa/inet.h>
4131488Scharnier#include <rpc/rpc.h>
4231488Scharnier#include <rpcsvc/rwall.h>
432341Scsgr#include <sys/socket.h>
4431488Scharnier#include <sys/types.h>
452341Scsgr#include <sys/wait.h>
4631488Scharnier#include <unistd.h>
472341Scsgr
482341Scsgr#ifdef OSF
492341Scsgr#define WALL_CMD "/usr/sbin/wall"
502341Scsgr#else
512341Scsgr#define WALL_CMD "/usr/bin/wall -n"
522341Scsgr#endif
532341Scsgr
5490336Simpvoid wallprog_1(struct svc_req *rqstp, SVCXPRT *transp);
5590336Simpvoid possess(void);
5690336Simpvoid killkids(int sig);
5790336Simpstatic void usage(void);
582341Scsgr
592341Scsgrint nodaemon = 0;
602341Scsgrint from_inetd = 1;
612341Scsgr
6231488Scharnierint
6390336Simpmain(int argc, char *argv[])
642341Scsgr{
652341Scsgr	SVCXPRT *transp;
66141918Sstefanf	socklen_t salen;
67141918Sstefanf	int ok;
68100120Salfred	struct sockaddr_storage sa;
692341Scsgr
702341Scsgr	if (argc == 2 && !strcmp(argv[1], "-n"))
712341Scsgr		nodaemon = 1;
7231488Scharnier	if (argc != 1 && !nodaemon)
7331488Scharnier		usage();
742341Scsgr
752341Scsgr	if (geteuid() == 0) {
762341Scsgr		struct passwd *pep = getpwnam("nobody");
772341Scsgr		if (pep)
782341Scsgr			setuid(pep->pw_uid);
792341Scsgr		else
802341Scsgr			setuid(getuid());
812341Scsgr	}
822341Scsgr
832341Scsgr        /*
842341Scsgr         * See if inetd started us
852341Scsgr         */
864659Sats	salen = sizeof(sa);
872341Scsgr        if (getsockname(0, (struct sockaddr *)&sa, &salen) < 0) {
882341Scsgr                from_inetd = 0;
892341Scsgr        }
908870Srgrimes
912341Scsgr        if (!from_inetd) {
922341Scsgr                if (!nodaemon)
932341Scsgr                        possess();
942341Scsgr
95100120Salfred		(void)rpcb_unset(WALLPROG, WALLVERS, NULL);
962341Scsgr        }
972341Scsgr
982341Scsgr	(void)signal(SIGCHLD, killkids);
992341Scsgr
10031488Scharnier	openlog("rpc.rwalld", LOG_CONS|LOG_PID, LOG_DAEMON);
10131488Scharnier
102100120Salfred	/* create and register the service */
103100120Salfred	if (from_inetd) {
104100120Salfred		transp = svc_tli_create(0, NULL, NULL, 0, 0);
105100120Salfred		if (transp == NULL) {
106100120Salfred			syslog(LOG_ERR, "couldn't create udp service.");
107100120Salfred			exit(1);
108100120Salfred		}
109100120Salfred		ok = svc_reg(transp, WALLPROG, WALLVERS,
110100120Salfred			     wallprog_1, NULL);
111100120Salfred	} else
112100120Salfred		ok = svc_create(wallprog_1,
113100120Salfred				WALLPROG, WALLVERS, "udp");
114100120Salfred	if (!ok) {
115100120Salfred		syslog(LOG_ERR, "unable to register (WALLPROG, WALLVERS, %s)", (!from_inetd)?"udp":"(inetd)");
1162341Scsgr		exit(1);
1172341Scsgr	}
1182341Scsgr	svc_run();
11931488Scharnier	syslog(LOG_ERR, "svc_run returned");
1202341Scsgr	exit(1);
12131488Scharnier}
1222341Scsgr
12331488Scharnierstatic void
12490336Simpusage(void)
12531488Scharnier{
12631488Scharnier	fprintf(stderr, "usage: rpc.rwalld [-n]\n");
12731488Scharnier	exit(1);
1282341Scsgr}
1292341Scsgr
13090336Simpvoid
13190336Simppossess(void)
1322341Scsgr{
1332341Scsgr	daemon(0, 0);
1342341Scsgr}
1352341Scsgr
13690336Simpvoid
137216560Scharnierkillkids(int sig __unused)
1382341Scsgr{
1392341Scsgr	while(wait4(-1, NULL, WNOHANG, NULL) > 0)
1402341Scsgr		;
1412341Scsgr}
1422341Scsgr
14390336Simpvoid *
144216560Scharnierwallproc_wall_1_svc(wrapstring *s, struct svc_req *rqstp __unused)
1452341Scsgr{
14632629Swpaul	static void		*dummy = NULL;
14732629Swpaul
1482341Scsgr	/* fork, popen wall with special option, and send the message */
1492341Scsgr	if (fork() == 0) {
1502341Scsgr		FILE *pfp;
1512341Scsgr
1522341Scsgr		pfp = popen(WALL_CMD, "w");
1532341Scsgr		if (pfp != NULL) {
1542341Scsgr			fprintf(pfp, "\007\007%s", *s);
1552341Scsgr			pclose(pfp);
1562341Scsgr			exit(0);
1572341Scsgr		}
1582341Scsgr	}
15932629Swpaul	return(&dummy);
1602341Scsgr}
1612341Scsgr
1622341Scsgrvoid
16390336Simpwallprog_1(struct svc_req *rqstp, SVCXPRT *transp)
1642341Scsgr{
1652341Scsgr	union {
1662341Scsgr		char *wallproc_wall_1_arg;
1672341Scsgr	} argument;
1682341Scsgr	char *result;
1692341Scsgr	bool_t (*xdr_argument)(), (*xdr_result)();
1702341Scsgr	char *(*local)();
1712341Scsgr
1722341Scsgr	switch (rqstp->rq_proc) {
1732341Scsgr	case NULLPROC:
17495658Sdes		(void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL);
1752341Scsgr		goto leave;
1762341Scsgr
1772341Scsgr	case WALLPROC_WALL:
1782341Scsgr		xdr_argument = xdr_wrapstring;
1792341Scsgr		xdr_result = xdr_void;
18032629Swpaul		local = (char *(*)()) wallproc_wall_1_svc;
1812341Scsgr		break;
1822341Scsgr
1832341Scsgr	default:
1842341Scsgr		svcerr_noproc(transp);
1852341Scsgr		goto leave;
1862341Scsgr	}
18795658Sdes	bzero(&argument, sizeof(argument));
18895658Sdes	if (!svc_getargs(transp, (xdrproc_t)xdr_argument, &argument)) {
1892341Scsgr		svcerr_decode(transp);
1902341Scsgr		goto leave;
1912341Scsgr	}
1922341Scsgr	result = (*local)(&argument, rqstp);
19395658Sdes	if (result != NULL &&
19495658Sdes	    !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) {
1952341Scsgr		svcerr_systemerr(transp);
1962341Scsgr	}
19795658Sdes	if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, &argument)) {
19831488Scharnier		syslog(LOG_ERR, "unable to free arguments");
1992341Scsgr		exit(1);
2002341Scsgr	}
2012341Scsgrleave:
2022341Scsgr        if (from_inetd)
2032341Scsgr                exit(0);
2042341Scsgr}
205