Index: head/usr.sbin/rpc.lockd/procs.c =================================================================== --- head/usr.sbin/rpc.lockd/procs.c (revision 62988) +++ head/usr.sbin/rpc.lockd/procs.c (revision 62989) @@ -1,592 +1,592 @@ /* * Copyright (c) 1995 * A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the FreeBSD project * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include "lockd.h" #include /* for MAXHOSTNAMELEN */ #include #include #include #include #define CLIENT_CACHE_SIZE 64 /* No. of client sockets cached */ #define CLIENT_CACHE_LIFETIME 120 /* In seconds */ /* log_from_addr ----------------------------------------------------------- */ /* Purpose: Log name of function called and source address Returns: Nothing Notes: Extracts the source address from the transport handle passed in as part of the called procedure specification */ static void log_from_addr(char *fun_name, struct svc_req *req) { struct sockaddr_in *addr; struct hostent *host; char hostname_buf[40]; addr = svc_getcaller(req->rq_xprt); host = gethostbyaddr((char *)&(addr->sin_addr), addr->sin_len, AF_INET); if (host) { strncpy(hostname_buf, host->h_name, sizeof(hostname_buf)); hostname_buf[sizeof(hostname_buf) -1] = '\0'; } else /* No hostname available - print raw address */ { strcpy(hostname_buf, inet_ntoa(addr->sin_addr)); } syslog(LOG_DEBUG, "%s from %s", fun_name, hostname_buf); } /* get_client -------------------------------------------------------------- */ /* Purpose: Get a CLIENT* for making RPC calls to lockd on given host Returns: CLIENT* pointer, from clnt_udp_create, or NULL if error Notes: Creating a CLIENT* is quite expensive, involving a conversation with the remote portmapper to get the port number. Since a given client is quite likely to make several locking requests in succession, it is desirable to cache the created CLIENT*. Since we are using UDP rather than TCP, there is no cost to the remote system in keeping these cached indefinitely. Unfortunately there is a snag: if the remote system reboots, the cached portmapper results will be invalid, and we will never detect this since all of the xxx_msg() calls return no result - we just fire off a udp packet and hope for the best. We solve this by discarding cached values after two minutes, regardless of whether they have been used in the meanwhile (since a bad one might have been used plenty of times, as the host keeps retrying the request and we keep sending the reply back to the wrong port). Given that the entries will always expire in the order that they were created, there is no point in a LRU algorithm for when the cache gets full - entries are always re-used in sequence. */ static CLIENT *clnt_cache_ptr[CLIENT_CACHE_SIZE]; static long clnt_cache_time[CLIENT_CACHE_SIZE]; /* time entry created */ static struct in_addr clnt_cache_addr[CLIENT_CACHE_SIZE]; static int clnt_cache_next_to_use = 0; static CLIENT *get_client(struct sockaddr_in *host_addr) { CLIENT *client; int sock_no; struct timeval retry_time, time_now; int i; gettimeofday(&time_now, NULL); /* Search for the given client in the cache, zapping any expired */ /* entries that we happen to notice in passing. */ for (i = 0; i < CLIENT_CACHE_SIZE; i++) { client = clnt_cache_ptr[i]; if (client && ((clnt_cache_time[i] + CLIENT_CACHE_LIFETIME) < time_now.tv_sec)) { /* Cache entry has expired. */ if (debug_level > 3) syslog(LOG_DEBUG, "Expired CLIENT* in cache"); clnt_cache_time[i] = 0L; clnt_destroy(client); clnt_cache_ptr[i] = NULL; client = NULL; } if (client && !memcmp(&clnt_cache_addr[i], &host_addr->sin_addr, sizeof(struct in_addr))) { /* Found it! */ if (debug_level > 3) syslog(LOG_DEBUG, "Found CLIENT* in cache"); return (client); } } /* Not found in cache. Free the next entry if it is in use */ if (clnt_cache_ptr[clnt_cache_next_to_use]) { clnt_destroy(clnt_cache_ptr[clnt_cache_next_to_use]); clnt_cache_ptr[clnt_cache_next_to_use] = NULL; } /* Create the new client handle */ sock_no = RPC_ANYSOCK; retry_time.tv_sec = 5; retry_time.tv_usec = 0; host_addr->sin_port = 0; /* Force consultation with portmapper */ client = clntudp_create(host_addr, NLM_PROG, NLM_VERS, retry_time, &sock_no); if (!client) { - syslog(LOG_ERR, clnt_spcreateerror("clntudp_create")); + syslog(LOG_ERR, "%s", clnt_spcreateerror("clntudp_create")); syslog(LOG_ERR, "Unable to return result to %s", inet_ntoa(host_addr->sin_addr)); return NULL; } /* Success - update the cache entry */ clnt_cache_ptr[clnt_cache_next_to_use] = client; clnt_cache_addr[clnt_cache_next_to_use] = host_addr->sin_addr; clnt_cache_time[clnt_cache_next_to_use] = time_now.tv_sec; if (++clnt_cache_next_to_use > CLIENT_CACHE_SIZE) clnt_cache_next_to_use = 0; /* Disable the default timeout, so we can specify our own in calls */ /* to clnt_call(). [note that the timeout is a different concept */ /* from the retry period set in clnt_udp_create() above.] */ retry_time.tv_sec = -1; retry_time.tv_usec = -1; clnt_control(client, CLSET_TIMEOUT, &retry_time); if (debug_level > 3) syslog(LOG_DEBUG, "Created CLIENT* for %s", inet_ntoa(host_addr->sin_addr)); return client; } /* transmit_result --------------------------------------------------------- */ /* Purpose: Transmit result for nlm_xxx_msg pseudo-RPCs Returns: Nothing - we have no idea if the datagram got there Notes: clnt_call() will always fail (with timeout) as we are calling it with timeout 0 as a hack to just issue a datagram without expecting a result */ static void transmit_result(int opcode, nlm_res *result, struct svc_req *req) { static char dummy; struct sockaddr_in *addr; CLIENT *cli; int success; struct timeval timeo; addr = svc_getcaller(req->rq_xprt); if ((cli = get_client(addr))) { timeo.tv_sec = 0; /* No timeout - not expecting response */ timeo.tv_usec = 0; success = clnt_call(cli, opcode, xdr_nlm_res, result, xdr_void, &dummy, timeo); if (debug_level > 2) syslog(LOG_DEBUG, "clnt_call returns %d\n", success); } } /* ------------------------------------------------------------------------- */ /* Functions for Unix<->Unix locking (ie. monitored locking, with rpc.statd involved to ensure reclaim of locks after a crash of the "stateless" server. These all come in two flavours - nlm_xxx() and nlm_xxx_msg(). The first are standard RPCs with argument and result. The nlm_xxx_msg() calls implement exactly the same functions, but use two pseudo-RPCs (one in each direction). These calls are NOT standard use of the RPC protocol in that they do not return a result at all (NB. this is quite different from returning a void result). The effect of this is to make the nlm_xxx_msg() calls simple unacknowledged datagrams, requiring higher-level code to perform retries. Despite the disadvantages of the nlm_xxx_msg() approach (some of which are documented in the comments to get_client() above), this is the interface used by all current commercial NFS implementations [Solaris, SCO, AIX etc.]. This is presumed to be because these allow implementations to continue using the standard RPC libraries, while avoiding the block-until-result nature of the library interface. No client implementations have been identified so far that make use of the true RPC version (early SunOS releases would be a likely candidate for testing). */ /* nlm_test ---------------------------------------------------------------- */ /* Purpose: Test whether a specified lock would be granted if requested Returns: nlm_granted (or error code) Notes: */ nlm_testres *nlm_test_1_svc(nlm_testargs *arg, struct svc_req *rqstp) { static nlm_testres res; if (debug_level) log_from_addr("nlm_test", rqstp); /* Copy the cookie from the argument into the result. Note that this */ /* is slightly hazardous, as the structure contains a pointer to a */ /* malloc()ed buffer that will get freed by the caller. However, the */ /* main function transmits the result before freeing the argument */ /* so it is in fact safe. */ res.cookie = arg->cookie; res.stat.stat = nlm_granted; return (&res); } void *nlm_test_msg_1_svc(nlm_testargs *arg, struct svc_req *rqstp) { nlm_testres res; static char dummy; struct sockaddr_in *addr; CLIENT *cli; int success; struct timeval timeo; if (debug_level) log_from_addr("nlm_test_msg", rqstp); res.cookie = arg->cookie; res.stat.stat = nlm_granted; /* nlm_test has different result type to the other operations, so */ /* can't use transmit_result() in this case */ addr = svc_getcaller(rqstp->rq_xprt); if ((cli = get_client(addr))) { timeo.tv_sec = 0; /* No timeout - not expecting response */ timeo.tv_usec = 0; success = clnt_call(cli, NLM_TEST_RES, xdr_nlm_testres, &res, xdr_void, &dummy, timeo); if (debug_level > 2) syslog(LOG_DEBUG, "clnt_call returns %d\n", success); } return (NULL); } /* nlm_lock ---------------------------------------------------------------- */ /* Purposes: Establish a lock Returns: granted, denied or blocked Notes: *** grace period support missing */ nlm_res *nlm_lock_1_svc(nlm_lockargs *arg, struct svc_req *rqstp) { static nlm_res res; if (debug_level) log_from_addr("nlm_lock", rqstp); /* copy cookie from arg to result. See comment in nlm_test_1() */ res.cookie = arg->cookie; res.stat.stat = nlm_granted; return (&res); } void *nlm_lock_msg_1_svc(nlm_lockargs *arg, struct svc_req *rqstp) { static nlm_res res; if (debug_level) log_from_addr("nlm_lock_msg", rqstp); res.cookie = arg->cookie; res.stat.stat = nlm_granted; transmit_result(NLM_LOCK_RES, &res, rqstp); return (NULL); } /* nlm_cancel -------------------------------------------------------------- */ /* Purpose: Cancel a blocked lock request Returns: granted or denied Notes: */ nlm_res *nlm_cancel_1_svc(nlm_cancargs *arg, struct svc_req *rqstp) { static nlm_res res; if (debug_level) log_from_addr("nlm_cancel", rqstp); /* copy cookie from arg to result. See comment in nlm_test_1() */ res.cookie = arg->cookie; /* Since at present we never return 'nlm_blocked', there can never be */ /* a lock to cancel, so this call always fails. */ res.stat.stat = nlm_denied; return (&res); } void *nlm_cancel_msg_1_svc(nlm_cancargs *arg, struct svc_req *rqstp) { static nlm_res res; if (debug_level) log_from_addr("nlm_cancel_msg", rqstp); res.cookie = arg->cookie; /* Since at present we never return 'nlm_blocked', there can never be */ /* a lock to cancel, so this call always fails. */ res.stat.stat = nlm_denied; transmit_result(NLM_CANCEL_RES, &res, rqstp); return (NULL); } /* nlm_unlock -------------------------------------------------------------- */ /* Purpose: Release an existing lock Returns: Always granted, unless during grace period Notes: "no such lock" error condition is ignored, as the protocol uses unreliable UDP datagrams, and may well re-try an unlock that has already succeeded. */ nlm_res *nlm_unlock_1_svc(nlm_unlockargs *arg, struct svc_req *rqstp) { static nlm_res res; if (debug_level) log_from_addr("nlm_unlock", rqstp); res.stat.stat= nlm_granted; res.cookie = arg->cookie; return (&res); } void *nlm_unlock_msg_1_svc(nlm_unlockargs *arg, struct svc_req *rqstp) { static nlm_res res; if (debug_level) log_from_addr("nlm_unlock_msg", rqstp); res.stat.stat = nlm_granted; res.cookie = arg->cookie; transmit_result(NLM_UNLOCK_RES, &res, rqstp); return (NULL); } /* ------------------------------------------------------------------------- */ /* Client-side pseudo-RPCs for results. Note that for the client there are only nlm_xxx_msg() versions of each call, since the 'real RPC' version returns the results in the RPC result, and so the client does not normally receive incoming RPCs. The exception to this is nlm_granted(), which is genuinely an RPC call from the server to the client - a 'call-back' in normal procedure call terms. */ /* nlm_granted ------------------------------------------------------------- */ /* Purpose: Receive notification that formerly blocked lock now granted Returns: always success ('granted') Notes: */ nlm_res *nlm_granted_1_svc(nlm_testargs *arg, struct svc_req *rqstp) { static nlm_res res; if (debug_level) log_from_addr("nlm_granted", rqstp); /* copy cookie from arg to result. See comment in nlm_test_1() */ res.cookie = arg->cookie; res.stat.stat = nlm_granted; return (&res); } void *nlm_granted_msg_1_svc(nlm_testargs *arg, struct svc_req *rqstp) { nlm_res res; if (debug_level) log_from_addr("nlm_granted_msg", rqstp); res.cookie = arg->cookie; res.stat.stat = nlm_granted; transmit_result(NLM_GRANTED_RES, &res, rqstp); return (NULL); } /* nlm_test_res ------------------------------------------------------------ */ /* Purpose: Accept result from earlier nlm_test_msg() call Returns: Nothing */ void *nlm_test_res_1_svc(nlm_testres *arg, struct svc_req *rqstp) { if (debug_level) log_from_addr("nlm_test_res", rqstp); return (NULL); } /* nlm_lock_res ------------------------------------------------------------ */ /* Purpose: Accept result from earlier nlm_lock_msg() call Returns: Nothing */ void *nlm_lock_res_1_svc(nlm_res *arg, struct svc_req *rqstp) { if (debug_level) log_from_addr("nlm_lock_res", rqstp); return (NULL); } /* nlm_cancel_res ---------------------------------------------------------- */ /* Purpose: Accept result from earlier nlm_cancel_msg() call Returns: Nothing */ void *nlm_cancel_res_1_svc(nlm_res *arg, struct svc_req *rqstp) { if (debug_level) log_from_addr("nlm_cancel_res", rqstp); return (NULL); } /* nlm_unlock_res ---------------------------------------------------------- */ /* Purpose: Accept result from earlier nlm_unlock_msg() call Returns: Nothing */ void *nlm_unlock_res_1_svc(nlm_res *arg, struct svc_req *rqstp) { if (debug_level) log_from_addr("nlm_unlock_res", rqstp); return (NULL); } /* nlm_granted_res --------------------------------------------------------- */ /* Purpose: Accept result from earlier nlm_granted_msg() call Returns: Nothing */ void *nlm_granted_res_1_svc(nlm_res *arg, struct svc_req *rqstp) { if (debug_level) log_from_addr("nlm_granted_res", rqstp); return (NULL); } /* ------------------------------------------------------------------------- */ /* Calls for PCNFS locking (aka non-monitored locking, no involvement of rpc.statd). These are all genuine RPCs - no nlm_xxx_msg() nonsense here. */ /* nlm_share --------------------------------------------------------------- */ /* Purpose: Establish a DOS-style lock Returns: success or failure Notes: Blocking locks are not supported - client is expected to retry if required. */ nlm_shareres *nlm_share_3_svc(nlm_shareargs *arg, struct svc_req *rqstp) { static nlm_shareres res; if (debug_level) log_from_addr("nlm_share", rqstp); res.cookie = arg->cookie; res.stat = nlm_granted; res.sequence = 1234356; /* X/Open says this field is ignored? */ return (&res); } /* nlm_unshare ------------------------------------------------------------ */ /* Purpose: Release a DOS-style lock Returns: nlm_granted, unless in grace period Notes: */ nlm_shareres *nlm_unshare_3_svc(nlm_shareargs *arg, struct svc_req *rqstp) { static nlm_shareres res; if (debug_level) log_from_addr("nlm_unshare", rqstp); res.cookie = arg->cookie; res.stat = nlm_granted; res.sequence = 1234356; /* X/Open says this field is ignored? */ return (&res); } /* nlm_nm_lock ------------------------------------------------------------ */ /* Purpose: non-monitored version of nlm_lock() Returns: as for nlm_lock() Notes: These locks are in the same style as the standard nlm_lock, but the rpc.statd should not be called to establish a monitor for the client machine, since that machine is declared not to be running a rpc.statd, and so would not respond to the statd protocol. */ nlm_res *nlm_nm_lock_3_svc(nlm_lockargs *arg, struct svc_req *rqstp) { static nlm_res res; if (debug_level) log_from_addr("nlm_nm_lock", rqstp); /* copy cookie from arg to result. See comment in nlm_test_1() */ res.cookie = arg->cookie; res.stat.stat = nlm_granted; return (&res); } /* nlm_free_all ------------------------------------------------------------ */ /* Purpose: Release all locks held by a named client Returns: Nothing Notes: Potential denial of service security problem here - the locks to be released are specified by a host name, independent of the address from which the request has arrived. Should probably be rejected if the named host has been using monitored locks. */ void *nlm_free_all_3_svc(nlm_notify *arg, struct svc_req *rqstp) { static char dummy; if (debug_level) log_from_addr("nlm_free_all", rqstp); return (&dummy); } Index: head/usr.sbin/rpc.ypupdated/ypupdated_main.c =================================================================== --- head/usr.sbin/rpc.ypupdated/ypupdated_main.c (revision 62988) +++ head/usr.sbin/rpc.ypupdated/ypupdated_main.c (revision 62989) @@ -1,288 +1,288 @@ /* * Copyright (c) 1995, 1996 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include "ypupdate_prot.h" #include #include /* getenv, exit */ #include /* for pmap_unset */ #include /* strcmp */ #include #ifdef __cplusplus #include /* getdtablesize, open */ #endif /* __cplusplus */ #include #include #include #include #include #include #include #include #include #include "ypupdated_extern.h" #include "yp_extern.h" #ifndef SIG_PF #define SIG_PF void(*)(int) #endif #ifdef DEBUG #define RPC_SVC_FG #endif #define _RPCSVC_CLOSEDOWN 120 int _rpcpmstart; /* Started by a port monitor ? */ static int _rpcfdtype; /* Whether Stream or Datagram ? */ /* States a server can be in wrt request */ #define _IDLE 0 #define _SERVED 1 #define _SERVING 2 extern int _rpcsvcstate; /* Set when a request is serviced */ char *progname = "rpc.ypupdated"; char *yp_dir = "/var/yp/"; static void _msgout(char* msg) { #ifdef RPC_SVC_FG if (_rpcpmstart) - syslog(LOG_ERR, msg); + syslog(LOG_ERR, "%s", msg); else warnx("%s", msg); #else - syslog(LOG_ERR, msg); + syslog(LOG_ERR, "%s", msg); #endif } static void closedown(int sig) { if (_rpcsvcstate == _IDLE) { extern fd_set svc_fdset; static int size; int i, openfd; if (_rpcfdtype == SOCK_DGRAM) exit(0); if (size == 0) { size = getdtablesize(); } for (i = 0, openfd = 0; i < size && openfd < 2; i++) if (FD_ISSET(i, &svc_fdset)) openfd++; if (openfd <= 1) exit(0); } if (_rpcsvcstate == _SERVED) _rpcsvcstate = _IDLE; (void) signal(SIGALRM, (SIG_PF) closedown); (void) alarm(_RPCSVC_CLOSEDOWN/2); } static void ypupdated_svc_run() { #ifdef FD_SETSIZE fd_set readfds; #else int readfds; #endif /* def FD_SETSIZE */ extern int forked; int pid; int fd_setsize = _rpc_dtablesize(); /* Establish the identity of the parent ypupdated process. */ pid = getpid(); for (;;) { #ifdef FD_SETSIZE readfds = svc_fdset; #else readfds = svc_fds; #endif /* def FD_SETSIZE */ switch (select(fd_setsize, &readfds, NULL, NULL, (struct timeval *)0)) { case -1: if (errno == EINTR) { continue; } warn("svc_run: - select failed"); return; case 0: continue; default: svc_getreqset(&readfds); if (forked && pid != getpid()) exit(0); } } } static void reaper(sig) int sig; { int status; if (sig == SIGHUP) { #ifdef foo load_securenets(); #endif return; } if (sig == SIGCHLD) { while (wait3(&status, WNOHANG, NULL) > 0) children--; } else { (void) pmap_unset(YPU_PROG, YPU_VERS); exit(0); } } void usage() { fprintf(stderr, "rpc.ypupdatedd [-p path]\n"); exit(0); } int main(argc, argv) int argc; char *argv[]; { register SVCXPRT *transp = NULL; int sock; int proto = 0; struct sockaddr_in saddr; int asize = sizeof (saddr); int ch; while ((ch = getopt(argc, argv, "p:h")) != -1) { switch(ch) { case 'p': yp_dir = optarg; break; default: usage(); break; } } #ifdef foo load_securenets(); #endif if (svc_auth_reg(AUTH_DES, _svcauth_des) == -1) { yp_error("failed to register AUTH_DES flavor"); exit(1); } if (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) { int ssize = sizeof (int); if (saddr.sin_family != AF_INET) exit(1); if (getsockopt(0, SOL_SOCKET, SO_TYPE, (char *)&_rpcfdtype, &ssize) == -1) exit(1); sock = 0; _rpcpmstart = 1; proto = 0; openlog("rpc.ypupdatedd", LOG_PID, LOG_DAEMON); } else { #ifndef RPC_SVC_FG if (daemon(0,0)) { err(1, "cannot fork"); } openlog("rpc.ypupdated", LOG_PID, LOG_DAEMON); #endif sock = RPC_ANYSOCK; (void) pmap_unset(YPU_PROG, YPU_VERS); } if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) { transp = svcudp_create(sock); if (transp == NULL) { _msgout("cannot create udp service."); exit(1); } if (!_rpcpmstart) proto = IPPROTO_UDP; if (!svc_register(transp, YPU_PROG, YPU_VERS, ypu_prog_1, proto)) { _msgout("unable to register (YPU_PROG, YPU_VERS, udp)."); exit(1); } } if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) { transp = svctcp_create(sock, 0, 0); if (transp == NULL) { _msgout("cannot create tcp service."); exit(1); } if (!_rpcpmstart) proto = IPPROTO_TCP; if (!svc_register(transp, YPU_PROG, YPU_VERS, ypu_prog_1, proto)) { _msgout("unable to register (YPU_PROG, YPU_VERS, tcp)."); exit(1); } } if (transp == (SVCXPRT *)NULL) { _msgout("could not create a handle"); exit(1); } if (_rpcpmstart) { (void) signal(SIGALRM, (SIG_PF) closedown); (void) alarm(_RPCSVC_CLOSEDOWN/2); } (void) signal(SIGPIPE, SIG_IGN); (void) signal(SIGCHLD, (SIG_PF) reaper); (void) signal(SIGTERM, (SIG_PF) reaper); (void) signal(SIGINT, (SIG_PF) reaper); (void) signal(SIGHUP, (SIG_PF) reaper); ypupdated_svc_run(); _msgout("svc_run returned"); exit(1); /* NOTREACHED */ } Index: head/usr.sbin/rpc.ypxfrd/ypxfrd_main.c =================================================================== --- head/usr.sbin/rpc.ypxfrd/ypxfrd_main.c (revision 62988) +++ head/usr.sbin/rpc.ypxfrd/ypxfrd_main.c (revision 62989) @@ -1,304 +1,304 @@ /* * Copyright (c) 1995, 1996 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include "ypxfrd.h" #include #include #include #include /* getenv, exit */ #include #include /* for pmap_unset */ #include /* strcmp */ #include #include /* TIOCNOTTY */ #ifdef __cplusplus #include /* getdtablesize, open */ #endif /* __cplusplus */ #include #include #include #include #include "ypxfrd_extern.h" #include #include #ifndef SIG_PF #define SIG_PF void(*)(int) #endif #ifdef DEBUG #define RPC_SVC_FG #endif #define _RPCSVC_CLOSEDOWN 120 int _rpcpmstart; /* Started by a port monitor ? */ static int _rpcfdtype; /* Whether Stream or Datagram ? */ /* States a server can be in wrt request */ #define _IDLE 0 #define _SERVED 1 #define _SERVING 2 extern int _rpcsvcstate; /* Set when a request is serviced */ char *progname = "rpc.ypxfrd"; char *yp_dir = "/var/yp/"; static void _msgout(char* msg) { #ifdef RPC_SVC_FG if (_rpcpmstart) - syslog(LOG_ERR, msg); + syslog(LOG_ERR, "%s", msg); else warnx("%s", msg); #else - syslog(LOG_ERR, msg); + syslog(LOG_ERR, "%s", msg); #endif } static void closedown(int sig) { if (_rpcsvcstate == _IDLE) { extern fd_set svc_fdset; static int size; int i, openfd; if (_rpcfdtype == SOCK_DGRAM) exit(0); if (size == 0) { size = getdtablesize(); } for (i = 0, openfd = 0; i < size && openfd < 2; i++) if (FD_ISSET(i, &svc_fdset)) openfd++; if (openfd <= 1) exit(0); } if (_rpcsvcstate == _SERVED) _rpcsvcstate = _IDLE; (void) signal(SIGALRM, (SIG_PF) closedown); (void) alarm(_RPCSVC_CLOSEDOWN/2); } static void ypxfrd_svc_run() { #ifdef FD_SETSIZE fd_set readfds; #else int readfds; #endif /* def FD_SETSIZE */ extern int forked; int pid; int fd_setsize = _rpc_dtablesize(); /* Establish the identity of the parent ypserv process. */ pid = getpid(); for (;;) { #ifdef FD_SETSIZE readfds = svc_fdset; #else readfds = svc_fds; #endif /* def FD_SETSIZE */ switch (select(fd_setsize, &readfds, NULL, NULL, (struct timeval *)0)) { case -1: if (errno == EINTR) { continue; } warn("svc_run: - select failed"); return; case 0: continue; default: svc_getreqset(&readfds); if (forked && pid != getpid()) exit(0); } } } static void reaper(sig) int sig; { int status; int saved_errno; saved_errno = errno; if (sig == SIGHUP) { load_securenets(); errno = saved_errno; return; } if (sig == SIGCHLD) { while (wait3(&status, WNOHANG, NULL) > 0) children--; } else { (void) pmap_unset(YPXFRD_FREEBSD_PROG, YPXFRD_FREEBSD_VERS); exit(0); } errno = saved_errno; return; } void usage() { fprintf(stderr, "usage: rpc.ypxfrd [-p path]\n"); exit(0); } int main(argc, argv) int argc; char *argv[]; { register SVCXPRT *transp = NULL; int sock; int proto = 0; struct sockaddr_in saddr; int asize = sizeof (saddr); int ch; while ((ch = getopt(argc, argv, "p:h")) != -1) { switch(ch) { case 'p': yp_dir = optarg; break; default: usage(); break; } } load_securenets(); if (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) { int ssize = sizeof (int); if (saddr.sin_family != AF_INET) exit(1); if (getsockopt(0, SOL_SOCKET, SO_TYPE, (char *)&_rpcfdtype, &ssize) == -1) exit(1); sock = 0; _rpcpmstart = 1; proto = 0; openlog("rpc.ypxfrd", LOG_PID, LOG_DAEMON); } else { #ifndef RPC_SVC_FG int size; int pid, i; pid = fork(); if (pid < 0) err(1, "fork"); if (pid) exit(0); size = getdtablesize(); for (i = 0; i < size; i++) (void) close(i); i = open("/dev/console", 2); (void) dup2(i, 1); (void) dup2(i, 2); i = open("/dev/tty", 2); if (i >= 0) { (void) ioctl(i, TIOCNOTTY, (char *)NULL); (void) close(i); } openlog("rpc.ypxfrd", LOG_PID, LOG_DAEMON); #endif sock = RPC_ANYSOCK; (void) pmap_unset(YPXFRD_FREEBSD_PROG, YPXFRD_FREEBSD_VERS); } if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) { transp = svcudp_create(sock); if (transp == NULL) { _msgout("cannot create udp service."); exit(1); } if (!_rpcpmstart) proto = IPPROTO_UDP; if (!svc_register(transp, YPXFRD_FREEBSD_PROG, YPXFRD_FREEBSD_VERS, ypxfrd_freebsd_prog_1, proto)) { _msgout("unable to register (YPXFRD_FREEBSD_PROG, YPXFRD_FREEBSD_VERS, udp)."); exit(1); } } if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) { transp = svctcp_create(sock, 0, 0); if (transp == NULL) { _msgout("cannot create tcp service."); exit(1); } if (!_rpcpmstart) proto = IPPROTO_TCP; if (!svc_register(transp, YPXFRD_FREEBSD_PROG, YPXFRD_FREEBSD_VERS, ypxfrd_freebsd_prog_1, proto)) { _msgout("unable to register (YPXFRD_FREEBSD_PROG, YPXFRD_FREEBSD_VERS, tcp)."); exit(1); } } if (transp == (SVCXPRT *)NULL) { _msgout("could not create a handle"); exit(1); } if (_rpcpmstart) { (void) signal(SIGALRM, (SIG_PF) closedown); (void) alarm(_RPCSVC_CLOSEDOWN/2); } (void) signal(SIGPIPE, SIG_IGN); (void) signal(SIGCHLD, (SIG_PF) reaper); (void) signal(SIGTERM, (SIG_PF) reaper); (void) signal(SIGINT, (SIG_PF) reaper); (void) signal(SIGHUP, (SIG_PF) reaper); ypxfrd_svc_run(); _msgout("svc_run returned"); exit(1); /* NOTREACHED */ } Index: head/usr.sbin/rwhod/rwhod.c =================================================================== --- head/usr.sbin/rwhod/rwhod.c (revision 62988) +++ head/usr.sbin/rwhod/rwhod.c (revision 62989) @@ -1,739 +1,739 @@ /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1983, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)rwhod.c 8.1 (Berkeley) 6/6/93"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * This version of Berkeley's rwhod has been modified to use IP multicast * datagrams, under control of a new command-line option: * * rwhod -m causes rwhod to use IP multicast (instead of * broadcast or unicast) on all interfaces that have * the IFF_MULTICAST flag set in their "ifnet" structs * (excluding the loopback interface). The multicast * reports are sent with a time-to-live of 1, to prevent * forwarding beyond the directly-connected subnet(s). * * rwhod -m causes rwhod to send IP multicast datagrams with a * time-to-live of , via a SINGLE interface rather * than all interfaces. must be between 0 and * MAX_MULTICAST_SCOPE, defined below. Note that "-m 1" * is different than "-m", in that "-m 1" specifies * transmission on one interface only. * * When "-m" is used without a argument, the program accepts multicast * rwhod reports from all multicast-capable interfaces. If a argument * is given, it accepts multicast reports from only one interface, the one * on which reports are sent (which may be controlled via the host's routing * table). Regardless of the "-m" option, the program accepts broadcast or * unicast reports from all interfaces. Thus, this program will hear the * reports of old, non-multicasting rwhods, but, if multicasting is used, * those old rwhods won't hear the reports generated by this program. * * -- Steve Deering, Stanford University, February 1989 */ #define UNPRIV_USER "daemon" #define UNPRIV_GROUP "daemon" #define NO_MULTICAST 0 /* multicast modes */ #define PER_INTERFACE_MULTICAST 1 #define SCOPED_MULTICAST 2 #define MAX_MULTICAST_SCOPE 32 /* "site-wide", by convention */ #define INADDR_WHOD_GROUP (u_long)0xe0000103 /* 224.0.1.3 */ /* (belongs in protocols/rwhod.h) */ int insecure_mode; int quiet_mode; int iff_flag = IFF_POINTOPOINT; int multicast_mode = NO_MULTICAST; int multicast_scope; struct sockaddr_in multicast_addr = { sizeof multicast_addr, AF_INET }; /* * Alarm interval. Don't forget to change the down time check in ruptime * if this is changed. */ #define AL_INTERVAL (3 * 60) char myname[MAXHOSTNAMELEN]; /* * We communicate with each neighbor in a list constructed at the time we're * started up. Neighbors are currently directly connected via a hardware * interface. */ struct neighbor { struct neighbor *n_next; char *n_name; /* interface name */ struct sockaddr *n_addr; /* who to send to */ int n_addrlen; /* size of address */ int n_flags; /* should forward?, interface flags */ }; struct neighbor *neighbors; struct whod mywd; struct servent *sp; int s, utmpf; #define WHDRSIZE (sizeof(mywd) - sizeof(mywd.wd_we)) void run_as __P((uid_t *, gid_t *)); int configure __P((int)); void getboottime __P((int)); void onalrm __P((int)); void quit __P((char *)); void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *)); int verify __P((char *, int)); static void usage __P((void)); #ifdef DEBUG char *interval __P((int, char *)); void Sendto __P((int, const void *, size_t, int, const struct sockaddr *, int)); #define sendto Sendto #endif int main(argc, argv) int argc; char *argv[]; { struct sockaddr_in from; struct stat st; char path[64]; int on = 1; char *cp; struct sockaddr_in sin; uid_t unpriv_uid; gid_t unpriv_gid; if (getuid()) errx(1, "not super user"); run_as(&unpriv_uid, &unpriv_gid); argv++; argc--; while (argc > 0 && *argv[0] == '-') { if (strcmp(*argv, "-m") == 0) { if (argc > 1 && isdigit(*(argv + 1)[0])) { argv++, argc--; multicast_mode = SCOPED_MULTICAST; multicast_scope = atoi(*argv); if (multicast_scope > MAX_MULTICAST_SCOPE) errx(1, "ttl must not exceed %u", MAX_MULTICAST_SCOPE); } else multicast_mode = PER_INTERFACE_MULTICAST; } else if (strcmp(*argv, "-i") == 0) insecure_mode = 1; else if (strcmp(*argv, "-l") == 0) quiet_mode = 1; else if (strcmp(*argv, "-p") == 0) iff_flag = 0; else usage(); argv++, argc--; } if (argc > 0) usage(); #ifndef DEBUG daemon(1, 0); #endif (void) signal(SIGHUP, getboottime); openlog("rwhod", LOG_PID, LOG_DAEMON); sp = getservbyname("who", "udp"); if (sp == NULL) { syslog(LOG_ERR, "udp/who: unknown service"); exit(1); } if (chdir(_PATH_RWHODIR) < 0) { syslog(LOG_ERR, "%s: %m", _PATH_RWHODIR); exit(1); } /* * Establish host name as returned by system. */ if (gethostname(myname, sizeof(myname) - 1) < 0) { syslog(LOG_ERR, "gethostname: %m"); exit(1); } if ((cp = index(myname, '.')) != NULL) *cp = '\0'; strncpy(mywd.wd_hostname, myname, sizeof(mywd.wd_hostname) - 1); mywd.wd_hostname[sizeof(mywd.wd_hostname) - 1] = '\0'; utmpf = open(_PATH_UTMP, O_RDONLY|O_CREAT, 0644); if (utmpf < 0) { syslog(LOG_ERR, "%s: %m", _PATH_UTMP); exit(1); } getboottime(0); if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { syslog(LOG_ERR, "socket: %m"); exit(1); } if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) { syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m"); exit(1); } memset(&sin, 0, sizeof(sin)); sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; sin.sin_port = sp->s_port; if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { syslog(LOG_ERR, "bind: %m"); exit(1); } setgid(unpriv_gid); setgroups(1, &unpriv_gid); /* XXX BOGUS groups[0] = egid */ setuid(unpriv_uid); if (!configure(s)) exit(1); if (!quiet_mode) { signal(SIGALRM, onalrm); onalrm(0); } for (;;) { struct whod wd; int cc, whod, len = sizeof(from); cc = recvfrom(s, (char *)&wd, sizeof(struct whod), 0, (struct sockaddr *)&from, &len); if (cc <= 0) { if (cc < 0 && errno != EINTR) syslog(LOG_WARNING, "recv: %m"); continue; } if (from.sin_port != sp->s_port && !insecure_mode) { syslog(LOG_WARNING, "%d: bad from port", ntohs(from.sin_port)); continue; } if (wd.wd_vers != WHODVERSION) continue; if (wd.wd_type != WHODTYPE_STATUS) continue; if (!verify(wd.wd_hostname, sizeof wd.wd_hostname)) { syslog(LOG_WARNING, "malformed host name from %x", from.sin_addr); continue; } (void) snprintf(path, sizeof path, "whod.%s", wd.wd_hostname); /* * Rather than truncating and growing the file each time, * use ftruncate if size is less than previous size. */ whod = open(path, O_WRONLY | O_CREAT, 0644); if (whod < 0) { syslog(LOG_WARNING, "%s: %m", path); continue; } #if ENDIAN != BIG_ENDIAN { int i, n = (cc - WHDRSIZE)/sizeof(struct whoent); struct whoent *we; /* undo header byte swapping before writing to file */ wd.wd_sendtime = ntohl(wd.wd_sendtime); for (i = 0; i < 3; i++) wd.wd_loadav[i] = ntohl(wd.wd_loadav[i]); wd.wd_boottime = ntohl(wd.wd_boottime); we = wd.wd_we; for (i = 0; i < n; i++) { we->we_idle = ntohl(we->we_idle); we->we_utmp.out_time = ntohl(we->we_utmp.out_time); we++; } } #endif (void) time((time_t *)&wd.wd_recvtime); (void) write(whod, (char *)&wd, cc); if (fstat(whod, &st) < 0 || st.st_size > cc) ftruncate(whod, cc); (void) close(whod); } } static void usage() { fprintf(stderr, "usage: rwhod [-i] [-p] [-l] [-m [ttl]]\n"); exit(1); } void run_as(uid, gid) uid_t *uid; gid_t *gid; { struct passwd *pw; struct group *gr; pw = getpwnam(UNPRIV_USER); if (!pw) { syslog(LOG_ERR, "getpwnam(%s): %m", UNPRIV_USER); exit(1); } *uid = pw->pw_uid; gr = getgrnam(UNPRIV_GROUP); if (!gr) { syslog(LOG_ERR, "getgrnam(%s): %m", UNPRIV_GROUP); exit(1); } *gid = gr->gr_gid; } /* * Check out host name for unprintables * and other funnies before allowing a file * to be created. Sorry, but blanks aren't allowed. */ int verify(name, maxlen) register char *name; register int maxlen; { register int size = 0; while (*name && size < maxlen - 1) { if (!isascii(*name) || !(isalnum(*name) || ispunct(*name))) return (0); name++, size++; } *name = '\0'; return (size > 0); } int utmptime; int utmpent; int utmpsize = 0; struct utmp *utmp; int alarmcount; void onalrm(signo) int signo; { register struct neighbor *np; register struct whoent *we = mywd.wd_we, *wlast; register int i; struct stat stb; double avenrun[3]; time_t now; int cc; now = time(NULL); if (alarmcount % 10 == 0) getboottime(0); alarmcount++; (void) fstat(utmpf, &stb); if ((stb.st_mtime != utmptime) || (stb.st_size > utmpsize)) { utmptime = stb.st_mtime; if (stb.st_size > utmpsize) { utmpsize = stb.st_size + 10 * sizeof(struct utmp); if (utmp) utmp = (struct utmp *)realloc(utmp, utmpsize); else utmp = (struct utmp *)malloc(utmpsize); if (! utmp) { syslog(LOG_WARNING, "malloc failed"); utmpsize = 0; goto done; } } (void) lseek(utmpf, (off_t)0, L_SET); cc = read(utmpf, (char *)utmp, stb.st_size); if (cc < 0) { syslog(LOG_ERR, "read(%s): %m", _PATH_UTMP); goto done; } wlast = &mywd.wd_we[1024 / sizeof(struct whoent) - 1]; utmpent = cc / sizeof(struct utmp); for (i = 0; i < utmpent; i++) if (utmp[i].ut_name[0]) { memcpy(we->we_utmp.out_line, utmp[i].ut_line, sizeof(utmp[i].ut_line)); memcpy(we->we_utmp.out_name, utmp[i].ut_name, sizeof(utmp[i].ut_name)); we->we_utmp.out_time = htonl(utmp[i].ut_time); if (we >= wlast) break; we++; } utmpent = we - mywd.wd_we; } /* * The test on utmpent looks silly---after all, if no one is * logged on, why worry about efficiency?---but is useful on * (e.g.) compute servers. */ if (utmpent && chdir(_PATH_DEV)) { syslog(LOG_ERR, "chdir(%s): %m", _PATH_DEV); exit(1); } we = mywd.wd_we; for (i = 0; i < utmpent; i++) { if (stat(we->we_utmp.out_line, &stb) >= 0) we->we_idle = htonl(now - stb.st_atime); we++; } (void)getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])); for (i = 0; i < 3; i++) mywd.wd_loadav[i] = htonl((u_long)(avenrun[i] * 100)); cc = (char *)we - (char *)&mywd; mywd.wd_sendtime = htonl(time(0)); mywd.wd_vers = WHODVERSION; mywd.wd_type = WHODTYPE_STATUS; if (multicast_mode == SCOPED_MULTICAST) { (void) sendto(s, (char *)&mywd, cc, 0, (struct sockaddr *)&multicast_addr, sizeof(multicast_addr)); } else for (np = neighbors; np != NULL; np = np->n_next) { if (multicast_mode == PER_INTERFACE_MULTICAST && np->n_flags & IFF_MULTICAST) { /* * Select the outgoing interface for the multicast. */ if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &(((struct sockaddr_in *)np->n_addr)->sin_addr), sizeof(struct in_addr)) < 0) { syslog(LOG_ERR, "setsockopt IP_MULTICAST_IF: %m"); exit(1); } (void) sendto(s, (char *)&mywd, cc, 0, (struct sockaddr *)&multicast_addr, sizeof(multicast_addr)); } else (void) sendto(s, (char *)&mywd, cc, 0, np->n_addr, np->n_addrlen); } if (utmpent && chdir(_PATH_RWHODIR)) { syslog(LOG_ERR, "chdir(%s): %m", _PATH_RWHODIR); exit(1); } done: (void) alarm(AL_INTERVAL); } void getboottime(signo) int signo; { int mib[2]; size_t size; struct timeval tm; mib[0] = CTL_KERN; mib[1] = KERN_BOOTTIME; size = sizeof(tm); if (sysctl(mib, 2, &tm, &size, NULL, 0) == -1) { syslog(LOG_ERR, "cannot get boottime: %m"); exit(1); } mywd.wd_boottime = htonl(tm.tv_sec); } void quit(msg) char *msg; { - syslog(LOG_ERR, msg); + syslog(LOG_ERR, "%s", msg); exit(1); } #define ROUNDUP(a) \ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) void rt_xaddrs(cp, cplim, rtinfo) register caddr_t cp, cplim; register struct rt_addrinfo *rtinfo; { register struct sockaddr *sa; register int i; memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info)); for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) { if ((rtinfo->rti_addrs & (1 << i)) == 0) continue; rtinfo->rti_info[i] = sa = (struct sockaddr *)cp; ADVANCE(cp, sa); } } /* * Figure out device configuration and select * networks which deserve status information. */ int configure(s) int s; { register struct neighbor *np; register struct if_msghdr *ifm; register struct ifa_msghdr *ifam; struct sockaddr_dl *sdl; size_t needed; int mib[6], flags = 0, len; char *buf, *lim, *next; struct rt_addrinfo info; if (multicast_mode != NO_MULTICAST) { multicast_addr.sin_addr.s_addr = htonl(INADDR_WHOD_GROUP); multicast_addr.sin_port = sp->s_port; } if (multicast_mode == SCOPED_MULTICAST) { struct ip_mreq mreq; unsigned char ttl; mreq.imr_multiaddr.s_addr = htonl(INADDR_WHOD_GROUP); mreq.imr_interface.s_addr = htonl(INADDR_ANY); if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { syslog(LOG_ERR, "setsockopt IP_ADD_MEMBERSHIP: %m"); return(0); } ttl = multicast_scope; if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) { syslog(LOG_ERR, "setsockopt IP_MULTICAST_TTL: %m"); return(0); } return(1); } mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; mib[3] = AF_INET; mib[4] = NET_RT_IFLIST; mib[5] = 0; if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) quit("route-sysctl-estimate"); if ((buf = malloc(needed)) == NULL) quit("malloc"); if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) quit("actual retrieval of interface table"); lim = buf + needed; sdl = NULL; /* XXX just to keep gcc -Wall happy */ for (next = buf; next < lim; next += ifm->ifm_msglen) { ifm = (struct if_msghdr *)next; if (ifm->ifm_type == RTM_IFINFO) { sdl = (struct sockaddr_dl *)(ifm + 1); flags = ifm->ifm_flags; continue; } if ((flags & IFF_UP) == 0 || (flags & (((multicast_mode == PER_INTERFACE_MULTICAST) ? IFF_MULTICAST : 0) | IFF_BROADCAST|iff_flag)) == 0) continue; if (ifm->ifm_type != RTM_NEWADDR) quit("out of sync parsing NET_RT_IFLIST"); ifam = (struct ifa_msghdr *)ifm; info.rti_addrs = ifam->ifam_addrs; rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info); /* gag, wish we could get rid of Internet dependencies */ #define dstaddr info.rti_info[RTAX_BRD] #define ifaddr info.rti_info[RTAX_IFA] #define IPADDR_SA(x) ((struct sockaddr_in *)(x))->sin_addr.s_addr #define PORT_SA(x) ((struct sockaddr_in *)(x))->sin_port if (dstaddr == 0 || dstaddr->sa_family != AF_INET) continue; PORT_SA(dstaddr) = sp->s_port; for (np = neighbors; np != NULL; np = np->n_next) if (memcmp(sdl->sdl_data, np->n_name, sdl->sdl_nlen) == 0 && IPADDR_SA(np->n_addr) == IPADDR_SA(dstaddr)) break; if (np != NULL) continue; len = sizeof(*np) + dstaddr->sa_len + sdl->sdl_nlen + 1; np = (struct neighbor *)malloc(len); if (np == NULL) quit("malloc of neighbor structure"); memset(np, 0, len); np->n_flags = flags; np->n_addr = (struct sockaddr *)(np + 1); np->n_addrlen = dstaddr->sa_len; np->n_name = np->n_addrlen + (char *)np->n_addr; memcpy((char *)np->n_addr, (char *)dstaddr, np->n_addrlen); memcpy(np->n_name, sdl->sdl_data, sdl->sdl_nlen); if (multicast_mode == PER_INTERFACE_MULTICAST && (flags & IFF_MULTICAST) && !(flags & IFF_LOOPBACK)) { struct ip_mreq mreq; memcpy((char *)np->n_addr, (char *)ifaddr, np->n_addrlen); mreq.imr_multiaddr.s_addr = htonl(INADDR_WHOD_GROUP); mreq.imr_interface.s_addr = ((struct sockaddr_in *)np->n_addr)->sin_addr.s_addr; if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { syslog(LOG_ERR, "setsockopt IP_ADD_MEMBERSHIP: %m"); #if 0 /* Fall back to broadcast on this if. */ np->n_flags &= ~IFF_MULTICAST; #else free((char *)np); continue; #endif } } np->n_next = neighbors; neighbors = np; } free(buf); return (1); } #ifdef DEBUG void Sendto(s, buf, cc, flags, to, tolen) int s; const void *buf; size_t cc; int flags; const struct sockaddr *to; int tolen; { register struct whod *w = (struct whod *)buf; register struct whoent *we; struct sockaddr_in *sin = (struct sockaddr_in *)to; printf("sendto %x.%d\n", ntohl(sin->sin_addr.s_addr), ntohs(sin->sin_port)); printf("hostname %s %s\n", w->wd_hostname, interval(ntohl(w->wd_sendtime) - ntohl(w->wd_boottime), " up")); printf("load %4.2f, %4.2f, %4.2f\n", ntohl(w->wd_loadav[0]) / 100.0, ntohl(w->wd_loadav[1]) / 100.0, ntohl(w->wd_loadav[2]) / 100.0); cc -= WHDRSIZE; for (we = w->wd_we, cc /= sizeof(struct whoent); cc > 0; cc--, we++) { time_t t = ntohl(we->we_utmp.out_time); printf("%-8.8s %s:%s %.12s", we->we_utmp.out_name, w->wd_hostname, we->we_utmp.out_line, ctime(&t)+4); we->we_idle = ntohl(we->we_idle) / 60; if (we->we_idle) { if (we->we_idle >= 100*60) we->we_idle = 100*60 - 1; if (we->we_idle >= 60) printf(" %2d", we->we_idle / 60); else printf(" "); printf(":%02d", we->we_idle % 60); } printf("\n"); } } char * interval(time, updown) int time; char *updown; { static char resbuf[32]; int days, hours, minutes; if (time < 0 || time > 3*30*24*60*60) { (void) sprintf(resbuf, " %s ??:??", updown); return (resbuf); } minutes = (time + 59) / 60; /* round to minutes */ hours = minutes / 60; minutes %= 60; days = hours / 24; hours %= 24; if (days) (void) sprintf(resbuf, "%s %2d+%02d:%02d", updown, days, hours, minutes); else (void) sprintf(resbuf, "%s %2d:%02d", updown, hours, minutes); return (resbuf); } #endif Index: head/usr.sbin/ypserv/yp_main.c =================================================================== --- head/usr.sbin/ypserv/yp_main.c (revision 62988) +++ head/usr.sbin/ypserv/yp_main.c (revision 62989) @@ -1,340 +1,340 @@ /* * Copyright (c) 1995 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ /* * ypserv startup function. * We need out own main() since we have to do some additional work * that rpcgen won't do for us. Most of this file was generated using * rpcgen.new, and later modified. */ #include "yp.h" #include #include #include #include #include #include /* getenv, exit */ #include /* strcmp */ #include #include #include /* for pmap_unset */ #ifdef __cplusplus #include /* getdtablesize, open */ #endif /* __cplusplus */ #include #include #include #include "yp_extern.h" #include #ifndef SIG_PF #define SIG_PF void(*)(int) #endif #define _RPCSVC_CLOSEDOWN 120 int _rpcpmstart; /* Started by a port monitor ? */ static int _rpcfdtype; /* Whether Stream or Datagram ? */ /* States a server can be in wrt request */ #define _IDLE 0 #define _SERVED 1 #define _SERVING 2 extern void ypprog_1 __P((struct svc_req *, register SVCXPRT *)); extern void ypprog_2 __P((struct svc_req *, register SVCXPRT *)); extern int _rpc_dtablesize __P((void)); extern int _rpcsvcstate; /* Set when a request is serviced */ char *progname = "ypserv"; char *yp_dir = _PATH_YP; /*int debug = 0;*/ int do_dns = 0; int resfd; static void _msgout(char* msg) { if (debug) { if (_rpcpmstart) - syslog(LOG_ERR, msg); + syslog(LOG_ERR, "%s", msg); else warnx("%s", msg); } else - syslog(LOG_ERR, msg); + syslog(LOG_ERR, "%s", msg); } pid_t yp_pid; static void yp_svc_run() { #ifdef FD_SETSIZE fd_set readfds; #else int readfds; #endif /* def FD_SETSIZE */ extern int forked; int fd_setsize = _rpc_dtablesize(); struct timeval timeout; /* Establish the identity of the parent ypserv process. */ yp_pid = getpid(); for (;;) { #ifdef FD_SETSIZE readfds = svc_fdset; #else readfds = svc_fds; #endif /* def FD_SETSIZE */ FD_SET(resfd, &readfds); timeout.tv_sec = RESOLVER_TIMEOUT; timeout.tv_usec = 0; switch (select(fd_setsize, &readfds, NULL, NULL, &timeout)) { case -1: if (errno == EINTR) { continue; } warn("svc_run: - select failed"); return; case 0: if (getpid() == yp_pid) yp_prune_dnsq(); break; default: if (getpid() == yp_pid) { if (FD_ISSET(resfd, &readfds)) { yp_run_dnsq(); FD_CLR(resfd, &readfds); } svc_getreqset(&readfds); } } if (yp_pid != getpid()) _exit(0); } } static void unregister() { (void) pmap_unset(YPPROG, YPVERS); (void) pmap_unset(YPPROG, YPOLDVERS); } static void reaper(sig) int sig; { int status; int saved_errno; saved_errno = errno; if (sig == SIGHUP) { load_securenets(); #ifdef DB_CACHE yp_flush_all(); #endif errno = saved_errno; return; } if (sig == SIGCHLD) { while (wait3(&status, WNOHANG, NULL) > 0) children--; } else { unregister(); exit(0); } errno = saved_errno; return; } static void usage() { fprintf(stderr, "usage: ypserv [-h] [-d] [-n] [-p path]\n"); exit(1); } static void closedown(int sig) { if (_rpcsvcstate == _IDLE) { extern fd_set svc_fdset; static int size; int i, openfd; if (_rpcfdtype == SOCK_DGRAM) { unregister(); exit(0); } if (size == 0) { size = getdtablesize(); } for (i = 0, openfd = 0; i < size && openfd < 2; i++) if (FD_ISSET(i, &svc_fdset)) openfd++; if (openfd <= 1) { unregister(); exit(0); } } if (_rpcsvcstate == _SERVED) _rpcsvcstate = _IDLE; (void) signal(SIGALRM, (SIG_PF) closedown); (void) alarm(_RPCSVC_CLOSEDOWN/2); } int main(argc, argv) int argc; char *argv[]; { register SVCXPRT *transp = NULL; int sock; int proto = 0; struct sockaddr_in saddr; int asize = sizeof (saddr); int ch; while ((ch = getopt(argc, argv, "hdnp:")) != -1) { switch(ch) { case 'd': debug = ypdb_debug = 1; break; case 'n': do_dns = 1; break; case 'p': yp_dir = optarg; break; case 'h': default: usage(); } } load_securenets(); yp_init_resolver(); #ifdef DB_CACHE yp_init_dbs(); #endif if (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) { int ssize = sizeof (int); if (saddr.sin_family != AF_INET) exit(1); if (getsockopt(0, SOL_SOCKET, SO_TYPE, (char *)&_rpcfdtype, &ssize) == -1) exit(1); sock = 0; _rpcpmstart = 1; proto = 0; openlog("ypserv", LOG_PID, LOG_DAEMON); } else { if (!debug) { if (daemon(0,0)) { err(1,"cannot fork"); } openlog("ypserv", LOG_PID, LOG_DAEMON); } sock = RPC_ANYSOCK; (void) pmap_unset(YPPROG, YPVERS); (void) pmap_unset(YPPROG, 1); } if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) { transp = svcudp_create(sock); if (transp == NULL) { _msgout("cannot create udp service"); exit(1); } if (!_rpcpmstart) proto = IPPROTO_UDP; if (!svc_register(transp, YPPROG, YPOLDVERS, ypprog_1, proto)) { _msgout("unable to register (YPPROG, YPOLDVERS, udp)"); exit(1); } if (!svc_register(transp, YPPROG, YPVERS, ypprog_2, proto)) { _msgout("unable to register (YPPROG, YPVERS, udp)"); exit(1); } } if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) { transp = svctcp_create(sock, 0, 0); if (transp == NULL) { _msgout("cannot create tcp service"); exit(1); } if (!_rpcpmstart) proto = IPPROTO_TCP; if (!svc_register(transp, YPPROG, YPOLDVERS, ypprog_1, proto)) { _msgout("unable to register (YPPROG, YPOLDVERS, tcp)"); exit(1); } if (!svc_register(transp, YPPROG, YPVERS, ypprog_2, proto)) { _msgout("unable to register (YPPROG, YPVERS, tcp)"); exit(1); } } if (transp == (SVCXPRT *)NULL) { _msgout("could not create a handle"); exit(1); } if (_rpcpmstart) { (void) signal(SIGALRM, (SIG_PF) closedown); (void) alarm(_RPCSVC_CLOSEDOWN/2); } /* * Make sure SIGPIPE doesn't blow us away while servicing TCP * connections. */ (void) signal(SIGPIPE, SIG_IGN); (void) signal(SIGCHLD, (SIG_PF) reaper); (void) signal(SIGTERM, (SIG_PF) reaper); (void) signal(SIGINT, (SIG_PF) reaper); (void) signal(SIGHUP, (SIG_PF) reaper); yp_svc_run(); _msgout("svc_run returned"); exit(1); /* NOTREACHED */ }