オープンソース・ソフトウェアの開発とダウンロード

Subversion リポジトリの参照

Annotation of /trunk/1.7.x/ccs-patch/security/ccsecurity/util.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2985 - (hide annotations) (download) (as text)
Thu Sep 3 08:27:32 2009 UTC (14 years, 8 months ago) by kumaneko
File MIME type: text/x-csrc
File size: 28984 byte(s)
1.7.0-rc
1 kumaneko 111 /*
2 kumaneko 2864 * security/ccsecurity/util.c
3 kumaneko 111 *
4 kumaneko 2030 * Copyright (C) 2005-2009 NTT DATA CORPORATION
5 kumaneko 111 *
6 kumaneko 2985 * Version: 1.7.0 2009/09/03
7 kumaneko 111 *
8     * This file is applicable to both 2.4.30 and 2.6.11 and later.
9     * See README.ccs for ChangeLog.
10     *
11     */
12    
13 kumaneko 2854 #include "internal.h"
14 kumaneko 1052
15 kumaneko 2948 /* Lock for protecting policy. */
16 kumaneko 2690 DEFINE_MUTEX(ccs_policy_lock);
17 kumaneko 2540
18 kumaneko 1052 /* Has /sbin/init started? */
19 kumaneko 2040 bool ccs_policy_loaded;
20 kumaneko 111
21 kumaneko 2948 /* Index table for searching parent category. */
22 kumaneko 2943 static const u8 ccs_index2category[CCS_MAX_MAC_INDEX +
23     CCS_MAX_CAPABILITY_INDEX] = {
24     [CCS_MAC_FILE_EXECUTE] = CCS_MAC_CATEGORY_FILE,
25     [CCS_MAC_FILE_OPEN] = CCS_MAC_CATEGORY_FILE,
26     [CCS_MAC_FILE_CREATE] = CCS_MAC_CATEGORY_FILE,
27     [CCS_MAC_FILE_UNLINK] = CCS_MAC_CATEGORY_FILE,
28     [CCS_MAC_FILE_MKDIR] = CCS_MAC_CATEGORY_FILE,
29     [CCS_MAC_FILE_RMDIR] = CCS_MAC_CATEGORY_FILE,
30     [CCS_MAC_FILE_MKFIFO] = CCS_MAC_CATEGORY_FILE,
31     [CCS_MAC_FILE_MKSOCK] = CCS_MAC_CATEGORY_FILE,
32     [CCS_MAC_FILE_TRUNCATE] = CCS_MAC_CATEGORY_FILE,
33     [CCS_MAC_FILE_SYMLINK] = CCS_MAC_CATEGORY_FILE,
34     [CCS_MAC_FILE_REWRITE] = CCS_MAC_CATEGORY_FILE,
35     [CCS_MAC_FILE_MKBLOCK] = CCS_MAC_CATEGORY_FILE,
36     [CCS_MAC_FILE_MKCHAR] = CCS_MAC_CATEGORY_FILE,
37     [CCS_MAC_FILE_LINK] = CCS_MAC_CATEGORY_FILE,
38     [CCS_MAC_FILE_RENAME] = CCS_MAC_CATEGORY_FILE,
39     [CCS_MAC_FILE_CHMOD] = CCS_MAC_CATEGORY_FILE,
40     [CCS_MAC_FILE_CHOWN] = CCS_MAC_CATEGORY_FILE,
41     [CCS_MAC_FILE_CHGRP] = CCS_MAC_CATEGORY_FILE,
42     [CCS_MAC_FILE_IOCTL] = CCS_MAC_CATEGORY_FILE,
43     [CCS_MAC_FILE_CHROOT] = CCS_MAC_CATEGORY_FILE,
44     [CCS_MAC_FILE_MOUNT] = CCS_MAC_CATEGORY_FILE,
45     [CCS_MAC_FILE_UMOUNT] = CCS_MAC_CATEGORY_FILE,
46     [CCS_MAC_FILE_PIVOT_ROOT] = CCS_MAC_CATEGORY_FILE,
47     [CCS_MAC_ENVIRON] = CCS_MAC_CATEGORY_MISC,
48     [CCS_MAC_NETWORK_UDP_BIND] = CCS_MAC_CATEGORY_NETWORK,
49     [CCS_MAC_NETWORK_UDP_CONNECT] = CCS_MAC_CATEGORY_NETWORK,
50     [CCS_MAC_NETWORK_TCP_BIND] = CCS_MAC_CATEGORY_NETWORK,
51     [CCS_MAC_NETWORK_TCP_LISTEN] = CCS_MAC_CATEGORY_NETWORK,
52     [CCS_MAC_NETWORK_TCP_CONNECT] = CCS_MAC_CATEGORY_NETWORK,
53     [CCS_MAC_NETWORK_TCP_ACCEPT] = CCS_MAC_CATEGORY_NETWORK,
54     [CCS_MAC_NETWORK_RAW_BIND] = CCS_MAC_CATEGORY_NETWORK,
55     [CCS_MAC_NETWORK_RAW_CONNECT] = CCS_MAC_CATEGORY_NETWORK,
56     [CCS_MAC_SIGNAL] = CCS_MAC_CATEGORY_IPC,
57     [CCS_MAX_MAC_INDEX + CCS_INET_STREAM_SOCKET_CREATE]
58     = CCS_MAC_CATEGORY_CAPABILITY,
59     [CCS_MAX_MAC_INDEX + CCS_INET_STREAM_SOCKET_LISTEN]
60     = CCS_MAC_CATEGORY_CAPABILITY,
61     [CCS_MAX_MAC_INDEX + CCS_INET_STREAM_SOCKET_CONNECT]
62     = CCS_MAC_CATEGORY_CAPABILITY,
63     [CCS_MAX_MAC_INDEX + CCS_USE_INET_DGRAM_SOCKET]
64     = CCS_MAC_CATEGORY_CAPABILITY,
65     [CCS_MAX_MAC_INDEX + CCS_USE_INET_RAW_SOCKET]
66     = CCS_MAC_CATEGORY_CAPABILITY,
67     [CCS_MAX_MAC_INDEX + CCS_USE_ROUTE_SOCKET]
68     = CCS_MAC_CATEGORY_CAPABILITY,
69     [CCS_MAX_MAC_INDEX + CCS_USE_PACKET_SOCKET]
70     = CCS_MAC_CATEGORY_CAPABILITY,
71     [CCS_MAX_MAC_INDEX + CCS_SYS_MOUNT]
72     = CCS_MAC_CATEGORY_CAPABILITY,
73     [CCS_MAX_MAC_INDEX + CCS_SYS_UMOUNT]
74     = CCS_MAC_CATEGORY_CAPABILITY,
75     [CCS_MAX_MAC_INDEX + CCS_SYS_REBOOT]
76     = CCS_MAC_CATEGORY_CAPABILITY,
77     [CCS_MAX_MAC_INDEX + CCS_SYS_CHROOT]
78     = CCS_MAC_CATEGORY_CAPABILITY,
79     [CCS_MAX_MAC_INDEX + CCS_SYS_KILL]
80     = CCS_MAC_CATEGORY_CAPABILITY,
81     [CCS_MAX_MAC_INDEX + CCS_SYS_VHANGUP]
82     = CCS_MAC_CATEGORY_CAPABILITY,
83     [CCS_MAX_MAC_INDEX + CCS_SYS_SETTIME]
84     = CCS_MAC_CATEGORY_CAPABILITY,
85     [CCS_MAX_MAC_INDEX + CCS_SYS_NICE]
86     = CCS_MAC_CATEGORY_CAPABILITY,
87     [CCS_MAX_MAC_INDEX + CCS_SYS_SETHOSTNAME]
88     = CCS_MAC_CATEGORY_CAPABILITY,
89     [CCS_MAX_MAC_INDEX + CCS_USE_KERNEL_MODULE]
90     = CCS_MAC_CATEGORY_CAPABILITY,
91     [CCS_MAX_MAC_INDEX + CCS_CREATE_FIFO]
92     = CCS_MAC_CATEGORY_CAPABILITY,
93     [CCS_MAX_MAC_INDEX + CCS_CREATE_BLOCK_DEV]
94     = CCS_MAC_CATEGORY_CAPABILITY,
95     [CCS_MAX_MAC_INDEX + CCS_CREATE_CHAR_DEV]
96     = CCS_MAC_CATEGORY_CAPABILITY,
97     [CCS_MAX_MAC_INDEX + CCS_CREATE_UNIX_SOCKET]
98     = CCS_MAC_CATEGORY_CAPABILITY,
99     [CCS_MAX_MAC_INDEX + CCS_SYS_LINK]
100     = CCS_MAC_CATEGORY_CAPABILITY,
101     [CCS_MAX_MAC_INDEX + CCS_SYS_SYMLINK]
102     = CCS_MAC_CATEGORY_CAPABILITY,
103     [CCS_MAX_MAC_INDEX + CCS_SYS_RENAME]
104     = CCS_MAC_CATEGORY_CAPABILITY,
105     [CCS_MAX_MAC_INDEX + CCS_SYS_UNLINK]
106     = CCS_MAC_CATEGORY_CAPABILITY,
107     [CCS_MAX_MAC_INDEX + CCS_SYS_CHMOD]
108     = CCS_MAC_CATEGORY_CAPABILITY,
109     [CCS_MAX_MAC_INDEX + CCS_SYS_CHOWN]
110     = CCS_MAC_CATEGORY_CAPABILITY,
111     [CCS_MAX_MAC_INDEX + CCS_SYS_IOCTL]
112     = CCS_MAC_CATEGORY_CAPABILITY,
113     [CCS_MAX_MAC_INDEX + CCS_SYS_KEXEC_LOAD]
114     = CCS_MAC_CATEGORY_CAPABILITY,
115     [CCS_MAX_MAC_INDEX + CCS_SYS_PIVOT_ROOT]
116     = CCS_MAC_CATEGORY_CAPABILITY,
117     [CCS_MAX_MAC_INDEX + CCS_SYS_PTRACE]
118     = CCS_MAC_CATEGORY_CAPABILITY,
119     [CCS_MAX_MAC_INDEX + CCS_CONCEAL_MOUNT]
120     = CCS_MAC_CATEGORY_CAPABILITY,
121     };
122    
123 kumaneko 1052 /* Utility functions. */
124 kumaneko 111
125 kumaneko 1052 /**
126 kumaneko 2871 * ccs_parse_ulong - Parse an "unsigned long" value.
127     *
128     * @result: Pointer to "unsigned long".
129     * @str: Pointer to string to parse.
130     *
131     * Returns value type on success, 0 otherwise.
132     *
133     * The @src is updated to point the first character after the value
134     * on success.
135     */
136     u8 ccs_parse_ulong(unsigned long *result, char **str)
137     {
138     const char *cp = *str;
139     char *ep;
140     int base = 10;
141     if (*cp == '0') {
142     char c = *(cp + 1);
143     if (c == 'x' || c == 'X') {
144     base = 16;
145     cp += 2;
146     } else if (c >= '0' && c <= '7') {
147     base = 8;
148     cp++;
149     }
150     }
151     *result = simple_strtoul(cp, &ep, base);
152     if (cp == ep)
153     return 0;
154     *str = ep;
155     switch (base) {
156     case 16:
157 kumaneko 2892 return CCS_VALUE_TYPE_HEXADECIMAL;
158 kumaneko 2871 case 8:
159 kumaneko 2892 return CCS_VALUE_TYPE_OCTAL;
160 kumaneko 2871 default:
161 kumaneko 2892 return CCS_VALUE_TYPE_DECIMAL;
162 kumaneko 2871 }
163     }
164    
165     /**
166     * ccs_print_ulong - Print an "unsigned long" value.
167     *
168     * @buffer: Pointer to buffer.
169     * @buffer_len: Size of @buffer.
170     * @value: An "unsigned long" value.
171     * @type: Type of @value.
172     *
173     * Returns nothing.
174     */
175     void ccs_print_ulong(char *buffer, const int buffer_len,
176     const unsigned long value, const u8 type)
177     {
178 kumaneko 2892 if (type == CCS_VALUE_TYPE_DECIMAL)
179 kumaneko 2871 snprintf(buffer, buffer_len, "%lu", value);
180 kumaneko 2892 else if (type == CCS_VALUE_TYPE_OCTAL)
181 kumaneko 2871 snprintf(buffer, buffer_len, "0%lo", value);
182 kumaneko 2892 else if (type == CCS_VALUE_TYPE_HEXADECIMAL)
183 kumaneko 2871 snprintf(buffer, buffer_len, "0x%lX", value);
184     else
185     snprintf(buffer, buffer_len, "type(%u)", type);
186     }
187    
188 kumaneko 2948 /**
189     * ccs_parse_name_union - Parse a ccs_name_union.
190     *
191     * @filename: Name or name group.
192     * @ptr: Pointer to "struct ccs_name_union".
193     *
194     * Returns true on success, false otherwise.
195     */
196 kumaneko 2894 bool ccs_parse_name_union(const char *filename, struct ccs_name_union *ptr)
197     {
198     if (!ccs_is_correct_path(filename, 0, 0, 0))
199     return false;
200     if (filename[0] == '@') {
201     ptr->group = ccs_get_path_group(filename + 1);
202     ptr->is_group = true;
203     return ptr->group != NULL;
204     }
205     ptr->filename = ccs_get_name(filename);
206     ptr->is_group = false;
207     return ptr->filename != NULL;
208     }
209    
210 kumaneko 2948 /**
211     * ccs_parse_number_union - Parse a ccs_number_union.
212     *
213     * @data: Number or number range or number group.
214     * @ptr: Pointer to "struct ccs_number_union".
215     *
216     * Returns true on success, false otherwise.
217     */
218 kumaneko 2888 bool ccs_parse_number_union(char *data, struct ccs_number_union *num)
219 kumaneko 2871 {
220     u8 type;
221     unsigned long v;
222     memset(num, 0, sizeof(*num));
223 kumaneko 2890 if (data[0] == '@') {
224     if (!ccs_is_correct_path(data, 0, 0, 0))
225     return false;
226     num->group = ccs_get_number_group(data + 1);
227     num->is_group = true;
228     return num->group != NULL;
229     }
230 kumaneko 2871 type = ccs_parse_ulong(&v, &data);
231     if (!type)
232     return false;
233 kumaneko 2888 num->values[0] = v;
234     num->min_type = type;
235 kumaneko 2871 if (!*data) {
236 kumaneko 2888 num->values[1] = v;
237     num->max_type = type;
238 kumaneko 2871 return true;
239     }
240     if (*data++ != '-')
241     return false;
242     type = ccs_parse_ulong(&v, &data);
243     if (!type || *data)
244     return false;
245 kumaneko 2888 num->values[1] = v;
246     num->max_type = type;
247 kumaneko 2871 return true;
248     }
249    
250     /**
251 kumaneko 2002 * ccs_is_byte_range - Check whether the string isa \ooo style octal value.
252 kumaneko 1052 *
253     * @str: Pointer to the string.
254     *
255     * Returns true if @str is a \ooo style octal value, false otherwise.
256     */
257 kumaneko 2002 static inline bool ccs_is_byte_range(const char *str)
258 kumaneko 1052 {
259     return *str >= '0' && *str++ <= '3' &&
260     *str >= '0' && *str++ <= '7' &&
261     *str >= '0' && *str <= '7';
262     }
263    
264     /**
265 kumaneko 2002 * ccs_is_decimal - Check whether the character is a decimal character.
266 kumaneko 1052 *
267     * @c: The character to check.
268     *
269     * Returns true if @c is a decimal character, false otherwise.
270     */
271 kumaneko 2002 static inline bool ccs_is_decimal(const char c)
272 kumaneko 1052 {
273 kumaneko 1468 return c >= '0' && c <= '9';
274 kumaneko 1052 }
275    
276     /**
277 kumaneko 2002 * ccs_is_hexadecimal - Check whether the character is a hexadecimal character.
278 kumaneko 1052 *
279     * @c: The character to check.
280     *
281     * Returns true if @c is a hexadecimal character, false otherwise.
282     */
283 kumaneko 2002 static inline bool ccs_is_hexadecimal(const char c)
284 kumaneko 1052 {
285 kumaneko 1468 return (c >= '0' && c <= '9') ||
286 kumaneko 1052 (c >= 'A' && c <= 'F') ||
287 kumaneko 1468 (c >= 'a' && c <= 'f');
288 kumaneko 1052 }
289    
290     /**
291 kumaneko 2002 * ccs_is_alphabet_char - Check whether the character is an alphabet.
292 kumaneko 1052 *
293     * @c: The character to check.
294     *
295     * Returns true if @c is an alphabet character, false otherwise.
296     */
297 kumaneko 2002 static inline bool ccs_is_alphabet_char(const char c)
298 kumaneko 1052 {
299 kumaneko 1794 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
300 kumaneko 1052 }
301    
302     /**
303 kumaneko 2002 * ccs_make_byte - Make byte value from three octal characters.
304 kumaneko 1064 *
305     * @c1: The first character.
306     * @c2: The second character.
307     * @c3: The third character.
308     *
309     * Returns byte value.
310     */
311 kumaneko 2002 static inline u8 ccs_make_byte(const u8 c1, const u8 c2, const u8 c3)
312 kumaneko 1064 {
313     return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
314     }
315    
316     /**
317 kumaneko 2002 * ccs_str_starts - Check whether the given string starts with the given keyword.
318 kumaneko 1052 *
319     * @src: Pointer to pointer to the string.
320     * @find: Pointer to the keyword.
321     *
322     * Returns true if @src starts with @find, false otherwise.
323     *
324     * The @src is updated to point the first character after the @find
325 kumaneko 1064 * if @src starts with @find.
326 kumaneko 1052 */
327 kumaneko 2863 bool ccs_str_starts(char **src, const char *find)
328 kumaneko 1052 {
329     const int len = strlen(find);
330     char *tmp = *src;
331     if (strncmp(tmp, find, len))
332     return false;
333     tmp += len;
334     *src = tmp;
335     return true;
336     }
337    
338     /**
339 kumaneko 2002 * ccs_normalize_line - Format string.
340 kumaneko 1052 *
341     * @buffer: The line to normalize.
342     *
343 kumaneko 111 * Leading and trailing whitespaces are removed.
344     * Multiple whitespaces are packed into single space.
345 kumaneko 1052 *
346     * Returns nothing.
347 kumaneko 111 */
348 kumaneko 2308 void ccs_normalize_line(unsigned char *buffer)
349 kumaneko 111 {
350 kumaneko 1064 unsigned char *sp = buffer;
351     unsigned char *dp = buffer;
352 kumaneko 1006 bool first = true;
353 kumaneko 1052 while (*sp && (*sp <= ' ' || *sp >= 127))
354     sp++;
355 kumaneko 111 while (*sp) {
356 kumaneko 1052 if (!first)
357     *dp++ = ' ';
358 kumaneko 1006 first = false;
359 kumaneko 1052 while (*sp > ' ' && *sp < 127)
360     *dp++ = *sp++;
361     while (*sp && (*sp <= ' ' || *sp >= 127))
362     sp++;
363 kumaneko 111 }
364     *dp = '\0';
365     }
366    
367 kumaneko 1052 /**
368 kumaneko 2779 * ccs_tokenize - Tokenize string.
369     *
370     * @buffer: The line to tokenize.
371     * @w: Pointer to "char *".
372     * @size: Sizeof @w .
373     *
374     * Returns true on success, false otherwise.
375     */
376     bool ccs_tokenize(char *buffer, char *w[], size_t size)
377     {
378     int count = size / sizeof(char *);
379     int i;
380     for (i = 0; i < count; i++)
381     w[i] = "";
382     for (i = 0; i < count; i++) {
383     char *cp = strchr(buffer, ' ');
384     if (cp)
385     *cp = '\0';
386     w[i] = buffer;
387     if (!cp)
388     break;
389     buffer = cp + 1;
390     }
391     return i < count || !*buffer;
392     }
393    
394     /**
395 kumaneko 1054 * ccs_is_correct_path - Validate a pathname.
396     * @filename: The pathname to check.
397     * @start_type: Should the pathname start with '/'?
398     * 1 = must / -1 = must not / 0 = don't care
399     * @pattern_type: Can the pathname contain a wildcard?
400     * 1 = must / -1 = must not / 0 = don't care
401     * @end_type: Should the pathname end with '/'?
402     * 1 = must / -1 = must not / 0 = don't care
403 kumaneko 1052 *
404 kumaneko 1054 * Check whether the given filename follows the naming rules.
405 kumaneko 1052 * Returns true if @filename follows the naming rules, false otherwise.
406 kumaneko 111 */
407 kumaneko 1052 bool ccs_is_correct_path(const char *filename, const s8 start_type,
408 kumaneko 2577 const s8 pattern_type, const s8 end_type)
409 kumaneko 111 {
410 kumaneko 1006 bool contains_pattern = false;
411 kumaneko 1064 unsigned char c;
412     unsigned char d;
413     unsigned char e;
414 kumaneko 1052 if (!filename)
415     goto out;
416 kumaneko 111 c = *filename;
417     if (start_type == 1) { /* Must start with '/' */
418 kumaneko 1052 if (c != '/')
419     goto out;
420 kumaneko 111 } else if (start_type == -1) { /* Must not start with '/' */
421 kumaneko 1052 if (c == '/')
422     goto out;
423 kumaneko 111 }
424 kumaneko 1052 if (c)
425 kumaneko 1795 c = *(filename + strlen(filename) - 1);
426 kumaneko 111 if (end_type == 1) { /* Must end with '/' */
427 kumaneko 1052 if (c != '/')
428     goto out;
429 kumaneko 111 } else if (end_type == -1) { /* Must not end with '/' */
430 kumaneko 1052 if (c == '/')
431     goto out;
432 kumaneko 111 }
433 kumaneko 1747 while (1) {
434     c = *filename++;
435     if (!c)
436     break;
437 kumaneko 111 if (c == '\\') {
438 kumaneko 1747 c = *filename++;
439     switch (c) {
440 kumaneko 111 case '\\': /* "\\" */
441     continue;
442     case '$': /* "\$" */
443     case '+': /* "\+" */
444     case '?': /* "\?" */
445     case '*': /* "\*" */
446     case '@': /* "\@" */
447     case 'x': /* "\x" */
448     case 'X': /* "\X" */
449     case 'a': /* "\a" */
450     case 'A': /* "\A" */
451 kumaneko 206 case '-': /* "\-" */
452 kumaneko 1052 if (pattern_type == -1)
453     break; /* Must not contain pattern */
454 kumaneko 1006 contains_pattern = true;
455 kumaneko 111 continue;
456     case '0': /* "\ooo" */
457     case '1':
458     case '2':
459     case '3':
460 kumaneko 1052 d = *filename++;
461     if (d < '0' || d > '7')
462     break;
463     e = *filename++;
464     if (e < '0' || e > '7')
465     break;
466 kumaneko 2002 c = ccs_make_byte(c, d, e);
467 kumaneko 1052 if (c && (c <= ' ' || c >= 127))
468     continue; /* pattern is not \000 */
469 kumaneko 111 }
470     goto out;
471     } else if (c <= ' ' || c >= 127) {
472     goto out;
473     }
474     }
475     if (pattern_type == 1) { /* Must contain pattern */
476 kumaneko 1052 if (!contains_pattern)
477     goto out;
478 kumaneko 111 }
479 kumaneko 1006 return true;
480 kumaneko 111 out:
481 kumaneko 1006 return false;
482 kumaneko 111 }
483    
484 kumaneko 1052 /**
485 kumaneko 1054 * ccs_is_correct_domain - Check whether the given domainname follows the naming rules.
486     * @domainname: The domainname to check.
487 kumaneko 1052 *
488     * Returns true if @domainname follows the naming rules, false otherwise.
489 kumaneko 111 */
490 kumaneko 2577 bool ccs_is_correct_domain(const unsigned char *domainname)
491 kumaneko 111 {
492 kumaneko 1064 unsigned char c;
493     unsigned char d;
494     unsigned char e;
495 kumaneko 1052 if (!domainname || strncmp(domainname, ROOT_NAME, ROOT_NAME_LEN))
496     goto out;
497 kumaneko 111 domainname += ROOT_NAME_LEN;
498 kumaneko 1052 if (!*domainname)
499     return true;
500 kumaneko 111 do {
501 kumaneko 1052 if (*domainname++ != ' ')
502     goto out;
503     if (*domainname++ != '/')
504     goto out;
505 kumaneko 1747 while (1) {
506     c = *domainname;
507     if (!c || c == ' ')
508     break;
509 kumaneko 111 domainname++;
510     if (c == '\\') {
511 kumaneko 1052 c = *domainname++;
512     switch ((c)) {
513 kumaneko 111 case '\\': /* "\\" */
514     continue;
515     case '0': /* "\ooo" */
516     case '1':
517     case '2':
518     case '3':
519 kumaneko 1052 d = *domainname++;
520     if (d < '0' || d > '7')
521     break;
522     e = *domainname++;
523     if (e < '0' || e > '7')
524     break;
525 kumaneko 2002 c = ccs_make_byte(c, d, e);
526 kumaneko 1052 if (c && (c <= ' ' || c >= 127))
527     /* pattern is not \000 */
528     continue;
529 kumaneko 111 }
530     goto out;
531     } else if (c < ' ' || c >= 127) {
532     goto out;
533     }
534     }
535     } while (*domainname);
536 kumaneko 1006 return true;
537 kumaneko 111 out:
538 kumaneko 1006 return false;
539 kumaneko 111 }
540    
541 kumaneko 1052 /**
542     * ccs_is_domain_def - Check whether the given token can be a domainname.
543     *
544     * @buffer: The token to check.
545     *
546     * Returns true if @buffer possibly be a domainname, false otherwise.
547     */
548     bool ccs_is_domain_def(const unsigned char *buffer)
549 kumaneko 461 {
550 kumaneko 1052 return !strncmp(buffer, ROOT_NAME, ROOT_NAME_LEN);
551 kumaneko 461 }
552    
553 kumaneko 1052 /**
554     * ccs_find_domain - Find a domain by the given name.
555     *
556 kumaneko 1054 * @domainname: The domainname to find.
557 kumaneko 1052 *
558 kumaneko 2690 * Returns pointer to "struct ccs_domain_info" if found, NULL otherwise.
559     *
560 kumaneko 2828 * Caller holds ccs_read_lock().
561 kumaneko 1052 */
562 kumaneko 2690 struct ccs_domain_info *ccs_find_domain(const char *domainname)
563 kumaneko 461 {
564 kumaneko 2282 struct ccs_domain_info *domain;
565 kumaneko 2002 struct ccs_path_info name;
566 kumaneko 1052 name.name = domainname;
567     ccs_fill_path_info(&name);
568 kumaneko 2690 list_for_each_entry_rcu(domain, &ccs_domain_list, list) {
569 kumaneko 2692 if (!domain->is_deleted &&
570     !ccs_pathcmp(&name, domain->domainname))
571     return domain;
572 kumaneko 461 }
573 kumaneko 2692 return NULL;
574 kumaneko 461 }
575    
576 kumaneko 1052 /**
577 kumaneko 2002 * ccs_path_depth - Evaluate the number of '/' in a string.
578 kumaneko 1052 *
579     * @pathname: The string to evaluate.
580     *
581     * Returns path depth of the string.
582     *
583     * I score 2 for each of the '/' in the @pathname
584     * and score 1 if the @pathname ends with '/'.
585     */
586 kumaneko 2002 static int ccs_path_depth(const char *pathname)
587 kumaneko 111 {
588     int i = 0;
589     if (pathname) {
590 kumaneko 1795 const char *ep = pathname + strlen(pathname);
591 kumaneko 111 if (pathname < ep--) {
592 kumaneko 1052 if (*ep != '/')
593     i++;
594     while (pathname <= ep)
595     if (*ep-- == '/')
596     i += 2;
597 kumaneko 111 }
598     }
599     return i;
600     }
601    
602 kumaneko 1052 /**
603 kumaneko 2002 * ccs_const_part_length - Evaluate the initial length without a pattern in a token.
604 kumaneko 1052 *
605     * @filename: The string to evaluate.
606     *
607 kumaneko 1064 * Returns the initial length without a pattern in @filename.
608 kumaneko 1052 */
609 kumaneko 2002 static int ccs_const_part_length(const char *filename)
610 kumaneko 111 {
611 kumaneko 1052 char c;
612 kumaneko 111 int len = 0;
613 kumaneko 1052 if (!filename)
614     return 0;
615 kumaneko 1747 while (1) {
616     c = *filename++;
617     if (!c)
618     break;
619 kumaneko 1052 if (c != '\\') {
620     len++;
621     continue;
622 kumaneko 111 }
623 kumaneko 1052 c = *filename++;
624     switch (c) {
625     case '\\': /* "\\" */
626     len += 2;
627     continue;
628     case '0': /* "\ooo" */
629     case '1':
630     case '2':
631     case '3':
632     c = *filename++;
633     if (c < '0' || c > '7')
634     break;
635     c = *filename++;
636     if (c < '0' || c > '7')
637     break;
638     len += 4;
639     continue;
640     }
641     break;
642 kumaneko 111 }
643     return len;
644     }
645    
646 kumaneko 1052 /**
647 kumaneko 2002 * ccs_fill_path_info - Fill in "struct ccs_path_info" members.
648 kumaneko 1052 *
649 kumaneko 2002 * @ptr: Pointer to "struct ccs_path_info" to fill in.
650 kumaneko 1052 *
651 kumaneko 2002 * The caller sets "struct ccs_path_info"->name.
652 kumaneko 1052 */
653 kumaneko 2002 void ccs_fill_path_info(struct ccs_path_info *ptr)
654 kumaneko 111 {
655     const char *name = ptr->name;
656     const int len = strlen(name);
657     ptr->total_len = len;
658 kumaneko 2002 ptr->const_len = ccs_const_part_length(name);
659 kumaneko 111 ptr->is_dir = len && (name[len - 1] == '/');
660     ptr->is_patterned = (ptr->const_len < len);
661     ptr->hash = full_name_hash(name, len);
662 kumaneko 2002 ptr->depth = ccs_path_depth(name);
663 kumaneko 111 }
664    
665 kumaneko 1052 /**
666 kumaneko 2039 * ccs_file_matches_pattern2 - Pattern matching without '/' character
667 kumaneko 1052 * and "\-" pattern.
668     *
669     * @filename: The start of string to check.
670     * @filename_end: The end of string to check.
671     * @pattern: The start of pattern to compare.
672     * @pattern_end: The end of pattern to compare.
673     *
674     * Returns true if @filename matches @pattern, false otherwise.
675     */
676 kumaneko 2039 static bool ccs_file_matches_pattern2(const char *filename,
677     const char *filename_end,
678     const char *pattern,
679     const char *pattern_end)
680 kumaneko 111 {
681     while (filename < filename_end && pattern < pattern_end) {
682 kumaneko 1052 char c;
683 kumaneko 111 if (*pattern != '\\') {
684 kumaneko 1052 if (*filename++ != *pattern++)
685     return false;
686     continue;
687     }
688     c = *filename;
689     pattern++;
690     switch (*pattern) {
691 kumaneko 1064 int i;
692     int j;
693 kumaneko 1052 case '?':
694     if (c == '/') {
695     return false;
696     } else if (c == '\\') {
697     if (filename[1] == '\\')
698     filename++;
699 kumaneko 2002 else if (ccs_is_byte_range(filename + 1))
700 kumaneko 1052 filename += 3;
701     else
702 kumaneko 1006 return false;
703 kumaneko 1052 }
704     break;
705     case '\\':
706     if (c != '\\')
707     return false;
708     if (*++filename != '\\')
709     return false;
710     break;
711     case '+':
712 kumaneko 2002 if (!ccs_is_decimal(c))
713 kumaneko 1052 return false;
714     break;
715     case 'x':
716 kumaneko 2002 if (!ccs_is_hexadecimal(c))
717 kumaneko 1052 return false;
718     break;
719     case 'a':
720 kumaneko 2002 if (!ccs_is_alphabet_char(c))
721 kumaneko 1052 return false;
722     break;
723     case '0':
724     case '1':
725     case '2':
726     case '3':
727 kumaneko 2002 if (c == '\\' && ccs_is_byte_range(filename + 1)
728 kumaneko 1052 && strncmp(filename + 1, pattern, 3) == 0) {
729     filename += 3;
730     pattern += 2;
731 kumaneko 111 break;
732 kumaneko 1052 }
733     return false; /* Not matched. */
734     case '*':
735     case '@':
736     for (i = 0; i <= filename_end - filename; i++) {
737 kumaneko 2039 if (ccs_file_matches_pattern2(filename + i,
738     filename_end,
739     pattern + 1,
740     pattern_end))
741 kumaneko 1052 return true;
742     c = filename[i];
743     if (c == '.' && *pattern == '@')
744 kumaneko 111 break;
745 kumaneko 1052 if (c != '\\')
746     continue;
747     if (filename[i + 1] == '\\')
748     i++;
749 kumaneko 2002 else if (ccs_is_byte_range(filename + i + 1))
750 kumaneko 1052 i += 3;
751     else
752     break; /* Bad pattern. */
753 kumaneko 111 }
754 kumaneko 1052 return false; /* Not matched. */
755     default:
756     j = 0;
757     c = *pattern;
758     if (c == '$') {
759 kumaneko 2002 while (ccs_is_decimal(filename[j]))
760 kumaneko 1052 j++;
761     } else if (c == 'X') {
762 kumaneko 2002 while (ccs_is_hexadecimal(filename[j]))
763 kumaneko 1052 j++;
764     } else if (c == 'A') {
765 kumaneko 2002 while (ccs_is_alphabet_char(filename[j]))
766 kumaneko 1052 j++;
767     }
768     for (i = 1; i <= j; i++) {
769 kumaneko 2039 if (ccs_file_matches_pattern2(filename + i,
770     filename_end,
771     pattern + 1,
772     pattern_end))
773 kumaneko 1052 return true;
774     }
775     return false; /* Not matched or bad pattern. */
776 kumaneko 111 }
777 kumaneko 1052 filename++;
778     pattern++;
779 kumaneko 111 }
780 kumaneko 1052 while (*pattern == '\\' &&
781     (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
782     pattern += 2;
783 kumaneko 1468 return filename == filename_end && pattern == pattern_end;
784 kumaneko 111 }
785    
786 kumaneko 1052 /**
787 kumaneko 2039 * ccs_file_matches_pattern - Pattern matching without without '/' character.
788 kumaneko 1052 *
789     * @filename: The start of string to check.
790     * @filename_end: The end of string to check.
791     * @pattern: The start of pattern to compare.
792     * @pattern_end: The end of pattern to compare.
793     *
794     * Returns true if @filename matches @pattern, false otherwise.
795     */
796 kumaneko 2039 static bool ccs_file_matches_pattern(const char *filename,
797     const char *filename_end,
798     const char *pattern,
799     const char *pattern_end)
800 kumaneko 206 {
801     const char *pattern_start = pattern;
802 kumaneko 1006 bool first = true;
803     bool result;
804 kumaneko 206 while (pattern < pattern_end - 1) {
805 kumaneko 1052 /* Split at "\-" pattern. */
806     if (*pattern++ != '\\' || *pattern++ != '-')
807     continue;
808 kumaneko 2039 result = ccs_file_matches_pattern2(filename, filename_end,
809 kumaneko 2040 pattern_start, pattern - 2);
810 kumaneko 1052 if (first)
811     result = !result;
812     if (result)
813     return false;
814 kumaneko 1006 first = false;
815 kumaneko 206 pattern_start = pattern;
816     }
817 kumaneko 2039 result = ccs_file_matches_pattern2(filename, filename_end,
818     pattern_start, pattern_end);
819 kumaneko 206 return first ? result : !result;
820     }
821    
822 kumaneko 1052 /**
823 kumaneko 1054 * ccs_path_matches_pattern - Check whether the given filename matches the given pattern.
824 kumaneko 1052 * @filename: The filename to check.
825     * @pattern: The pattern to compare.
826 kumaneko 111 *
827 kumaneko 1052 * Returns true if matches, false otherwise.
828     *
829     * The following patterns are available.
830     * \\ \ itself.
831     * \ooo Octal representation of a byte.
832     * \* More than or equals to 0 character other than '/'.
833     * \@ More than or equals to 0 character other than '/' or '.'.
834     * \? 1 byte character other than '/'.
835     * \$ More than or equals to 1 decimal digit.
836     * \+ 1 decimal digit.
837     * \X More than or equals to 1 hexadecimal digit.
838     * \x 1 hexadecimal digit.
839     * \A More than or equals to 1 alphabet character.
840     * \a 1 alphabet character.
841     * \- Subtraction operator.
842 kumaneko 111 */
843 kumaneko 2002 bool ccs_path_matches_pattern(const struct ccs_path_info *filename,
844     const struct ccs_path_info *pattern)
845 kumaneko 111 {
846 kumaneko 1052 /*
847     if (!filename || !pattern)
848     return false;
849     */
850     const char *f = filename->name;
851     const char *p = pattern->name;
852     const int len = pattern->const_len;
853     /* If @pattern doesn't contain pattern, I can use strcmp(). */
854     if (!pattern->is_patterned)
855     return !ccs_pathcmp(filename, pattern);
856 kumaneko 2892 /* Don't compare if the number of '/' differs. */
857 kumaneko 1052 if (filename->depth != pattern->depth)
858     return false;
859     /* Compare the initial length without patterns. */
860     if (strncmp(f, p, len))
861     return false;
862     f += len;
863     p += len;
864     /* Main loop. Compare each directory component. */
865     while (*f && *p) {
866     const char *f_delimiter = strchr(f, '/');
867     const char *p_delimiter = strchr(p, '/');
868     if (!f_delimiter)
869 kumaneko 1795 f_delimiter = f + strlen(f);
870 kumaneko 1052 if (!p_delimiter)
871 kumaneko 1795 p_delimiter = p + strlen(p);
872 kumaneko 2040 if (!ccs_file_matches_pattern(f, f_delimiter, p, p_delimiter))
873 kumaneko 1052 return false;
874     f = f_delimiter;
875     if (*f)
876     f++;
877     p = p_delimiter;
878     if (*p)
879     p++;
880 kumaneko 111 }
881 kumaneko 1052 /* Ignore trailing "\*" and "\@" in @pattern. */
882     while (*p == '\\' &&
883     (*(p + 1) == '*' || *(p + 1) == '@'))
884     p += 2;
885 kumaneko 1468 return !*f && !*p;
886 kumaneko 111 }
887    
888 kumaneko 1052 /**
889     * ccs_get_exe - Get ccs_realpath() of current process.
890     *
891     * Returns the ccs_realpath() of current process on success, NULL otherwise.
892     *
893 kumaneko 2711 * This function uses kzalloc(), so the caller must kfree()
894 kumaneko 1052 * if this function didn't return NULL.
895 kumaneko 111 */
896 kumaneko 1052 const char *ccs_get_exe(void)
897 kumaneko 111 {
898 kumaneko 737 struct mm_struct *mm = current->mm;
899     struct vm_area_struct *vma;
900     const char *cp = NULL;
901 kumaneko 1052 if (!mm)
902     return NULL;
903 kumaneko 737 down_read(&mm->mmap_sem);
904     for (vma = mm->mmap; vma; vma = vma->vm_next) {
905     if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
906 kumaneko 2911 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
907     struct path path = { vma->vm_file->f_vfsmnt,
908     vma->vm_file->f_dentry };
909     cp = ccs_realpath_from_path(&path);
910     #else
911     cp = ccs_realpath_from_path(&vma->vm_file->f_path);
912     #endif
913 kumaneko 737 break;
914 kumaneko 111 }
915     }
916 kumaneko 737 up_read(&mm->mmap_sem);
917     return cp;
918 kumaneko 111 }
919    
920 kumaneko 1052 /**
921 kumaneko 2943 * ccs_get_audit - Get audit mode.
922     *
923     * @profile: Profile number.
924     * @index: Index number of functionality.
925     * @is_granted: True if granted log, false otehrwise.
926     *
927     * Returns mode.
928     */
929     bool ccs_get_audit(const u8 profile, const u8 index, const bool is_granted)
930     {
931     u8 mode;
932     const u8 category = ccs_index2category[index] + CCS_MAX_MAC_INDEX
933     + CCS_MAX_CAPABILITY_INDEX;
934 kumaneko 2958 if (!ccs_policy_loaded)
935 kumaneko 2943 return false;
936 kumaneko 2958 mode = ccs_profile(profile)->config[index];
937     if (mode == CCS_CONFIG_USE_DEFAULT)
938     mode = ccs_profile(profile)->config[category];
939     if (mode == CCS_CONFIG_USE_DEFAULT)
940     mode = ccs_profile(profile)->default_config;
941 kumaneko 2943 if (is_granted)
942 kumaneko 2973 return mode & CCS_CONFIG_WANT_GRANT_LOG;
943     return mode & CCS_CONFIG_WANT_REJECT_LOG;
944 kumaneko 2943 }
945    
946     /**
947     * ccs_get_mode - Get MAC mode.
948     *
949     * @profile: Profile number.
950     * @index: Index number of functionality.
951     *
952     * Returns mode.
953     */
954     int ccs_get_mode(const u8 profile, const u8 index)
955     {
956     u8 mode;
957     const u8 category = ccs_index2category[index] + CCS_MAX_MAC_INDEX
958     + CCS_MAX_CAPABILITY_INDEX;
959 kumaneko 2958 if (!ccs_policy_loaded)
960     return CCS_CONFIG_DISABLED;
961     mode = ccs_profile(profile)->config[index];
962     if (mode == CCS_CONFIG_USE_DEFAULT)
963     mode = ccs_profile(profile)->config[category];
964     if (mode == CCS_CONFIG_USE_DEFAULT)
965     mode = ccs_profile(profile)->default_config;
966 kumaneko 2943 return mode & 3;
967     }
968    
969     /**
970 kumaneko 1657 * ccs_init_request_info - Initialize "struct ccs_request_info" members.
971     *
972     * @r: Pointer to "struct ccs_request_info" to initialize.
973 kumaneko 2282 * @domain: Pointer to "struct ccs_domain_info". NULL for ccs_current_domain().
974 kumaneko 1657 * @index: Index number of functionality.
975 kumaneko 2911 *
976     * Returns mode.
977 kumaneko 1657 */
978 kumaneko 2911 int ccs_init_request_info(struct ccs_request_info *r,
979     struct ccs_domain_info *domain, const u8 index)
980 kumaneko 1657 {
981 kumaneko 2943 u8 profile;
982 kumaneko 1657 memset(r, 0, sizeof(*r));
983     if (!domain)
984 kumaneko 2282 domain = ccs_current_domain();
985 kumaneko 2690 r->domain = domain;
986 kumaneko 2943 profile = domain->profile;
987     r->profile = profile;
988 kumaneko 2918 r->type = index;
989 kumaneko 2943 r->mode = ccs_get_mode(profile, index);
990 kumaneko 2911 return r->mode;
991 kumaneko 1657 }
992    
993     /**
994 kumaneko 2943 * ccs_last_word - Get last component of a line.
995 kumaneko 1052 *
996 kumaneko 2943 * @line: A line.
997 kumaneko 1657 *
998 kumaneko 2943 * Returns the last word of a line.
999 kumaneko 1052 */
1000 kumaneko 2943 const char *ccs_last_word(const char *name)
1001 kumaneko 111 {
1002 kumaneko 2943 const char *cp = strrchr(name, ' ');
1003     if (cp)
1004     return cp + 1;
1005     return name;
1006 kumaneko 111 }
1007    
1008 kumaneko 2948 /**
1009     * ccs_warn_log - Print warning or error message on console.
1010     *
1011     * @r: Pointer to "struct ccs_request_info".
1012     * @fmt: The printf()'s format string, followed by parameters.
1013     */
1014 kumaneko 2943 void ccs_warn_log(struct ccs_request_info *r, const char *fmt, ...)
1015     {
1016     int len = PAGE_SIZE;
1017     va_list args;
1018     char *buffer;
1019 kumaneko 2958 const struct ccs_profile *profile =
1020     ccs_profile(r->domain->profile);
1021     switch (r->mode) {
1022     case CCS_CONFIG_ENFORCING:
1023 kumaneko 2962 if (!profile->enforcing->enforcing_verbose)
1024 kumaneko 2958 return;
1025     break;
1026     case CCS_CONFIG_PERMISSIVE:
1027 kumaneko 2962 if (!profile->permissive->permissive_verbose)
1028 kumaneko 2958 return;
1029     break;
1030     case CCS_CONFIG_LEARNING:
1031 kumaneko 2962 if (!profile->learning->learning_verbose)
1032 kumaneko 2958 return;
1033     break;
1034     }
1035 kumaneko 2943 while (1) {
1036     int len2;
1037     buffer = kmalloc(len, GFP_KERNEL);
1038     if (!buffer)
1039     return;
1040     va_start(args, fmt);
1041     len2 = vsnprintf(buffer, len - 1, fmt, args);
1042     va_end(args);
1043 kumaneko 2981 if (len2 <= len - 1) {
1044 kumaneko 2943 buffer[len2] = '\0';
1045     break;
1046     }
1047     len = len2 + 1;
1048     kfree(buffer);
1049     }
1050     printk(KERN_WARNING "%s: Access %s denied for %s\n",
1051 kumaneko 2958 r->mode == CCS_CONFIG_ENFORCING ? "ERROR" : "WARNING", buffer,
1052 kumaneko 2943 ccs_last_word(r->domain->domainname->name));
1053     kfree(buffer);
1054     }
1055    
1056 kumaneko 1052 /**
1057 kumaneko 2209 * ccs_domain_quota_ok - Check for domain's quota.
1058 kumaneko 1052 *
1059 kumaneko 2780 * @r: Pointer to "struct ccs_request_info".
1060 kumaneko 1052 *
1061     * Returns true if the domain is not exceeded quota, false otherwise.
1062 kumaneko 2690 *
1063 kumaneko 2828 * Caller holds ccs_read_lock().
1064 kumaneko 1052 */
1065 kumaneko 2780 bool ccs_domain_quota_ok(struct ccs_request_info *r)
1066 kumaneko 512 {
1067     unsigned int count = 0;
1068 kumaneko 2780 struct ccs_domain_info *domain = r->domain;
1069 kumaneko 2002 struct ccs_acl_info *ptr;
1070 kumaneko 2780 if (r->mode != 1)
1071     return false;
1072 kumaneko 1052 if (!domain)
1073     return true;
1074 kumaneko 2690 list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
1075 kumaneko 2900 if (ptr->is_deleted)
1076 kumaneko 1064 continue;
1077 kumaneko 2900 switch (ptr->type) {
1078 kumaneko 1064 u16 perm;
1079 kumaneko 2916 u8 i;
1080 kumaneko 2915 case CCS_TYPE_PATH_ACL:
1081 kumaneko 2916 perm = container_of(ptr, struct ccs_path_acl, head)->
1082     perm;
1083     for (i = 0; i < CCS_MAX_PATH_OPERATION; i++)
1084     if (perm & (1 << i))
1085     count++;
1086     if (perm & (1 << CCS_TYPE_READ_WRITE))
1087     count -= 2;
1088 kumaneko 1064 break;
1089 kumaneko 2922 case CCS_TYPE_PATH2_ACL:
1090     perm = container_of(ptr, struct ccs_path2_acl,
1091 kumaneko 2916 head)->perm;
1092 kumaneko 2922 for (i = 0; i < CCS_MAX_PATH2_OPERATION; i++)
1093 kumaneko 2916 if (perm & (1 << i))
1094     count++;
1095 kumaneko 1064 break;
1096 kumaneko 2892 case CCS_TYPE_EXECUTE_HANDLER:
1097     case CCS_TYPE_DENIED_EXECUTE_HANDLER:
1098 kumaneko 1064 break;
1099 kumaneko 2915 case CCS_TYPE_PATH_NUMBER_ACL:
1100 kumaneko 2916 perm = container_of(ptr, struct ccs_path_number_acl,
1101     head)->perm;
1102     for (i = 0; i < CCS_MAX_PATH_NUMBER_OPERATION; i++)
1103     if (perm & (1 << i))
1104     count++;
1105 kumaneko 2915 break;
1106 kumaneko 2922 case CCS_TYPE_PATH_NUMBER3_ACL:
1107 kumaneko 2916 perm = container_of(ptr,
1108 kumaneko 2922 struct ccs_path_number3_acl,
1109 kumaneko 2916 head)->perm;
1110 kumaneko 2922 for (i = 0; i < CCS_MAX_PATH_NUMBER3_OPERATION;
1111 kumaneko 2916 i++)
1112     if (perm & (1 << i))
1113     count++;
1114 kumaneko 2915 break;
1115 kumaneko 2916 case CCS_TYPE_IP_NETWORK_ACL:
1116     perm = container_of(ptr, struct ccs_ip_network_acl,
1117     head)->perm;
1118     for (i = 0; i < CCS_MAX_NETWORK_OPERATION; i++)
1119     if (perm & (1 << i))
1120     count++;
1121     break;
1122 kumaneko 1064 default:
1123 kumaneko 1052 count++;
1124 kumaneko 1064 }
1125 kumaneko 512 }
1126 kumaneko 2962 if (count < ccs_profile(domain->profile)->learning->learning_max_entry)
1127 kumaneko 2692 return true;
1128     if (!domain->quota_warned) {
1129 kumaneko 1006 domain->quota_warned = true;
1130 kumaneko 2918 printk(KERN_WARNING "WARNING: "
1131 kumaneko 1052 "Domain '%s' has so many ACLs to hold. "
1132     "Stopped learning mode.\n", domain->domainname->name);
1133 kumaneko 512 }
1134 kumaneko 2692 return false;
1135 kumaneko 512 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26