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