2 * Copyright (C) 2013 Marin Hannache <ipxe@mareo.fr>.
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.
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.
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
27 #include <ipxe/socket.h>
28 #include <ipxe/tcpip.h>
30 #include <ipxe/iobuf.h>
31 #include <ipxe/dhcp.h>
32 #include <ipxe/xfer.h>
33 #include <ipxe/open.h>
35 #include <ipxe/features.h>
36 #include <ipxe/oncrpc.h>
37 #include <ipxe/oncrpc_iob.h>
38 #include <ipxe/init.h>
39 #include <ipxe/settings.h>
40 #include <ipxe/version.h>
44 * SUN ONC RPC protocol
48 /** Set most significant bit to 1. */
49 #define SET_LAST_FRAME( x ) ( (x) | 1 << 31 )
50 #define GET_FRAME_SIZE( x ) ( (x) & ~( 1 << 31 ) )
53 #define ONCRPC_REPLY 1
55 /** AUTH NONE authentication flavor */
56 struct oncrpc_cred oncrpc_auth_none = {
57 .flavor = ONCRPC_AUTH_NONE,
61 const struct setting uid_setting __setting ( SETTING_AUTH, uid ) = {
63 .description = "User ID",
65 .type = &setting_type_uint32
68 const struct setting gid_setting __setting ( SETTING_AUTH, gid ) = {
70 .description = "Group ID",
72 .type = &setting_type_uint32
76 * Initialize an ONC RPC AUTH SYS credential structure
78 * @v auth_sys The structure to initialize
80 * The hostname field is filled with the value of the hostname setting, if the
81 * hostname setting is empty, PRODUCT_SHORT_NAME (usually "iPXE") is used
84 int oncrpc_init_cred_sys ( struct oncrpc_cred_sys *auth_sys ) {
88 fetch_string_setting_copy ( NULL, &hostname_setting,
89 &auth_sys->hostname );
90 if ( ! auth_sys->hostname )
91 if ( ! ( auth_sys->hostname = strdup ( product_short_name ) ) )
94 auth_sys->uid = fetch_uintz_setting ( NULL, &uid_setting );
95 auth_sys->gid = fetch_uintz_setting ( NULL, &uid_setting );
96 auth_sys->aux_gid_len = 0;
99 auth_sys->credential.flavor = ONCRPC_AUTH_SYS;
100 auth_sys->credential.length = 16 +
101 oncrpc_strlen ( auth_sys->hostname );
107 * Prepare an ONC RPC session structure to be used by the ONC RPC layer
109 * @v session ONC RPC session
110 * @v credential Credential structure pointer
111 * @v verifier Verifier structure pointer
112 * @v prog_name ONC RPC program number
113 * @v prog_vers ONC RPC program version number
115 void oncrpc_init_session ( struct oncrpc_session *session,
116 struct oncrpc_cred *credential,
117 struct oncrpc_cred *verifier, uint32_t prog_name,
118 uint32_t prog_vers ) {
122 session->rpc_id = rand();
123 session->credential = credential;
124 session->verifier = verifier;
125 session->prog_name = prog_name;
126 session->prog_vers = prog_vers;
129 int oncrpc_call ( struct interface *intf, struct oncrpc_session *session,
130 uint32_t proc_name, const struct oncrpc_field fields[] ) {
133 struct io_buffer *io_buf;
138 struct oncrpc_field header[] = {
139 ONCRPC_FIELD ( int32, 0 ),
140 ONCRPC_FIELD ( int32, ++session->rpc_id ),
141 ONCRPC_FIELD ( int32, ONCRPC_CALL ),
142 ONCRPC_FIELD ( int32, ONCRPC_VERS ),
143 ONCRPC_FIELD ( int32, session->prog_name ),
144 ONCRPC_FIELD ( int32, session->prog_vers ),
145 ONCRPC_FIELD ( int32, proc_name ),
146 ONCRPC_FIELD ( cred, session->credential ),
147 ONCRPC_FIELD ( cred, session->verifier ),
151 frame_size = oncrpc_compute_size ( header );
152 frame_size += oncrpc_compute_size ( fields );
154 io_buf = alloc_iob ( frame_size );
158 header[0].value.int32 = SET_LAST_FRAME ( frame_size -
159 sizeof ( uint32_t ) );
161 oncrpc_iob_add_fields ( io_buf, header );
162 oncrpc_iob_add_fields ( io_buf, fields );
164 rc = xfer_deliver_iob ( intf, io_buf );
171 size_t oncrpc_compute_size ( const struct oncrpc_field fields[] ) {
176 for ( i = 0; fields[i].type != oncrpc_none; i++ ) {
177 switch ( fields[i].type ) {
179 size += sizeof ( uint32_t );
183 size += sizeof ( uint64_t );
187 size += oncrpc_strlen ( fields[i].value.str );
191 size += oncrpc_align ( fields[i].value.array.length );
192 size += sizeof ( uint32_t );
195 case oncrpc_intarray:
196 size += sizeof ( uint32_t ) *
197 fields[i].value.intarray.length;
198 size += sizeof ( uint32_t );
202 size += fields[i].value.cred->length;
203 size += 2 * sizeof ( uint32_t );
215 * Parse an I/O buffer to extract a ONC RPC REPLY
216 * @v session ONC RPC session
217 * @v reply Reply structure where data will be saved
218 * @v io_buf I/O buffer
220 int oncrpc_get_reply ( struct oncrpc_session *session __unused,
221 struct oncrpc_reply *reply, struct io_buffer *io_buf ) {
222 if ( ! reply || ! io_buf )
225 reply->frame_size = GET_FRAME_SIZE ( oncrpc_iob_get_int ( io_buf ) );
226 reply->rpc_id = oncrpc_iob_get_int ( io_buf );
228 /* iPXE has no support for handling ONC RPC call */
229 if ( oncrpc_iob_get_int ( io_buf ) != ONCRPC_REPLY )
232 reply->reply_state = oncrpc_iob_get_int ( io_buf );
234 if ( reply->reply_state == 0 )
236 /* verifier.flavor */
237 oncrpc_iob_get_int ( io_buf );
238 /* verifier.length */
239 iob_pull ( io_buf, oncrpc_iob_get_int ( io_buf ));
241 /* We don't use the verifier in iPXE, let it be an empty
243 reply->verifier = &oncrpc_auth_none;
246 reply->accept_state = oncrpc_iob_get_int ( io_buf );
247 reply->data = io_buf;