- handle fs acls internally instead of passing device names to resmgr
[opensuse:hal-resmgr.git] / file.c
1 /*
2  * Device file resource family
3  *
4  * Copyright (C) 2002, Olaf Kirch <okir@lst.de>
5  * Copyright (C) 2005, Ludwig Nussel <lnussel@suse.de>
6  */
7
8 #define _GNU_SOURCE /* O_NOFOLLOW */
9
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include <stdlib.h>
13 #include <errno.h>
14 #include <string.h>
15 #include <sys/stat.h>
16 #include "file.h"
17 #include "facl.h"
18 #include "debug.h"
19
20 res_file_t* res_file_new(const char* name, const char* flags)
21 {
22         res_file_t* dev;
23
24         dev = calloc(1, sizeof(res_file_t)+strlen(name)+1);
25         strcpy(dev->name, name);
26         // TODO: parse flags
27         
28         return dev;
29 }
30
31 void res_file_free(res_file_t* dev)
32 {
33         free(dev);
34 }
35
36 int
37 res_file_grant(res_file_t *dev, uid_t uid)
38 {
39         int ret = -1;
40
41         if(dev->flags & DEV_FLAGS_NOFACL || 0 == uid)
42                 return 0;
43
44         debug(1, "grant uid %d on %s", uid, dev->name);
45
46         if(dev->flags & DEV_FLAGS_NEW)
47         {
48                 facl_clear(dev->name);
49         }
50         else if(dev->flags & DEV_FLAGS_OWNER)
51         {
52                 warning("acl support missing on %s, cannot grant uid %d additional access\n",
53                         dev->name, uid);
54                 return -1;
55         }
56
57         if(dev->flags & DEV_FLAGS_RO)
58                 ret = add_facl_r(dev->name, uid);
59         else
60                 ret = add_facl_rw(dev->name, uid);
61
62         debug(1, "%s %x %d\n", dev->name, dev->flags, ret);
63
64         if(dev->flags & DEV_FLAGS_NEW)
65         {
66                 if(ret != 0) // no ACL support?
67                 {
68                         int fd = -1;
69                         struct stat stb;
70                         /* RO doesn't work as the user could just
71                          * chmod if he is owner of the device */
72                         if(dev->flags & DEV_FLAGS_RO)
73                         {
74                                 warning("can't grant read-only access via chown method on %s\n",
75                                                 dev->name);
76                                 ret = -1;
77                         }
78                         else if((fd = open(dev->name, O_RDONLY|O_NONBLOCK|O_NOFOLLOW)) == -1
79                                 || fstat(fd, &stb) == -1
80                                 || fchown(fd, uid, -1) == -1
81                                 || fchmod(fd, (stb.st_mode&0777)|0600) == -1)
82                         {
83                                 if(fd != -1)
84                                         close(fd);
85                                 warning("failed to change owner of %s to uid %d: %s\n",
86                                                 dev->name, uid, strerror(errno));
87                                 ret = -1;
88                         }
89                         else
90                         {
91                                 close(fd);
92                                 dev->saved_uid = stb.st_uid;
93                                 dev->saved_gid = stb.st_gid;
94                                 dev->saved_mode = stb.st_mode&0777;
95                                 dev->flags |= DEV_FLAGS_OWNER;
96                                 ret = 0;
97
98                                 debug(1, "used chown %d instead of ACL on %s\n", uid, dev->name);
99                         }
100                 }
101         }
102
103         return ret;
104 }
105
106 int
107 res_file_revoke(res_file_t *dev, uid_t uid)
108 {
109         if(dev->flags & DEV_FLAGS_NOFACL || 0 == uid)
110                 return 0;
111
112         debug(1, "revoke uid %d on %s", uid, dev->name);
113         
114         if(dev->flags & DEV_FLAGS_OWNER)
115         {
116                 int fd = -1;
117                 errno = 0;
118                 if((fd = open(dev->name, O_RDONLY|O_NONBLOCK|O_NOFOLLOW)) == -1
119                         || fchown(fd, dev->saved_uid, dev->saved_gid) == -1
120                         || fchmod(fd, dev->saved_mode) == -1)
121                 {
122                         if(fd != -1)
123                                 close(fd);
124
125                         if(errno != ENOENT)
126                                 warning("failed to change owner of %s to uid %d: %s\n",
127                                         dev->name, 0, strerror(errno));
128                         return -1;
129                 }
130                 else
131                 {
132                         close(fd);
133                         dev->flags ^= DEV_FLAGS_OWNER;
134                         dev->flags |= DEV_FLAGS_NEW;
135                         return 0;
136                 }
137         }
138         else
139         {
140                 return remove_facl(dev->name, uid);
141         }
142 }
143
144 int
145 res_file_create(res_file_t *dev)
146 {
147         dev->flags |= DEV_FLAGS_NEW;
148         return 0;
149 }
150
151 int
152 res_file_destroy(res_file_t *dev)
153 {
154         if(!(dev->flags & DEV_FLAGS_NOACCES)
155         && !(dev->flags & DEV_FLAGS_NOFACL))
156                 facl_clear(dev->name);
157         return 0;
158 }