1 /* $NetBSD: bootparam.c,v 1.11 1997/06/26 19:11:32 drochner 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 <string.h>
46
47 #include "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)
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 uint32_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 * domain name (domainname)
93 * gateway address
94 *
95 * The hostname and domainname are set here for convenience.
96 *
97 * Note - bpsin is initialized to the broadcast address,
98 * and will be replaced with the bootparam server address
99 * after this call is complete. Have to use PMAP_PROC_CALL
100 * to make sure we get responses only from a servers that
101 * know about us (don't want to broadcast a getport call).
102 */
103 int
bp_whoami(int sockfd)104 bp_whoami(int sockfd)
105 {
106 /* RPC structures for PMAPPROC_CALLIT */
107 struct args {
108 uint32_t prog;
109 uint32_t vers;
110 uint32_t proc;
111 uint32_t arglen;
112 struct xdr_inaddr xina;
113 } *args;
114 struct repl {
115 uint16_t _pad;
116 uint16_t port;
117 uint32_t encap_len;
118 /* encapsulated data here */
119 n_long capsule[64];
120 } *repl;
121 struct {
122 n_long h[RPC_HEADER_WORDS];
123 struct args d;
124 } sdata;
125 char *send_tail, *recv_head;
126 struct iodesc *d;
127 void *pkt;
128 int len, x, rc;
129
130 RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip)));
131
132 rc = -1;
133 if (!(d = socktodesc(sockfd))) {
134 RPC_PRINTF(("bp_whoami: bad socket. %d\n", sockfd));
135 return (rc);
136 }
137 args = &sdata.d;
138
139 /*
140 * Build request args for PMAPPROC_CALLIT.
141 */
142 args->prog = htonl(BOOTPARAM_PROG);
143 args->vers = htonl(BOOTPARAM_VERS);
144 args->proc = htonl(BOOTPARAM_WHOAMI);
145 args->arglen = htonl(sizeof(struct xdr_inaddr));
146 send_tail = (char*) &args->xina;
147
148 /*
149 * append encapsulated data (client IP address)
150 */
151 if (xdr_inaddr_encode(&send_tail, myip))
152 return (rc);
153
154 /* RPC: portmap/callit */
155 d->myport = htons(--rpc_port);
156 d->destip.s_addr = INADDR_BROADCAST; /* XXX: subnet bcast? */
157 /* rpc_call will set d->destport */
158
159 pkt = NULL;
160 len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT,
161 args, send_tail - (char*)args, (void **)&repl, &pkt);
162 if (len < 8) {
163 printf("bootparamd: 'whoami' call failed\n");
164 goto done;
165 }
166
167 /* Save bootparam server address (from IP header). */
168 rpc_fromaddr(repl, &bp_server_addr, &bp_server_port);
169
170 /*
171 * Note that bp_server_port is now 111 due to the
172 * indirect call (using PMAPPROC_CALLIT), so get the
173 * actual port number from the reply data.
174 */
175 bp_server_port = repl->port;
176
177 RPC_PRINTF(("bp_whoami: server at %s:%d\n",
178 inet_ntoa(bp_server_addr), ntohs(bp_server_port)));
179
180 /* We have just done a portmap call, so cache the portnum. */
181 rpc_pmap_putcache(bp_server_addr,
182 BOOTPARAM_PROG,
183 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 goto done;
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 goto done;
201 }
202
203 /* domain name */
204 domainnamelen = MAXHOSTNAMELEN-1;
205 if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) {
206 RPC_PRINTF(("bp_whoami: bad domainname\n"));
207 goto done;
208 }
209
210 /* gateway address */
211 if (xdr_inaddr_decode(&recv_head, &gateip)) {
212 RPC_PRINTF(("bp_whoami: bad gateway\n"));
213 goto done;
214 }
215
216 /* success */
217 rc = 0;
218 done:
219 free(pkt);
220 return (rc);
221 }
222
223
224 /*
225 * RPC: bootparam/getfile
226 * Given client name and file "key", get:
227 * server name
228 * server IP address
229 * server pathname
230 */
231 int
bp_getfile(int sockfd,char * key,struct in_addr * serv_addr,char * pathname)232 bp_getfile(int sockfd, char *key, struct in_addr *serv_addr, char *pathname)
233 {
234 struct {
235 n_long h[RPC_HEADER_WORDS];
236 n_long d[64];
237 } sdata;
238 void *pkt;
239 char serv_name[FNAME_SIZE];
240 char *rdata, *send_tail;
241 /* misc... */
242 struct iodesc *d;
243 int rc = -1, sn_len, path_len, rlen;
244
245 if (!(d = socktodesc(sockfd))) {
246 RPC_PRINTF(("bp_getfile: bad socket. %d\n", sockfd));
247 return (-1);
248 }
249
250 send_tail = (char*) sdata.d;
251
252 /*
253 * Build request message.
254 */
255
256 /* client name (hostname) */
257 if (xdr_string_encode(&send_tail, hostname, hostnamelen)) {
258 RPC_PRINTF(("bp_getfile: bad client\n"));
259 return (-1);
260 }
261
262 /* key name (root or swap) */
263 if (xdr_string_encode(&send_tail, key, strlen(key))) {
264 RPC_PRINTF(("bp_getfile: bad key\n"));
265 return (-1);
266 }
267
268 /* RPC: bootparam/getfile */
269 d->myport = htons(--rpc_port);
270 d->destip = bp_server_addr;
271 /* rpc_call will set d->destport */
272 pkt = NULL;
273 rlen = rpc_call(d,
274 BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE,
275 sdata.d, send_tail - (char*)sdata.d,
276 (void **)&rdata, &pkt);
277 if (rlen < 4) {
278 RPC_PRINTF(("bp_getfile: short reply\n"));
279 errno = EBADRPC;
280 goto done;
281 }
282
283 /*
284 * Parse result message.
285 */
286
287 /* server name */
288 sn_len = FNAME_SIZE-1;
289 if (xdr_string_decode(&rdata, serv_name, &sn_len)) {
290 RPC_PRINTF(("bp_getfile: bad server name\n"));
291 goto done;
292 }
293
294 /* server IP address (mountd/NFS) */
295 if (xdr_inaddr_decode(&rdata, serv_addr)) {
296 RPC_PRINTF(("bp_getfile: bad server addr\n"));
297 goto done;
298 }
299
300 /* server pathname */
301 path_len = MAXPATHLEN-1;
302 if (xdr_string_decode(&rdata, pathname, &path_len)) {
303 RPC_PRINTF(("bp_getfile: bad server path\n"));
304 goto done;
305 }
306
307 /* success */
308 rc = 0;
309 done:
310 free(pkt);
311 return (rc);
312 }
313
314
315 /*
316 * eXternal Data Representation routines.
317 * (but with non-standard args...)
318 */
319
320
321 int
xdr_string_encode(char ** pkt,char * str,int len)322 xdr_string_encode(char **pkt, char *str, int len)
323 {
324 uint32_t *lenp;
325 char *datap;
326 int padlen = (len + 3) & ~3; /* padded length */
327
328 /* The data will be int aligned. */
329 lenp = (uint32_t *) *pkt;
330 *pkt += sizeof(*lenp);
331 *lenp = htonl(len);
332
333 datap = *pkt;
334 *pkt += padlen;
335 bcopy(str, datap, len);
336
337 return (0);
338 }
339
340 int
xdr_string_decode(char ** pkt,char * str,int * len_p)341 xdr_string_decode(char **pkt, char *str, int *len_p)
342 {
343 uint32_t *lenp;
344 char *datap;
345 int slen; /* string length */
346 int plen; /* padded length */
347
348 /* The data will be int aligned. */
349 lenp = (uint32_t *) *pkt;
350 *pkt += sizeof(*lenp);
351 slen = ntohl(*lenp);
352 plen = (slen + 3) & ~3;
353
354 if (slen > *len_p)
355 slen = *len_p;
356 datap = *pkt;
357 *pkt += plen;
358 bcopy(datap, str, slen);
359
360 str[slen] = '\0';
361 *len_p = slen;
362
363 return (0);
364 }
365
366
367 int
xdr_inaddr_encode(char ** pkt,struct in_addr ia)368 xdr_inaddr_encode(char **pkt, struct in_addr ia)
369 {
370 struct xdr_inaddr *xi;
371 u_char *cp;
372 int32_t *ip;
373 union {
374 n_long l; /* network order */
375 u_char c[4];
376 } uia;
377
378 /* The data will be int aligned. */
379 xi = (struct xdr_inaddr *) *pkt;
380 *pkt += sizeof(*xi);
381 xi->atype = htonl(1);
382 uia.l = ia.s_addr;
383 cp = uia.c;
384 ip = xi->addr;
385 /*
386 * Note: the htonl() calls below DO NOT
387 * imply that uia.l is in host order.
388 * In fact this needs it in net order.
389 */
390 *ip++ = htonl((unsigned int)*cp++);
391 *ip++ = htonl((unsigned int)*cp++);
392 *ip++ = htonl((unsigned int)*cp++);
393 *ip++ = htonl((unsigned int)*cp++);
394
395 return (0);
396 }
397
398 int
xdr_inaddr_decode(char ** pkt,struct in_addr * ia)399 xdr_inaddr_decode(char **pkt, struct in_addr *ia)
400 {
401 struct xdr_inaddr *xi;
402 u_char *cp;
403 int32_t *ip;
404 union {
405 n_long l; /* network order */
406 u_char c[4];
407 } uia;
408
409 /* The data will be int aligned. */
410 xi = (struct xdr_inaddr *) *pkt;
411 *pkt += sizeof(*xi);
412 if (xi->atype != htonl(1)) {
413 RPC_PRINTF(("xdr_inaddr_decode: bad addrtype=%d\n",
414 ntohl(xi->atype)));
415 return(-1);
416 }
417
418 cp = uia.c;
419 ip = xi->addr;
420 /*
421 * Note: the ntohl() calls below DO NOT
422 * imply that uia.l is in host order.
423 * In fact this needs it in net order.
424 */
425 *cp++ = ntohl(*ip++);
426 *cp++ = ntohl(*ip++);
427 *cp++ = ntohl(*ip++);
428 *cp++ = ntohl(*ip++);
429 ia->s_addr = uia.l;
430
431 return (0);
432 }
433