LCOV - code coverage report
Current view: top level - login - logind-acl.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 0 145 0.0 %
Date: 2015-07-29 18:47:03 Functions: 0 3 0.0 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2011 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <errno.h>
      23             : #include <string.h>
      24             : 
      25             : #include "util.h"
      26             : #include "formats-util.h"
      27             : #include "acl-util.h"
      28             : #include "set.h"
      29             : #include "logind-acl.h"
      30             : #include "udev-util.h"
      31             : 
      32           0 : static int flush_acl(acl_t acl) {
      33             :         acl_entry_t i;
      34             :         int found;
      35           0 :         bool changed = false;
      36             : 
      37           0 :         assert(acl);
      38             : 
      39           0 :         for (found = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
      40             :              found > 0;
      41           0 :              found = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) {
      42             : 
      43             :                 acl_tag_t tag;
      44             : 
      45           0 :                 if (acl_get_tag_type(i, &tag) < 0)
      46           0 :                         return -errno;
      47             : 
      48           0 :                 if (tag != ACL_USER)
      49           0 :                         continue;
      50             : 
      51           0 :                 if (acl_delete_entry(acl, i) < 0)
      52           0 :                         return -errno;
      53             : 
      54           0 :                 changed = true;
      55             :         }
      56             : 
      57           0 :         if (found < 0)
      58           0 :                 return -errno;
      59             : 
      60           0 :         return changed;
      61             : }
      62             : 
      63           0 : int devnode_acl(const char *path,
      64             :                 bool flush,
      65             :                 bool del, uid_t old_uid,
      66             :                 bool add, uid_t new_uid) {
      67             : 
      68             :         acl_t acl;
      69           0 :         int r = 0;
      70           0 :         bool changed = false;
      71             : 
      72           0 :         assert(path);
      73             : 
      74           0 :         acl = acl_get_file(path, ACL_TYPE_ACCESS);
      75           0 :         if (!acl)
      76           0 :                 return -errno;
      77             : 
      78           0 :         if (flush) {
      79             : 
      80           0 :                 r = flush_acl(acl);
      81           0 :                 if (r < 0)
      82           0 :                         goto finish;
      83           0 :                 if (r > 0)
      84           0 :                         changed = true;
      85             : 
      86           0 :         } else if (del && old_uid > 0) {
      87             :                 acl_entry_t entry;
      88             : 
      89           0 :                 r = acl_find_uid(acl, old_uid, &entry);
      90           0 :                 if (r < 0)
      91           0 :                         goto finish;
      92             : 
      93           0 :                 if (r > 0) {
      94           0 :                         if (acl_delete_entry(acl, entry) < 0) {
      95           0 :                                 r = -errno;
      96           0 :                                 goto finish;
      97             :                         }
      98             : 
      99           0 :                         changed = true;
     100             :                 }
     101             :         }
     102             : 
     103           0 :         if (add && new_uid > 0) {
     104             :                 acl_entry_t entry;
     105             :                 acl_permset_t permset;
     106             :                 int rd, wt;
     107             : 
     108           0 :                 r = acl_find_uid(acl, new_uid, &entry);
     109           0 :                 if (r < 0)
     110           0 :                         goto finish;
     111             : 
     112           0 :                 if (r == 0) {
     113           0 :                         if (acl_create_entry(&acl, &entry) < 0) {
     114           0 :                                 r = -errno;
     115           0 :                                 goto finish;
     116             :                         }
     117             : 
     118           0 :                         if (acl_set_tag_type(entry, ACL_USER) < 0 ||
     119           0 :                             acl_set_qualifier(entry, &new_uid) < 0) {
     120           0 :                                 r = -errno;
     121           0 :                                 goto finish;
     122             :                         }
     123             :                 }
     124             : 
     125           0 :                 if (acl_get_permset(entry, &permset) < 0) {
     126           0 :                         r = -errno;
     127           0 :                         goto finish;
     128             :                 }
     129             : 
     130           0 :                 rd = acl_get_perm(permset, ACL_READ);
     131           0 :                 if (rd < 0) {
     132           0 :                         r = -errno;
     133           0 :                         goto finish;
     134             :                 }
     135             : 
     136           0 :                 wt = acl_get_perm(permset, ACL_WRITE);
     137           0 :                 if (wt < 0) {
     138           0 :                         r = -errno;
     139           0 :                         goto finish;
     140             :                 }
     141             : 
     142           0 :                 if (!rd || !wt) {
     143             : 
     144           0 :                         if (acl_add_perm(permset, ACL_READ|ACL_WRITE) < 0) {
     145           0 :                                 r = -errno;
     146           0 :                                 goto finish;
     147             :                         }
     148             : 
     149           0 :                         changed = true;
     150             :                 }
     151             :         }
     152             : 
     153           0 :         if (!changed)
     154           0 :                 goto finish;
     155             : 
     156           0 :         if (acl_calc_mask(&acl) < 0) {
     157           0 :                 r = -errno;
     158           0 :                 goto finish;
     159             :         }
     160             : 
     161           0 :         if (acl_set_file(path, ACL_TYPE_ACCESS, acl) < 0) {
     162           0 :                 r = -errno;
     163           0 :                 goto finish;
     164             :         }
     165             : 
     166           0 :         r = 0;
     167             : 
     168             : finish:
     169           0 :         acl_free(acl);
     170             : 
     171           0 :         return r;
     172             : }
     173             : 
     174           0 : int devnode_acl_all(struct udev *udev,
     175             :                     const char *seat,
     176             :                     bool flush,
     177             :                     bool del, uid_t old_uid,
     178             :                     bool add, uid_t new_uid) {
     179             : 
     180           0 :         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
     181           0 :         struct udev_list_entry *item = NULL, *first = NULL;
     182           0 :         _cleanup_set_free_free_ Set *nodes = NULL;
     183           0 :         _cleanup_closedir_ DIR *dir = NULL;
     184             :         struct dirent *dent;
     185             :         Iterator i;
     186             :         char *n;
     187             :         int r;
     188             : 
     189           0 :         assert(udev);
     190             : 
     191           0 :         nodes = set_new(&string_hash_ops);
     192           0 :         if (!nodes)
     193           0 :                 return -ENOMEM;
     194             : 
     195           0 :         e = udev_enumerate_new(udev);
     196           0 :         if (!e)
     197           0 :                 return -ENOMEM;
     198             : 
     199           0 :         if (isempty(seat))
     200           0 :                 seat = "seat0";
     201             : 
     202             :         /* We can only match by one tag in libudev. We choose
     203             :          * "uaccess" for that. If we could match for two tags here we
     204             :          * could add the seat name as second match tag, but this would
     205             :          * be hardly optimizable in libudev, and hence checking the
     206             :          * second tag manually in our loop is a good solution. */
     207           0 :         r = udev_enumerate_add_match_tag(e, "uaccess");
     208           0 :         if (r < 0)
     209           0 :                 return r;
     210             : 
     211           0 :         r = udev_enumerate_add_match_is_initialized(e);
     212           0 :         if (r < 0)
     213           0 :                 return r;
     214             : 
     215           0 :         r = udev_enumerate_scan_devices(e);
     216           0 :         if (r < 0)
     217           0 :                 return r;
     218             : 
     219           0 :         first = udev_enumerate_get_list_entry(e);
     220           0 :         udev_list_entry_foreach(item, first) {
     221           0 :                 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
     222             :                 const char *node, *sn;
     223             : 
     224           0 :                 d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
     225           0 :                 if (!d)
     226           0 :                         return -ENOMEM;
     227             : 
     228           0 :                 sn = udev_device_get_property_value(d, "ID_SEAT");
     229           0 :                 if (isempty(sn))
     230           0 :                         sn = "seat0";
     231             : 
     232           0 :                 if (!streq(seat, sn))
     233           0 :                         continue;
     234             : 
     235           0 :                 node = udev_device_get_devnode(d);
     236             :                 /* In case people mistag devices with nodes, we need to ignore this */
     237           0 :                 if (!node)
     238           0 :                         continue;
     239             : 
     240           0 :                 n = strdup(node);
     241           0 :                 if (!n)
     242           0 :                         return -ENOMEM;
     243             : 
     244           0 :                 log_debug("Found udev node %s for seat %s", n, seat);
     245           0 :                 r = set_consume(nodes, n);
     246           0 :                 if (r < 0)
     247           0 :                         return r;
     248             :         }
     249             : 
     250             :         /* udev exports "dead" device nodes to allow module on-demand loading,
     251             :          * these devices are not known to the kernel at this moment */
     252           0 :         dir = opendir("/run/udev/static_node-tags/uaccess");
     253           0 :         if (dir) {
     254           0 :                 FOREACH_DIRENT(dent, dir, return -errno) {
     255           0 :                         _cleanup_free_ char *unescaped_devname = NULL;
     256             : 
     257           0 :                         if (cunescape(dent->d_name, UNESCAPE_RELAX, &unescaped_devname) < 0)
     258           0 :                                 return -ENOMEM;
     259             : 
     260           0 :                         n = strappend("/dev/", unescaped_devname);
     261           0 :                         if (!n)
     262           0 :                                 return -ENOMEM;
     263             : 
     264           0 :                         log_debug("Found static node %s for seat %s", n, seat);
     265           0 :                         r = set_consume(nodes, n);
     266           0 :                         if (r == -EEXIST)
     267           0 :                                 continue;
     268           0 :                         if (r < 0)
     269           0 :                                 return r;
     270           0 :                 }
     271             :         }
     272             : 
     273           0 :         r = 0;
     274           0 :         SET_FOREACH(n, nodes, i) {
     275             :                 int k;
     276             : 
     277           0 :                 log_debug("Changing ACLs at %s for seat %s (uid "UID_FMT"→"UID_FMT"%s%s)",
     278             :                           n, seat, old_uid, new_uid,
     279             :                           del ? " del" : "", add ? " add" : "");
     280             : 
     281           0 :                 k = devnode_acl(n, flush, del, old_uid, add, new_uid);
     282           0 :                 if (k == -ENOENT)
     283           0 :                         log_debug("Device %s disappeared while setting ACLs", n);
     284           0 :                 else if (k < 0 && r == 0)
     285           0 :                         r = k;
     286             :         }
     287             : 
     288           0 :         return r;
     289             : }

Generated by: LCOV version 1.11