1*421949a3Ssevan /* $NetBSD: stat_proc.c,v 1.9 2018/01/23 21:06:26 sevan Exp $ */
224ce527bSscottr
324ce527bSscottr /*
424ce527bSscottr * Copyright (c) 1995
524ce527bSscottr * A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved.
624ce527bSscottr *
724ce527bSscottr * Redistribution and use in source and binary forms, with or without
824ce527bSscottr * modification, are permitted provided that the following conditions
924ce527bSscottr * are met:
1024ce527bSscottr * 1. Redistributions of source code must retain the above copyright
1124ce527bSscottr * notice, this list of conditions and the following disclaimer.
1224ce527bSscottr * 2. Redistributions in binary form must reproduce the above copyright
1324ce527bSscottr * notice, this list of conditions and the following disclaimer in the
1424ce527bSscottr * documentation and/or other materials provided with the distribution.
1524ce527bSscottr * 3. All advertising materials mentioning features or use of this software
1624ce527bSscottr * must display the following acknowledgement:
1724ce527bSscottr * This product includes software developed for the FreeBSD project
1824ce527bSscottr * 4. Neither the name of the author nor the names of any co-contributors
1924ce527bSscottr * may be used to endorse or promote products derived from this software
2024ce527bSscottr * without specific prior written permission.
2124ce527bSscottr *
2224ce527bSscottr * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
2324ce527bSscottr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2424ce527bSscottr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2524ce527bSscottr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2624ce527bSscottr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2724ce527bSscottr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2824ce527bSscottr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2924ce527bSscottr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3024ce527bSscottr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3124ce527bSscottr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3224ce527bSscottr * SUCH DAMAGE.
3324ce527bSscottr *
3424ce527bSscottr */
3524ce527bSscottr
3690a9b36aSlukem #include <sys/cdefs.h>
3790a9b36aSlukem #ifndef lint
38*421949a3Ssevan __RCSID("$NetBSD: stat_proc.c,v 1.9 2018/01/23 21:06:26 sevan Exp $");
3990a9b36aSlukem #endif
4090a9b36aSlukem
41021be7fdSlukem #include <errno.h>
42021be7fdSlukem #include <netdb.h>
4324ce527bSscottr #include <stdio.h>
4424ce527bSscottr #include <stdlib.h>
4524ce527bSscottr #include <string.h>
4624ce527bSscottr #include <syslog.h>
471175f55bSchristos #include <signal.h>
48021be7fdSlukem #include <unistd.h>
49021be7fdSlukem
50021be7fdSlukem #include <rpc/rpc.h>
5124ce527bSscottr
5224ce527bSscottr #include "statd.h"
5324ce527bSscottr
5424ce527bSscottr /* sm_stat_1 --------------------------------------------------------------- */
5524ce527bSscottr /*
5624ce527bSscottr * Purpose: RPC call to enquire if a host can be monitored
5724ce527bSscottr * Returns: TRUE for any hostname that can be looked up to give
5824ce527bSscottr * an address.
5924ce527bSscottr */
6024ce527bSscottr struct sm_stat_res *
sm_stat_1_svc(sm_name * arg,struct svc_req * req)61*421949a3Ssevan sm_stat_1_svc(sm_name *arg, struct svc_req *req)
6224ce527bSscottr {
630466bbb6Slukem static sm_stat_res smres;
6477044250Sfvdl struct addrinfo *ai;
6524ce527bSscottr
661175f55bSchristos NO_ALARM;
6724ce527bSscottr if (debug)
6824ce527bSscottr syslog(LOG_DEBUG, "stat called for host %s", arg->mon_name);
6924ce527bSscottr
7077044250Sfvdl if (getaddrinfo(arg->mon_name, NULL, NULL, &ai) == 0) {
710466bbb6Slukem smres.res_stat = stat_succ;
7277044250Sfvdl freeaddrinfo(ai);
7377044250Sfvdl } else {
7424ce527bSscottr syslog(LOG_ERR, "invalid hostname to sm_stat: %s",
7524ce527bSscottr arg->mon_name);
760466bbb6Slukem smres.res_stat = stat_fail;
7724ce527bSscottr }
7824ce527bSscottr
790466bbb6Slukem smres.state = status_info.ourState;
801175f55bSchristos ALARM;
810466bbb6Slukem return (&smres);
8224ce527bSscottr }
8324ce527bSscottr
8424ce527bSscottr /* sm_mon_1 ---------------------------------------------------------------- */
8524ce527bSscottr /*
8624ce527bSscottr * Purpose: RPC procedure to establish a monitor request
8724ce527bSscottr * Returns: Success, unless lack of resources prevents
8824ce527bSscottr * the necessary structures from being set up
8924ce527bSscottr * to record the request, or if the hostname is not
9024ce527bSscottr * valid (as judged by gethostbyname())
9124ce527bSscottr */
9224ce527bSscottr struct sm_stat_res *
sm_mon_1_svc(mon * arg,struct svc_req * req)93*421949a3Ssevan sm_mon_1_svc(mon *arg, struct svc_req *req)
9424ce527bSscottr {
950466bbb6Slukem static sm_stat_res smres;
9677044250Sfvdl struct addrinfo *ai;
971175f55bSchristos HostInfo *hp, h;
9824ce527bSscottr MonList *lp;
9924ce527bSscottr
1001175f55bSchristos NO_ALARM;
10124ce527bSscottr if (debug) {
10224ce527bSscottr syslog(LOG_DEBUG, "monitor request for host %s",
10324ce527bSscottr arg->mon_id.mon_name);
10424ce527bSscottr syslog(LOG_DEBUG, "recall host: %s prog: %d ver: %d proc: %d",
105021be7fdSlukem arg->mon_id.my_id.my_name, arg->mon_id.my_id.my_prog,
106021be7fdSlukem arg->mon_id.my_id.my_vers, arg->mon_id.my_id.my_proc);
10724ce527bSscottr }
1080466bbb6Slukem smres.res_stat = stat_fail; /* Assume fail until set otherwise */
1090466bbb6Slukem smres.state = status_info.ourState;
11024ce527bSscottr
11124ce527bSscottr /*
11224ce527bSscottr * Find existing host entry, or create one if not found. If
11324ce527bSscottr * find_host() fails, it will have logged the error already.
11424ce527bSscottr */
11577044250Sfvdl if (getaddrinfo(arg->mon_id.mon_name, NULL, NULL, &ai) != 0) {
11624ce527bSscottr syslog(LOG_ERR, "Invalid hostname to sm_mon: %s",
11724ce527bSscottr arg->mon_id.mon_name);
1180466bbb6Slukem return &smres;
1191175f55bSchristos }
1201175f55bSchristos
12177044250Sfvdl freeaddrinfo(ai);
12277044250Sfvdl
1231175f55bSchristos if ((hp = find_host(arg->mon_id.mon_name, &h)) == NULL)
1241175f55bSchristos memset(hp = &h, 0, sizeof(h));
1251175f55bSchristos
12624ce527bSscottr lp = (MonList *)malloc(sizeof(MonList));
12724ce527bSscottr if (!lp)
12824ce527bSscottr syslog(LOG_ERR, "Out of memory");
12924ce527bSscottr else {
13024ce527bSscottr strncpy(lp->notifyHost, arg->mon_id.my_id.my_name,
13124ce527bSscottr SM_MAXSTRLEN);
13224ce527bSscottr lp->notifyProg = arg->mon_id.my_id.my_prog;
13324ce527bSscottr lp->notifyVers = arg->mon_id.my_id.my_vers;
13424ce527bSscottr lp->notifyProc = arg->mon_id.my_id.my_proc;
13524ce527bSscottr memcpy(lp->notifyData, arg->priv,
13624ce527bSscottr sizeof(lp->notifyData));
13724ce527bSscottr
13824ce527bSscottr lp->next = hp->monList;
13924ce527bSscottr hp->monList = lp;
1401175f55bSchristos change_host(arg->mon_id.mon_name, hp);
14124ce527bSscottr sync_file();
1420466bbb6Slukem smres.res_stat = stat_succ; /* Report success */
14324ce527bSscottr }
1441175f55bSchristos ALARM;
1450466bbb6Slukem return (&smres);
14624ce527bSscottr }
14724ce527bSscottr
14824ce527bSscottr /* do_unmon ---------------------------------------------------------------- */
14924ce527bSscottr /*
15024ce527bSscottr * Purpose: Remove a monitor request from a host
15124ce527bSscottr * Returns: TRUE if found, FALSE if not found.
15224ce527bSscottr * Notes: Common code from sm_unmon_1_svc and sm_unmon_all_1_svc
15324ce527bSscottr * In the unlikely event of more than one identical monitor
15424ce527bSscottr * request, all are removed.
15524ce527bSscottr */
1561175f55bSchristos int
do_unmon(char * name,HostInfo * hp,void * ptr)157*421949a3Ssevan do_unmon(char *name, HostInfo *hp, void *ptr)
15824ce527bSscottr {
1591175f55bSchristos my_id *idp = ptr;
16024ce527bSscottr MonList *lp, *next;
16124ce527bSscottr MonList *last = NULL;
16224ce527bSscottr int result = FALSE;
16324ce527bSscottr
16424ce527bSscottr lp = hp->monList;
16524ce527bSscottr while (lp) {
16624ce527bSscottr if (!strncasecmp(idp->my_name, lp->notifyHost, SM_MAXSTRLEN)
16724ce527bSscottr && (idp->my_prog == lp->notifyProg)
16824ce527bSscottr && (idp->my_proc == lp->notifyProc)
16924ce527bSscottr && (idp->my_vers == lp->notifyVers)) {
17024ce527bSscottr /* found one. Unhook from chain and free. */
17124ce527bSscottr next = lp->next;
17224ce527bSscottr if (last)
17324ce527bSscottr last->next = next;
17424ce527bSscottr else
17524ce527bSscottr hp->monList = next;
17624ce527bSscottr free(lp);
17724ce527bSscottr lp = next;
17824ce527bSscottr result = TRUE;
17924ce527bSscottr } else {
18024ce527bSscottr last = lp;
18124ce527bSscottr lp = lp->next;
18224ce527bSscottr }
18324ce527bSscottr }
18424ce527bSscottr return (result);
18524ce527bSscottr }
18624ce527bSscottr
18724ce527bSscottr /* sm_unmon_1 -------------------------------------------------------------- */
18824ce527bSscottr /*
18924ce527bSscottr * Purpose: RPC procedure to release a monitor request.
19024ce527bSscottr * Returns: Local machine's status number
19124ce527bSscottr * Notes: The supplied mon_id should match the value passed in an
19224ce527bSscottr * earlier call to sm_mon_1
19324ce527bSscottr */
19424ce527bSscottr struct sm_stat *
sm_unmon_1_svc(mon_id * arg,struct svc_req * req)195*421949a3Ssevan sm_unmon_1_svc(mon_id *arg, struct svc_req *req)
19624ce527bSscottr {
1970466bbb6Slukem static sm_stat smres;
1981175f55bSchristos HostInfo *hp, h;
19924ce527bSscottr
2001175f55bSchristos NO_ALARM;
20124ce527bSscottr if (debug) {
20224ce527bSscottr syslog(LOG_DEBUG, "un-monitor request for host %s",
20324ce527bSscottr arg->mon_name);
20424ce527bSscottr syslog(LOG_DEBUG, "recall host: %s prog: %d ver: %d proc: %d",
205021be7fdSlukem arg->my_id.my_name, arg->my_id.my_prog,
20624ce527bSscottr arg->my_id.my_vers, arg->my_id.my_proc);
20724ce527bSscottr }
2081175f55bSchristos if ((hp = find_host(arg->mon_name, &h)) != NULL) {
2091175f55bSchristos if (do_unmon(arg->mon_name, hp, &arg->my_id)) {
2101175f55bSchristos change_host(arg->mon_name, hp);
21124ce527bSscottr sync_file();
2121175f55bSchristos }
21324ce527bSscottr else
21424ce527bSscottr syslog(LOG_ERR,
21524ce527bSscottr "unmon request from %s, no matching monitor",
21624ce527bSscottr arg->my_id.my_name);
21724ce527bSscottr } else
21824ce527bSscottr syslog(LOG_ERR, "unmon request from %s for unknown host %s",
21924ce527bSscottr arg->my_id.my_name, arg->mon_name);
22024ce527bSscottr
2210466bbb6Slukem smres.state = status_info.ourState;
2221175f55bSchristos ALARM;
22324ce527bSscottr
2240466bbb6Slukem return (&smres);
22524ce527bSscottr }
22624ce527bSscottr
22724ce527bSscottr /* sm_unmon_all_1 ---------------------------------------------------------- */
22824ce527bSscottr /*
22924ce527bSscottr * Purpose: RPC procedure to release monitor requests.
23024ce527bSscottr * Returns: Local machine's status number
23124ce527bSscottr * Notes: Releases all monitor requests (if any) from the specified
23224ce527bSscottr * host and program number.
23324ce527bSscottr */
23424ce527bSscottr struct sm_stat *
sm_unmon_all_1_svc(my_id * arg,struct svc_req * req)235*421949a3Ssevan sm_unmon_all_1_svc(my_id *arg, struct svc_req *req)
23624ce527bSscottr {
2370466bbb6Slukem static sm_stat smres;
23824ce527bSscottr
2391175f55bSchristos NO_ALARM;
24024ce527bSscottr if (debug) {
24124ce527bSscottr syslog(LOG_DEBUG,
24224ce527bSscottr "unmon_all for host: %s prog: %d ver: %d proc: %d",
24324ce527bSscottr arg->my_name, arg->my_prog, arg->my_vers, arg->my_proc);
24424ce527bSscottr }
24524ce527bSscottr
2461175f55bSchristos unmon_hosts();
24724ce527bSscottr sync_file();
24824ce527bSscottr
2490466bbb6Slukem smres.state = status_info.ourState;
2501175f55bSchristos ALARM;
25124ce527bSscottr
2520466bbb6Slukem return (&smres);
25324ce527bSscottr }
25424ce527bSscottr
25524ce527bSscottr /* sm_simu_crash_1 --------------------------------------------------------- */
25624ce527bSscottr /*
25724ce527bSscottr * Purpose: RPC procedure to simulate a crash
25824ce527bSscottr * Returns: Nothing
25924ce527bSscottr * Notes: Standardised mechanism for debug purposes
26024ce527bSscottr * The specification says that we should drop all of our
26124ce527bSscottr * status information (apart from the list of monitored hosts
26224ce527bSscottr * on disc). However, this would confuse the rpc.lockd
26324ce527bSscottr * which would be unaware that all of its monitor requests
26424ce527bSscottr * had been silently junked. Hence we in fact retain all
26524ce527bSscottr * current requests and simply increment the status counter
26624ce527bSscottr * and inform all hosts on the monitor list.
26724ce527bSscottr */
26824ce527bSscottr void *
sm_simu_crash_1_svc(void * v,struct svc_req * req)269*421949a3Ssevan sm_simu_crash_1_svc(void *v, struct svc_req *req)
27024ce527bSscottr {
27124ce527bSscottr static char dummy;
27224ce527bSscottr
2731175f55bSchristos NO_ALARM;
27424ce527bSscottr if (debug)
27524ce527bSscottr syslog(LOG_DEBUG, "simu_crash called!!");
27624ce527bSscottr
2771175f55bSchristos reset_database();
2781175f55bSchristos ALARM;
2791175f55bSchristos notify_handler(0);
28024ce527bSscottr
28124ce527bSscottr return (&dummy);
28224ce527bSscottr }
28324ce527bSscottr
28424ce527bSscottr /* sm_notify_1 ------------------------------------------------------------- */
28524ce527bSscottr /*
28624ce527bSscottr * Purpose: RPC procedure notifying local statd of the crash of another
28724ce527bSscottr * Returns: Nothing
28824ce527bSscottr * Notes: There is danger of deadlock, since it is quite likely that
28924ce527bSscottr * the client procedure that we call will in turn call us
29024ce527bSscottr * to remove or adjust the monitor request.
29124ce527bSscottr * We therefore fork() a process to do the notifications.
29224ce527bSscottr * Note that the main HostInfo structure is in a mmap()
29324ce527bSscottr * region and so will be shared with the child, but the
29424ce527bSscottr * monList pointed to by the HostInfo is in normal memory.
29524ce527bSscottr * Hence if we read the monList before forking, we are
29624ce527bSscottr * protected from the parent servicing other requests
29724ce527bSscottr * that modify the list.
29824ce527bSscottr */
29924ce527bSscottr void *
sm_notify_1_svc(stat_chge * arg,struct svc_req * req)300*421949a3Ssevan sm_notify_1_svc(stat_chge *arg, struct svc_req *req)
30124ce527bSscottr {
30224ce527bSscottr struct timeval timeout = {20, 0}; /* 20 secs timeout */
30324ce527bSscottr CLIENT *cli;
30424ce527bSscottr static char dummy;
30524ce527bSscottr status tx_arg; /* arg sent to callback procedure */
30624ce527bSscottr MonList *lp;
3071175f55bSchristos HostInfo *hp, h;
30824ce527bSscottr pid_t pid;
30924ce527bSscottr
31024ce527bSscottr if (debug)
31124ce527bSscottr syslog(LOG_DEBUG, "notify from host %s, new state %d",
31224ce527bSscottr arg->mon_name, arg->state);
31324ce527bSscottr
3141175f55bSchristos hp = find_host(arg->mon_name, &h);
31524ce527bSscottr if (!hp) {
31624ce527bSscottr /* Never heard of this host - why is it notifying us? */
317ff01cf48Sbouyer syslog(LOG_DEBUG, "Unsolicited notification from host %s",
31824ce527bSscottr arg->mon_name);
319ff01cf48Sbouyer return (&dummy);
32024ce527bSscottr }
32124ce527bSscottr lp = hp->monList;
32224ce527bSscottr if (!lp) /* We know this host, but have no outstanding requests. */
323ff01cf48Sbouyer return (&dummy);
32424ce527bSscottr
32558ce78eeSbouyer sync_file();
32624ce527bSscottr pid = fork();
32724ce527bSscottr if (pid == -1) {
32824ce527bSscottr syslog(LOG_ERR, "Unable to fork notify process - %s",
32924ce527bSscottr strerror(errno));
330021be7fdSlukem return (FALSE);
33124ce527bSscottr }
33224ce527bSscottr if (pid)
33324ce527bSscottr return (&dummy); /* Parent returns */
33424ce527bSscottr
33524ce527bSscottr while (lp) {
33624ce527bSscottr tx_arg.mon_name = arg->mon_name;
33724ce527bSscottr tx_arg.state = arg->state;
33824ce527bSscottr memcpy(tx_arg.priv, lp->notifyData, sizeof(tx_arg.priv));
33924ce527bSscottr cli = clnt_create(lp->notifyHost, lp->notifyProg,
34024ce527bSscottr lp->notifyVers, "udp");
34124ce527bSscottr if (!cli)
34224ce527bSscottr syslog(LOG_ERR, "Failed to contact host %s%s",
34324ce527bSscottr lp->notifyHost, clnt_spcreateerror(""));
34424ce527bSscottr else {
34524ce527bSscottr if (clnt_call(cli, lp->notifyProc, xdr_status, &tx_arg,
34624ce527bSscottr xdr_void, &dummy, timeout) != RPC_SUCCESS)
34724ce527bSscottr syslog(LOG_ERR,
34824ce527bSscottr "Failed to call rpc.statd client at host %s",
34924ce527bSscottr lp->notifyHost);
35024ce527bSscottr clnt_destroy(cli);
35124ce527bSscottr }
35224ce527bSscottr lp = lp->next;
35324ce527bSscottr }
35424ce527bSscottr
35524ce527bSscottr exit(0); /* Child quits */
35624ce527bSscottr }
357