rwalld.c revision 95658
1/*
2 * Copyright (c) 1993 Christopher G. Demetriou
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote
14 *    products derived from this software without specific prior written
15 *    permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#ifndef lint
31static const char rcsid[] =
32  "$FreeBSD: head/libexec/rpc.rwalld/rwalld.c 95658 2002-04-28 15:18:50Z des $";
33#endif /* not lint */
34
35#include <err.h>
36#include <pwd.h>
37#include <signal.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <syslog.h>
42#include <arpa/inet.h>
43#include <rpc/rpc.h>
44#include <rpc/pmap_clnt.h>
45#include <rpcsvc/rwall.h>
46#include <sys/socket.h>
47#include <sys/types.h>
48#include <sys/wait.h>
49#include <unistd.h>
50
51#ifdef OSF
52#define WALL_CMD "/usr/sbin/wall"
53#else
54#define WALL_CMD "/usr/bin/wall -n"
55#endif
56
57void wallprog_1(struct svc_req *rqstp, SVCXPRT *transp);
58void possess(void);
59void killkids(int sig);
60static void usage(void);
61
62int nodaemon = 0;
63int from_inetd = 1;
64
65int
66main(int argc, char *argv[])
67{
68	SVCXPRT *transp;
69	int s, salen;
70	struct sockaddr_in sa;
71        int sock = 0;
72        int proto = 0;
73
74	if (argc == 2 && !strcmp(argv[1], "-n"))
75		nodaemon = 1;
76	if (argc != 1 && !nodaemon)
77		usage();
78
79	if (geteuid() == 0) {
80		struct passwd *pep = getpwnam("nobody");
81		if (pep)
82			setuid(pep->pw_uid);
83		else
84			setuid(getuid());
85	}
86
87        /*
88         * See if inetd started us
89         */
90	salen = sizeof(sa);
91        if (getsockname(0, (struct sockaddr *)&sa, &salen) < 0) {
92                from_inetd = 0;
93                sock = RPC_ANYSOCK;
94                proto = IPPROTO_UDP;
95        }
96
97        if (!from_inetd) {
98                if (!nodaemon)
99                        possess();
100
101                (void)pmap_unset(WALLPROG, WALLVERS);
102                if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
103                        err(1, "socket");
104                bzero(&sa, sizeof sa);
105                if (bind(s, (struct sockaddr *)&sa, sizeof sa) < 0)
106                        err(1, "bind");
107
108                salen = sizeof sa;
109                if (getsockname(s, (struct sockaddr *)&sa, &salen))
110                        err(1, "getsockname");
111
112                pmap_set(WALLPROG, WALLVERS, IPPROTO_UDP, ntohs(sa.sin_port));
113                if (dup2(s, 0) < 0)
114                        err(1, "dup2");
115                (void)pmap_unset(WALLPROG, WALLVERS);
116        }
117
118	(void)signal(SIGCHLD, killkids);
119
120	openlog("rpc.rwalld", LOG_CONS|LOG_PID, LOG_DAEMON);
121
122	transp = svcudp_create(sock);
123	if (transp == NULL) {
124		syslog(LOG_ERR, "cannot create udp service");
125		exit(1);
126	}
127	if (!svc_register(transp, WALLPROG, WALLVERS, wallprog_1, proto)) {
128		syslog(LOG_ERR, "unable to register (WALLPROG, WALLVERS, %s)", proto?"udp":"(inetd)");
129		exit(1);
130	}
131	svc_run();
132	syslog(LOG_ERR, "svc_run returned");
133	exit(1);
134}
135
136static void
137usage(void)
138{
139	fprintf(stderr, "usage: rpc.rwalld [-n]\n");
140	exit(1);
141}
142
143void
144possess(void)
145{
146	daemon(0, 0);
147}
148
149void
150killkids(int sig)
151{
152	while(wait4(-1, NULL, WNOHANG, NULL) > 0)
153		;
154}
155
156void *
157wallproc_wall_1_svc(wrapstring *s, struct svc_req *rqstp)
158{
159	static void		*dummy = NULL;
160
161	/* fork, popen wall with special option, and send the message */
162	if (fork() == 0) {
163		FILE *pfp;
164
165		pfp = popen(WALL_CMD, "w");
166		if (pfp != NULL) {
167			fprintf(pfp, "\007\007%s", *s);
168			pclose(pfp);
169			exit(0);
170		}
171	}
172	return(&dummy);
173}
174
175void
176wallprog_1(struct svc_req *rqstp, SVCXPRT *transp)
177{
178	union {
179		char *wallproc_wall_1_arg;
180	} argument;
181	char *result;
182	bool_t (*xdr_argument)(), (*xdr_result)();
183	char *(*local)();
184
185	switch (rqstp->rq_proc) {
186	case NULLPROC:
187		(void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL);
188		goto leave;
189
190	case WALLPROC_WALL:
191		xdr_argument = xdr_wrapstring;
192		xdr_result = xdr_void;
193		local = (char *(*)()) wallproc_wall_1_svc;
194		break;
195
196	default:
197		svcerr_noproc(transp);
198		goto leave;
199	}
200	bzero(&argument, sizeof(argument));
201	if (!svc_getargs(transp, (xdrproc_t)xdr_argument, &argument)) {
202		svcerr_decode(transp);
203		goto leave;
204	}
205	result = (*local)(&argument, rqstp);
206	if (result != NULL &&
207	    !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) {
208		svcerr_systemerr(transp);
209	}
210	if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, &argument)) {
211		syslog(LOG_ERR, "unable to free arguments");
212		exit(1);
213	}
214leave:
215        if (from_inetd)
216                exit(0);
217}
218