3 * A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed for the FreeBSD project
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $
33 * $FreeBSD: src/usr.sbin/rpc.lockd/lockd.c,v 1.6 2001/03/19 12:50:09 alfred Exp $
37 * main() function for NFS lock daemon. Most of the code in this
38 * file was generated by running rpcgen /usr/include/rpcsvc/nlm_prot.x.
40 * The actual program logic is in the file lock_proc.c
43 #include <sys/types.h>
44 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
58 #include <netconfig.h>
62 #include <rpc/rpc_com.h>
63 #include <rpcsvc/sm_inter.h>
66 #include <rpcsvc/nlm_prot.h>
68 int debug_level
= 0; /* 0 = no debugging syslog() calls */
72 char **hosts
, *svcport_str
= NULL
;
77 #define IPPORT_MAX 65535
80 void create_service(struct netconfig
*);
82 void nlm_prog_0(struct svc_req
*, SVCXPRT
*);
83 void nlm_prog_1(struct svc_req
*, SVCXPRT
*);
84 void nlm_prog_3(struct svc_req
*, SVCXPRT
*);
85 void nlm_prog_4(struct svc_req
*, SVCXPRT
*);
86 void out_of_mem(void) __dead2
;
88 static void usage(void) __dead2
;
90 void sigalarm_handler(void);
93 main(int argc
, char **argv
)
97 char *endptr
, **hosts_bak
;
98 struct sigaction sigalarm
;
99 int grace_period
= 30;
100 struct netconfig
*nconf
;
102 int maxrec
= RPC_MAXDATASIZE
;
103 in_port_t svcport
= 0;
105 while ((ch
= getopt(argc
, argv
, "d:g:h:p:")) != (-1)) {
108 debug_level
= atoi(optarg
);
115 grace_period
= atoi(optarg
);
124 hosts_bak
= realloc(hosts
, nhosts
* sizeof(char *));
125 if (hosts_bak
== NULL
) {
127 for (i
= 0; i
< nhosts
; i
++)
134 hosts
[nhosts
- 1] = strdup(optarg
);
135 if (hosts
[nhosts
- 1] == NULL
) {
136 for (i
= 0; i
< (nhosts
- 1); i
++)
144 svcport
= (in_port_t
)strtoul(optarg
, &endptr
, 10);
145 if (endptr
== NULL
|| *endptr
!= '\0' ||
146 svcport
== 0 || svcport
>= IPPORT_MAX
)
148 svcport_str
= strdup(optarg
);
156 if (geteuid()) { /* This command allowed only to root */
157 fprintf(stderr
, "Sorry. You are not superuser\n");
161 rpcb_unset(NLM_PROG
, NLM_SM
, NULL
);
162 rpcb_unset(NLM_PROG
, NLM_VERS
, NULL
);
163 rpcb_unset(NLM_PROG
, NLM_VERSX
, NULL
);
164 rpcb_unset(NLM_PROG
, NLM_VERS4
, NULL
);
167 * Check if IPv6 support is present.
169 s
= socket(AF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
);
175 rpc_control(RPC_SVC_CONNMAXREC_SET
, &maxrec
);
178 * If no hosts were specified, add a wildcard entry to bind to
179 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the
183 hosts
= malloc(sizeof(char**));
192 hosts_bak
= realloc(hosts
, (nhosts
+ 2) *
194 if (hosts_bak
== NULL
) {
195 for (i
= 0; i
< nhosts
; i
++)
203 hosts
[nhosts
- 2] = "::1";
205 hosts_bak
= realloc(hosts
, (nhosts
+ 1) * sizeof(char *));
206 if (hosts_bak
== NULL
) {
207 for (i
= 0; i
< nhosts
; i
++)
217 hosts
[nhosts
- 1] = "127.0.0.1";
220 nc_handle
= setnetconfig();
221 while ((nconf
= getnetconfig(nc_handle
))) {
222 /* We want to listen only on udp6, tcp6, udp, tcp transports */
223 if (nconf
->nc_flag
& NC_VISIBLE
) {
224 /* Skip if there's no IPv6 support */
225 if (have_v6
== 0 && strcmp(nconf
->nc_protofmly
, "inet6") == 0) {
228 create_service(nconf
);
232 endnetconfig(nc_handle
);
235 * Note that it is NOT sensible to run this program from inetd - the
236 * protocol assumes that it will run immediately at boot time.
238 if (daemon(0, debug_level
> 0)) {
239 err(1, "cannot fork");
243 openlog("rpc.lockd", 0, LOG_DAEMON
);
245 syslog(LOG_INFO
, "Starting, debug level %d", debug_level
);
247 syslog(LOG_INFO
, "Starting");
249 sigalarm
.sa_handler
= (sig_t
) sigalarm_handler
;
250 sigemptyset(&sigalarm
.sa_mask
);
251 sigalarm
.sa_flags
= SA_RESETHAND
; /* should only happen once */
252 sigalarm
.sa_flags
|= SA_RESTART
;
253 if (sigaction(SIGALRM
, &sigalarm
, NULL
) != 0) {
254 syslog(LOG_WARNING
, "sigaction(SIGALRM) failed: %s",
261 svc_run(); /* Should never return */
266 * This routine creates and binds sockets on the appropriate
267 * addresses. It gets called one time for each transport and
268 * registrates the service with rpcbind on that trasport.
271 create_service(struct netconfig
*nconf
)
273 struct addrinfo hints
, *res
= NULL
;
274 struct sockaddr_in
*sin
;
275 struct sockaddr_in6
*sin6
;
276 struct __rpc_sockinfo si
;
277 struct netbuf servaddr
;
278 SVCXPRT
*transp
= NULL
;
284 u_int32_t host_addr
[4]; /* IPv4 or IPv6 */
286 if ((nconf
->nc_semantics
!= NC_TPI_CLTS
) &&
287 (nconf
->nc_semantics
!= NC_TPI_COTS
) &&
288 (nconf
->nc_semantics
!= NC_TPI_COTS_ORD
))
289 return; /* not my type */
292 * XXX - using RPC library internal functions.
294 if (!__rpc_nconf2sockinfo(nconf
, &si
)) {
295 syslog(LOG_ERR
, "cannot get information for %s",
300 /* Get rpc.statd's address on this transport */
301 memset(&hints
, 0, sizeof hints
);
302 hints
.ai_flags
= AI_PASSIVE
;
303 hints
.ai_family
= si
.si_af
;
304 hints
.ai_socktype
= si
.si_socktype
;
305 hints
.ai_protocol
= si
.si_proto
;
308 * Bind to specific IPs if asked to
311 while (nhostsbak
> 0) {
315 * XXX - using RPC library internal functions.
317 if ((fd
= __rpc_nconf2fd(nconf
)) < 0) {
318 syslog(LOG_ERR
, "cannot create socket for %s",
323 switch (hints
.ai_family
) {
325 if (inet_pton(AF_INET
, hosts
[nhostsbak
],
327 hints
.ai_flags
&= AI_NUMERICHOST
;
330 * Skip if we have an AF_INET6 address.
332 if (inet_pton(AF_INET6
, hosts
[nhostsbak
],
340 if (inet_pton(AF_INET6
, hosts
[nhostsbak
],
342 hints
.ai_flags
&= AI_NUMERICHOST
;
345 * Skip if we have an AF_INET address.
347 if (inet_pton(AF_INET
, hosts
[nhostsbak
],
359 * If no hosts were specified, just bind to INADDR_ANY
361 if (strcmp("*", hosts
[nhostsbak
]) == 0) {
362 if (svcport_str
== NULL
) {
363 res
= malloc(sizeof(struct addrinfo
));
366 res
->ai_flags
= hints
.ai_flags
;
367 res
->ai_family
= hints
.ai_family
;
368 res
->ai_protocol
= hints
.ai_protocol
;
369 switch (res
->ai_family
) {
371 sin
= malloc(sizeof(struct sockaddr_in
));
374 sin
->sin_family
= AF_INET
;
375 sin
->sin_port
= htons(0);
376 sin
->sin_addr
.s_addr
= htonl(INADDR_ANY
);
377 res
->ai_addr
= (struct sockaddr
*) sin
;
378 res
->ai_addrlen
= (socklen_t
)
379 sizeof(res
->ai_addr
);
382 sin6
= malloc(sizeof(struct sockaddr_in6
));
385 sin6
->sin6_family
= AF_INET6
;
386 sin6
->sin6_port
= htons(0);
387 sin6
->sin6_addr
= in6addr_any
;
388 res
->ai_addr
= (struct sockaddr
*) sin6
;
389 res
->ai_addrlen
= (socklen_t
) sizeof(res
->ai_addr
);
395 if ((aicode
= getaddrinfo(NULL
, svcport_str
,
396 &hints
, &res
)) != 0) {
398 "cannot get local address for %s: %s",
400 gai_strerror(aicode
));
405 if ((aicode
= getaddrinfo(hosts
[nhostsbak
], svcport_str
,
406 &hints
, &res
)) != 0) {
408 "cannot get local address for %s: %s",
409 nconf
->nc_netid
, gai_strerror(aicode
));
414 r
= bindresvport_sa(fd
, res
->ai_addr
);
416 syslog(LOG_ERR
, "bindresvport_sa: %m");
420 transp
= svc_tli_create(fd
, nconf
, NULL
,
421 RPC_MAXDATASIZE
, RPC_MAXDATASIZE
);
423 if (transp
!= NULL
) {
424 if (!svc_reg(transp
, NLM_PROG
, NLM_SM
, nlm_prog_0
,
427 "can't register %s NLM_PROG, NLM_SM service",
430 if (!svc_reg(transp
, NLM_PROG
, NLM_VERS
, nlm_prog_1
,
433 "can't register %s NLM_PROG, NLM_VERS service",
436 if (!svc_reg(transp
, NLM_PROG
, NLM_VERSX
, nlm_prog_3
,
439 "can't register %s NLM_PROG, NLM_VERSX service",
442 if (!svc_reg(transp
, NLM_PROG
, NLM_VERS4
, nlm_prog_4
,
445 "can't register %s NLM_PROG, NLM_VERS4 service",
449 syslog(LOG_WARNING
, "can't create %s services",
452 if (registered
== 0) {
454 memset(&hints
, 0, sizeof hints
);
455 hints
.ai_flags
= AI_PASSIVE
;
456 hints
.ai_family
= si
.si_af
;
457 hints
.ai_socktype
= si
.si_socktype
;
458 hints
.ai_protocol
= si
.si_proto
;
460 if (svcport_str
== NULL
) {
461 svcport_str
= malloc(NI_MAXSERV
* sizeof(char));
462 if (svcport_str
== NULL
)
465 if (getnameinfo(res
->ai_addr
,
466 res
->ai_addr
->sa_len
, NULL
, NI_MAXHOST
,
467 svcport_str
, NI_MAXSERV
* sizeof(char),
468 NI_NUMERICHOST
| NI_NUMERICSERV
))
469 errx(1, "Cannot get port number");
472 if((aicode
= getaddrinfo(NULL
, svcport_str
, &hints
,
474 syslog(LOG_ERR
, "cannot get local address: %s",
475 gai_strerror(aicode
));
479 servaddr
.buf
= malloc(res
->ai_addrlen
);
480 memcpy(servaddr
.buf
, res
->ai_addr
, res
->ai_addrlen
);
481 servaddr
.len
= res
->ai_addrlen
;
483 rpcb_set(NLM_PROG
, NLM_SM
, nconf
, &servaddr
);
484 rpcb_set(NLM_PROG
, NLM_VERS
, nconf
, &servaddr
);
485 rpcb_set(NLM_PROG
, NLM_VERSX
, nconf
, &servaddr
);
486 rpcb_set(NLM_PROG
, NLM_VERS4
, nconf
, &servaddr
);
495 sigalarm_handler(void)
504 errx(1, "usage: rpc.lockd [-d <debuglevel>]"
505 " [-g <grace period>] [-h <bindip>] [-p <port>]");
509 * Out of memory, fatal
514 syslog(LOG_ERR
, "out of memory");