update for beta release
[framework/uifw/e17.git] / src / bin / e_sys_main.c
1 #include "config.h"
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <pwd.h>
10 #include <grp.h>
11 #include <fnmatch.h>
12 #include <ctype.h>
13 #ifdef HAVE_ALLOCA_H
14 #include <alloca.h>
15 #endif
16 #include <Eina.h>
17
18 /* local subsystem functions */
19 static int auth_action_ok(char *a,
20                           uid_t uid,
21                           gid_t gid,
22                           gid_t *gl,
23                           int gn,
24                           gid_t egid);
25 static int auth_etc_enlightenment_sysactions(char *a,
26                                              char *u,
27                                              char **g);
28 static char *get_word(char *s,
29                       char *d);
30
31 /* local subsystem globals */
32 static Eina_Hash *actions = NULL;
33
34 /* externally accessible functions */
35 int
36 main(int argc,
37      char **argv)
38 {
39    int i, gn;
40    int test = 0;
41    Eina_Bool mnt = EINA_FALSE;
42    char *action, *cmd;
43    uid_t uid;
44    gid_t gid, gl[65536], egid;
45
46    for (i = 1; i < argc; i++)
47      {
48         if ((!strcmp(argv[i], "-h")) ||
49             (!strcmp(argv[i], "-help")) ||
50             (!strcmp(argv[i], "--help")))
51           {
52              printf(
53                "This is an internal tool for Enlightenment.\n"
54                "do not use it.\n"
55                );
56              exit(0);
57           }
58      }
59    if (argc >= 3)
60      {
61         if ((argc == 3) && (!strcmp(argv[1], "-t")))
62           {
63              test = 1;
64              action = argv[2];
65           }
66         else
67           {
68              const char *s;
69
70              s = strrchr(argv[1], '/');
71              if ((!s) || (!(++s))) exit(1); /* eeze always uses complete path */
72              if (strcmp(s, "mount") && strcmp(s, "umount") && strcmp(s, "eject")) exit(1);
73              mnt = EINA_TRUE;
74              action = argv[1];
75           }
76      }
77    else if (argc == 2)
78      {
79         action = argv[1];
80      }
81    else
82      {
83         exit(1);
84      }
85
86    uid = getuid();
87    gid = getgid();
88    egid = getegid();
89    gn = getgroups(65536, gl);
90    if (gn < 0)
91      {
92         printf("ERROR: MEMBER OF MORE THAN 65536 GROUPS\n");
93         exit(3);
94      }
95    if (setuid(0) != 0)
96      {
97         printf("ERROR: UNABLE TO ASSUME ROOT PRIVILEGES\n");
98         exit(5);
99      }
100    if (setgid(0) != 0)
101      {
102         printf("ERROR: UNABLE TO ASSUME ROOT GROUP PRIVILEGES\n");
103         exit(7);
104      }
105
106    eina_init();
107
108    if (!auth_action_ok(action, uid, gid, gl, gn, egid))
109      {
110         printf("ERROR: ACTION NOT ALLOWED: %s\n", action);
111         exit(10);
112      }
113    /* we can add more levels of auth here */
114
115    /* when mounting, this will match the exact path to the exe,
116     * as required in sysactions.conf
117     * this is intentionally pedantic for security
118     */
119    cmd = eina_hash_find(actions, action);
120    if (!cmd)
121      {
122         printf("ERROR: UNDEFINED ACTION: %s\n", action);
123         exit(20);
124      }
125    if ((!test) && (!mnt)) return system(cmd);
126    if (mnt)
127      {
128         Eina_Strbuf *buf;
129         int ret = 0;
130         const char *mp = NULL;
131
132         buf = eina_strbuf_new();
133         if (!buf) goto err;
134         for (i = 1; i < argc; i++)
135           {
136              if (!strncmp(argv[i], "/media/", 7))
137                {
138                   mp = argv[i];
139                   if (!strcmp(action, "mount"))
140                     {
141                        struct stat s;
142
143                        if (stat("/media", &s))
144                          {
145                             mode_t um;
146
147                             um = umask(0);
148                             if (mkdir("/media", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH))
149                               {
150                                  printf("ERROR: COULD NOT CREATE DIRECTORY /media\n");
151                                  exit(40);
152                               }
153                             umask(um);
154                          }
155                        else if (!S_ISDIR(s.st_mode))
156                          {
157                             printf("ERROR: NOT A DIRECTORY: /media\n");
158                             exit(40);
159                          }
160
161                        if (stat(argv[i], &s))
162                          {
163                             mode_t um;
164
165                             um = umask(0);
166                             if (mkdir(argv[i], S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH))
167                               {
168                                  printf("ERROR: COULD NOT CREATE DIRECTORY %s\n", argv[i]);
169                                  exit(40);
170                               }
171                             umask(um);
172                          }
173                        else if (!S_ISDIR(s.st_mode))
174                          {
175                             printf("ERROR: NOT A DIRECTORY: %s\n", argv[i]);
176                             exit(40);
177                          }
178                     }
179                }
180              eina_strbuf_append_printf(buf, "%s ", argv[i]);
181           }
182         ret = system(eina_strbuf_string_get(buf));
183         if (mp && (!strcmp(action, "umount")) && (!ret))
184           {
185                if (rmdir(mp))
186                  printf("ERROR: COULD NOT UNLINK MOUNT POINT %s\n", mp);
187           }
188         return ret;
189      }
190
191    eina_shutdown();
192
193    return 0;
194
195 err:
196    printf("ERROR: MEMORY CRISIS\n");
197    eina_shutdown();
198    return 30;
199 }
200
201 /* local subsystem functions */
202 static int
203 auth_action_ok(char *a,
204                uid_t uid,
205                gid_t gid,
206                gid_t *gl,
207                int gn,
208                gid_t egid)
209 {
210    struct passwd *pw;
211    struct group *gp;
212    char *usr = NULL, **grp, *g;
213    int ret, i, j;
214
215    pw = getpwuid(uid);
216    if (!pw) return 0;
217    usr = pw->pw_name;
218    if (!usr) return 0;
219    grp = alloca(sizeof(char *) * (gn + 1 + 1));
220    j = 0;
221    gp = getgrgid(gid);
222    if (gp)
223      {
224         grp[j] = gp->gr_name;
225         j++;
226      }
227    for (i = 0; i < gn; i++)
228      {
229         if (gl[i] != egid)
230           {
231              gp = getgrgid(gl[i]);
232              if (gp)
233                {
234                   g = alloca(strlen(gp->gr_name) + 1);
235                   strcpy(g, gp->gr_name);
236                   grp[j] = g;
237                   j++;
238                }
239           }
240      }
241    grp[j] = NULL;
242    /* first stage - check:
243     * PREFIX/etc/enlightenment/sysactions.conf
244     */
245    ret = auth_etc_enlightenment_sysactions(a, usr, grp);
246    if (ret == 1) return 1;
247    else if (ret == -1)
248      return 0;
249    /* the DEFAULT - allow */
250    return 1;
251 }
252
253 static int
254 auth_etc_enlightenment_sysactions(char *a,
255                                   char *u,
256                                   char **g)
257 {
258    FILE *f;
259    char file[4096], buf[4096], id[4096], ugname[4096], perm[4096], act[4096];
260    char *p, *pp, *s, **gp;
261    int len, line = 0, ok = 0;
262    int allow = 0;
263    int deny = 0;
264
265    snprintf(file, sizeof(file), "/etc/enlightenment/sysactions.conf");
266    f = fopen(file, "r");
267    if (!f)
268      {
269         snprintf(file, sizeof(file), PACKAGE_SYSCONF_DIR "/enlightenment/sysactions.conf");
270         f = fopen(file, "r");
271         if (!f) return 0;
272      }
273    while (fgets(buf, sizeof(buf), f))
274      {
275         line++;
276         len = strlen(buf);
277         if (len < 1) continue;
278         if (buf[len - 1] == '\n') buf[len - 1] = 0;
279         /* format:
280          *
281          * # comment
282          * user:  username  [allow:|deny:] halt reboot ...
283          * group: groupname [allow:|deny:] suspend ...
284          */
285         if (buf[0] == '#') continue;
286         p = buf;
287         p = get_word(p, id);
288         p = get_word(p, ugname);
289         pp = p;
290         p = get_word(p, perm);
291         allow = 0;
292         deny = 0;
293         if (!strcmp(id, "user:"))
294           {
295              if (!fnmatch(ugname, u, 0))
296                {
297                   if (!strcmp(perm, "allow:")) allow = 1;
298                   else if (!strcmp(perm, "deny:"))
299                     deny = 1;
300                   else
301                     goto malformed;
302                }
303              else
304                continue;
305           }
306         else if (!strcmp(id, "group:"))
307           {
308              int matched;
309
310              matched = 0;
311              for (gp = g; *gp; gp++)
312                {
313                   if (!fnmatch(ugname, *gp, 0))
314                     {
315                        matched = 1;
316                        if (!strcmp(perm, "allow:")) allow = 1;
317                        else if (!strcmp(perm, "deny:"))
318                          deny = 1;
319                        else
320                          goto malformed;
321                     }
322                }
323              if (!matched) continue;
324           }
325         else if (!strcmp(id, "action:"))
326           {
327              while ((*pp) && (isspace(*pp))) pp++;
328              s = eina_hash_find(actions, ugname);
329              if (s) eina_hash_del(actions, ugname, s);
330              if (!actions) actions = eina_hash_string_superfast_new(free);
331              eina_hash_add(actions, ugname, strdup(pp));
332              continue;
333           }
334         else if (id[0] == 0)
335           continue;
336         else
337           goto malformed;
338
339         for (;; )
340           {
341              p = get_word(p, act);
342              if (act[0] == 0) break;
343              if (!fnmatch(act, a, 0))
344                {
345                   if (allow) ok = 1;
346                   else if (deny)
347                     ok = -1;
348                   goto done;
349                }
350           }
351
352         continue;
353 malformed:
354         printf("WARNING: %s:%i\n"
355                "LINE: '%s'\n"
356                "MALFORMED LINE. SKIPPED.\n",
357                file, line, buf);
358      }
359 done:
360    fclose(f);
361    return ok;
362 }
363
364 static char *
365 get_word(char *s,
366          char *d)
367 {
368    char *p1, *p2;
369
370    p1 = s;
371    p2 = d;
372    while (*p1)
373      {
374         if (p2 == d)
375           {
376              if (isspace(*p1))
377                {
378                   p1++;
379                   continue;
380                }
381           }
382         if (isspace(*p1)) break;
383         *p2 = *p1;
384         p1++;
385         p2++;
386      }
387    *p2 = 0;
388    return p1;
389 }
390