TOMOYO: Use struct for passing ACL line.
Use structure for passing ACL line, in preparation for supporting policy namespace and conditional parameters. Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp> Signed-off-by: James Morris <jmorris@namei.org>
This commit is contained in:
parent
0df7e8b8f1
commit
a238cf5b89
8 changed files with 348 additions and 372 deletions
|
@ -611,8 +611,11 @@ static int tomoyo_update_manager_entry(const char *manager,
|
||||||
const bool is_delete)
|
const bool is_delete)
|
||||||
{
|
{
|
||||||
struct tomoyo_manager e = { };
|
struct tomoyo_manager e = { };
|
||||||
int error;
|
struct tomoyo_acl_param param = {
|
||||||
|
.is_delete = is_delete,
|
||||||
|
.list = &tomoyo_policy_list[TOMOYO_ID_MANAGER],
|
||||||
|
};
|
||||||
|
int error = is_delete ? -ENOENT : -ENOMEM;
|
||||||
if (tomoyo_domain_def(manager)) {
|
if (tomoyo_domain_def(manager)) {
|
||||||
if (!tomoyo_correct_domain(manager))
|
if (!tomoyo_correct_domain(manager))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -622,12 +625,11 @@ static int tomoyo_update_manager_entry(const char *manager,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
e.manager = tomoyo_get_name(manager);
|
e.manager = tomoyo_get_name(manager);
|
||||||
if (!e.manager)
|
if (e.manager) {
|
||||||
return -ENOMEM;
|
error = tomoyo_update_policy(&e.head, sizeof(e), ¶m,
|
||||||
error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
|
tomoyo_same_manager);
|
||||||
&tomoyo_policy_list[TOMOYO_ID_MANAGER],
|
tomoyo_put_name(e.manager);
|
||||||
tomoyo_same_manager);
|
}
|
||||||
tomoyo_put_name(e.manager);
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -821,18 +823,36 @@ static int tomoyo_delete_domain(char *domainname)
|
||||||
/**
|
/**
|
||||||
* tomoyo_write_domain2 - Write domain policy.
|
* tomoyo_write_domain2 - Write domain policy.
|
||||||
*
|
*
|
||||||
* @head: Pointer to "struct tomoyo_io_buffer".
|
* @list: Pointer to "struct list_head".
|
||||||
|
* @data: Policy to be interpreted.
|
||||||
|
* @is_delete: True if it is a delete request.
|
||||||
*
|
*
|
||||||
* Returns 0 on success, negative value otherwise.
|
* Returns 0 on success, negative value otherwise.
|
||||||
*
|
*
|
||||||
* Caller holds tomoyo_read_lock().
|
* Caller holds tomoyo_read_lock().
|
||||||
*/
|
*/
|
||||||
static int tomoyo_write_domain2(char *data, struct tomoyo_domain_info *domain,
|
static int tomoyo_write_domain2(struct list_head *list, char *data,
|
||||||
const bool is_delete)
|
const bool is_delete)
|
||||||
{
|
{
|
||||||
if (tomoyo_str_starts(&data, "allow_mount "))
|
struct tomoyo_acl_param param = {
|
||||||
return tomoyo_write_mount(data, domain, is_delete);
|
.list = list,
|
||||||
return tomoyo_write_file(data, domain, is_delete);
|
.data = data,
|
||||||
|
.is_delete = is_delete,
|
||||||
|
};
|
||||||
|
static const struct {
|
||||||
|
const char *keyword;
|
||||||
|
int (*write) (struct tomoyo_acl_param *);
|
||||||
|
} tomoyo_callback[1] = {
|
||||||
|
{ "file ", tomoyo_write_file },
|
||||||
|
};
|
||||||
|
u8 i;
|
||||||
|
for (i = 0; i < 1; i++) {
|
||||||
|
if (!tomoyo_str_starts(¶m.data,
|
||||||
|
tomoyo_callback[i].keyword))
|
||||||
|
continue;
|
||||||
|
return tomoyo_callback[i].write(¶m);
|
||||||
|
}
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -889,7 +909,7 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head)
|
||||||
domain->transition_failed = !is_delete;
|
domain->transition_failed = !is_delete;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return tomoyo_write_domain2(data, domain, is_delete);
|
return tomoyo_write_domain2(&domain->acl_info_list, data, is_delete);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1213,26 +1233,19 @@ static const char *tomoyo_group_name[TOMOYO_MAX_GROUP] = {
|
||||||
*/
|
*/
|
||||||
static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
|
static int tomoyo_write_exception(struct tomoyo_io_buffer *head)
|
||||||
{
|
{
|
||||||
char *data = head->write_buf;
|
struct tomoyo_acl_param param = {
|
||||||
bool is_delete = tomoyo_str_starts(&data, "delete ");
|
.data = head->write_buf,
|
||||||
u8 i;
|
|
||||||
static const struct {
|
|
||||||
const char *keyword;
|
|
||||||
int (*write) (char *, const bool);
|
|
||||||
} tomoyo_callback[1] = {
|
|
||||||
{ "aggregator ", tomoyo_write_aggregator },
|
|
||||||
};
|
};
|
||||||
|
u8 i;
|
||||||
|
param.is_delete = tomoyo_str_starts(¶m.data, "delete ");
|
||||||
|
if (tomoyo_str_starts(¶m.data, "aggregator "))
|
||||||
|
return tomoyo_write_aggregator(¶m);
|
||||||
for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++)
|
for (i = 0; i < TOMOYO_MAX_TRANSITION_TYPE; i++)
|
||||||
if (tomoyo_str_starts(&data, tomoyo_transition_type[i]))
|
if (tomoyo_str_starts(¶m.data, tomoyo_transition_type[i]))
|
||||||
return tomoyo_write_transition_control(data, is_delete,
|
return tomoyo_write_transition_control(¶m, i);
|
||||||
i);
|
|
||||||
for (i = 0; i < 1; i++)
|
|
||||||
if (tomoyo_str_starts(&data, tomoyo_callback[i].keyword))
|
|
||||||
return tomoyo_callback[i].write(data, is_delete);
|
|
||||||
for (i = 0; i < TOMOYO_MAX_GROUP; i++)
|
for (i = 0; i < TOMOYO_MAX_GROUP; i++)
|
||||||
if (tomoyo_str_starts(&data, tomoyo_group_name[i]))
|
if (tomoyo_str_starts(¶m.data, tomoyo_group_name[i]))
|
||||||
return tomoyo_write_group(data, is_delete, i);
|
return tomoyo_write_group(¶m, i);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1490,7 +1503,7 @@ int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
|
||||||
vsnprintf(buffer, len - 1, fmt, args);
|
vsnprintf(buffer, len - 1, fmt, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
tomoyo_normalize_line(buffer);
|
tomoyo_normalize_line(buffer);
|
||||||
tomoyo_write_domain2(buffer, r->domain, false);
|
tomoyo_write_domain2(&r->domain->acl_info_list, buffer, false);
|
||||||
kfree(buffer);
|
kfree(buffer);
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case TOMOYO_CONFIG_PERMISSIVE:
|
case TOMOYO_CONFIG_PERMISSIVE:
|
||||||
|
|
|
@ -397,6 +397,13 @@ struct tomoyo_mount_acl {
|
||||||
struct tomoyo_number_union flags;
|
struct tomoyo_number_union flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Structure for holding a line from /sys/kernel/security/tomoyo/ interface. */
|
||||||
|
struct tomoyo_acl_param {
|
||||||
|
char *data;
|
||||||
|
struct list_head *list;
|
||||||
|
bool is_delete;
|
||||||
|
};
|
||||||
|
|
||||||
#define TOMOYO_MAX_IO_READ_QUEUE 32
|
#define TOMOYO_MAX_IO_READ_QUEUE 32
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -521,7 +528,7 @@ bool tomoyo_correct_domain(const unsigned char *domainname);
|
||||||
bool tomoyo_correct_path(const char *filename);
|
bool tomoyo_correct_path(const char *filename);
|
||||||
bool tomoyo_correct_word(const char *string);
|
bool tomoyo_correct_word(const char *string);
|
||||||
bool tomoyo_domain_def(const unsigned char *buffer);
|
bool tomoyo_domain_def(const unsigned char *buffer);
|
||||||
bool tomoyo_parse_name_union(const char *filename,
|
bool tomoyo_parse_name_union(struct tomoyo_acl_param *param,
|
||||||
struct tomoyo_name_union *ptr);
|
struct tomoyo_name_union *ptr);
|
||||||
const struct tomoyo_path_info *
|
const struct tomoyo_path_info *
|
||||||
tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
|
tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
|
||||||
|
@ -531,7 +538,8 @@ bool tomoyo_number_matches_group(const unsigned long min,
|
||||||
const struct tomoyo_group *group);
|
const struct tomoyo_group *group);
|
||||||
bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
|
bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
|
||||||
const struct tomoyo_path_info *pattern);
|
const struct tomoyo_path_info *pattern);
|
||||||
bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num);
|
bool tomoyo_parse_number_union(struct tomoyo_acl_param *param,
|
||||||
|
struct tomoyo_number_union *ptr);
|
||||||
bool tomoyo_tokenize(char *buffer, char *w[], size_t size);
|
bool tomoyo_tokenize(char *buffer, char *w[], size_t size);
|
||||||
bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain);
|
bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain);
|
||||||
int tomoyo_init_request_info(struct tomoyo_request_info *r,
|
int tomoyo_init_request_info(struct tomoyo_request_info *r,
|
||||||
|
@ -540,21 +548,19 @@ int tomoyo_init_request_info(struct tomoyo_request_info *r,
|
||||||
int tomoyo_mount_permission(char *dev_name, struct path *path,
|
int tomoyo_mount_permission(char *dev_name, struct path *path,
|
||||||
const char *type, unsigned long flags,
|
const char *type, unsigned long flags,
|
||||||
void *data_page);
|
void *data_page);
|
||||||
int tomoyo_write_aggregator(char *data, const bool is_delete);
|
int tomoyo_write_aggregator(struct tomoyo_acl_param *param);
|
||||||
int tomoyo_write_transition_control(char *data, const bool is_delete,
|
int tomoyo_write_transition_control(struct tomoyo_acl_param *param,
|
||||||
const u8 type);
|
const u8 type);
|
||||||
int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain,
|
int tomoyo_write_file(struct tomoyo_acl_param *param);
|
||||||
const bool is_delete);
|
int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type);
|
||||||
int tomoyo_write_mount(char *data, struct tomoyo_domain_info *domain,
|
|
||||||
const bool is_delete);
|
|
||||||
int tomoyo_write_group(char *data, const bool is_delete, const u8 type);
|
|
||||||
int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
|
int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
|
||||||
__attribute__ ((format(printf, 2, 3)));
|
__attribute__ ((format(printf, 2, 3)));
|
||||||
struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
|
struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
|
||||||
struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
|
struct tomoyo_domain_info *tomoyo_assign_domain(const char *domainname,
|
||||||
const u8 profile);
|
const u8 profile);
|
||||||
struct tomoyo_profile *tomoyo_profile(const u8 profile);
|
struct tomoyo_profile *tomoyo_profile(const u8 profile);
|
||||||
struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 type);
|
struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param,
|
||||||
|
const u8 idx);
|
||||||
unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
|
unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
|
||||||
const u8 index);
|
const u8 index);
|
||||||
void tomoyo_fill_path_info(struct tomoyo_path_info *ptr);
|
void tomoyo_fill_path_info(struct tomoyo_path_info *ptr);
|
||||||
|
@ -587,7 +593,7 @@ void tomoyo_put_name_union(struct tomoyo_name_union *ptr);
|
||||||
void tomoyo_run_gc(void);
|
void tomoyo_run_gc(void);
|
||||||
void tomoyo_memory_free(void *ptr);
|
void tomoyo_memory_free(void *ptr);
|
||||||
int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
|
int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
|
||||||
bool is_delete, struct tomoyo_domain_info *domain,
|
struct tomoyo_acl_param *param,
|
||||||
bool (*check_duplicate) (const struct tomoyo_acl_info
|
bool (*check_duplicate) (const struct tomoyo_acl_info
|
||||||
*,
|
*,
|
||||||
const struct tomoyo_acl_info
|
const struct tomoyo_acl_info
|
||||||
|
@ -596,7 +602,7 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
|
||||||
struct tomoyo_acl_info *,
|
struct tomoyo_acl_info *,
|
||||||
const bool));
|
const bool));
|
||||||
int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
|
int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
|
||||||
bool is_delete, struct list_head *list,
|
struct tomoyo_acl_param *param,
|
||||||
bool (*check_duplicate) (const struct tomoyo_acl_head
|
bool (*check_duplicate) (const struct tomoyo_acl_head
|
||||||
*,
|
*,
|
||||||
const struct tomoyo_acl_head
|
const struct tomoyo_acl_head
|
||||||
|
@ -604,6 +610,8 @@ int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
|
||||||
void tomoyo_check_acl(struct tomoyo_request_info *r,
|
void tomoyo_check_acl(struct tomoyo_request_info *r,
|
||||||
bool (*check_entry) (struct tomoyo_request_info *,
|
bool (*check_entry) (struct tomoyo_request_info *,
|
||||||
const struct tomoyo_acl_info *));
|
const struct tomoyo_acl_info *));
|
||||||
|
char *tomoyo_read_token(struct tomoyo_acl_param *param);
|
||||||
|
bool tomoyo_permstr(const char *string, const char *keyword);
|
||||||
|
|
||||||
/********** External variable definitions. **********/
|
/********** External variable definitions. **********/
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,7 @@ struct tomoyo_domain_info tomoyo_kernel_domain;
|
||||||
*
|
*
|
||||||
* @new_entry: Pointer to "struct tomoyo_acl_info".
|
* @new_entry: Pointer to "struct tomoyo_acl_info".
|
||||||
* @size: Size of @new_entry in bytes.
|
* @size: Size of @new_entry in bytes.
|
||||||
* @is_delete: True if it is a delete request.
|
* @param: Pointer to "struct tomoyo_acl_param".
|
||||||
* @list: Pointer to "struct list_head".
|
|
||||||
* @check_duplicate: Callback function to find duplicated entry.
|
* @check_duplicate: Callback function to find duplicated entry.
|
||||||
*
|
*
|
||||||
* Returns 0 on success, negative value otherwise.
|
* Returns 0 on success, negative value otherwise.
|
||||||
|
@ -29,25 +28,26 @@ struct tomoyo_domain_info tomoyo_kernel_domain;
|
||||||
* Caller holds tomoyo_read_lock().
|
* Caller holds tomoyo_read_lock().
|
||||||
*/
|
*/
|
||||||
int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
|
int tomoyo_update_policy(struct tomoyo_acl_head *new_entry, const int size,
|
||||||
bool is_delete, struct list_head *list,
|
struct tomoyo_acl_param *param,
|
||||||
bool (*check_duplicate) (const struct tomoyo_acl_head
|
bool (*check_duplicate) (const struct tomoyo_acl_head
|
||||||
*,
|
*,
|
||||||
const struct tomoyo_acl_head
|
const struct tomoyo_acl_head
|
||||||
*))
|
*))
|
||||||
{
|
{
|
||||||
int error = is_delete ? -ENOENT : -ENOMEM;
|
int error = param->is_delete ? -ENOENT : -ENOMEM;
|
||||||
struct tomoyo_acl_head *entry;
|
struct tomoyo_acl_head *entry;
|
||||||
|
struct list_head *list = param->list;
|
||||||
|
|
||||||
if (mutex_lock_interruptible(&tomoyo_policy_lock))
|
if (mutex_lock_interruptible(&tomoyo_policy_lock))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
list_for_each_entry_rcu(entry, list, list) {
|
list_for_each_entry_rcu(entry, list, list) {
|
||||||
if (!check_duplicate(entry, new_entry))
|
if (!check_duplicate(entry, new_entry))
|
||||||
continue;
|
continue;
|
||||||
entry->is_deleted = is_delete;
|
entry->is_deleted = param->is_delete;
|
||||||
error = 0;
|
error = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (error && !is_delete) {
|
if (error && !param->is_delete) {
|
||||||
entry = tomoyo_commit_ok(new_entry, size);
|
entry = tomoyo_commit_ok(new_entry, size);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
list_add_tail_rcu(&entry->list, list);
|
list_add_tail_rcu(&entry->list, list);
|
||||||
|
@ -77,8 +77,7 @@ static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a,
|
||||||
*
|
*
|
||||||
* @new_entry: Pointer to "struct tomoyo_acl_info".
|
* @new_entry: Pointer to "struct tomoyo_acl_info".
|
||||||
* @size: Size of @new_entry in bytes.
|
* @size: Size of @new_entry in bytes.
|
||||||
* @is_delete: True if it is a delete request.
|
* @param: Pointer to "struct tomoyo_acl_param".
|
||||||
* @domain: Pointer to "struct tomoyo_domain_info".
|
|
||||||
* @check_duplicate: Callback function to find duplicated entry.
|
* @check_duplicate: Callback function to find duplicated entry.
|
||||||
* @merge_duplicate: Callback function to merge duplicated entry.
|
* @merge_duplicate: Callback function to merge duplicated entry.
|
||||||
*
|
*
|
||||||
|
@ -87,7 +86,7 @@ static inline bool tomoyo_same_acl_head(const struct tomoyo_acl_info *a,
|
||||||
* Caller holds tomoyo_read_lock().
|
* Caller holds tomoyo_read_lock().
|
||||||
*/
|
*/
|
||||||
int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
|
int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
|
||||||
bool is_delete, struct tomoyo_domain_info *domain,
|
struct tomoyo_acl_param *param,
|
||||||
bool (*check_duplicate) (const struct tomoyo_acl_info
|
bool (*check_duplicate) (const struct tomoyo_acl_info
|
||||||
*,
|
*,
|
||||||
const struct tomoyo_acl_info
|
const struct tomoyo_acl_info
|
||||||
|
@ -96,12 +95,14 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
|
||||||
struct tomoyo_acl_info *,
|
struct tomoyo_acl_info *,
|
||||||
const bool))
|
const bool))
|
||||||
{
|
{
|
||||||
|
const bool is_delete = param->is_delete;
|
||||||
int error = is_delete ? -ENOENT : -ENOMEM;
|
int error = is_delete ? -ENOENT : -ENOMEM;
|
||||||
struct tomoyo_acl_info *entry;
|
struct tomoyo_acl_info *entry;
|
||||||
|
struct list_head * const list = param->list;
|
||||||
|
|
||||||
if (mutex_lock_interruptible(&tomoyo_policy_lock))
|
if (mutex_lock_interruptible(&tomoyo_policy_lock))
|
||||||
return error;
|
return error;
|
||||||
list_for_each_entry_rcu(entry, &domain->acl_info_list, list) {
|
list_for_each_entry_rcu(entry, list, list) {
|
||||||
if (!tomoyo_same_acl_head(entry, new_entry) ||
|
if (!tomoyo_same_acl_head(entry, new_entry) ||
|
||||||
!check_duplicate(entry, new_entry))
|
!check_duplicate(entry, new_entry))
|
||||||
continue;
|
continue;
|
||||||
|
@ -116,7 +117,7 @@ int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size,
|
||||||
if (error && !is_delete) {
|
if (error && !is_delete) {
|
||||||
entry = tomoyo_commit_ok(new_entry, size);
|
entry = tomoyo_commit_ok(new_entry, size);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
list_add_tail_rcu(&entry->list, &domain->acl_info_list);
|
list_add_tail_rcu(&entry->list, list);
|
||||||
error = 0;
|
error = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,6 +164,14 @@ static const char *tomoyo_last_word(const char *name)
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tomoyo_same_transition_control - Check for duplicated "struct tomoyo_transition_control" entry.
|
||||||
|
*
|
||||||
|
* @a: Pointer to "struct tomoyo_acl_head".
|
||||||
|
* @b: Pointer to "struct tomoyo_acl_head".
|
||||||
|
*
|
||||||
|
* Returns true if @a == @b, false otherwise.
|
||||||
|
*/
|
||||||
static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a,
|
static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a,
|
||||||
const struct tomoyo_acl_head *b)
|
const struct tomoyo_acl_head *b)
|
||||||
{
|
{
|
||||||
|
@ -178,22 +187,28 @@ static bool tomoyo_same_transition_control(const struct tomoyo_acl_head *a,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tomoyo_update_transition_control_entry - Update "struct tomoyo_transition_control" list.
|
* tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list.
|
||||||
*
|
*
|
||||||
* @domainname: The name of domain. Maybe NULL.
|
* @param: Pointer to "struct tomoyo_acl_param".
|
||||||
* @program: The name of program. Maybe NULL.
|
* @type: Type of this entry.
|
||||||
* @type: Type of transition.
|
|
||||||
* @is_delete: True if it is a delete request.
|
|
||||||
*
|
*
|
||||||
* Returns 0 on success, negative value otherwise.
|
* Returns 0 on success, negative value otherwise.
|
||||||
*/
|
*/
|
||||||
static int tomoyo_update_transition_control_entry(const char *domainname,
|
int tomoyo_write_transition_control(struct tomoyo_acl_param *param,
|
||||||
const char *program,
|
const u8 type)
|
||||||
const u8 type,
|
|
||||||
const bool is_delete)
|
|
||||||
{
|
{
|
||||||
struct tomoyo_transition_control e = { .type = type };
|
struct tomoyo_transition_control e = { .type = type };
|
||||||
int error = is_delete ? -ENOENT : -ENOMEM;
|
int error = param->is_delete ? -ENOENT : -ENOMEM;
|
||||||
|
char *program = param->data;
|
||||||
|
char *domainname = strstr(program, " from ");
|
||||||
|
if (domainname) {
|
||||||
|
*domainname = '\0';
|
||||||
|
domainname += 6;
|
||||||
|
} else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP ||
|
||||||
|
type == TOMOYO_TRANSITION_CONTROL_KEEP) {
|
||||||
|
domainname = program;
|
||||||
|
program = NULL;
|
||||||
|
}
|
||||||
if (program) {
|
if (program) {
|
||||||
if (!tomoyo_correct_path(program))
|
if (!tomoyo_correct_path(program))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -211,41 +226,15 @@ static int tomoyo_update_transition_control_entry(const char *domainname,
|
||||||
if (!e.domainname)
|
if (!e.domainname)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
|
param->list = &tomoyo_policy_list[TOMOYO_ID_TRANSITION_CONTROL];
|
||||||
&tomoyo_policy_list
|
error = tomoyo_update_policy(&e.head, sizeof(e), param,
|
||||||
[TOMOYO_ID_TRANSITION_CONTROL],
|
|
||||||
tomoyo_same_transition_control);
|
tomoyo_same_transition_control);
|
||||||
out:
|
out:
|
||||||
tomoyo_put_name(e.domainname);
|
tomoyo_put_name(e.domainname);
|
||||||
tomoyo_put_name(e.program);
|
tomoyo_put_name(e.program);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* tomoyo_write_transition_control - Write "struct tomoyo_transition_control" list.
|
|
||||||
*
|
|
||||||
* @data: String to parse.
|
|
||||||
* @is_delete: True if it is a delete request.
|
|
||||||
* @type: Type of this entry.
|
|
||||||
*
|
|
||||||
* Returns 0 on success, negative value otherwise.
|
|
||||||
*/
|
|
||||||
int tomoyo_write_transition_control(char *data, const bool is_delete,
|
|
||||||
const u8 type)
|
|
||||||
{
|
|
||||||
char *domainname = strstr(data, " from ");
|
|
||||||
if (domainname) {
|
|
||||||
*domainname = '\0';
|
|
||||||
domainname += 6;
|
|
||||||
} else if (type == TOMOYO_TRANSITION_CONTROL_NO_KEEP ||
|
|
||||||
type == TOMOYO_TRANSITION_CONTROL_KEEP) {
|
|
||||||
domainname = data;
|
|
||||||
data = NULL;
|
|
||||||
}
|
|
||||||
return tomoyo_update_transition_control_entry(domainname, data, type,
|
|
||||||
is_delete);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tomoyo_transition_type - Get domain transition type.
|
* tomoyo_transition_type - Get domain transition type.
|
||||||
*
|
*
|
||||||
|
@ -303,34 +292,41 @@ static u8 tomoyo_transition_type(const struct tomoyo_path_info *domainname,
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tomoyo_same_aggregator - Check for duplicated "struct tomoyo_aggregator" entry.
|
||||||
|
*
|
||||||
|
* @a: Pointer to "struct tomoyo_acl_head".
|
||||||
|
* @b: Pointer to "struct tomoyo_acl_head".
|
||||||
|
*
|
||||||
|
* Returns true if @a == @b, false otherwise.
|
||||||
|
*/
|
||||||
static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a,
|
static bool tomoyo_same_aggregator(const struct tomoyo_acl_head *a,
|
||||||
const struct tomoyo_acl_head *b)
|
const struct tomoyo_acl_head *b)
|
||||||
{
|
{
|
||||||
const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1), head);
|
const struct tomoyo_aggregator *p1 = container_of(a, typeof(*p1),
|
||||||
const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2), head);
|
head);
|
||||||
|
const struct tomoyo_aggregator *p2 = container_of(b, typeof(*p2),
|
||||||
|
head);
|
||||||
return p1->original_name == p2->original_name &&
|
return p1->original_name == p2->original_name &&
|
||||||
p1->aggregated_name == p2->aggregated_name;
|
p1->aggregated_name == p2->aggregated_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tomoyo_update_aggregator_entry - Update "struct tomoyo_aggregator" list.
|
* tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list.
|
||||||
*
|
*
|
||||||
* @original_name: The original program's name.
|
* @param: Pointer to "struct tomoyo_acl_param".
|
||||||
* @aggregated_name: The program name to use.
|
|
||||||
* @is_delete: True if it is a delete request.
|
|
||||||
*
|
*
|
||||||
* Returns 0 on success, negative value otherwise.
|
* Returns 0 on success, negative value otherwise.
|
||||||
*
|
*
|
||||||
* Caller holds tomoyo_read_lock().
|
* Caller holds tomoyo_read_lock().
|
||||||
*/
|
*/
|
||||||
static int tomoyo_update_aggregator_entry(const char *original_name,
|
int tomoyo_write_aggregator(struct tomoyo_acl_param *param)
|
||||||
const char *aggregated_name,
|
|
||||||
const bool is_delete)
|
|
||||||
{
|
{
|
||||||
struct tomoyo_aggregator e = { };
|
struct tomoyo_aggregator e = { };
|
||||||
int error = is_delete ? -ENOENT : -ENOMEM;
|
int error = param->is_delete ? -ENOENT : -ENOMEM;
|
||||||
|
const char *original_name = tomoyo_read_token(param);
|
||||||
if (!tomoyo_correct_path(original_name) ||
|
const char *aggregated_name = tomoyo_read_token(param);
|
||||||
|
if (!tomoyo_correct_word(original_name) ||
|
||||||
!tomoyo_correct_path(aggregated_name))
|
!tomoyo_correct_path(aggregated_name))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
e.original_name = tomoyo_get_name(original_name);
|
e.original_name = tomoyo_get_name(original_name);
|
||||||
|
@ -338,35 +334,15 @@ static int tomoyo_update_aggregator_entry(const char *original_name,
|
||||||
if (!e.original_name || !e.aggregated_name ||
|
if (!e.original_name || !e.aggregated_name ||
|
||||||
e.aggregated_name->is_patterned) /* No patterns allowed. */
|
e.aggregated_name->is_patterned) /* No patterns allowed. */
|
||||||
goto out;
|
goto out;
|
||||||
error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
|
param->list = &tomoyo_policy_list[TOMOYO_ID_AGGREGATOR];
|
||||||
&tomoyo_policy_list[TOMOYO_ID_AGGREGATOR],
|
error = tomoyo_update_policy(&e.head, sizeof(e), param,
|
||||||
tomoyo_same_aggregator);
|
tomoyo_same_aggregator);
|
||||||
out:
|
out:
|
||||||
tomoyo_put_name(e.original_name);
|
tomoyo_put_name(e.original_name);
|
||||||
tomoyo_put_name(e.aggregated_name);
|
tomoyo_put_name(e.aggregated_name);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* tomoyo_write_aggregator - Write "struct tomoyo_aggregator" list.
|
|
||||||
*
|
|
||||||
* @data: String to parse.
|
|
||||||
* @is_delete: True if it is a delete request.
|
|
||||||
*
|
|
||||||
* Returns 0 on success, negative value otherwise.
|
|
||||||
*
|
|
||||||
* Caller holds tomoyo_read_lock().
|
|
||||||
*/
|
|
||||||
int tomoyo_write_aggregator(char *data, const bool is_delete)
|
|
||||||
{
|
|
||||||
char *cp = strchr(data, ' ');
|
|
||||||
|
|
||||||
if (!cp)
|
|
||||||
return -EINVAL;
|
|
||||||
*cp++ = '\0';
|
|
||||||
return tomoyo_update_aggregator_entry(data, cp, is_delete);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tomoyo_assign_domain - Create a domain.
|
* tomoyo_assign_domain - Create a domain.
|
||||||
*
|
*
|
||||||
|
|
|
@ -428,29 +428,27 @@ static bool tomoyo_merge_path_acl(struct tomoyo_acl_info *a,
|
||||||
/**
|
/**
|
||||||
* tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
|
* tomoyo_update_path_acl - Update "struct tomoyo_path_acl" list.
|
||||||
*
|
*
|
||||||
* @type: Type of operation.
|
* @perm: Permission.
|
||||||
* @filename: Filename.
|
* @param: Pointer to "struct tomoyo_acl_param".
|
||||||
* @domain: Pointer to "struct tomoyo_domain_info".
|
|
||||||
* @is_delete: True if it is a delete request.
|
|
||||||
*
|
*
|
||||||
* Returns 0 on success, negative value otherwise.
|
* Returns 0 on success, negative value otherwise.
|
||||||
*
|
*
|
||||||
* Caller holds tomoyo_read_lock().
|
* Caller holds tomoyo_read_lock().
|
||||||
*/
|
*/
|
||||||
static int tomoyo_update_path_acl(const u8 type, const char *filename,
|
static int tomoyo_update_path_acl(const u16 perm,
|
||||||
struct tomoyo_domain_info * const domain,
|
struct tomoyo_acl_param *param)
|
||||||
const bool is_delete)
|
|
||||||
{
|
{
|
||||||
struct tomoyo_path_acl e = {
|
struct tomoyo_path_acl e = {
|
||||||
.head.type = TOMOYO_TYPE_PATH_ACL,
|
.head.type = TOMOYO_TYPE_PATH_ACL,
|
||||||
.perm = 1 << type
|
.perm = perm
|
||||||
};
|
};
|
||||||
int error;
|
int error;
|
||||||
if (!tomoyo_parse_name_union(filename, &e.name))
|
if (!tomoyo_parse_name_union(param, &e.name))
|
||||||
return -EINVAL;
|
error = -EINVAL;
|
||||||
error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
|
else
|
||||||
tomoyo_same_path_acl,
|
error = tomoyo_update_domain(&e.head, sizeof(e), param,
|
||||||
tomoyo_merge_path_acl);
|
tomoyo_same_path_acl,
|
||||||
|
tomoyo_merge_path_acl);
|
||||||
tomoyo_put_name_union(&e.name);
|
tomoyo_put_name_union(&e.name);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
@ -503,37 +501,30 @@ static bool tomoyo_merge_mkdev_acl(struct tomoyo_acl_info *a,
|
||||||
/**
|
/**
|
||||||
* tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list.
|
* tomoyo_update_mkdev_acl - Update "struct tomoyo_mkdev_acl" list.
|
||||||
*
|
*
|
||||||
* @type: Type of operation.
|
* @perm: Permission.
|
||||||
* @filename: Filename.
|
* @param: Pointer to "struct tomoyo_acl_param".
|
||||||
* @mode: Create mode.
|
|
||||||
* @major: Device major number.
|
|
||||||
* @minor: Device minor number.
|
|
||||||
* @domain: Pointer to "struct tomoyo_domain_info".
|
|
||||||
* @is_delete: True if it is a delete request.
|
|
||||||
*
|
*
|
||||||
* Returns 0 on success, negative value otherwise.
|
* Returns 0 on success, negative value otherwise.
|
||||||
*
|
*
|
||||||
* Caller holds tomoyo_read_lock().
|
* Caller holds tomoyo_read_lock().
|
||||||
*/
|
*/
|
||||||
static int tomoyo_update_mkdev_acl(const u8 type, const char *filename,
|
static int tomoyo_update_mkdev_acl(const u8 perm,
|
||||||
char *mode, char *major, char *minor,
|
struct tomoyo_acl_param *param)
|
||||||
struct tomoyo_domain_info * const domain,
|
|
||||||
const bool is_delete)
|
|
||||||
{
|
{
|
||||||
struct tomoyo_mkdev_acl e = {
|
struct tomoyo_mkdev_acl e = {
|
||||||
.head.type = TOMOYO_TYPE_MKDEV_ACL,
|
.head.type = TOMOYO_TYPE_MKDEV_ACL,
|
||||||
.perm = 1 << type
|
.perm = perm
|
||||||
};
|
};
|
||||||
int error = is_delete ? -ENOENT : -ENOMEM;
|
int error;
|
||||||
if (!tomoyo_parse_name_union(filename, &e.name) ||
|
if (!tomoyo_parse_name_union(param, &e.name) ||
|
||||||
!tomoyo_parse_number_union(mode, &e.mode) ||
|
!tomoyo_parse_number_union(param, &e.mode) ||
|
||||||
!tomoyo_parse_number_union(major, &e.major) ||
|
!tomoyo_parse_number_union(param, &e.major) ||
|
||||||
!tomoyo_parse_number_union(minor, &e.minor))
|
!tomoyo_parse_number_union(param, &e.minor))
|
||||||
goto out;
|
error = -EINVAL;
|
||||||
error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
|
else
|
||||||
tomoyo_same_mkdev_acl,
|
error = tomoyo_update_domain(&e.head, sizeof(e), param,
|
||||||
tomoyo_merge_mkdev_acl);
|
tomoyo_same_mkdev_acl,
|
||||||
out:
|
tomoyo_merge_mkdev_acl);
|
||||||
tomoyo_put_name_union(&e.name);
|
tomoyo_put_name_union(&e.name);
|
||||||
tomoyo_put_number_union(&e.mode);
|
tomoyo_put_number_union(&e.mode);
|
||||||
tomoyo_put_number_union(&e.major);
|
tomoyo_put_number_union(&e.major);
|
||||||
|
@ -586,33 +577,28 @@ static bool tomoyo_merge_path2_acl(struct tomoyo_acl_info *a,
|
||||||
/**
|
/**
|
||||||
* tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
|
* tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
|
||||||
*
|
*
|
||||||
* @type: Type of operation.
|
* @perm: Permission.
|
||||||
* @filename1: First filename.
|
* @param: Pointer to "struct tomoyo_acl_param".
|
||||||
* @filename2: Second filename.
|
|
||||||
* @domain: Pointer to "struct tomoyo_domain_info".
|
|
||||||
* @is_delete: True if it is a delete request.
|
|
||||||
*
|
*
|
||||||
* Returns 0 on success, negative value otherwise.
|
* Returns 0 on success, negative value otherwise.
|
||||||
*
|
*
|
||||||
* Caller holds tomoyo_read_lock().
|
* Caller holds tomoyo_read_lock().
|
||||||
*/
|
*/
|
||||||
static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
|
static int tomoyo_update_path2_acl(const u8 perm,
|
||||||
const char *filename2,
|
struct tomoyo_acl_param *param)
|
||||||
struct tomoyo_domain_info * const domain,
|
|
||||||
const bool is_delete)
|
|
||||||
{
|
{
|
||||||
struct tomoyo_path2_acl e = {
|
struct tomoyo_path2_acl e = {
|
||||||
.head.type = TOMOYO_TYPE_PATH2_ACL,
|
.head.type = TOMOYO_TYPE_PATH2_ACL,
|
||||||
.perm = 1 << type
|
.perm = perm
|
||||||
};
|
};
|
||||||
int error = is_delete ? -ENOENT : -ENOMEM;
|
int error;
|
||||||
if (!tomoyo_parse_name_union(filename1, &e.name1) ||
|
if (!tomoyo_parse_name_union(param, &e.name1) ||
|
||||||
!tomoyo_parse_name_union(filename2, &e.name2))
|
!tomoyo_parse_name_union(param, &e.name2))
|
||||||
goto out;
|
error = -EINVAL;
|
||||||
error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
|
else
|
||||||
tomoyo_same_path2_acl,
|
error = tomoyo_update_domain(&e.head, sizeof(e), param,
|
||||||
tomoyo_merge_path2_acl);
|
tomoyo_same_path2_acl,
|
||||||
out:
|
tomoyo_merge_path2_acl);
|
||||||
tomoyo_put_name_union(&e.name1);
|
tomoyo_put_name_union(&e.name1);
|
||||||
tomoyo_put_name_union(&e.name2);
|
tomoyo_put_name_union(&e.name2);
|
||||||
return error;
|
return error;
|
||||||
|
@ -701,32 +687,26 @@ static bool tomoyo_merge_path_number_acl(struct tomoyo_acl_info *a,
|
||||||
/**
|
/**
|
||||||
* tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
|
* tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
|
||||||
*
|
*
|
||||||
* @type: Type of operation.
|
* @perm: Permission.
|
||||||
* @filename: Filename.
|
* @param: Pointer to "struct tomoyo_acl_param".
|
||||||
* @number: Number.
|
|
||||||
* @domain: Pointer to "struct tomoyo_domain_info".
|
|
||||||
* @is_delete: True if it is a delete request.
|
|
||||||
*
|
*
|
||||||
* Returns 0 on success, negative value otherwise.
|
* Returns 0 on success, negative value otherwise.
|
||||||
*/
|
*/
|
||||||
static int tomoyo_update_path_number_acl(const u8 type, const char *filename,
|
static int tomoyo_update_path_number_acl(const u8 perm,
|
||||||
char *number,
|
struct tomoyo_acl_param *param)
|
||||||
struct tomoyo_domain_info * const
|
|
||||||
domain, const bool is_delete)
|
|
||||||
{
|
{
|
||||||
struct tomoyo_path_number_acl e = {
|
struct tomoyo_path_number_acl e = {
|
||||||
.head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
|
.head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
|
||||||
.perm = 1 << type
|
.perm = perm
|
||||||
};
|
};
|
||||||
int error = is_delete ? -ENOENT : -ENOMEM;
|
int error;
|
||||||
if (!tomoyo_parse_name_union(filename, &e.name))
|
if (!tomoyo_parse_name_union(param, &e.name) ||
|
||||||
return -EINVAL;
|
!tomoyo_parse_number_union(param, &e.number))
|
||||||
if (!tomoyo_parse_number_union(number, &e.number))
|
error = -EINVAL;
|
||||||
goto out;
|
else
|
||||||
error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
|
error = tomoyo_update_domain(&e.head, sizeof(e), param,
|
||||||
tomoyo_same_path_number_acl,
|
tomoyo_same_path_number_acl,
|
||||||
tomoyo_merge_path_number_acl);
|
tomoyo_merge_path_number_acl);
|
||||||
out:
|
|
||||||
tomoyo_put_name_union(&e.name);
|
tomoyo_put_name_union(&e.name);
|
||||||
tomoyo_put_number_union(&e.number);
|
tomoyo_put_number_union(&e.number);
|
||||||
return error;
|
return error;
|
||||||
|
@ -963,53 +943,88 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tomoyo_write_file - Update file related list.
|
* tomoyo_same_mount_acl - Check for duplicated "struct tomoyo_mount_acl" entry.
|
||||||
*
|
*
|
||||||
* @data: String to parse.
|
* @a: Pointer to "struct tomoyo_acl_info".
|
||||||
* @domain: Pointer to "struct tomoyo_domain_info".
|
* @b: Pointer to "struct tomoyo_acl_info".
|
||||||
* @is_delete: True if it is a delete request.
|
*
|
||||||
|
* Returns true if @a == @b, false otherwise.
|
||||||
|
*/
|
||||||
|
static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a,
|
||||||
|
const struct tomoyo_acl_info *b)
|
||||||
|
{
|
||||||
|
const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head);
|
||||||
|
const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head);
|
||||||
|
return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) &&
|
||||||
|
tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) &&
|
||||||
|
tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) &&
|
||||||
|
tomoyo_same_number_union(&p1->flags, &p2->flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tomoyo_update_mount_acl - Write "struct tomoyo_mount_acl" list.
|
||||||
|
*
|
||||||
|
* @param: Pointer to "struct tomoyo_acl_param".
|
||||||
*
|
*
|
||||||
* Returns 0 on success, negative value otherwise.
|
* Returns 0 on success, negative value otherwise.
|
||||||
*
|
*
|
||||||
* Caller holds tomoyo_read_lock().
|
* Caller holds tomoyo_read_lock().
|
||||||
*/
|
*/
|
||||||
int tomoyo_write_file(char *data, struct tomoyo_domain_info *domain,
|
static int tomoyo_update_mount_acl(struct tomoyo_acl_param *param)
|
||||||
const bool is_delete)
|
|
||||||
{
|
{
|
||||||
char *w[5];
|
struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL };
|
||||||
|
int error;
|
||||||
|
if (!tomoyo_parse_name_union(param, &e.dev_name) ||
|
||||||
|
!tomoyo_parse_name_union(param, &e.dir_name) ||
|
||||||
|
!tomoyo_parse_name_union(param, &e.fs_type) ||
|
||||||
|
!tomoyo_parse_number_union(param, &e.flags))
|
||||||
|
error = -EINVAL;
|
||||||
|
else
|
||||||
|
error = tomoyo_update_domain(&e.head, sizeof(e), param,
|
||||||
|
tomoyo_same_mount_acl, NULL);
|
||||||
|
tomoyo_put_name_union(&e.dev_name);
|
||||||
|
tomoyo_put_name_union(&e.dir_name);
|
||||||
|
tomoyo_put_name_union(&e.fs_type);
|
||||||
|
tomoyo_put_number_union(&e.flags);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tomoyo_write_file - Update file related list.
|
||||||
|
*
|
||||||
|
* @param: Pointer to "struct tomoyo_acl_param".
|
||||||
|
*
|
||||||
|
* Returns 0 on success, negative value otherwise.
|
||||||
|
*
|
||||||
|
* Caller holds tomoyo_read_lock().
|
||||||
|
*/
|
||||||
|
int tomoyo_write_file(struct tomoyo_acl_param *param)
|
||||||
|
{
|
||||||
|
u16 perm = 0;
|
||||||
u8 type;
|
u8 type;
|
||||||
if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
|
const char *operation = tomoyo_read_token(param);
|
||||||
return -EINVAL;
|
for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++)
|
||||||
if (strncmp(w[0], "allow_", 6))
|
if (tomoyo_permstr(operation, tomoyo_path_keyword[type]))
|
||||||
goto out;
|
perm |= 1 << type;
|
||||||
w[0] += 6;
|
if (perm)
|
||||||
for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
|
return tomoyo_update_path_acl(perm, param);
|
||||||
if (strcmp(w[0], tomoyo_path_keyword[type]))
|
for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++)
|
||||||
continue;
|
if (tomoyo_permstr(operation, tomoyo_path2_keyword[type]))
|
||||||
return tomoyo_update_path_acl(type, w[1], domain, is_delete);
|
perm |= 1 << type;
|
||||||
}
|
if (perm)
|
||||||
if (!w[2][0])
|
return tomoyo_update_path2_acl(perm, param);
|
||||||
goto out;
|
for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++)
|
||||||
for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) {
|
if (tomoyo_permstr(operation,
|
||||||
if (strcmp(w[0], tomoyo_path2_keyword[type]))
|
tomoyo_path_number_keyword[type]))
|
||||||
continue;
|
perm |= 1 << type;
|
||||||
return tomoyo_update_path2_acl(type, w[1], w[2], domain,
|
if (perm)
|
||||||
is_delete);
|
return tomoyo_update_path_number_acl(perm, param);
|
||||||
}
|
for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++)
|
||||||
for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) {
|
if (tomoyo_permstr(operation, tomoyo_mkdev_keyword[type]))
|
||||||
if (strcmp(w[0], tomoyo_path_number_keyword[type]))
|
perm |= 1 << type;
|
||||||
continue;
|
if (perm)
|
||||||
return tomoyo_update_path_number_acl(type, w[1], w[2], domain,
|
return tomoyo_update_mkdev_acl(perm, param);
|
||||||
is_delete);
|
if (tomoyo_permstr(operation, "mount"))
|
||||||
}
|
return tomoyo_update_mount_acl(param);
|
||||||
if (!w[3][0] || !w[4][0])
|
|
||||||
goto out;
|
|
||||||
for (type = 0; type < TOMOYO_MAX_MKDEV_OPERATION; type++) {
|
|
||||||
if (strcmp(w[0], tomoyo_mkdev_keyword[type]))
|
|
||||||
continue;
|
|
||||||
return tomoyo_update_mkdev_acl(type, w[1], w[2], w[3],
|
|
||||||
w[4], domain, is_delete);
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,48 +28,41 @@ static bool tomoyo_same_number_group(const struct tomoyo_acl_head *a,
|
||||||
/**
|
/**
|
||||||
* tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group" list.
|
* tomoyo_write_group - Write "struct tomoyo_path_group"/"struct tomoyo_number_group" list.
|
||||||
*
|
*
|
||||||
* @data: String to parse.
|
* @param: Pointer to "struct tomoyo_acl_param".
|
||||||
* @is_delete: True if it is a delete request.
|
|
||||||
* @type: Type of this group.
|
* @type: Type of this group.
|
||||||
*
|
*
|
||||||
* Returns 0 on success, negative value otherwise.
|
* Returns 0 on success, negative value otherwise.
|
||||||
*/
|
*/
|
||||||
int tomoyo_write_group(char *data, const bool is_delete, const u8 type)
|
int tomoyo_write_group(struct tomoyo_acl_param *param, const u8 type)
|
||||||
{
|
{
|
||||||
struct tomoyo_group *group;
|
struct tomoyo_group *group = tomoyo_get_group(param, type);
|
||||||
struct list_head *member;
|
|
||||||
char *w[2];
|
|
||||||
int error = -EINVAL;
|
int error = -EINVAL;
|
||||||
if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
|
|
||||||
return -EINVAL;
|
|
||||||
group = tomoyo_get_group(w[0], type);
|
|
||||||
if (!group)
|
if (!group)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
member = &group->member_list;
|
param->list = &group->member_list;
|
||||||
if (type == TOMOYO_PATH_GROUP) {
|
if (type == TOMOYO_PATH_GROUP) {
|
||||||
struct tomoyo_path_group e = { };
|
struct tomoyo_path_group e = { };
|
||||||
e.member_name = tomoyo_get_name(w[1]);
|
e.member_name = tomoyo_get_name(tomoyo_read_token(param));
|
||||||
if (!e.member_name) {
|
if (!e.member_name) {
|
||||||
error = -ENOMEM;
|
error = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
|
error = tomoyo_update_policy(&e.head, sizeof(e), param,
|
||||||
member, tomoyo_same_path_group);
|
tomoyo_same_path_group);
|
||||||
tomoyo_put_name(e.member_name);
|
tomoyo_put_name(e.member_name);
|
||||||
} else if (type == TOMOYO_NUMBER_GROUP) {
|
} else if (type == TOMOYO_NUMBER_GROUP) {
|
||||||
struct tomoyo_number_group e = { };
|
struct tomoyo_number_group e = { };
|
||||||
if (w[1][0] == '@'
|
if (param->data[0] == '@' ||
|
||||||
|| !tomoyo_parse_number_union(w[1], &e.number)
|
!tomoyo_parse_number_union(param, &e.number))
|
||||||
|| e.number.values[0] > e.number.values[1])
|
|
||||||
goto out;
|
goto out;
|
||||||
error = tomoyo_update_policy(&e.head, sizeof(e), is_delete,
|
error = tomoyo_update_policy(&e.head, sizeof(e), param,
|
||||||
member, tomoyo_same_number_group);
|
tomoyo_same_number_group);
|
||||||
/*
|
/*
|
||||||
* tomoyo_put_number_union() is not needed because
|
* tomoyo_put_number_union() is not needed because
|
||||||
* w[1][0] != '@'.
|
* param->data[0] != '@'.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
tomoyo_put_group(group);
|
tomoyo_put_group(group);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,15 +93,18 @@ void tomoyo_memory_free(void *ptr)
|
||||||
/**
|
/**
|
||||||
* tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group".
|
* tomoyo_get_group - Allocate memory for "struct tomoyo_path_group"/"struct tomoyo_number_group".
|
||||||
*
|
*
|
||||||
* @group_name: The name of address group.
|
* @param: Pointer to "struct tomoyo_acl_param".
|
||||||
* @idx: Index number.
|
* @idx: Index number.
|
||||||
*
|
*
|
||||||
* Returns pointer to "struct tomoyo_group" on success, NULL otherwise.
|
* Returns pointer to "struct tomoyo_group" on success, NULL otherwise.
|
||||||
*/
|
*/
|
||||||
struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 idx)
|
struct tomoyo_group *tomoyo_get_group(struct tomoyo_acl_param *param,
|
||||||
|
const u8 idx)
|
||||||
{
|
{
|
||||||
struct tomoyo_group e = { };
|
struct tomoyo_group e = { };
|
||||||
struct tomoyo_group *group = NULL;
|
struct tomoyo_group *group = NULL;
|
||||||
|
struct list_head *list;
|
||||||
|
const char *group_name = tomoyo_read_token(param);
|
||||||
bool found = false;
|
bool found = false;
|
||||||
if (!tomoyo_correct_word(group_name) || idx >= TOMOYO_MAX_GROUP)
|
if (!tomoyo_correct_word(group_name) || idx >= TOMOYO_MAX_GROUP)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -110,7 +113,8 @@ struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 idx)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (mutex_lock_interruptible(&tomoyo_policy_lock))
|
if (mutex_lock_interruptible(&tomoyo_policy_lock))
|
||||||
goto out;
|
goto out;
|
||||||
list_for_each_entry(group, &tomoyo_group_list[idx], head.list) {
|
list = &tomoyo_group_list[idx];
|
||||||
|
list_for_each_entry(group, list, head.list) {
|
||||||
if (e.group_name != group->group_name)
|
if (e.group_name != group->group_name)
|
||||||
continue;
|
continue;
|
||||||
atomic_inc(&group->head.users);
|
atomic_inc(&group->head.users);
|
||||||
|
@ -122,14 +126,13 @@ struct tomoyo_group *tomoyo_get_group(const char *group_name, const u8 idx)
|
||||||
if (entry) {
|
if (entry) {
|
||||||
INIT_LIST_HEAD(&entry->member_list);
|
INIT_LIST_HEAD(&entry->member_list);
|
||||||
atomic_set(&entry->head.users, 1);
|
atomic_set(&entry->head.users, 1);
|
||||||
list_add_tail_rcu(&entry->head.list,
|
list_add_tail_rcu(&entry->head.list, list);
|
||||||
&tomoyo_group_list[idx]);
|
|
||||||
group = entry;
|
group = entry;
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&tomoyo_policy_lock);
|
mutex_unlock(&tomoyo_policy_lock);
|
||||||
out:
|
out:
|
||||||
tomoyo_put_name(e.group_name);
|
tomoyo_put_name(e.group_name);
|
||||||
return found ? group : NULL;
|
return found ? group : NULL;
|
||||||
}
|
}
|
||||||
|
@ -210,6 +213,8 @@ void __init tomoyo_mm_init(void)
|
||||||
idx = tomoyo_read_lock();
|
idx = tomoyo_read_lock();
|
||||||
if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
|
if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
|
||||||
panic("Can't register tomoyo_kernel_domain");
|
panic("Can't register tomoyo_kernel_domain");
|
||||||
|
#if 0
|
||||||
|
/* Will be replaced with tomoyo_load_builtin_policy(). */
|
||||||
{
|
{
|
||||||
/* Load built-in policy. */
|
/* Load built-in policy. */
|
||||||
tomoyo_write_transition_control("/sbin/hotplug", false,
|
tomoyo_write_transition_control("/sbin/hotplug", false,
|
||||||
|
@ -217,6 +222,7 @@ void __init tomoyo_mm_init(void)
|
||||||
tomoyo_write_transition_control("/sbin/modprobe", false,
|
tomoyo_write_transition_control("/sbin/modprobe", false,
|
||||||
TOMOYO_TRANSITION_CONTROL_INITIALIZE);
|
TOMOYO_TRANSITION_CONTROL_INITIALIZE);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
tomoyo_read_unlock(idx);
|
tomoyo_read_unlock(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -243,56 +243,3 @@ int tomoyo_mount_permission(char *dev_name, struct path *path,
|
||||||
tomoyo_read_unlock(idx);
|
tomoyo_read_unlock(idx);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* tomoyo_same_mount_acl - Check for duplicated "struct tomoyo_mount_acl" entry.
|
|
||||||
*
|
|
||||||
* @a: Pointer to "struct tomoyo_acl_info".
|
|
||||||
* @b: Pointer to "struct tomoyo_acl_info".
|
|
||||||
*
|
|
||||||
* Returns true if @a == @b, false otherwise.
|
|
||||||
*/
|
|
||||||
static bool tomoyo_same_mount_acl(const struct tomoyo_acl_info *a,
|
|
||||||
const struct tomoyo_acl_info *b)
|
|
||||||
{
|
|
||||||
const struct tomoyo_mount_acl *p1 = container_of(a, typeof(*p1), head);
|
|
||||||
const struct tomoyo_mount_acl *p2 = container_of(b, typeof(*p2), head);
|
|
||||||
return tomoyo_same_name_union(&p1->dev_name, &p2->dev_name) &&
|
|
||||||
tomoyo_same_name_union(&p1->dir_name, &p2->dir_name) &&
|
|
||||||
tomoyo_same_name_union(&p1->fs_type, &p2->fs_type) &&
|
|
||||||
tomoyo_same_number_union(&p1->flags, &p2->flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* tomoyo_write_mount - Write "struct tomoyo_mount_acl" list.
|
|
||||||
*
|
|
||||||
* @data: String to parse.
|
|
||||||
* @domain: Pointer to "struct tomoyo_domain_info".
|
|
||||||
* @is_delete: True if it is a delete request.
|
|
||||||
*
|
|
||||||
* Returns 0 on success, negative value otherwise.
|
|
||||||
*
|
|
||||||
* Caller holds tomoyo_read_lock().
|
|
||||||
*/
|
|
||||||
int tomoyo_write_mount(char *data, struct tomoyo_domain_info *domain,
|
|
||||||
const bool is_delete)
|
|
||||||
{
|
|
||||||
struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL };
|
|
||||||
int error = is_delete ? -ENOENT : -ENOMEM;
|
|
||||||
char *w[4];
|
|
||||||
if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[3][0])
|
|
||||||
return -EINVAL;
|
|
||||||
if (!tomoyo_parse_name_union(w[0], &e.dev_name) ||
|
|
||||||
!tomoyo_parse_name_union(w[1], &e.dir_name) ||
|
|
||||||
!tomoyo_parse_name_union(w[2], &e.fs_type) ||
|
|
||||||
!tomoyo_parse_number_union(w[3], &e.flags))
|
|
||||||
goto out;
|
|
||||||
error = tomoyo_update_domain(&e.head, sizeof(e), is_delete, domain,
|
|
||||||
tomoyo_same_mount_acl, NULL);
|
|
||||||
out:
|
|
||||||
tomoyo_put_name_union(&e.dev_name);
|
|
||||||
tomoyo_put_name_union(&e.dir_name);
|
|
||||||
tomoyo_put_name_union(&e.fs_type);
|
|
||||||
tomoyo_put_number_union(&e.flags);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
|
@ -15,6 +15,46 @@ DEFINE_MUTEX(tomoyo_policy_lock);
|
||||||
/* Has /sbin/init started? */
|
/* Has /sbin/init started? */
|
||||||
bool tomoyo_policy_loaded;
|
bool tomoyo_policy_loaded;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tomoyo_permstr - Find permission keywords.
|
||||||
|
*
|
||||||
|
* @string: String representation for permissions in foo/bar/buz format.
|
||||||
|
* @keyword: Keyword to find from @string/
|
||||||
|
*
|
||||||
|
* Returns ture if @keyword was found in @string, false otherwise.
|
||||||
|
*
|
||||||
|
* This function assumes that strncmp(w1, w2, strlen(w1)) != 0 if w1 != w2.
|
||||||
|
*/
|
||||||
|
bool tomoyo_permstr(const char *string, const char *keyword)
|
||||||
|
{
|
||||||
|
const char *cp = strstr(string, keyword);
|
||||||
|
if (cp)
|
||||||
|
return cp == string || *(cp - 1) == '/';
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tomoyo_read_token - Read a word from a line.
|
||||||
|
*
|
||||||
|
* @param: Pointer to "struct tomoyo_acl_param".
|
||||||
|
*
|
||||||
|
* Returns a word on success, "" otherwise.
|
||||||
|
*
|
||||||
|
* To allow the caller to skip NULL check, this function returns "" rather than
|
||||||
|
* NULL if there is no more words to read.
|
||||||
|
*/
|
||||||
|
char *tomoyo_read_token(struct tomoyo_acl_param *param)
|
||||||
|
{
|
||||||
|
char *pos = param->data;
|
||||||
|
char *del = strchr(pos, ' ');
|
||||||
|
if (del)
|
||||||
|
*del++ = '\0';
|
||||||
|
else
|
||||||
|
del = pos + strlen(pos);
|
||||||
|
param->data = del;
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tomoyo_parse_ulong - Parse an "unsigned long" value.
|
* tomoyo_parse_ulong - Parse an "unsigned long" value.
|
||||||
*
|
*
|
||||||
|
@ -81,20 +121,23 @@ void tomoyo_print_ulong(char *buffer, const int buffer_len,
|
||||||
/**
|
/**
|
||||||
* tomoyo_parse_name_union - Parse a tomoyo_name_union.
|
* tomoyo_parse_name_union - Parse a tomoyo_name_union.
|
||||||
*
|
*
|
||||||
* @filename: Name or name group.
|
* @param: Pointer to "struct tomoyo_acl_param".
|
||||||
* @ptr: Pointer to "struct tomoyo_name_union".
|
* @ptr: Pointer to "struct tomoyo_name_union".
|
||||||
*
|
*
|
||||||
* Returns true on success, false otherwise.
|
* Returns true on success, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool tomoyo_parse_name_union(const char *filename,
|
bool tomoyo_parse_name_union(struct tomoyo_acl_param *param,
|
||||||
struct tomoyo_name_union *ptr)
|
struct tomoyo_name_union *ptr)
|
||||||
{
|
{
|
||||||
if (!tomoyo_correct_word(filename))
|
char *filename;
|
||||||
return false;
|
if (param->data[0] == '@') {
|
||||||
if (filename[0] == '@') {
|
param->data++;
|
||||||
ptr->group = tomoyo_get_group(filename + 1, TOMOYO_PATH_GROUP);
|
ptr->group = tomoyo_get_group(param, TOMOYO_PATH_GROUP);
|
||||||
return ptr->group != NULL;
|
return ptr->group != NULL;
|
||||||
}
|
}
|
||||||
|
filename = tomoyo_read_token(param);
|
||||||
|
if (!tomoyo_correct_word(filename))
|
||||||
|
return false;
|
||||||
ptr->filename = tomoyo_get_name(filename);
|
ptr->filename = tomoyo_get_name(filename);
|
||||||
return ptr->filename != NULL;
|
return ptr->filename != NULL;
|
||||||
}
|
}
|
||||||
|
@ -102,39 +145,41 @@ bool tomoyo_parse_name_union(const char *filename,
|
||||||
/**
|
/**
|
||||||
* tomoyo_parse_number_union - Parse a tomoyo_number_union.
|
* tomoyo_parse_number_union - Parse a tomoyo_number_union.
|
||||||
*
|
*
|
||||||
* @data: Number or number range or number group.
|
* @param: Pointer to "struct tomoyo_acl_param".
|
||||||
* @ptr: Pointer to "struct tomoyo_number_union".
|
* @ptr: Pointer to "struct tomoyo_number_union".
|
||||||
*
|
*
|
||||||
* Returns true on success, false otherwise.
|
* Returns true on success, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num)
|
bool tomoyo_parse_number_union(struct tomoyo_acl_param *param,
|
||||||
|
struct tomoyo_number_union *ptr)
|
||||||
{
|
{
|
||||||
|
char *data;
|
||||||
u8 type;
|
u8 type;
|
||||||
unsigned long v;
|
unsigned long v;
|
||||||
memset(num, 0, sizeof(*num));
|
memset(ptr, 0, sizeof(*ptr));
|
||||||
if (data[0] == '@') {
|
if (param->data[0] == '@') {
|
||||||
if (!tomoyo_correct_word(data))
|
param->data++;
|
||||||
return false;
|
ptr->group = tomoyo_get_group(param, TOMOYO_NUMBER_GROUP);
|
||||||
num->group = tomoyo_get_group(data + 1, TOMOYO_NUMBER_GROUP);
|
return ptr->group != NULL;
|
||||||
return num->group != NULL;
|
|
||||||
}
|
}
|
||||||
|
data = tomoyo_read_token(param);
|
||||||
type = tomoyo_parse_ulong(&v, &data);
|
type = tomoyo_parse_ulong(&v, &data);
|
||||||
if (!type)
|
if (type == TOMOYO_VALUE_TYPE_INVALID)
|
||||||
return false;
|
return false;
|
||||||
num->values[0] = v;
|
ptr->values[0] = v;
|
||||||
num->value_type[0] = type;
|
ptr->value_type[0] = type;
|
||||||
if (!*data) {
|
if (!*data) {
|
||||||
num->values[1] = v;
|
ptr->values[1] = v;
|
||||||
num->value_type[1] = type;
|
ptr->value_type[1] = type;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (*data++ != '-')
|
if (*data++ != '-')
|
||||||
return false;
|
return false;
|
||||||
type = tomoyo_parse_ulong(&v, &data);
|
type = tomoyo_parse_ulong(&v, &data);
|
||||||
if (!type || *data)
|
if (type == TOMOYO_VALUE_TYPE_INVALID || *data || ptr->values[0] > v)
|
||||||
return false;
|
return false;
|
||||||
num->values[1] = v;
|
ptr->values[1] = v;
|
||||||
num->value_type[1] = type;
|
ptr->value_type[1] = type;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,33 +303,6 @@ void tomoyo_normalize_line(unsigned char *buffer)
|
||||||
*dp = '\0';
|
*dp = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* tomoyo_tokenize - Tokenize string.
|
|
||||||
*
|
|
||||||
* @buffer: The line to tokenize.
|
|
||||||
* @w: Pointer to "char *".
|
|
||||||
* @size: Sizeof @w .
|
|
||||||
*
|
|
||||||
* Returns true on success, false otherwise.
|
|
||||||
*/
|
|
||||||
bool tomoyo_tokenize(char *buffer, char *w[], size_t size)
|
|
||||||
{
|
|
||||||
int count = size / sizeof(char *);
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < count; i++)
|
|
||||||
w[i] = "";
|
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
char *cp = strchr(buffer, ' ');
|
|
||||||
if (cp)
|
|
||||||
*cp = '\0';
|
|
||||||
w[i] = buffer;
|
|
||||||
if (!cp)
|
|
||||||
break;
|
|
||||||
buffer = cp + 1;
|
|
||||||
}
|
|
||||||
return i < count || !*buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tomoyo_correct_word2 - Validate a string.
|
* tomoyo_correct_word2 - Validate a string.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in a new issue