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