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