xref: /freebsd/libexec/rpc.rwalld/rwalld.c (revision a174e5b13a175815f5fd5137885ce59136d46853)
1935a0024SGeoff Rehmet /*
2935a0024SGeoff Rehmet  * Copyright (c) 1993 Christopher G. Demetriou
3935a0024SGeoff Rehmet  * All rights reserved.
4935a0024SGeoff Rehmet  *
5935a0024SGeoff Rehmet  * Redistribution and use in source and binary forms, with or without
6935a0024SGeoff Rehmet  * modification, are permitted provided that the following conditions
7935a0024SGeoff Rehmet  * are met:
8935a0024SGeoff Rehmet  * 1. Redistributions of source code must retain the above copyright
9935a0024SGeoff Rehmet  *    notice, this list of conditions and the following disclaimer.
10935a0024SGeoff Rehmet  * 2. Redistributions in binary form must reproduce the above copyright
11935a0024SGeoff Rehmet  *    notice, this list of conditions and the following disclaimer in the
12935a0024SGeoff Rehmet  *    documentation and/or other materials provided with the distribution.
13935a0024SGeoff Rehmet  * 3. The name of the author may not be used to endorse or promote
14935a0024SGeoff Rehmet  *    products derived from this software without specific prior written
15935a0024SGeoff Rehmet  *    permission.
16935a0024SGeoff Rehmet  *
17935a0024SGeoff Rehmet  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18935a0024SGeoff Rehmet  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19935a0024SGeoff Rehmet  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20935a0024SGeoff Rehmet  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21935a0024SGeoff Rehmet  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22935a0024SGeoff Rehmet  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23935a0024SGeoff Rehmet  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24935a0024SGeoff Rehmet  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25935a0024SGeoff Rehmet  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26935a0024SGeoff Rehmet  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27935a0024SGeoff Rehmet  * SUCH DAMAGE.
28935a0024SGeoff Rehmet  */
29935a0024SGeoff Rehmet 
30935a0024SGeoff Rehmet #ifndef lint
3140150947SPhilippe Charnier static const char rcsid[] =
327f3dea24SPeter Wemm   "$FreeBSD$";
33935a0024SGeoff Rehmet #endif /* not lint */
34935a0024SGeoff Rehmet 
3540150947SPhilippe Charnier #include <err.h>
36935a0024SGeoff Rehmet #include <pwd.h>
37935a0024SGeoff Rehmet #include <signal.h>
3840150947SPhilippe Charnier #include <stdio.h>
3940150947SPhilippe Charnier #include <stdlib.h>
4040150947SPhilippe Charnier #include <string.h>
4140150947SPhilippe Charnier #include <syslog.h>
42935a0024SGeoff Rehmet #include <rpc/rpc.h>
4340150947SPhilippe Charnier #include <rpc/pmap_clnt.h>
44935a0024SGeoff Rehmet #include <rpcsvc/rwall.h>
4540150947SPhilippe Charnier #include <sys/socket.h>
4640150947SPhilippe Charnier #include <sys/types.h>
4740150947SPhilippe Charnier #include <sys/wait.h>
4840150947SPhilippe Charnier #include <unistd.h>
49935a0024SGeoff Rehmet 
50935a0024SGeoff Rehmet #ifdef OSF
51935a0024SGeoff Rehmet #define WALL_CMD "/usr/sbin/wall"
52935a0024SGeoff Rehmet #else
53935a0024SGeoff Rehmet #define WALL_CMD "/usr/bin/wall -n"
54935a0024SGeoff Rehmet #endif
55935a0024SGeoff Rehmet 
56a174e5b1SWarner Losh void wallprog_1(struct svc_req *rqstp, SVCXPRT *transp);
57a174e5b1SWarner Losh void possess(void);
58a174e5b1SWarner Losh void killkids(int sig);
59a174e5b1SWarner Losh static void usage(void);
60935a0024SGeoff Rehmet 
61935a0024SGeoff Rehmet int nodaemon = 0;
62935a0024SGeoff Rehmet int from_inetd = 1;
63935a0024SGeoff Rehmet 
6440150947SPhilippe Charnier int
65a174e5b1SWarner Losh main(int argc, char *argv[])
66935a0024SGeoff Rehmet {
67935a0024SGeoff Rehmet 	SVCXPRT *transp;
68935a0024SGeoff Rehmet 	int s, salen;
69935a0024SGeoff Rehmet 	struct sockaddr_in sa;
70935a0024SGeoff Rehmet         int sock = 0;
71935a0024SGeoff Rehmet         int proto = 0;
72935a0024SGeoff Rehmet 
73935a0024SGeoff Rehmet 	if (argc == 2 && !strcmp(argv[1], "-n"))
74935a0024SGeoff Rehmet 		nodaemon = 1;
7540150947SPhilippe Charnier 	if (argc != 1 && !nodaemon)
7640150947SPhilippe Charnier 		usage();
77935a0024SGeoff Rehmet 
78935a0024SGeoff Rehmet 	if (geteuid() == 0) {
79935a0024SGeoff Rehmet 		struct passwd *pep = getpwnam("nobody");
80935a0024SGeoff Rehmet 		if (pep)
81935a0024SGeoff Rehmet 			setuid(pep->pw_uid);
82935a0024SGeoff Rehmet 		else
83935a0024SGeoff Rehmet 			setuid(getuid());
84935a0024SGeoff Rehmet 	}
85935a0024SGeoff Rehmet 
86935a0024SGeoff Rehmet         /*
87935a0024SGeoff Rehmet          * See if inetd started us
88935a0024SGeoff Rehmet          */
897c760cfdSAndreas Schulz 	salen = sizeof(sa);
90935a0024SGeoff Rehmet         if (getsockname(0, (struct sockaddr *)&sa, &salen) < 0) {
91935a0024SGeoff Rehmet                 from_inetd = 0;
92935a0024SGeoff Rehmet                 sock = RPC_ANYSOCK;
93935a0024SGeoff Rehmet                 proto = IPPROTO_UDP;
94935a0024SGeoff Rehmet         }
95935a0024SGeoff Rehmet 
96935a0024SGeoff Rehmet         if (!from_inetd) {
97935a0024SGeoff Rehmet                 if (!nodaemon)
98935a0024SGeoff Rehmet                         possess();
99935a0024SGeoff Rehmet 
100935a0024SGeoff Rehmet                 (void)pmap_unset(WALLPROG, WALLVERS);
10140150947SPhilippe Charnier                 if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
10240150947SPhilippe Charnier                         err(1, "socket");
103935a0024SGeoff Rehmet                 bzero((char *)&sa, sizeof sa);
10440150947SPhilippe Charnier                 if (bind(s, (struct sockaddr *)&sa, sizeof sa) < 0)
10540150947SPhilippe Charnier                         err(1, "bind");
106935a0024SGeoff Rehmet 
107935a0024SGeoff Rehmet                 salen = sizeof sa;
10840150947SPhilippe Charnier                 if (getsockname(s, (struct sockaddr *)&sa, &salen))
10940150947SPhilippe Charnier                         err(1, "getsockname");
110935a0024SGeoff Rehmet 
111935a0024SGeoff Rehmet                 pmap_set(WALLPROG, WALLVERS, IPPROTO_UDP, ntohs(sa.sin_port));
11240150947SPhilippe Charnier                 if (dup2(s, 0) < 0)
11340150947SPhilippe Charnier                         err(1, "dup2");
114935a0024SGeoff Rehmet                 (void)pmap_unset(WALLPROG, WALLVERS);
115935a0024SGeoff Rehmet         }
116935a0024SGeoff Rehmet 
117935a0024SGeoff Rehmet 	(void)signal(SIGCHLD, killkids);
118935a0024SGeoff Rehmet 
11940150947SPhilippe Charnier 	openlog("rpc.rwalld", LOG_CONS|LOG_PID, LOG_DAEMON);
12040150947SPhilippe Charnier 
121935a0024SGeoff Rehmet 	transp = svcudp_create(sock);
122935a0024SGeoff Rehmet 	if (transp == NULL) {
12340150947SPhilippe Charnier 		syslog(LOG_ERR, "cannot create udp service");
124935a0024SGeoff Rehmet 		exit(1);
125935a0024SGeoff Rehmet 	}
126935a0024SGeoff Rehmet 	if (!svc_register(transp, WALLPROG, WALLVERS, wallprog_1, proto)) {
12740150947SPhilippe Charnier 		syslog(LOG_ERR, "unable to register (WALLPROG, WALLVERS, %s)", proto?"udp":"(inetd)");
128935a0024SGeoff Rehmet 		exit(1);
129935a0024SGeoff Rehmet 	}
130935a0024SGeoff Rehmet 	svc_run();
13140150947SPhilippe Charnier 	syslog(LOG_ERR, "svc_run returned");
132935a0024SGeoff Rehmet 	exit(1);
13340150947SPhilippe Charnier }
134935a0024SGeoff Rehmet 
13540150947SPhilippe Charnier static void
136a174e5b1SWarner Losh usage(void)
13740150947SPhilippe Charnier {
13840150947SPhilippe Charnier 	fprintf(stderr, "usage: rpc.rwalld [-n]\n");
13940150947SPhilippe Charnier 	exit(1);
140935a0024SGeoff Rehmet }
141935a0024SGeoff Rehmet 
142a174e5b1SWarner Losh void
143a174e5b1SWarner Losh possess(void)
144935a0024SGeoff Rehmet {
145935a0024SGeoff Rehmet 	daemon(0, 0);
146935a0024SGeoff Rehmet }
147935a0024SGeoff Rehmet 
148a174e5b1SWarner Losh void
149a174e5b1SWarner Losh killkids(int sig)
150935a0024SGeoff Rehmet {
151935a0024SGeoff Rehmet 	while(wait4(-1, NULL, WNOHANG, NULL) > 0)
152935a0024SGeoff Rehmet 		;
153935a0024SGeoff Rehmet }
154935a0024SGeoff Rehmet 
155a174e5b1SWarner Losh void *
156a174e5b1SWarner Losh wallproc_wall_1_svc(wrapstring *s, struct svc_req *rqstp)
157935a0024SGeoff Rehmet {
158e4a0e42bSBill Paul 	static void		*dummy = NULL;
159e4a0e42bSBill Paul 
160935a0024SGeoff Rehmet 	/* fork, popen wall with special option, and send the message */
161935a0024SGeoff Rehmet 	if (fork() == 0) {
162935a0024SGeoff Rehmet 		FILE *pfp;
163935a0024SGeoff Rehmet 
164935a0024SGeoff Rehmet 		pfp = popen(WALL_CMD, "w");
165935a0024SGeoff Rehmet 		if (pfp != NULL) {
166935a0024SGeoff Rehmet 			fprintf(pfp, "\007\007%s", *s);
167935a0024SGeoff Rehmet 			pclose(pfp);
168935a0024SGeoff Rehmet 			exit(0);
169935a0024SGeoff Rehmet 		}
170935a0024SGeoff Rehmet 	}
171e4a0e42bSBill Paul 	return(&dummy);
172935a0024SGeoff Rehmet }
173935a0024SGeoff Rehmet 
174935a0024SGeoff Rehmet void
175a174e5b1SWarner Losh wallprog_1(struct svc_req *rqstp, SVCXPRT *transp)
176935a0024SGeoff Rehmet {
177935a0024SGeoff Rehmet 	union {
178935a0024SGeoff Rehmet 		char *wallproc_wall_1_arg;
179935a0024SGeoff Rehmet 	} argument;
180935a0024SGeoff Rehmet 	char *result;
181935a0024SGeoff Rehmet 	bool_t (*xdr_argument)(), (*xdr_result)();
182935a0024SGeoff Rehmet 	char *(*local)();
183935a0024SGeoff Rehmet 
184935a0024SGeoff Rehmet 	switch (rqstp->rq_proc) {
185935a0024SGeoff Rehmet 	case NULLPROC:
186935a0024SGeoff Rehmet 		(void)svc_sendreply(transp, xdr_void, (char *)NULL);
187935a0024SGeoff Rehmet 		goto leave;
188935a0024SGeoff Rehmet 
189935a0024SGeoff Rehmet 	case WALLPROC_WALL:
190935a0024SGeoff Rehmet 		xdr_argument = xdr_wrapstring;
191935a0024SGeoff Rehmet 		xdr_result = xdr_void;
192e4a0e42bSBill Paul 		local = (char *(*)()) wallproc_wall_1_svc;
193935a0024SGeoff Rehmet 		break;
194935a0024SGeoff Rehmet 
195935a0024SGeoff Rehmet 	default:
196935a0024SGeoff Rehmet 		svcerr_noproc(transp);
197935a0024SGeoff Rehmet 		goto leave;
198935a0024SGeoff Rehmet 	}
199935a0024SGeoff Rehmet 	bzero((char *)&argument, sizeof(argument));
200e4a0e42bSBill Paul 	if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) {
201935a0024SGeoff Rehmet 		svcerr_decode(transp);
202935a0024SGeoff Rehmet 		goto leave;
203935a0024SGeoff Rehmet 	}
204935a0024SGeoff Rehmet 	result = (*local)(&argument, rqstp);
205935a0024SGeoff Rehmet 	if (result != NULL && !svc_sendreply(transp, xdr_result, result)) {
206935a0024SGeoff Rehmet 		svcerr_systemerr(transp);
207935a0024SGeoff Rehmet 	}
208e4a0e42bSBill Paul 	if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) {
20940150947SPhilippe Charnier 		syslog(LOG_ERR, "unable to free arguments");
210935a0024SGeoff Rehmet 		exit(1);
211935a0024SGeoff Rehmet 	}
212935a0024SGeoff Rehmet leave:
213935a0024SGeoff Rehmet         if (from_inetd)
214935a0024SGeoff Rehmet                 exit(0);
215935a0024SGeoff Rehmet }
216