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