2019-07-31 10:40:39 +01:00
/*
* libvirt_nss_macs . c : Name Service Switch plugin MAC file parser
*
* Copyright ( C ) 2019 Red Hat , Inc .
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library . If not , see
* < http : //www.gnu.org/licenses/>.
*/
# include <config.h>
# include <unistd.h>
# include <string.h>
# include <stdlib.h>
# include <fcntl.h>
# include <yajl/yajl_gen.h>
# include <yajl/yajl_parse.h>
# include "libvirt_nss_macs.h"
2019-07-31 10:40:39 +01:00
# include "libvirt_nss.h"
2019-07-31 10:40:39 +01:00
enum {
FIND_MACS_STATE_START ,
FIND_MACS_STATE_LIST ,
FIND_MACS_STATE_ENTRY ,
FIND_MACS_STATE_ENTRY_MACS ,
} ;
typedef struct {
const char * name ;
char * * * macs ;
size_t * nmacs ;
int state ;
char * key ;
struct {
char * name ;
char * * macs ;
size_t nmacs ;
} entry ;
} findMACsParser ;
static int
findMACsParserString ( void * ctx ,
const unsigned char * stringVal ,
size_t stringLen )
{
findMACsParser * parser = ctx ;
DEBUG ( " Parse string state=%d '%.*s' (map key '%s') " ,
parser - > state , ( int ) stringLen , ( const char * ) stringVal ,
NULLSTR ( parser - > key ) ) ;
if ( ! parser - > key )
return 0 ;
if ( parser - > state = = FIND_MACS_STATE_ENTRY ) {
2019-08-08 10:23:26 +01:00
if ( strcmp ( parser - > key , " domain " ) )
2019-08-09 10:25:22 +02:00
return 1 ;
2019-07-31 10:40:39 +01:00
free ( parser - > entry . name ) ;
if ( ! ( parser - > entry . name = strndup ( ( char * ) stringVal , stringLen ) ) )
return 0 ;
} else if ( parser - > state = = FIND_MACS_STATE_ENTRY_MACS ) {
char * * macs ;
2019-08-08 10:23:26 +01:00
if ( strcmp ( parser - > key , " macs " ) )
2019-08-09 10:25:22 +02:00
return 1 ;
2019-07-31 10:40:39 +01:00
if ( ! ( macs = realloc ( parser - > entry . macs ,
sizeof ( char * ) * ( parser - > entry . nmacs + 1 ) ) ) )
return 0 ;
parser - > entry . macs = macs ;
if ( ! ( macs [ parser - > entry . nmacs + + ] = strndup ( ( char * ) stringVal , stringLen ) ) )
return 0 ;
} else {
return 0 ;
}
return 1 ;
}
static int
findMACsParserMapKey ( void * ctx ,
const unsigned char * stringVal ,
size_t stringLen )
{
findMACsParser * parser = ctx ;
DEBUG ( " Parse map key state=%d '%.*s' " ,
parser - > state , ( int ) stringLen , ( const char * ) stringVal ) ;
free ( parser - > key ) ;
if ( ! ( parser - > key = strndup ( ( char * ) stringVal , stringLen ) ) )
return 0 ;
return 1 ;
}
static int
findMACsParserStartMap ( void * ctx )
{
findMACsParser * parser = ctx ;
DEBUG ( " Parse start map state=%d " , parser - > state ) ;
if ( parser - > state ! = FIND_MACS_STATE_LIST )
return 0 ;
free ( parser - > key ) ;
parser - > key = NULL ;
parser - > state = FIND_MACS_STATE_ENTRY ;
return 1 ;
}
static int
findMACsParserEndMap ( void * ctx )
{
findMACsParser * parser = ctx ;
size_t i ;
DEBUG ( " Parse end map state=%d " , parser - > state ) ;
if ( parser - > entry . name = = NULL )
return 0 ;
if ( parser - > state ! = FIND_MACS_STATE_ENTRY )
return 0 ;
2019-08-08 10:23:26 +01:00
if ( ! strcmp ( parser - > entry . name , parser - > name ) ) {
2019-07-31 10:40:39 +01:00
char * * macs = realloc ( * parser - > macs ,
sizeof ( char * ) * ( ( * parser - > nmacs ) + parser - > entry . nmacs ) ) ;
if ( ! macs )
return 0 ;
* parser - > macs = macs ;
for ( i = 0 ; i < parser - > entry . nmacs ; i + + )
( * parser - > macs ) [ ( * parser - > nmacs ) + + ] = parser - > entry . macs [ i ] ;
} else {
for ( i = 0 ; i < parser - > entry . nmacs ; i + + )
free ( parser - > entry . macs [ i ] ) ;
}
free ( parser - > entry . macs ) ;
parser - > entry . macs = NULL ;
parser - > entry . nmacs = 0 ;
parser - > state = FIND_MACS_STATE_LIST ;
return 1 ;
}
static int
findMACsParserStartArray ( void * ctx )
{
findMACsParser * parser = ctx ;
DEBUG ( " Parse start array state=%d " , parser - > state ) ;
if ( parser - > state = = FIND_MACS_STATE_START )
parser - > state = FIND_MACS_STATE_LIST ;
else if ( parser - > state = = FIND_MACS_STATE_ENTRY )
parser - > state = FIND_MACS_STATE_ENTRY_MACS ;
else
return 0 ;
return 1 ;
}
static int
findMACsParserEndArray ( void * ctx )
{
findMACsParser * parser = ctx ;
DEBUG ( " Parse end array state=%d " , parser - > state ) ;
if ( parser - > state = = FIND_MACS_STATE_LIST )
parser - > state = FIND_MACS_STATE_START ;
else if ( parser - > state = = FIND_MACS_STATE_ENTRY_MACS )
parser - > state = FIND_MACS_STATE_ENTRY ;
else
return 0 ;
return 1 ;
}
int
findMACs ( const char * file ,
const char * name ,
char * * * macs ,
size_t * nmacs )
{
int fd = - 1 ;
int ret = - 1 ;
const yajl_callbacks parserCallbacks = {
NULL , /* null */
NULL , /* bool */
NULL , /* integer */
NULL , /* double */
NULL , /* number */
findMACsParserString ,
findMACsParserStartMap ,
findMACsParserMapKey ,
findMACsParserEndMap ,
findMACsParserStartArray ,
findMACsParserEndArray ,
} ;
findMACsParser parserState = {
. name = name ,
. macs = macs ,
. nmacs = nmacs ,
} ;
yajl_handle parser = NULL ;
char line [ 1024 ] ;
size_t i ;
int rv ;
if ( ( fd = open ( file , O_RDONLY ) ) < 0 ) {
ERROR ( " Cannot open %s " , file ) ;
goto cleanup ;
}
parser = yajl_alloc ( & parserCallbacks , NULL , & parserState ) ;
if ( ! parser ) {
ERROR ( " Unable to create JSON parser " ) ;
goto cleanup ;
}
while ( 1 ) {
rv = read ( fd , line , sizeof ( line ) ) ;
if ( rv < 0 )
goto cleanup ;
if ( rv = = 0 )
break ;
if ( yajl_parse ( parser , ( const unsigned char * ) line , rv ) ! =
yajl_status_ok ) {
2019-08-09 10:37:05 +02:00
unsigned char * err = yajl_get_error ( parser , 1 ,
( const unsigned char * ) line , rv ) ;
ERROR ( " Parse failed %s " , ( const char * ) err ) ;
yajl_free_error ( parser , err ) ;
2019-07-31 10:40:39 +01:00
goto cleanup ;
}
}
if ( yajl_complete_parse ( parser ) ! = yajl_status_ok ) {
ERROR ( " Parse failed %s " ,
yajl_get_error ( parser , 1 , NULL , 0 ) ) ;
goto cleanup ;
}
ret = 0 ;
cleanup :
if ( ret ! = 0 ) {
for ( i = 0 ; i < * nmacs ; i + + ) {
char * mac = ( * macs ) [ i ] ;
free ( mac ) ;
}
free ( * macs ) ;
* macs = NULL ;
* nmacs = 0 ;
}
2020-03-30 10:37:09 +02:00
if ( parser )
yajl_free ( parser ) ;
2019-07-31 10:40:39 +01:00
for ( i = 0 ; i < parserState . entry . nmacs ; i + + )
free ( parserState . entry . macs [ i ] ) ;
free ( parserState . entry . macs ) ;
free ( parserState . entry . name ) ;
free ( parserState . key ) ;
if ( fd ! = - 1 )
close ( fd ) ;
return ret ;
}