bootparam.c 9.9 KB

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