rpc.c revision 1.5 1 1.5 gwr /* $NetBSD: rpc.c,v 1.5 1995/06/27 15:28:58 gwr 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.5 gwr * This code was copied from sys/lib/libsa/rpc.c and modified to
44 1.5 gwr * avoid copying the args/results to/from local packet buffers,
45 1.5 gwr * because that allows the new function rpc_fromaddr() to look
46 1.5 gwr * back into the headers to find out where a response is from.
47 1.5 gwr * This is needed by the bootparam.c code, and is also a little
48 1.5 gwr * more efficient (though efficiency is not a concern here.)
49 1.5 gwr * The new calling interface means nfs.c had to change too...
50 1.5 gwr */
51 1.5 gwr
52 1.1 brezak #include <sys/param.h>
53 1.1 brezak #include <sys/socket.h>
54 1.1 brezak
55 1.1 brezak #include <netinet/in.h>
56 1.1 brezak #include <netinet/in_systm.h>
57 1.1 brezak
58 1.1 brezak #include <nfs/rpcv2.h>
59 1.1 brezak #include <nfs/nfsv2.h>
60 1.4 mycroft #include <nfs/xdr_subs.h>
61 1.4 mycroft
62 1.1 brezak #include <string.h>
63 1.1 brezak
64 1.1 brezak #include "stand.h"
65 1.1 brezak #include "net.h"
66 1.1 brezak #include "netif.h"
67 1.1 brezak #include "rpc.h"
68 1.1 brezak
69 1.5 gwr struct auth_info {
70 1.5 gwr int32_t authtype; /* auth type */
71 1.5 gwr u_int32_t authlen; /* auth length */
72 1.5 gwr };
73 1.5 gwr
74 1.5 gwr struct auth_unix {
75 1.5 gwr int32_t ua_time;
76 1.5 gwr int32_t ua_hostname; /* null */
77 1.5 gwr int32_t ua_uid;
78 1.5 gwr int32_t ua_gid;
79 1.5 gwr int32_t ua_gidlist; /* null */
80 1.1 brezak };
81 1.1 brezak
82 1.5 gwr struct rpc_call {
83 1.5 gwr u_int32_t rp_xid; /* request transaction id */
84 1.5 gwr int32_t rp_direction; /* call direction (0) */
85 1.5 gwr u_int32_t rp_rpcvers; /* rpc version (2) */
86 1.5 gwr u_int32_t rp_prog; /* program */
87 1.5 gwr u_int32_t rp_vers; /* version */
88 1.5 gwr u_int32_t rp_proc; /* procedure */
89 1.5 gwr };
90 1.1 brezak
91 1.5 gwr struct rpc_reply {
92 1.5 gwr u_int32_t rp_xid; /* request transaction id */
93 1.5 gwr int32_t rp_direction; /* call direction (1) */
94 1.5 gwr int32_t rp_astatus; /* accept status (0: accepted) */
95 1.5 gwr union {
96 1.5 gwr u_int32_t rpu_errno;
97 1.5 gwr struct {
98 1.5 gwr struct auth_info rok_auth;
99 1.5 gwr u_int32_t rok_status;
100 1.5 gwr } rpu_rok;
101 1.5 gwr } rp_u;
102 1.1 brezak };
103 1.1 brezak
104 1.1 brezak /* Local forwards */
105 1.4 mycroft static size_t recvrpc __P((struct iodesc *, void *, size_t, time_t));
106 1.1 brezak
107 1.5 gwr int rpc_xid;
108 1.5 gwr int rpc_port = 0x400; /* predecrement */
109 1.5 gwr
110 1.5 gwr /*
111 1.5 gwr * Make a rpc call; return length of answer
112 1.5 gwr * XXX - Caller must leave room for headers.
113 1.5 gwr */
114 1.4 mycroft size_t
115 1.5 gwr rpc_call(d, prog, vers, proc, sdata, slen, rdata, rlen)
116 1.1 brezak register struct iodesc *d;
117 1.5 gwr register n_long prog, vers, proc;
118 1.1 brezak register void *sdata;
119 1.4 mycroft register size_t slen;
120 1.1 brezak register void *rdata;
121 1.4 mycroft register size_t rlen;
122 1.1 brezak {
123 1.4 mycroft register size_t cc;
124 1.5 gwr struct auth_info *auth;
125 1.5 gwr struct rpc_call *call;
126 1.5 gwr struct rpc_reply *reply;
127 1.5 gwr void *send_head, *send_tail;
128 1.5 gwr void *recv_head, *recv_tail;
129 1.5 gwr n_long x;
130 1.1 brezak
131 1.1 brezak #ifdef RPC_DEBUG
132 1.1 brezak if (debug)
133 1.5 gwr printf("rpc_call: prog=0x%x vers=%d proc=%d\n",
134 1.5 gwr prog, vers, proc);
135 1.5 gwr #endif
136 1.5 gwr
137 1.5 gwr d->destport = rpc_getport(d, prog, vers);
138 1.5 gwr
139 1.5 gwr /*
140 1.5 gwr * Prepend authorization stuff and headers.
141 1.5 gwr * Note, must prepend things in reverse order.
142 1.5 gwr */
143 1.5 gwr send_head = sdata;
144 1.5 gwr send_tail = sdata + slen;
145 1.5 gwr
146 1.5 gwr /* Auth verifier is always auth_null */
147 1.5 gwr send_head -= sizeof(*auth);
148 1.5 gwr auth = send_head;
149 1.5 gwr auth->authtype = htonl(RPCAUTH_NULL);
150 1.5 gwr auth->authlen = 0;
151 1.5 gwr
152 1.5 gwr #if 0 /* XXX */
153 1.5 gwr /* Auth credentials: always auth unix (as root) */
154 1.5 gwr send_head -= sizeof(struct auth_unix);
155 1.5 gwr bzero(send_head, sizeof(struct auth_unix));
156 1.5 gwr send_head -= sizeof(*auth);
157 1.5 gwr auth = send_head;
158 1.5 gwr auth->authtype = htonl(RPCAUTH_UNIX);
159 1.5 gwr auth->authlen = htonl(sizeof(struct auth_unix));
160 1.5 gwr #else
161 1.5 gwr /* Auth credentials: always auth_null (XXX OK?) */
162 1.5 gwr send_head -= sizeof(*auth);
163 1.5 gwr auth = send_head;
164 1.5 gwr auth->authtype = htonl(RPCAUTH_NULL);
165 1.5 gwr auth->authlen = 0;
166 1.1 brezak #endif
167 1.1 brezak
168 1.5 gwr /* RPC call structure. */
169 1.5 gwr send_head -= sizeof(*call);
170 1.5 gwr call = send_head;
171 1.5 gwr rpc_xid++;
172 1.5 gwr call->rp_xid = htonl(rpc_xid);
173 1.5 gwr call->rp_direction = htonl(RPC_CALL);
174 1.5 gwr call->rp_rpcvers = htonl(RPC_VER2);
175 1.5 gwr call->rp_prog = htonl(prog);
176 1.5 gwr call->rp_vers = htonl(vers);
177 1.5 gwr call->rp_proc = htonl(proc);
178 1.5 gwr
179 1.5 gwr /* Make room for the rpc_reply header. */
180 1.5 gwr recv_head = rdata;
181 1.5 gwr recv_tail = rdata + rlen;
182 1.5 gwr recv_head -= sizeof(*reply);
183 1.1 brezak
184 1.4 mycroft cc = sendrecv(d,
185 1.5 gwr sendudp, send_head, (send_tail - send_head),
186 1.5 gwr recvrpc, recv_head, (recv_tail - recv_head));
187 1.3 mycroft #ifdef RPC_DEBUG
188 1.3 mycroft if (debug)
189 1.5 gwr printf("callrpc: cc=%d rlen=%d\n", cc, rlen);
190 1.3 mycroft #endif
191 1.5 gwr if (cc <= sizeof(*reply))
192 1.5 gwr return (-1);
193 1.5 gwr recv_tail = recv_head + cc;
194 1.3 mycroft
195 1.5 gwr /*
196 1.5 gwr * Check the RPC reply status.
197 1.5 gwr * The xid, dir, astatus were already checked.
198 1.5 gwr */
199 1.5 gwr reply = recv_head;
200 1.5 gwr auth = &reply->rp_u.rpu_rok.rok_auth;
201 1.5 gwr x = ntohl(auth->authlen);
202 1.5 gwr if (x != 0) {
203 1.5 gwr #ifdef RPC_DEBUG
204 1.5 gwr if (debug)
205 1.5 gwr printf("callrpc: reply auth != NULL\n");
206 1.5 gwr #endif
207 1.5 gwr return(-1);
208 1.5 gwr }
209 1.5 gwr x = ntohl(reply->rp_u.rpu_rok.rok_status);
210 1.5 gwr if (x != 0) {
211 1.5 gwr printf("callrpc: error = %d\n", x);
212 1.5 gwr return(-1);
213 1.5 gwr }
214 1.5 gwr recv_head += sizeof(*reply);
215 1.1 brezak
216 1.5 gwr return (recv_tail - recv_head);
217 1.1 brezak }
218 1.1 brezak
219 1.5 gwr /*
220 1.5 gwr * Returns true if packet is the one we're waiting for.
221 1.5 gwr * This just checks the XID, direction, acceptance.
222 1.5 gwr * Remaining checks are done by callrpc
223 1.5 gwr */
224 1.4 mycroft static size_t
225 1.4 mycroft recvrpc(d, pkt, len, tleft)
226 1.1 brezak register struct iodesc *d;
227 1.1 brezak register void *pkt;
228 1.4 mycroft register size_t len;
229 1.4 mycroft time_t tleft;
230 1.1 brezak {
231 1.5 gwr register struct rpc_reply *reply;
232 1.5 gwr int x;
233 1.1 brezak
234 1.1 brezak errno = 0;
235 1.1 brezak #ifdef RPC_DEBUG
236 1.1 brezak if (debug)
237 1.3 mycroft printf("recvrpc: called len=%d\n", len);
238 1.1 brezak #endif
239 1.1 brezak
240 1.4 mycroft len = readudp(d, pkt, len, tleft);
241 1.5 gwr if (len <= (4 * 4))
242 1.4 mycroft goto bad;
243 1.5 gwr reply = (struct rpc_reply *)pkt;
244 1.4 mycroft
245 1.5 gwr x = ntohl(reply->rp_xid);
246 1.5 gwr if (x != rpc_xid) {
247 1.1 brezak #ifdef RPC_DEBUG
248 1.5 gwr if (debug)
249 1.5 gwr printf("recvrpc: rp_xid %d != xid %d\n", x, rpc_xid);
250 1.1 brezak #endif
251 1.4 mycroft goto bad;
252 1.1 brezak }
253 1.1 brezak
254 1.5 gwr x = ntohl(reply->rp_direction);
255 1.5 gwr if (x != RPC_REPLY) {
256 1.5 gwr #ifdef RPC_DEBUG
257 1.5 gwr if (debug)
258 1.5 gwr printf("recvrpc: rp_direction %d != REPLY\n", x);
259 1.5 gwr #endif
260 1.5 gwr goto bad;
261 1.5 gwr }
262 1.5 gwr
263 1.5 gwr x = ntohl(reply->rp_astatus);
264 1.5 gwr if (x != RPC_MSGACCEPTED) {
265 1.5 gwr errno = ntohl(reply->rp_u.rpu_errno);
266 1.5 gwr printf("recvrpc: reject, astat=%d, errno=%d\n", x, errno);
267 1.5 gwr goto bad;
268 1.5 gwr }
269 1.5 gwr
270 1.1 brezak /* Return data count (thus indicating success) */
271 1.5 gwr return (len);
272 1.4 mycroft
273 1.4 mycroft bad:
274 1.4 mycroft return (-1);
275 1.1 brezak }
276 1.1 brezak
277 1.5 gwr /*
278 1.5 gwr * Given a pointer to a reply just received,
279 1.5 gwr * dig out the IP address/port from the headers.
280 1.5 gwr */
281 1.5 gwr void
282 1.5 gwr rpc_fromaddr(void *pkt, n_long *addr, u_short *port)
283 1.5 gwr {
284 1.5 gwr struct hackhdr {
285 1.5 gwr /* Tail of IP header: just IP addresses */
286 1.5 gwr n_long ip_src;
287 1.5 gwr n_long ip_dst;
288 1.5 gwr /* UDP header: */
289 1.5 gwr u_int16_t uh_sport; /* source port */
290 1.5 gwr u_int16_t uh_dport; /* destination port */
291 1.5 gwr int16_t uh_ulen; /* udp length */
292 1.5 gwr u_int16_t uh_sum; /* udp checksum */
293 1.5 gwr /* RPC reply header: */
294 1.5 gwr struct rpc_reply rpc;
295 1.5 gwr } *hhdr;
296 1.5 gwr
297 1.5 gwr hhdr = ((struct hackhdr *)pkt) - 1;
298 1.5 gwr *addr = hhdr->ip_src;
299 1.5 gwr *port = hhdr->uh_sport;
300 1.5 gwr }
301 1.5 gwr
302 1.5 gwr /*
303 1.5 gwr * RPC Portmapper cache
304 1.5 gwr */
305 1.5 gwr
306 1.5 gwr #define PMAP_NUM 8 /* need at most 5 pmap entries */
307 1.5 gwr
308 1.5 gwr int rpc_pmap_num;
309 1.5 gwr struct pmap_list {
310 1.5 gwr u_long addr; /* server, net order */
311 1.5 gwr u_long prog; /* host order */
312 1.5 gwr u_long vers; /* host order */
313 1.5 gwr u_short port; /* net order */
314 1.5 gwr u_short _pad;
315 1.5 gwr } rpc_pmap_list[PMAP_NUM];
316 1.5 gwr
317 1.5 gwr /* return port number in net order */
318 1.5 gwr int
319 1.5 gwr rpc_pmap_getcache(addr, prog, vers)
320 1.5 gwr u_long addr; /* server, net order */
321 1.5 gwr u_long prog; /* host order */
322 1.5 gwr u_long vers; /* host order */
323 1.5 gwr {
324 1.5 gwr struct pmap_list *pl;
325 1.5 gwr
326 1.5 gwr for (pl = rpc_pmap_list; pl < &rpc_pmap_list[rpc_pmap_num]; pl++)
327 1.5 gwr if (pl->addr == addr && pl->prog == prog && pl->vers == vers)
328 1.5 gwr return ((int) pl->port);
329 1.5 gwr return (-1);
330 1.5 gwr }
331 1.5 gwr
332 1.5 gwr void
333 1.5 gwr rpc_pmap_putcache(addr, prog, vers, port)
334 1.5 gwr n_long addr; /* net order */
335 1.5 gwr n_long prog; /* host order */
336 1.5 gwr n_long vers; /* host order */
337 1.5 gwr int port; /* net order */
338 1.5 gwr {
339 1.5 gwr struct pmap_list *pl;
340 1.5 gwr
341 1.5 gwr /* Don't overflow cache... */
342 1.5 gwr if (rpc_pmap_num >= PMAP_NUM) {
343 1.5 gwr /* ... just re-use the last entry. */
344 1.5 gwr rpc_pmap_num = PMAP_NUM - 1;
345 1.5 gwr #ifdef RPC_DEBUG
346 1.5 gwr printf("rpc_pmap_putcache: cache overflow\n");
347 1.5 gwr #endif
348 1.5 gwr }
349 1.5 gwr
350 1.5 gwr pl = &rpc_pmap_list[rpc_pmap_num];
351 1.5 gwr rpc_pmap_num++;
352 1.5 gwr
353 1.5 gwr /* Cache answer */
354 1.5 gwr pl->addr = addr;
355 1.5 gwr pl->prog = prog;
356 1.5 gwr pl->vers = vers;
357 1.5 gwr pl->port = port;
358 1.5 gwr }
359 1.5 gwr
360 1.5 gwr
361 1.5 gwr /*
362 1.5 gwr * Request a port number from the port mapper.
363 1.5 gwr * Returns the port in network order.
364 1.5 gwr */
365 1.5 gwr int
366 1.5 gwr rpc_getport(d, prog, vers)
367 1.1 brezak register struct iodesc *d;
368 1.5 gwr n_long prog; /* host order */
369 1.5 gwr n_long vers; /* host order */
370 1.1 brezak {
371 1.5 gwr struct args {
372 1.1 brezak u_long prog; /* call program */
373 1.1 brezak u_long vers; /* call version */
374 1.1 brezak u_long proto; /* call protocol */
375 1.1 brezak u_long port; /* call port (unused) */
376 1.5 gwr } *args;
377 1.5 gwr struct res {
378 1.5 gwr u_long port;
379 1.5 gwr } *res;
380 1.5 gwr struct {
381 1.5 gwr n_long h[RPC_HEADER_WORDS];
382 1.5 gwr struct args d;
383 1.1 brezak } sdata;
384 1.5 gwr struct {
385 1.5 gwr n_long h[RPC_HEADER_WORDS];
386 1.5 gwr struct res d;
387 1.5 gwr n_long pad;
388 1.5 gwr } rdata;
389 1.5 gwr int cc, port;
390 1.1 brezak
391 1.1 brezak #ifdef RPC_DEBUG
392 1.1 brezak if (debug)
393 1.5 gwr printf("getport: prog=0x%x vers=%d\n", prog, vers);
394 1.1 brezak #endif
395 1.5 gwr
396 1.5 gwr /* This one is fixed forever. */
397 1.5 gwr if (prog == PMAPPROG)
398 1.5 gwr return PMAPPORT;
399 1.5 gwr
400 1.1 brezak /* Try for cached answer first */
401 1.5 gwr port = rpc_pmap_getcache(d->destip, prog, vers);
402 1.5 gwr if (port >= 0)
403 1.5 gwr return (port);
404 1.5 gwr
405 1.5 gwr args = &sdata.d;
406 1.5 gwr args->prog = htonl(prog);
407 1.5 gwr args->vers = htonl(vers);
408 1.5 gwr args->proto = htonl(IPPROTO_UDP);
409 1.5 gwr args->port = 0;
410 1.5 gwr res = &rdata.d;
411 1.5 gwr
412 1.5 gwr cc = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT,
413 1.5 gwr args, sizeof(*args), res, sizeof(*res));
414 1.5 gwr if (cc < sizeof(*res)) {
415 1.1 brezak printf("getport: %s", strerror(errno));
416 1.1 brezak return(-1);
417 1.1 brezak }
418 1.5 gwr port = (u_short)res->port;
419 1.1 brezak
420 1.5 gwr rpc_pmap_putcache(d->destip, prog, vers, port);
421 1.1 brezak
422 1.5 gwr return (port);
423 1.1 brezak }
424