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