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