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