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 $
34 * $DragonFly: src/usr.sbin/rpc.lockd/lockd.c,v 1.5 2005/11/25 00:32:49 swildner Exp $
38 * main() function for NFS lock daemon. Most of the code in this
39 * file was generated by running rpcgen /usr/include/rpcsvc/nlm_prot.x.
41 * The actual program logic is in the file lock_proc.c
44 #include <sys/types.h>
45 #include <sys/socket.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
59 #include <netconfig.h>
63 #include <rpc/rpc_com.h>
64 #include <rpcsvc/sm_inter.h>
67 #include <rpcsvc/nlm_prot.h>
69 int debug_level
= 0; /* 0 = no debugging syslog() calls */
73 char **hosts
, *svcport_str
= NULL
;
78 #define IPPORT_MAX 65535
81 void create_service(struct netconfig
*);
83 void nlm_prog_0(struct svc_req
*, SVCXPRT
*);
84 void nlm_prog_1(struct svc_req
*, SVCXPRT
*);
85 void nlm_prog_3(struct svc_req
*, SVCXPRT
*);
86 void nlm_prog_4(struct svc_req
*, SVCXPRT
*);
87 void out_of_mem(void);
89 static void usage(void);
91 void sigalarm_handler(void);
94 main(int argc
, char **argv
)
98 char *endptr
, **hosts_bak
;
99 struct sigaction sigalarm
;
100 int grace_period
= 30;
101 struct netconfig
*nconf
;
103 int maxrec
= RPC_MAXDATASIZE
;
104 in_port_t svcport
= 0;
106 while ((ch
= getopt(argc
, argv
, "d:g:h:p:")) != (-1)) {
109 debug_level
= atoi(optarg
);
116 grace_period
= atoi(optarg
);
125 hosts_bak
= realloc(hosts
, nhosts
* sizeof(char *));
126 if (hosts_bak
== NULL
) {
128 for (i
= 0; i
< nhosts
; i
++)
135 hosts
[nhosts
- 1] = strdup(optarg
);
136 if (hosts
[nhosts
- 1] == NULL
) {
137 for (i
= 0; i
< (nhosts
- 1); i
++)
145 svcport
= (in_port_t
)strtoul(optarg
, &endptr
, 10);
146 if (endptr
== NULL
|| *endptr
!= '\0' ||
147 svcport
== 0 || svcport
>= IPPORT_MAX
)
149 svcport_str
= strdup(optarg
);
157 if (geteuid()) { /* This command allowed only to root */
158 fprintf(stderr
, "Sorry. You are not superuser\n");
162 rpcb_unset(NLM_PROG
, NLM_SM
, NULL
);
163 rpcb_unset(NLM_PROG
, NLM_VERS
, NULL
);
164 rpcb_unset(NLM_PROG
, NLM_VERSX
, NULL
);
165 rpcb_unset(NLM_PROG
, NLM_VERS4
, NULL
);
168 * Check if IPv6 support is present.
170 s
= socket(AF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
);
176 rpc_control(RPC_SVC_CONNMAXREC_SET
, &maxrec
);
179 * If no hosts were specified, add a wildcard entry to bind to
180 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the
184 hosts
= malloc(sizeof(char**));
193 hosts_bak
= realloc(hosts
, (nhosts
+ 2) *
195 if (hosts_bak
== NULL
) {
196 for (i
= 0; i
< nhosts
; i
++)
204 hosts
[nhosts
- 2] = "::1";
206 hosts_bak
= realloc(hosts
, (nhosts
+ 1) * sizeof(char *));
207 if (hosts_bak
== NULL
) {
208 for (i
= 0; i
< nhosts
; i
++)
218 hosts
[nhosts
- 1] = "127.0.0.1";
221 nc_handle
= setnetconfig();
222 while ((nconf
= getnetconfig(nc_handle
))) {
223 /* We want to listen only on udp6, tcp6, udp, tcp transports */
224 if (nconf
->nc_flag
& NC_VISIBLE
) {
225 /* Skip if there's no IPv6 support */
226 if (have_v6
== 0 && strcmp(nconf
->nc_protofmly
, "inet6") == 0) {
229 create_service(nconf
);
233 endnetconfig(nc_handle
);
236 * Note that it is NOT sensible to run this program from inetd - the
237 * protocol assumes that it will run immediately at boot time.
239 if (daemon(0, debug_level
> 0)) {
240 err(1, "cannot fork");
244 openlog("rpc.lockd", 0, LOG_DAEMON
);
246 syslog(LOG_INFO
, "Starting, debug level %d", debug_level
);
248 syslog(LOG_INFO
, "Starting");
250 sigalarm
.sa_handler
= (sig_t
) sigalarm_handler
;
251 sigemptyset(&sigalarm
.sa_mask
);
252 sigalarm
.sa_flags
= SA_RESETHAND
; /* should only happen once */
253 sigalarm
.sa_flags
|= SA_RESTART
;
254 if (sigaction(SIGALRM
, &sigalarm
, NULL
) != 0) {
255 syslog(LOG_WARNING
, "sigaction(SIGALRM) failed: %s",
262 svc_run(); /* Should never return */
267 * This routine creates and binds sockets on the appropriate
268 * addresses. It gets called one time for each transport and
269 * registrates the service with rpcbind on that trasport.
272 create_service(struct netconfig
*nconf
)
274 struct addrinfo hints
, *res
= NULL
;
275 struct sockaddr_in
*sin
;
276 struct sockaddr_in6
*sin6
;
277 struct __rpc_sockinfo si
;
278 struct netbuf servaddr
;
279 SVCXPRT
*transp
= NULL
;
285 u_int32_t host_addr
[4]; /* IPv4 or IPv6 */
287 if ((nconf
->nc_semantics
!= NC_TPI_CLTS
) &&
288 (nconf
->nc_semantics
!= NC_TPI_COTS
) &&
289 (nconf
->nc_semantics
!= NC_TPI_COTS_ORD
))
290 return; /* not my type */
293 * XXX - using RPC library internal functions.
295 if (!__rpc_nconf2sockinfo(nconf
, &si
)) {
296 syslog(LOG_ERR
, "cannot get information for %s",
301 /* Get rpc.statd's address on this transport */
302 memset(&hints
, 0, sizeof hints
);
303 hints
.ai_flags
= AI_PASSIVE
;
304 hints
.ai_family
= si
.si_af
;
305 hints
.ai_socktype
= si
.si_socktype
;
306 hints
.ai_protocol
= si
.si_proto
;
309 * Bind to specific IPs if asked to
312 while (nhostsbak
> 0) {
316 * XXX - using RPC library internal functions.
318 if ((fd
= __rpc_nconf2fd(nconf
)) < 0) {
319 syslog(LOG_ERR
, "cannot create socket for %s",
324 switch (hints
.ai_family
) {
326 if (inet_pton(AF_INET
, hosts
[nhostsbak
],
328 hints
.ai_flags
&= AI_NUMERICHOST
;
331 * Skip if we have an AF_INET6 address.
333 if (inet_pton(AF_INET6
, hosts
[nhostsbak
],
341 if (inet_pton(AF_INET6
, hosts
[nhostsbak
],
343 hints
.ai_flags
&= AI_NUMERICHOST
;
346 * Skip if we have an AF_INET address.
348 if (inet_pton(AF_INET
, hosts
[nhostsbak
],
360 * If no hosts were specified, just bind to INADDR_ANY
362 if (strcmp("*", hosts
[nhostsbak
]) == 0) {
363 if (svcport_str
== NULL
) {
364 res
= malloc(sizeof(struct addrinfo
));
367 res
->ai_flags
= hints
.ai_flags
;
368 res
->ai_family
= hints
.ai_family
;
369 res
->ai_protocol
= hints
.ai_protocol
;
370 switch (res
->ai_family
) {
372 sin
= malloc(sizeof(struct sockaddr_in
));
375 sin
->sin_family
= AF_INET
;
376 sin
->sin_port
= htons(0);
377 sin
->sin_addr
.s_addr
= htonl(INADDR_ANY
);
378 res
->ai_addr
= (struct sockaddr
*) sin
;
379 res
->ai_addrlen
= (socklen_t
)
380 sizeof(res
->ai_addr
);
383 sin6
= malloc(sizeof(struct sockaddr_in6
));
386 sin6
->sin6_family
= AF_INET6
;
387 sin6
->sin6_port
= htons(0);
388 sin6
->sin6_addr
= in6addr_any
;
389 res
->ai_addr
= (struct sockaddr
*) sin6
;
390 res
->ai_addrlen
= (socklen_t
) sizeof(res
->ai_addr
);
396 if ((aicode
= getaddrinfo(NULL
, svcport_str
,
397 &hints
, &res
)) != 0) {
399 "cannot get local address for %s: %s",
401 gai_strerror(aicode
));
406 if ((aicode
= getaddrinfo(hosts
[nhostsbak
], svcport_str
,
407 &hints
, &res
)) != 0) {
409 "cannot get local address for %s: %s",
410 nconf
->nc_netid
, gai_strerror(aicode
));
415 r
= bindresvport_sa(fd
, res
->ai_addr
);
417 syslog(LOG_ERR
, "bindresvport_sa: %m");
421 transp
= svc_tli_create(fd
, nconf
, NULL
,
422 RPC_MAXDATASIZE
, RPC_MAXDATASIZE
);
424 if (transp
!= NULL
) {
425 if (!svc_reg(transp
, NLM_PROG
, NLM_SM
, nlm_prog_0
,
428 "can't register %s NLM_PROG, NLM_SM service",
431 if (!svc_reg(transp
, NLM_PROG
, NLM_VERS
, nlm_prog_1
,
434 "can't register %s NLM_PROG, NLM_VERS service",
437 if (!svc_reg(transp
, NLM_PROG
, NLM_VERSX
, nlm_prog_3
,
440 "can't register %s NLM_PROG, NLM_VERSX service",
443 if (!svc_reg(transp
, NLM_PROG
, NLM_VERS4
, nlm_prog_4
,
446 "can't register %s NLM_PROG, NLM_VERS4 service",
450 syslog(LOG_WARNING
, "can't create %s services",
453 if (registered
== 0) {
455 memset(&hints
, 0, sizeof hints
);
456 hints
.ai_flags
= AI_PASSIVE
;
457 hints
.ai_family
= si
.si_af
;
458 hints
.ai_socktype
= si
.si_socktype
;
459 hints
.ai_protocol
= si
.si_proto
;
461 if (svcport_str
== NULL
) {
462 svcport_str
= malloc(NI_MAXSERV
* sizeof(char));
463 if (svcport_str
== NULL
)
466 if (getnameinfo(res
->ai_addr
,
467 res
->ai_addr
->sa_len
, NULL
, NI_MAXHOST
,
468 svcport_str
, NI_MAXSERV
* sizeof(char),
469 NI_NUMERICHOST
| NI_NUMERICSERV
))
470 errx(1, "Cannot get port number");
473 if((aicode
= getaddrinfo(NULL
, svcport_str
, &hints
,
475 syslog(LOG_ERR
, "cannot get local address: %s",
476 gai_strerror(aicode
));
480 servaddr
.buf
= malloc(res
->ai_addrlen
);
481 memcpy(servaddr
.buf
, res
->ai_addr
, res
->ai_addrlen
);
482 servaddr
.len
= res
->ai_addrlen
;
484 rpcb_set(NLM_PROG
, NLM_SM
, nconf
, &servaddr
);
485 rpcb_set(NLM_PROG
, NLM_VERS
, nconf
, &servaddr
);
486 rpcb_set(NLM_PROG
, NLM_VERSX
, nconf
, &servaddr
);
487 rpcb_set(NLM_PROG
, NLM_VERS4
, nconf
, &servaddr
);
496 sigalarm_handler(void)
505 errx(1, "usage: rpc.lockd [-d <debuglevel>]"
506 " [-g <grace period>] [-h <bindip>] [-p <port>]");
510 * Out of memory, fatal
515 syslog(LOG_ERR
, "out of memory");