You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /*
  2. * Copyright (C) 2013 Marin Hannache <ipxe@mareo.fr>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. */
  19. #include <stdint.h>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <assert.h>
  24. #include <errno.h>
  25. #include <byteswap.h>
  26. #include <ipxe/socket.h>
  27. #include <ipxe/tcpip.h>
  28. #include <ipxe/in.h>
  29. #include <ipxe/iobuf.h>
  30. #include <ipxe/dhcp.h>
  31. #include <ipxe/xfer.h>
  32. #include <ipxe/open.h>
  33. #include <ipxe/uri.h>
  34. #include <ipxe/features.h>
  35. #include <ipxe/oncrpc.h>
  36. #include <ipxe/oncrpc_iob.h>
  37. #include <ipxe/init.h>
  38. #include <ipxe/settings.h>
  39. #include <ipxe/version.h>
  40. /** @file
  41. *
  42. * SUN ONC RPC protocol
  43. *
  44. */
  45. /** Set most significant bit to 1. */
  46. #define SET_LAST_FRAME( x ) ( (x) | 1 << 31 )
  47. #define GET_FRAME_SIZE( x ) ( (x) & ~( 1 << 31 ) )
  48. #define ONCRPC_CALL 0
  49. #define ONCRPC_REPLY 1
  50. /** AUTH NONE authentication flavor */
  51. struct oncrpc_cred oncrpc_auth_none = {
  52. .flavor = ONCRPC_AUTH_NONE,
  53. .length = 0
  54. };
  55. const struct setting uid_setting __setting ( SETTING_AUTH, uid ) = {
  56. .name = "uid",
  57. .description = "User ID",
  58. .tag = DHCP_EB_UID,
  59. .type = &setting_type_uint32
  60. };
  61. const struct setting gid_setting __setting ( SETTING_AUTH, gid ) = {
  62. .name = "gid",
  63. .description = "Group ID",
  64. .tag = DHCP_EB_GID,
  65. .type = &setting_type_uint32
  66. };
  67. /**
  68. * Initialize an ONC RPC AUTH SYS credential structure
  69. *
  70. * @v auth_sys The structure to initialize
  71. *
  72. * The hostname field is filled with the value of the hostname setting, if the
  73. * hostname setting is empty, PRODUCT_SHORT_NAME (usually "iPXE") is used
  74. * instead.
  75. */
  76. int oncrpc_init_cred_sys ( struct oncrpc_cred_sys *auth_sys ) {
  77. if ( ! auth_sys )
  78. return -EINVAL;
  79. fetch_string_setting_copy ( NULL, &hostname_setting,
  80. &auth_sys->hostname );
  81. if ( ! auth_sys->hostname )
  82. if ( ! ( auth_sys->hostname = strdup ( product_short_name ) ) )
  83. return -ENOMEM;
  84. auth_sys->uid = fetch_uintz_setting ( NULL, &uid_setting );
  85. auth_sys->gid = fetch_uintz_setting ( NULL, &uid_setting );
  86. auth_sys->aux_gid_len = 0;
  87. auth_sys->stamp = 0;
  88. auth_sys->credential.flavor = ONCRPC_AUTH_SYS;
  89. auth_sys->credential.length = 16 +
  90. oncrpc_strlen ( auth_sys->hostname );
  91. return 0;
  92. }
  93. /**
  94. * Prepare an ONC RPC session structure to be used by the ONC RPC layer
  95. *
  96. * @v session ONC RPC session
  97. * @v credential Credential structure pointer
  98. * @v verifier Verifier structure pointer
  99. * @v prog_name ONC RPC program number
  100. * @v prog_vers ONC RPC program version number
  101. */
  102. void oncrpc_init_session ( struct oncrpc_session *session,
  103. struct oncrpc_cred *credential,
  104. struct oncrpc_cred *verifier, uint32_t prog_name,
  105. uint32_t prog_vers ) {
  106. if ( ! session )
  107. return;
  108. session->rpc_id = rand();
  109. session->credential = credential;
  110. session->verifier = verifier;
  111. session->prog_name = prog_name;
  112. session->prog_vers = prog_vers;
  113. }
  114. int oncrpc_call ( struct interface *intf, struct oncrpc_session *session,
  115. uint32_t proc_name, const struct oncrpc_field fields[] ) {
  116. size_t frame_size;
  117. struct io_buffer *io_buf;
  118. if ( ! session )
  119. return -EINVAL;
  120. struct oncrpc_field header[] = {
  121. ONCRPC_FIELD ( int32, 0 ),
  122. ONCRPC_FIELD ( int32, ++session->rpc_id ),
  123. ONCRPC_FIELD ( int32, ONCRPC_CALL ),
  124. ONCRPC_FIELD ( int32, ONCRPC_VERS ),
  125. ONCRPC_FIELD ( int32, session->prog_name ),
  126. ONCRPC_FIELD ( int32, session->prog_vers ),
  127. ONCRPC_FIELD ( int32, proc_name ),
  128. ONCRPC_FIELD ( cred, session->credential ),
  129. ONCRPC_FIELD ( cred, session->verifier ),
  130. ONCRPC_FIELD_END,
  131. };
  132. frame_size = oncrpc_compute_size ( header );
  133. frame_size += oncrpc_compute_size ( fields );
  134. io_buf = alloc_iob ( frame_size );
  135. if ( ! io_buf )
  136. return -ENOBUFS;
  137. header[0].value.int32 = SET_LAST_FRAME ( frame_size -
  138. sizeof ( uint32_t ) );
  139. oncrpc_iob_add_fields ( io_buf, header );
  140. oncrpc_iob_add_fields ( io_buf, fields );
  141. return xfer_deliver_iob ( intf, iob_disown ( io_buf ) );
  142. }
  143. size_t oncrpc_compute_size ( const struct oncrpc_field fields[] ) {
  144. size_t i;
  145. size_t size = 0;
  146. for ( i = 0; fields[i].type != oncrpc_none; i++ ) {
  147. switch ( fields[i].type ) {
  148. case oncrpc_int32:
  149. size += sizeof ( uint32_t );
  150. break;
  151. case oncrpc_int64:
  152. size += sizeof ( uint64_t );
  153. break;
  154. case oncrpc_str:
  155. size += oncrpc_strlen ( fields[i].value.str );
  156. break;
  157. case oncrpc_array:
  158. size += oncrpc_align ( fields[i].value.array.length );
  159. size += sizeof ( uint32_t );
  160. break;
  161. case oncrpc_intarray:
  162. size += sizeof ( uint32_t ) *
  163. fields[i].value.intarray.length;
  164. size += sizeof ( uint32_t );
  165. break;
  166. case oncrpc_cred:
  167. size += fields[i].value.cred->length;
  168. size += 2 * sizeof ( uint32_t );
  169. break;
  170. default:
  171. return size;
  172. }
  173. }
  174. return size;
  175. }
  176. /**
  177. * Parse an I/O buffer to extract a ONC RPC REPLY
  178. * @v session ONC RPC session
  179. * @v reply Reply structure where data will be saved
  180. * @v io_buf I/O buffer
  181. */
  182. int oncrpc_get_reply ( struct oncrpc_session *session __unused,
  183. struct oncrpc_reply *reply, struct io_buffer *io_buf ) {
  184. if ( ! reply || ! io_buf )
  185. return -EINVAL;
  186. reply->frame_size = GET_FRAME_SIZE ( oncrpc_iob_get_int ( io_buf ) );
  187. reply->rpc_id = oncrpc_iob_get_int ( io_buf );
  188. /* iPXE has no support for handling ONC RPC call */
  189. if ( oncrpc_iob_get_int ( io_buf ) != ONCRPC_REPLY )
  190. return -ENOSYS;
  191. reply->reply_state = oncrpc_iob_get_int ( io_buf );
  192. if ( reply->reply_state == 0 )
  193. {
  194. /* verifier.flavor */
  195. oncrpc_iob_get_int ( io_buf );
  196. /* verifier.length */
  197. iob_pull ( io_buf, oncrpc_iob_get_int ( io_buf ));
  198. /* We don't use the verifier in iPXE, let it be an empty
  199. verifier. */
  200. reply->verifier = &oncrpc_auth_none;
  201. }
  202. reply->accept_state = oncrpc_iob_get_int ( io_buf );
  203. reply->data = io_buf;
  204. return 0;
  205. }