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 54struct in_addr bp_server_addr; /* net order */ 55u_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 */ 69struct xdr_inaddr { 70 u_int32_t atype; 71 int32_t addr[4]; 72}; 73 74int xdr_inaddr_encode(char **p, struct in_addr ia); 75int xdr_inaddr_decode(char **p, struct in_addr *ia); 76 77int xdr_string_encode(char **p, char *str, int len); 78int 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 */ 96int 97bp_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 */ 222int 223bp_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 313int 314xdr_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 332int 333xdr_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 358int 359xdr_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 389int 390xdr_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