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