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