1 /*
2 posix1e - a python module exposing the posix acl functions
3
4 Copyright (C) 2002-2009, 2012 Iustin Pop <iusty@k1024.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA
20
21 */
22
23 #include <Python.h>
24
25 #include <sys/types.h>
26 #include <sys/acl.h>
27
28 #ifdef HAVE_LINUX
29 #include <acl/libacl.h>
30 #define get_perm acl_get_perm
31 #elif HAVE_FREEBSD
32 #define get_perm acl_get_perm_np
33 #endif
34
35 #if PY_MAJOR_VERSION >= 3
36 #define IS_PY3K
37 #define PyInt_Check(op) PyLong_Check(op)
38 #define PyInt_FromString PyLong_FromString
39 #define PyInt_FromUnicode PyLong_FromUnicode
40 #define PyInt_FromLong PyLong_FromLong
41 #define PyInt_FromSize_t PyLong_FromSize_t
42 #define PyInt_FromSsize_t PyLong_FromSsize_t
43 #define PyInt_AsLong PyLong_AsLong
44 #define PyInt_AsSsize_t PyLong_AsSsize_t
45 #define PyInt_AsUnsignedLongMask PyLong_AsUnsignedLongMask
46 #define PyInt_AsUnsignedLongLongMask PyLong_AsUnsignedLongLongMask
47 #define PyInt_AS_LONG PyLong_AS_LONG
48 #define MyString_ConcatAndDel PyUnicode_AppendAndDel
49 #define MyString_FromFormat PyUnicode_FromFormat
50 #define MyString_FromString PyUnicode_FromString
51 #define MyString_FromStringAndSize PyUnicode_FromStringAndSize
52 #else
53 #define PyBytes_Check PyString_Check
54 #define PyBytes_AS_STRING PyString_AS_STRING
55 #define PyBytes_FromStringAndSize PyString_FromStringAndSize
56 #define PyBytes_FromString PyString_FromString
57 #define PyBytes_FromFormat PyString_FromFormat
58 #define PyBytes_ConcatAndDel PyString_ConcatAndDel
59 #define MyString_ConcatAndDel PyBytes_ConcatAndDel
60 #define MyString_FromFormat PyBytes_FromFormat
61 #define MyString_FromString PyBytes_FromString
62 #define MyString_FromStringAndSize PyBytes_FromStringAndSize
63
64 /* Python 2.6 already defines Py_TYPE */
65 #ifndef Py_TYPE
66 #define Py_TYPE(o) (((PyObject*)(o))->ob_type)
67 #endif
68 #endif
69
70 static PyTypeObject ACL_Type;
71 static PyObject* ACL_applyto(PyObject* obj, PyObject* args);
72 static PyObject* ACL_valid(PyObject* obj, PyObject* args);
73
74 #ifdef HAVE_ACL_COPY_EXT
75 static PyObject* ACL_get_state(PyObject *obj, PyObject* args);
76 static PyObject* ACL_set_state(PyObject *obj, PyObject* args);
77 #endif
78
79 #ifdef HAVE_LEVEL2
80 static PyTypeObject Entry_Type;
81 static PyTypeObject Permset_Type;
82 static PyObject* Permset_new(PyTypeObject* type, PyObject* args,
83 PyObject *keywds);
84 #endif
85
86 #ifndef __DragonFly__
87 static acl_perm_t holder_ACL_EXECUTE = ACL_EXECUTE;
88 static acl_perm_t holder_ACL_READ = ACL_READ;
89 static acl_perm_t holder_ACL_WRITE = ACL_WRITE;
90 #endif
91
92 typedef struct {
93 PyObject_HEAD
94 acl_t acl;
95 #ifdef HAVE_LEVEL2
96 int entry_id;
97 #endif
98 } ACL_Object;
99
100 #ifdef HAVE_LEVEL2
101
102 typedef struct {
103 PyObject_HEAD
104 PyObject *parent_acl; /* The parent acl, so it won't run out on us */
105 acl_entry_t entry;
106 } Entry_Object;
107
108 typedef struct {
109 PyObject_HEAD
110 PyObject *parent_entry; /* The parent entry, so it won't run out on us */
111 acl_permset_t permset;
112 } Permset_Object;
113
114 #endif
115
116 /* Creation of a new ACL instance */
ACL_new(PyTypeObject * type,PyObject * args,PyObject * keywds)117 static PyObject* ACL_new(PyTypeObject* type, PyObject* args,
118 PyObject *keywds) {
119 PyObject* newacl;
120
121 newacl = type->tp_alloc(type, 0);
122
123 if(newacl != NULL) {
124 ((ACL_Object*)newacl)->acl = NULL;
125 #ifdef HAVEL_LEVEL2
126 ((ACL_Object*)newacl)->entry_id = ACL_FIRST_ENTRY;
127 #endif
128 }
129
130 return newacl;
131 }
132
133 /* Initialization of a new ACL instance */
ACL_init(PyObject * obj,PyObject * args,PyObject * keywds)134 static int ACL_init(PyObject* obj, PyObject* args, PyObject *keywds) {
135 ACL_Object* self = (ACL_Object*) obj;
136 #ifdef HAVE_LINUX
137 static char *kwlist[] = { "file", "fd", "text", "acl", "filedef",
138 "mode", NULL };
139 char *format = "|etisO!sH";
140 mode_t mode = 0;
141 #else
142 static char *kwlist[] = { "file", "fd", "text", "acl", "filedef", NULL };
143 char *format = "|etisO!s";
144 #endif
145 char *file = NULL;
146 char *filedef = NULL;
147 char *text = NULL;
148 int fd = -1;
149 ACL_Object* thesrc = NULL;
150
151 if(!PyTuple_Check(args) || PyTuple_Size(args) != 0 ||
152 (keywds != NULL && PyDict_Check(keywds) && PyDict_Size(keywds) > 1)) {
153 PyErr_SetString(PyExc_ValueError, "a max of one keyword argument"
154 " must be passed");
155 return -1;
156 }
157 if(!PyArg_ParseTupleAndKeywords(args, keywds, format, kwlist,
158 NULL, &file, &fd, &text, &ACL_Type,
159 &thesrc, &filedef
160 #ifdef HAVE_LINUX
161 , &mode
162 #endif
163 ))
164 return -1;
165
166 /* Free the old acl_t without checking for error, we don't
167 * care right now */
168 if(self->acl != NULL)
169 acl_free(self->acl);
170
171 if(file != NULL)
172 self->acl = acl_get_file(file, ACL_TYPE_ACCESS);
173 else if(text != NULL)
174 self->acl = acl_from_text(text);
175 else if(fd != -1)
176 self->acl = acl_get_fd(fd);
177 else if(thesrc != NULL)
178 self->acl = acl_dup(thesrc->acl);
179 else if(filedef != NULL)
180 self->acl = acl_get_file(filedef, ACL_TYPE_DEFAULT);
181 #ifdef HAVE_LINUX
182 else if(PyMapping_HasKeyString(keywds, kwlist[5]))
183 self->acl = acl_from_mode(mode);
184 #endif
185 else
186 self->acl = acl_init(0);
187
188 if(self->acl == NULL) {
189 PyErr_SetFromErrno(PyExc_IOError);
190 return -1;
191 }
192
193 return 0;
194 }
195
196 /* Standard type functions */
ACL_dealloc(PyObject * obj)197 static void ACL_dealloc(PyObject* obj) {
198 ACL_Object *self = (ACL_Object*) obj;
199 PyObject *err_type, *err_value, *err_traceback;
200 int have_error = PyErr_Occurred() ? 1 : 0;
201
202 if (have_error)
203 PyErr_Fetch(&err_type, &err_value, &err_traceback);
204 if(self->acl != NULL && acl_free(self->acl) != 0)
205 PyErr_WriteUnraisable(obj);
206 if (have_error)
207 PyErr_Restore(err_type, err_value, err_traceback);
208 PyObject_DEL(self);
209 }
210
211 /* Converts the acl to a text format */
ACL_str(PyObject * obj)212 static PyObject* ACL_str(PyObject *obj) {
213 char *text;
214 ACL_Object *self = (ACL_Object*) obj;
215 PyObject *ret;
216
217 text = acl_to_text(self->acl, NULL);
218 if(text == NULL) {
219 return PyErr_SetFromErrno(PyExc_IOError);
220 }
221 ret = MyString_FromString(text);
222 if(acl_free(text) != 0) {
223 Py_XDECREF(ret);
224 return PyErr_SetFromErrno(PyExc_IOError);
225 }
226 return ret;
227 }
228
229 #ifdef HAVE_LINUX
230 static char __to_any_text_doc__[] =
231 "to_any_text([prefix='', separator='n', options=0])\n"
232 "Convert the ACL to a custom text format.\n"
233 "\n"
234 "This method encapsulates the ``acl_to_any_text()`` function.\n"
235 "It allows a customized text format to be generated for the ACL. See\n"
236 ":manpage:`acl_to_any_text(3)` for more details.\n"
237 "\n"
238 ":param string prefix: if given, this string will be pre-pended to\n"
239 " all lines\n"
240 ":param string separator: a single character (defaults to '\\n'); this will"
241 " be used to separate the entries in the ACL\n"
242 ":param options: a bitwise combination of:\n\n"
243 " - :py:data:`TEXT_ABBREVIATE`: use 'u' instead of 'user', 'g' \n"
244 " instead of 'group', etc.\n"
245 " - :py:data:`TEXT_NUMERIC_IDS`: User and group IDs are included as\n"
246 " decimal numbers instead of names\n"
247 " - :py:data:`TEXT_SOME_EFFECTIVE`: Include comments denoting the\n"
248 " effective permissions when some are masked\n"
249 " - :py:data:`TEXT_ALL_EFFECTIVE`: Include comments after all ACL\n"
250 " entries affected by an ACL_MASK entry\n"
251 " - :py:data:`TEXT_SMART_INDENT`: Used in combination with the\n"
252 " _EFFECTIVE options, this will ensure that comments are aligned\n"
253 " to the fourth tab position (assuming one tab equals eight spaces)\n"
254 ":rtype: string\n"
255 ;
256
257 /* Converts the acl to a custom text format */
ACL_to_any_text(PyObject * obj,PyObject * args,PyObject * kwds)258 static PyObject* ACL_to_any_text(PyObject *obj, PyObject *args,
259 PyObject *kwds) {
260 char *text;
261 ACL_Object *self = (ACL_Object*) obj;
262 PyObject *ret;
263 const char *arg_prefix = NULL;
264 char arg_separator = '\n';
265 int arg_options = 0;
266 static char *kwlist[] = {"prefix", "separator", "options", NULL};
267
268 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sci", kwlist, &arg_prefix,
269 &arg_separator, &arg_options))
270 return NULL;
271
272 text = acl_to_any_text(self->acl, arg_prefix, arg_separator, arg_options);
273 if(text == NULL) {
274 return PyErr_SetFromErrno(PyExc_IOError);
275 }
276 ret = PyBytes_FromString(text);
277 if(acl_free(text) != 0) {
278 Py_XDECREF(ret);
279 return PyErr_SetFromErrno(PyExc_IOError);
280 }
281 return ret;
282 }
283
284 static char __check_doc__[] =
285 "Check the ACL validity.\n"
286 "\n"
287 "This is a non-portable, Linux specific extension that allow more\n"
288 "information to be retrieved in case an ACL is not valid than via the\n"
289 ":py:func:`valid` method.\n"
290 "\n"
291 "This method will return either False (the ACL is valid), or a tuple\n"
292 "with two elements. The first element is one of the following\n"
293 "constants:\n\n"
294 " - :py:data:`ACL_MULTI_ERROR`: The ACL contains multiple entries that\n"
295 " have a tag type that may occur at most once\n"
296 " - :py:data:`ACL_DUPLICATE_ERROR`: The ACL contains multiple \n"
297 " :py:data:`ACL_USER` or :py:data:`ACL_GROUP` entries with the\n"
298 " same ID\n"
299 " - :py:data:`ACL_MISS_ERROR`: A required entry is missing\n"
300 " - :py:data:`ACL_ENTRY_ERROR`: The ACL contains an invalid entry\n"
301 " tag type\n"
302 "\n"
303 "The second element of the tuple is the index of the entry that is\n"
304 "invalid (in the same order as by iterating over the ACL entry)\n"
305 ;
306
307 /* The acl_check method */
ACL_check(PyObject * obj,PyObject * args)308 static PyObject* ACL_check(PyObject* obj, PyObject* args) {
309 ACL_Object *self = (ACL_Object*) obj;
310 int result;
311 int eindex;
312
313 if((result = acl_check(self->acl, &eindex)) == -1)
314 return PyErr_SetFromErrno(PyExc_IOError);
315 if(result == 0) {
316 Py_RETURN_FALSE;
317 }
318 return Py_BuildValue("(ii)", result, eindex);
319 }
320
321 /* Implementation of the rich compare for ACLs */
ACL_richcompare(PyObject * o1,PyObject * o2,int op)322 static PyObject* ACL_richcompare(PyObject* o1, PyObject* o2, int op) {
323 ACL_Object *acl1, *acl2;
324 int n;
325 PyObject *ret;
326
327 if(!PyObject_IsInstance(o2, (PyObject*)&ACL_Type)) {
328 if(op == Py_EQ)
329 Py_RETURN_FALSE;
330 if(op == Py_NE)
331 Py_RETURN_TRUE;
332 PyErr_SetString(PyExc_TypeError, "can only compare to an ACL");
333 return NULL;
334 }
335
336 acl1 = (ACL_Object*)o1;
337 acl2 = (ACL_Object*)o2;
338 if((n=acl_cmp(acl1->acl, acl2->acl))==-1)
339 return PyErr_SetFromErrno(PyExc_IOError);
340 switch(op) {
341 case Py_EQ:
342 ret = n == 0 ? Py_True : Py_False;
343 break;
344 case Py_NE:
345 ret = n == 1 ? Py_True : Py_False;
346 break;
347 default:
348 ret = Py_NotImplemented;
349 }
350 Py_INCREF(ret);
351 return ret;
352 }
353
354 static char __equiv_mode_doc__[] =
355 "Return the octal mode the ACL is equivalent to.\n"
356 "\n"
357 "This is a non-portable, Linux specific extension that checks\n"
358 "if the ACL is a basic ACL and returns the corresponding mode.\n"
359 "\n"
360 ":rtype: integer\n"
361 ":raise IOError: An IOerror exception will be raised if the ACL is\n"
362 " an extended ACL.\n"
363 ;
364
365 /* The acl_equiv_mode method */
ACL_equiv_mode(PyObject * obj,PyObject * args)366 static PyObject* ACL_equiv_mode(PyObject* obj, PyObject* args) {
367 ACL_Object *self = (ACL_Object*) obj;
368 mode_t mode;
369
370 if(acl_equiv_mode(self->acl, &mode) == -1)
371 return PyErr_SetFromErrno(PyExc_IOError);
372 return PyInt_FromLong(mode);
373 }
374 #endif
375
376 /* Implementation of the compare for ACLs */
ACL_nocmp(PyObject * o1,PyObject * o2)377 static int ACL_nocmp(PyObject* o1, PyObject* o2) {
378
379 PyErr_SetString(PyExc_TypeError, "cannot compare ACLs using cmp()");
380 return -1;
381 }
382
383 /* Custom methods */
384 static char __applyto_doc__[] =
385 "applyto(item[, flag=ACL_TYPE_ACCESS])\n"
386 "Apply the ACL to a file or filehandle.\n"
387 "\n"
388 ":param item: either a filename or a file-like object or an integer;\n"
389 " this represents the filesystem object on which to act\n"
390 ":param flag: optional flag representing the type of ACL to set, either\n"
391 " :py:data:`ACL_TYPE_ACCESS` (default) or :py:data:`ACL_TYPE_DEFAULT`\n"
392 ;
393
394 /* Applies the ACL to a file */
ACL_applyto(PyObject * obj,PyObject * args)395 static PyObject* ACL_applyto(PyObject* obj, PyObject* args) {
396 ACL_Object *self = (ACL_Object*) obj;
397 PyObject *myarg;
398 acl_type_t type = ACL_TYPE_ACCESS;
399 int nret;
400 int fd;
401
402 if (!PyArg_ParseTuple(args, "O|I", &myarg, &type))
403 return NULL;
404
405 if(PyBytes_Check(myarg)) {
406 char *filename = PyBytes_AS_STRING(myarg);
407 nret = acl_set_file(filename, type, self->acl);
408 } else if (PyUnicode_Check(myarg)) {
409 PyObject *o =
410 PyUnicode_AsEncodedString(myarg,
411 Py_FileSystemDefaultEncoding, "strict");
412 if (o == NULL)
413 return NULL;
414 const char *filename = PyBytes_AS_STRING(o);
415 nret = acl_set_file(filename, type, self->acl);
416 Py_DECREF(o);
417 } else if((fd = PyObject_AsFileDescriptor(myarg)) != -1) {
418 nret = acl_set_fd(fd, self->acl);
419 } else {
420 PyErr_SetString(PyExc_TypeError, "argument 1 must be string, int,"
421 " or file-like object");
422 return 0;
423 }
424 if(nret == -1) {
425 return PyErr_SetFromErrno(PyExc_IOError);
426 }
427
428 /* Return the result */
429 Py_INCREF(Py_None);
430 return Py_None;
431 }
432
433 static char __valid_doc__[] =
434 "Test the ACL for validity.\n"
435 "\n"
436 "This method tests the ACL to see if it is a valid ACL\n"
437 "in terms of the file-system. More precisely, it checks that:\n"
438 "\n"
439 "The ACL contains exactly one entry with each of the\n"
440 ":py:data:`ACL_USER_OBJ`, :py:data:`ACL_GROUP_OBJ`, and \n"
441 ":py:data:`ACL_OTHER` tag types. Entries\n"
442 "with :py:data:`ACL_USER` and :py:data:`ACL_GROUP` tag types may\n"
443 "appear zero or more\n"
444 "times in an ACL. An ACL that contains entries of :py:data:`ACL_USER` or\n"
445 ":py:data:`ACL_GROUP` tag types must contain exactly one entry of the \n"
446 ":py:data:`ACL_MASK` tag type. If an ACL contains no entries of\n"
447 ":py:data:`ACL_USER` or :py:data:`ACL_GROUP` tag types, the\n"
448 ":py:data:`ACL_MASK` entry is optional.\n"
449 "\n"
450 "All user ID qualifiers must be unique among all entries of\n"
451 "the :py:data:`ACL_USER` tag type, and all group IDs must be unique\n"
452 "among all entries of :py:data:`ACL_GROUP` tag type.\n"
453 "\n"
454 "The method will return 1 for a valid ACL and 0 for an invalid one.\n"
455 "This has been chosen because the specification for\n"
456 ":manpage:`acl_valid(3)`\n"
457 "in the POSIX.1e standard documents only one possible value for errno\n"
458 "in case of an invalid ACL, so we can't differentiate between\n"
459 "classes of errors. Other suggestions are welcome.\n"
460 "\n"
461 ":return: 0 or 1\n"
462 ":rtype: integer\n"
463 ;
464
465 /* Checks the ACL for validity */
ACL_valid(PyObject * obj,PyObject * args)466 static PyObject* ACL_valid(PyObject* obj, PyObject* args) {
467 ACL_Object *self = (ACL_Object*) obj;
468
469 if(acl_valid(self->acl) == -1) {
470 Py_RETURN_FALSE;
471 } else {
472 Py_RETURN_TRUE;
473 }
474 }
475
476 #ifdef HAVE_ACL_COPY_EXT
ACL_get_state(PyObject * obj,PyObject * args)477 static PyObject* ACL_get_state(PyObject *obj, PyObject* args) {
478 ACL_Object *self = (ACL_Object*) obj;
479 PyObject *ret;
480 ssize_t size, nsize;
481 char *buf;
482
483 size = acl_size(self->acl);
484 if(size == -1)
485 return PyErr_SetFromErrno(PyExc_IOError);
486
487 if((ret = PyBytes_FromStringAndSize(NULL, size)) == NULL)
488 return NULL;
489 buf = PyBytes_AsString(ret);
490
491 if((nsize = acl_copy_ext(buf, self->acl, size)) == -1) {
492 Py_DECREF(ret);
493 return PyErr_SetFromErrno(PyExc_IOError);
494 }
495
496 return ret;
497 }
498
ACL_set_state(PyObject * obj,PyObject * args)499 static PyObject* ACL_set_state(PyObject *obj, PyObject* args) {
500 ACL_Object *self = (ACL_Object*) obj;
501 const void *buf;
502 int bufsize;
503 acl_t ptr;
504
505 /* Parse the argument */
506 if (!PyArg_ParseTuple(args, "s#", &buf, &bufsize))
507 return NULL;
508
509 /* Try to import the external representation */
510 if((ptr = acl_copy_int(buf)) == NULL)
511 return PyErr_SetFromErrno(PyExc_IOError);
512
513 /* Free the old acl. Should we ignore errors here? */
514 if(self->acl != NULL) {
515 if(acl_free(self->acl) == -1)
516 return PyErr_SetFromErrno(PyExc_IOError);
517 }
518
519 self->acl = ptr;
520
521 /* Return the result */
522 Py_INCREF(Py_None);
523 return Py_None;
524 }
525 #endif
526
527 #ifdef HAVE_LEVEL2
528
529 /* tp_iter for the ACL type; since it can be iterated only
530 * destructively, the type is its iterator
531 */
ACL_iter(PyObject * obj)532 static PyObject* ACL_iter(PyObject *obj) {
533 ACL_Object *self = (ACL_Object*)obj;
534 self->entry_id = ACL_FIRST_ENTRY;
535 Py_INCREF(obj);
536 return obj;
537 }
538
539 /* the tp_iternext function for the ACL type */
ACL_iternext(PyObject * obj)540 static PyObject* ACL_iternext(PyObject *obj) {
541 ACL_Object *self = (ACL_Object*)obj;
542 acl_entry_t the_entry_t;
543 Entry_Object *the_entry_obj;
544 int nerr;
545
546 nerr = acl_get_entry(self->acl, self->entry_id, &the_entry_t);
547 self->entry_id = ACL_NEXT_ENTRY;
548 if(nerr == -1)
549 return PyErr_SetFromErrno(PyExc_IOError);
550 else if(nerr == 0) {
551 /* Docs says this is not needed */
552 /*PyErr_SetObject(PyExc_StopIteration, Py_None);*/
553 return NULL;
554 }
555
556 the_entry_obj = (Entry_Object*) PyType_GenericNew(&Entry_Type, NULL, NULL);
557 if(the_entry_obj == NULL)
558 return NULL;
559
560 the_entry_obj->entry = the_entry_t;
561
562 the_entry_obj->parent_acl = obj;
563 Py_INCREF(obj); /* For the reference we have in entry->parent */
564
565 return (PyObject*)the_entry_obj;
566 }
567
568 static char __ACL_delete_entry_doc__[] =
569 "delete_entry(entry)\n"
570 "Deletes an entry from the ACL.\n"
571 "\n"
572 ".. note:: Only available with level 2.\n"
573 "\n"
574 ":param entry: the Entry object which should be deleted; note that after\n"
575 " this function is called, that object is unusable any longer\n"
576 " and should be deleted\n"
577 ;
578
579 /* Deletes an entry from the ACL */
ACL_delete_entry(PyObject * obj,PyObject * args)580 static PyObject* ACL_delete_entry(PyObject *obj, PyObject *args) {
581 ACL_Object *self = (ACL_Object*)obj;
582 Entry_Object *e;
583
584 if (!PyArg_ParseTuple(args, "O!", &Entry_Type, &e))
585 return NULL;
586
587 if(acl_delete_entry(self->acl, e->entry) == -1)
588 return PyErr_SetFromErrno(PyExc_IOError);
589
590 /* Return the result */
591 Py_INCREF(Py_None);
592 return Py_None;
593 }
594
595 static char __ACL_calc_mask_doc__[] =
596 "Compute the file group class mask.\n"
597 "\n"
598 "The calc_mask() method calculates and sets the permissions \n"
599 "associated with the :py:data:`ACL_MASK` Entry of the ACL.\n"
600 "The value of the new permissions is the union of the permissions \n"
601 "granted by all entries of tag type :py:data:`ACL_GROUP`, \n"
602 ":py:data:`ACL_GROUP_OBJ`, or \n"
603 ":py:data:`ACL_USER`. If the ACL already contains an :py:data:`ACL_MASK`\n"
604 "entry, its \n"
605 "permissions are overwritten; if it does not contain an \n"
606 ":py:data:`ACL_MASK` Entry, one is added.\n"
607 "\n"
608 "The order of existing entries in the ACL is undefined after this \n"
609 "function.\n"
610 ;
611
612 /* Updates the mask entry in the ACL */
ACL_calc_mask(PyObject * obj,PyObject * args)613 static PyObject* ACL_calc_mask(PyObject *obj, PyObject *args) {
614 ACL_Object *self = (ACL_Object*)obj;
615
616 if(acl_calc_mask(&self->acl) == -1)
617 return PyErr_SetFromErrno(PyExc_IOError);
618
619 /* Return the result */
620 Py_INCREF(Py_None);
621 return Py_None;
622 }
623
624 static char __ACL_append_doc__[] =
625 "append([entry])\n"
626 "Append a new Entry to the ACL and return it.\n"
627 "\n"
628 "This is a convenience function to create a new Entry \n"
629 "and append it to the ACL.\n"
630 "If a parameter of type Entry instance is given, the \n"
631 "entry will be a copy of that one (as if copied with \n"
632 ":py:func:`Entry.copy`), otherwise, the new entry will be empty.\n"
633 "\n"
634 ":rtype: :py:class:`Entry`\n"
635 ":returns: the newly created entry\n"
636 ;
637
638 /* Convenience method to create a new Entry */
ACL_append(PyObject * obj,PyObject * args)639 static PyObject* ACL_append(PyObject *obj, PyObject *args) {
640 ACL_Object* self = (ACL_Object*) obj;
641 Entry_Object* newentry;
642 Entry_Object* oldentry = NULL;
643 int nret;
644
645 newentry = (Entry_Object*)PyType_GenericNew(&Entry_Type, NULL, NULL);
646 if(newentry == NULL) {
647 return NULL;
648 }
649
650 if (!PyArg_ParseTuple(args, "|O!", &Entry_Type, &oldentry)) {
651 Py_DECREF(newentry);
652 return NULL;
653 }
654
655 nret = acl_create_entry(&self->acl, &newentry->entry);
656 if(nret == -1) {
657 Py_DECREF(newentry);
658 return PyErr_SetFromErrno(PyExc_IOError);
659 }
660
661 if(oldentry != NULL) {
662 nret = acl_copy_entry(newentry->entry, oldentry->entry);
663 if(nret == -1) {
664 Py_DECREF(newentry);
665 return PyErr_SetFromErrno(PyExc_IOError);
666 }
667 }
668
669 newentry->parent_acl = obj;
670 Py_INCREF(obj);
671
672 return (PyObject*)newentry;
673 }
674
675 /***** Entry type *****/
676
677 /* Creation of a new Entry instance */
Entry_new(PyTypeObject * type,PyObject * args,PyObject * keywds)678 static PyObject* Entry_new(PyTypeObject* type, PyObject* args,
679 PyObject *keywds) {
680 PyObject* newentry;
681
682 newentry = PyType_GenericNew(type, args, keywds);
683
684 if(newentry != NULL) {
685 ((Entry_Object*)newentry)->entry = NULL;
686 ((Entry_Object*)newentry)->parent_acl = NULL;
687 }
688
689 return newentry;
690 }
691
692 /* Initialization of a new Entry instance */
Entry_init(PyObject * obj,PyObject * args,PyObject * keywds)693 static int Entry_init(PyObject* obj, PyObject* args, PyObject *keywds) {
694 Entry_Object* self = (Entry_Object*) obj;
695 ACL_Object* parent = NULL;
696
697 if (!PyArg_ParseTuple(args, "O!", &ACL_Type, &parent))
698 return -1;
699
700 if(acl_create_entry(&parent->acl, &self->entry) == -1) {
701 PyErr_SetFromErrno(PyExc_IOError);
702 return -1;
703 }
704
705 self->parent_acl = (PyObject*)parent;
706 Py_INCREF(parent);
707
708 return 0;
709 }
710
711 /* Free the Entry instance */
Entry_dealloc(PyObject * obj)712 static void Entry_dealloc(PyObject* obj) {
713 Entry_Object *self = (Entry_Object*) obj;
714 PyObject *err_type, *err_value, *err_traceback;
715 int have_error = PyErr_Occurred() ? 1 : 0;
716
717 if (have_error)
718 PyErr_Fetch(&err_type, &err_value, &err_traceback);
719 if(self->parent_acl != NULL) {
720 Py_DECREF(self->parent_acl);
721 self->parent_acl = NULL;
722 }
723 if (have_error)
724 PyErr_Restore(err_type, err_value, err_traceback);
725 PyObject_DEL(self);
726 }
727
728 /* Converts the entry to a text format */
Entry_str(PyObject * obj)729 static PyObject* Entry_str(PyObject *obj) {
730 acl_tag_t tag;
731 uid_t qualifier;
732 void *p;
733 PyObject *format, *kind;
734 Entry_Object *self = (Entry_Object*) obj;
735
736 if(acl_get_tag_type(self->entry, &tag) == -1) {
737 PyErr_SetFromErrno(PyExc_IOError);
738 return NULL;
739 }
740 if(tag == ACL_USER || tag == ACL_GROUP) {
741 if((p = acl_get_qualifier(self->entry)) == NULL) {
742 PyErr_SetFromErrno(PyExc_IOError);
743 return NULL;
744 }
745 qualifier = *(uid_t*)p;
746 acl_free(p);
747 } else {
748 qualifier = 0;
749 }
750
751 format = MyString_FromString("ACL entry for ");
752 if(format == NULL)
753 return NULL;
754 switch(tag) {
755 case ACL_UNDEFINED_TAG:
756 kind = MyString_FromString("undefined type");
757 break;
758 case ACL_USER_OBJ:
759 kind = MyString_FromString("the owner");
760 break;
761 case ACL_GROUP_OBJ:
762 kind = MyString_FromString("the group");
763 break;
764 case ACL_OTHER:
765 kind = MyString_FromString("the others");
766 break;
767 case ACL_USER:
768 kind = MyString_FromFormat("user with uid %d", qualifier);
769 break;
770 case ACL_GROUP:
771 kind = MyString_FromFormat("group with gid %d", qualifier);
772 break;
773 case ACL_MASK:
774 kind = MyString_FromString("the mask");
775 break;
776 default:
777 kind = MyString_FromString("UNKNOWN_TAG_TYPE!");
778 break;
779 }
780 if (kind == NULL) {
781 Py_DECREF(format);
782 return NULL;
783 }
784 MyString_ConcatAndDel(&format, kind);
785 return format;
786 }
787
788 /* Sets the tag type of the entry */
Entry_set_tag_type(PyObject * obj,PyObject * value,void * arg)789 static int Entry_set_tag_type(PyObject* obj, PyObject* value, void* arg) {
790 Entry_Object *self = (Entry_Object*) obj;
791
792 if(value == NULL) {
793 PyErr_SetString(PyExc_TypeError,
794 "tag type deletion is not supported");
795 return -1;
796 }
797
798 if(!PyInt_Check(value)) {
799 PyErr_SetString(PyExc_TypeError,
800 "tag type must be integer");
801 return -1;
802 }
803 if(acl_set_tag_type(self->entry, (acl_tag_t)PyInt_AsLong(value)) == -1) {
804 PyErr_SetFromErrno(PyExc_IOError);
805 return -1;
806 }
807
808 return 0;
809 }
810
811 /* Returns the tag type of the entry */
Entry_get_tag_type(PyObject * obj,void * arg)812 static PyObject* Entry_get_tag_type(PyObject *obj, void* arg) {
813 Entry_Object *self = (Entry_Object*) obj;
814 acl_tag_t value;
815
816 if (self->entry == NULL) {
817 PyErr_SetString(PyExc_AttributeError, "entry attribute");
818 return NULL;
819 }
820 if(acl_get_tag_type(self->entry, &value) == -1) {
821 PyErr_SetFromErrno(PyExc_IOError);
822 return NULL;
823 }
824
825 return PyInt_FromLong(value);
826 }
827
828 /* Sets the qualifier (either uid_t or gid_t) for the entry,
829 * usable only if the tag type if ACL_USER or ACL_GROUP
830 */
Entry_set_qualifier(PyObject * obj,PyObject * value,void * arg)831 static int Entry_set_qualifier(PyObject* obj, PyObject* value, void* arg) {
832 Entry_Object *self = (Entry_Object*) obj;
833 int uidgid;
834
835 if(value == NULL) {
836 PyErr_SetString(PyExc_TypeError,
837 "qualifier deletion is not supported");
838 return -1;
839 }
840
841 if(!PyInt_Check(value)) {
842 PyErr_SetString(PyExc_TypeError,
843 "tag type must be integer");
844 return -1;
845 }
846 uidgid = PyInt_AsLong(value);
847 if(acl_set_qualifier(self->entry, (void*)&uidgid) == -1) {
848 PyErr_SetFromErrno(PyExc_IOError);
849 return -1;
850 }
851
852 return 0;
853 }
854
855 /* Returns the qualifier of the entry */
Entry_get_qualifier(PyObject * obj,void * arg)856 static PyObject* Entry_get_qualifier(PyObject *obj, void* arg) {
857 Entry_Object *self = (Entry_Object*) obj;
858 void *p;
859 int value;
860
861 if (self->entry == NULL) {
862 PyErr_SetString(PyExc_AttributeError, "entry attribute");
863 return NULL;
864 }
865 if((p = acl_get_qualifier(self->entry)) == NULL) {
866 PyErr_SetFromErrno(PyExc_IOError);
867 return NULL;
868 }
869 value = *(uid_t*)p;
870 acl_free(p);
871
872 return PyInt_FromLong(value);
873 }
874
875 /* Returns the parent ACL of the entry */
Entry_get_parent(PyObject * obj,void * arg)876 static PyObject* Entry_get_parent(PyObject *obj, void* arg) {
877 Entry_Object *self = (Entry_Object*) obj;
878
879 Py_INCREF(self->parent_acl);
880 return self->parent_acl;
881 }
882
883 /* Returns the a new Permset representing the permset of the entry
884 * FIXME: Should return a new reference to the same object, which
885 * should be created at init time!
886 */
Entry_get_permset(PyObject * obj,void * arg)887 static PyObject* Entry_get_permset(PyObject *obj, void* arg) {
888 Entry_Object *self = (Entry_Object*)obj;
889 PyObject *p;
890 Permset_Object *ps;
891
892 p = Permset_new(&Permset_Type, NULL, NULL);
893 if(p == NULL)
894 return NULL;
895 ps = (Permset_Object*)p;
896 if(acl_get_permset(self->entry, &ps->permset) == -1) {
897 PyErr_SetFromErrno(PyExc_IOError);
898 Py_DECREF(p);
899 return NULL;
900 }
901 ps->parent_entry = obj;
902 Py_INCREF(obj);
903
904 return (PyObject*)p;
905 }
906
907 /* Sets the permset of the entry to the passed Permset */
Entry_set_permset(PyObject * obj,PyObject * value,void * arg)908 static int Entry_set_permset(PyObject* obj, PyObject* value, void* arg) {
909 Entry_Object *self = (Entry_Object*)obj;
910 Permset_Object *p;
911
912 if(!PyObject_IsInstance(value, (PyObject*)&Permset_Type)) {
913 PyErr_SetString(PyExc_TypeError, "argument 1 must be posix1e.Permset");
914 return -1;
915 }
916 p = (Permset_Object*)value;
917 if(acl_set_permset(self->entry, p->permset) == -1) {
918 PyErr_SetFromErrno(PyExc_IOError);
919 return -1;
920 }
921 return 0;
922 }
923
924 static char __Entry_copy_doc__[] =
925 "copy(src)\n"
926 "Copies an ACL entry.\n"
927 "\n"
928 "This method sets all the parameters to those of another\n"
929 "entry (either of the same ACL or belonging to another ACL).\n"
930 "\n"
931 ":param Entry src: instance of type Entry\n"
932 ;
933
934 /* Sets all the entry parameters to another entry */
Entry_copy(PyObject * obj,PyObject * args)935 static PyObject* Entry_copy(PyObject *obj, PyObject *args) {
936 Entry_Object *self = (Entry_Object*)obj;
937 Entry_Object *other;
938
939 if(!PyArg_ParseTuple(args, "O!", &Entry_Type, &other))
940 return NULL;
941
942 if(acl_copy_entry(self->entry, other->entry) == -1)
943 return PyErr_SetFromErrno(PyExc_IOError);
944
945 Py_INCREF(Py_None);
946 return Py_None;
947 }
948
949 /**** Permset type *****/
950
951 /* Creation of a new Permset instance */
Permset_new(PyTypeObject * type,PyObject * args,PyObject * keywds)952 static PyObject* Permset_new(PyTypeObject* type, PyObject* args,
953 PyObject *keywds) {
954 PyObject* newpermset;
955
956 newpermset = PyType_GenericNew(type, args, keywds);
957
958 if(newpermset != NULL) {
959 ((Permset_Object*)newpermset)->permset = NULL;
960 ((Permset_Object*)newpermset)->parent_entry = NULL;
961 }
962
963 return newpermset;
964 }
965
966 /* Initialization of a new Permset instance */
Permset_init(PyObject * obj,PyObject * args,PyObject * keywds)967 static int Permset_init(PyObject* obj, PyObject* args, PyObject *keywds) {
968 Permset_Object* self = (Permset_Object*) obj;
969 Entry_Object* parent = NULL;
970
971 if (!PyArg_ParseTuple(args, "O!", &Entry_Type, &parent))
972 return -1;
973
974 if(acl_get_permset(parent->entry, &self->permset) == -1) {
975 PyErr_SetFromErrno(PyExc_IOError);
976 return -1;
977 }
978
979 self->parent_entry = (PyObject*)parent;
980 Py_INCREF(parent);
981
982 return 0;
983 }
984
985 /* Free the Permset instance */
Permset_dealloc(PyObject * obj)986 static void Permset_dealloc(PyObject* obj) {
987 Permset_Object *self = (Permset_Object*) obj;
988 PyObject *err_type, *err_value, *err_traceback;
989 int have_error = PyErr_Occurred() ? 1 : 0;
990
991 if (have_error)
992 PyErr_Fetch(&err_type, &err_value, &err_traceback);
993 if(self->parent_entry != NULL) {
994 Py_DECREF(self->parent_entry);
995 self->parent_entry = NULL;
996 }
997 if (have_error)
998 PyErr_Restore(err_type, err_value, err_traceback);
999 PyObject_DEL(self);
1000 }
1001
1002 /* Permset string representation */
Permset_str(PyObject * obj)1003 static PyObject* Permset_str(PyObject *obj) {
1004 Permset_Object *self = (Permset_Object*) obj;
1005 char pstr[3];
1006
1007 pstr[0] = get_perm(self->permset, ACL_READ) ? 'r' : '-';
1008 pstr[1] = get_perm(self->permset, ACL_WRITE) ? 'w' : '-';
1009 pstr[2] = get_perm(self->permset, ACL_EXECUTE) ? 'x' : '-';
1010 return MyString_FromStringAndSize(pstr, 3);
1011 }
1012
1013 static char __Permset_clear_doc__[] =
1014 "Clears all permissions from the permission set.\n"
1015 ;
1016
1017 /* Clears all permissions from the permset */
Permset_clear(PyObject * obj,PyObject * args)1018 static PyObject* Permset_clear(PyObject* obj, PyObject* args) {
1019 Permset_Object *self = (Permset_Object*) obj;
1020
1021 if(acl_clear_perms(self->permset) == -1)
1022 return PyErr_SetFromErrno(PyExc_IOError);
1023
1024 /* Return the result */
1025 Py_INCREF(Py_None);
1026 return Py_None;
1027 }
1028
Permset_get_right(PyObject * obj,void * arg)1029 static PyObject* Permset_get_right(PyObject *obj, void* arg) {
1030 Permset_Object *self = (Permset_Object*) obj;
1031
1032 if(get_perm(self->permset, *(acl_perm_t*)arg)) {
1033 Py_RETURN_TRUE;
1034 } else {
1035 Py_RETURN_FALSE;
1036 }
1037 }
1038
Permset_set_right(PyObject * obj,PyObject * value,void * arg)1039 static int Permset_set_right(PyObject* obj, PyObject* value, void* arg) {
1040 Permset_Object *self = (Permset_Object*) obj;
1041 int on;
1042 int nerr;
1043
1044 if(!PyInt_Check(value)) {
1045 PyErr_SetString(PyExc_ValueError, "a maximum of one argument must"
1046 " be passed");
1047 return -1;
1048 }
1049 on = PyInt_AsLong(value);
1050 if(on)
1051 nerr = acl_add_perm(self->permset, *(acl_perm_t*)arg);
1052 else
1053 nerr = acl_delete_perm(self->permset, *(acl_perm_t*)arg);
1054 if(nerr == -1) {
1055 PyErr_SetFromErrno(PyExc_IOError);
1056 return -1;
1057 }
1058 return 0;
1059 }
1060
1061 static char __Permset_add_doc__[] =
1062 "add(perm)\n"
1063 "Add a permission to the permission set.\n"
1064 "\n"
1065 "This function adds the permission contained in \n"
1066 "the argument perm to the permission set. An attempt \n"
1067 "to add a permission that is already contained in the \n"
1068 "permission set is not considered an error.\n"
1069 "\n"
1070 ":param perm: a permission (:py:data:`ACL_WRITE`, :py:data:`ACL_READ`,\n"
1071 " :py:data:`ACL_EXECUTE`, ...)\n"
1072 ":raises IOError: in case the argument is not a valid descriptor\n"
1073 ;
1074
Permset_add(PyObject * obj,PyObject * args)1075 static PyObject* Permset_add(PyObject* obj, PyObject* args) {
1076 Permset_Object *self = (Permset_Object*) obj;
1077 int right;
1078
1079 if (!PyArg_ParseTuple(args, "i", &right))
1080 return NULL;
1081
1082 if(acl_add_perm(self->permset, (acl_perm_t) right) == -1)
1083 return PyErr_SetFromErrno(PyExc_IOError);
1084
1085 /* Return the result */
1086 Py_INCREF(Py_None);
1087 return Py_None;
1088 }
1089
1090 static char __Permset_delete_doc__[] =
1091 "delete(perm)\n"
1092 "Delete a permission from the permission set.\n"
1093 "\n"
1094 "This function deletes the permission contained in \n"
1095 "the argument perm from the permission set. An attempt \n"
1096 "to delete a permission that is not contained in the \n"
1097 "permission set is not considered an error.\n"
1098 "\n"
1099 ":param perm: a permission (:py:data:`ACL_WRITE`, :py:data:`ACL_READ`,\n"
1100 " :py:data:`ACL_EXECUTE`, ...)\n"
1101 ":raises IOError: in case the argument is not a valid descriptor\n"
1102 ;
1103
Permset_delete(PyObject * obj,PyObject * args)1104 static PyObject* Permset_delete(PyObject* obj, PyObject* args) {
1105 Permset_Object *self = (Permset_Object*) obj;
1106 int right;
1107
1108 if (!PyArg_ParseTuple(args, "i", &right))
1109 return NULL;
1110
1111 if(acl_delete_perm(self->permset, (acl_perm_t) right) == -1)
1112 return PyErr_SetFromErrno(PyExc_IOError);
1113
1114 /* Return the result */
1115 Py_INCREF(Py_None);
1116 return Py_None;
1117 }
1118
1119 static char __Permset_test_doc__[] =
1120 "test(perm)\n"
1121 "Test if a permission exists in the permission set.\n"
1122 "\n"
1123 "The test() function tests if the permission represented by\n"
1124 "the argument perm exists in the permission set.\n"
1125 "\n"
1126 ":param perm: a permission (:py:data:`ACL_WRITE`, :py:data:`ACL_READ`,\n"
1127 " :py:data:`ACL_EXECUTE`, ...)\n"
1128 ":rtype: Boolean\n"
1129 ":raises IOError: in case the argument is not a valid descriptor\n"
1130 ;
1131
Permset_test(PyObject * obj,PyObject * args)1132 static PyObject* Permset_test(PyObject* obj, PyObject* args) {
1133 Permset_Object *self = (Permset_Object*) obj;
1134 int right;
1135 int ret;
1136
1137 if (!PyArg_ParseTuple(args, "i", &right))
1138 return NULL;
1139
1140 ret = get_perm(self->permset, (acl_perm_t) right);
1141 if(ret == -1)
1142 return PyErr_SetFromErrno(PyExc_IOError);
1143
1144 if(ret) {
1145 Py_RETURN_TRUE;
1146 } else {
1147 Py_RETURN_FALSE;
1148 }
1149 }
1150
1151 #endif
1152
1153 static char __ACL_Type_doc__[] =
1154 "Type which represents a POSIX ACL\n"
1155 "\n"
1156 ".. note:: only one keyword parameter should be provided\n"
1157 "\n"
1158 ":param string file: creates an ACL representing\n"
1159 " the access ACL of the specified file\n"
1160 ":param string filedef: creates an ACL representing\n"
1161 " the default ACL of the given directory\n"
1162 ":param int fd: creates an ACL representing\n"
1163 " the access ACL of the given file descriptor\n"
1164 ":param string text: creates an ACL from a \n"
1165 " textual description\n"
1166 ":param ACL acl: creates a copy of an existing ACL instance\n"
1167 ":param int mode: creates an ACL from a numeric mode\n"
1168 " (e.g. mode=0644) (this is valid only when the C library\n"
1169 " provides the acl_from_mode call)\n"
1170 "\n"
1171 "If no parameters are passed, an empty ACL will be created; this\n"
1172 "makes sense only when your OS supports ACL modification\n"
1173 "(i.e. it implements full POSIX.1e support), otherwise the ACL won't\n"
1174 "be useful.\n"
1175 ;
1176
1177 /* ACL type methods */
1178 static PyMethodDef ACL_methods[] = {
1179 {"applyto", ACL_applyto, METH_VARARGS, __applyto_doc__},
1180 {"valid", ACL_valid, METH_NOARGS, __valid_doc__},
1181 #ifdef HAVE_LINUX
1182 {"to_any_text", (PyCFunction)ACL_to_any_text, METH_VARARGS | METH_KEYWORDS,
1183 __to_any_text_doc__},
1184 {"check", ACL_check, METH_NOARGS, __check_doc__},
1185 {"equiv_mode", ACL_equiv_mode, METH_NOARGS, __equiv_mode_doc__},
1186 #endif
1187 #ifdef HAVE_ACL_COPYEXT
1188 {"__getstate__", ACL_get_state, METH_NOARGS,
1189 "Dumps the ACL to an external format."},
1190 {"__setstate__", ACL_set_state, METH_VARARGS,
1191 "Loads the ACL from an external format."},
1192 #endif
1193 #ifdef HAVE_LEVEL2
1194 {"delete_entry", ACL_delete_entry, METH_VARARGS, __ACL_delete_entry_doc__},
1195 {"calc_mask", ACL_calc_mask, METH_NOARGS, __ACL_calc_mask_doc__},
1196 {"append", ACL_append, METH_VARARGS, __ACL_append_doc__},
1197 #endif
1198 {NULL, NULL, 0, NULL}
1199 };
1200
1201
1202 /* The definition of the ACL Type */
1203 static PyTypeObject ACL_Type = {
1204 #ifdef IS_PY3K
1205 PyVarObject_HEAD_INIT(NULL, 0)
1206 #else
1207 PyObject_HEAD_INIT(NULL)
1208 0,
1209 #endif
1210 "posix1e.ACL",
1211 sizeof(ACL_Object),
1212 0,
1213 ACL_dealloc, /* tp_dealloc */
1214 0, /* tp_print */
1215 0, /* tp_getattr */
1216 0, /* tp_setattr */
1217 ACL_nocmp, /* tp_compare */
1218 0, /* tp_repr */
1219 0, /* tp_as_number */
1220 0, /* tp_as_sequence */
1221 0, /* tp_as_mapping */
1222 0, /* tp_hash */
1223 0, /* tp_call */
1224 ACL_str, /* tp_str */
1225 0, /* tp_getattro */
1226 0, /* tp_setattro */
1227 0, /* tp_as_buffer */
1228 Py_TPFLAGS_DEFAULT, /* tp_flags */
1229 __ACL_Type_doc__, /* tp_doc */
1230 0, /* tp_traverse */
1231 0, /* tp_clear */
1232 #ifdef HAVE_LINUX
1233 ACL_richcompare, /* tp_richcompare */
1234 #else
1235 0, /* tp_richcompare */
1236 #endif
1237 0, /* tp_weaklistoffset */
1238 #ifdef HAVE_LEVEL2
1239 ACL_iter,
1240 ACL_iternext,
1241 #else
1242 0, /* tp_iter */
1243 0, /* tp_iternext */
1244 #endif
1245 ACL_methods, /* tp_methods */
1246 0, /* tp_members */
1247 0, /* tp_getset */
1248 0, /* tp_base */
1249 0, /* tp_dict */
1250 0, /* tp_descr_get */
1251 0, /* tp_descr_set */
1252 0, /* tp_dictoffset */
1253 ACL_init, /* tp_init */
1254 0, /* tp_alloc */
1255 ACL_new, /* tp_new */
1256 };
1257
1258 #ifdef HAVE_LEVEL2
1259
1260 /* Entry type methods */
1261 static PyMethodDef Entry_methods[] = {
1262 {"copy", Entry_copy, METH_VARARGS, __Entry_copy_doc__},
1263 {NULL, NULL, 0, NULL}
1264 };
1265
1266 static char __Entry_tagtype_doc__[] =
1267 "The tag type of the current entry\n"
1268 "\n"
1269 "This is one of:\n"
1270 " - :py:data:`ACL_UNDEFINED_TAG`\n"
1271 " - :py:data:`ACL_USER_OBJ`\n"
1272 " - :py:data:`ACL_USER`\n"
1273 " - :py:data:`ACL_GROUP_OBJ`\n"
1274 " - :py:data:`ACL_GROUP`\n"
1275 " - :py:data:`ACL_MASK`\n"
1276 " - :py:data:`ACL_OTHER`\n"
1277 ;
1278
1279 static char __Entry_qualifier_doc__[] =
1280 "The qualifier of the current entry\n"
1281 "\n"
1282 "If the tag type is :py:data:`ACL_USER`, this should be a user id.\n"
1283 "If the tag type if :py:data:`ACL_GROUP`, this should be a group id.\n"
1284 "Else it doesn't matter.\n"
1285 ;
1286
1287 static char __Entry_parent_doc__[] =
1288 "The parent ACL of this entry\n"
1289 ;
1290
1291 static char __Entry_permset_doc__[] =
1292 "The permission set of this ACL entry\n"
1293 ;
1294
1295 /* Entry getset */
1296 static PyGetSetDef Entry_getsets[] = {
1297 {"tag_type", Entry_get_tag_type, Entry_set_tag_type,
1298 __Entry_tagtype_doc__},
1299 {"qualifier", Entry_get_qualifier, Entry_set_qualifier,
1300 __Entry_qualifier_doc__},
1301 {"parent", Entry_get_parent, NULL, __Entry_parent_doc__},
1302 {"permset", Entry_get_permset, Entry_set_permset, __Entry_permset_doc__},
1303 {NULL}
1304 };
1305
1306 static char __Entry_Type_doc__[] =
1307 "Type which represents an entry in an ACL.\n"
1308 "\n"
1309 "The type exists only if the OS has full support for POSIX.1e\n"
1310 "Can be created either by:\n"
1311 "\n"
1312 " >>> e = posix1e.Entry(myACL) # this creates a new entry in the ACL\n"
1313 " >>> e = myACL.append() # another way for doing the same thing\n"
1314 "\n"
1315 "or by:\n"
1316 "\n"
1317 " >>> for entry in myACL:\n"
1318 " ... print entry\n"
1319 "\n"
1320 "Note that the Entry keeps a reference to its ACL, so even if \n"
1321 "you delete the ACL, it won't be cleaned up and will continue to \n"
1322 "exist until its Entry(ies) will be deleted.\n"
1323 ;
1324 /* The definition of the Entry Type */
1325 static PyTypeObject Entry_Type = {
1326 #ifdef IS_PY3K
1327 PyVarObject_HEAD_INIT(NULL, 0)
1328 #else
1329 PyObject_HEAD_INIT(NULL)
1330 0,
1331 #endif
1332 "posix1e.Entry",
1333 sizeof(Entry_Object),
1334 0,
1335 Entry_dealloc, /* tp_dealloc */
1336 0, /* tp_print */
1337 0, /* tp_getattr */
1338 0, /* tp_setattr */
1339 0, /* tp_compare */
1340 0, /* tp_repr */
1341 0, /* tp_as_number */
1342 0, /* tp_as_sequence */
1343 0, /* tp_as_mapping */
1344 0, /* tp_hash */
1345 0, /* tp_call */
1346 Entry_str, /* tp_str */
1347 0, /* tp_getattro */
1348 0, /* tp_setattro */
1349 0, /* tp_as_buffer */
1350 Py_TPFLAGS_DEFAULT, /* tp_flags */
1351 __Entry_Type_doc__, /* tp_doc */
1352 0, /* tp_traverse */
1353 0, /* tp_clear */
1354 0, /* tp_richcompare */
1355 0, /* tp_weaklistoffset */
1356 0, /* tp_iter */
1357 0, /* tp_iternext */
1358 Entry_methods, /* tp_methods */
1359 0, /* tp_members */
1360 Entry_getsets, /* tp_getset */
1361 0, /* tp_base */
1362 0, /* tp_dict */
1363 0, /* tp_descr_get */
1364 0, /* tp_descr_set */
1365 0, /* tp_dictoffset */
1366 Entry_init, /* tp_init */
1367 0, /* tp_alloc */
1368 Entry_new, /* tp_new */
1369 };
1370
1371 /* Permset type methods */
1372 static PyMethodDef Permset_methods[] = {
1373 {"clear", Permset_clear, METH_NOARGS, __Permset_clear_doc__, },
1374 {"add", Permset_add, METH_VARARGS, __Permset_add_doc__, },
1375 {"delete", Permset_delete, METH_VARARGS, __Permset_delete_doc__, },
1376 {"test", Permset_test, METH_VARARGS, __Permset_test_doc__, },
1377 {NULL, NULL, 0, NULL}
1378 };
1379
1380 static char __Permset_execute_doc__[] =
1381 "Execute permission property\n"
1382 "\n"
1383 "This is a convenience method of retrieving and setting the execute\n"
1384 "permission in the permission set; the \n"
1385 "same effect can be achieved using the functions\n"
1386 "add(), test(), delete(), and those can take any \n"
1387 "permission defined by your platform.\n"
1388 ;
1389
1390 static char __Permset_read_doc__[] =
1391 "Read permission property\n"
1392 "\n"
1393 "This is a convenience method of retrieving and setting the read\n"
1394 "permission in the permission set; the \n"
1395 "same effect can be achieved using the functions\n"
1396 "add(), test(), delete(), and those can take any \n"
1397 "permission defined by your platform.\n"
1398 ;
1399
1400 static char __Permset_write_doc__[] =
1401 "Write permission property\n"
1402 "\n"
1403 "This is a convenience method of retrieving and setting the write\n"
1404 "permission in the permission set; the \n"
1405 "same effect can be achieved using the functions\n"
1406 "add(), test(), delete(), and those can take any \n"
1407 "permission defined by your platform.\n"
1408 ;
1409
1410 /* Permset getset */
1411 static PyGetSetDef Permset_getsets[] = {
1412 {"execute", Permset_get_right, Permset_set_right,
1413 __Permset_execute_doc__, &holder_ACL_EXECUTE},
1414 {"read", Permset_get_right, Permset_set_right,
1415 __Permset_read_doc__, &holder_ACL_READ},
1416 {"write", Permset_get_right, Permset_set_right,
1417 __Permset_write_doc__, &holder_ACL_WRITE},
1418 {NULL}
1419 };
1420
1421 static char __Permset_Type_doc__[] =
1422 "Type which represents the permission set in an ACL entry\n"
1423 "\n"
1424 "The type exists only if the OS has full support for POSIX.1e\n"
1425 "Can be retrieved either by:\n\n"
1426 ">>> perms = myEntry.permset\n"
1427 "\n"
1428 "or by:\n\n"
1429 ">>> perms = posix1e.Permset(myEntry)\n"
1430 "\n"
1431 "Note that the Permset keeps a reference to its Entry, so even if \n"
1432 "you delete the entry, it won't be cleaned up and will continue to \n"
1433 "exist until its Permset will be deleted.\n"
1434 ;
1435
1436 /* The definition of the Permset Type */
1437 static PyTypeObject Permset_Type = {
1438 #ifdef IS_PY3K
1439 PyVarObject_HEAD_INIT(NULL, 0)
1440 #else
1441 PyObject_HEAD_INIT(NULL)
1442 0,
1443 #endif
1444 "posix1e.Permset",
1445 sizeof(Permset_Object),
1446 0,
1447 Permset_dealloc, /* tp_dealloc */
1448 0, /* tp_print */
1449 0, /* tp_getattr */
1450 0, /* tp_setattr */
1451 0, /* tp_compare */
1452 0, /* tp_repr */
1453 0, /* tp_as_number */
1454 0, /* tp_as_sequence */
1455 0, /* tp_as_mapping */
1456 0, /* tp_hash */
1457 0, /* tp_call */
1458 Permset_str, /* tp_str */
1459 0, /* tp_getattro */
1460 0, /* tp_setattro */
1461 0, /* tp_as_buffer */
1462 Py_TPFLAGS_DEFAULT, /* tp_flags */
1463 __Permset_Type_doc__,/* tp_doc */
1464 0, /* tp_traverse */
1465 0, /* tp_clear */
1466 0, /* tp_richcompare */
1467 0, /* tp_weaklistoffset */
1468 0, /* tp_iter */
1469 0, /* tp_iternext */
1470 Permset_methods, /* tp_methods */
1471 0, /* tp_members */
1472 Permset_getsets, /* tp_getset */
1473 0, /* tp_base */
1474 0, /* tp_dict */
1475 0, /* tp_descr_get */
1476 0, /* tp_descr_set */
1477 0, /* tp_dictoffset */
1478 Permset_init, /* tp_init */
1479 0, /* tp_alloc */
1480 Permset_new, /* tp_new */
1481 };
1482
1483 #endif
1484
1485 /* Module methods */
1486
1487 static char __deletedef_doc__[] =
1488 "delete_default(path)\n"
1489 "Delete the default ACL from a directory.\n"
1490 "\n"
1491 "This function deletes the default ACL associated with\n"
1492 "a directory (the ACL which will be ANDed with the mode\n"
1493 "parameter to the open, creat functions).\n"
1494 "\n"
1495 ":param string path: the directory whose default ACL should be deleted\n"
1496 ;
1497
1498 /* Deletes the default ACL from a directory */
aclmodule_delete_default(PyObject * obj,PyObject * args)1499 static PyObject* aclmodule_delete_default(PyObject* obj, PyObject* args) {
1500 char *filename;
1501
1502 /* Parse the arguments */
1503 if (!PyArg_ParseTuple(args, "et", NULL, &filename))
1504 return NULL;
1505
1506 if(acl_delete_def_file(filename) == -1) {
1507 return PyErr_SetFromErrno(PyExc_IOError);
1508 }
1509
1510 /* Return the result */
1511 Py_INCREF(Py_None);
1512 return Py_None;
1513 }
1514
1515 #ifdef HAVE_LINUX
1516 static char __has_extended_doc__[] =
1517 "has_extended(item)\n"
1518 "Check if a file or file handle has an extended ACL.\n"
1519 "\n"
1520 ":param item: either a file name or a file-like object or an integer;\n"
1521 " it represents the file-system object on which to act\n"
1522 ;
1523
1524 /* Check for extended ACL a file or fd */
aclmodule_has_extended(PyObject * obj,PyObject * args)1525 static PyObject* aclmodule_has_extended(PyObject* obj, PyObject* args) {
1526 PyObject *myarg;
1527 int nret;
1528 int fd;
1529
1530 if (!PyArg_ParseTuple(args, "O", &myarg))
1531 return NULL;
1532
1533 if(PyBytes_Check(myarg)) {
1534 const char *filename = PyBytes_AS_STRING(myarg);
1535 nret = acl_extended_file(filename);
1536 } else if (PyUnicode_Check(myarg)) {
1537 PyObject *o =
1538 PyUnicode_AsEncodedString(myarg,
1539 Py_FileSystemDefaultEncoding, "strict");
1540 if (o == NULL)
1541 return NULL;
1542 const char *filename = PyBytes_AS_STRING(o);
1543 nret = acl_extended_file(filename);
1544 Py_DECREF(o);
1545 } else if((fd = PyObject_AsFileDescriptor(myarg)) != -1) {
1546 nret = acl_extended_fd(fd);
1547 } else {
1548 PyErr_SetString(PyExc_TypeError, "argument 1 must be string, int,"
1549 " or file-like object");
1550 return 0;
1551 }
1552 if(nret == -1) {
1553 return PyErr_SetFromErrno(PyExc_IOError);
1554 }
1555
1556 /* Return the result */
1557 return PyBool_FromLong(nret);
1558 }
1559 #endif
1560
1561 /* The module methods */
1562 static PyMethodDef aclmodule_methods[] = {
1563 {"delete_default", aclmodule_delete_default, METH_VARARGS,
1564 __deletedef_doc__},
1565 #ifdef HAVE_LINUX
1566 {"has_extended", aclmodule_has_extended, METH_VARARGS,
1567 __has_extended_doc__},
1568 #endif
1569 {NULL, NULL, 0, NULL}
1570 };
1571
1572 static char __posix1e_doc__[] =
1573 "POSIX.1e ACLs manipulation\n"
1574 "==========================\n"
1575 "\n"
1576 "This module provides support for manipulating POSIX.1e ACLS\n"
1577 "\n"
1578 "Depending on the operating system support for POSIX.1e, \n"
1579 "the ACL type will have more or less capabilities:\n\n"
1580 " - level 1, only basic support, you can create\n"
1581 " ACLs from files and text descriptions;\n"
1582 " once created, the type is immutable\n"
1583 " - level 2, complete support, you can alter\n"
1584 " the ACL once it is created\n"
1585 "\n"
1586 "Also, in level 2, more types are available, corresponding\n"
1587 "to acl_entry_t (the Entry type), acl_permset_t (the Permset type).\n"
1588 "\n"
1589 "The existence of level 2 support and other extensions can be\n"
1590 "checked by the constants:\n\n"
1591 " - :py:data:`HAS_ACL_ENTRY` for level 2 and the Entry/Permset classes\n"
1592 " - :py:data:`HAS_ACL_FROM_MODE` for ``ACL(mode=...)`` usage\n"
1593 " - :py:data:`HAS_ACL_CHECK` for the :py:func:`ACL.check` function\n"
1594 " - :py:data:`HAS_EXTENDED_CHECK` for the module-level\n"
1595 " :py:func:`has_extended` function\n"
1596 " - :py:data:`HAS_EQUIV_MODE` for the :py:func:`ACL.equiv_mode` method\n"
1597 "\n"
1598 "Example:\n"
1599 "\n"
1600 ">>> import posix1e\n"
1601 ">>> acl1 = posix1e.ACL(file=\"file.txt\") \n"
1602 ">>> print acl1\n"
1603 "user::rw-\n"
1604 "group::rw-\n"
1605 "other::r--\n"
1606 ">>>\n"
1607 ">>> b = posix1e.ACL(text=\"u::rx,g::-,o::-\")\n"
1608 ">>> print b\n"
1609 "user::r-x\n"
1610 "group::---\n"
1611 "other::---\n"
1612 ">>>\n"
1613 ">>> b.applyto(\"file.txt\")\n"
1614 ">>> print posix1e.ACL(file=\"file.txt\")\n"
1615 "user::r-x\n"
1616 "group::---\n"
1617 "other::---\n"
1618 ">>>\n"
1619 "\n"
1620 ".. py:data:: ACL_USER\n\n"
1621 " Denotes a specific user entry in an ACL.\n"
1622 "\n"
1623 ".. py:data:: ACL_USER_OBJ\n\n"
1624 " Denotes the user owner entry in an ACL.\n"
1625 "\n"
1626 ".. py:data:: ACL_GROUP\n\n"
1627 " Denotes the a group entry in an ACL.\n"
1628 "\n"
1629 ".. py:data:: ACL_GROUP_OBJ\n\n"
1630 " Denotes the group owner entry in an ACL.\n"
1631 "\n"
1632 ".. py:data:: ACL_OTHER\n\n"
1633 " Denotes the 'others' entry in an ACL.\n"
1634 "\n"
1635 ".. py:data:: ACL_MASK\n\n"
1636 " Denotes the mask entry in an ACL, representing the maximum\n"
1637 " access granted other users, the owner group and other groups.\n"
1638 "\n"
1639 ".. py:data:: ACL_UNDEFINED_TAG\n\n"
1640 " An undefined tag in an ACL.\n"
1641 "\n"
1642 ".. py:data:: ACL_READ\n\n"
1643 " Read permission in a permission set.\n"
1644 "\n"
1645 ".. py:data:: ACL_WRITE\n\n"
1646 " Write permission in a permission set.\n"
1647 "\n"
1648 ".. py:data:: ACL_EXECUTE\n\n"
1649 " Execute permission in a permission set.\n"
1650 "\n"
1651 ".. py:data:: HAS_ACL_ENTRY\n\n"
1652 " denotes support for level 2 and the Entry/Permset classes\n"
1653 "\n"
1654 ".. py:data:: HAS_ACL_FROM_MODE\n\n"
1655 " denotes support for building an ACL from an octal mode\n"
1656 "\n"
1657 ".. py:data:: HAS_ACL_CHECK\n\n"
1658 " denotes support for extended checks of an ACL's validity\n"
1659 "\n"
1660 ".. py:data:: HAS_EXTENDED_CHECK\n\n"
1661 " denotes support for checking whether an ACL is basic or extended\n"
1662 "\n"
1663 ".. py:data:: HAS_EQUIV_MODE\n\n"
1664 " denotes support for the equiv_mode function\n"
1665 "\n"
1666 ;
1667
1668 #ifdef IS_PY3K
1669
1670 static struct PyModuleDef posix1emodule = {
1671 PyModuleDef_HEAD_INIT,
1672 "posix1e",
1673 __posix1e_doc__,
1674 0,
1675 aclmodule_methods,
1676 };
1677
1678 #define INITERROR return NULL
1679
1680 PyMODINIT_FUNC
PyInit_posix1e(void)1681 PyInit_posix1e(void)
1682
1683 #else
1684 #define INITERROR return
1685
1686 void initposix1e(void)
1687 #endif
1688 {
1689 PyObject *m, *d;
1690
1691 Py_TYPE(&ACL_Type) = &PyType_Type;
1692 if(PyType_Ready(&ACL_Type) < 0)
1693 INITERROR;
1694
1695 #ifdef HAVE_LEVEL2
1696 Py_TYPE(&Entry_Type) = &PyType_Type;
1697 if(PyType_Ready(&Entry_Type) < 0)
1698 INITERROR;
1699
1700 Py_TYPE(&Permset_Type) = &PyType_Type;
1701 if(PyType_Ready(&Permset_Type) < 0)
1702 INITERROR;
1703 #endif
1704
1705 #ifdef IS_PY3K
1706 m = PyModule_Create(&posix1emodule);
1707 #else
1708 m = Py_InitModule3("posix1e", aclmodule_methods, __posix1e_doc__);
1709 #endif
1710 if (m==NULL)
1711 INITERROR;
1712
1713 d = PyModule_GetDict(m);
1714 if (d == NULL)
1715 INITERROR;
1716
1717 Py_INCREF(&ACL_Type);
1718 if (PyDict_SetItemString(d, "ACL",
1719 (PyObject *) &ACL_Type) < 0)
1720 INITERROR;
1721
1722 /* 23.3.6 acl_type_t values */
1723 PyModule_AddIntConstant(m, "ACL_TYPE_ACCESS", ACL_TYPE_ACCESS);
1724 PyModule_AddIntConstant(m, "ACL_TYPE_DEFAULT", ACL_TYPE_DEFAULT);
1725
1726
1727 #ifdef HAVE_LEVEL2
1728 Py_INCREF(&Entry_Type);
1729 if (PyDict_SetItemString(d, "Entry",
1730 (PyObject *) &Entry_Type) < 0)
1731 INITERROR;
1732
1733 Py_INCREF(&Permset_Type);
1734 if (PyDict_SetItemString(d, "Permset",
1735 (PyObject *) &Permset_Type) < 0)
1736 INITERROR;
1737
1738 /* 23.2.2 acl_perm_t values */
1739 PyModule_AddIntConstant(m, "ACL_READ", ACL_READ);
1740 PyModule_AddIntConstant(m, "ACL_WRITE", ACL_WRITE);
1741 PyModule_AddIntConstant(m, "ACL_EXECUTE", ACL_EXECUTE);
1742
1743 /* 23.2.5 acl_tag_t values */
1744 PyModule_AddIntConstant(m, "ACL_UNDEFINED_TAG", ACL_UNDEFINED_TAG);
1745 PyModule_AddIntConstant(m, "ACL_USER_OBJ", ACL_USER_OBJ);
1746 PyModule_AddIntConstant(m, "ACL_USER", ACL_USER);
1747 PyModule_AddIntConstant(m, "ACL_GROUP_OBJ", ACL_GROUP_OBJ);
1748 PyModule_AddIntConstant(m, "ACL_GROUP", ACL_GROUP);
1749 PyModule_AddIntConstant(m, "ACL_MASK", ACL_MASK);
1750 PyModule_AddIntConstant(m, "ACL_OTHER", ACL_OTHER);
1751
1752 /* Document extended functionality via easy-to-use constants */
1753 PyModule_AddIntConstant(m, "HAS_ACL_ENTRY", 1);
1754 #else
1755 PyModule_AddIntConstant(m, "HAS_ACL_ENTRY", 0);
1756 #endif
1757
1758 #ifdef HAVE_LINUX
1759 /* Linux libacl specific acl_to_any_text constants */
1760 PyModule_AddIntConstant(m, "TEXT_ABBREVIATE", TEXT_ABBREVIATE);
1761 PyModule_AddIntConstant(m, "TEXT_NUMERIC_IDS", TEXT_NUMERIC_IDS);
1762 PyModule_AddIntConstant(m, "TEXT_SOME_EFFECTIVE", TEXT_SOME_EFFECTIVE);
1763 PyModule_AddIntConstant(m, "TEXT_ALL_EFFECTIVE", TEXT_ALL_EFFECTIVE);
1764 PyModule_AddIntConstant(m, "TEXT_SMART_INDENT", TEXT_SMART_INDENT);
1765
1766 /* Linux libacl specific acl_check constants */
1767 PyModule_AddIntConstant(m, "ACL_MULTI_ERROR", ACL_MULTI_ERROR);
1768 PyModule_AddIntConstant(m, "ACL_DUPLICATE_ERROR", ACL_DUPLICATE_ERROR);
1769 PyModule_AddIntConstant(m, "ACL_MISS_ERROR", ACL_MISS_ERROR);
1770 PyModule_AddIntConstant(m, "ACL_ENTRY_ERROR", ACL_ENTRY_ERROR);
1771
1772 /* declare the Linux extensions */
1773 PyModule_AddIntConstant(m, "HAS_ACL_FROM_MODE", 1);
1774 PyModule_AddIntConstant(m, "HAS_ACL_CHECK", 1);
1775 PyModule_AddIntConstant(m, "HAS_EXTENDED_CHECK", 1);
1776 PyModule_AddIntConstant(m, "HAS_EQUIV_MODE", 1);
1777 #else
1778 PyModule_AddIntConstant(m, "HAS_ACL_FROM_MODE", 0);
1779 PyModule_AddIntConstant(m, "HAS_ACL_CHECK", 0);
1780 PyModule_AddIntConstant(m, "HAS_EXTENDED_CHECK", 0);
1781 PyModule_AddIntConstant(m, "HAS_EQUIV_MODE", 0);
1782 #endif
1783
1784 #ifdef IS_PY3K
1785 return m;
1786 #endif
1787 }
1788