]> git.k1024.org Git - pylibacl.git/blob - acl.c
Implement acl_from_mode
[pylibacl.git] / acl.c
1 #include <Python.h>
2
3 #include <sys/types.h>
4 #include <sys/acl.h>
5
6 #ifdef HAVE_LINUX
7 #include "os_linux.c"
8 #endif
9
10 staticforward PyTypeObject ACL_Type;
11 static PyObject* ACL_applyto(PyObject* obj, PyObject* args);
12 static PyObject* ACL_valid(PyObject* obj, PyObject* args);
13
14 #ifdef HAVE_LEVEL2
15 static PyObject* ACL_get_state(PyObject *obj, PyObject* args);
16 static PyObject* ACL_set_state(PyObject *obj, PyObject* args);
17
18 staticforward PyTypeObject Entry_Type;
19 staticforward PyTypeObject Permset_Type;
20 static PyObject* Permset_new(PyTypeObject* type, PyObject* args,
21                              PyObject *keywds);
22 #endif
23
24 static acl_perm_t holder_ACL_EXECUTE = ACL_EXECUTE;
25 static acl_perm_t holder_ACL_READ = ACL_READ;
26 static acl_perm_t holder_ACL_WRITE = ACL_WRITE;
27
28 typedef struct {
29     PyObject_HEAD
30     acl_t acl;
31 #ifdef HAVE_LEVEL2
32     int entry_id;
33 #endif
34 } ACL_Object;
35
36 #ifdef HAVE_LEVEL2
37
38 typedef struct {
39     PyObject_HEAD
40     PyObject *parent_acl; /* The parent acl, so it won't run out on us */
41     acl_entry_t entry;
42 } Entry_Object;
43
44 typedef struct {
45     PyObject_HEAD
46     PyObject *parent_entry; /* The parent entry, so it won't run out on us */
47     acl_permset_t permset;
48 } Permset_Object;
49
50 #endif
51
52 /* Creation of a new ACL instance */
53 static PyObject* ACL_new(PyTypeObject* type, PyObject* args,
54                          PyObject *keywds) {
55     PyObject* newacl;
56
57     newacl = type->tp_alloc(type, 0);
58
59     if(newacl != NULL) {
60         ((ACL_Object*)newacl)->acl = NULL;
61 #ifdef HAVEL_LEVEL2
62         ((ACL_Object*)newacl)->entry_id = ACL_FIRST_ENTRY;
63 #endif
64     }
65
66     return newacl;
67 }
68
69 /* Initialization of a new ACL instance */
70 static int ACL_init(PyObject* obj, PyObject* args, PyObject *keywds) {
71     ACL_Object* self = (ACL_Object*) obj;
72 #ifdef HAVE_LINUX
73     static char *kwlist[] = { "file", "fd", "text", "acl", "filedef",
74                               "mode", NULL };
75     const char *format = "|sisO!sH";
76     mode_t mode = 0;
77 #else
78     static char *kwlist[] = { "file", "fd", "text", "acl", "filedef", NULL };
79     const char *format = "|sisO!s";
80 #endif
81     char *file = NULL;
82     char *filedef = NULL;
83     char *text = NULL;
84     int fd = -1;
85     ACL_Object* thesrc = NULL;
86
87     if(!PyTuple_Check(args) || PyTuple_Size(args) != 0 ||
88        (keywds != NULL && PyDict_Check(keywds) && PyDict_Size(keywds) > 1)) {
89         PyErr_SetString(PyExc_ValueError, "a max of one keyword argument"
90                         " must be passed");
91         return -1;
92     }
93     if(!PyArg_ParseTupleAndKeywords(args, keywds, format, kwlist,
94                                     &file, &fd, &text, &ACL_Type,
95                                     &thesrc, &filedef
96 #ifdef HAVE_LINUX
97                                     , &mode
98 #endif
99                                     ))
100         return -1;
101
102     /* Free the old acl_t without checking for error, we don't
103      * care right now */
104     if(self->acl != NULL)
105         acl_free(self->acl);
106
107     if(file != NULL)
108         self->acl = acl_get_file(file, ACL_TYPE_ACCESS);
109     else if(text != NULL)
110         self->acl = acl_from_text(text);
111     else if(fd != -1)
112         self->acl = acl_get_fd(fd);
113     else if(thesrc != NULL)
114         self->acl = acl_dup(thesrc->acl);
115     else if(filedef != NULL)
116         self->acl = acl_get_file(filedef, ACL_TYPE_DEFAULT);
117 #ifdef HAVE_LINUX
118     else if(PyMapping_HasKeyString(keywds, kwlist[5]))
119         self->acl = acl_from_mode(mode);
120 #endif
121     else
122         self->acl = acl_init(0);
123
124     if(self->acl == NULL) {
125         PyErr_SetFromErrno(PyExc_IOError);
126         return -1;
127     }
128
129     return 0;
130 }
131
132 /* Standard type functions */
133 static void ACL_dealloc(PyObject* obj) {
134     ACL_Object *self = (ACL_Object*) obj;
135     PyObject *err_type, *err_value, *err_traceback;
136     int have_error = PyErr_Occurred() ? 1 : 0;
137
138     if (have_error)
139         PyErr_Fetch(&err_type, &err_value, &err_traceback);
140     if(self->acl != NULL && acl_free(self->acl) != 0)
141         PyErr_WriteUnraisable(obj);
142     if (have_error)
143         PyErr_Restore(err_type, err_value, err_traceback);
144     PyObject_DEL(self);
145 }
146
147 /* Converts the acl to a text format */
148 static PyObject* ACL_str(PyObject *obj) {
149     char *text;
150     ACL_Object *self = (ACL_Object*) obj;
151     PyObject *ret;
152
153     text = acl_to_text(self->acl, NULL);
154     if(text == NULL) {
155         return PyErr_SetFromErrno(PyExc_IOError);
156     }
157     ret = PyString_FromString(text);
158     if(acl_free(text) != 0) {
159         Py_DECREF(ret);
160         return PyErr_SetFromErrno(PyExc_IOError);
161     }
162     return ret;
163 }
164
165 /* Custom methods */
166 static char __applyto_doc__[] = \
167 "Apply the ACL to a file or filehandle.\n" \
168 "\n" \
169 "Parameters:\n" \
170 "  - either a filename or a file-like object or an integer; this\n" \
171 "    represents the filesystem object on which to act\n" \
172 "  - optional flag representing the type of ACL to set, either\n" \
173 "    ACL_TYPE_ACCESS (default) or ACL_TYPE_DEFAULT\n" \
174 ;
175
176 /* Applyes the ACL to a file */
177 static PyObject* ACL_applyto(PyObject* obj, PyObject* args) {
178     ACL_Object *self = (ACL_Object*) obj;
179     PyObject *myarg;
180     acl_type_t type = ACL_TYPE_ACCESS;
181     int nret;
182     int fd;
183
184     if (!PyArg_ParseTuple(args, "O|i", &myarg, &type))
185         return NULL;
186
187     if(PyString_Check(myarg)) {
188         char *filename = PyString_AS_STRING(myarg);
189         nret = acl_set_file(filename, type, self->acl);
190     } else if((fd = PyObject_AsFileDescriptor(myarg)) != -1) {
191         nret = acl_set_fd(fd, self->acl);
192     } else {
193         PyErr_SetString(PyExc_TypeError, "argument 1 must be string, int,"
194                         " or file-like object");
195         return 0;
196     }
197     if(nret == -1) {
198         return PyErr_SetFromErrno(PyExc_IOError);
199     }
200
201     /* Return the result */
202     Py_INCREF(Py_None);
203     return Py_None;
204 }
205
206 static char __valid_doc__[] = \
207 "Test the ACL for validity.\n" \
208 "\n" \
209 "This method tests the ACL to see if it is a valid ACL\n" \
210 "in terms of the filesystem. More precisely, it checks:\n" \
211 "A valid ACL contains exactly one entry with each of the ACL_USER_OBJ,\n" \
212 "ACL_GROUP_OBJ, and ACL_OTHER tag types. Entries with ACL_USER and\n" \
213 "ACL_GROUP tag types may appear zero or more times in an ACL. An ACL that\n" \
214 "contains entries of ACL_USER or ACL_GROUP tag types must contain exactly\n" \
215 "one entry of the ACL_MASK tag type. If an ACL contains no entries of\n" \
216 "ACL_USER or ACL_GROUP tag types, the ACL_MASK entry is optional.\n" \
217 "\n" \
218 "All user ID qualifiers must be unique among all entries of ACL_USER tag\n" \
219 "type, and all group IDs must be unique among all entries of ACL_GROUP tag\n" \
220 "type.\n" \
221 "\n" \
222 "The method will return 1 for a valid ACL and 0 for an invalid one.\n" \
223 "This has been chosen because the specification for acl_valid in POSIX.1e\n" \
224 "documents only one possible value for errno in case of an invalid ACL, \n" \
225 "so we can't differentiate between classes of errors. Other suggestions \n" \
226 "are welcome.\n" \
227 ;
228
229 /* Checks the ACL for validity */
230 static PyObject* ACL_valid(PyObject* obj, PyObject* args) {
231     ACL_Object *self = (ACL_Object*) obj;
232
233     if(acl_valid(self->acl) == -1) {
234         Py_INCREF(Py_False);
235         return Py_False;
236     } else {
237         Py_INCREF(Py_True);
238         return Py_True;
239     }
240 }
241
242 #ifdef HAVE_LEVEL2
243
244 static PyObject* ACL_get_state(PyObject *obj, PyObject* args) {
245     ACL_Object *self = (ACL_Object*) obj;
246     PyObject *ret;
247     ssize_t size, nsize;
248     char *buf;
249
250     size = acl_size(self->acl);
251     if(size == -1)
252         return PyErr_SetFromErrno(PyExc_IOError);
253
254     if((ret = PyString_FromStringAndSize(NULL, size)) == NULL)
255         return NULL;
256     buf = PyString_AsString(ret);
257
258     if((nsize = acl_copy_ext(buf, self->acl, size)) == -1) {
259         Py_DECREF(ret);
260         return PyErr_SetFromErrno(PyExc_IOError);
261     }
262
263     return ret;
264 }
265
266 static PyObject* ACL_set_state(PyObject *obj, PyObject* args) {
267     ACL_Object *self = (ACL_Object*) obj;
268     const void *buf;
269     int bufsize;
270     acl_t ptr;
271
272     /* Parse the argument */
273     if (!PyArg_ParseTuple(args, "s#", &buf, &bufsize))
274         return NULL;
275
276     /* Try to import the external representation */
277     if((ptr = acl_copy_int(buf)) == NULL)
278         return PyErr_SetFromErrno(PyExc_IOError);
279
280     /* Free the old acl. Should we ignore errors here? */
281     if(self->acl != NULL) {
282         if(acl_free(self->acl) == -1)
283             return PyErr_SetFromErrno(PyExc_IOError);
284     }
285
286     self->acl = ptr;
287
288     /* Return the result */
289     Py_INCREF(Py_None);
290     return Py_None;
291 }
292
293 /* tp_iter for the ACL type; since it can be iterated only
294  * destructively, the type is its iterator
295  */
296 static PyObject* ACL_iter(PyObject *obj) {
297     ACL_Object *self = (ACL_Object*)obj;
298     self->entry_id = ACL_FIRST_ENTRY;
299     Py_INCREF(obj);
300     return obj;
301 }
302
303 /* the tp_iternext function for the ACL type */
304 static PyObject* ACL_iternext(PyObject *obj) {
305     ACL_Object *self = (ACL_Object*)obj;
306     acl_entry_t the_entry_t;
307     Entry_Object *the_entry_obj;
308     int nerr;
309
310     nerr = acl_get_entry(self->acl, self->entry_id, &the_entry_t);
311     self->entry_id = ACL_NEXT_ENTRY;
312     if(nerr == -1)
313         return PyErr_SetFromErrno(PyExc_IOError);
314     else if(nerr == 0) {
315         /* Docs says this is not needed */
316         /*PyErr_SetObject(PyExc_StopIteration, Py_None);*/
317         return NULL;
318     }
319
320     the_entry_obj = (Entry_Object*) PyType_GenericNew(&Entry_Type, NULL, NULL);
321     if(the_entry_obj == NULL)
322         return NULL;
323
324     the_entry_obj->entry = the_entry_t;
325
326     the_entry_obj->parent_acl = obj;
327     Py_INCREF(obj); /* For the reference we have in entry->parent */
328
329     return (PyObject*)the_entry_obj;
330 }
331
332 static char __ACL_delete_entry_doc__[] = \
333 "Deletes an entry from the ACL.\n" \
334 "\n" \
335 "Note: Only with level 2\n" \
336 "Parameters:\n" \
337 " - the Entry object which should be deleted; note that after\n" \
338 "   this function is called, that object is unusable any longer\n" \
339 "   and should be deleted\n" \
340 ;
341
342 /* Deletes an entry from the ACL */
343 static PyObject* ACL_delete_entry(PyObject *obj, PyObject *args) {
344     ACL_Object *self = (ACL_Object*)obj;
345     Entry_Object *e;
346
347     if (!PyArg_ParseTuple(args, "O!", &Entry_Type, &e))
348         return NULL;
349
350     if(acl_delete_entry(self->acl, e->entry) == -1)
351         return PyErr_SetFromErrno(PyExc_IOError);
352
353     /* Return the result */
354     Py_INCREF(Py_None);
355     return Py_None;
356 }
357
358 static char __ACL_calc_mask_doc__[] = \
359 "Compute the file group class mask.\n" \
360 "\n" \
361 "The calc_mask() method calculates and sets the permissions \n" \
362 "associated with the ACL_MASK Entry of the ACL.\n" \
363 "The value of the new permissions is the union of the permissions \n" \
364 "granted by all entries of tag type ACL_GROUP, ACL_GROUP_OBJ, or \n" \
365 "ACL_USER.  If the ACL already contains an ACL_MASK entry, its \n" \
366 "permissions are overwritten; if it does not contain an ACL_MASK \n" \
367 "Entry, one is added.\n" \
368 "\n" \
369 "The order of existing entries in the ACL is undefined after this \n" \
370 "function.\n" \
371 ;
372
373 /* Updates the mask entry in the ACL */
374 static PyObject* ACL_calc_mask(PyObject *obj, PyObject *args) {
375     ACL_Object *self = (ACL_Object*)obj;
376
377     if(acl_calc_mask(&self->acl) == -1)
378         return PyErr_SetFromErrno(PyExc_IOError);
379
380     /* Return the result */
381     Py_INCREF(Py_None);
382     return Py_None;
383 }
384
385 static char __ACL_append_doc__[] = \
386 "Append a new Entry to the ACL and return it.\n" \
387 "\n" \
388 "This is a convenience function to create a new Entry \n" \
389 "and append it to the ACL.\n" \
390 "If a parameter of type Entry instance is given, the \n" \
391 "entry will be a copy of that one (as if copied with \n" \
392 "Entry.copy()), otherwise, the new entry will be empty.\n" \
393 ;
394
395 /* Convenience method to create a new Entry */
396 static PyObject* ACL_append(PyObject *obj, PyObject *args) {
397     ACL_Object* self = (ACL_Object*) obj;
398     Entry_Object* newentry;
399     Entry_Object* oldentry = NULL;
400     int nret;
401
402     newentry = (Entry_Object*)PyType_GenericNew(&Entry_Type, NULL, NULL);
403     if(newentry == NULL) {
404         return NULL;
405     }
406
407     if (!PyArg_ParseTuple(args, "|O!", &Entry_Type, &oldentry))
408         return NULL;
409
410     nret = acl_create_entry(&self->acl, &newentry->entry);
411     if(nret == -1) {
412         Py_DECREF(newentry);
413         return PyErr_SetFromErrno(PyExc_IOError);
414     }
415
416     if(oldentry != NULL) {
417         nret = acl_copy_entry(newentry->entry, oldentry->entry);
418         if(nret == -1) {
419             Py_DECREF(newentry);
420             return PyErr_SetFromErrno(PyExc_IOError);
421         }
422     }
423
424     newentry->parent_acl = obj;
425     Py_INCREF(obj);
426
427     return (PyObject*)newentry;
428 }
429
430 /***** Entry type *****/
431
432 /* Creation of a new Entry instance */
433 static PyObject* Entry_new(PyTypeObject* type, PyObject* args,
434                            PyObject *keywds) {
435     PyObject* newentry;
436
437     newentry = PyType_GenericNew(type, args, keywds);
438
439     if(newentry != NULL) {
440         ((Entry_Object*)newentry)->entry = NULL;
441         ((Entry_Object*)newentry)->parent_acl = NULL;
442     }
443
444     return newentry;
445 }
446
447 /* Initialization of a new Entry instance */
448 static int Entry_init(PyObject* obj, PyObject* args, PyObject *keywds) {
449     Entry_Object* self = (Entry_Object*) obj;
450     ACL_Object* parent = NULL;
451
452     if (!PyArg_ParseTuple(args, "O!", &ACL_Type, &parent))
453         return -1;
454
455     if(acl_create_entry(&parent->acl, &self->entry) == -1) {
456         PyErr_SetFromErrno(PyExc_IOError);
457         return -1;
458     }
459
460     self->parent_acl = (PyObject*)parent;
461     Py_INCREF(parent);
462
463     return 0;
464 }
465
466 /* Free the Entry instance */
467 static void Entry_dealloc(PyObject* obj) {
468     Entry_Object *self = (Entry_Object*) obj;
469     PyObject *err_type, *err_value, *err_traceback;
470     int have_error = PyErr_Occurred() ? 1 : 0;
471
472     if (have_error)
473         PyErr_Fetch(&err_type, &err_value, &err_traceback);
474     if(self->parent_acl != NULL) {
475         Py_DECREF(self->parent_acl);
476         self->parent_acl = NULL;
477     }
478     if (have_error)
479         PyErr_Restore(err_type, err_value, err_traceback);
480     PyObject_DEL(self);
481 }
482
483 /* Converts the entry to a text format */
484 static PyObject* Entry_str(PyObject *obj) {
485     acl_tag_t tag;
486     uid_t qualifier;
487     void *p;
488     PyObject *ret;
489     PyObject *format, *list;
490     Entry_Object *self = (Entry_Object*) obj;
491
492     if(acl_get_tag_type(self->entry, &tag) == -1) {
493         PyErr_SetFromErrno(PyExc_IOError);
494         return NULL;
495     }
496     if(tag == ACL_USER || tag == ACL_GROUP) {
497         if((p = acl_get_qualifier(self->entry)) == NULL) {
498             PyErr_SetFromErrno(PyExc_IOError);
499             return NULL;
500         }
501         qualifier = *(uid_t*)p;
502         acl_free(p);
503     } else {
504         qualifier = 0;
505     }
506
507     format = PyString_FromString("ACL entry for %s");
508     if(format == NULL)
509         return NULL;
510     list = PyTuple_New(1);
511     if(tag == ACL_UNDEFINED_TAG) {
512         PyTuple_SetItem(list, 0, PyString_FromString("undefined type"));
513     } else if(tag == ACL_USER_OBJ) {
514         PyTuple_SetItem(list, 0, PyString_FromString("the owner"));
515     } else if(tag == ACL_GROUP_OBJ) {
516         PyTuple_SetItem(list, 0, PyString_FromString("the group"));
517     } else if(tag == ACL_OTHER) {
518         PyTuple_SetItem(list, 0, PyString_FromString("the others"));
519     } else if(tag == ACL_USER) {
520         PyTuple_SetItem(list, 0, PyString_FromFormat("user with uid %d",
521                                                      qualifier));
522     } else if(tag == ACL_GROUP) {
523         PyTuple_SetItem(list, 0, PyString_FromFormat("group with gid %d",
524                                                      qualifier));
525     } else if(tag == ACL_MASK) {
526         PyTuple_SetItem(list, 0, PyString_FromString("the mask"));
527     } else {
528         PyTuple_SetItem(list, 0, PyString_FromString("UNKNOWN_TAG_TYPE!"));
529     }
530     ret = PyString_Format(format, list);
531     Py_DECREF(format);
532     Py_DECREF(list);
533     return ret;
534 }
535
536 /* Sets the tag type of the entry */
537 static int Entry_set_tag_type(PyObject* obj, PyObject* value, void* arg) {
538     Entry_Object *self = (Entry_Object*) obj;
539
540     if(value == NULL) {
541         PyErr_SetString(PyExc_TypeError,
542                         "tag type deletion is not supported");
543         return -1;
544     }
545
546     if(!PyInt_Check(value)) {
547         PyErr_SetString(PyExc_TypeError,
548                         "tag type must be integer");
549         return -1;
550     }
551     if(acl_set_tag_type(self->entry, (acl_tag_t)PyInt_AsLong(value)) == -1) {
552         PyErr_SetFromErrno(PyExc_IOError);
553         return -1;
554     }
555
556     return 0;
557 }
558
559 /* Returns the tag type of the entry */
560 static PyObject* Entry_get_tag_type(PyObject *obj, void* arg) {
561     Entry_Object *self = (Entry_Object*) obj;
562     acl_tag_t value;
563
564     if (self->entry == NULL) {
565         PyErr_SetString(PyExc_AttributeError, "entry attribute");
566         return NULL;
567     }
568     if(acl_get_tag_type(self->entry, &value) == -1) {
569         PyErr_SetFromErrno(PyExc_IOError);
570         return NULL;
571     }
572
573     return PyInt_FromLong(value);
574 }
575
576 /* Sets the qualifier (either uid_t or gid_t) for the entry,
577  * usable only if the tag type if ACL_USER or ACL_GROUP
578  */
579 static int Entry_set_qualifier(PyObject* obj, PyObject* value, void* arg) {
580     Entry_Object *self = (Entry_Object*) obj;
581     int uidgid;
582
583     if(value == NULL) {
584         PyErr_SetString(PyExc_TypeError,
585                         "qualifier deletion is not supported");
586         return -1;
587     }
588
589     if(!PyInt_Check(value)) {
590         PyErr_SetString(PyExc_TypeError,
591                         "tag type must be integer");
592         return -1;
593     }
594     uidgid = PyInt_AsLong(value);
595     if(acl_set_qualifier(self->entry, (void*)&uidgid) == -1) {
596         PyErr_SetFromErrno(PyExc_IOError);
597         return -1;
598     }
599
600     return 0;
601 }
602
603 /* Returns the qualifier of the entry */
604 static PyObject* Entry_get_qualifier(PyObject *obj, void* arg) {
605     Entry_Object *self = (Entry_Object*) obj;
606     void *p;
607     int value;
608
609     if (self->entry == NULL) {
610         PyErr_SetString(PyExc_AttributeError, "entry attribute");
611         return NULL;
612     }
613     if((p = acl_get_qualifier(self->entry)) == NULL) {
614         PyErr_SetFromErrno(PyExc_IOError);
615         return NULL;
616     }
617     value = *(uid_t*)p;
618     acl_free(p);
619
620     return PyInt_FromLong(value);
621 }
622
623 /* Returns the parent ACL of the entry */
624 static PyObject* Entry_get_parent(PyObject *obj, void* arg) {
625     Entry_Object *self = (Entry_Object*) obj;
626
627     Py_INCREF(self->parent_acl);
628     return self->parent_acl;
629 }
630
631 /* Returns the a new Permset representing the permset of the entry
632  * FIXME: Should return a new reference to the same object, which
633  * should be created at init time!
634 */
635 static PyObject* Entry_get_permset(PyObject *obj, void* arg) {
636     Entry_Object *self = (Entry_Object*)obj;
637     PyObject *p;
638     Permset_Object *ps;
639
640     p = Permset_new(&Permset_Type, NULL, NULL);
641     if(p == NULL)
642         return NULL;
643     ps = (Permset_Object*)p;
644     if(acl_get_permset(self->entry, &ps->permset) == -1) {
645         PyErr_SetFromErrno(PyExc_IOError);
646         return NULL;
647     }
648     ps->parent_entry = obj;
649     Py_INCREF(obj);
650
651     return (PyObject*)p;
652 }
653
654 /* Sets the permset of the entry to the passed Permset */
655 static int Entry_set_permset(PyObject* obj, PyObject* value, void* arg) {
656     Entry_Object *self = (Entry_Object*)obj;
657     Permset_Object *p;
658
659     if(!PyObject_IsInstance(value, (PyObject*)&Permset_Type)) {
660         PyErr_SetString(PyExc_TypeError, "argument 1 must be posix1e.Permset");
661         return -1;
662     }
663     p = (Permset_Object*)value;
664     if(acl_set_permset(self->entry, p->permset) == -1) {
665         PyErr_SetFromErrno(PyExc_IOError);
666         return -1;
667     }
668     return 0;
669 }
670
671 static char __Entry_copy_doc__[] = \
672 "Copy an ACL entry.\n" \
673 "\n" \
674 "This method sets all the parameters to those of another\n" \
675 "entry, even one of another's ACL\n" \
676 "Parameters:\n" \
677 " - src, instance of type Entry\n" \
678 ;
679
680 /* Sets all the entry parameters to another's entry */
681 static PyObject* Entry_copy(PyObject *obj, PyObject *args) {
682     Entry_Object *self = (Entry_Object*)obj;
683     Entry_Object *other;
684
685     if(!PyArg_ParseTuple(args, "O!", &Entry_Type, &other))
686         return NULL;
687
688     if(acl_copy_entry(self->entry, other->entry) == -1)
689         return PyErr_SetFromErrno(PyExc_IOError);
690
691     Py_INCREF(Py_None);
692     return Py_None;
693 }
694
695 /**** Permset type *****/
696
697 /* Creation of a new Permset instance */
698 static PyObject* Permset_new(PyTypeObject* type, PyObject* args,
699                              PyObject *keywds) {
700     PyObject* newpermset;
701
702     newpermset = PyType_GenericNew(type, args, keywds);
703
704     if(newpermset != NULL) {
705         ((Permset_Object*)newpermset)->permset = NULL;
706         ((Permset_Object*)newpermset)->parent_entry = NULL;
707     }
708
709     return newpermset;
710 }
711
712 /* Initialization of a new Permset instance */
713 static int Permset_init(PyObject* obj, PyObject* args, PyObject *keywds) {
714     Permset_Object* self = (Permset_Object*) obj;
715     Entry_Object* parent = NULL;
716
717     if (!PyArg_ParseTuple(args, "O!", &Entry_Type, &parent))
718         return -1;
719
720     if(acl_get_permset(parent->entry, &self->permset) == -1) {
721         PyErr_SetFromErrno(PyExc_IOError);
722         return -1;
723     }
724
725     self->parent_entry = (PyObject*)parent;
726     Py_INCREF(parent);
727
728     return 0;
729 }
730
731 /* Free the Permset instance */
732 static void Permset_dealloc(PyObject* obj) {
733     Permset_Object *self = (Permset_Object*) obj;
734     PyObject *err_type, *err_value, *err_traceback;
735     int have_error = PyErr_Occurred() ? 1 : 0;
736
737     if (have_error)
738         PyErr_Fetch(&err_type, &err_value, &err_traceback);
739     if(self->parent_entry != NULL) {
740         Py_DECREF(self->parent_entry);
741         self->parent_entry = NULL;
742     }
743     if (have_error)
744         PyErr_Restore(err_type, err_value, err_traceback);
745     PyObject_DEL(self);
746 }
747
748 /* Permset string representation */
749 static PyObject* Permset_str(PyObject *obj) {
750     Permset_Object *self = (Permset_Object*) obj;
751     char pstr[3];
752
753     pstr[0] = get_perm(self->permset, ACL_READ) ? 'r' : '-';
754     pstr[1] = get_perm(self->permset, ACL_WRITE) ? 'w' : '-';
755     pstr[2] = get_perm(self->permset, ACL_EXECUTE) ? 'x' : '-';
756     return PyString_FromStringAndSize(pstr, 3);
757 }
758
759 static char __Permset_clear_doc__[] = \
760 "Clear all permissions from the permission set.\n" \
761 ;
762
763 /* Clears all permissions from the permset */
764 static PyObject* Permset_clear(PyObject* obj, PyObject* args) {
765     Permset_Object *self = (Permset_Object*) obj;
766
767     if(acl_clear_perms(self->permset) == -1)
768         return PyErr_SetFromErrno(PyExc_IOError);
769
770     /* Return the result */
771     Py_INCREF(Py_None);
772     return Py_None;
773 }
774
775 static PyObject* Permset_get_right(PyObject *obj, void* arg) {
776     Permset_Object *self = (Permset_Object*) obj;
777
778     if(get_perm(self->permset, *(acl_perm_t*)arg)) {
779         Py_INCREF(Py_True);
780         return Py_True;
781     } else {
782         Py_INCREF(Py_False);
783         return Py_False;
784     }
785 }
786
787 static int Permset_set_right(PyObject* obj, PyObject* value, void* arg) {
788     Permset_Object *self = (Permset_Object*) obj;
789     int on;
790     int nerr;
791
792     if(!PyInt_Check(value)) {
793         PyErr_SetString(PyExc_ValueError, "a maximum of one argument must"
794                         " be passed");
795         return -1;
796     }
797     on = PyInt_AsLong(value);
798     if(on)
799         nerr = acl_add_perm(self->permset, *(acl_perm_t*)arg);
800     else
801         nerr = acl_delete_perm(self->permset, *(acl_perm_t*)arg);
802     if(nerr == -1) {
803         PyErr_SetFromErrno(PyExc_IOError);
804         return -1;
805     }
806     return 0;
807 }
808
809 static char __Permset_add_doc__[] = \
810 "Add a permission to the permission set.\n" \
811 "\n" \
812 "The add() function adds the permission contained in \n" \
813 "the argument perm to the permission set.  An attempt \n" \
814 "to add a permission that is already contained in the \n" \
815 "permission set is not considered an error.\n" \
816 "Parameters:\n" \
817 "  - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...\n" \
818 "Return value:\n" \
819 "  None\n" \
820 "Can raise: IOError\n" \
821 ;
822
823 static PyObject* Permset_add(PyObject* obj, PyObject* args) {
824     Permset_Object *self = (Permset_Object*) obj;
825     int right;
826
827     if (!PyArg_ParseTuple(args, "i", &right))
828         return NULL;
829
830     if(acl_add_perm(self->permset, (acl_perm_t) right) == -1)
831         return PyErr_SetFromErrno(PyExc_IOError);
832
833     /* Return the result */
834     Py_INCREF(Py_None);
835     return Py_None;
836 }
837
838 static char __Permset_delete_doc__[] = \
839 "Delete a permission from the permission set.\n" \
840 "\n" \
841 "The delete() function deletes the permission contained in \n" \
842 "the argument perm from the permission set.  An attempt \n" \
843 "to delete a permission that is not contained in the \n" \
844 "permission set is not considered an error.\n" \
845 "Parameters:\n" \
846 "  - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...\n" \
847 "Return value:\n" \
848 "  None\n" \
849 "Can raise: IOError\n" \
850 ;
851
852 static PyObject* Permset_delete(PyObject* obj, PyObject* args) {
853     Permset_Object *self = (Permset_Object*) obj;
854     int right;
855
856     if (!PyArg_ParseTuple(args, "i", &right))
857         return NULL;
858
859     if(acl_delete_perm(self->permset, (acl_perm_t) right) == -1)
860         return PyErr_SetFromErrno(PyExc_IOError);
861
862     /* Return the result */
863     Py_INCREF(Py_None);
864     return Py_None;
865 }
866
867 static char __Permset_test_doc__[] = \
868 "Test if a permission exists in the permission set.\n" \
869 "\n" \
870 "The test() function tests if the permission contained in \n" \
871 "the argument perm exits the permission set.\n" \
872 "Parameters:\n" \
873 "  - perm a permission (ACL_WRITE, ACL_READ, ACL_EXECUTE, ...\n" \
874 "Return value:\n" \
875 "  Bool\n" \
876 "Can raise: IOError\n" \
877 ;
878
879 static PyObject* Permset_test(PyObject* obj, PyObject* args) {
880     Permset_Object *self = (Permset_Object*) obj;
881     int right;
882     int ret;
883
884     if (!PyArg_ParseTuple(args, "i", &right))
885         return NULL;
886
887     ret = get_perm(self->permset, (acl_perm_t) right);
888     if(ret == -1)
889         return PyErr_SetFromErrno(PyExc_IOError);
890
891     if(ret) {
892         Py_INCREF(Py_True);
893         return Py_True;
894     } else {
895         Py_INCREF(Py_False);
896         return Py_False;
897     }
898 }
899
900 #endif
901
902 static char __ACL_Type_doc__[] = \
903 "Type which represents a POSIX ACL\n" \
904 "\n" \
905 "Parameters:\n" \
906 "  Only one keword parameter should be provided:\n"
907 "  - file=\"...\", meaning create ACL representing\n"
908 "    the access ACL of that file\n" \
909 "  - filedef=\"...\", meaning create ACL representing\n"
910 "    the default ACL of that directory\n" \
911 "  - fd=<int>, meaning create ACL representing\n" \
912 "    the access ACL of that file descriptor\n" \
913 "  - text=\"...\", meaning create ACL from a \n" \
914 "    textual description\n" \
915 "  - acl=<ACL instance>, meaning create a copy\n" \
916 "    of an existing ACL instance\n" \
917 "  - mode=<int>, meaning create an ACL from a numeric mode\n"
918 "    (e.g. mode=0644) (this is valid only when the C library\n"
919 "    provides the acl_from_mode call)\n"
920 "If no parameters are passed, create an empty ACL; this\n" \
921 "makes sense only when your OS supports ACL modification\n" \
922 " (i.e. it implements full POSIX.1e support)\n" \
923 ;
924
925 /* ACL type methods */
926 static PyMethodDef ACL_methods[] = {
927     {"applyto", ACL_applyto, METH_VARARGS, __applyto_doc__},
928     {"valid", ACL_valid, METH_NOARGS, __valid_doc__},
929 #ifdef HAVE_LEVEL2
930     {"__getstate__", ACL_get_state, METH_NOARGS,
931      "Dumps the ACL to an external format."},
932     {"__setstate__", ACL_set_state, METH_VARARGS,
933      "Loads the ACL from an external format."},
934     {"delete_entry", ACL_delete_entry, METH_VARARGS, __ACL_delete_entry_doc__},
935     {"calc_mask", ACL_calc_mask, METH_NOARGS, __ACL_calc_mask_doc__},
936     {"append", ACL_append, METH_VARARGS, __ACL_append_doc__},
937 #endif
938     {NULL, NULL, 0, NULL}
939 };
940
941
942 /* The definition of the ACL Type */
943 static PyTypeObject ACL_Type = {
944     PyObject_HEAD_INIT(NULL)
945     0,
946     "posix1e.ACL",
947     sizeof(ACL_Object),
948     0,
949     ACL_dealloc,        /* tp_dealloc */
950     0,                  /* tp_print */
951     0,                  /* tp_getattr */
952     0,                  /* tp_setattr */
953     0,                  /* tp_compare */
954     0,                  /* tp_repr */
955     0,                  /* tp_as_number */
956     0,                  /* tp_as_sequence */
957     0,                  /* tp_as_mapping */
958     0,                  /* tp_hash */
959     0,                  /* tp_call */
960     ACL_str,            /* tp_str */
961     0,                  /* tp_getattro */
962     0,                  /* tp_setattro */
963     0,                  /* tp_as_buffer */
964     Py_TPFLAGS_DEFAULT, /* tp_flags */
965     __ACL_Type_doc__,   /* tp_doc */
966     0,                  /* tp_traverse */
967     0,                  /* tp_clear */
968     0,                  /* tp_richcompare */
969     0,                  /* tp_weaklistoffset */
970 #ifdef HAVE_LEVEL2
971     ACL_iter,
972     ACL_iternext,
973 #else
974     0,                  /* tp_iter */
975     0,                  /* tp_iternext */
976 #endif
977     ACL_methods,        /* tp_methods */
978     0,                  /* tp_members */
979     0,                  /* tp_getset */
980     0,                  /* tp_base */
981     0,                  /* tp_dict */
982     0,                  /* tp_descr_get */
983     0,                  /* tp_descr_set */
984     0,                  /* tp_dictoffset */
985     ACL_init,           /* tp_init */
986     0,                  /* tp_alloc */
987     ACL_new,            /* tp_new */
988 };
989
990 #ifdef HAVE_LEVEL2
991
992 /* Entry type methods */
993 static PyMethodDef Entry_methods[] = {
994     {"copy", Entry_copy, METH_VARARGS, __Entry_copy_doc__},
995     {NULL, NULL, 0, NULL}
996 };
997
998 static char __Entry_tagtype_doc__[] = \
999 "The tag type of the current entry\n" \
1000 "\n" \
1001 "This is one of:\n" \
1002 " - ACL_UNDEFINED_TAG\n" \
1003 " - ACL_USER_OBJ\n" \
1004 " - ACL_USER\n" \
1005 " - ACL_GROUP_OBJ\n" \
1006 " - ACL_GROUP\n" \
1007 " - ACL_MASK\n" \
1008 " - ACL_OTHER\n" \
1009 ;
1010
1011 static char __Entry_qualifier_doc__[] = \
1012 "The qualifier of the current entry\n" \
1013 "\n" \
1014 "If the tag type is ACL_USER, this should be a user id.\n" \
1015 "If the tag type if ACL_GROUP, this should be a group id.\n" \
1016 "Else, it doesn't matter.\n" \
1017 ;
1018
1019 static char __Entry_parent_doc__[] = \
1020 "The parent ACL of this entry\n" \
1021 ;
1022
1023 static char __Entry_permset_doc__[] = \
1024 "The permission set of this ACL entry\n" \
1025 ;
1026
1027 /* Entry getset */
1028 static PyGetSetDef Entry_getsets[] = {
1029     {"tag_type", Entry_get_tag_type, Entry_set_tag_type,
1030      __Entry_tagtype_doc__},
1031     {"qualifier", Entry_get_qualifier, Entry_set_qualifier,
1032      __Entry_qualifier_doc__},
1033     {"parent", Entry_get_parent, NULL, __Entry_parent_doc__},
1034     {"permset", Entry_get_permset, Entry_set_permset, __Entry_permset_doc__},
1035     {NULL}
1036 };
1037
1038 static char __Entry_Type_doc__[] = \
1039 "Type which represents an entry in an ACL.\n" \
1040 "\n" \
1041 "The type exists only if the OS has full support for POSIX.1e\n" \
1042 "Can be created either by:\n" \
1043 "  e = posix1e.Entry(myACL) # this creates a new entry in the ACL\n" \
1044 "or by:\n" \
1045 "  for entry in myACL:\n" \
1046 "      print entry\n" \
1047 "\n" \
1048 "Note that the Entry keeps a reference to its ACL, so even if \n" \
1049 "you delete the ACL, it won't be cleaned up and will continue to \n" \
1050 "exist until its Entry(ies) will be deleted.\n" \
1051 ;
1052 /* The definition of the Entry Type */
1053 static PyTypeObject Entry_Type = {
1054     PyObject_HEAD_INIT(NULL)
1055     0,
1056     "posix1e.Entry",
1057     sizeof(Entry_Object),
1058     0,
1059     Entry_dealloc,      /* tp_dealloc */
1060     0,                  /* tp_print */
1061     0,                  /* tp_getattr */
1062     0,                  /* tp_setattr */
1063     0,                  /* tp_compare */
1064     0,                  /* tp_repr */
1065     0,                  /* tp_as_number */
1066     0,                  /* tp_as_sequence */
1067     0,                  /* tp_as_mapping */
1068     0,                  /* tp_hash */
1069     0,                  /* tp_call */
1070     Entry_str,          /* tp_str */
1071     0,                  /* tp_getattro */
1072     0,                  /* tp_setattro */
1073     0,                  /* tp_as_buffer */
1074     Py_TPFLAGS_DEFAULT, /* tp_flags */
1075     __Entry_Type_doc__, /* tp_doc */
1076     0,                  /* tp_traverse */
1077     0,                  /* tp_clear */
1078     0,                  /* tp_richcompare */
1079     0,                  /* tp_weaklistoffset */
1080     0,                  /* tp_iter */
1081     0,                  /* tp_iternext */
1082     Entry_methods,      /* tp_methods */
1083     0,                  /* tp_members */
1084     Entry_getsets,      /* tp_getset */
1085     0,                  /* tp_base */
1086     0,                  /* tp_dict */
1087     0,                  /* tp_descr_get */
1088     0,                  /* tp_descr_set */
1089     0,                  /* tp_dictoffset */
1090     Entry_init,         /* tp_init */
1091     0,                  /* tp_alloc */
1092     Entry_new,          /* tp_new */
1093 };
1094
1095 /* Permset type methods */
1096 static PyMethodDef Permset_methods[] = {
1097     {"clear", Permset_clear, METH_NOARGS, __Permset_clear_doc__, },
1098     {"add", Permset_add, METH_VARARGS, __Permset_add_doc__, },
1099     {"delete", Permset_delete, METH_VARARGS, __Permset_delete_doc__, },
1100     {"test", Permset_test, METH_VARARGS, __Permset_test_doc__, },
1101     {NULL, NULL, 0, NULL}
1102 };
1103
1104 static char __Permset_execute_doc__[] = \
1105 "Execute permsission\n" \
1106 "\n" \
1107 "This is a convenience method of access; the \n" \
1108 "same effect can be achieved using the functions\n" \
1109 "add(), test(), delete(), and those can take any \n" \
1110 "permission defined by your platform.\n" \
1111 ;
1112
1113 static char __Permset_read_doc__[] = \
1114 "Read permsission\n" \
1115 "\n" \
1116 "This is a convenience method of access; the \n" \
1117 "same effect can be achieved using the functions\n" \
1118 "add(), test(), delete(), and those can take any \n" \
1119 "permission defined by your platform.\n" \
1120 ;
1121
1122 static char __Permset_write_doc__[] = \
1123 "Write permsission\n" \
1124 "\n" \
1125 "This is a convenience method of access; the \n" \
1126 "same effect can be achieved using the functions\n" \
1127 "add(), test(), delete(), and those can take any \n" \
1128 "permission defined by your platform.\n" \
1129 ;
1130
1131 /* Permset getset */
1132 static PyGetSetDef Permset_getsets[] = {
1133     {"execute", Permset_get_right, Permset_set_right, \
1134      __Permset_execute_doc__, &holder_ACL_EXECUTE},
1135     {"read", Permset_get_right, Permset_set_right, \
1136      __Permset_read_doc__, &holder_ACL_READ},
1137     {"write", Permset_get_right, Permset_set_right, \
1138      __Permset_write_doc__, &holder_ACL_WRITE},
1139     {NULL}
1140 };
1141
1142 static char __Permset_Type_doc__[] = \
1143 "Type which represents the permission set in an ACL entry\n" \
1144 "\n" \
1145 "The type exists only if the OS has full support for POSIX.1e\n" \
1146 "Can be created either by:\n" \
1147 "  perms = myEntry.permset\n" \
1148 "or by:\n" \
1149 "  perms = posix1e.Permset(myEntry)\n" \
1150 "\n" \
1151 "Note that the Permset keeps a reference to its Entry, so even if \n" \
1152 "you delete the entry, it won't be cleaned up and will continue to \n" \
1153 "exist until its Permset will be deleted.\n" \
1154 ;
1155
1156 /* The definition of the Permset Type */
1157 static PyTypeObject Permset_Type = {
1158     PyObject_HEAD_INIT(NULL)
1159     0,
1160     "posix1e.Permset",
1161     sizeof(Permset_Object),
1162     0,
1163     Permset_dealloc,    /* tp_dealloc */
1164     0,                  /* tp_print */
1165     0,                  /* tp_getattr */
1166     0,                  /* tp_setattr */
1167     0,                  /* tp_compare */
1168     0,                  /* tp_repr */
1169     0,                  /* tp_as_number */
1170     0,                  /* tp_as_sequence */
1171     0,                  /* tp_as_mapping */
1172     0,                  /* tp_hash */
1173     0,                  /* tp_call */
1174     Permset_str,        /* tp_str */
1175     0,                  /* tp_getattro */
1176     0,                  /* tp_setattro */
1177     0,                  /* tp_as_buffer */
1178     Py_TPFLAGS_DEFAULT, /* tp_flags */
1179     __Permset_Type_doc__,/* tp_doc */
1180     0,                  /* tp_traverse */
1181     0,                  /* tp_clear */
1182     0,                  /* tp_richcompare */
1183     0,                  /* tp_weaklistoffset */
1184     0,                  /* tp_iter */
1185     0,                  /* tp_iternext */
1186     Permset_methods,    /* tp_methods */
1187     0,                  /* tp_members */
1188     Permset_getsets,    /* tp_getset */
1189     0,                  /* tp_base */
1190     0,                  /* tp_dict */
1191     0,                  /* tp_descr_get */
1192     0,                  /* tp_descr_set */
1193     0,                  /* tp_dictoffset */
1194     Permset_init,       /* tp_init */
1195     0,                  /* tp_alloc */
1196     Permset_new,        /* tp_new */
1197 };
1198
1199 #endif
1200
1201 /* Module methods */
1202
1203 static char __deletedef_doc__[] = \
1204 "Delete the default ACL from a directory.\n" \
1205 "\n" \
1206 "This function deletes the default ACL associated with \n" \
1207 "a directory (the ACL which will be ANDed with the mode\n" \
1208 "parameter to the open, creat functions).\n" \
1209 "Parameters:\n" \
1210 "  - a string representing the directory whose default ACL\n" \
1211 "    should be deleted\n" \
1212 ;
1213
1214 /* Deletes the default ACL from a directory */
1215 static PyObject* aclmodule_delete_default(PyObject* obj, PyObject* args) {
1216     char *filename;
1217
1218     /* Parse the arguments */
1219     if (!PyArg_ParseTuple(args, "s", &filename))
1220         return NULL;
1221
1222     if(acl_delete_def_file(filename) == -1) {
1223         return PyErr_SetFromErrno(PyExc_IOError);
1224     }
1225
1226     /* Return the result */
1227     Py_INCREF(Py_None);
1228     return Py_None;
1229 }
1230
1231 /* The module methods */
1232 static PyMethodDef aclmodule_methods[] = {
1233     {"delete_default", aclmodule_delete_default, METH_VARARGS,
1234      __deletedef_doc__},
1235     {NULL, NULL, 0, NULL}
1236 };
1237
1238 static char __posix1e_doc__[] = \
1239 "POSIX.1e ACLs manipulation\n" \
1240 "\n" \
1241 "This module provides support for manipulating POSIX.1e ACLS\n" \
1242 "\n" \
1243 "Depending on the operating system support for POSIX.1e, \n" \
1244 "the ACL type will have more or less capabilities:\n" \
1245 "  - level 1, only basic support, you can create\n" \
1246 "    ACLs from files and text descriptions;\n" \
1247 "    once created, the type is immutable\n" \
1248 "  - level 2, complete support, you can alter\n"\
1249 "    the ACL once it is created\n" \
1250 "\n" \
1251 "Also, in level 2, more types are available, corresponding\n" \
1252 "to acl_entry_t (Entry type), acl_permset_t (Permset type).\n" \
1253 "\n" \
1254 "Example:\n" \
1255 ">>> import posix1e\n" \
1256 ">>> acl1 = posix1e.ACL(file=\"file.txt\") \n" \
1257 ">>> print acl1\n" \
1258 "user::rw-\n" \
1259 "group::rw-\n" \
1260 "other::r--\n" \
1261 "\n" \
1262 ">>> b = posix1e.ACL(text=\"u::rx,g::-,o::-\")\n" \
1263 ">>> print b\n" \
1264 "user::r-x\n" \
1265 "group::---\n" \
1266 "other::---\n" \
1267 "\n" \
1268 ">>> b.applyto(\"file.txt\")\n" \
1269 ">>> print posix1e.ACL(file=\"file.txt\")\n" \
1270 "user::r-x\n" \
1271 "group::---\n" \
1272 "other::---\n" \
1273 "\n" \
1274 ">>>\n" \
1275 ;
1276
1277 void initposix1e(void) {
1278     PyObject *m, *d;
1279
1280     ACL_Type.ob_type = &PyType_Type;
1281     if(PyType_Ready(&ACL_Type) < 0)
1282         return;
1283
1284 #ifdef HAVE_LEVEL2
1285     Entry_Type.ob_type = &PyType_Type;
1286     if(PyType_Ready(&Entry_Type) < 0)
1287         return;
1288
1289     Permset_Type.ob_type = &PyType_Type;
1290     if(PyType_Ready(&Permset_Type) < 0)
1291         return;
1292 #endif
1293
1294     m = Py_InitModule3("posix1e", aclmodule_methods, __posix1e_doc__);
1295
1296     d = PyModule_GetDict(m);
1297     if (d == NULL)
1298         return;
1299
1300     Py_INCREF(&ACL_Type);
1301     if (PyDict_SetItemString(d, "ACL",
1302                              (PyObject *) &ACL_Type) < 0)
1303         return;
1304
1305     /* 23.3.6 acl_type_t values */
1306     PyModule_AddIntConstant(m, "ACL_TYPE_ACCESS", ACL_TYPE_ACCESS);
1307     PyModule_AddIntConstant(m, "ACL_TYPE_DEFAULT", ACL_TYPE_DEFAULT);
1308
1309
1310 #ifdef HAVE_LEVEL2
1311     Py_INCREF(&Entry_Type);
1312     if (PyDict_SetItemString(d, "Entry",
1313                              (PyObject *) &Entry_Type) < 0)
1314         return;
1315
1316     Py_INCREF(&Permset_Type);
1317     if (PyDict_SetItemString(d, "Permset",
1318                              (PyObject *) &Permset_Type) < 0)
1319         return;
1320
1321     /* 23.2.2 acl_perm_t values */
1322     PyModule_AddIntConstant(m, "ACL_READ", ACL_READ);
1323     PyModule_AddIntConstant(m, "ACL_WRITE", ACL_WRITE);
1324     PyModule_AddIntConstant(m, "ACL_EXECUTE", ACL_EXECUTE);
1325
1326     /* 23.2.5 acl_tag_t values */
1327     PyModule_AddIntConstant(m, "ACL_UNDEFINED_TAG", ACL_UNDEFINED_TAG);
1328     PyModule_AddIntConstant(m, "ACL_USER_OBJ", ACL_USER_OBJ);
1329     PyModule_AddIntConstant(m, "ACL_USER", ACL_USER);
1330     PyModule_AddIntConstant(m, "ACL_GROUP_OBJ", ACL_GROUP_OBJ);
1331     PyModule_AddIntConstant(m, "ACL_GROUP", ACL_GROUP);
1332     PyModule_AddIntConstant(m, "ACL_MASK", ACL_MASK);
1333     PyModule_AddIntConstant(m, "ACL_OTHER", ACL_OTHER);
1334
1335 #endif
1336 }