iPXE
oncrpc_iob.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2013 Marin Hannache <ipxe@mareo.fr>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  */
00019 
00020 #include <stdint.h>
00021 #include <stdlib.h>
00022 #include <stdio.h>
00023 #include <string.h>
00024 #include <assert.h>
00025 #include <errno.h>
00026 #include <byteswap.h>
00027 #include <ipxe/socket.h>
00028 #include <ipxe/tcpip.h>
00029 #include <ipxe/in.h>
00030 #include <ipxe/iobuf.h>
00031 #include <ipxe/xfer.h>
00032 #include <ipxe/open.h>
00033 #include <ipxe/uri.h>
00034 #include <ipxe/features.h>
00035 #include <ipxe/oncrpc.h>
00036 #include <ipxe/oncrpc_iob.h>
00037 
00038 /** @file
00039  *
00040  * SUN ONC RPC protocol
00041  *
00042  */
00043 
00044 size_t oncrpc_iob_add_fields ( struct io_buffer *io_buf,
00045                                const struct oncrpc_field fields[] ) {
00046         size_t i;
00047         size_t s = 0;
00048 
00049         struct oncrpc_field f;
00050 
00051         if ( ! io_buf )
00052                 return 0;
00053 
00054         for ( i = 0; fields[i].type != oncrpc_none; i++ ) {
00055                 f = fields[i];
00056                 switch ( f.type ) {
00057                 case oncrpc_int32:
00058                         s += oncrpc_iob_add_int ( io_buf, f.value.int32 );
00059                         break;
00060 
00061                 case oncrpc_int64:
00062                         s += oncrpc_iob_add_int64 ( io_buf, f.value.int64 );
00063                         break;
00064 
00065                 case oncrpc_str:
00066                         s += oncrpc_iob_add_string ( io_buf, f.value.str );
00067                         break;
00068 
00069                 case oncrpc_array:
00070                         s += oncrpc_iob_add_array ( io_buf,
00071                                                     f.value.array.length,
00072                                                     f.value.array.ptr );
00073                         break;
00074 
00075                 case oncrpc_intarray:
00076                         s += oncrpc_iob_add_intarray ( io_buf,
00077                                                        f.value.intarray.length,
00078                                                        f.value.intarray.ptr );
00079                         break;
00080 
00081                 case oncrpc_cred:
00082                         s += oncrpc_iob_add_cred ( io_buf, f.value.cred);
00083                         break;
00084 
00085                 default:
00086                         return s;
00087                 }
00088         }
00089 
00090         return s;
00091 }
00092 
00093 /**
00094  * Add an array of bytes to the end of an I/O buffer
00095  *
00096  * @v io_buf            I/O buffer
00097  * @v val               String
00098  * @ret size            Size of the data written
00099  *
00100  * In the ONC RPC protocol, every data is four byte paded, we add padding when
00101  * necessary by using oncrpc_align()
00102  */
00103 size_t oncrpc_iob_add_array ( struct io_buffer *io_buf, size_t length,
00104                               const void *data ) {
00105         size_t padding = oncrpc_align ( length ) - length;
00106 
00107         oncrpc_iob_add_int ( io_buf, length );
00108         memcpy ( iob_put ( io_buf, length ), data, length );
00109         memset ( iob_put ( io_buf, padding ), 0, padding );
00110 
00111         return length + padding + sizeof ( uint32_t );
00112 }
00113 
00114 /**
00115  * Add an int array to the end of an I/O buffer
00116  *
00117  * @v io_buf            I/O buffer
00118  * @v length            Length od the array
00119  * @v val               Int array
00120  * @ret size            Size of the data written
00121  */
00122 size_t oncrpc_iob_add_intarray ( struct io_buffer *io_buf, size_t length,
00123                                  const uint32_t *array ) {
00124         size_t                  i;
00125 
00126         oncrpc_iob_add_int ( io_buf, length );
00127 
00128         for ( i = 0; i < length; ++i )
00129                 oncrpc_iob_add_int ( io_buf, array[i] );
00130 
00131         return ( ( length + 1 ) * sizeof ( uint32_t ) );
00132 }
00133 
00134 /**
00135  * Add credential information to the end of an I/O buffer
00136  *
00137  * @v io_buf            I/O buffer
00138  * @v cred              Credential information
00139  * @ret size            Size of the data written
00140  */
00141 size_t oncrpc_iob_add_cred ( struct io_buffer *io_buf,
00142                              const struct oncrpc_cred *cred ) {
00143         struct oncrpc_cred_sys  *syscred;
00144         size_t                  s;
00145 
00146         struct oncrpc_field credfields[] = {
00147                 ONCRPC_FIELD ( int32, cred->flavor ),
00148                 ONCRPC_FIELD ( int32, cred->length ),
00149                 ONCRPC_FIELD_END,
00150         };
00151 
00152         if ( ! io_buf || ! cred )
00153                 return 0;
00154 
00155         s  = oncrpc_iob_add_fields ( io_buf, credfields);
00156 
00157         switch ( cred->flavor ) {
00158         case ONCRPC_AUTH_NONE:
00159                 break;
00160 
00161         case ONCRPC_AUTH_SYS:
00162                 syscred = container_of ( cred, struct oncrpc_cred_sys,
00163                                          credential );
00164 
00165                 struct oncrpc_field syscredfields[] = {
00166                         ONCRPC_FIELD ( int32, syscred->stamp ),
00167                         ONCRPC_FIELD ( str, syscred->hostname ),
00168                         ONCRPC_FIELD ( int32, syscred->uid ),
00169                         ONCRPC_FIELD ( int32, syscred->gid ),
00170                         ONCRPC_SUBFIELD ( intarray, syscred->aux_gid_len,
00171                                           syscred->aux_gid ),
00172                         ONCRPC_FIELD_END,
00173                 };
00174 
00175                 s += oncrpc_iob_add_fields ( io_buf, syscredfields );
00176                 break;
00177         }
00178 
00179         return s;
00180 }
00181 
00182 /**
00183  * Get credential information from the beginning of an I/O buffer
00184  *
00185  * @v io_buf            I/O buffer
00186  * @v cred              Struct where the information will be saved
00187  * @ret size            Size of the data read
00188  */
00189 size_t oncrpc_iob_get_cred ( struct io_buffer *io_buf,
00190                              struct oncrpc_cred *cred ) {
00191         if ( cred == NULL )
00192                 return * ( uint32_t * ) io_buf->data;
00193 
00194         cred->flavor = oncrpc_iob_get_int ( io_buf );
00195         cred->length = oncrpc_iob_get_int ( io_buf );
00196 
00197         iob_pull ( io_buf, cred->length );
00198 
00199         return ( 2 * sizeof ( uint32_t ) + cred->length );
00200 }