~ubuntu-branches/debian/stretch/nfs-utils/stretch

« back to all changes in this revision

Viewing changes to support/nsm/rpc.c

  • Committer: Bazaar Package Importer
  • Author(s): Anibal Monsalve Salazar, Anibal Monsalve Salazar, Ben Hutchings
  • Date: 2010-04-06 16:11:22 UTC
  • mfrom: (1.2.18 upstream)
  • Revision ID: james.westby@ubuntu.com-20100406161122-x7erw0q8xiitoyp6
Tags: 1:1.2.2-1
[ Anibal Monsalve Salazar ]
* New upstream release 
  Build depend on libcap-dev
  Set configure option --enable-nfsv41
* X-ref nfsd({7,8})
  02-524255-manpages.patch by Cyril Brulebois
  Closes: 524255

[ Ben Hutchings ]
* Change maintainer to Debian kernel team; move Aníbal to uploaders and
  add myself to uploaders
* Check for nfsd in /proc/filesystems rather than looking for signs of it in
  /proc/kallsyms (Closes: #563104, #572736)
* Document the -n option to svcgssd, thanks to Alberto Gonzalez Iniesta
  (Closes: #451402, #550270)
* Replace upstream reference in package descriptions with Homepage fields,
  and do not refer to the obsolete CVS repository
* Update policy version to 3.8.4; no changes required
* Override lintian error 'init.d-script-missing-dependency-on-remote_fs';
  the init script does work without /usr mounted

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}