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