krpc_subr.c revision 1.4 1 1.1 dholland /* NetBSD: krpc_subr.c,v 1.12.4.1 1996/06/07 00:52:26 cgd Exp */
2 1.1 dholland
3 1.1 dholland /*-
4 1.1 dholland * Copyright (c) 1995 Gordon Ross, Adam Glass
5 1.1 dholland * Copyright (c) 1992 Regents of the University of California.
6 1.1 dholland * All rights reserved.
7 1.1 dholland *
8 1.1 dholland * This software was developed by the Computer Systems Engineering group
9 1.1 dholland * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
10 1.1 dholland * contributed to Berkeley.
11 1.1 dholland *
12 1.1 dholland * Redistribution and use in source and binary forms, with or without
13 1.1 dholland * modification, are permitted provided that the following conditions
14 1.1 dholland * are met:
15 1.1 dholland * 1. Redistributions of source code must retain the above copyright
16 1.1 dholland * notice, this list of conditions and the following disclaimer.
17 1.1 dholland * 2. Redistributions in binary form must reproduce the above copyright
18 1.1 dholland * notice, this list of conditions and the following disclaimer in the
19 1.1 dholland * documentation and/or other materials provided with the distribution.
20 1.1 dholland * 3. All advertising materials mentioning features or use of this software
21 1.1 dholland * must display the following acknowledgement:
22 1.1 dholland * This product includes software developed by the University of
23 1.1 dholland * California, Lawrence Berkeley Laboratory and its contributors.
24 1.1 dholland * 4. Neither the name of the University nor the names of its contributors
25 1.1 dholland * may be used to endorse or promote products derived from this software
26 1.1 dholland * without specific prior written permission.
27 1.1 dholland *
28 1.1 dholland * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 1.1 dholland * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 1.1 dholland * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 1.1 dholland * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 1.1 dholland * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 1.1 dholland * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 1.1 dholland * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 1.1 dholland * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 1.1 dholland * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 1.1 dholland * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 1.1 dholland * SUCH DAMAGE.
39 1.1 dholland *
40 1.1 dholland * partially based on:
41 1.1 dholland * libnetboot/rpc.c
42 1.1 dholland * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL)
43 1.1 dholland */
44 1.1 dholland
45 1.1 dholland #include <sys/cdefs.h>
46 1.1 dholland /* __FBSDID("FreeBSD: head/sys/nfs/krpc_subr.c 248207 2013-03-12 13:42:47Z glebius "); */
47 1.4 ozaki __RCSID("$NetBSD: krpc_subr.c,v 1.4 2016/06/10 13:27:15 ozaki-r Exp $");
48 1.1 dholland
49 1.1 dholland #include <sys/param.h>
50 1.1 dholland #include <sys/systm.h>
51 1.1 dholland #include <sys/jail.h>
52 1.1 dholland #include <sys/malloc.h>
53 1.1 dholland #include <sys/mbuf.h>
54 1.1 dholland #include <sys/proc.h>
55 1.1 dholland #include <sys/socket.h>
56 1.1 dholland #include <sys/socketvar.h>
57 1.1 dholland #include <sys/uio.h>
58 1.1 dholland
59 1.1 dholland #include <net/if.h>
60 1.1 dholland #include <net/vnet.h>
61 1.1 dholland
62 1.1 dholland #include <netinet/in.h>
63 1.1 dholland
64 1.1 dholland #include <rpc/types.h>
65 1.1 dholland #include <rpc/auth.h>
66 1.1 dholland #include <rpc/rpc_msg.h>
67 1.1 dholland #include <nfs/krpc.h>
68 1.1 dholland #include <nfs/xdr_subs.h>
69 1.1 dholland
70 1.1 dholland /*
71 1.1 dholland * Kernel support for Sun RPC
72 1.1 dholland *
73 1.1 dholland * Used currently for bootstrapping in nfs diskless configurations.
74 1.1 dholland */
75 1.1 dholland
76 1.1 dholland /*
77 1.1 dholland * Generic RPC headers
78 1.1 dholland */
79 1.1 dholland
80 1.1 dholland struct auth_info {
81 1.1 dholland u_int32_t authtype; /* auth type */
82 1.1 dholland u_int32_t authlen; /* auth length */
83 1.1 dholland };
84 1.1 dholland
85 1.1 dholland struct auth_unix {
86 1.1 dholland int32_t ua_time;
87 1.1 dholland int32_t ua_hostname; /* null */
88 1.1 dholland int32_t ua_uid;
89 1.1 dholland int32_t ua_gid;
90 1.1 dholland int32_t ua_gidlist; /* null */
91 1.1 dholland };
92 1.1 dholland
93 1.1 dholland struct krpc_call {
94 1.1 dholland u_int32_t rp_xid; /* request transaction id */
95 1.1 dholland int32_t rp_direction; /* call direction (0) */
96 1.1 dholland u_int32_t rp_rpcvers; /* rpc version (2) */
97 1.1 dholland u_int32_t rp_prog; /* program */
98 1.1 dholland u_int32_t rp_vers; /* version */
99 1.1 dholland u_int32_t rp_proc; /* procedure */
100 1.1 dholland struct auth_info rpc_auth;
101 1.1 dholland struct auth_unix rpc_unix;
102 1.1 dholland struct auth_info rpc_verf;
103 1.1 dholland };
104 1.1 dholland
105 1.1 dholland struct krpc_reply {
106 1.1 dholland u_int32_t rp_xid; /* request transaction id */
107 1.1 dholland int32_t rp_direction; /* call direction (1) */
108 1.1 dholland int32_t rp_astatus; /* accept status (0: accepted) */
109 1.1 dholland union {
110 1.1 dholland u_int32_t rpu_errno;
111 1.1 dholland struct {
112 1.1 dholland struct auth_info rok_auth;
113 1.1 dholland u_int32_t rok_status;
114 1.1 dholland } rpu_rok;
115 1.1 dholland } rp_u;
116 1.1 dholland };
117 1.1 dholland #define rp_errno rp_u.rpu_errno
118 1.1 dholland #define rp_auth rp_u.rpu_rok.rok_auth
119 1.1 dholland #define rp_status rp_u.rpu_rok.rok_status
120 1.1 dholland
121 1.1 dholland #define MIN_REPLY_HDR 16 /* xid, dir, astat, errno */
122 1.1 dholland
123 1.1 dholland /*
124 1.1 dholland * What is the longest we will wait before re-sending a request?
125 1.1 dholland * Note this is also the frequency of "RPC timeout" messages.
126 1.1 dholland * The re-send loop count sup linearly to this maximum, so the
127 1.1 dholland * first complaint will happen after (1+2+3+4+5)=15 seconds.
128 1.1 dholland */
129 1.1 dholland #define MAX_RESEND_DELAY 5 /* seconds */
130 1.1 dholland
131 1.1 dholland /*
132 1.1 dholland * Call portmap to lookup a port number for a particular rpc program
133 1.1 dholland * Returns non-zero error on failure.
134 1.1 dholland */
135 1.1 dholland int
136 1.1 dholland krpc_portmap(struct sockaddr_in *sin, u_int prog, u_int vers, u_int16_t *portp,
137 1.1 dholland struct thread *td)
138 1.1 dholland {
139 1.1 dholland struct sdata {
140 1.1 dholland u_int32_t prog; /* call program */
141 1.1 dholland u_int32_t vers; /* call version */
142 1.1 dholland u_int32_t proto; /* call protocol */
143 1.1 dholland u_int32_t port; /* call port (unused) */
144 1.1 dholland } *sdata;
145 1.1 dholland struct rdata {
146 1.1 dholland u_int16_t pad;
147 1.1 dholland u_int16_t port;
148 1.1 dholland } *rdata;
149 1.1 dholland struct mbuf *m;
150 1.1 dholland int error;
151 1.1 dholland
152 1.1 dholland /* The portmapper port is fixed. */
153 1.1 dholland if (prog == PMAPPROG) {
154 1.1 dholland *portp = htons(PMAPPORT);
155 1.1 dholland return 0;
156 1.1 dholland }
157 1.1 dholland
158 1.1 dholland m = m_get(M_WAITOK, MT_DATA);
159 1.1 dholland sdata = mtod(m, struct sdata *);
160 1.1 dholland m->m_len = sizeof(*sdata);
161 1.1 dholland
162 1.1 dholland /* Do the RPC to get it. */
163 1.1 dholland sdata->prog = txdr_unsigned(prog);
164 1.1 dholland sdata->vers = txdr_unsigned(vers);
165 1.1 dholland sdata->proto = txdr_unsigned(IPPROTO_UDP);
166 1.1 dholland sdata->port = 0;
167 1.1 dholland
168 1.1 dholland sin->sin_port = htons(PMAPPORT);
169 1.1 dholland error = krpc_call(sin, PMAPPROG, PMAPVERS,
170 1.1 dholland PMAPPROC_GETPORT, &m, NULL, td);
171 1.1 dholland if (error)
172 1.2 christos goto out;
173 1.1 dholland
174 1.1 dholland if (m->m_len < sizeof(*rdata)) {
175 1.1 dholland m = m_pullup(m, sizeof(*rdata));
176 1.1 dholland if (m == NULL)
177 1.1 dholland return ENOBUFS;
178 1.1 dholland }
179 1.1 dholland rdata = mtod(m, struct rdata *);
180 1.1 dholland *portp = rdata->port;
181 1.1 dholland
182 1.2 christos out:
183 1.1 dholland m_freem(m);
184 1.2 christos return error;
185 1.1 dholland }
186 1.1 dholland
187 1.1 dholland /*
188 1.1 dholland * Do a remote procedure call (RPC) and wait for its reply.
189 1.1 dholland * If from_p is non-null, then we are doing broadcast, and
190 1.1 dholland * the address from whence the response came is saved there.
191 1.1 dholland */
192 1.1 dholland int
193 1.1 dholland krpc_call(struct sockaddr_in *sa, u_int prog, u_int vers, u_int func,
194 1.1 dholland struct mbuf **data, struct sockaddr **from_p, struct thread *td)
195 1.1 dholland {
196 1.1 dholland struct socket *so;
197 1.1 dholland struct sockaddr_in *sin, ssin;
198 1.1 dholland struct sockaddr *from;
199 1.1 dholland struct mbuf *m, *nam, *mhead;
200 1.1 dholland struct krpc_call *call;
201 1.1 dholland struct krpc_reply *reply;
202 1.1 dholland struct sockopt sopt;
203 1.1 dholland struct timeval tv;
204 1.1 dholland struct uio auio;
205 1.1 dholland int error, rcvflg, timo, secs, len;
206 1.1 dholland static u_int32_t xid = ~0xFF;
207 1.1 dholland u_int16_t tport;
208 1.1 dholland u_int32_t saddr;
209 1.1 dholland
210 1.1 dholland /*
211 1.1 dholland * Validate address family.
212 1.1 dholland * Sorry, this is INET specific...
213 1.1 dholland */
214 1.1 dholland if (sa->sin_family != AF_INET)
215 1.1 dholland return (EAFNOSUPPORT);
216 1.1 dholland
217 1.1 dholland /* Free at end if not null. */
218 1.1 dholland nam = mhead = NULL;
219 1.1 dholland from = NULL;
220 1.1 dholland
221 1.1 dholland /*
222 1.1 dholland * Create socket and set its recieve timeout.
223 1.1 dholland */
224 1.1 dholland if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0, td->td_ucred, td)))
225 1.1 dholland goto out;
226 1.1 dholland
227 1.1 dholland tv.tv_sec = 1;
228 1.1 dholland tv.tv_usec = 0;
229 1.1 dholland bzero(&sopt, sizeof sopt);
230 1.1 dholland sopt.sopt_dir = SOPT_SET;
231 1.1 dholland sopt.sopt_level = SOL_SOCKET;
232 1.1 dholland sopt.sopt_name = SO_RCVTIMEO;
233 1.1 dholland sopt.sopt_val = &tv;
234 1.1 dholland sopt.sopt_valsize = sizeof tv;
235 1.1 dholland
236 1.1 dholland if ((error = sosetopt(so, &sopt)) != 0)
237 1.1 dholland goto out;
238 1.1 dholland
239 1.1 dholland /*
240 1.1 dholland * Enable broadcast if necessary.
241 1.1 dholland */
242 1.1 dholland if (from_p) {
243 1.1 dholland int on = 1;
244 1.1 dholland sopt.sopt_name = SO_BROADCAST;
245 1.1 dholland sopt.sopt_val = &on;
246 1.1 dholland sopt.sopt_valsize = sizeof on;
247 1.1 dholland if ((error = sosetopt(so, &sopt)) != 0)
248 1.1 dholland goto out;
249 1.1 dholland }
250 1.1 dholland
251 1.1 dholland /*
252 1.1 dholland * Bind the local endpoint to a reserved port,
253 1.1 dholland * because some NFS servers refuse requests from
254 1.1 dholland * non-reserved (non-privileged) ports.
255 1.1 dholland */
256 1.1 dholland sin = &ssin;
257 1.1 dholland bzero(sin, sizeof *sin);
258 1.1 dholland sin->sin_len = sizeof(*sin);
259 1.1 dholland sin->sin_family = AF_INET;
260 1.1 dholland sin->sin_addr.s_addr = INADDR_ANY;
261 1.1 dholland tport = IPPORT_RESERVED;
262 1.1 dholland do {
263 1.1 dholland tport--;
264 1.1 dholland sin->sin_port = htons(tport);
265 1.1 dholland error = sobind(so, (struct sockaddr *)sin, td);
266 1.1 dholland } while (error == EADDRINUSE &&
267 1.1 dholland tport > IPPORT_RESERVED / 2);
268 1.1 dholland if (error) {
269 1.1 dholland printf("bind failed\n");
270 1.1 dholland goto out;
271 1.1 dholland }
272 1.1 dholland
273 1.1 dholland /*
274 1.1 dholland * Setup socket address for the server.
275 1.1 dholland */
276 1.1 dholland
277 1.1 dholland /*
278 1.1 dholland * Prepend RPC message header.
279 1.1 dholland */
280 1.1 dholland mhead = m_gethdr(M_WAITOK, MT_DATA);
281 1.1 dholland mhead->m_next = *data;
282 1.3 mlelstv *data = NULL;
283 1.1 dholland call = mtod(mhead, struct krpc_call *);
284 1.1 dholland mhead->m_len = sizeof(*call);
285 1.1 dholland bzero((caddr_t)call, sizeof(*call));
286 1.1 dholland /* rpc_call part */
287 1.1 dholland xid++;
288 1.1 dholland call->rp_xid = txdr_unsigned(xid);
289 1.1 dholland /* call->rp_direction = 0; */
290 1.1 dholland call->rp_rpcvers = txdr_unsigned(2);
291 1.1 dholland call->rp_prog = txdr_unsigned(prog);
292 1.1 dholland call->rp_vers = txdr_unsigned(vers);
293 1.1 dholland call->rp_proc = txdr_unsigned(func);
294 1.1 dholland /* rpc_auth part (auth_unix as root) */
295 1.1 dholland call->rpc_auth.authtype = txdr_unsigned(AUTH_UNIX);
296 1.1 dholland call->rpc_auth.authlen = txdr_unsigned(sizeof(struct auth_unix));
297 1.1 dholland /* rpc_verf part (auth_null) */
298 1.1 dholland call->rpc_verf.authtype = 0;
299 1.1 dholland call->rpc_verf.authlen = 0;
300 1.1 dholland
301 1.1 dholland /*
302 1.1 dholland * Setup packet header
303 1.1 dholland */
304 1.1 dholland m_fixhdr(mhead);
305 1.4 ozaki m_reset_rcvif(mhead);
306 1.1 dholland
307 1.1 dholland /*
308 1.1 dholland * Send it, repeatedly, until a reply is received,
309 1.1 dholland * but delay each re-send by an increasing amount.
310 1.1 dholland * If the delay hits the maximum, start complaining.
311 1.1 dholland */
312 1.1 dholland timo = 0;
313 1.1 dholland for (;;) {
314 1.1 dholland /* Send RPC request (or re-send). */
315 1.1 dholland m = m_copym(mhead, 0, M_COPYALL, M_WAITOK);
316 1.1 dholland error = sosend(so, (struct sockaddr *)sa, NULL, m,
317 1.1 dholland NULL, 0, td);
318 1.1 dholland if (error) {
319 1.1 dholland printf("krpc_call: sosend: %d\n", error);
320 1.1 dholland goto out;
321 1.1 dholland }
322 1.1 dholland m = NULL;
323 1.1 dholland
324 1.1 dholland /* Determine new timeout. */
325 1.1 dholland if (timo < MAX_RESEND_DELAY)
326 1.1 dholland timo++;
327 1.1 dholland else {
328 1.1 dholland saddr = ntohl(sa->sin_addr.s_addr);
329 1.1 dholland printf("RPC timeout for server %d.%d.%d.%d\n",
330 1.1 dholland (saddr >> 24) & 255,
331 1.1 dholland (saddr >> 16) & 255,
332 1.1 dholland (saddr >> 8) & 255,
333 1.1 dholland saddr & 255);
334 1.1 dholland }
335 1.1 dholland
336 1.1 dholland /*
337 1.1 dholland * Wait for up to timo seconds for a reply.
338 1.1 dholland * The socket receive timeout was set to 1 second.
339 1.1 dholland */
340 1.1 dholland secs = timo;
341 1.1 dholland while (secs > 0) {
342 1.1 dholland if (from) {
343 1.1 dholland free(from, M_SONAME);
344 1.1 dholland from = NULL;
345 1.1 dholland }
346 1.1 dholland if (m) {
347 1.1 dholland m_freem(m);
348 1.1 dholland m = NULL;
349 1.1 dholland }
350 1.1 dholland bzero(&auio, sizeof(auio));
351 1.1 dholland auio.uio_resid = len = 1<<16;
352 1.1 dholland rcvflg = 0;
353 1.1 dholland error = soreceive(so, &from, &auio, &m, NULL, &rcvflg);
354 1.1 dholland if (error == EWOULDBLOCK) {
355 1.1 dholland secs--;
356 1.1 dholland continue;
357 1.1 dholland }
358 1.1 dholland if (error)
359 1.1 dholland goto out;
360 1.1 dholland len -= auio.uio_resid;
361 1.1 dholland
362 1.1 dholland /* Does the reply contain at least a header? */
363 1.1 dholland if (len < MIN_REPLY_HDR)
364 1.1 dholland continue;
365 1.1 dholland if (m->m_len < MIN_REPLY_HDR)
366 1.1 dholland continue;
367 1.1 dholland reply = mtod(m, struct krpc_reply *);
368 1.1 dholland
369 1.1 dholland /* Is it the right reply? */
370 1.1 dholland if (reply->rp_direction != txdr_unsigned(REPLY))
371 1.1 dholland continue;
372 1.1 dholland
373 1.1 dholland if (reply->rp_xid != txdr_unsigned(xid))
374 1.1 dholland continue;
375 1.1 dholland
376 1.1 dholland /* Was RPC accepted? (authorization OK) */
377 1.1 dholland if (reply->rp_astatus != 0) {
378 1.1 dholland error = fxdr_unsigned(u_int32_t, reply->rp_errno);
379 1.1 dholland printf("rpc denied, error=%d\n", error);
380 1.1 dholland continue;
381 1.1 dholland }
382 1.1 dholland
383 1.1 dholland /* Did the call succeed? */
384 1.1 dholland if (reply->rp_status != 0) {
385 1.1 dholland error = fxdr_unsigned(u_int32_t, reply->rp_status);
386 1.1 dholland if (error == PROG_MISMATCH) {
387 1.1 dholland error = EBADRPC;
388 1.1 dholland goto out;
389 1.1 dholland }
390 1.1 dholland printf("rpc denied, status=%d\n", error);
391 1.1 dholland continue;
392 1.1 dholland }
393 1.1 dholland
394 1.1 dholland goto gotreply; /* break two levels */
395 1.1 dholland
396 1.1 dholland } /* while secs */
397 1.1 dholland } /* forever send/receive */
398 1.1 dholland
399 1.1 dholland error = ETIMEDOUT;
400 1.1 dholland goto out;
401 1.1 dholland
402 1.1 dholland gotreply:
403 1.1 dholland
404 1.1 dholland /*
405 1.1 dholland * Get RPC reply header into first mbuf,
406 1.1 dholland * get its length, then strip it off.
407 1.1 dholland */
408 1.1 dholland len = sizeof(*reply);
409 1.1 dholland if (m->m_len < len) {
410 1.1 dholland m = m_pullup(m, len);
411 1.1 dholland if (m == NULL) {
412 1.1 dholland error = ENOBUFS;
413 1.1 dholland goto out;
414 1.1 dholland }
415 1.1 dholland }
416 1.1 dholland reply = mtod(m, struct krpc_reply *);
417 1.1 dholland if (reply->rp_auth.authtype != 0) {
418 1.1 dholland len += fxdr_unsigned(u_int32_t, reply->rp_auth.authlen);
419 1.1 dholland len = (len + 3) & ~3; /* XXX? */
420 1.1 dholland }
421 1.1 dholland m_adj(m, len);
422 1.1 dholland
423 1.1 dholland /* result */
424 1.1 dholland *data = m;
425 1.1 dholland if (from_p) {
426 1.1 dholland *from_p = from;
427 1.1 dholland from = NULL;
428 1.1 dholland }
429 1.1 dholland
430 1.1 dholland out:
431 1.1 dholland if (mhead) m_freem(mhead);
432 1.1 dholland if (from) free(from, M_SONAME);
433 1.1 dholland soclose(so);
434 1.1 dholland return error;
435 1.1 dholland }
436 1.1 dholland
437 1.1 dholland /*
438 1.1 dholland * eXternal Data Representation routines.
439 1.1 dholland * (but with non-standard args...)
440 1.1 dholland */
441 1.1 dholland
442 1.1 dholland /*
443 1.1 dholland * String representation for RPC.
444 1.1 dholland */
445 1.1 dholland struct xdr_string {
446 1.1 dholland u_int32_t len; /* length without null or padding */
447 1.1 dholland char data[4]; /* data (longer, of course) */
448 1.1 dholland /* data is padded to a long-word boundary */
449 1.1 dholland };
450 1.1 dholland
451 1.1 dholland struct mbuf *
452 1.1 dholland xdr_string_encode(char *str, int len)
453 1.1 dholland {
454 1.1 dholland struct mbuf *m;
455 1.1 dholland struct xdr_string *xs;
456 1.1 dholland int dlen; /* padded string length */
457 1.1 dholland int mlen; /* message length */
458 1.1 dholland
459 1.1 dholland dlen = (len + 3) & ~3;
460 1.1 dholland mlen = dlen + 4;
461 1.1 dholland
462 1.1 dholland if (mlen > MCLBYTES) /* If too big, we just can't do it. */
463 1.1 dholland return (NULL);
464 1.1 dholland
465 1.1 dholland m = m_get2(mlen, M_WAITOK, MT_DATA, 0);
466 1.1 dholland xs = mtod(m, struct xdr_string *);
467 1.1 dholland m->m_len = mlen;
468 1.1 dholland xs->len = txdr_unsigned(len);
469 1.1 dholland bcopy(str, xs->data, len);
470 1.1 dholland return (m);
471 1.1 dholland }
472