diff options
-rw-r--r-- | src/firejail/checkcfg.c | 20 | ||||
-rw-r--r-- | src/firejail/firejail.h | 4 | ||||
-rw-r--r-- | src/firejail/main.c | 236 | ||||
-rw-r--r-- | src/firejail/profile.c | 57 |
4 files changed, 213 insertions, 104 deletions
diff --git a/src/firejail/checkcfg.c b/src/firejail/checkcfg.c index 670fdc502..8376cd9af 100644 --- a/src/firejail/checkcfg.c +++ b/src/firejail/checkcfg.c | |||
@@ -86,7 +86,7 @@ int checkcfg(int val) { | |||
86 | else | 86 | else |
87 | goto errout; | 87 | goto errout; |
88 | } | 88 | } |
89 | // bind | 89 | // user namespace |
90 | else if (strncmp(ptr, "userns ", 7) == 0) { | 90 | else if (strncmp(ptr, "userns ", 7) == 0) { |
91 | if (strcmp(ptr + 7, "yes") == 0) | 91 | if (strcmp(ptr + 7, "yes") == 0) |
92 | cfg_val[CFG_USERNS] = 1; | 92 | cfg_val[CFG_USERNS] = 1; |
@@ -95,6 +95,24 @@ int checkcfg(int val) { | |||
95 | else | 95 | else |
96 | goto errout; | 96 | goto errout; |
97 | } | 97 | } |
98 | // chroot | ||
99 | else if (strncmp(ptr, "chroot ", 7) == 0) { | ||
100 | if (strcmp(ptr + 7, "yes") == 0) | ||
101 | cfg_val[CFG_CHROOT] = 1; | ||
102 | else if (strcmp(ptr + 7, "no") == 0) | ||
103 | cfg_val[CFG_CHROOT] = 0; | ||
104 | else | ||
105 | goto errout; | ||
106 | } | ||
107 | // seccomp | ||
108 | else if (strncmp(ptr, "seccomp ", 8) == 0) { | ||
109 | if (strcmp(ptr + 8, "yes") == 0) | ||
110 | cfg_val[CFG_SECCOMP] = 1; | ||
111 | else if (strcmp(ptr + 8, "no") == 0) | ||
112 | cfg_val[CFG_SECCOMP] = 0; | ||
113 | else | ||
114 | goto errout; | ||
115 | } | ||
98 | else | 116 | else |
99 | goto errout; | 117 | goto errout; |
100 | free(ptr); | 118 | free(ptr); |
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index ed9343345..2b2912b3e 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -542,7 +542,9 @@ void sandboxfs(int op, pid_t pid, const char *patqh); | |||
542 | #define CFG_X11 1 | 542 | #define CFG_X11 1 |
543 | #define CFG_BIND 2 | 543 | #define CFG_BIND 2 |
544 | #define CFG_USERNS 3 | 544 | #define CFG_USERNS 3 |
545 | #define CFG_MAX 4 // this should always be the last entry | 545 | #define CFG_CHROOT 4 |
546 | #define CFG_SECCOMP 5 | ||
547 | #define CFG_MAX 6 // this should always be the last entry | ||
546 | int checkcfg(int val); | 548 | int checkcfg(int val); |
547 | 549 | ||
548 | #endif | 550 | #endif |
diff --git a/src/firejail/main.c b/src/firejail/main.c index df625a7ba..8f89a804f 100644 --- a/src/firejail/main.c +++ b/src/firejail/main.c | |||
@@ -356,20 +356,38 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { | |||
356 | //************************************* | 356 | //************************************* |
357 | #ifdef HAVE_SECCOMP | 357 | #ifdef HAVE_SECCOMP |
358 | else if (strcmp(argv[i], "--debug-syscalls") == 0) { | 358 | else if (strcmp(argv[i], "--debug-syscalls") == 0) { |
359 | syscall_print(); | 359 | if (checkcfg(CFG_SECCOMP)) { |
360 | exit(0); | 360 | syscall_print(); |
361 | exit(0); | ||
362 | } | ||
363 | else { | ||
364 | fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); | ||
365 | exit(1); | ||
366 | } | ||
361 | } | 367 | } |
362 | else if (strcmp(argv[i], "--debug-errnos") == 0) { | 368 | else if (strcmp(argv[i], "--debug-errnos") == 0) { |
363 | errno_print(); | 369 | if (checkcfg(CFG_SECCOMP)) { |
370 | errno_print(); | ||
371 | } | ||
372 | else { | ||
373 | fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); | ||
374 | exit(1); | ||
375 | } | ||
364 | exit(0); | 376 | exit(0); |
365 | } | 377 | } |
366 | else if (strncmp(argv[i], "--seccomp.print=", 16) == 0) { | 378 | else if (strncmp(argv[i], "--seccomp.print=", 16) == 0) { |
367 | // print seccomp filter for a sandbox specified by pid or by name | 379 | if (checkcfg(CFG_SECCOMP)) { |
368 | pid_t pid; | 380 | // print seccomp filter for a sandbox specified by pid or by name |
369 | if (read_pid(argv[i] + 16, &pid) == 0) | 381 | pid_t pid; |
370 | seccomp_print_filter(pid); | 382 | if (read_pid(argv[i] + 16, &pid) == 0) |
371 | else | 383 | seccomp_print_filter(pid); |
372 | seccomp_print_filter_name(argv[i] + 16); | 384 | else |
385 | seccomp_print_filter_name(argv[i] + 16); | ||
386 | } | ||
387 | else { | ||
388 | fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); | ||
389 | exit(1); | ||
390 | } | ||
373 | exit(0); | 391 | exit(0); |
374 | } | 392 | } |
375 | else if (strcmp(argv[i], "--debug-protocols") == 0) { | 393 | else if (strcmp(argv[i], "--debug-protocols") == 0) { |
@@ -377,12 +395,18 @@ static void run_cmd_and_exit(int i, int argc, char **argv) { | |||
377 | exit(0); | 395 | exit(0); |
378 | } | 396 | } |
379 | else if (strncmp(argv[i], "--protocol.print=", 17) == 0) { | 397 | else if (strncmp(argv[i], "--protocol.print=", 17) == 0) { |
380 | // print seccomp filter for a sandbox specified by pid or by name | 398 | if (checkcfg(CFG_SECCOMP)) { |
381 | pid_t pid; | 399 | // print seccomp filter for a sandbox specified by pid or by name |
382 | if (read_pid(argv[i] + 17, &pid) == 0) | 400 | pid_t pid; |
383 | protocol_print_filter(pid); | 401 | if (read_pid(argv[i] + 17, &pid) == 0) |
384 | else | 402 | protocol_print_filter(pid); |
385 | protocol_print_filter_name(argv[i] + 17); | 403 | else |
404 | protocol_print_filter_name(argv[i] + 17); | ||
405 | } | ||
406 | else { | ||
407 | fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); | ||
408 | exit(1); | ||
409 | } | ||
386 | exit(0); | 410 | exit(0); |
387 | } | 411 | } |
388 | #endif | 412 | #endif |
@@ -733,72 +757,109 @@ int main(int argc, char **argv) { | |||
733 | // filtering | 757 | // filtering |
734 | //************************************* | 758 | //************************************* |
735 | #ifdef HAVE_SECCOMP | 759 | #ifdef HAVE_SECCOMP |
736 | else if (strncmp(argv[i], "--protocol=", 11) == 0) | 760 | else if (strncmp(argv[i], "--protocol=", 11) == 0) { |
737 | protocol_store(argv[i] + 11); | 761 | if (checkcfg(CFG_SECCOMP)) { |
762 | protocol_store(argv[i] + 11); | ||
763 | } | ||
764 | else { | ||
765 | fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); | ||
766 | exit(1); | ||
767 | } | ||
768 | } | ||
738 | else if (strcmp(argv[i], "--seccomp") == 0) { | 769 | else if (strcmp(argv[i], "--seccomp") == 0) { |
739 | if (arg_seccomp) { | 770 | if (checkcfg(CFG_SECCOMP)) { |
740 | fprintf(stderr, "Error: seccomp already enabled\n"); | 771 | if (arg_seccomp) { |
772 | fprintf(stderr, "Error: seccomp already enabled\n"); | ||
773 | exit(1); | ||
774 | } | ||
775 | arg_seccomp = 1; | ||
776 | } | ||
777 | else { | ||
778 | fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); | ||
741 | exit(1); | 779 | exit(1); |
742 | } | 780 | } |
743 | arg_seccomp = 1; | ||
744 | } | 781 | } |
745 | else if (strncmp(argv[i], "--seccomp=", 10) == 0) { | 782 | else if (strncmp(argv[i], "--seccomp=", 10) == 0) { |
746 | if (arg_seccomp) { | 783 | if (checkcfg(CFG_SECCOMP)) { |
747 | fprintf(stderr, "Error: seccomp already enabled\n"); | 784 | if (arg_seccomp) { |
785 | fprintf(stderr, "Error: seccomp already enabled\n"); | ||
786 | exit(1); | ||
787 | } | ||
788 | arg_seccomp = 1; | ||
789 | cfg.seccomp_list = strdup(argv[i] + 10); | ||
790 | if (!cfg.seccomp_list) | ||
791 | errExit("strdup"); | ||
792 | } | ||
793 | else { | ||
794 | fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); | ||
748 | exit(1); | 795 | exit(1); |
749 | } | 796 | } |
750 | arg_seccomp = 1; | ||
751 | cfg.seccomp_list = strdup(argv[i] + 10); | ||
752 | if (!cfg.seccomp_list) | ||
753 | errExit("strdup"); | ||
754 | } | 797 | } |
755 | else if (strncmp(argv[i], "--seccomp.drop=", 15) == 0) { | 798 | else if (strncmp(argv[i], "--seccomp.drop=", 15) == 0) { |
756 | if (arg_seccomp) { | 799 | if (checkcfg(CFG_SECCOMP)) { |
757 | fprintf(stderr, "Error: seccomp already enabled\n"); | 800 | if (arg_seccomp) { |
801 | fprintf(stderr, "Error: seccomp already enabled\n"); | ||
802 | exit(1); | ||
803 | } | ||
804 | arg_seccomp = 1; | ||
805 | cfg.seccomp_list_drop = strdup(argv[i] + 15); | ||
806 | if (!cfg.seccomp_list_drop) | ||
807 | errExit("strdup"); | ||
808 | } | ||
809 | else { | ||
810 | fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); | ||
758 | exit(1); | 811 | exit(1); |
759 | } | 812 | } |
760 | arg_seccomp = 1; | ||
761 | cfg.seccomp_list_drop = strdup(argv[i] + 15); | ||
762 | if (!cfg.seccomp_list_drop) | ||
763 | errExit("strdup"); | ||
764 | } | 813 | } |
765 | else if (strncmp(argv[i], "--seccomp.keep=", 15) == 0) { | 814 | else if (strncmp(argv[i], "--seccomp.keep=", 15) == 0) { |
766 | if (arg_seccomp) { | 815 | if (checkcfg(CFG_SECCOMP)) { |
767 | fprintf(stderr, "Error: seccomp already enabled\n"); | 816 | if (arg_seccomp) { |
817 | fprintf(stderr, "Error: seccomp already enabled\n"); | ||
818 | exit(1); | ||
819 | } | ||
820 | arg_seccomp = 1; | ||
821 | cfg.seccomp_list_keep = strdup(argv[i] + 15); | ||
822 | if (!cfg.seccomp_list_keep) | ||
823 | errExit("strdup"); | ||
824 | } | ||
825 | else { | ||
826 | fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); | ||
768 | exit(1); | 827 | exit(1); |
769 | } | 828 | } |
770 | arg_seccomp = 1; | ||
771 | cfg.seccomp_list_keep = strdup(argv[i] + 15); | ||
772 | if (!cfg.seccomp_list_keep) | ||
773 | errExit("strdup"); | ||
774 | } | 829 | } |
775 | else if (strncmp(argv[i], "--seccomp.e", 11) == 0 && strchr(argv[i], '=')) { | 830 | else if (strncmp(argv[i], "--seccomp.e", 11) == 0 && strchr(argv[i], '=')) { |
776 | if (arg_seccomp && !cfg.seccomp_list_errno) { | 831 | if (checkcfg(CFG_SECCOMP)) { |
777 | fprintf(stderr, "Error: seccomp already enabled\n"); | 832 | if (arg_seccomp && !cfg.seccomp_list_errno) { |
778 | exit(1); | 833 | fprintf(stderr, "Error: seccomp already enabled\n"); |
779 | } | 834 | exit(1); |
780 | char *eq = strchr(argv[i], '='); | 835 | } |
781 | char *errnoname = strndup(argv[i] + 10, eq - (argv[i] + 10)); | 836 | char *eq = strchr(argv[i], '='); |
782 | int nr = errno_find_name(errnoname); | 837 | char *errnoname = strndup(argv[i] + 10, eq - (argv[i] + 10)); |
783 | if (nr == -1) { | 838 | int nr = errno_find_name(errnoname); |
784 | fprintf(stderr, "Error: unknown errno %s\n", errnoname); | 839 | if (nr == -1) { |
840 | fprintf(stderr, "Error: unknown errno %s\n", errnoname); | ||
841 | free(errnoname); | ||
842 | exit(1); | ||
843 | } | ||
844 | |||
845 | if (!cfg.seccomp_list_errno) | ||
846 | cfg.seccomp_list_errno = calloc(highest_errno+1, sizeof(cfg.seccomp_list_errno[0])); | ||
847 | |||
848 | if (cfg.seccomp_list_errno[nr]) { | ||
849 | fprintf(stderr, "Error: errno %s already configured\n", errnoname); | ||
850 | free(errnoname); | ||
851 | exit(1); | ||
852 | } | ||
853 | arg_seccomp = 1; | ||
854 | cfg.seccomp_list_errno[nr] = strdup(eq+1); | ||
855 | if (!cfg.seccomp_list_errno[nr]) | ||
856 | errExit("strdup"); | ||
785 | free(errnoname); | 857 | free(errnoname); |
786 | exit(1); | ||
787 | } | 858 | } |
788 | 859 | else { | |
789 | if (!cfg.seccomp_list_errno) | 860 | fprintf(stderr, "Error: seccomp feature is disabled in Firejail configuration file\n"); |
790 | cfg.seccomp_list_errno = calloc(highest_errno+1, sizeof(cfg.seccomp_list_errno[0])); | ||
791 | |||
792 | if (cfg.seccomp_list_errno[nr]) { | ||
793 | fprintf(stderr, "Error: errno %s already configured\n", errnoname); | ||
794 | free(errnoname); | ||
795 | exit(1); | 861 | exit(1); |
796 | } | 862 | } |
797 | arg_seccomp = 1; | ||
798 | cfg.seccomp_list_errno[nr] = strdup(eq+1); | ||
799 | if (!cfg.seccomp_list_errno[nr]) | ||
800 | errExit("strdup"); | ||
801 | free(errnoname); | ||
802 | } | 863 | } |
803 | #endif | 864 | #endif |
804 | else if (strcmp(argv[i], "--caps") == 0) | 865 | else if (strcmp(argv[i], "--caps") == 0) |
@@ -1061,33 +1122,40 @@ int main(int argc, char **argv) { | |||
1061 | } | 1122 | } |
1062 | #ifdef HAVE_CHROOT | 1123 | #ifdef HAVE_CHROOT |
1063 | else if (strncmp(argv[i], "--chroot=", 9) == 0) { | 1124 | else if (strncmp(argv[i], "--chroot=", 9) == 0) { |
1064 | if (arg_overlay) { | 1125 | if (checkcfg(CFG_CHROOT)) { |
1065 | fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); | 1126 | if (arg_overlay) { |
1066 | exit(1); | 1127 | fprintf(stderr, "Error: --overlay and --chroot options are mutually exclusive\n"); |
1067 | } | 1128 | exit(1); |
1068 | invalid_filename(argv[i] + 9); | 1129 | } |
1069 | 1130 | invalid_filename(argv[i] + 9); | |
1070 | // extract chroot dirname | 1131 | |
1071 | cfg.chrootdir = argv[i] + 9; | 1132 | // extract chroot dirname |
1072 | // if the directory starts with ~, expand the home directory | 1133 | cfg.chrootdir = argv[i] + 9; |
1073 | if (*cfg.chrootdir == '~') { | 1134 | // if the directory starts with ~, expand the home directory |
1074 | char *tmp; | 1135 | if (*cfg.chrootdir == '~') { |
1075 | if (asprintf(&tmp, "%s%s", cfg.homedir, cfg.chrootdir + 1) == -1) | 1136 | char *tmp; |
1076 | errExit("asprintf"); | 1137 | if (asprintf(&tmp, "%s%s", cfg.homedir, cfg.chrootdir + 1) == -1) |
1077 | cfg.chrootdir = tmp; | 1138 | errExit("asprintf"); |
1078 | } | 1139 | cfg.chrootdir = tmp; |
1079 | 1140 | } | |
1080 | // check chroot dirname exists | 1141 | |
1081 | if (strstr(cfg.chrootdir, "..") || !is_dir(cfg.chrootdir) || is_link(cfg.chrootdir)) { | 1142 | // check chroot dirname exists |
1082 | fprintf(stderr, "Error: invalid directory %s\n", cfg.chrootdir); | 1143 | if (strstr(cfg.chrootdir, "..") || !is_dir(cfg.chrootdir) || is_link(cfg.chrootdir)) { |
1083 | return 1; | 1144 | fprintf(stderr, "Error: invalid directory %s\n", cfg.chrootdir); |
1145 | return 1; | ||
1146 | } | ||
1147 | |||
1148 | // check chroot directory structure | ||
1149 | if (fs_check_chroot_dir(cfg.chrootdir)) { | ||
1150 | fprintf(stderr, "Error: invalid chroot\n"); | ||
1151 | exit(1); | ||
1152 | } | ||
1084 | } | 1153 | } |
1085 | 1154 | else { | |
1086 | // check chroot directory structure | 1155 | fprintf(stderr, "Error: --chroot feature is disabled in Firejail configuration file\n"); |
1087 | if (fs_check_chroot_dir(cfg.chrootdir)) { | ||
1088 | fprintf(stderr, "Error: invalid chroot\n"); | ||
1089 | exit(1); | 1156 | exit(1); |
1090 | } | 1157 | } |
1158 | |||
1091 | } | 1159 | } |
1092 | #endif | 1160 | #endif |
1093 | else if (strcmp(argv[i], "--private") == 0) | 1161 | else if (strcmp(argv[i], "--private") == 0) |
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 1c843a460..723889dd2 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -132,7 +132,12 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
132 | return 0; | 132 | return 0; |
133 | } | 133 | } |
134 | else if (strcmp(ptr, "seccomp") == 0) { | 134 | else if (strcmp(ptr, "seccomp") == 0) { |
135 | arg_seccomp = 1; | 135 | #ifdef HAVE_SECCOMP |
136 | if (checkcfg(CFG_SECCOMP)) | ||
137 | arg_seccomp = 1; | ||
138 | else | ||
139 | fprintf(stderr, "Warning: user seccomp feature is disabled in Firejail configuration file\n"); | ||
140 | #endif | ||
136 | return 0; | 141 | return 0; |
137 | } | 142 | } |
138 | else if (strcmp(ptr, "caps") == 0) { | 143 | else if (strcmp(ptr, "caps") == 0) { |
@@ -209,12 +214,15 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
209 | return 0; | 214 | return 0; |
210 | } | 215 | } |
211 | 216 | ||
212 | #ifdef HAVE_SECCOMP | ||
213 | if (strncmp(ptr, "protocol ", 9) == 0) { | 217 | if (strncmp(ptr, "protocol ", 9) == 0) { |
214 | protocol_store(ptr + 9); | 218 | #ifdef HAVE_SECCOMP |
219 | if (checkcfg(CFG_SECCOMP)) | ||
220 | protocol_store(ptr + 9); | ||
221 | else | ||
222 | fprintf(stderr, "Warning: user seccomp feature is disabled in Firejail configuration file\n"); | ||
223 | #endif | ||
215 | return 0; | 224 | return 0; |
216 | } | 225 | } |
217 | #endif | ||
218 | 226 | ||
219 | if (strncmp(ptr, "env ", 4) == 0) { | 227 | if (strncmp(ptr, "env ", 4) == 0) { |
220 | env_store(ptr + 4); | 228 | env_store(ptr + 4); |
@@ -223,34 +231,47 @@ int profile_check_line(char *ptr, int lineno, const char *fname) { | |||
223 | 231 | ||
224 | // seccomp drop list on top of default list | 232 | // seccomp drop list on top of default list |
225 | if (strncmp(ptr, "seccomp ", 8) == 0) { | 233 | if (strncmp(ptr, "seccomp ", 8) == 0) { |
226 | arg_seccomp = 1; | ||
227 | #ifdef HAVE_SECCOMP | 234 | #ifdef HAVE_SECCOMP |
228 | cfg.seccomp_list = strdup(ptr + 8); | 235 | if (checkcfg(CFG_SECCOMP)) { |
229 | if (!cfg.seccomp_list) | 236 | arg_seccomp = 1; |
230 | errExit("strdup"); | 237 | cfg.seccomp_list = strdup(ptr + 8); |
238 | if (!cfg.seccomp_list) | ||
239 | errExit("strdup"); | ||
240 | } | ||
241 | else | ||
242 | fprintf(stderr, "Warning: user seccomp feature is disabled in Firejail configuration file\n"); | ||
231 | #endif | 243 | #endif |
244 | |||
232 | return 0; | 245 | return 0; |
233 | } | 246 | } |
234 | 247 | ||
235 | // seccomp drop list without default list | 248 | // seccomp drop list without default list |
236 | if (strncmp(ptr, "seccomp.drop ", 13) == 0) { | 249 | if (strncmp(ptr, "seccomp.drop ", 13) == 0) { |
237 | arg_seccomp = 1; | ||
238 | #ifdef HAVE_SECCOMP | 250 | #ifdef HAVE_SECCOMP |
239 | cfg.seccomp_list_drop = strdup(ptr + 13); | 251 | if (checkcfg(CFG_SECCOMP)) { |
240 | if (!cfg.seccomp_list_drop) | 252 | arg_seccomp = 1; |
241 | errExit("strdup"); | 253 | cfg.seccomp_list_drop = strdup(ptr + 13); |
242 | #endif | 254 | if (!cfg.seccomp_list_drop) |
255 | errExit("strdup"); | ||
256 | } | ||
257 | else | ||
258 | fprintf(stderr, "Warning: user seccomp feature is disabled in Firejail configuration file\n"); | ||
259 | #endif | ||
243 | return 0; | 260 | return 0; |
244 | } | 261 | } |
245 | 262 | ||
246 | // seccomp keep list | 263 | // seccomp keep list |
247 | if (strncmp(ptr, "seccomp.keep ", 13) == 0) { | 264 | if (strncmp(ptr, "seccomp.keep ", 13) == 0) { |
248 | arg_seccomp = 1; | ||
249 | #ifdef HAVE_SECCOMP | 265 | #ifdef HAVE_SECCOMP |
250 | cfg.seccomp_list_keep= strdup(ptr + 13); | 266 | if (checkcfg(CFG_SECCOMP)) { |
251 | if (!cfg.seccomp_list_keep) | 267 | arg_seccomp = 1; |
252 | errExit("strdup"); | 268 | cfg.seccomp_list_keep= strdup(ptr + 13); |
253 | #endif | 269 | if (!cfg.seccomp_list_keep) |
270 | errExit("strdup"); | ||
271 | } | ||
272 | else | ||
273 | fprintf(stderr, "Warning: user seccomp feature is disabled in Firejail configuration file\n"); | ||
274 | #endif | ||
254 | return 0; | 275 | return 0; |
255 | } | 276 | } |
256 | 277 | ||