bootparam.c revision 1.4 1 /* $NetBSD: bootparam.c,v 1.4 1995/09/18 21:19:22 pk Exp $ */
2
3 /*
4 * Copyright (c) 1995 Gordon W. Ross
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 * 4. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Gordon W. Ross
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34 * RPC/bootparams
35 */
36
37 #include <sys/param.h>
38 #include <sys/socket.h>
39
40 #include <net/if.h>
41
42 #include <netinet/in.h>
43 #include <netinet/in_systm.h>
44
45 #include <nfs/rpcv2.h>
46
47 #include <string.h>
48
49 #include "stand.h"
50 #include "net.h"
51 #include "netif.h"
52 #include "rpc.h"
53 #include "bootparam.h"
54
55 struct in_addr bp_server_addr; /* net order */
56 n_short bp_server_port; /* net order */
57
58 /*
59 * RPC definitions for bootparamd
60 */
61 #define BOOTPARAM_PROG 100026
62 #define BOOTPARAM_VERS 1
63 #define BOOTPARAM_WHOAMI 1
64 #define BOOTPARAM_GETFILE 2
65
66 /*
67 * Inet address in RPC messages
68 * (Note, really four ints, NOT chars. Blech.)
69 */
70 struct xdr_inaddr {
71 u_int32_t atype;
72 int32_t addr[4];
73 };
74
75 int xdr_inaddr_encode __P((void **p, struct in_addr ia));
76 int xdr_inaddr_decode __P((void **p, struct in_addr *ia));
77
78 int xdr_string_encode __P((void **p, char *str, int len));
79 int xdr_string_decode __P((void **p, char *str, int *len_p));
80
81
82 /*
83 * RPC: bootparam/whoami
84 * Given client IP address, get:
85 * client name (hostname)
86 * domain name (domainname)
87 * gateway address
88 *
89 * The hostname and domainname are set here for convenience.
90 *
91 * Note - bpsin is initialized to the broadcast address,
92 * and will be replaced with the bootparam server address
93 * after this call is complete. Have to use PMAP_PROC_CALL
94 * to make sure we get responses only from a servers that
95 * know about us (don't want to broadcast a getport call).
96 */
97 int
98 bp_whoami(sockfd)
99 int sockfd;
100 {
101 /* RPC structures for PMAPPROC_CALLIT */
102 struct args {
103 u_int32_t prog;
104 u_int32_t vers;
105 u_int32_t proc;
106 u_int32_t arglen;
107 struct xdr_inaddr xina;
108 } *args;
109 struct repl {
110 u_int32_t port;
111 u_int32_t encap_len;
112 /* encapsulated data here */
113 n_long capsule[64];
114 } *repl;
115 struct {
116 n_long h[RPC_HEADER_WORDS];
117 struct args d;
118 } sdata;
119 struct {
120 n_long h[RPC_HEADER_WORDS];
121 struct repl d;
122 } rdata;
123 void *send_tail, *recv_head;
124 struct iodesc *d;
125 int len, x;
126
127 #ifdef RPC_DEBUG
128 printf("bp_whoami: myip=%s\n", inet_ntoa(myip));
129 #endif
130
131 if (!(d = socktodesc(sockfd))) {
132 printf("bp_whoami: bad socket. %d\n", sockfd);
133 return (-1);
134 }
135 args = &sdata.d;
136 repl = &rdata.d;
137
138 /*
139 * Build request args for PMAPPROC_CALLIT.
140 */
141 args->prog = htonl(BOOTPARAM_PROG);
142 args->vers = htonl(BOOTPARAM_VERS);
143 args->proc = htonl(BOOTPARAM_WHOAMI);
144 args->arglen = htonl(sizeof(struct xdr_inaddr));
145 send_tail = &args->xina;
146
147 /*
148 * append encapsulated data (client IP address)
149 */
150 if (xdr_inaddr_encode(&send_tail, myip))
151 return (-1);
152
153 /* RPC: portmap/callit */
154 d->myport = htons(--rpc_port);
155 d->destip.s_addr = INADDR_BROADCAST; /* XXX: subnet bcast? */
156 /* rpc_call will set d->destport */
157
158 len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT,
159 args, (int)send_tail - (int)args,
160 repl, sizeof(*repl));
161 if (len < 8) {
162 printf("bootparamd: 'whoami' call failed\n");
163 return (-1);
164 }
165
166 /* Save bootparam server address (from IP header). */
167 rpc_fromaddr(repl, &bp_server_addr, &bp_server_port);
168
169 /*
170 * Note that bp_server_port is now 111 due to the
171 * indirect call (using PMAPPROC_CALLIT), so get the
172 * actual port number from the reply data.
173 */
174 bp_server_port = repl->port;
175
176 #ifdef RPC_DEBUG
177 printf("bp_whoami: server at %s:%d\n",
178 inet_ntoa(bp_server_addr), ntohs(bp_server_port));
179 #endif
180
181 /* We have just done a portmap call, so cache the portnum. */
182 rpc_pmap_putcache(bp_server_addr,
183 BOOTPARAM_PROG,
184 BOOTPARAM_VERS,
185 (int)bp_server_port);
186
187 /*
188 * Parse the encapsulated results from bootparam/whoami
189 */
190 x = ntohl(repl->encap_len);
191 if (len < x) {
192 printf("bp_whoami: short reply, %d < %d\n", len, x);
193 return (-1);
194 }
195 recv_head = repl->capsule;
196
197 /* client name */
198 hostnamelen = MAXHOSTNAMELEN-1;
199 if (xdr_string_decode(&recv_head, hostname, &hostnamelen)) {
200 #ifdef RPC_DEBUG
201 printf("bp_whoami: bad hostname\n");
202 #endif
203 return (-1);
204 }
205
206 /* domain name */
207 domainnamelen = MAXHOSTNAMELEN-1;
208 if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) {
209 #ifdef RPC_DEBUG
210 printf("bp_whoami: bad domainname\n");
211 #endif
212 return (-1);
213 }
214
215 /* gateway address */
216 if (xdr_inaddr_decode(&recv_head, &gateip)) {
217 #ifdef RPC_DEBUG
218 printf("bp_whoami: bad gateway\n");
219 #endif
220 return (-1);
221 }
222
223 /* success */
224 return(0);
225 }
226
227
228 /*
229 * RPC: bootparam/getfile
230 * Given client name and file "key", get:
231 * server name
232 * server IP address
233 * server pathname
234 */
235 int
236 bp_getfile(sockfd, key, serv_addr, pathname)
237 int sockfd;
238 char *key;
239 char *pathname;
240 struct in_addr *serv_addr;
241 {
242 struct {
243 n_long h[RPC_HEADER_WORDS];
244 n_long d[64];
245 } sdata;
246 struct {
247 n_long h[RPC_HEADER_WORDS];
248 n_long d[128];
249 } rdata;
250 char serv_name[FNAME_SIZE];
251 void *send_tail, *recv_head;
252 /* misc... */
253 struct iodesc *d;
254 int sn_len, path_len, rlen;
255
256 if (!(d = socktodesc(sockfd))) {
257 printf("bp_getfile: bad socket. %d\n", sockfd);
258 return (-1);
259 }
260
261 send_tail = sdata.d;
262 recv_head = rdata.d;
263
264 /*
265 * Build request message.
266 */
267
268 /* client name (hostname) */
269 if (xdr_string_encode(&send_tail, hostname, hostnamelen)) {
270 #ifdef RPC_DEBUG
271 printf("bp_getfile: bad client\n");
272 #endif
273 return (-1);
274 }
275
276 /* key name (root or swap) */
277 if (xdr_string_encode(&send_tail, key, strlen(key))) {
278 #ifdef RPC_DEBUG
279 printf("bp_getfile: bad key\n");
280 #endif
281 return (-1);
282 }
283
284 /* RPC: bootparam/getfile */
285 d->myport = htons(--rpc_port);
286 d->destip = bp_server_addr;
287 /* rpc_call will set d->destport */
288
289 rlen = rpc_call(d,
290 BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE,
291 sdata.d, (int)send_tail - (int)sdata.d,
292 rdata.d, sizeof(rdata.d));
293 if (rlen < 4) {
294 #ifdef RPC_DEBUG
295 printf("bp_getfile: short reply\n");
296 #endif
297 errno = EBADRPC;
298 return (-1);
299 }
300 recv_head = rdata.d;
301
302 /*
303 * Parse result message.
304 */
305
306 /* server name */
307 sn_len = FNAME_SIZE-1;
308 if (xdr_string_decode(&recv_head, serv_name, &sn_len)) {
309 #ifdef RPC_DEBUG
310 printf("bp_getfile: bad server name\n");
311 #endif
312 return (-1);
313 }
314
315 /* server IP address (mountd/NFS) */
316 if (xdr_inaddr_decode(&recv_head, serv_addr)) {
317 #ifdef RPC_DEBUG
318 printf("bp_getfile: bad server addr\n");
319 #endif
320 return (-1);
321 }
322
323 /* server pathname */
324 path_len = MAXPATHLEN-1;
325 if (xdr_string_decode(&recv_head, pathname, &path_len)) {
326 #ifdef RPC_DEBUG
327 printf("bp_getfile: bad server path\n");
328 #endif
329 return (-1);
330 }
331
332 /* success */
333 return(0);
334 }
335
336
337 /*
338 * eXternal Data Representation routines.
339 * (but with non-standard args...)
340 */
341
342
343 int
344 xdr_string_encode(pkt, str, len)
345 void **pkt;
346 char *str;
347 int len;
348 {
349 u_int32_t *lenp;
350 char *datap;
351 int padlen = (len + 3) & ~3; /* padded length */
352
353 lenp = *pkt;
354 *(char**)pkt += sizeof(*lenp);
355 *lenp = htonl(len);
356
357 datap = *pkt;
358 *(char**)pkt += padlen;
359 bcopy(str, datap, len);
360
361 return (0);
362 }
363
364 int
365 xdr_string_decode(pkt, str, len_p)
366 void **pkt;
367 char *str;
368 int *len_p; /* bufsize - 1 */
369 {
370 u_int32_t *lenp;
371 char *datap;
372 int slen; /* string length */
373 int plen; /* padded length */
374
375 lenp = *pkt;
376 *(char**)pkt += sizeof(*lenp);
377 slen = ntohl(*lenp);
378 plen = (slen + 3) & ~3;
379
380 if (slen > *len_p)
381 slen = *len_p;
382 datap = *pkt;
383 *(char**)pkt += plen;
384 bcopy(datap, str, slen);
385
386 str[slen] = '\0';
387 *len_p = slen;
388
389 return (0);
390 }
391
392
393 int
394 xdr_inaddr_encode(pkt, ia)
395 void **pkt;
396 struct in_addr ia;
397 {
398 struct xdr_inaddr *xi;
399 u_char *cp;
400 int32_t *ip;
401 union {
402 n_long l;
403 u_char c[4];
404 } uia;
405
406 xi = *pkt;
407 *(char**)pkt += sizeof(*xi);
408 xi->atype = htonl(1);
409 uia.l = ia.s_addr;
410 cp = uia.c;
411 ip = xi->addr;
412 *ip++ = htonl((unsigned int)*cp++);
413 *ip++ = htonl((unsigned int)*cp++);
414 *ip++ = htonl((unsigned int)*cp++);
415 *ip++ = htonl((unsigned int)*cp++);
416
417 return (0);
418 }
419
420 int
421 xdr_inaddr_decode(pkt, ia)
422 void **pkt;
423 struct in_addr *ia; /* host order */
424 {
425 struct xdr_inaddr *xi;
426 u_char *cp;
427 int32_t *ip;
428 union {
429 n_long l;
430 u_char c[4];
431 } uia;
432
433 xi = *pkt;
434 *(char**)pkt += sizeof(*xi);
435 if (xi->atype != htonl(1)) {
436 #ifdef RPC_DEBUG
437 printf("xdr_inaddr_decode: bad addrtype=%d\n",
438 ntohl(xi->atype));
439 #endif
440 return(-1);
441 }
442
443 cp = uia.c;
444 ip = xi->addr;
445 *cp++ = ntohl(*ip++);
446 *cp++ = ntohl(*ip++);
447 *cp++ = ntohl(*ip++);
448 *cp++ = ntohl(*ip++);
449 ia->s_addr = uia.l;
450
451 return (0);
452 }
453