rpc.c revision 1.30 1 1.30 christos /* $NetBSD: rpc.c,v 1.30 2019/03/31 20:08:45 christos Exp $ */
2 1.2 cgd
3 1.1 brezak /*
4 1.1 brezak * Copyright (c) 1992 Regents of the University of California.
5 1.1 brezak * All rights reserved.
6 1.1 brezak *
7 1.1 brezak * This software was developed by the Computer Systems Engineering group
8 1.1 brezak * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9 1.1 brezak * contributed to Berkeley.
10 1.1 brezak *
11 1.1 brezak * Redistribution and use in source and binary forms, with or without
12 1.1 brezak * modification, are permitted provided that the following conditions
13 1.1 brezak * are met:
14 1.1 brezak * 1. Redistributions of source code must retain the above copyright
15 1.1 brezak * notice, this list of conditions and the following disclaimer.
16 1.1 brezak * 2. Redistributions in binary form must reproduce the above copyright
17 1.1 brezak * notice, this list of conditions and the following disclaimer in the
18 1.1 brezak * documentation and/or other materials provided with the distribution.
19 1.1 brezak * 3. All advertising materials mentioning features or use of this software
20 1.1 brezak * must display the following acknowledgement:
21 1.1 brezak * This product includes software developed by the University of
22 1.1 brezak * California, Lawrence Berkeley Laboratory and its contributors.
23 1.1 brezak * 4. Neither the name of the University nor the names of its contributors
24 1.1 brezak * may be used to endorse or promote products derived from this software
25 1.1 brezak * without specific prior written permission.
26 1.1 brezak *
27 1.1 brezak * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 1.1 brezak * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 1.1 brezak * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 1.1 brezak * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 1.1 brezak * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 1.1 brezak * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 1.1 brezak * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 1.1 brezak * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 1.1 brezak * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 1.1 brezak * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 1.1 brezak * SUCH DAMAGE.
38 1.1 brezak *
39 1.2 cgd * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL)
40 1.1 brezak */
41 1.1 brezak
42 1.5 gwr /*
43 1.6 gwr * RPC functions used by NFS and bootparams.
44 1.6 gwr * Note that bootparams requires the ability to find out the
45 1.6 gwr * address of the server from which its response has come.
46 1.6 gwr * This is supported by keeping the IP/UDP headers in the
47 1.6 gwr * buffer space provided by the caller. (See rpc_fromaddr)
48 1.5 gwr */
49 1.5 gwr
50 1.1 brezak #include <sys/param.h>
51 1.1 brezak #include <sys/socket.h>
52 1.1 brezak
53 1.1 brezak #include <netinet/in.h>
54 1.1 brezak #include <netinet/in_systm.h>
55 1.4 mycroft
56 1.20 thorpej #ifdef _STANDALONE
57 1.20 thorpej #include <lib/libkern/libkern.h>
58 1.25 dsl #include "stand.h"
59 1.20 thorpej #else
60 1.20 thorpej #include <string.h>
61 1.25 dsl #include <errno.h>
62 1.25 dsl #include <stdio.h>
63 1.20 thorpej #endif
64 1.20 thorpej
65 1.12 gwr #include "rpcv2.h"
66 1.1 brezak
67 1.1 brezak #include "net.h"
68 1.1 brezak #include "rpc.h"
69 1.1 brezak
70 1.5 gwr struct auth_info {
71 1.5 gwr int32_t authtype; /* auth type */
72 1.5 gwr u_int32_t authlen; /* auth length */
73 1.5 gwr };
74 1.5 gwr
75 1.5 gwr struct auth_unix {
76 1.5 gwr int32_t ua_time;
77 1.5 gwr int32_t ua_hostname; /* null */
78 1.5 gwr int32_t ua_uid;
79 1.5 gwr int32_t ua_gid;
80 1.5 gwr int32_t ua_gidlist; /* null */
81 1.1 brezak };
82 1.1 brezak
83 1.5 gwr struct rpc_call {
84 1.5 gwr u_int32_t rp_xid; /* request transaction id */
85 1.5 gwr int32_t rp_direction; /* call direction (0) */
86 1.5 gwr u_int32_t rp_rpcvers; /* rpc version (2) */
87 1.5 gwr u_int32_t rp_prog; /* program */
88 1.5 gwr u_int32_t rp_vers; /* version */
89 1.5 gwr u_int32_t rp_proc; /* procedure */
90 1.5 gwr };
91 1.1 brezak
92 1.5 gwr struct rpc_reply {
93 1.5 gwr u_int32_t rp_xid; /* request transaction id */
94 1.5 gwr int32_t rp_direction; /* call direction (1) */
95 1.5 gwr int32_t rp_astatus; /* accept status (0: accepted) */
96 1.5 gwr union {
97 1.5 gwr u_int32_t rpu_errno;
98 1.5 gwr struct {
99 1.5 gwr struct auth_info rok_auth;
100 1.5 gwr u_int32_t rok_status;
101 1.5 gwr } rpu_rok;
102 1.5 gwr } rp_u;
103 1.1 brezak };
104 1.1 brezak
105 1.1 brezak /* Local forwards */
106 1.29 tsutsui static ssize_t recvrpc(struct iodesc *, void *, size_t, saseconds_t);
107 1.1 brezak
108 1.5 gwr int rpc_xid;
109 1.5 gwr int rpc_port = 0x400; /* predecrement */
110 1.5 gwr
111 1.5 gwr /*
112 1.5 gwr * Make a rpc call; return length of answer
113 1.6 gwr * Note: Caller must leave room for headers.
114 1.5 gwr */
115 1.7 pk ssize_t
116 1.26 isaki rpc_call(struct iodesc *d, n_long prog, n_long vers, n_long proc,
117 1.26 isaki void *sdata, size_t slen, void *rdata, size_t rlen)
118 1.1 brezak {
119 1.21 augustss ssize_t cc;
120 1.5 gwr struct auth_info *auth;
121 1.5 gwr struct rpc_call *call;
122 1.5 gwr struct rpc_reply *reply;
123 1.8 pk char *send_head, *send_tail;
124 1.8 pk char *recv_head, *recv_tail;
125 1.5 gwr n_long x;
126 1.10 gwr int port; /* host order */
127 1.1 brezak
128 1.1 brezak #ifdef RPC_DEBUG
129 1.1 brezak if (debug)
130 1.30 christos printf("%s: prog=%#x vers=%d proc=%d\n", __func__,
131 1.15 christos prog, vers, proc);
132 1.5 gwr #endif
133 1.5 gwr
134 1.10 gwr port = rpc_getport(d, prog, vers);
135 1.10 gwr if (port == -1)
136 1.26 isaki return -1;
137 1.9 pk
138 1.10 gwr d->destport = htons(port);
139 1.5 gwr
140 1.5 gwr /*
141 1.5 gwr * Prepend authorization stuff and headers.
142 1.5 gwr * Note, must prepend things in reverse order.
143 1.5 gwr */
144 1.5 gwr send_head = sdata;
145 1.7 pk send_tail = (char *)sdata + slen;
146 1.5 gwr
147 1.5 gwr /* Auth verifier is always auth_null */
148 1.8 pk send_head -= sizeof(*auth);
149 1.8 pk auth = (struct auth_info *)send_head;
150 1.5 gwr auth->authtype = htonl(RPCAUTH_NULL);
151 1.5 gwr auth->authlen = 0;
152 1.5 gwr
153 1.6 gwr #if 1
154 1.5 gwr /* Auth credentials: always auth unix (as root) */
155 1.8 pk send_head -= sizeof(struct auth_unix);
156 1.27 christos (void)memset(send_head, 0, sizeof(struct auth_unix));
157 1.8 pk send_head -= sizeof(*auth);
158 1.8 pk auth = (struct auth_info *)send_head;
159 1.5 gwr auth->authtype = htonl(RPCAUTH_UNIX);
160 1.5 gwr auth->authlen = htonl(sizeof(struct auth_unix));
161 1.5 gwr #else
162 1.5 gwr /* Auth credentials: always auth_null (XXX OK?) */
163 1.8 pk send_head -= sizeof(*auth);
164 1.5 gwr auth = send_head;
165 1.5 gwr auth->authtype = htonl(RPCAUTH_NULL);
166 1.5 gwr auth->authlen = 0;
167 1.1 brezak #endif
168 1.1 brezak
169 1.5 gwr /* RPC call structure. */
170 1.8 pk send_head -= sizeof(*call);
171 1.8 pk call = (struct rpc_call *)send_head;
172 1.5 gwr rpc_xid++;
173 1.5 gwr call->rp_xid = htonl(rpc_xid);
174 1.5 gwr call->rp_direction = htonl(RPC_CALL);
175 1.5 gwr call->rp_rpcvers = htonl(RPC_VER2);
176 1.5 gwr call->rp_prog = htonl(prog);
177 1.5 gwr call->rp_vers = htonl(vers);
178 1.5 gwr call->rp_proc = htonl(proc);
179 1.5 gwr
180 1.5 gwr /* Make room for the rpc_reply header. */
181 1.5 gwr recv_head = rdata;
182 1.7 pk recv_tail = (char *)rdata + rlen;
183 1.8 pk recv_head -= sizeof(*reply);
184 1.1 brezak
185 1.4 mycroft cc = sendrecv(d,
186 1.13 cgd sendudp, send_head, send_tail - send_head,
187 1.13 cgd recvrpc, recv_head, recv_tail - recv_head);
188 1.9 pk
189 1.3 mycroft #ifdef RPC_DEBUG
190 1.3 mycroft if (debug)
191 1.30 christos printf("%s: cc=%zd rlen=%zu\n", __func__, cc, rlen);
192 1.3 mycroft #endif
193 1.7 pk if (cc == -1)
194 1.26 isaki return -1;
195 1.7 pk
196 1.23 fvdl if ((size_t)cc <= sizeof(*reply)) {
197 1.7 pk errno = EBADRPC;
198 1.26 isaki return -1;
199 1.7 pk }
200 1.7 pk
201 1.8 pk recv_tail = recv_head + cc;
202 1.3 mycroft
203 1.5 gwr /*
204 1.5 gwr * Check the RPC reply status.
205 1.5 gwr * The xid, dir, astatus were already checked.
206 1.5 gwr */
207 1.8 pk reply = (struct rpc_reply *)recv_head;
208 1.5 gwr auth = &reply->rp_u.rpu_rok.rok_auth;
209 1.5 gwr x = ntohl(auth->authlen);
210 1.5 gwr if (x != 0) {
211 1.5 gwr #ifdef RPC_DEBUG
212 1.5 gwr if (debug)
213 1.30 christos printf("%s: reply auth != NULL\n", __func__);
214 1.5 gwr #endif
215 1.8 pk errno = EBADRPC;
216 1.26 isaki return -1;
217 1.5 gwr }
218 1.5 gwr x = ntohl(reply->rp_u.rpu_rok.rok_status);
219 1.5 gwr if (x != 0) {
220 1.30 christos printf("%s: error = %d\n", __func__, x);
221 1.8 pk errno = EBADRPC;
222 1.26 isaki return -1;
223 1.5 gwr }
224 1.8 pk recv_head += sizeof(*reply);
225 1.1 brezak
226 1.13 cgd return (ssize_t)(recv_tail - recv_head);
227 1.1 brezak }
228 1.1 brezak
229 1.5 gwr /*
230 1.5 gwr * Returns true if packet is the one we're waiting for.
231 1.5 gwr * This just checks the XID, direction, acceptance.
232 1.5 gwr * Remaining checks are done by callrpc
233 1.5 gwr */
234 1.7 pk static ssize_t
235 1.28 tsutsui recvrpc(struct iodesc *d, void *pkt, size_t len, saseconds_t tleft)
236 1.1 brezak {
237 1.21 augustss struct rpc_reply *reply;
238 1.8 pk ssize_t n;
239 1.14 cgd int x;
240 1.1 brezak
241 1.1 brezak errno = 0;
242 1.1 brezak #ifdef RPC_DEBUG
243 1.1 brezak if (debug)
244 1.30 christos printf("%s: called len=%zu\n", __func__, len);
245 1.1 brezak #endif
246 1.1 brezak
247 1.7 pk n = readudp(d, pkt, len, tleft);
248 1.7 pk if (n <= (4 * 4))
249 1.8 pk return -1;
250 1.8 pk
251 1.5 gwr reply = (struct rpc_reply *)pkt;
252 1.4 mycroft
253 1.5 gwr x = ntohl(reply->rp_xid);
254 1.5 gwr if (x != rpc_xid) {
255 1.1 brezak #ifdef RPC_DEBUG
256 1.5 gwr if (debug)
257 1.30 christos printf("%s: rp_xid %d != xid %d\n",
258 1.30 christos __func__, x, rpc_xid);
259 1.1 brezak #endif
260 1.8 pk return -1;
261 1.1 brezak }
262 1.1 brezak
263 1.5 gwr x = ntohl(reply->rp_direction);
264 1.5 gwr if (x != RPC_REPLY) {
265 1.5 gwr #ifdef RPC_DEBUG
266 1.5 gwr if (debug)
267 1.30 christos printf("%s: rp_direction %d != REPLY\n", __func__, x);
268 1.5 gwr #endif
269 1.8 pk return -1;
270 1.5 gwr }
271 1.5 gwr
272 1.5 gwr x = ntohl(reply->rp_astatus);
273 1.5 gwr if (x != RPC_MSGACCEPTED) {
274 1.5 gwr errno = ntohl(reply->rp_u.rpu_errno);
275 1.30 christos printf("%s: reject, astat=%d, errno=%d\n", __func__, x, errno);
276 1.8 pk return -1;
277 1.5 gwr }
278 1.5 gwr
279 1.1 brezak /* Return data count (thus indicating success) */
280 1.26 isaki return n;
281 1.1 brezak }
282 1.1 brezak
283 1.5 gwr /*
284 1.5 gwr * Given a pointer to a reply just received,
285 1.5 gwr * dig out the IP address/port from the headers.
286 1.5 gwr */
287 1.5 gwr void
288 1.26 isaki rpc_fromaddr(void *pkt, struct in_addr *addr, u_short *port)
289 1.5 gwr {
290 1.5 gwr struct hackhdr {
291 1.5 gwr /* Tail of IP header: just IP addresses */
292 1.5 gwr n_long ip_src;
293 1.5 gwr n_long ip_dst;
294 1.5 gwr /* UDP header: */
295 1.5 gwr u_int16_t uh_sport; /* source port */
296 1.5 gwr u_int16_t uh_dport; /* destination port */
297 1.5 gwr int16_t uh_ulen; /* udp length */
298 1.5 gwr u_int16_t uh_sum; /* udp checksum */
299 1.5 gwr /* RPC reply header: */
300 1.5 gwr struct rpc_reply rpc;
301 1.5 gwr } *hhdr;
302 1.5 gwr
303 1.5 gwr hhdr = ((struct hackhdr *)pkt) - 1;
304 1.9 pk addr->s_addr = hhdr->ip_src;
305 1.5 gwr *port = hhdr->uh_sport;
306 1.5 gwr }
307 1.5 gwr
308 1.25 dsl #ifdef NO_PMAP_CACHE
309 1.25 dsl #define rpc_pmap_getcache(addr, prog, vers) (-1)
310 1.25 dsl #define rpc_pmap_putcache(addr, prog, vers, port)
311 1.25 dsl #else
312 1.25 dsl
313 1.5 gwr /*
314 1.5 gwr * RPC Portmapper cache
315 1.5 gwr */
316 1.5 gwr #define PMAP_NUM 8 /* need at most 5 pmap entries */
317 1.5 gwr
318 1.5 gwr int rpc_pmap_num;
319 1.5 gwr struct pmap_list {
320 1.9 pk struct in_addr addr; /* server, net order */
321 1.14 cgd u_int prog; /* host order */
322 1.14 cgd u_int vers; /* host order */
323 1.10 gwr int port; /* host order */
324 1.5 gwr } rpc_pmap_list[PMAP_NUM];
325 1.5 gwr
326 1.26 isaki /*
327 1.26 isaki * return port number in host order, or -1.
328 1.26 isaki * arguments are:
329 1.26 isaki * addr .. server, net order.
330 1.26 isaki * prog .. host order.
331 1.26 isaki * vers .. host order.
332 1.26 isaki */
333 1.5 gwr int
334 1.26 isaki rpc_pmap_getcache(struct in_addr addr, u_int prog, u_int vers)
335 1.5 gwr {
336 1.5 gwr struct pmap_list *pl;
337 1.5 gwr
338 1.10 gwr for (pl = rpc_pmap_list; pl < &rpc_pmap_list[rpc_pmap_num]; pl++) {
339 1.10 gwr if (pl->addr.s_addr == addr.s_addr &&
340 1.10 gwr pl->prog == prog && pl->vers == vers )
341 1.10 gwr {
342 1.26 isaki return pl->port;
343 1.10 gwr }
344 1.10 gwr }
345 1.26 isaki return -1;
346 1.5 gwr }
347 1.5 gwr
348 1.26 isaki /*
349 1.26 isaki * arguments are:
350 1.26 isaki * addr .. server, net order.
351 1.26 isaki * prog .. host order.
352 1.26 isaki * vers .. host order.
353 1.26 isaki * port .. host order.
354 1.26 isaki */
355 1.5 gwr void
356 1.26 isaki rpc_pmap_putcache(struct in_addr addr, u_int prog, u_int vers, int port)
357 1.5 gwr {
358 1.5 gwr struct pmap_list *pl;
359 1.5 gwr
360 1.5 gwr /* Don't overflow cache... */
361 1.5 gwr if (rpc_pmap_num >= PMAP_NUM) {
362 1.5 gwr /* ... just re-use the last entry. */
363 1.5 gwr rpc_pmap_num = PMAP_NUM - 1;
364 1.5 gwr #ifdef RPC_DEBUG
365 1.30 christos printf("%s: cache overflow\n", __func__);
366 1.5 gwr #endif
367 1.5 gwr }
368 1.5 gwr
369 1.5 gwr pl = &rpc_pmap_list[rpc_pmap_num];
370 1.5 gwr rpc_pmap_num++;
371 1.5 gwr
372 1.5 gwr /* Cache answer */
373 1.5 gwr pl->addr = addr;
374 1.5 gwr pl->prog = prog;
375 1.5 gwr pl->vers = vers;
376 1.5 gwr pl->port = port;
377 1.5 gwr }
378 1.25 dsl #endif
379 1.5 gwr
380 1.5 gwr /*
381 1.5 gwr * Request a port number from the port mapper.
382 1.10 gwr * Returns the port in host order.
383 1.26 isaki * prog and vers are host order.
384 1.5 gwr */
385 1.5 gwr int
386 1.26 isaki rpc_getport(struct iodesc *d, n_long prog, n_long vers)
387 1.1 brezak {
388 1.5 gwr struct args {
389 1.9 pk n_long prog; /* call program */
390 1.9 pk n_long vers; /* call version */
391 1.9 pk n_long proto; /* call protocol */
392 1.9 pk n_long port; /* call port (unused) */
393 1.5 gwr } *args;
394 1.5 gwr struct res {
395 1.9 pk n_long port;
396 1.5 gwr } *res;
397 1.5 gwr struct {
398 1.5 gwr n_long h[RPC_HEADER_WORDS];
399 1.5 gwr struct args d;
400 1.1 brezak } sdata;
401 1.5 gwr struct {
402 1.5 gwr n_long h[RPC_HEADER_WORDS];
403 1.5 gwr struct res d;
404 1.5 gwr n_long pad;
405 1.5 gwr } rdata;
406 1.9 pk ssize_t cc;
407 1.10 gwr int port;
408 1.1 brezak
409 1.1 brezak #ifdef RPC_DEBUG
410 1.1 brezak if (debug)
411 1.30 christos printf("%s: prog=%#x vers=%d\n", __func__, prog, vers);
412 1.1 brezak #endif
413 1.5 gwr
414 1.5 gwr /* This one is fixed forever. */
415 1.5 gwr if (prog == PMAPPROG)
416 1.26 isaki return PMAPPORT;
417 1.5 gwr
418 1.1 brezak /* Try for cached answer first */
419 1.5 gwr port = rpc_pmap_getcache(d->destip, prog, vers);
420 1.10 gwr if (port != -1)
421 1.26 isaki return port;
422 1.5 gwr
423 1.5 gwr args = &sdata.d;
424 1.5 gwr args->prog = htonl(prog);
425 1.5 gwr args->vers = htonl(vers);
426 1.5 gwr args->proto = htonl(IPPROTO_UDP);
427 1.5 gwr args->port = 0;
428 1.5 gwr res = &rdata.d;
429 1.5 gwr
430 1.5 gwr cc = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT,
431 1.5 gwr args, sizeof(*args), res, sizeof(*res));
432 1.23 fvdl if ((size_t)cc < sizeof(*res)) {
433 1.30 christos printf("%s: %s", __func__, strerror(errno));
434 1.9 pk errno = EBADRPC;
435 1.26 isaki return -1;
436 1.1 brezak }
437 1.10 gwr port = (int)ntohl(res->port);
438 1.1 brezak
439 1.5 gwr rpc_pmap_putcache(d->destip, prog, vers, port);
440 1.1 brezak
441 1.26 isaki return port;
442 1.1 brezak }
443