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