1 |
/* |
2 |
* fs/sakura_mount.c |
3 |
* |
4 |
* Implementation of the Domain-Free Mandatory Access Control. |
5 |
* |
6 |
* Copyright (C) 2005-2007 NTT DATA CORPORATION |
7 |
* |
8 |
* Version: 1.4.2 2007/07/13 |
9 |
* |
10 |
* This file is applicable to both 2.4.30 and 2.6.11 and later. |
11 |
* See README.ccs for ChangeLog. |
12 |
* |
13 |
*/ |
14 |
/***** SAKURA Linux start. *****/ |
15 |
|
16 |
#include <linux/ccs_common.h> |
17 |
#include <linux/sakura.h> |
18 |
#include <linux/realpath.h> |
19 |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) |
20 |
#include <linux/namespace.h> |
21 |
#endif |
22 |
|
23 |
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) |
24 |
#define MS_UNBINDABLE (1<<17) /* change to unbindable */ |
25 |
#define MS_PRIVATE (1<<18) /* change to private */ |
26 |
#define MS_SLAVE (1<<19) /* change to slave */ |
27 |
#define MS_SHARED (1<<20) /* change to shared */ |
28 |
#endif |
29 |
|
30 |
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) |
31 |
#include <linux/namei.h> |
32 |
#else |
33 |
static inline void module_put(struct module *module) |
34 |
{ |
35 |
if (module) __MOD_DEC_USE_COUNT(module); |
36 |
} |
37 |
#endif |
38 |
|
39 |
extern const char *ccs_log_level; |
40 |
|
41 |
/***** KEYWORDS for mount restrictions. *****/ |
42 |
|
43 |
#define MOUNT_BIND_KEYWORD "--bind" /* Allow to call 'mount --bind /source_dir /dest_dir' */ |
44 |
#define MOUNT_MOVE_KEYWORD "--move" /* Allow to call 'mount --move /old_dir /new_dir ' */ |
45 |
#define MOUNT_REMOUNT_KEYWORD "--remount" /* Allow to call 'mount -o remount /dir ' */ |
46 |
#define MOUNT_MAKE_UNBINDABLE_KEYWORD "--make-unbindable" /* Allow to call 'mount --make-unbindable /dir' */ |
47 |
#define MOUNT_MAKE_PRIVATE_KEYWORD "--make-private" /* Allow to call 'mount --make-private /dir' */ |
48 |
#define MOUNT_MAKE_SLAVE_KEYWORD "--make-slave" /* Allow to call 'mount --make-slave /dir' */ |
49 |
#define MOUNT_MAKE_SHARED_KEYWORD "--make-shared" /* Allow to call 'mount --make-shared /dir' */ |
50 |
|
51 |
/***** The structure for mount restrictions. *****/ |
52 |
|
53 |
struct mount_entry { |
54 |
struct mount_entry *next; |
55 |
const struct path_info *dev_name; |
56 |
const struct path_info *dir_name; |
57 |
const struct path_info *fs_type; |
58 |
unsigned int disabled_options; /* Options to forcefully disable. */ |
59 |
unsigned int enabled_options; /* Options to forcefully enable. */ |
60 |
int is_deleted; |
61 |
}; |
62 |
|
63 |
/************************* MOUNT RESTRICTION HANDLER *************************/ |
64 |
|
65 |
static void ParseMountOptions(char *arg, unsigned int *enabled_options, unsigned int *disabled_options) |
66 |
{ |
67 |
char *sp = arg, *cp; |
68 |
unsigned int enable = 0, disable = 0; |
69 |
while ((cp = strsep(&sp, " ,")) != NULL) { |
70 |
if (strcmp(cp, "rw") == 0) disable |= MS_RDONLY; |
71 |
else if (strcmp(cp, "ro") == 0) enable |= MS_RDONLY; |
72 |
else if (strcmp(cp, "suid") == 0) disable |= MS_NOSUID; |
73 |
else if (strcmp(cp, "nosuid") == 0) enable |= MS_NOSUID; |
74 |
else if (strcmp(cp, "dev") == 0) disable |= MS_NODEV; |
75 |
else if (strcmp(cp, "nodev") == 0) enable |= MS_NODEV; |
76 |
else if (strcmp(cp, "exec") == 0) disable |= MS_NOEXEC; |
77 |
else if (strcmp(cp, "noexec") == 0) enable |= MS_NOEXEC; |
78 |
else if (strcmp(cp, "atime") == 0) disable |= MS_NOATIME; |
79 |
else if (strcmp(cp, "noatime") == 0) enable |= MS_NOATIME; |
80 |
else if (strcmp(cp, "diratime") == 0) disable |= MS_NODIRATIME; |
81 |
else if (strcmp(cp, "nodiratime") == 0) enable |= MS_NODIRATIME; |
82 |
else if (strcmp(cp, "norecurse") == 0) disable |= MS_REC; |
83 |
else if (strcmp(cp, "recurse") == 0) enable |= MS_REC; |
84 |
} |
85 |
*enabled_options = enable; |
86 |
*disabled_options = disable; |
87 |
} |
88 |
|
89 |
static void MakeMountOptions(char *buffer, const int buffer_len, const unsigned int enabled, const unsigned int disabled) |
90 |
{ |
91 |
memset(buffer, 0, buffer_len); |
92 |
if (enabled == 0 && disabled == 0) { |
93 |
snprintf(buffer, buffer_len - 1, "defaults"); |
94 |
} else { |
95 |
snprintf(buffer, buffer_len - 1, "%s%s%s%s%s%s%s", |
96 |
enabled & MS_RDONLY ? "ro " : (disabled & MS_RDONLY ? "rw " : ""), |
97 |
enabled & MS_NOSUID ? "nosuid " : (disabled & MS_NOSUID ? "suid " : ""), |
98 |
enabled & MS_NODEV ? "nodev " : (disabled & MS_NODEV ? "dev " : ""), |
99 |
enabled & MS_NOEXEC ? "noexec " : (disabled & MS_NOEXEC ? "exec " : ""), |
100 |
enabled & MS_NOATIME ? "noatime " : (disabled & MS_NOATIME ? "atime " : ""), |
101 |
enabled & MS_NODIRATIME ? "nodiratime " : (disabled & MS_NODIRATIME ? "diratime " : ""), |
102 |
enabled & MS_REC ? "recurse " : (disabled & MS_REC ? "norecurse " : "")); |
103 |
} |
104 |
} |
105 |
|
106 |
static void put_filesystem(struct file_system_type *fs) |
107 |
{ |
108 |
module_put(fs->owner); |
109 |
} |
110 |
|
111 |
static struct mount_entry *mount_list = NULL; |
112 |
|
113 |
static int AddMountACL(const char *dev_name, const char *dir_name, const char *fs_type, const unsigned int enable, const unsigned int disable, const int is_delete) |
114 |
{ |
115 |
struct mount_entry *new_entry, *ptr; |
116 |
const struct path_info *fs, *dev, *dir; |
117 |
static DECLARE_MUTEX(lock); |
118 |
int error = -ENOMEM; |
119 |
if (enable & disable) return -EINVAL; /* options mismatch. */ |
120 |
if ((fs = SaveName(fs_type)) == NULL) return -EINVAL; |
121 |
if (!dev_name) dev_name = "<NULL>"; /* Map dev_name to "<NULL>" for if no dev_name given. */ |
122 |
if (strcmp(fs->name, MOUNT_REMOUNT_KEYWORD) == 0) dev_name = "any"; /* Fix dev_name to "any" for remount permission. */ |
123 |
if (strcmp(fs->name, MOUNT_MAKE_UNBINDABLE_KEYWORD) == 0 || |
124 |
strcmp(fs->name, MOUNT_MAKE_PRIVATE_KEYWORD) == 0 || |
125 |
strcmp(fs->name, MOUNT_MAKE_SLAVE_KEYWORD) == 0 || |
126 |
strcmp(fs->name, MOUNT_MAKE_SHARED_KEYWORD) == 0) dev_name = "any"; |
127 |
if (!IsCorrectPath(dev_name, 0, 0, 0, __FUNCTION__) || !IsCorrectPath(dir_name, 1, 0, 1, __FUNCTION__)) return -EINVAL; |
128 |
if ((dev = SaveName(dev_name)) == NULL || (dir = SaveName(dir_name)) == NULL) return -ENOMEM; |
129 |
down(&lock); |
130 |
for (ptr = mount_list; ptr; ptr = ptr->next) { |
131 |
if (pathcmp(ptr->dev_name, dev) || pathcmp(ptr->dir_name, dir) || pathcmp(ptr->fs_type, fs)) continue; |
132 |
if (is_delete) { |
133 |
if (ptr->disabled_options != disable || ptr->enabled_options != enable) continue; |
134 |
ptr->is_deleted = 1; |
135 |
error = 0; |
136 |
goto out; |
137 |
} else { |
138 |
if (ptr->is_deleted) { |
139 |
ptr->enabled_options = enable; |
140 |
ptr->disabled_options = disable; |
141 |
ptr->is_deleted = 0; |
142 |
} else { |
143 |
if ((ptr->enabled_options & disable) || (ptr->disabled_options | enable)) { |
144 |
error = -EINVAL; goto out; /* options mismatch. */ |
145 |
} |
146 |
if ((ptr->enabled_options & enable) == enable && (ptr->disabled_options & disable) == disable) { |
147 |
error = 0; goto out; /* No changes. */ |
148 |
} |
149 |
ptr->enabled_options |= enable; |
150 |
ptr->disabled_options |= disable; |
151 |
} |
152 |
error = 0; |
153 |
goto update; |
154 |
} |
155 |
} |
156 |
if (is_delete) { |
157 |
error = -ENOENT; |
158 |
goto out; |
159 |
} |
160 |
if ((new_entry = alloc_element(sizeof(*new_entry))) == NULL) goto out; |
161 |
new_entry->dev_name = dev; |
162 |
new_entry->dir_name = dir; |
163 |
new_entry->fs_type = fs; |
164 |
new_entry->enabled_options = enable; |
165 |
new_entry->disabled_options = disable; |
166 |
mb(); /* Instead of using spinlock. */ |
167 |
if ((ptr = mount_list) != NULL) { |
168 |
while (ptr->next) ptr = ptr->next; ptr->next = new_entry; |
169 |
} else { |
170 |
mount_list = new_entry; |
171 |
} |
172 |
error = 0; |
173 |
ptr = new_entry; |
174 |
update: |
175 |
{ |
176 |
struct file_system_type *type = NULL; |
177 |
char options[64]; |
178 |
MakeMountOptions(options, sizeof(options), ptr->enabled_options, ptr->disabled_options); |
179 |
if (strcmp(fs->name, MOUNT_REMOUNT_KEYWORD) == 0) { |
180 |
printk("%sAllow remount %s with options %s.\n", ccs_log_level, dir->name, options); |
181 |
} else if (strcmp(fs->name, MOUNT_BIND_KEYWORD) == 0 || strcmp(fs->name, MOUNT_MOVE_KEYWORD) == 0) { |
182 |
printk("%sAllow mount %s %s %s\n", ccs_log_level, fs->name, dev->name, dir->name); |
183 |
} else if (strcmp(fs->name, MOUNT_MAKE_UNBINDABLE_KEYWORD) == 0 || |
184 |
strcmp(fs->name, MOUNT_MAKE_PRIVATE_KEYWORD) == 0 || |
185 |
strcmp(fs->name, MOUNT_MAKE_SLAVE_KEYWORD) == 0 || |
186 |
strcmp(fs->name, MOUNT_MAKE_SHARED_KEYWORD) == 0) { |
187 |
printk("%sAllow mount %s %s with options %s.\n", ccs_log_level, fs->name, dir->name, options); |
188 |
} else if ((type = get_fs_type(fs->name)) != NULL && (type->fs_flags & FS_REQUIRES_DEV) != 0) { |
189 |
printk("%sAllow mount -t %s %s %s with options %s.\n", ccs_log_level, fs->name, dev->name, dir->name, options); |
190 |
} else { |
191 |
printk("%sAllow mount %s on %s with options %s.\n", ccs_log_level, fs->name, dir->name, options); |
192 |
} |
193 |
if (type) put_filesystem(type); |
194 |
} |
195 |
out: |
196 |
up(&lock); |
197 |
return error; |
198 |
} |
199 |
|
200 |
int CheckMountPermission(char *dev_name, char *dir_name, char *type, unsigned long *flags) |
201 |
{ |
202 |
const int is_enforce = CheckCCSEnforce(CCS_SAKURA_RESTRICT_MOUNT); |
203 |
int error_flag = 1; |
204 |
if (!CheckCCSFlags(CCS_SAKURA_RESTRICT_MOUNT)) return 0; |
205 |
if (!type) type = "<NULL>"; |
206 |
if ((*flags & MS_MGC_MSK) == MS_MGC_VAL) *flags &= ~MS_MGC_MSK; |
207 |
switch (*flags & (MS_REMOUNT | MS_MOVE | MS_BIND)) { |
208 |
case MS_REMOUNT: |
209 |
case MS_MOVE: |
210 |
case MS_BIND: |
211 |
case 0: |
212 |
break; |
213 |
default: |
214 |
printk("SAKURA-ERROR: %s%s%sare given for single mount operation.\n", |
215 |
*flags & MS_REMOUNT ? "'remount' " : "", |
216 |
*flags & MS_MOVE ? "'move' " : "", |
217 |
*flags & MS_BIND ? "'bind' " : ""); |
218 |
return -EINVAL; |
219 |
} |
220 |
switch (*flags & (MS_UNBINDABLE | MS_PRIVATE | MS_SLAVE | MS_SHARED)) { |
221 |
case MS_UNBINDABLE: |
222 |
case MS_PRIVATE: |
223 |
case MS_SLAVE: |
224 |
case MS_SHARED: |
225 |
case 0: |
226 |
break; |
227 |
default: |
228 |
printk("SAKURA-ERROR: %s%s%s%sare given for single mount operation.\n", |
229 |
*flags & MS_UNBINDABLE ? "'unbindable' " : "", |
230 |
*flags & MS_PRIVATE ? "'private' " : "", |
231 |
*flags & MS_SLAVE ? "'slave' " : "", |
232 |
*flags & MS_SHARED ? "'shared' " : ""); |
233 |
return -EINVAL; |
234 |
} |
235 |
if (*flags & MS_REMOUNT) { |
236 |
*flags &= ~MS_REMOUNT; |
237 |
error_flag = CheckMountPermission(dev_name, dir_name, MOUNT_REMOUNT_KEYWORD, flags); |
238 |
*flags |= MS_REMOUNT; |
239 |
} else if (*flags & MS_MOVE) { |
240 |
*flags &= ~MS_MOVE; |
241 |
error_flag = CheckMountPermission(dev_name, dir_name, MOUNT_MOVE_KEYWORD, flags); |
242 |
*flags |= MS_MOVE; |
243 |
} else if (*flags & MS_BIND) { |
244 |
*flags &= ~MS_BIND; |
245 |
error_flag = CheckMountPermission(dev_name, dir_name, MOUNT_BIND_KEYWORD, flags); |
246 |
*flags |= MS_BIND; |
247 |
} else if (*flags & MS_UNBINDABLE) { |
248 |
*flags &= ~MS_UNBINDABLE; |
249 |
error_flag = CheckMountPermission(dev_name, dir_name, MOUNT_MAKE_UNBINDABLE_KEYWORD, flags); |
250 |
*flags |= MS_UNBINDABLE; |
251 |
} else if (*flags & MS_PRIVATE) { |
252 |
*flags &= ~MS_PRIVATE; |
253 |
error_flag = CheckMountPermission(dev_name, dir_name, MOUNT_MAKE_PRIVATE_KEYWORD, flags); |
254 |
*flags |= MS_PRIVATE; |
255 |
} else if (*flags & MS_SLAVE) { |
256 |
*flags &= ~MS_SLAVE; |
257 |
error_flag = CheckMountPermission(dev_name, dir_name, MOUNT_MAKE_SLAVE_KEYWORD, flags); |
258 |
*flags |= MS_SLAVE; |
259 |
} else if (*flags & MS_SHARED) { |
260 |
*flags &= ~MS_SHARED; |
261 |
error_flag = CheckMountPermission(dev_name, dir_name, MOUNT_MAKE_SHARED_KEYWORD, flags); |
262 |
*flags |= MS_SHARED; |
263 |
} else { |
264 |
goto normal_mount; |
265 |
} |
266 |
if (error_flag) { |
267 |
if (is_enforce) return -EPERM; |
268 |
return 0; |
269 |
} |
270 |
normal_mount: ; |
271 |
{ |
272 |
struct mount_entry *ptr; |
273 |
struct file_system_type *fstype = NULL; |
274 |
const char *requested_dir_name = NULL; |
275 |
const char *requested_dev_name = NULL; |
276 |
struct path_info rdev, rdir; |
277 |
int need_dev = 0; |
278 |
|
279 |
if ((requested_dir_name = realpath(dir_name)) == NULL) goto cleanup; |
280 |
rdir.name = requested_dir_name; |
281 |
fill_path_info(&rdir); |
282 |
|
283 |
/* Compare fs name. */ |
284 |
if (strcmp(type, MOUNT_REMOUNT_KEYWORD) == 0) { |
285 |
/* Needn't to resolve dev_name */ |
286 |
} else if (strcmp(type, MOUNT_MAKE_UNBINDABLE_KEYWORD) == 0 || |
287 |
strcmp(type, MOUNT_MAKE_PRIVATE_KEYWORD) == 0 || |
288 |
strcmp(type, MOUNT_MAKE_SLAVE_KEYWORD) == 0 || |
289 |
strcmp(type, MOUNT_MAKE_SHARED_KEYWORD) == 0) { |
290 |
/* Needn't to resolve dev_name */ |
291 |
} else if (strcmp(type, MOUNT_BIND_KEYWORD) == 0 || strcmp(type, MOUNT_MOVE_KEYWORD) == 0) { |
292 |
if ((requested_dev_name = realpath(dev_name)) == NULL) goto cleanup; |
293 |
rdev.name = requested_dev_name; |
294 |
fill_path_info(&rdev); |
295 |
need_dev = -1; |
296 |
} else if ((fstype = get_fs_type(type)) != NULL) { |
297 |
if (fstype->fs_flags & FS_REQUIRES_DEV) { |
298 |
if ((requested_dev_name = realpath(dev_name)) == NULL) goto cleanup; |
299 |
rdev.name = requested_dev_name; |
300 |
fill_path_info(&rdev); |
301 |
need_dev = 1; |
302 |
} |
303 |
} else { |
304 |
goto cleanup; |
305 |
} |
306 |
for (ptr = mount_list; ptr; ptr = ptr->next) { |
307 |
if (ptr->is_deleted) continue; |
308 |
|
309 |
/* Compare fs name. */ |
310 |
if (strcmp(type, ptr->fs_type->name)) continue; |
311 |
|
312 |
/* Compare mount point. */ |
313 |
if (PathMatchesToPattern(&rdir, ptr->dir_name) == 0) continue; |
314 |
|
315 |
/* Compare device name. */ |
316 |
if (requested_dev_name && PathMatchesToPattern(&rdev, ptr->dev_name) == 0) continue; |
317 |
|
318 |
/* OK. */ |
319 |
error_flag = 0; |
320 |
*flags &= ~ptr->disabled_options; |
321 |
*flags |= ptr->enabled_options; |
322 |
|
323 |
if (need_dev > 0) { |
324 |
printk(KERN_DEBUG "SAKURA-NOTICE: 'mount -t %s %s %s' accepted.\n", type, requested_dev_name, requested_dir_name); |
325 |
} else if (need_dev < 0) { |
326 |
printk(KERN_DEBUG "SAKURA-NOTICE: 'mount %s %s %s' accepted.\n", type, requested_dev_name, requested_dir_name); |
327 |
} else if (strcmp(type, MOUNT_REMOUNT_KEYWORD) == 0) { |
328 |
printk(KERN_DEBUG "SAKURA-NOTICE: 'mount -o remount %s' accepted.\n", requested_dir_name); |
329 |
} else if (strcmp(type, MOUNT_MAKE_UNBINDABLE_KEYWORD) == 0 || |
330 |
strcmp(type, MOUNT_MAKE_PRIVATE_KEYWORD) == 0 || |
331 |
strcmp(type, MOUNT_MAKE_SLAVE_KEYWORD) == 0 || |
332 |
strcmp(type, MOUNT_MAKE_SHARED_KEYWORD) == 0) { |
333 |
printk(KERN_DEBUG "SAKURA-NOTICE: 'mount %s %s' accepted.\n", type, requested_dir_name); |
334 |
} else { |
335 |
printk(KERN_DEBUG "SAKURA-NOTICE: 'mount %s on %s' accepted.\n", type, requested_dir_name); |
336 |
} |
337 |
break; |
338 |
} |
339 |
if (error_flag && !is_enforce && CheckCCSAccept(CCS_SAKURA_RESTRICT_MOUNT)) { |
340 |
AddMountACL(need_dev ? requested_dev_name : dev_name, requested_dir_name, type, 0, 0, 0); |
341 |
UpdateCounter(CCS_UPDATES_COUNTER_SYSTEM_POLICY); |
342 |
} |
343 |
cleanup: |
344 |
if (requested_dev_name) ccs_free(requested_dev_name); |
345 |
if (requested_dir_name) ccs_free(requested_dir_name); |
346 |
if (fstype) put_filesystem(fstype); |
347 |
} |
348 |
|
349 |
if (error_flag) { |
350 |
int error = -EPERM; |
351 |
const int is_enforce = CheckCCSEnforce(CCS_SAKURA_RESTRICT_MOUNT); |
352 |
const char *realname1 = realpath(dev_name), *realname2 = realpath(dir_name), *exename = GetEXE(); |
353 |
if (strcmp(type, MOUNT_REMOUNT_KEYWORD) == 0) { |
354 |
printk("SAKURA-%s: mount -o remount %s (pid=%d:exe=%s): Permission denied.\n", GetMSG(is_enforce), realname2 ? realname2 : dir_name, current->pid, exename); |
355 |
if (is_enforce && CheckSupervisor("# %s is requesting\nmount -o remount %s\n", exename, realname2 ? realname2 : dir_name) == 0) error = 0; |
356 |
} else if (strcmp(type, MOUNT_BIND_KEYWORD) == 0 || strcmp(type, MOUNT_MOVE_KEYWORD) == 0) { |
357 |
printk("SAKURA-%s: mount %s %s %s (pid=%d:exe=%s): Permission denied.\n", GetMSG(is_enforce), type, realname1 ? realname1 : dev_name, realname2 ? realname2 : dir_name, current->pid, exename); |
358 |
if (is_enforce && CheckSupervisor("# %s is requesting\nmount %s %s %s\n", exename, type, realname1 ? realname1 : dev_name, realname2 ? realname2 : dir_name) == 0) error = 0; |
359 |
} else if (strcmp(type, MOUNT_MAKE_UNBINDABLE_KEYWORD) == 0 || |
360 |
strcmp(type, MOUNT_MAKE_PRIVATE_KEYWORD) == 0 || |
361 |
strcmp(type, MOUNT_MAKE_SLAVE_KEYWORD) == 0 || |
362 |
strcmp(type, MOUNT_MAKE_SHARED_KEYWORD) == 0) { |
363 |
printk("SAKURA-%s: mount %s %s (pid=%d:exe=%s): Permission denied.\n", GetMSG(is_enforce), type, realname2 ? realname2 : dir_name, current->pid, exename); |
364 |
if (is_enforce && CheckSupervisor("# %s is requesting\nmount %s %s", exename, type, realname2 ? realname2 : dir_name) == 0) error = 0; |
365 |
} else { |
366 |
printk("SAKURA-%s: mount -t %s %s %s (pid=%d:exe=%s): Permission denied.\n", GetMSG(is_enforce), type, realname1 ? realname1 : dev_name, realname2 ? realname2 : dir_name, current->pid, exename); |
367 |
if (is_enforce && CheckSupervisor("# %s is requesting\nmount -t %s %s %s\n", exename, type, realname1 ? realname1 : dev_name, realname2 ? realname2 : dir_name) == 0) error = 0; |
368 |
} |
369 |
if (exename) ccs_free(exename); |
370 |
if (realname2) ccs_free(realname2); |
371 |
if (realname1) ccs_free(realname1); |
372 |
if (is_enforce) return error; |
373 |
} |
374 |
return 0; |
375 |
} |
376 |
EXPORT_SYMBOL(CheckMountPermission); |
377 |
|
378 |
int AddMountPolicy(char *data, const int is_delete) |
379 |
{ |
380 |
char *cp, *cp2; |
381 |
const char *fs, *dev, *dir; |
382 |
unsigned int enable = 0, disable = 0; |
383 |
cp2 = data; if ((cp = strchr(cp2, ' ')) == NULL) return -EINVAL; *cp = '\0'; dev = cp2; |
384 |
cp2 = cp + 1; if ((cp = strchr(cp2, ' ')) == NULL) return -EINVAL; *cp = '\0'; dir = cp2; |
385 |
cp2 = cp + 1; |
386 |
if ((cp = strchr(cp2, ' ')) != NULL) { |
387 |
*cp = '\0'; |
388 |
ParseMountOptions(cp + 1, &enable, &disable); |
389 |
} |
390 |
fs = cp2; |
391 |
return AddMountACL(dev, dir, fs, enable, disable, is_delete); |
392 |
} |
393 |
|
394 |
int ReadMountPolicy(struct io_buffer *head) |
395 |
{ |
396 |
struct mount_entry *ptr = head->read_var2; |
397 |
if (!ptr) ptr = mount_list; |
398 |
while (ptr) { |
399 |
char options[64]; |
400 |
head->read_var2 = ptr; |
401 |
MakeMountOptions(options, sizeof(options), ptr->enabled_options, ptr->disabled_options); |
402 |
if (ptr->is_deleted == 0 && io_printf(head, KEYWORD_ALLOW_MOUNT "%s %s %s %s\n", ptr->dev_name->name, ptr->dir_name->name, ptr->fs_type->name, options)) break; |
403 |
ptr = ptr->next; |
404 |
} |
405 |
return ptr ? -ENOMEM : 0; |
406 |
} |
407 |
|
408 |
/***** SAKURA Linux end. *****/ |