1*f7f1b834Skrw /* $OpenBSD: procs.c,v 1.3 2017/01/21 08:33:51 krw Exp $ */
2b0c57e47Ssturm
3b0c57e47Ssturm /*
4b0c57e47Ssturm * Copyright (c) 1995
5b0c57e47Ssturm * A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved.
6b0c57e47Ssturm *
7b0c57e47Ssturm * Redistribution and use in source and binary forms, with or without
8b0c57e47Ssturm * modification, are permitted provided that the following conditions
9b0c57e47Ssturm * are met:
10b0c57e47Ssturm * 1. Redistributions of source code must retain the above copyright
11b0c57e47Ssturm * notice, this list of conditions and the following disclaimer.
12b0c57e47Ssturm * 2. Redistributions in binary form must reproduce the above copyright
13b0c57e47Ssturm * notice, this list of conditions and the following disclaimer in the
14b0c57e47Ssturm * documentation and/or other materials provided with the distribution.
15b0c57e47Ssturm * 3. All advertising materials mentioning features or use of this software
16b0c57e47Ssturm * must display the following acknowledgement:
17b0c57e47Ssturm * This product includes software developed for the FreeBSD project
18b0c57e47Ssturm * 4. Neither the name of the author nor the names of any co-contributors
19b0c57e47Ssturm * may be used to endorse or promote products derived from this software
20b0c57e47Ssturm * without specific prior written permission.
21b0c57e47Ssturm *
22b0c57e47Ssturm * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
23b0c57e47Ssturm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24b0c57e47Ssturm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25b0c57e47Ssturm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26b0c57e47Ssturm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27b0c57e47Ssturm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28b0c57e47Ssturm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29b0c57e47Ssturm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30b0c57e47Ssturm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31b0c57e47Ssturm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32b0c57e47Ssturm * SUCH DAMAGE.
33b0c57e47Ssturm *
34b0c57e47Ssturm */
35b0c57e47Ssturm
36b0c57e47Ssturm #include <errno.h>
37b0c57e47Ssturm #include <netdb.h>
38b0c57e47Ssturm #include <stdio.h>
39b0c57e47Ssturm #include <stdlib.h>
40b0c57e47Ssturm #include <string.h>
41b0c57e47Ssturm #include <syslog.h>
42b0c57e47Ssturm #include <signal.h>
43b0c57e47Ssturm #include <unistd.h>
44b0c57e47Ssturm
45b0c57e47Ssturm #include <rpc/rpc.h>
46b0c57e47Ssturm
47b0c57e47Ssturm #include "statd.h"
48b0c57e47Ssturm
49b0c57e47Ssturm /* sm_stat_1 --------------------------------------------------------------- */
50b0c57e47Ssturm /*
51b0c57e47Ssturm * Purpose: RPC call to enquire if a host can be monitored
52b0c57e47Ssturm * Returns: TRUE for any hostname that can be looked up to give
53b0c57e47Ssturm * an address.
54b0c57e47Ssturm */
55b0c57e47Ssturm struct sm_stat_res *
sm_stat_1_svc(sm_name * arg,struct svc_req * req)56b0c57e47Ssturm sm_stat_1_svc(sm_name *arg, struct svc_req *req)
57b0c57e47Ssturm {
58b0c57e47Ssturm static sm_stat_res res;
59b0c57e47Ssturm
60b0c57e47Ssturm NO_ALARM;
61b0c57e47Ssturm if (debug)
62b0c57e47Ssturm syslog(LOG_DEBUG, "stat called for host %s", arg->mon_name);
63b0c57e47Ssturm
64b0c57e47Ssturm if (gethostbyname(arg->mon_name))
65b0c57e47Ssturm res.res_stat = stat_succ;
66b0c57e47Ssturm else {
67b0c57e47Ssturm syslog(LOG_ERR, "invalid hostname to sm_stat: %s",
68b0c57e47Ssturm arg->mon_name);
69b0c57e47Ssturm res.res_stat = stat_fail;
70b0c57e47Ssturm }
71b0c57e47Ssturm
72b0c57e47Ssturm res.state = status_info.ourState;
73b0c57e47Ssturm ALARM;
74b0c57e47Ssturm return (&res);
75b0c57e47Ssturm }
76b0c57e47Ssturm
77b0c57e47Ssturm /* sm_mon_1 ---------------------------------------------------------------- */
78b0c57e47Ssturm /*
79b0c57e47Ssturm * Purpose: RPC procedure to establish a monitor request
80b0c57e47Ssturm * Returns: Success, unless lack of resources prevents
81b0c57e47Ssturm * the necessary structures from being set up
82b0c57e47Ssturm * to record the request, or if the hostname is not
83b0c57e47Ssturm * valid (as judged by gethostbyname())
84b0c57e47Ssturm */
85b0c57e47Ssturm struct sm_stat_res *
sm_mon_1_svc(mon * arg,struct svc_req * req)86b0c57e47Ssturm sm_mon_1_svc(mon *arg, struct svc_req *req)
87b0c57e47Ssturm {
88b0c57e47Ssturm static sm_stat_res res;
89b0c57e47Ssturm HostInfo *hp, h;
90b0c57e47Ssturm MonList *lp;
91b0c57e47Ssturm
92b0c57e47Ssturm NO_ALARM;
93b0c57e47Ssturm if (debug) {
94b0c57e47Ssturm syslog(LOG_DEBUG, "monitor request for host %s",
95b0c57e47Ssturm arg->mon_id.mon_name);
96b0c57e47Ssturm syslog(LOG_DEBUG, "recall host: %s prog: %d ver: %d proc: %d",
97b0c57e47Ssturm arg->mon_id.my_id.my_name, arg->mon_id.my_id.my_prog,
98b0c57e47Ssturm arg->mon_id.my_id.my_vers, arg->mon_id.my_id.my_proc);
99b0c57e47Ssturm }
100b0c57e47Ssturm res.res_stat = stat_fail; /* Assume fail until set otherwise */
101b0c57e47Ssturm res.state = status_info.ourState;
102b0c57e47Ssturm
103b0c57e47Ssturm /*
104b0c57e47Ssturm * Find existing host entry, or create one if not found. If
105b0c57e47Ssturm * find_host() fails, it will have logged the error already.
106b0c57e47Ssturm */
107b0c57e47Ssturm if (!gethostbyname(arg->mon_id.mon_name)) {
108b0c57e47Ssturm syslog(LOG_ERR, "Invalid hostname to sm_mon: %s",
109b0c57e47Ssturm arg->mon_id.mon_name);
110b0c57e47Ssturm return &res;
111b0c57e47Ssturm }
112b0c57e47Ssturm
113b0c57e47Ssturm if ((hp = find_host(arg->mon_id.mon_name, &h)) == NULL)
114b0c57e47Ssturm memset(hp = &h, 0, sizeof(h));
115b0c57e47Ssturm
11635de856eSderaadt lp = malloc(sizeof(MonList));
117b0c57e47Ssturm if (!lp)
118b0c57e47Ssturm syslog(LOG_ERR, "Out of memory");
119b0c57e47Ssturm else {
120b0c57e47Ssturm strncpy(lp->notifyHost, arg->mon_id.my_id.my_name,
121b0c57e47Ssturm SM_MAXSTRLEN);
122b0c57e47Ssturm lp->notifyProg = arg->mon_id.my_id.my_prog;
123b0c57e47Ssturm lp->notifyVers = arg->mon_id.my_id.my_vers;
124b0c57e47Ssturm lp->notifyProc = arg->mon_id.my_id.my_proc;
125b0c57e47Ssturm memcpy(lp->notifyData, arg->priv,
126b0c57e47Ssturm sizeof(lp->notifyData));
127b0c57e47Ssturm
128b0c57e47Ssturm lp->next = hp->monList;
129b0c57e47Ssturm hp->monList = lp;
130b0c57e47Ssturm change_host(arg->mon_id.mon_name, hp);
131b0c57e47Ssturm sync_file();
132b0c57e47Ssturm res.res_stat = stat_succ; /* Report success */
133b0c57e47Ssturm }
134b0c57e47Ssturm ALARM;
135b0c57e47Ssturm return (&res);
136b0c57e47Ssturm }
137b0c57e47Ssturm
138b0c57e47Ssturm /* do_unmon ---------------------------------------------------------------- */
139b0c57e47Ssturm /*
140b0c57e47Ssturm * Purpose: Remove a monitor request from a host
141b0c57e47Ssturm * Returns: TRUE if found, FALSE if not found.
142b0c57e47Ssturm * Notes: Common code from sm_unmon_1_svc and sm_unmon_all_1_svc
143b0c57e47Ssturm * In the unlikely event of more than one identical monitor
144b0c57e47Ssturm * request, all are removed.
145b0c57e47Ssturm */
146b0c57e47Ssturm int
do_unmon(char * name,HostInfo * hp,void * ptr)147b0c57e47Ssturm do_unmon(char *name, HostInfo *hp, void *ptr)
148b0c57e47Ssturm {
149b0c57e47Ssturm my_id *idp = ptr;
150b0c57e47Ssturm MonList *lp, *next;
151b0c57e47Ssturm MonList *last = NULL;
152b0c57e47Ssturm int result = FALSE;
153b0c57e47Ssturm
154b0c57e47Ssturm lp = hp->monList;
155b0c57e47Ssturm while (lp) {
156b0c57e47Ssturm if (!strncasecmp(idp->my_name, lp->notifyHost, SM_MAXSTRLEN)
157b0c57e47Ssturm && (idp->my_prog == lp->notifyProg)
158b0c57e47Ssturm && (idp->my_proc == lp->notifyProc)
159b0c57e47Ssturm && (idp->my_vers == lp->notifyVers)) {
160b0c57e47Ssturm /* found one. Unhook from chain and free. */
161b0c57e47Ssturm next = lp->next;
162b0c57e47Ssturm if (last)
163b0c57e47Ssturm last->next = next;
164b0c57e47Ssturm else
165b0c57e47Ssturm hp->monList = next;
166b0c57e47Ssturm free(lp);
167b0c57e47Ssturm lp = next;
168b0c57e47Ssturm result = TRUE;
169b0c57e47Ssturm } else {
170b0c57e47Ssturm last = lp;
171b0c57e47Ssturm lp = lp->next;
172b0c57e47Ssturm }
173b0c57e47Ssturm }
174b0c57e47Ssturm return (result);
175b0c57e47Ssturm }
176b0c57e47Ssturm
177b0c57e47Ssturm /* sm_unmon_1 -------------------------------------------------------------- */
178b0c57e47Ssturm /*
179b0c57e47Ssturm * Purpose: RPC procedure to release a monitor request.
180b0c57e47Ssturm * Returns: Local machine's status number
181b0c57e47Ssturm * Notes: The supplied mon_id should match the value passed in an
182b0c57e47Ssturm * earlier call to sm_mon_1
183b0c57e47Ssturm */
184b0c57e47Ssturm struct sm_stat *
sm_unmon_1_svc(mon_id * arg,struct svc_req * req)185b0c57e47Ssturm sm_unmon_1_svc(mon_id *arg, struct svc_req *req)
186b0c57e47Ssturm {
187b0c57e47Ssturm static sm_stat res;
188b0c57e47Ssturm HostInfo *hp, h;
189b0c57e47Ssturm
190b0c57e47Ssturm NO_ALARM;
191b0c57e47Ssturm if (debug) {
192b0c57e47Ssturm syslog(LOG_DEBUG, "un-monitor request for host %s",
193b0c57e47Ssturm arg->mon_name);
194b0c57e47Ssturm syslog(LOG_DEBUG, "recall host: %s prog: %d ver: %d proc: %d",
195b0c57e47Ssturm arg->my_id.my_name, arg->my_id.my_prog,
196b0c57e47Ssturm arg->my_id.my_vers, arg->my_id.my_proc);
197b0c57e47Ssturm }
198b0c57e47Ssturm if ((hp = find_host(arg->mon_name, &h)) != NULL) {
199b0c57e47Ssturm if (do_unmon(arg->mon_name, hp, &arg->my_id)) {
200b0c57e47Ssturm change_host(arg->mon_name, hp);
201b0c57e47Ssturm sync_file();
202b0c57e47Ssturm } else
203b0c57e47Ssturm syslog(LOG_ERR,
204b0c57e47Ssturm "unmon request from %s, no matching monitor",
205b0c57e47Ssturm arg->my_id.my_name);
206b0c57e47Ssturm } else
207b0c57e47Ssturm syslog(LOG_ERR, "unmon request from %s for unknown host %s",
208b0c57e47Ssturm arg->my_id.my_name, arg->mon_name);
209b0c57e47Ssturm
210b0c57e47Ssturm res.state = status_info.ourState;
211b0c57e47Ssturm ALARM;
212b0c57e47Ssturm
213b0c57e47Ssturm return (&res);
214b0c57e47Ssturm }
215b0c57e47Ssturm
216b0c57e47Ssturm /* sm_unmon_all_1 ---------------------------------------------------------- */
217b0c57e47Ssturm /*
218b0c57e47Ssturm * Purpose: RPC procedure to release monitor requests.
219b0c57e47Ssturm * Returns: Local machine's status number
220b0c57e47Ssturm * Notes: Releases all monitor requests (if any) from the specified
221b0c57e47Ssturm * host and program number.
222b0c57e47Ssturm */
223b0c57e47Ssturm struct sm_stat *
sm_unmon_all_1_svc(my_id * arg,struct svc_req * req)224b0c57e47Ssturm sm_unmon_all_1_svc(my_id *arg, struct svc_req *req)
225b0c57e47Ssturm {
226b0c57e47Ssturm static sm_stat res;
227b0c57e47Ssturm
228b0c57e47Ssturm NO_ALARM;
229b0c57e47Ssturm if (debug) {
230b0c57e47Ssturm syslog(LOG_DEBUG,
231b0c57e47Ssturm "unmon_all for host: %s prog: %d ver: %d proc: %d",
232b0c57e47Ssturm arg->my_name, arg->my_prog, arg->my_vers, arg->my_proc);
233b0c57e47Ssturm }
234b0c57e47Ssturm
235b0c57e47Ssturm unmon_hosts();
236b0c57e47Ssturm sync_file();
237b0c57e47Ssturm
238b0c57e47Ssturm res.state = status_info.ourState;
239b0c57e47Ssturm ALARM;
240b0c57e47Ssturm
241b0c57e47Ssturm return (&res);
242b0c57e47Ssturm }
243b0c57e47Ssturm
244b0c57e47Ssturm /* sm_simu_crash_1 --------------------------------------------------------- */
245b0c57e47Ssturm /*
246b0c57e47Ssturm * Purpose: RPC procedure to simulate a crash
247b0c57e47Ssturm * Returns: Nothing
248b0c57e47Ssturm * Notes: Standardised mechanism for debug purposes
249b0c57e47Ssturm * The specification says that we should drop all of our
250b0c57e47Ssturm * status information (apart from the list of monitored hosts
251b0c57e47Ssturm * on disc). However, this would confuse the rpc.lockd
252b0c57e47Ssturm * which would be unaware that all of its monitor requests
253b0c57e47Ssturm * had been silently junked. Hence we in fact retain all
254b0c57e47Ssturm * current requests and simply increment the status counter
255b0c57e47Ssturm * and inform all hosts on the monitor list.
256b0c57e47Ssturm */
257b0c57e47Ssturm void *
sm_simu_crash_1_svc(void * v,struct svc_req * req)258b0c57e47Ssturm sm_simu_crash_1_svc(void *v, struct svc_req *req)
259b0c57e47Ssturm {
260b0c57e47Ssturm static char dummy;
261b0c57e47Ssturm
262b0c57e47Ssturm NO_ALARM;
263b0c57e47Ssturm if (debug)
264b0c57e47Ssturm syslog(LOG_DEBUG, "simu_crash called!!");
265b0c57e47Ssturm
266b0c57e47Ssturm reset_database();
267b0c57e47Ssturm ALARM;
268b0c57e47Ssturm notify_handler(0);
269b0c57e47Ssturm
270b0c57e47Ssturm return (&dummy);
271b0c57e47Ssturm }
272b0c57e47Ssturm
273b0c57e47Ssturm /* sm_notify_1 ------------------------------------------------------------- */
274b0c57e47Ssturm /*
275b0c57e47Ssturm * Purpose: RPC procedure notifying local statd of the crash of another
276b0c57e47Ssturm * Returns: Nothing
277b0c57e47Ssturm * Notes: There is danger of deadlock, since it is quite likely that
278b0c57e47Ssturm * the client procedure that we call will in turn call us
279b0c57e47Ssturm * to remove or adjust the monitor request.
280b0c57e47Ssturm * We therefore fork() a process to do the notifications.
281b0c57e47Ssturm * Note that the main HostInfo structure is in a mmap()
282b0c57e47Ssturm * region and so will be shared with the child, but the
283b0c57e47Ssturm * monList pointed to by the HostInfo is in normal memory.
284b0c57e47Ssturm * Hence if we read the monList before forking, we are
285b0c57e47Ssturm * protected from the parent servicing other requests
286b0c57e47Ssturm * that modify the list.
287b0c57e47Ssturm */
288b0c57e47Ssturm void *
sm_notify_1_svc(stat_chge * arg,struct svc_req * req)289b0c57e47Ssturm sm_notify_1_svc(stat_chge *arg, struct svc_req *req)
290b0c57e47Ssturm {
291b0c57e47Ssturm struct timeval timeout = {20, 0}; /* 20 secs timeout */
292b0c57e47Ssturm CLIENT *cli;
293b0c57e47Ssturm static char dummy;
294b0c57e47Ssturm status tx_arg; /* arg sent to callback procedure */
295b0c57e47Ssturm MonList *lp;
296b0c57e47Ssturm HostInfo *hp, h;
297b0c57e47Ssturm pid_t pid;
298b0c57e47Ssturm
299b0c57e47Ssturm if (debug)
300b0c57e47Ssturm syslog(LOG_DEBUG, "notify from host %s, new state %d",
301b0c57e47Ssturm arg->mon_name, arg->state);
302b0c57e47Ssturm
303b0c57e47Ssturm hp = find_host(arg->mon_name, &h);
304b0c57e47Ssturm if (!hp) {
305b0c57e47Ssturm /* Never heard of this host - why is it notifying us? */
306b0c57e47Ssturm syslog(LOG_DEBUG, "Unsolicited notification from host %s",
307b0c57e47Ssturm arg->mon_name);
308b0c57e47Ssturm return (&dummy);
309b0c57e47Ssturm }
310b0c57e47Ssturm lp = hp->monList;
311b0c57e47Ssturm if (!lp) /* We know this host, but have no outstanding requests. */
312b0c57e47Ssturm return (&dummy);
313b0c57e47Ssturm
314b0c57e47Ssturm sync_file();
315b0c57e47Ssturm pid = fork();
316b0c57e47Ssturm if (pid == -1) {
317b0c57e47Ssturm syslog(LOG_ERR, "Unable to fork notify process - %s",
318b0c57e47Ssturm strerror(errno));
319b0c57e47Ssturm return (FALSE);
320b0c57e47Ssturm }
321b0c57e47Ssturm if (pid)
322b0c57e47Ssturm return (&dummy); /* Parent returns */
323b0c57e47Ssturm
324b0c57e47Ssturm while (lp) {
325b0c57e47Ssturm tx_arg.mon_name = arg->mon_name;
326b0c57e47Ssturm tx_arg.state = arg->state;
327b0c57e47Ssturm memcpy(tx_arg.priv, lp->notifyData, sizeof(tx_arg.priv));
328b0c57e47Ssturm cli = clnt_create(lp->notifyHost, lp->notifyProg,
329b0c57e47Ssturm lp->notifyVers, "udp");
330b0c57e47Ssturm if (!cli)
331b0c57e47Ssturm syslog(LOG_ERR, "Failed to contact host %s%s",
332b0c57e47Ssturm lp->notifyHost, clnt_spcreateerror(""));
333b0c57e47Ssturm else {
334b0c57e47Ssturm if (clnt_call(cli, lp->notifyProc, xdr_status, &tx_arg,
335b0c57e47Ssturm xdr_void, &dummy, timeout) != RPC_SUCCESS)
336b0c57e47Ssturm syslog(LOG_ERR,
337b0c57e47Ssturm "Failed to call rpc.statd client at host %s",
338b0c57e47Ssturm lp->notifyHost);
339b0c57e47Ssturm clnt_destroy(cli);
340b0c57e47Ssturm }
341b0c57e47Ssturm lp = lp->next;
342b0c57e47Ssturm }
343b0c57e47Ssturm
344b0c57e47Ssturm exit(0); /* Child quits */
345b0c57e47Ssturm }
346