2010-10-13 04:15:41 +04:00
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd .
2010-10-14 02:40:39 +04:00
Copyright 2010 Lennart Poettering
2010-10-13 04:15:41 +04:00
systemd is free software ; you can redistribute it and / or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
systemd 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
General Public License for more details .
You should have received a copy of the GNU General Public License
along with systemd ; If not , see < http : //www.gnu.org/licenses/>.
* * */
# include <stdlib.h>
# include <errno.h>
# include <string.h>
# include <unistd.h>
2011-10-11 17:16:52 +04:00
# include <sys/capability.h>
2010-10-13 04:15:41 +04:00
2011-04-03 20:16:59 +04:00
# ifdef HAVE_SELINUX
# include <selinux/selinux.h>
# endif
2010-10-13 04:15:41 +04:00
# include "util.h"
# include "condition.h"
2011-09-23 19:09:49 +04:00
# include "virt.h"
2010-10-13 04:15:41 +04:00
2011-03-08 05:04:47 +03:00
Condition * condition_new ( ConditionType type , const char * parameter , bool trigger , bool negate ) {
2010-10-13 04:15:41 +04:00
Condition * c ;
2011-07-07 04:07:39 +04:00
assert ( type < _CONDITION_TYPE_MAX ) ;
2011-09-21 02:44:51 +04:00
c = new0 ( Condition , 1 ) ;
if ( ! c )
2011-03-31 17:35:40 +04:00
return NULL ;
2010-10-13 04:15:41 +04:00
c - > type = type ;
2011-03-08 05:04:47 +03:00
c - > trigger = trigger ;
2010-10-13 04:15:41 +04:00
c - > negate = negate ;
2011-09-21 02:44:51 +04:00
if ( parameter ) {
c - > parameter = strdup ( parameter ) ;
if ( ! c - > parameter ) {
2010-11-11 00:28:19 +03:00
free ( c ) ;
return NULL ;
}
2011-09-21 02:44:51 +04:00
}
2010-10-13 04:15:41 +04:00
return c ;
}
void condition_free ( Condition * c ) {
assert ( c ) ;
free ( c - > parameter ) ;
free ( c ) ;
}
void condition_free_list ( Condition * first ) {
Condition * c , * n ;
LIST_FOREACH_SAFE ( conditions , c , n , first )
condition_free ( c ) ;
}
static bool test_kernel_command_line ( const char * parameter ) {
char * line , * w , * state , * word = NULL ;
bool equal ;
int r ;
size_t l , pl ;
bool found = false ;
2011-02-22 00:07:55 +03:00
assert ( parameter ) ;
2011-09-20 01:51:15 +04:00
if ( detect_container ( NULL ) > 0 )
2011-03-15 01:41:47 +03:00
return false ;
2011-09-21 02:44:51 +04:00
r = read_one_line_file ( " /proc/cmdline " , & line ) ;
if ( r < 0 ) {
2010-10-13 04:15:41 +04:00
log_warning ( " Failed to read /proc/cmdline, ignoring: %s " , strerror ( - r ) ) ;
return false ;
}
equal = ! ! strchr ( parameter , ' = ' ) ;
pl = strlen ( parameter ) ;
FOREACH_WORD_QUOTED ( w , l , line , state ) {
free ( word ) ;
2011-09-21 02:44:51 +04:00
word = strndup ( w , l ) ;
if ( ! word )
2010-10-13 04:15:41 +04:00
break ;
if ( equal ) {
if ( streq ( word , parameter ) ) {
found = true ;
break ;
}
} else {
if ( startswith ( word , parameter ) & & ( word [ pl ] = = ' = ' | | word [ pl ] = = 0 ) ) {
found = true ;
break ;
}
}
}
free ( word ) ;
free ( line ) ;
return found ;
}
2011-02-22 00:07:55 +03:00
static bool test_virtualization ( const char * parameter ) {
2011-09-23 19:09:49 +04:00
int b ;
Virtualization v ;
2011-02-22 00:07:55 +03:00
const char * id ;
assert ( parameter ) ;
2011-09-23 19:09:49 +04:00
v = detect_virtualization ( & id ) ;
if ( v < 0 ) {
log_warning ( " Failed to detect virtualization, ignoring: %s " , strerror ( - v ) ) ;
2011-02-22 00:07:55 +03:00
return false ;
}
2011-09-23 19:09:49 +04:00
/* First, compare with yes/no */
2011-02-22 00:07:55 +03:00
b = parse_boolean ( parameter ) ;
2011-09-23 19:09:49 +04:00
if ( v > 0 & & b > 0 )
return true ;
if ( v = = 0 & & b = = 0 )
return true ;
/* Then, compare categorization */
if ( v = = VIRTUALIZATION_VM & & streq ( parameter , " vm " ) )
2011-02-22 00:07:55 +03:00
return true ;
2011-09-23 19:09:49 +04:00
if ( v = = VIRTUALIZATION_CONTAINER & & streq ( parameter , " container " ) )
2011-02-22 00:07:55 +03:00
return true ;
2011-09-23 19:09:49 +04:00
/* Finally compare id */
2011-10-09 18:36:45 +04:00
return v > 0 & & streq ( parameter , id ) ;
2011-02-22 00:07:55 +03:00
}
2011-04-03 20:16:59 +04:00
static bool test_security ( const char * parameter ) {
# ifdef HAVE_SELINUX
2011-04-04 00:18:35 +04:00
if ( streq ( parameter , " selinux " ) )
2011-04-03 20:16:59 +04:00
return is_selinux_enabled ( ) > 0 ;
# endif
return false ;
}
2011-10-11 17:16:52 +04:00
static bool test_capability ( const char * parameter ) {
cap_value_t value ;
FILE * f ;
char line [ LINE_MAX ] ;
unsigned long long capabilities = ( unsigned long long ) - 1 ;
/* If it's an invalid capability, we don't have it */
if ( cap_from_name ( parameter , & value ) < 0 )
return false ;
/* If it's a valid capability we default to assume
* that we have it */
f = fopen ( " /proc/self/status " , " re " ) ;
if ( ! f )
return true ;
while ( fgets ( line , sizeof ( line ) , f ) ) {
truncate_nl ( line ) ;
if ( startswith ( line , " CapBnd: " ) ) {
( void ) sscanf ( line + 7 , " %llx " , & capabilities ) ;
break ;
}
}
2011-10-26 11:38:39 +04:00
fclose ( f ) ;
2011-10-11 17:16:52 +04:00
return ! ! ( capabilities & ( 1ULL < < value ) ) ;
}
2010-10-13 04:15:41 +04:00
bool condition_test ( Condition * c ) {
assert ( c ) ;
switch ( c - > type ) {
case CONDITION_PATH_EXISTS :
return ( access ( c - > parameter , F_OK ) > = 0 ) = = ! c - > negate ;
2011-07-07 04:07:39 +04:00
case CONDITION_PATH_EXISTS_GLOB :
return ( glob_exists ( c - > parameter ) > 0 ) = = ! c - > negate ;
2011-03-25 07:07:20 +03:00
case CONDITION_PATH_IS_DIRECTORY : {
struct stat st ;
2011-09-21 03:07:25 +04:00
if ( stat ( c - > parameter , & st ) < 0 )
2011-09-23 04:10:00 +04:00
return c - > negate ;
2011-03-25 07:07:20 +03:00
return S_ISDIR ( st . st_mode ) = = ! c - > negate ;
}
2011-09-21 03:29:38 +04:00
case CONDITION_PATH_IS_SYMBOLIC_LINK : {
struct stat st ;
if ( lstat ( c - > parameter , & st ) < 0 )
2011-09-23 04:10:00 +04:00
return c - > negate ;
2011-09-21 03:29:38 +04:00
return S_ISLNK ( st . st_mode ) = = ! c - > negate ;
}
2011-09-21 02:44:51 +04:00
case CONDITION_PATH_IS_MOUNT_POINT :
return ( path_is_mount_point ( c - > parameter , true ) > 0 ) = = ! c - > negate ;
2010-11-15 22:06:49 +03:00
case CONDITION_DIRECTORY_NOT_EMPTY : {
int k ;
k = dir_is_empty ( c - > parameter ) ;
return ! ( k = = - ENOENT | | k > 0 ) = = ! c - > negate ;
}
2011-07-12 06:25:02 +04:00
case CONDITION_FILE_IS_EXECUTABLE : {
struct stat st ;
2011-09-20 03:28:00 +04:00
if ( stat ( c - > parameter , & st ) < 0 )
2011-09-23 04:10:00 +04:00
return c - > negate ;
2011-07-12 06:25:02 +04:00
return ( S_ISREG ( st . st_mode ) & & ( st . st_mode & 0111 ) ) = = ! c - > negate ;
}
2010-10-13 04:15:41 +04:00
case CONDITION_KERNEL_COMMAND_LINE :
2011-02-22 00:10:04 +03:00
return test_kernel_command_line ( c - > parameter ) = = ! c - > negate ;
2010-10-13 04:15:41 +04:00
2011-02-22 00:07:55 +03:00
case CONDITION_VIRTUALIZATION :
2011-02-22 00:10:04 +03:00
return test_virtualization ( c - > parameter ) = = ! c - > negate ;
2011-02-22 00:07:55 +03:00
2011-04-03 20:16:59 +04:00
case CONDITION_SECURITY :
return test_security ( c - > parameter ) = = ! c - > negate ;
2011-10-11 17:16:52 +04:00
case CONDITION_CAPABILITY :
return test_capability ( c - > parameter ) = = ! c - > negate ;
2010-11-11 00:28:19 +03:00
case CONDITION_NULL :
return ! c - > negate ;
2010-10-13 04:15:41 +04:00
default :
assert_not_reached ( " Invalid condition type. " ) ;
}
}
bool condition_test_list ( Condition * first ) {
Condition * c ;
2011-03-08 05:04:47 +03:00
int triggered = - 1 ;
2010-10-13 04:15:41 +04:00
/* If the condition list is empty, then it is true */
if ( ! first )
return true ;
2011-03-08 05:04:47 +03:00
/* Otherwise, if all of the non-trigger conditions apply and
* if any of the trigger conditions apply ( unless there are
* none ) we return true */
LIST_FOREACH ( conditions , c , first ) {
bool b ;
b = condition_test ( c ) ;
if ( ! c - > trigger & & ! b )
return false ;
if ( c - > trigger & & triggered < = 0 )
triggered = b ;
}
2010-10-13 04:15:41 +04:00
2011-03-08 05:04:47 +03:00
return triggered ! = 0 ;
2010-10-13 04:15:41 +04:00
}
void condition_dump ( Condition * c , FILE * f , const char * prefix ) {
assert ( c ) ;
assert ( f ) ;
if ( ! prefix )
prefix = " " ;
fprintf ( f ,
2011-04-03 20:16:48 +04:00
" %s \t %s: %s%s%s \n " ,
2010-10-13 04:15:41 +04:00
prefix ,
condition_type_to_string ( c - > type ) ,
2011-03-08 05:04:47 +03:00
c - > trigger ? " | " : " " ,
2010-10-13 04:15:41 +04:00
c - > negate ? " ! " : " " ,
c - > parameter ) ;
}
void condition_dump_list ( Condition * first , FILE * f , const char * prefix ) {
Condition * c ;
LIST_FOREACH ( conditions , c , first )
condition_dump ( c , f , prefix ) ;
}
static const char * const condition_type_table [ _CONDITION_TYPE_MAX ] = {
2010-11-11 00:28:19 +03:00
[ CONDITION_PATH_EXISTS ] = " ConditionPathExists " ,
2011-07-07 04:07:39 +04:00
[ CONDITION_PATH_EXISTS_GLOB ] = " ConditionPathExistsGlob " ,
2011-04-03 20:16:48 +04:00
[ CONDITION_PATH_IS_DIRECTORY ] = " ConditionPathIsDirectory " ,
2011-09-21 03:29:38 +04:00
[ CONDITION_PATH_IS_SYMBOLIC_LINK ] = " ConditionPathIsSymbolicLink " ,
2011-09-21 02:44:51 +04:00
[ CONDITION_PATH_IS_MOUNT_POINT ] = " ConditionPathIsMountPoint " ,
2011-04-03 20:16:48 +04:00
[ CONDITION_DIRECTORY_NOT_EMPTY ] = " ConditionDirectoryNotEmpty " ,
[ CONDITION_KERNEL_COMMAND_LINE ] = " ConditionKernelCommandLine " ,
[ CONDITION_VIRTUALIZATION ] = " ConditionVirtualization " ,
2011-04-03 20:16:59 +04:00
[ CONDITION_SECURITY ] = " ConditionSecurity " ,
2010-11-11 00:28:19 +03:00
[ CONDITION_NULL ] = " ConditionNull "
2010-10-13 04:15:41 +04:00
} ;
DEFINE_STRING_TABLE_LOOKUP ( condition_type , ConditionType ) ;