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