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 u_int32_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(sockfd) 108 int sockfd; 109 { 110 /* RPC structures for PMAPPROC_CALLIT */ 111 struct args { 112 u_int32_t prog; 113 u_int32_t vers; 114 u_int32_t proc; 115 u_int32_t arglen; 116 struct xdr_inaddr xina; 117 } *args; 118 struct repl { 119 u_int16_t _pad; 120 u_int16_t port; 121 u_int32_t encap_len; 122 /* encapsulated data here */ 123 n_long capsule[64]; 124 } *repl; 125 struct { 126 n_long h[RPC_HEADER_WORDS]; 127 struct args d; 128 } sdata; 129 struct { 130 n_long h[RPC_HEADER_WORDS]; 131 struct repl d; 132 } rdata; 133 char *send_tail, *recv_head; 134 struct iodesc *d; 135 int len, x; 136 137 RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip))); 138 139 if (!(d = socktodesc(sockfd))) { 140 RPC_PRINTF(("bp_whoami: bad socket. %d\n", sockfd)); 141 return (-1); 142 } 143 args = &sdata.d; 144 repl = &rdata.d; 145 146 /* 147 * Build request args for PMAPPROC_CALLIT. 148 */ 149 args->prog = htonl(BOOTPARAM_PROG); 150 args->vers = htonl(BOOTPARAM_VERS); 151 args->proc = htonl(BOOTPARAM_WHOAMI); 152 args->arglen = htonl(sizeof(struct xdr_inaddr)); 153 send_tail = (char*) &args->xina; 154 155 /* 156 * append encapsulated data (client IP address) 157 */ 158 if (xdr_inaddr_encode(&send_tail, myip)) 159 return (-1); 160 161 /* RPC: portmap/callit */ 162 d->myport = htons(--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, send_tail - (char*)args, 168 repl, sizeof(*repl)); 169 if (len < 8) { 170 printf("bootparamd: 'whoami' call failed\n"); 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(("bp_whoami: server at %s:%d\n", 185 inet_ntoa(bp_server_addr), ntohs(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(bp_server_port)); 192 193 /* 194 * Parse the encapsulated results from bootparam/whoami 195 */ 196 x = ntohl(repl->encap_len); 197 if (len < x) { 198 printf("bp_whoami: short reply, %d < %d\n", 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(("bp_whoami: bad hostname\n")); 207 return (-1); 208 } 209 210 /* domain name */ 211 domainnamelen = MAXHOSTNAMELEN-1; 212 if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) { 213 RPC_PRINTF(("bp_whoami: bad domainname\n")); 214 return (-1); 215 } 216 217 /* gateway address */ 218 if (xdr_inaddr_decode(&recv_head, &gateip)) { 219 RPC_PRINTF(("bp_whoami: bad gateway\n")); 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(sockfd, key, serv_addr, pathname) 237 int sockfd; 238 char *key; 239 char *pathname; 240 struct in_addr *serv_addr; 241 { 242 struct { 243 n_long h[RPC_HEADER_WORDS]; 244 n_long d[64]; 245 } sdata; 246 struct { 247 n_long h[RPC_HEADER_WORDS]; 248 n_long d[128]; 249 } rdata; 250 char serv_name[FNAME_SIZE]; 251 char *send_tail, *recv_head; 252 /* misc... */ 253 struct iodesc *d; 254 int sn_len, path_len, rlen; 255 256 if (!(d = socktodesc(sockfd))) { 257 RPC_PRINTF(("bp_getfile: bad socket. %d\n", sockfd)); 258 return (-1); 259 } 260 261 send_tail = (char*) sdata.d; 262 recv_head = (char*) rdata.d; 263 264 /* 265 * Build request message. 266 */ 267 268 /* client name (hostname) */ 269 if (xdr_string_encode(&send_tail, hostname, hostnamelen)) { 270 RPC_PRINTF(("bp_getfile: bad client\n")); 271 return (-1); 272 } 273 274 /* key name (root or swap) */ 275 if (xdr_string_encode(&send_tail, key, strlen(key))) { 276 RPC_PRINTF(("bp_getfile: bad key\n")); 277 return (-1); 278 } 279 280 /* RPC: bootparam/getfile */ 281 d->myport = htons(--rpc_port); 282 d->destip = bp_server_addr; 283 /* rpc_call will set d->destport */ 284 285 rlen = rpc_call(d, 286 BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE, 287 sdata.d, send_tail - (char*)sdata.d, 288 rdata.d, sizeof(rdata.d)); 289 if (rlen < 4) { 290 RPC_PRINTF(("bp_getfile: short reply\n")); 291 errno = EBADRPC; 292 return (-1); 293 } 294 recv_head = (char*) rdata.d; 295 296 /* 297 * Parse result message. 298 */ 299 300 /* server name */ 301 sn_len = FNAME_SIZE-1; 302 if (xdr_string_decode(&recv_head, serv_name, &sn_len)) { 303 RPC_PRINTF(("bp_getfile: bad server name\n")); 304 return (-1); 305 } 306 307 /* server IP address (mountd/NFS) */ 308 if (xdr_inaddr_decode(&recv_head, serv_addr)) { 309 RPC_PRINTF(("bp_getfile: bad server addr\n")); 310 return (-1); 311 } 312 313 /* server pathname */ 314 path_len = MAXPATHLEN-1; 315 if (xdr_string_decode(&recv_head, pathname, &path_len)) { 316 RPC_PRINTF(("bp_getfile: bad server path\n")); 317 return (-1); 318 } 319 320 /* success */ 321 return(0); 322 } 323 324 325 /* 326 * eXternal Data Representation routines. 327 * (but with non-standard args...) 328 */ 329 330 331 int 332 xdr_string_encode(pkt, str, len) 333 char **pkt; 334 char *str; 335 int len; 336 { 337 u_int32_t *lenp; 338 char *datap; 339 int padlen = (len + 3) & ~3; /* padded length */ 340 341 /* The data will be int aligned. */ 342 lenp = (u_int32_t*) *pkt; 343 *pkt += sizeof(*lenp); 344 *lenp = htonl(len); 345 346 datap = *pkt; 347 *pkt += padlen; 348 bcopy(str, datap, len); 349 350 return (0); 351 } 352 353 int 354 xdr_string_decode(pkt, str, len_p) 355 char **pkt; 356 char *str; 357 int *len_p; /* bufsize - 1 */ 358 { 359 u_int32_t *lenp; 360 char *datap; 361 int slen; /* string length */ 362 int plen; /* padded length */ 363 364 /* The data will be int aligned. */ 365 lenp = (u_int32_t*) *pkt; 366 *pkt += sizeof(*lenp); 367 slen = ntohl(*lenp); 368 plen = (slen + 3) & ~3; 369 370 if (slen > *len_p) 371 slen = *len_p; 372 datap = *pkt; 373 *pkt += plen; 374 bcopy(datap, str, slen); 375 376 str[slen] = '\0'; 377 *len_p = slen; 378 379 return (0); 380 } 381 382 383 int 384 xdr_inaddr_encode(pkt, ia) 385 char **pkt; 386 struct in_addr ia; /* network order */ 387 { 388 struct xdr_inaddr *xi; 389 u_char *cp; 390 int32_t *ip; 391 union { 392 n_long l; /* network order */ 393 u_char c[4]; 394 } uia; 395 396 /* The data will be int aligned. */ 397 xi = (struct xdr_inaddr *) *pkt; 398 *pkt += sizeof(*xi); 399 xi->atype = htonl(1); 400 uia.l = ia.s_addr; 401 cp = uia.c; 402 ip = xi->addr; 403 /* 404 * Note: the htonl() calls below DO NOT 405 * imply that uia.l is in host order. 406 * In fact this needs it in net order. 407 */ 408 *ip++ = htonl((unsigned int)*cp++); 409 *ip++ = htonl((unsigned int)*cp++); 410 *ip++ = htonl((unsigned int)*cp++); 411 *ip++ = htonl((unsigned int)*cp++); 412 413 return (0); 414 } 415 416 int 417 xdr_inaddr_decode(pkt, ia) 418 char **pkt; 419 struct in_addr *ia; /* network order */ 420 { 421 struct xdr_inaddr *xi; 422 u_char *cp; 423 int32_t *ip; 424 union { 425 n_long l; /* network order */ 426 u_char c[4]; 427 } uia; 428 429 /* The data will be int aligned. */ 430 xi = (struct xdr_inaddr *) *pkt; 431 *pkt += sizeof(*xi); 432 if (xi->atype != htonl(1)) { 433 RPC_PRINTF(("xdr_inaddr_decode: bad addrtype=%d\n", 434 ntohl(xi->atype))); 435 return(-1); 436 } 437 438 cp = uia.c; 439 ip = xi->addr; 440 /* 441 * Note: the ntohl() calls below DO NOT 442 * imply that uia.l is in host order. 443 * In fact this needs it in net order. 444 */ 445 *cp++ = ntohl(*ip++); 446 *cp++ = ntohl(*ip++); 447 *cp++ = ntohl(*ip++); 448 *cp++ = ntohl(*ip++); 449 ia->s_addr = uia.l; 450 451 return (0); 452 } 453