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