1 /* $OpenBSD: bootparam.c,v 1.11 2003/08/11 06:23:09 deraadt 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) /* 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(char **p, struct in_addr ia); 81 int xdr_inaddr_decode(char **p, struct in_addr *ia); 82 83 int xdr_string_encode(char **p, char *str, int len); 84 int xdr_string_decode(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(int sockfd) 104 { 105 /* RPC structures for PMAPPROC_CALLIT */ 106 struct args { 107 u_int32_t prog; 108 u_int32_t vers; 109 u_int32_t proc; 110 u_int32_t arglen; 111 struct xdr_inaddr xina; 112 } *args; 113 struct repl { 114 u_int16_t _pad; 115 u_int16_t port; 116 u_int32_t encap_len; 117 /* encapsulated data here */ 118 n_long capsule[64]; 119 } *repl; 120 struct { 121 n_long h[RPC_HEADER_WORDS]; 122 struct args d; 123 } sdata; 124 struct { 125 n_long h[RPC_HEADER_WORDS]; 126 struct repl d; 127 } rdata; 128 char *send_tail, *recv_head; 129 struct iodesc *d; 130 int len, x; 131 132 RPC_PRINTF(("bp_whoami: myip=%s\n", inet_ntoa(myip))); 133 134 if (!(d = socktodesc(sockfd))) { 135 RPC_PRINTF(("bp_whoami: bad socket. %d\n", sockfd)); 136 return (-1); 137 } 138 args = &sdata.d; 139 repl = &rdata.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 (-1); 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 len = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT, 162 args, send_tail - (char *)args, 163 repl, sizeof(*repl)); 164 if (len < 8) { 165 printf("bootparamd: 'whoami' call failed\n"); 166 return (-1); 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, BOOTPARAM_PROG, 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 return (-1); 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 return (-1); 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 return (-1); 208 } 209 210 /* gateway address */ 211 if (xdr_inaddr_decode(&recv_head, &gateip)) { 212 RPC_PRINTF(("bp_whoami: bad gateway\n")); 213 return (-1); 214 } 215 216 /* success */ 217 return(0); 218 } 219 220 221 /* 222 * RPC: bootparam/getfile 223 * Given client name and file "key", get: 224 * server name 225 * server IP address 226 * server pathname 227 */ 228 int 229 bp_getfile(int sockfd, char *key, struct in_addr *serv_addr, char *pathname) 230 { 231 struct { 232 n_long h[RPC_HEADER_WORDS]; 233 n_long d[64]; 234 } sdata; 235 struct { 236 n_long h[RPC_HEADER_WORDS]; 237 n_long d[128]; 238 } rdata; 239 char serv_name[FNAME_SIZE]; 240 char *send_tail, *recv_head; 241 /* misc... */ 242 struct iodesc *d; 243 int 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 recv_head = (char *)rdata.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 274 rlen = rpc_call(d, 275 BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE, 276 sdata.d, send_tail - (char *)sdata.d, 277 rdata.d, sizeof(rdata.d)); 278 if (rlen < 4) { 279 RPC_PRINTF(("bp_getfile: short reply\n")); 280 errno = EBADRPC; 281 return (-1); 282 } 283 recv_head = (char *)rdata.d; 284 285 /* 286 * Parse result message. 287 */ 288 289 /* server name */ 290 sn_len = FNAME_SIZE-1; 291 if (xdr_string_decode(&recv_head, serv_name, &sn_len)) { 292 RPC_PRINTF(("bp_getfile: bad server name\n")); 293 return (-1); 294 } 295 296 /* server IP address (mountd/NFS) */ 297 if (xdr_inaddr_decode(&recv_head, serv_addr)) { 298 RPC_PRINTF(("bp_getfile: bad server addr\n")); 299 return (-1); 300 } 301 302 /* server pathname */ 303 path_len = MAXPATHLEN-1; 304 if (xdr_string_decode(&recv_head, pathname, &path_len)) { 305 RPC_PRINTF(("bp_getfile: bad server path\n")); 306 return (-1); 307 } 308 309 /* success */ 310 return(0); 311 } 312 313 314 /* 315 * eXternal Data Representation routines. 316 * (but with non-standard args...) 317 */ 318 319 int 320 xdr_string_encode(char **pkt, char *str, int len) 321 { 322 u_int32_t *lenp; 323 char *datap; 324 int padlen = (len + 3) & ~3; /* padded length */ 325 326 /* The data will be int aligned. */ 327 lenp = (u_int32_t*) *pkt; 328 *pkt += sizeof(*lenp); 329 *lenp = htonl(len); 330 331 datap = *pkt; 332 *pkt += padlen; 333 bcopy(str, datap, len); 334 335 return (0); 336 } 337 338 int 339 xdr_string_decode(char **pkt, char *str, int *len_p) 340 { 341 u_int32_t *lenp; 342 char *datap; 343 int slen; /* string length */ 344 int plen; /* padded length */ 345 346 /* The data will be int aligned. */ 347 lenp = (u_int32_t*) *pkt; 348 *pkt += sizeof(*lenp); 349 slen = ntohl(*lenp); 350 plen = (slen + 3) & ~3; 351 352 if (slen > *len_p) 353 slen = *len_p; 354 datap = *pkt; 355 *pkt += plen; 356 bcopy(datap, str, slen); 357 358 str[slen] = '\0'; 359 *len_p = slen; 360 361 return (0); 362 } 363 364 int 365 xdr_inaddr_encode(char **pkt, struct in_addr ia) 366 { 367 struct xdr_inaddr *xi; 368 u_char *cp; 369 int32_t *ip; 370 union { 371 n_long l; /* network order */ 372 u_char c[4]; 373 } uia; 374 375 /* The data will be int aligned. */ 376 xi = (struct xdr_inaddr *) *pkt; 377 *pkt += sizeof(*xi); 378 xi->atype = htonl(1); 379 uia.l = ia.s_addr; 380 cp = uia.c; 381 ip = xi->addr; 382 /* 383 * Note: the htonl() calls below DO NOT 384 * imply that uia.l is in host order. 385 * In fact this needs it in net order. 386 */ 387 *ip++ = htonl((unsigned int)*cp++); 388 *ip++ = htonl((unsigned int)*cp++); 389 *ip++ = htonl((unsigned int)*cp++); 390 *ip++ = htonl((unsigned int)*cp++); 391 392 return (0); 393 } 394 395 int 396 xdr_inaddr_decode(char **pkt, struct in_addr *ia) 397 { 398 struct xdr_inaddr *xi; 399 u_char *cp; 400 int32_t *ip; 401 union { 402 n_long l; /* network order */ 403 u_char c[4]; 404 } uia; 405 406 /* The data will be int aligned. */ 407 xi = (struct xdr_inaddr *) *pkt; 408 *pkt += sizeof(*xi); 409 if (xi->atype != htonl(1)) { 410 RPC_PRINTF(("xdr_inaddr_decode: bad addrtype=%d\n", 411 ntohl(xi->atype))); 412 return(-1); 413 } 414 415 cp = uia.c; 416 ip = xi->addr; 417 /* 418 * Note: the ntohl() calls below DO NOT 419 * imply that uia.l is in host order. 420 * In fact this needs it in net order. 421 */ 422 *cp++ = ntohl(*ip++); 423 *cp++ = ntohl(*ip++); 424 *cp++ = ntohl(*ip++); 425 *cp++ = ntohl(*ip++); 426 ia->s_addr = uia.l; 427 428 return (0); 429 } 430