1 /* $OpenBSD: bootparam.c,v 1.7 1996/12/08 15:15:47 niklas Exp $ */ 2 /* $NetBSD: bootparam.c,v 1.10 1996/10/14 21:16:55 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 1995 Gordon W. Ross 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 4. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by Gordon W. Ross 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 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 <nfs/rpcv2.h> 47 48 #include "stand.h" 49 #include "net.h" 50 #include "netif.h" 51 #include "rpc.h" 52 #include "bootparam.h" 53 54 #ifdef DEBUG_RPC 55 #define RPC_PRINTF(a) printf a 56 #else 57 #define RPC_PRINTF(a) 58 #endif 59 60 struct in_addr bp_server_addr; /* net order */ 61 n_short bp_server_port; /* net order */ 62 63 /* 64 * RPC definitions for bootparamd 65 */ 66 #define BOOTPARAM_PROG 100026 67 #define BOOTPARAM_VERS 1 68 #define BOOTPARAM_WHOAMI 1 69 #define BOOTPARAM_GETFILE 2 70 71 /* 72 * Inet address in RPC messages 73 * (Note, really four ints, NOT chars. Blech.) 74 */ 75 struct xdr_inaddr { 76 u_int32_t atype; 77 int32_t addr[4]; 78 }; 79 80 int xdr_inaddr_encode __P((char **p, struct in_addr ia)); 81 int xdr_inaddr_decode __P((char **p, struct in_addr *ia)); 82 83 int xdr_string_encode __P((char **p, char *str, int len)); 84 int xdr_string_decode __P((char **p, char *str, int *len_p)); 85 86 87 /* 88 * RPC: bootparam/whoami 89 * Given client IP address, get: 90 * client name (hostname) 91 * domain name (domainname) 92 * gateway address 93 * 94 * The hostname and domainname are set here for convenience. 95 * 96 * Note - bpsin is initialized to the broadcast address, 97 * and will be replaced with the bootparam server address 98 * after this call is complete. Have to use PMAP_PROC_CALL 99 * to make sure we get responses only from a servers that 100 * know about us (don't want to broadcast a getport call). 101 */ 102 int 103 bp_whoami(sockfd) 104 int sockfd; 105 { 106 /* RPC structures for PMAPPROC_CALLIT */ 107 struct args { 108 u_int32_t prog; 109 u_int32_t vers; 110 u_int32_t proc; 111 u_int32_t arglen; 112 struct xdr_inaddr xina; 113 } *args; 114 struct repl { 115 u_int16_t _pad; 116 u_int16_t port; 117 u_int32_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 struct { 126 n_long h[RPC_HEADER_WORDS]; 127 struct repl d; 128 } rdata; 129 char *send_tail, *recv_head; 130 struct iodesc *d; 131 int len, x; 132 133 RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip))); 134 135 if (!(d = socktodesc(sockfd))) { 136 RPC_PRINTF(("bp_whoami: bad socket. %d\n", sockfd)); 137 return (-1); 138 } 139 args = &sdata.d; 140 repl = &rdata.d; 141 142 /* 143 * Build request args for PMAPPROC_CALLIT. 144 */ 145 args->prog = htonl(BOOTPARAM_PROG); 146 args->vers = htonl(BOOTPARAM_VERS); 147 args->proc = htonl(BOOTPARAM_WHOAMI); 148 args->arglen = htonl(sizeof(struct xdr_inaddr)); 149 send_tail = (char*) &args->xina; 150 151 /* 152 * append encapsulated data (client IP address) 153 */ 154 if (xdr_inaddr_encode(&send_tail, myip)) 155 return (-1); 156 157 /* RPC: portmap/callit */ 158 d->myport = htons(--rpc_port); 159 d->destip.s_addr = INADDR_BROADCAST; /* XXX: subnet bcast? */ 160 /* rpc_call will set d->destport */ 161 162 len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT, 163 args, send_tail - (char*)args, 164 repl, sizeof(*repl)); 165 if (len < 8) { 166 printf("bootparamd: 'whoami' call failed\n"); 167 return (-1); 168 } 169 170 /* Save bootparam server address (from IP header). */ 171 rpc_fromaddr(repl, &bp_server_addr, &bp_server_port); 172 173 /* 174 * Note that bp_server_port is now 111 due to the 175 * indirect call (using PMAPPROC_CALLIT), so get the 176 * actual port number from the reply data. 177 */ 178 bp_server_port = repl->port; 179 180 RPC_PRINTF(("bp_whoami: server at %s:%d\n", 181 inet_ntoa(bp_server_addr), ntohs(bp_server_port))); 182 183 /* We have just done a portmap call, so cache the portnum. */ 184 rpc_pmap_putcache(bp_server_addr, 185 BOOTPARAM_PROG, 186 BOOTPARAM_VERS, 187 (int)ntohs(bp_server_port)); 188 189 /* 190 * Parse the encapsulated results from bootparam/whoami 191 */ 192 x = ntohl(repl->encap_len); 193 if (len < x) { 194 printf("bp_whoami: short reply, %d < %d\n", len, x); 195 return (-1); 196 } 197 recv_head = (char*) repl->capsule; 198 199 /* client name */ 200 hostnamelen = MAXHOSTNAMELEN-1; 201 if (xdr_string_decode(&recv_head, hostname, &hostnamelen)) { 202 RPC_PRINTF(("bp_whoami: bad hostname\n")); 203 return (-1); 204 } 205 206 /* domain name */ 207 domainnamelen = MAXHOSTNAMELEN-1; 208 if (xdr_string_decode(&recv_head, domainname, &domainnamelen)) { 209 RPC_PRINTF(("bp_whoami: bad domainname\n")); 210 return (-1); 211 } 212 213 /* gateway address */ 214 if (xdr_inaddr_decode(&recv_head, &gateip)) { 215 RPC_PRINTF(("bp_whoami: bad gateway\n")); 216 return (-1); 217 } 218 219 /* success */ 220 return(0); 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(sockfd, key, serv_addr, pathname) 233 int sockfd; 234 char *key; 235 char *pathname; 236 struct in_addr *serv_addr; 237 { 238 struct { 239 n_long h[RPC_HEADER_WORDS]; 240 n_long d[64]; 241 } sdata; 242 struct { 243 n_long h[RPC_HEADER_WORDS]; 244 n_long d[128]; 245 } rdata; 246 char serv_name[FNAME_SIZE]; 247 char *send_tail, *recv_head; 248 /* misc... */ 249 struct iodesc *d; 250 int sn_len, path_len, rlen; 251 252 if (!(d = socktodesc(sockfd))) { 253 RPC_PRINTF(("bp_getfile: bad socket. %d\n", sockfd)); 254 return (-1); 255 } 256 257 send_tail = (char*) sdata.d; 258 recv_head = (char*) rdata.d; 259 260 /* 261 * Build request message. 262 */ 263 264 /* client name (hostname) */ 265 if (xdr_string_encode(&send_tail, hostname, hostnamelen)) { 266 RPC_PRINTF(("bp_getfile: bad client\n")); 267 return (-1); 268 } 269 270 /* key name (root or swap) */ 271 if (xdr_string_encode(&send_tail, key, strlen(key))) { 272 RPC_PRINTF(("bp_getfile: bad key\n")); 273 return (-1); 274 } 275 276 /* RPC: bootparam/getfile */ 277 d->myport = htons(--rpc_port); 278 d->destip = bp_server_addr; 279 /* rpc_call will set d->destport */ 280 281 rlen = rpc_call(d, 282 BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE, 283 sdata.d, send_tail - (char*)sdata.d, 284 rdata.d, sizeof(rdata.d)); 285 if (rlen < 4) { 286 RPC_PRINTF(("bp_getfile: short reply\n")); 287 errno = EBADRPC; 288 return (-1); 289 } 290 recv_head = (char*) rdata.d; 291 292 /* 293 * Parse result message. 294 */ 295 296 /* server name */ 297 sn_len = FNAME_SIZE-1; 298 if (xdr_string_decode(&recv_head, serv_name, &sn_len)) { 299 RPC_PRINTF(("bp_getfile: bad server name\n")); 300 return (-1); 301 } 302 303 /* server IP address (mountd/NFS) */ 304 if (xdr_inaddr_decode(&recv_head, serv_addr)) { 305 RPC_PRINTF(("bp_getfile: bad server addr\n")); 306 return (-1); 307 } 308 309 /* server pathname */ 310 path_len = MAXPATHLEN-1; 311 if (xdr_string_decode(&recv_head, pathname, &path_len)) { 312 RPC_PRINTF(("bp_getfile: bad server path\n")); 313 return (-1); 314 } 315 316 /* success */ 317 return(0); 318 } 319 320 321 /* 322 * eXternal Data Representation routines. 323 * (but with non-standard args...) 324 */ 325 326 327 int 328 xdr_string_encode(pkt, str, len) 329 char **pkt; 330 char *str; 331 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 int 350 xdr_string_decode(pkt, str, len_p) 351 char **pkt; 352 char *str; 353 int *len_p; /* bufsize - 1 */ 354 { 355 u_int32_t *lenp; 356 char *datap; 357 int slen; /* string length */ 358 int plen; /* padded length */ 359 360 /* The data will be int aligned. */ 361 lenp = (u_int32_t*) *pkt; 362 *pkt += sizeof(*lenp); 363 slen = ntohl(*lenp); 364 plen = (slen + 3) & ~3; 365 366 if (slen > *len_p) 367 slen = *len_p; 368 datap = *pkt; 369 *pkt += plen; 370 bcopy(datap, str, slen); 371 372 str[slen] = '\0'; 373 *len_p = slen; 374 375 return (0); 376 } 377 378 379 int 380 xdr_inaddr_encode(pkt, ia) 381 char **pkt; 382 struct in_addr ia; /* network order */ 383 { 384 struct xdr_inaddr *xi; 385 u_char *cp; 386 int32_t *ip; 387 union { 388 n_long l; /* network order */ 389 u_char c[4]; 390 } uia; 391 392 /* The data will be int aligned. */ 393 xi = (struct xdr_inaddr *) *pkt; 394 *pkt += sizeof(*xi); 395 xi->atype = htonl(1); 396 uia.l = ia.s_addr; 397 cp = uia.c; 398 ip = xi->addr; 399 /* 400 * Note: the htonl() calls below DO NOT 401 * imply that uia.l is in host order. 402 * In fact this needs it in net order. 403 */ 404 *ip++ = htonl((unsigned int)*cp++); 405 *ip++ = htonl((unsigned int)*cp++); 406 *ip++ = htonl((unsigned int)*cp++); 407 *ip++ = htonl((unsigned int)*cp++); 408 409 return (0); 410 } 411 412 int 413 xdr_inaddr_decode(pkt, ia) 414 char **pkt; 415 struct in_addr *ia; /* network order */ 416 { 417 struct xdr_inaddr *xi; 418 u_char *cp; 419 int32_t *ip; 420 union { 421 n_long l; /* network order */ 422 u_char c[4]; 423 } uia; 424 425 /* The data will be int aligned. */ 426 xi = (struct xdr_inaddr *) *pkt; 427 *pkt += sizeof(*xi); 428 if (xi->atype != htonl(1)) { 429 RPC_PRINTF(("xdr_inaddr_decode: bad addrtype=%d\n", 430 ntohl(xi->atype))); 431 return(-1); 432 } 433 434 cp = uia.c; 435 ip = xi->addr; 436 /* 437 * Note: the ntohl() calls below DO NOT 438 * imply that uia.l is in host order. 439 * In fact this needs it in net order. 440 */ 441 *cp++ = ntohl(*ip++); 442 *cp++ = ntohl(*ip++); 443 *cp++ = ntohl(*ip++); 444 *cp++ = ntohl(*ip++); 445 ia->s_addr = uia.l; 446 447 return (0); 448 } 449