Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/libsa/bootparam.c
34677 views
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
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
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
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
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
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
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
434