tizen 2.4 release
[framework/security/smack.git] / utils / chsmack.c
1 /*
2  * chsmack - Set smack attributes on files
3  *
4  * Copyright (C) 2011 Nokia Corporation.
5  * Copyright (C) 2011, 2012, 2013 Intel Corporation
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, version 2.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19  * 02110-1301 USA
20  */
21
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <sys/xattr.h>
25 #include <linux/xattr.h>
26 #include <sys/smack.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <getopt.h>
33 #include <errno.h>
34 #include <libgen.h>
35
36 static const char usage[] =
37         "Usage: %s [options] <path>\n"
38         "options:\n"
39         " -v --version       output version information and exit\n"
40         " -h --help          output usage information and exit\n"
41         " -a --access        set/remove "XATTR_NAME_SMACK"\n"
42         " -e --exec          set/remove "XATTR_NAME_SMACKEXEC"\n"
43         " -m --mmap          set/remove "XATTR_NAME_SMACKMMAP"\n"
44         " -t --transmute     set/remove "XATTR_NAME_SMACKTRANSMUTE"\n"
45         " -d --remove        tell to remove the attribute\n"
46         " -L --dereference   tell to follow the symbolic links\n"
47 ;
48
49 /* main */
50 int main(int argc, char *argv[])
51 {
52         static const char shortoptions[] = "vha::e::m::tdL";
53         static struct option options[] = {
54                 {"version", no_argument, 0, 'v'},
55                 {"help", no_argument, 0, 'h'},
56                 {"access", optional_argument, 0, 'a'},
57                 {"exec", optional_argument, 0, 'e'},
58                 {"mmap", optional_argument, 0, 'm'},
59                 {"transmute", no_argument, 0, 't'},
60                 {"dereference", no_argument, 0, 'L'},
61                 {NULL, 0, 0, 0}
62         };
63
64         /*  Buffers are zeroed automatically by keeping them static variables.
65          *  No separate memset is needed this way.
66          */
67         static int options_map[128];
68
69         /* structure for recording options of label and their init */
70         struct labelset {
71                 int isset; /* 0 if option not set, 1 if option set */
72                 const char *value; /* value of the option set if any or NULL else */
73         };
74         struct labelset access_set = { 0, NULL }; /* for option "access" */
75         struct labelset exec_set = { 0, NULL }; /* for option "exec" */
76         struct labelset mmap_set = { 0, NULL }; /* for option "mmap" */
77
78         struct labelset *labelset;
79         struct stat st;
80         char *label;
81
82         int delete_flag = 0;
83         int follow_flag = 0;
84         int transmute_flag = 0;
85         int option_flag = 0;
86         int rc;
87         int c;
88         int i;
89
90         for (i = 0; options[i].name != NULL; i++)
91                 options_map[options[i].val] = i;
92
93         /* scan options without argument */
94         while ((c = getopt_long(argc, argv, shortoptions, options, NULL)) != -1) {
95
96                 switch (c) {
97                         case 'a':
98                         case 'e':
99                         case 'm':
100                                 /* greedy on optional arguments */
101                                 if (optarg == NULL && argv[optind] != NULL
102                                                 && argv[optind][0] != '-') {
103                                         optind++;
104                                 }
105                                 break;
106                         case 't':
107                                 if (transmute_flag)
108                                         fprintf(stderr, "%s: %s: option set many times.\n",
109                                                         basename(argv[0]), options[options_map[c]].name);
110                                 transmute_flag = 1;
111                                 option_flag = 1;
112                                 break;
113                         case 'd':
114                                 if (delete_flag)
115                                         fprintf(stderr, "%s: %s: option set many times.\n",
116                                                         basename(argv[0]), options[options_map[c]].name);
117                                 delete_flag = 1;
118                                 break;
119                         case 'L':
120                                 if (follow_flag)
121                                         fprintf(stderr, "%s: %s: option set many times.\n",
122                                                         basename(argv[0]), options[options_map[c]].name);
123                                 follow_flag = 1;
124                                 break;
125                         case 'v':
126                                 printf("%s (libsmack) version " PACKAGE_VERSION "\n",
127                                        basename(argv[0]));
128                                 exit(0);
129                         case 'h':
130                                 printf(usage, basename(argv[0]));
131                                 exit(0);
132                         default:
133                                 printf(usage, basename(argv[0]));
134                                 exit(1);
135                 }
136         }
137
138         /* scan options with argument (possibly) */
139         optind = 1;
140         while ((c = getopt_long(argc, argv, shortoptions, options, NULL)) != -1) {
141
142                 switch (c) {
143                         case 'a':
144                                 labelset = &access_set;
145                                 break;
146                         case 'e':
147                                 labelset = &exec_set;
148                                 break;
149                         case 'm':
150                                 labelset = &mmap_set;
151                                 break;
152                         default:
153                                 continue;
154                 }
155
156                 if (labelset->isset) {
157                         fprintf(stderr, "%s: %s: option set many times.\n",
158                                 basename(argv[0]), options[options_map[c]].name);
159                         exit(1);
160                 }
161                 /* greedy on optional arguments */
162                 if (optarg == NULL && argv[optind] != NULL && argv[optind][0] != '-') {
163                         optarg = argv[optind++];
164                 }
165                 if (optarg == NULL) {
166                         if (!delete_flag) {
167                                 fprintf(stderr, "%s: %s: requires a label when setting.\n",
168                                         basename(argv[0]), options[options_map[c]].name);
169                                 exit(1);
170                         }
171                 }
172                 else if (delete_flag) {
173                         fprintf(stderr, "%s: %s: requires no label when deleting.\n",
174                                 basename(argv[0]), options[options_map[c]].name);
175                         exit(1);
176                 }
177                 else if (strnlen(optarg, SMACK_LABEL_LEN + 1) == SMACK_LABEL_LEN + 1) {
178                         fprintf(stderr, "%s: %s: \"%s\" exceeds %d characters.\n",
179                                 basename(argv[0]), options[options_map[c]].name, optarg,
180                                  SMACK_LABEL_LEN);
181                         exit(1);
182                 }
183                 else if (smack_label_length(optarg) < 0) {
184                         fprintf(stderr, "%s: %s: \"%s\" is an invalid Smack label.\n",
185                                 basename(argv[0]), options[options_map[c]].name, optarg);
186                         exit(1);
187                 }
188                 labelset->isset = 1;
189                 labelset->value = optarg;
190                 option_flag = 1;
191         }
192
193         /* deleting labels */
194         if (delete_flag) {
195                 if (!option_flag) {
196                         access_set.isset = 1;
197                         exec_set.isset = 1;
198                         mmap_set.isset = 1;
199                         transmute_flag = 1;
200                 }
201                 for (i = optind; i < argc; i++) {
202                         if (access_set.isset) {
203                                 rc = smack_remove_label_for_path(argv[i],
204                                                         XATTR_NAME_SMACK, follow_flag);
205                                 if (rc < 0 && (option_flag || errno != ENODATA))
206                                         perror(argv[i]);
207                         }
208
209                         if (exec_set.isset) {
210                                 rc = smack_remove_label_for_path(argv[i],
211                                                         XATTR_NAME_SMACKEXEC, follow_flag);
212                                 if (rc < 0 && (option_flag || errno != ENODATA))
213                                         perror(argv[i]);
214                         }
215
216                         if (mmap_set.isset) {
217                                 rc = smack_remove_label_for_path(argv[i],
218                                                         XATTR_NAME_SMACKMMAP, follow_flag);
219                                 if (rc < 0 && (option_flag || errno != ENODATA))
220                                         perror(argv[i]);
221                         }
222
223                         if (transmute_flag) {
224                                 rc = smack_remove_label_for_path(argv[i],
225                                                         XATTR_NAME_SMACKTRANSMUTE, follow_flag);
226                                 if (rc < 0 && (option_flag || errno != ENODATA))
227                                         perror(argv[i]);
228                         }
229                 }
230         }
231
232         /* setting labels */
233         else if (option_flag) {
234                 for (i = optind; i < argc; i++) {
235                         if (access_set.isset) {
236                                 rc = smack_set_label_for_path(argv[i],
237                                                         XATTR_NAME_SMACK, follow_flag, access_set.value);
238                                 if (rc < 0)
239                                         perror(argv[i]);
240                         }
241
242                         if (exec_set.isset) {
243                                 rc = smack_set_label_for_path(argv[i],
244                                                         XATTR_NAME_SMACKEXEC, follow_flag, exec_set.value);
245                                 if (rc < 0)
246                                         perror(argv[i]);
247                         }
248
249                         if (mmap_set.isset) {
250                                 rc = smack_set_label_for_path(argv[i],
251                                                         XATTR_NAME_SMACKMMAP, follow_flag, mmap_set.value);
252                                 if (rc < 0)
253                                         perror(argv[i]);
254                         }
255
256                         if (transmute_flag) {
257                                 rc = follow_flag ?  stat(argv[i], &st) : lstat(argv[i], &st);
258                                 if (rc < 0)
259                                         perror(argv[i]);
260                                 else if (!S_ISDIR(st.st_mode)) {
261                                         fprintf(stderr, "%s: transmute: not a directory %s\n",
262                                                 basename(argv[0]), argv[i]);
263                                 }
264                                 else {
265                                         rc = smack_set_label_for_path(argv[i],
266                                                                 XATTR_NAME_SMACKTRANSMUTE, follow_flag, "TRUE");
267                                         if (rc < 0)
268                                                 perror(argv[i]);
269                                 }
270                         }
271                 }
272         }
273
274         /* listing labels */
275         else {
276                 for (i = optind; i < argc; i++) {
277
278                         /* Print file path. */
279                         printf("%s", argv[i]);
280
281                         rc = (int)smack_new_label_from_path(argv[i],
282                                                 XATTR_NAME_SMACK, follow_flag, &label);
283                         if (rc > 0) {
284                                 printf(" access=\"%s\"", label);
285                                 free(label);
286                         }
287
288                         rc = (int)smack_new_label_from_path(argv[i],
289                                                 XATTR_NAME_SMACKEXEC, follow_flag, &label);
290                         if (rc > 0) {
291                                 printf(" execute=\"%s\"", label);
292                                 free(label);
293                         }
294
295                         rc = (int)smack_new_label_from_path(argv[i],
296                                                 XATTR_NAME_SMACKMMAP, follow_flag, &label);
297                         if (rc > 0) {
298                                 printf(" mmap=\"%s\"", label);
299                                 free(label);
300                         }
301
302                         rc = (int)smack_new_label_from_path(argv[i],
303                                                 XATTR_NAME_SMACKTRANSMUTE, follow_flag, &label);
304                         if (rc > 0) {
305                                 printf(" transmute=\"%s\"", label);
306                                 free(label);
307                         }
308
309                         printf("\n");
310                 }
311         }
312
313         exit(0);
314 }