restrict allowed characters in class names
[opensuse:resmgr.git] / class.c
1 /*
2  * Resource class handling
3  *
4  * Copyright (C) 2001-2002, Olaf Kirch <okir@lst.de>
5  */
6
7 #include <sys/stat.h>
8 #include <stdlib.h>
9 #include <signal.h>
10 #include <stdio.h>
11 #include <unistd.h>
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <pwd.h>
15 #include "resmgrd.h"
16
17 res_class_t *           res_classes;
18
19 static int              lock_stale(res_device_t *);
20 static int              class_name_sane(const char* name);
21
22 res_class_t *
23 res_class_get(const char *name)
24 {
25         res_class_t     *cls;
26
27         for (cls = res_classes; cls; cls = cls->next) {
28                 if (!strcmp(cls->name, name))
29                         return cls;
30         }
31         return NULL;
32 }
33
34 res_class_t *
35 res_class_create(const char *name)
36 {
37         res_class_t     *cls;
38
39         if(!class_name_sane(name))
40                 return NULL;
41
42         cls = (res_class_t *) calloc(1, sizeof(*cls));
43         cls->name = strdup(name);
44         cls->refcnt = 1;
45
46         cls->next = res_classes;
47         res_classes = cls;
48
49         return cls;
50 }
51
52 res_class_t *
53 res_class_add_subclass(res_class_t* cls, res_class_t* subcls)
54 {
55         unsigned int    n = cls->nsubclasses;
56
57         cls->subclasses = (res_class_t **) realloc(cls->subclasses, 
58                                 (n + 1) * sizeof(res_class_t *));
59         cls->subclasses[n] = subcls;
60         cls->nsubclasses += 1;
61         subcls->refcnt += 1;
62
63         return cls;
64 }
65
66
67 res_device_t *
68 res_class_add(res_class_t *cls, const char *devname, int flags)
69 {
70         res_device_t    *dev, **p;
71
72         for (p = &cls->devices; (dev = *p) != NULL; p = &dev->next)  {
73                 if (!strcmp(dev->name, devname)) {
74                         /* existing device: just update flags */
75                         dev->flags = flags;
76                         return dev;
77                 }
78         }
79
80         *p = dev = res_device_create(devname, flags);
81         return dev;
82 }
83
84 void
85 res_class_remove(res_class_t *cls, const char *devname)
86 {
87         res_device_t    *dev, **p;
88
89         p = &cls->devices;
90         while ((dev = *p) != NULL) {
91                 if (!strcmp(dev->name, devname)) {
92                         *p = dev->next;
93                         res_device_revoke_all(cls, dev);
94                         res_device_free(dev);
95                 } else {
96                         p = &dev->next;
97                 }
98         }
99 }
100
101 res_device_t *
102 res_class_get_device(res_class_t *cls, res_name_t *name)
103 {
104         res_device_t    *dev;
105
106         for (dev = cls->devices; dev != NULL; dev = dev->next)  {
107                 if (res_name_match(name, dev))
108                         return dev;
109         }
110         return NULL;
111 }
112
113 void
114 res_class_grant(res_class_t *cls, res_user_t *user)
115 {
116         struct passwd*  pw;
117         res_device_t    *dev;
118         char path[PATH_MAX];
119
120         pw = getpwnam(user->name);
121         if(pw)
122         {
123                 for (dev = cls->devices; dev; dev = dev->next) {
124                         res_device_grant(dev, pw->pw_uid);
125                 }
126         }
127
128         strcpy(path, path_class_state);
129         strncat(path, cls->name, sizeof(path)-strlen(path)-1);
130         if(mkdir(path, 0755) == -1 && errno != EEXIST)
131         {
132                 msg_log("can't create %s: %s", path, strerror(errno));
133                 return;
134         }
135
136         strncat(path, "/", sizeof(path)-strlen(path)-1);
137         strncat(path, user->name, sizeof(path)-strlen(path)-1);
138
139         if(open(path, O_WRONLY|O_CREAT, 0644) == -1)
140         {
141                 msg_log("can't create %s: %s", path, strerror(errno));
142         }
143 }
144
145 /** used when adding devices at runtime */
146 void
147 res_class_grant_single_device(res_class_t *cls, res_device_t *newdev, res_user_t *user)
148 {
149         struct passwd*  pw;
150         res_device_t    *dev;
151
152         for (dev = cls->devices; dev; dev = dev->next) {
153                 if(dev != newdev)
154                         continue;
155
156                 pw = getpwnam(user->name);
157                 if(pw)
158                         res_device_grant(dev, pw->pw_uid);
159                 break;
160         }
161 }
162
163 void
164 res_class_revoke(res_class_t *cls, res_user_t *user)
165 {
166         struct passwd*  pw;
167         res_device_t    *dev;
168         char path[PATH_MAX];
169
170         pw = getpwnam(user->name);
171         if(pw)
172         {
173                 for (dev = cls->devices; dev; dev = dev->next) {
174                         res_device_revoke(dev, pw->pw_uid);
175                 }
176         }
177
178         snprintf(path, sizeof(path), "%s/%s/%s", path_class_state, cls->name, user->name);
179         unlink(path);
180 }
181
182 void
183 res_class_free(res_class_t *cls)
184 {
185         res_device_t    *dev;
186
187         if(!cls->refcnt)
188                 msg_fatal("trying to free class with refcnt zero\n");
189
190         cls->refcnt--;
191         if (cls->refcnt == 0) {
192                 unsigned n;
193                 for (n = 0; n < cls->nsubclasses; ++n) {
194                         res_class_free(cls->subclasses[n]);
195                 }
196                 res_acl_free(cls->acl);
197                 while ((dev = cls->devices) != NULL) {
198                         cls->devices = dev->next;
199                         res_device_free(dev);
200                 }
201                 free(cls->name);
202                 memset(cls, 0, sizeof(*cls));
203                 free(cls);
204         }
205 }
206
207 /*
208  * Check whether a given path name is a sane device name
209  */
210 int
211 res_sane_device_path(const char *basedir, const char *path)
212 {
213         unsigned int    len;
214
215         /* Make sure we match the given base directory */
216         len = strlen(basedir);
217         if (strncmp(path, basedir, len)
218          || path[len] != '/')
219                 return 0;
220
221         /* It must not contain .. */
222         if (strstr(path, ".."))
223                 return 0;
224
225         return 1;
226 }
227
228 /*
229  * Create device objects
230  */
231 res_device_t *
232 res_device_create(const char *name, int flags)
233 {
234         res_device_t    *dev;
235         res_name_t      *namet;
236         char            path[4096], *s;
237
238         s = strchr(name, ':');
239
240         if(s != NULL && res_family_get_prefix(name) == NULL)
241         {
242                 msg_debug("%s has an invalid family", name);
243                 return NULL;
244         }
245
246         dev = (res_device_t *) calloc(1, sizeof(*dev));
247         dev->name = strdup(name);
248         dev->flags = flags;
249
250         namet = res_name_parse(name);
251         if(namet && namet->ops && namet->ops->create)
252         {
253                 if(s)
254                         dev->family = namet->ops;
255                 namet->ops->create(dev);
256         }
257         msg_debug("%s created", dev->name);
258         res_name_free(namet);
259
260         snprintf(path, sizeof(path), "%s/LCK.", res_config_lock_dir);
261         if (!strncmp(name, "/dev/", 5))
262                 name += 4;
263
264         s = path + strlen(path);
265         while (*name && s < path+sizeof(path)-1) {
266                 if (*name == '/') {
267                         *s++ = '.';
268                         while (*name == '/')
269                                 name++;
270                 } else {
271                         *s++ = *name++;
272                 }
273         }
274         *s++ = '\0';
275         dev->lock = strdup(path);
276
277         return dev;
278 }
279
280 int
281 res_device_grant(res_device_t *dev, uid_t uid)
282 {
283         res_name_t* name = NULL;
284
285         if(dev->flags & DEV_FLAGS_NOACCES)
286                 return 0;
287
288         if(dev->family && dev->family->grant)
289         {
290                 return dev->family->grant(dev, uid);
291         }
292         else if((name = res_name_parse(dev->name)) && name->ops && name->ops->grant)
293         {
294                 name->ops->grant(dev, uid);
295         }
296
297         if(dev->flags & DEV_FLAGS_NEW)
298                 dev->flags ^= DEV_FLAGS_NEW;
299
300         res_name_free(name);
301
302         return 0;
303 }
304
305 int
306 res_device_revoke(res_device_t *dev, uid_t uid)
307 {
308         res_name_t* name = NULL;
309
310         if(dev->flags & DEV_FLAGS_NOACCES)
311                 return 0;
312
313         if(dev->family && dev->family->revoke)
314         {
315                 return dev->family->revoke(dev, uid);
316         }
317         else if((name = res_name_parse(dev->name)) && name->ops && name->ops->revoke)
318         {
319                 name->ops->revoke(dev, uid);
320         }
321
322         res_name_free(name);
323
324         return 0;
325 }
326
327 /*
328  * Lock/unlock a device
329  */
330 int
331 res_device_lock(res_device_t *dev, uid_t uid, pid_t pid)
332 {
333         char    locktemp[4096], pidbuf[64];
334         int     fd;
335
336         sprintf(pidbuf, "%u\n", pid);
337
338         /* First create a temp lock file */
339         snprintf(locktemp, sizeof(locktemp),
340                         "%s.XXXXXX", dev->lock);
341         if ((fd = mkstemp(locktemp)) < 0) {
342                 msg_log("Unable to create lock fencepost: %m");
343                 return -1;
344         }
345
346         write(fd, pidbuf, strlen(pidbuf));
347         close(fd);
348
349         if (link(locktemp, dev->lock) >= 0) {
350                 chmod(dev->lock, 0644);
351                 chown(dev->lock, uid, 0);
352                 unlink(locktemp);
353                 return 0;
354         }
355
356         if (errno != EEXIST) {
357                 unlink(locktemp);
358                 return -1;
359         }
360         unlink(locktemp);
361
362         /* There's a conflicting lock - see if it still exists */
363         if (!(pid = lock_stale(dev)))
364                 return -1;
365
366         /* Stale lock file. Return the holder's pid */
367         return pid;
368 }
369
370 int
371 res_device_unlock(res_device_t *dev, uid_t uid)
372 {
373         struct stat     stb;
374
375         if (stat(dev->lock, &stb) < 0)
376                 return -1;
377         if (stb.st_uid != uid && !lock_stale(dev))
378                 return -1;
379         unlink(dev->lock);
380         return 0;
381 }
382
383 int
384 lock_stale(res_device_t *dev)
385 {
386         char    pidbuf[64];
387         int     n, fd, locker;
388
389         /* Now try to read the locker's pid from the file */
390         fd = open(dev->lock, O_RDONLY);
391         if (fd < 0)
392                 return 0;
393
394         n = read(fd, pidbuf, sizeof(pidbuf)-1);
395         close(fd);
396
397         if (n <= 0)
398                 return 0;
399         pidbuf[n] = '\0';
400
401         /* Transparently deal with binary lock files - nobody
402          * should use that locking style anymore, but better be
403          * safe than sorry */
404         if (n == sizeof(int)) {
405                 memcpy(&locker, pidbuf, sizeof(int));
406         } else {
407                 locker = strtol(pidbuf, NULL, 0);
408         }
409         if (locker <= 0)
410                 return 0;
411
412         if (kill(locker, 0) < 0 && errno == ESRCH)
413                 return locker;
414
415         return 0;
416 }
417
418 /*
419  * Delete a device object
420  */
421 void
422 res_device_free(res_device_t *dev)
423 {
424         res_name_t *name;
425         if(dev->family && dev->family->destroy)
426         {
427                 dev->family->destroy(dev);
428         }
429         else if((name = res_name_parse(dev->name)) && name->ops && name->ops->destroy)
430         {
431                 name->ops->destroy(dev);
432         }
433
434         free(dev->name);
435         free(dev->lock);
436         memset(dev, 0, sizeof(*dev));
437         free(dev);
438 }
439
440 int
441 class_name_sane(const char* name)
442 {
443         if(!name || !*name)
444                 return 0;
445
446         for(; *name; ++name)
447         {
448                 switch(*name)
449                 {
450                         case 'a' ... 'z':
451                         case 'A' ... 'Z':
452                         case '0' ... '9':
453                         case ':':
454                         case '.':
455                         case '_':
456                         case '-':
457                                 break;
458                         default:
459                                 return 0;
460                 }
461         }
462         return 1;
463 }