]> git.decadent.org.uk Git - nfs-utils.git/blob - support/nsm/rpc.c
Merge branch 'sid'
[nfs-utils.git] / support / nsm / rpc.c
1 /*
2  * Copyright 2009 Oracle.  All rights reserved.
3  *
4  * This file is part of nfs-utils.
5  *
6  * nfs-utils is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * nfs-utils is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with nfs-utils.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 /*
21  * NSM for Linux.
22  *
23  * Instead of using ONC or TI RPC library calls, statd constructs
24  * RPC calls directly in socket buffers.  This allows a single
25  * socket to be concurrently shared among several different RPC
26  * programs and versions using a simple RPC request dispatcher.
27  *
28  * This file contains the details of RPC header and call
29  * construction and reply parsing, and a method for creating a
30  * socket for use with these functions.
31  */
32
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif  /* HAVE_CONFIG_H */
36
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <sys/time.h>
40
41 #include <time.h>
42 #include <stdbool.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <fcntl.h>
46
47 #include <netinet/in.h>
48 #include <net/if.h>
49 #include <arpa/inet.h>
50 #include <netdb.h>
51
52 #include <rpc/rpc.h>
53 #include <rpc/pmap_prot.h>
54 #include <rpc/pmap_rmt.h>
55
56 #ifdef HAVE_LIBTIRPC
57 #include <netconfig.h>
58 #include <rpc/rpcb_prot.h>
59 #endif  /* HAVE_LIBTIRPC */
60
61 #include "xlog.h"
62 #include "nfsrpc.h"
63 #include "nsm.h"
64 #include "sm_inter.h"
65
66 /*
67  * Returns a fresh XID appropriate for RPC over UDP -- never zero.
68  */
69 static uint32_t
70 nsm_next_xid(void)
71 {
72         static uint32_t nsm_xid = 0;
73         struct timeval now;
74
75         if (nsm_xid == 0) {
76                 (void)gettimeofday(&now, NULL);
77                 nsm_xid = (uint32_t)getpid() ^
78                                 (uint32_t)now.tv_sec ^ (uint32_t)now.tv_usec;
79         }
80
81         return nsm_xid++;
82 }
83
84 /*
85  * Select a fresh XID and construct an RPC header in @mesg.
86  * Always use AUTH_NULL credentials and verifiers.
87  *
88  * Returns the new XID.
89  */
90 static uint32_t
91 nsm_init_rpc_header(const rpcprog_t program, const rpcvers_t version,
92                         const rpcproc_t procedure, struct rpc_msg *mesg)
93 {
94         struct call_body *cb = &mesg->rm_call;
95         uint32_t xid = nsm_next_xid();
96
97         memset(mesg, 0, sizeof(*mesg));
98
99         mesg->rm_xid = (unsigned long)xid;
100         mesg->rm_direction = CALL;
101
102         cb->cb_rpcvers = RPC_MSG_VERSION;
103         cb->cb_prog = program;
104         cb->cb_vers = version;
105         cb->cb_proc = procedure;
106
107         cb->cb_cred.oa_flavor = AUTH_NULL;
108         cb->cb_cred.oa_base = (caddr_t) NULL;
109         cb->cb_cred.oa_length = 0;
110         cb->cb_verf.oa_flavor = AUTH_NULL;
111         cb->cb_verf.oa_base = (caddr_t) NULL;
112         cb->cb_verf.oa_length = 0;
113
114         return xid;
115 }
116
117 /*
118  * Initialize the network send buffer and XDR memory for encoding.
119  */
120 static void
121 nsm_init_xdrmem(char *msgbuf, const unsigned int msgbuflen,
122                 XDR *xdrp)
123 {
124         memset(msgbuf, 0, (size_t)msgbuflen);
125         memset(xdrp, 0, sizeof(*xdrp));
126         xdrmem_create(xdrp, msgbuf, msgbuflen, XDR_ENCODE);
127 }
128
129 /*
130  * Send a completed RPC call on a socket.
131  *
132  * Returns true if all the bytes were sent successfully; otherwise
133  * false if any error occurred.
134  */
135 static _Bool
136 nsm_rpc_sendto(const int sock, const struct sockaddr *sap,
137                         const socklen_t salen, XDR *xdrs, void *buf)
138 {
139         const size_t buflen = (size_t)xdr_getpos(xdrs);
140         ssize_t err;
141
142         err = sendto(sock, buf, buflen, 0, sap, salen);
143         if ((err < 0) || ((size_t)err != buflen)) {
144                 xlog(L_ERROR, "%s: sendto failed: %m", __func__);
145                 return false;
146         }
147         return true;
148 }
149
150 /**
151  * nsm_xmit_getport - post a PMAP_GETPORT call on a socket descriptor
152  * @sock: datagram socket descriptor
153  * @sin: pointer to AF_INET socket address of server
154  * @program: RPC program number to query
155  * @version: RPC version number to query
156  *
157  * Send a PMAP_GETPORT call to the portmap daemon at @sin using
158  * socket descriptor @sock.  This request queries the RPC program
159  * [program, version, IPPROTO_UDP].
160  *
161  * NB: PMAP_GETPORT works only for IPv4 hosts.  This implementation
162  *     works only over UDP, and queries only UDP registrations.
163  *
164  * Returns the XID of the call, or zero if an error occurred.
165  */
166 uint32_t
167 nsm_xmit_getport(const int sock, const struct sockaddr_in *sin,
168                         const unsigned long program,
169                         const unsigned long version)
170 {
171         char msgbuf[NSM_MAXMSGSIZE];
172         struct sockaddr_in addr;
173         struct rpc_msg mesg;
174         _Bool sent = false;
175         struct pmap parms = {
176                 .pm_prog        = program,
177                 .pm_vers        = version,
178                 .pm_prot        = (unsigned long)IPPROTO_UDP,
179         };
180         uint32_t xid;
181         XDR xdr;
182
183         xlog(D_CALL, "Sending PMAP_GETPORT for %u, %u, udp", program, version);
184
185         nsm_init_xdrmem(msgbuf, NSM_MAXMSGSIZE, &xdr);
186         xid = nsm_init_rpc_header(PMAPPROG, PMAPVERS,
187                                         (rpcproc_t)PMAPPROC_GETPORT, &mesg);
188
189         addr = *sin;
190         addr.sin_port = htons(PMAPPORT);
191
192         if (xdr_callmsg(&xdr, &mesg) == TRUE &&
193             xdr_pmap(&xdr, &parms) == TRUE)
194                 sent = nsm_rpc_sendto(sock, (struct sockaddr *)(char *)&addr,
195                                         (socklen_t)sizeof(addr), &xdr, msgbuf);
196         else
197                 xlog(L_ERROR, "%s: can't encode PMAP_GETPORT call", __func__);
198
199         xdr_destroy(&xdr);
200
201         if (sent == false)
202                 return 0;
203         return xid;
204 }
205
206 /**
207  * nsm_xmit_getaddr - post an RPCB_GETADDR call on a socket descriptor
208  * @sock: datagram socket descriptor
209  * @sin: pointer to AF_INET6 socket address of server
210  * @program: RPC program number to query
211  * @version: RPC version number to query
212  *
213  * Send an RPCB_GETADDR call to the rpcbind daemon at @sap using
214  * socket descriptor @sock.  This request queries the RPC program
215  * [program, version, "udp6"].
216  *
217  * NB: RPCB_GETADDR works for both IPv4 and IPv6 hosts.  This
218  *     implementation works only over UDP and AF_INET6, and queries
219  *     only "udp6" registrations.
220  *
221  * Returns the XID of the call, or zero if an error occurred.
222  */
223 #ifdef HAVE_LIBTIRPC
224 uint32_t
225 nsm_xmit_getaddr(const int sock, const struct sockaddr_in6 *sin6,
226                         const rpcprog_t program, const rpcvers_t version)
227 {
228         char msgbuf[NSM_MAXMSGSIZE];
229         struct sockaddr_in6 addr;
230         struct rpc_msg mesg;
231         _Bool sent = false;
232         struct rpcb parms = {
233                 .r_prog         = program,
234                 .r_vers         = version,
235                 .r_netid        = "udp6",
236                 .r_owner        = "",
237         };
238         uint32_t xid;
239         XDR xdr;
240
241         xlog(D_CALL, "Sending RPCB_GETADDR for %u, %u, udp6", program, version);
242
243         nsm_init_xdrmem(msgbuf, NSM_MAXMSGSIZE, &xdr);
244         xid = nsm_init_rpc_header(RPCBPROG, RPCBVERS,
245                                         (rpcproc_t)RPCBPROC_GETADDR, &mesg);
246
247         addr = *sin6;
248         addr.sin6_port = htons(PMAPPORT);
249         parms.r_addr = nfs_sockaddr2universal((struct sockaddr *)(char *)&addr);
250         if (parms.r_addr == NULL) {
251                 xlog(L_ERROR, "%s: can't encode socket address", __func__);
252                 return 0;
253         }
254
255         if (xdr_callmsg(&xdr, &mesg) == TRUE &&
256             xdr_rpcb(&xdr, &parms) == TRUE)
257                 sent = nsm_rpc_sendto(sock, (struct sockaddr *)(char *)&addr,
258                                         (socklen_t)sizeof(addr), &xdr, msgbuf);
259         else
260                 xlog(L_ERROR, "%s: can't encode RPCB_GETADDR call", __func__);
261
262         xdr_destroy(&xdr);
263         free(parms.r_addr);
264
265         if (sent == false)
266                 return 0;
267         return xid;
268 }
269 #else   /* !HAVE_LIBTIRPC */
270 uint32_t
271 nsm_xmit_getaddr(const int sock __attribute__((unused)),
272                         const struct sockaddr_in6 *sin6 __attribute__((unused)),
273                         const rpcprog_t program __attribute__((unused)),
274                         const rpcvers_t version __attribute__((unused)))
275 {
276         return 0;
277 }
278 #endif  /* !HAVE_LIBTIRPC */
279
280 /**
281  * nsm_xmit_rpcbind - post an rpcbind request
282  * @sock: datagram socket descriptor
283  * @sap: pointer to socket address of server
284  * @program: RPC program number to query
285  * @version: RPC version number to query
286  *
287  * Send an rpcbind query to the rpcbind daemon at @sap using
288  * socket descriptor @sock.
289  *
290  * NB: This implementation works only over UDP, but can query IPv4 or IPv6
291  *     hosts.  It queries only UDP registrations.
292  *
293  * Returns the XID of the call, or zero if an error occurred.
294  */
295 uint32_t
296 nsm_xmit_rpcbind(const int sock, const struct sockaddr *sap,
297                         const rpcprog_t program, const rpcvers_t version)
298 {
299         switch (sap->sa_family) {
300         case AF_INET:
301                 return nsm_xmit_getport(sock, (const struct sockaddr_in *)sap,
302                                                 program, version);
303         case AF_INET6:
304                 return nsm_xmit_getaddr(sock, (const struct sockaddr_in6 *)sap,
305                                                 program, version);
306         }
307         return 0;
308 }
309
310 /**
311  * nsm_xmit_notify - post an NSMPROC_NOTIFY call on a socket descriptor
312  * @sock: datagram socket descriptor
313  * @sap: pointer to socket address of peer to notify (port already filled in)
314  * @salen: length of socket address
315  * @program: RPC program number to use
316  * @mon_name: mon_name of local peer (ie the rebooting system)
317  * @state: state of local peer
318  *
319  * Send an NSMPROC_NOTIFY call to the peer at @sap using socket descriptor @sock.
320  * This request notifies the peer that we have rebooted.
321  *
322  * NB: This implementation works only over UDP, but supports both AF_INET
323  *     and AF_INET6.
324  *
325  * Returns the XID of the call, or zero if an error occurred.
326  */
327 uint32_t
328 nsm_xmit_notify(const int sock, const struct sockaddr *sap,
329                         const socklen_t salen, const rpcprog_t program,
330                         const char *mon_name, const int state)
331 {
332         char msgbuf[NSM_MAXMSGSIZE];
333         struct stat_chge state_change;
334         struct rpc_msg mesg;
335         _Bool sent = false;
336         uint32_t xid;
337         XDR xdr;
338
339         state_change.mon_name = strdup(mon_name);
340         if (state_change.mon_name == NULL) {
341                 xlog(L_ERROR, "%s: no memory", __func__);
342                 return 0;
343         }
344         state_change.state = state;
345
346         xlog(D_CALL, "Sending SM_NOTIFY for %s", mon_name);
347
348         nsm_init_xdrmem(msgbuf, NSM_MAXMSGSIZE, &xdr);
349         xid = nsm_init_rpc_header(program, SM_VERS, SM_NOTIFY, &mesg);
350
351         if (xdr_callmsg(&xdr, &mesg) == TRUE &&
352             xdr_stat_chge(&xdr, &state_change) == TRUE)
353                 sent = nsm_rpc_sendto(sock, sap, salen, &xdr, msgbuf);
354         else
355                 xlog(L_ERROR, "%s: can't encode NSMPROC_NOTIFY call",
356                                 __func__);
357
358         xdr_destroy(&xdr);
359         free(state_change.mon_name);
360
361         if (sent == false)
362                 return 0;
363         return xid;
364 }
365
366 /**
367  * nsm_xmit_nlmcall - post an unnamed call to local NLM on a socket descriptor
368  * @sock: datagram socket descriptor
369  * @sap: address/port of NLM service to contact
370  * @salen: size of @sap
371  * @m: callback data defining RPC call to make
372  * @state: state of rebooting host
373  *
374  * Send an unnamed call (previously requested via NSMPROC_MON) to the
375  * specified local UDP-based RPC service using socket descriptor @sock.
376  *
377  * NB: This implementation works only over UDP, but supports both AF_INET
378  *     and AF_INET6.
379  *
380  * Returns the XID of the call, or zero if an error occurred.
381  */
382 uint32_t
383 nsm_xmit_nlmcall(const int sock, const struct sockaddr *sap,
384                         const socklen_t salen, const struct mon *m,
385                         const int state)
386 {
387         const struct my_id *id = &m->mon_id.my_id;
388         char msgbuf[NSM_MAXMSGSIZE];
389         struct status new_status;
390         struct rpc_msg mesg;
391         _Bool sent = false;
392         uint32_t xid;
393         XDR xdr;
394
395         xlog(D_CALL, "Sending NLM downcall for %s", m->mon_id.mon_name);
396
397         nsm_init_xdrmem(msgbuf, NSM_MAXMSGSIZE, &xdr);
398         xid = nsm_init_rpc_header((rpcprog_t)id->my_prog,
399                                         (rpcvers_t)id->my_vers,
400                                         (rpcproc_t)id->my_proc, &mesg);
401
402         new_status.mon_name = m->mon_id.mon_name;
403         new_status.state = state;
404         memcpy(&new_status.priv, &m->priv, sizeof(new_status.priv));
405
406         if (xdr_callmsg(&xdr, &mesg) == TRUE &&
407             xdr_status(&xdr, &new_status) == TRUE)
408                 sent = nsm_rpc_sendto(sock, sap, salen, &xdr, msgbuf);
409         else
410                 xlog(L_ERROR, "%s: can't encode NLM downcall", __func__);
411
412         xdr_destroy(&xdr);
413
414         if (sent == false)
415                 return 0;
416         return xid;
417 }
418
419 /**
420  * nsm_parse_reply - parse and validate the header in an RPC reply
421  * @xdrs: pointer to XDR
422  *
423  * Returns the XID of the reply, or zero if an error occurred.
424  */
425 uint32_t
426 nsm_parse_reply(XDR *xdrs)
427 {
428         struct rpc_msg mesg = {
429                 .rm_reply.rp_acpt.ar_results.proc       = (xdrproc_t)xdr_void,
430         };
431         uint32_t xid;
432
433         if (xdr_replymsg(xdrs, &mesg) == FALSE) {
434                 xlog(L_ERROR, "%s: can't decode RPC reply", __func__);
435                 return 0;
436         }
437         xid = (uint32_t)mesg.rm_xid;
438
439         if (mesg.rm_reply.rp_stat != MSG_ACCEPTED) {
440                 xlog(L_ERROR, "%s: [0x%x] RPC status %d",
441                         __func__, xid, mesg.rm_reply.rp_stat);
442                 return 0;
443         }
444
445         if (mesg.rm_reply.rp_acpt.ar_stat != SUCCESS) {
446                 xlog(L_ERROR, "%s: [0x%x] RPC accept status %d",
447                         __func__, xid, mesg.rm_reply.rp_acpt.ar_stat);
448                 return 0;
449         }
450
451         return xid;
452 }
453
454 /**
455  * nsm_recv_getport - parse PMAP_GETPORT reply
456  * @xdrs: pointer to XDR
457  *
458  * Returns the port number from the RPC reply, or zero
459  * if an error occurred.
460  */
461 unsigned long
462 nsm_recv_getport(XDR *xdrs)
463 {
464         unsigned long port = 0;
465
466         if (xdr_u_long(xdrs, &port) == FALSE)
467                 xlog(L_ERROR, "%s: can't decode pmap reply",
468                         __func__);
469         if (port > UINT16_MAX) {
470                 xlog(L_ERROR, "%s: bad port number",
471                         __func__);
472                 port = 0;
473         }
474
475         xlog(D_CALL, "Received PMAP_GETPORT result: %lu", port);
476         return port;
477 }
478
479 /**
480  * nsm_recv_getaddr - parse RPCB_GETADDR reply
481  * @xdrs: pointer to XDR
482  *
483  * Returns the port number from the RPC reply, or zero
484  * if an error occurred.
485  */
486 uint16_t
487 nsm_recv_getaddr(XDR *xdrs)
488 {
489         char *uaddr = NULL;
490         int port;
491
492         if (xdr_wrapstring(xdrs, &uaddr) == FALSE)
493                 xlog(L_ERROR, "%s: can't decode rpcb reply",
494                         __func__);
495
496         if ((uaddr == NULL) || (uaddr[0] == '\0')) {
497                 xlog(D_CALL, "Received RPCB_GETADDR result: "
498                                 "program not registered");
499                 return 0;
500         }
501
502         port = nfs_universal2port(uaddr);
503
504         xdr_free((xdrproc_t)xdr_wrapstring, (char *)&uaddr);
505
506         if (port < 0 || port > UINT16_MAX) {
507                 xlog(L_ERROR, "%s: bad port number",
508                         __func__);
509                 return 0;
510         }
511
512         xlog(D_CALL, "Received RPCB_GETADDR result: %d", port);
513         return (uint16_t)port;
514 }
515
516 /**
517  * nsm_recv_rpcbind - parse rpcbind reply
518  * @af: address family of reply
519  * @xdrs: pointer to XDR
520  *
521  * Returns the port number from the RPC reply, or zero
522  * if an error occurred.
523  */
524 uint16_t
525 nsm_recv_rpcbind(const sa_family_t family, XDR *xdrs)
526 {
527         switch (family) {
528         case AF_INET:
529                 return (uint16_t)nsm_recv_getport(xdrs);
530         case AF_INET6:
531                 return nsm_recv_getaddr(xdrs);
532         }
533         return 0;
534 }