xref: /freebsd/libexec/rpc.rwalld/rwalld.c (revision f249dbcc7149848de00cd8f4e93fe140dfa3f219)
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>
42fd8e4ebcSMike Barcroft #include <arpa/inet.h>
43935a0024SGeoff Rehmet #include <rpc/rpc.h>
4440150947SPhilippe Charnier #include <rpc/pmap_clnt.h>
45935a0024SGeoff Rehmet #include <rpcsvc/rwall.h>
4640150947SPhilippe Charnier #include <sys/socket.h>
4740150947SPhilippe Charnier #include <sys/types.h>
4840150947SPhilippe Charnier #include <sys/wait.h>
4940150947SPhilippe Charnier #include <unistd.h>
50935a0024SGeoff Rehmet 
51935a0024SGeoff Rehmet #ifdef OSF
52935a0024SGeoff Rehmet #define WALL_CMD "/usr/sbin/wall"
53935a0024SGeoff Rehmet #else
54935a0024SGeoff Rehmet #define WALL_CMD "/usr/bin/wall -n"
55935a0024SGeoff Rehmet #endif
56935a0024SGeoff Rehmet 
57a174e5b1SWarner Losh void wallprog_1(struct svc_req *rqstp, SVCXPRT *transp);
58a174e5b1SWarner Losh void possess(void);
59a174e5b1SWarner Losh void killkids(int sig);
60a174e5b1SWarner Losh static void usage(void);
61935a0024SGeoff Rehmet 
62935a0024SGeoff Rehmet int nodaemon = 0;
63935a0024SGeoff Rehmet int from_inetd = 1;
64935a0024SGeoff Rehmet 
6540150947SPhilippe Charnier int
66a174e5b1SWarner Losh main(int argc, char *argv[])
67935a0024SGeoff Rehmet {
68935a0024SGeoff Rehmet 	SVCXPRT *transp;
69935a0024SGeoff Rehmet 	int s, salen;
70935a0024SGeoff Rehmet 	struct sockaddr_in sa;
71935a0024SGeoff Rehmet         int sock = 0;
72935a0024SGeoff Rehmet         int proto = 0;
73935a0024SGeoff Rehmet 
74935a0024SGeoff Rehmet 	if (argc == 2 && !strcmp(argv[1], "-n"))
75935a0024SGeoff Rehmet 		nodaemon = 1;
7640150947SPhilippe Charnier 	if (argc != 1 && !nodaemon)
7740150947SPhilippe Charnier 		usage();
78935a0024SGeoff Rehmet 
79935a0024SGeoff Rehmet 	if (geteuid() == 0) {
80935a0024SGeoff Rehmet 		struct passwd *pep = getpwnam("nobody");
81935a0024SGeoff Rehmet 		if (pep)
82935a0024SGeoff Rehmet 			setuid(pep->pw_uid);
83935a0024SGeoff Rehmet 		else
84935a0024SGeoff Rehmet 			setuid(getuid());
85935a0024SGeoff Rehmet 	}
86935a0024SGeoff Rehmet 
87935a0024SGeoff Rehmet         /*
88935a0024SGeoff Rehmet          * See if inetd started us
89935a0024SGeoff Rehmet          */
907c760cfdSAndreas Schulz 	salen = sizeof(sa);
91935a0024SGeoff Rehmet         if (getsockname(0, (struct sockaddr *)&sa, &salen) < 0) {
92935a0024SGeoff Rehmet                 from_inetd = 0;
93935a0024SGeoff Rehmet                 sock = RPC_ANYSOCK;
94935a0024SGeoff Rehmet                 proto = IPPROTO_UDP;
95935a0024SGeoff Rehmet         }
96935a0024SGeoff Rehmet 
97935a0024SGeoff Rehmet         if (!from_inetd) {
98935a0024SGeoff Rehmet                 if (!nodaemon)
99935a0024SGeoff Rehmet                         possess();
100935a0024SGeoff Rehmet 
101935a0024SGeoff Rehmet                 (void)pmap_unset(WALLPROG, WALLVERS);
10240150947SPhilippe Charnier                 if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
10340150947SPhilippe Charnier                         err(1, "socket");
104f249dbccSDag-Erling Smørgrav                 bzero(&sa, sizeof sa);
10540150947SPhilippe Charnier                 if (bind(s, (struct sockaddr *)&sa, sizeof sa) < 0)
10640150947SPhilippe Charnier                         err(1, "bind");
107935a0024SGeoff Rehmet 
108935a0024SGeoff Rehmet                 salen = sizeof sa;
10940150947SPhilippe Charnier                 if (getsockname(s, (struct sockaddr *)&sa, &salen))
11040150947SPhilippe Charnier                         err(1, "getsockname");
111935a0024SGeoff Rehmet 
112935a0024SGeoff Rehmet                 pmap_set(WALLPROG, WALLVERS, IPPROTO_UDP, ntohs(sa.sin_port));
11340150947SPhilippe Charnier                 if (dup2(s, 0) < 0)
11440150947SPhilippe Charnier                         err(1, "dup2");
115935a0024SGeoff Rehmet                 (void)pmap_unset(WALLPROG, WALLVERS);
116935a0024SGeoff Rehmet         }
117935a0024SGeoff Rehmet 
118935a0024SGeoff Rehmet 	(void)signal(SIGCHLD, killkids);
119935a0024SGeoff Rehmet 
12040150947SPhilippe Charnier 	openlog("rpc.rwalld", LOG_CONS|LOG_PID, LOG_DAEMON);
12140150947SPhilippe Charnier 
122935a0024SGeoff Rehmet 	transp = svcudp_create(sock);
123935a0024SGeoff Rehmet 	if (transp == NULL) {
12440150947SPhilippe Charnier 		syslog(LOG_ERR, "cannot create udp service");
125935a0024SGeoff Rehmet 		exit(1);
126935a0024SGeoff Rehmet 	}
127935a0024SGeoff Rehmet 	if (!svc_register(transp, WALLPROG, WALLVERS, wallprog_1, proto)) {
12840150947SPhilippe Charnier 		syslog(LOG_ERR, "unable to register (WALLPROG, WALLVERS, %s)", proto?"udp":"(inetd)");
129935a0024SGeoff Rehmet 		exit(1);
130935a0024SGeoff Rehmet 	}
131935a0024SGeoff Rehmet 	svc_run();
13240150947SPhilippe Charnier 	syslog(LOG_ERR, "svc_run returned");
133935a0024SGeoff Rehmet 	exit(1);
13440150947SPhilippe Charnier }
135935a0024SGeoff Rehmet 
13640150947SPhilippe Charnier static void
137a174e5b1SWarner Losh usage(void)
13840150947SPhilippe Charnier {
13940150947SPhilippe Charnier 	fprintf(stderr, "usage: rpc.rwalld [-n]\n");
14040150947SPhilippe Charnier 	exit(1);
141935a0024SGeoff Rehmet }
142935a0024SGeoff Rehmet 
143a174e5b1SWarner Losh void
144a174e5b1SWarner Losh possess(void)
145935a0024SGeoff Rehmet {
146935a0024SGeoff Rehmet 	daemon(0, 0);
147935a0024SGeoff Rehmet }
148935a0024SGeoff Rehmet 
149a174e5b1SWarner Losh void
150a174e5b1SWarner Losh killkids(int sig)
151935a0024SGeoff Rehmet {
152935a0024SGeoff Rehmet 	while(wait4(-1, NULL, WNOHANG, NULL) > 0)
153935a0024SGeoff Rehmet 		;
154935a0024SGeoff Rehmet }
155935a0024SGeoff Rehmet 
156a174e5b1SWarner Losh void *
157a174e5b1SWarner Losh wallproc_wall_1_svc(wrapstring *s, struct svc_req *rqstp)
158935a0024SGeoff Rehmet {
159e4a0e42bSBill Paul 	static void		*dummy = NULL;
160e4a0e42bSBill Paul 
161935a0024SGeoff Rehmet 	/* fork, popen wall with special option, and send the message */
162935a0024SGeoff Rehmet 	if (fork() == 0) {
163935a0024SGeoff Rehmet 		FILE *pfp;
164935a0024SGeoff Rehmet 
165935a0024SGeoff Rehmet 		pfp = popen(WALL_CMD, "w");
166935a0024SGeoff Rehmet 		if (pfp != NULL) {
167935a0024SGeoff Rehmet 			fprintf(pfp, "\007\007%s", *s);
168935a0024SGeoff Rehmet 			pclose(pfp);
169935a0024SGeoff Rehmet 			exit(0);
170935a0024SGeoff Rehmet 		}
171935a0024SGeoff Rehmet 	}
172e4a0e42bSBill Paul 	return(&dummy);
173935a0024SGeoff Rehmet }
174935a0024SGeoff Rehmet 
175935a0024SGeoff Rehmet void
176a174e5b1SWarner Losh wallprog_1(struct svc_req *rqstp, SVCXPRT *transp)
177935a0024SGeoff Rehmet {
178935a0024SGeoff Rehmet 	union {
179935a0024SGeoff Rehmet 		char *wallproc_wall_1_arg;
180935a0024SGeoff Rehmet 	} argument;
181935a0024SGeoff Rehmet 	char *result;
182935a0024SGeoff Rehmet 	bool_t (*xdr_argument)(), (*xdr_result)();
183935a0024SGeoff Rehmet 	char *(*local)();
184935a0024SGeoff Rehmet 
185935a0024SGeoff Rehmet 	switch (rqstp->rq_proc) {
186935a0024SGeoff Rehmet 	case NULLPROC:
187f249dbccSDag-Erling Smørgrav 		(void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL);
188935a0024SGeoff Rehmet 		goto leave;
189935a0024SGeoff Rehmet 
190935a0024SGeoff Rehmet 	case WALLPROC_WALL:
191935a0024SGeoff Rehmet 		xdr_argument = xdr_wrapstring;
192935a0024SGeoff Rehmet 		xdr_result = xdr_void;
193e4a0e42bSBill Paul 		local = (char *(*)()) wallproc_wall_1_svc;
194935a0024SGeoff Rehmet 		break;
195935a0024SGeoff Rehmet 
196935a0024SGeoff Rehmet 	default:
197935a0024SGeoff Rehmet 		svcerr_noproc(transp);
198935a0024SGeoff Rehmet 		goto leave;
199935a0024SGeoff Rehmet 	}
200f249dbccSDag-Erling Smørgrav 	bzero(&argument, sizeof(argument));
201f249dbccSDag-Erling Smørgrav 	if (!svc_getargs(transp, (xdrproc_t)xdr_argument, &argument)) {
202935a0024SGeoff Rehmet 		svcerr_decode(transp);
203935a0024SGeoff Rehmet 		goto leave;
204935a0024SGeoff Rehmet 	}
205935a0024SGeoff Rehmet 	result = (*local)(&argument, rqstp);
206f249dbccSDag-Erling Smørgrav 	if (result != NULL &&
207f249dbccSDag-Erling Smørgrav 	    !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) {
208935a0024SGeoff Rehmet 		svcerr_systemerr(transp);
209935a0024SGeoff Rehmet 	}
210f249dbccSDag-Erling Smørgrav 	if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, &argument)) {
21140150947SPhilippe Charnier 		syslog(LOG_ERR, "unable to free arguments");
212935a0024SGeoff Rehmet 		exit(1);
213935a0024SGeoff Rehmet 	}
214935a0024SGeoff Rehmet leave:
215935a0024SGeoff Rehmet         if (from_inetd)
216935a0024SGeoff Rehmet                 exit(0);
217935a0024SGeoff Rehmet }
218