rwalld.c revision 100120
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 100120 2002-07-15 18:51:57Z alfred $";
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 <rpcsvc/rwall.h>
45#include <sys/socket.h>
46#include <sys/types.h>
47#include <sys/wait.h>
48#include <unistd.h>
49
50#ifdef OSF
51#define WALL_CMD "/usr/sbin/wall"
52#else
53#define WALL_CMD "/usr/bin/wall -n"
54#endif
55
56void wallprog_1(struct svc_req *rqstp, SVCXPRT *transp);
57void possess(void);
58void killkids(int sig);
59static void usage(void);
60
61int nodaemon = 0;
62int from_inetd = 1;
63
64int
65main(int argc, char *argv[])
66{
67	SVCXPRT *transp;
68	int ok, salen;
69	struct sockaddr_storage sa;
70
71	if (argc == 2 && !strcmp(argv[1], "-n"))
72		nodaemon = 1;
73	if (argc != 1 && !nodaemon)
74		usage();
75
76	if (geteuid() == 0) {
77		struct passwd *pep = getpwnam("nobody");
78		if (pep)
79			setuid(pep->pw_uid);
80		else
81			setuid(getuid());
82	}
83
84        /*
85         * See if inetd started us
86         */
87	salen = sizeof(sa);
88        if (getsockname(0, (struct sockaddr *)&sa, &salen) < 0) {
89                from_inetd = 0;
90        }
91
92        if (!from_inetd) {
93                if (!nodaemon)
94                        possess();
95
96		(void)rpcb_unset(WALLPROG, WALLVERS, NULL);
97        }
98
99	(void)signal(SIGCHLD, killkids);
100
101	openlog("rpc.rwalld", LOG_CONS|LOG_PID, LOG_DAEMON);
102
103	/* create and register the service */
104	if (from_inetd) {
105		transp = svc_tli_create(0, NULL, NULL, 0, 0);
106		if (transp == NULL) {
107			syslog(LOG_ERR, "couldn't create udp service.");
108			exit(1);
109		}
110		ok = svc_reg(transp, WALLPROG, WALLVERS,
111			     wallprog_1, NULL);
112	} else
113		ok = svc_create(wallprog_1,
114				WALLPROG, WALLVERS, "udp");
115	if (!ok) {
116		syslog(LOG_ERR, "unable to register (WALLPROG, WALLVERS, %s)", (!from_inetd)?"udp":"(inetd)");
117		exit(1);
118	}
119	svc_run();
120	syslog(LOG_ERR, "svc_run returned");
121	exit(1);
122}
123
124static void
125usage(void)
126{
127	fprintf(stderr, "usage: rpc.rwalld [-n]\n");
128	exit(1);
129}
130
131void
132possess(void)
133{
134	daemon(0, 0);
135}
136
137void
138killkids(int sig)
139{
140	while(wait4(-1, NULL, WNOHANG, NULL) > 0)
141		;
142}
143
144void *
145wallproc_wall_1_svc(wrapstring *s, struct svc_req *rqstp)
146{
147	static void		*dummy = NULL;
148
149	/* fork, popen wall with special option, and send the message */
150	if (fork() == 0) {
151		FILE *pfp;
152
153		pfp = popen(WALL_CMD, "w");
154		if (pfp != NULL) {
155			fprintf(pfp, "\007\007%s", *s);
156			pclose(pfp);
157			exit(0);
158		}
159	}
160	return(&dummy);
161}
162
163void
164wallprog_1(struct svc_req *rqstp, SVCXPRT *transp)
165{
166	union {
167		char *wallproc_wall_1_arg;
168	} argument;
169	char *result;
170	bool_t (*xdr_argument)(), (*xdr_result)();
171	char *(*local)();
172
173	switch (rqstp->rq_proc) {
174	case NULLPROC:
175		(void)svc_sendreply(transp, (xdrproc_t)xdr_void, NULL);
176		goto leave;
177
178	case WALLPROC_WALL:
179		xdr_argument = xdr_wrapstring;
180		xdr_result = xdr_void;
181		local = (char *(*)()) wallproc_wall_1_svc;
182		break;
183
184	default:
185		svcerr_noproc(transp);
186		goto leave;
187	}
188	bzero(&argument, sizeof(argument));
189	if (!svc_getargs(transp, (xdrproc_t)xdr_argument, &argument)) {
190		svcerr_decode(transp);
191		goto leave;
192	}
193	result = (*local)(&argument, rqstp);
194	if (result != NULL &&
195	    !svc_sendreply(transp, (xdrproc_t)xdr_result, result)) {
196		svcerr_systemerr(transp);
197	}
198	if (!svc_freeargs(transp, (xdrproc_t)xdr_argument, &argument)) {
199		syslog(LOG_ERR, "unable to free arguments");
200		exit(1);
201	}
202leave:
203        if (from_inetd)
204                exit(0);
205}
206