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