]> git.k1024.org Git - pylibacl.git/blob - acl.c
Moved to real instance creation via type()
[pylibacl.git] / acl.c
1 #include <sys/types.h>
2 #include <sys/acl.h>
3
4 #include <Python.h>
5
6 staticforward PyTypeObject ACLType;
7 static PyObject* ACL_applyto(PyObject* obj, PyObject* args);
8 static PyObject* ACL_valid(PyObject* obj, PyObject* args);
9 #ifdef HAVE_LEVEL2
10 static PyObject* ACL_get_state(PyObject *obj, PyObject* args);
11 static PyObject* ACL_set_state(PyObject *obj, PyObject* args);
12 #endif
13
14 typedef struct {
15     PyObject_HEAD
16     acl_t ob_acl;
17 } ACLObject;
18
19 /* Creation of a new ACL instance */
20 static PyObject* ACL_new(PyTypeObject* type, PyObject* args, PyObject *keywds) {
21     PyObject* newacl;
22
23     newacl = type->tp_alloc(type, 0);
24
25     if(newacl != NULL)
26         ((ACLObject*)newacl)->ob_acl = NULL;
27
28     return newacl;
29 }
30
31 /* Initialization of a new ACL instance */
32 static int ACL_init(PyObject* obj, PyObject* args, PyObject *keywds) {
33     ACLObject* self = (ACLObject*) obj;
34     static char *kwlist[] = { "file", "fd", "text", "acl", NULL };
35     char *file = NULL;
36     char *text = NULL;
37     int fd = -1;
38     ACLObject* thesrc = NULL;
39     int tmp;
40
41     if (!PyArg_ParseTupleAndKeywords(args, keywds, "|sisO!", kwlist,
42                                      &file, &fd, &text, &ACLType, &thesrc))
43         return -1;
44     tmp = 0;
45     if(file != NULL)
46         tmp++;
47     if(text != NULL)
48         tmp++;
49     if(fd != -1)
50         tmp++;
51     if(thesrc != NULL)
52         tmp++;
53     if(tmp > 1) {
54         PyErr_SetString(PyExc_ValueError, "a maximum of one argument must be passed");
55         return -1;
56     }
57
58     if(file != NULL)
59         self->ob_acl = acl_get_file(file, ACL_TYPE_ACCESS);
60     else if(text != NULL)
61         self->ob_acl = acl_from_text(text);
62     else if(fd != -1)
63         self->ob_acl = acl_get_fd(fd);
64     else if(thesrc != NULL)
65         self->ob_acl = acl_dup(thesrc->ob_acl);
66     else
67         self->ob_acl = acl_init(0);
68     if(self->ob_acl == NULL) {
69         PyErr_SetFromErrno(PyExc_IOError);
70         return -1;
71     }
72
73     return 0;
74 }
75
76 /* Standard type functions */
77 static void ACL_dealloc(PyObject* obj) {
78     ACLObject *self = (ACLObject*) obj;
79     PyObject *err_type, *err_value, *err_traceback;
80     int have_error = PyErr_Occurred() ? 1 : 0;
81
82     if (have_error)
83         PyErr_Fetch(&err_type, &err_value, &err_traceback);
84     if(acl_free(self->ob_acl) != 0)
85         PyErr_WriteUnraisable(obj);
86     if (have_error)
87         PyErr_Restore(err_type, err_value, err_traceback);
88     PyObject_DEL(self);
89 }
90
91 /* Converts the acl to a text format */
92 static PyObject* ACL_repr(PyObject *obj) {
93     char *text;
94     ACLObject *self = (ACLObject*) obj;
95     PyObject *ret;
96
97     text = acl_to_text(self->ob_acl, NULL);
98     if(text == NULL) {
99         return PyErr_SetFromErrno(PyExc_IOError);
100     }
101     ret = PyString_FromString(text);
102     if(acl_free(text) != 0) {
103         Py_DECREF(ret);
104         return PyErr_SetFromErrno(PyExc_IOError);
105     }
106     return ret;
107 }
108
109 /* Custom methods */
110 static char __applyto_doc__[] = \
111 "Apply the ACL to a file or filehandle.\n" \
112 "\n" \
113 "Parameters:\n" \
114 "  - either a filename or a file-like object or an integer; this\n" \
115 "    represents the filesystem object on which to act\n" \
116 ;
117
118 /* Applyes the ACL to a file */
119 static PyObject* ACL_applyto(PyObject* obj, PyObject* args) {
120     ACLObject *self = (ACLObject*) obj;
121     PyObject *myarg;
122     int type_default = 0;
123     acl_type_t type = ACL_TYPE_ACCESS;
124     int nret;
125     int fd;
126
127     if (!PyArg_ParseTuple(args, "O|i", &myarg, &type_default))
128         return NULL;
129     if(type_default)
130         type = ACL_TYPE_DEFAULT;
131
132     if(PyString_Check(myarg)) {
133         char *filename = PyString_AS_STRING(myarg);
134         nret = acl_set_file(filename, type, self->ob_acl);
135     } else if((fd = PyObject_AsFileDescriptor(myarg)) != -1) {
136         nret = acl_set_fd(fd, self->ob_acl);
137     } else {
138         PyErr_SetString(PyExc_TypeError, "argument 1 must be string, int, or file-like object");
139         return 0;
140     }
141     if(nret == -1) {
142         return PyErr_SetFromErrno(PyExc_IOError);
143     }
144
145     /* Return the result */
146     Py_INCREF(Py_None);
147     return Py_None;
148 }
149
150 static char __valid_doc__[] = \
151 "Test the ACL for validity.\n" \
152 "\n" \
153 "This method tests the ACL to see if it is a valid ACL\n" \
154 "in terms of the filesystem. More precisely, it checks:\n" \
155 "A valid ACL contains exactly one entry with each of the ACL_USER_OBJ,\n" \
156 "ACL_GROUP_OBJ, and ACL_OTHER tag types. Entries with ACL_USER and\n" \
157 "ACL_GROUP tag types may appear zero or more times in an ACL. An ACL that\n" \
158 "contains entries of ACL_USER or ACL_GROUP tag types must contain exactly\n" \
159 "one entry of the ACL_MASK tag type. If an ACL contains no entries of\n" \
160 "ACL_USER or ACL_GROUP tag types, the ACL_MASK entry is optional.\n" \
161 "\n" \
162 "All user ID qualifiers must be unique among all entries of ACL_USER tag\n" \
163 "type, and all group IDs must be unique among all entries of ACL_GROUP tag\n" \
164 "type." \
165 ;
166 /* Checks the ACL for validity */
167 static PyObject* ACL_valid(PyObject* obj, PyObject* args) {
168     ACLObject *self = (ACLObject*) obj;
169
170     if(acl_valid(self->ob_acl) == -1) {
171         return PyErr_SetFromErrno(PyExc_IOError);
172     }
173
174     /* Return the result */
175     Py_INCREF(Py_None);
176     return Py_None;
177 }
178
179 #ifdef HAVE_LEVEL2
180
181 static PyObject* ACL_get_state(PyObject *obj, PyObject* args) {
182     ACLObject *self = (ACLObject*) obj;
183     PyObject *ret;
184     ssize_t size, nsize;
185     char *buf;
186
187     size = acl_size(self->ob_acl);
188     if(size == -1)
189         return PyErr_SetFromErrno(PyExc_IOError);
190
191     if((ret = PyString_FromStringAndSize(NULL, size)) == NULL)
192         return NULL;
193     buf = PyString_AsString(ret);
194     
195     if((nsize = acl_copy_ext(buf, self->ob_acl, size)) == -1) {
196         Py_DECREF(ret);
197         return PyErr_SetFromErrno(PyExc_IOError);
198     }
199     
200     return ret;
201 }
202
203 static PyObject* ACL_set_state(PyObject *obj, PyObject* args) {
204     ACLObject *self = (ACLObject*) obj;
205     const void *buf;
206     int bufsize;
207     acl_t ptr;
208
209     /* Parse the argument */
210     if (!PyArg_ParseTuple(args, "s#", &buf, &bufsize))
211         return NULL;
212
213     /* Try to import the external representation */
214     if((ptr = acl_copy_int(buf)) == NULL)
215         return PyErr_SetFromErrno(PyExc_IOError);
216         
217     /* Free the old acl. Should we ignore errors here? */
218     if(self->ob_acl != NULL) {
219         if(acl_free(self->ob_acl) == -1)
220             return PyErr_SetFromErrno(PyExc_IOError);
221     }
222
223     self->ob_acl = ptr;
224
225     /* Return the result */
226     Py_INCREF(Py_None);
227     return Py_None;
228 }
229
230 #endif
231
232 static char __acltype_doc__[] = \
233 "Type which represents a POSIX ACL\n" \
234 "\n" \
235 "Depending on the operating system support for POSIX.1e, \n" \
236 "this type will have more or less capabilities:\n" \
237 "  - level 1, only basic support, you can create\n" \
238 "    ACLs from files and text descriptions;\n" \
239 "    once created, the type is immutable\n" \
240 "  - level 2, complete support, you can alter\n"\
241 "    the ACL once it is created\n" \
242 "\n" \
243 "Parameters:\n" \
244 "  Only one keword parameter should be provided:\n"
245 "  - file=\"...\", meaning create ACL representing\n"
246 "    the ACL of that file\n" \
247 "  - fd=<int>, meaning create ACL representing\n" \
248 "    the ACL of that file descriptor\n" \
249 "  - text=\"...\", meaning create ACL from a \n" \
250 "    textual description\n" \
251 "  - acl=<ACL instance>, meaning create a copy\n" \
252 "    of an existing ACL instance\n" \
253 ;
254
255 /* ACL type methods */
256 static PyMethodDef ACL_methods[] = {
257     {"applyto", ACL_applyto, METH_VARARGS, __applyto_doc__},
258     {"valid", ACL_valid, METH_NOARGS, __valid_doc__},
259 #ifdef HAVE_LEVEL2
260     {"__getstate__", ACL_get_state, METH_NOARGS, "Dumps the ACL to an external format."},
261     {"__setstate__", ACL_set_state, METH_VARARGS, "Loads the ACL from an external format."},
262 #endif
263     {NULL, NULL, 0, NULL}
264 };
265
266
267 /* The definition of the ACL Type */
268 static PyTypeObject ACLType = {
269     PyObject_HEAD_INIT(NULL)
270     0,
271     "posix1e.ACL",
272     sizeof(ACLObject),
273     0,
274     ACL_dealloc,        /* tp_dealloc */
275     0,                  /* tp_print */
276     0,                  /* tp_getattr */
277     0,                  /* tp_setattr */
278     0,                  /* tp_compare */
279     ACL_repr,           /* tp_repr */
280     0,                  /* tp_as_number */
281     0,                  /* tp_as_sequence */
282     0,                  /* tp_as_mapping */
283     0,                  /* tp_hash */
284     0,                  /* tp_call */
285     0,                  /* tp_str */
286     0,                  /* tp_getattro */
287     0,                  /* tp_setattro */
288     0,                  /* tp_as_buffer */
289     Py_TPFLAGS_DEFAULT, /* tp_flags */
290     __acltype_doc__,    /* tp_doc */
291     0,                  /* tp_traverse */
292     0,                  /* tp_clear */
293     0,                  /* tp_richcompare */
294     0,                  /* tp_weaklistoffset */
295     0,                  /* tp_iter */
296     0,                  /* tp_iternext */
297     ACL_methods,        /* tp_methods */
298     0,                  /* tp_members */
299     0,                  /* tp_getset */
300     0,                  /* tp_base */
301     0,                  /* tp_dict */
302     0,                  /* tp_descr_get */
303     0,                  /* tp_descr_set */
304     0,                  /* tp_dictoffset */
305     ACL_init,           /* tp_init */
306     0,                  /* tp_alloc */
307     ACL_new,            /* tp_new */
308 };
309
310 /* Module methods */
311
312 static char __deletedef_doc__[] = \
313 "Delete the default ACL from a directory.\n" \
314 "\n" \
315 "This function deletes the default ACL associated with \n" \
316 "a directory (the ACL which will be ANDed with the mode\n" \
317 "parameter to the open, creat functions.\n" \
318 "Parameters:\n" \
319 "  - a string representing the directory whose default ACL\n" \
320 "    should be deleted\n" \
321 ;
322
323 /* Deletes the default ACL from a directory */
324 static PyObject* aclmodule_delete_default(PyObject* obj, PyObject* args) {
325     char *filename;
326
327     /* Parse the arguments */
328     if (!PyArg_ParseTuple(args, "s", &filename))
329         return NULL;
330
331     if(acl_delete_def_file(filename) == -1) {
332         return PyErr_SetFromErrno(PyExc_IOError);
333     }
334
335     /* Return the result */
336     Py_INCREF(Py_None);
337     return Py_None;
338 }
339
340 /* The module methods */
341 static PyMethodDef aclmodule_methods[] = {
342     {"delete_default", aclmodule_delete_default, METH_VARARGS, __deletedef_doc__},
343     {NULL, NULL, 0, NULL}
344 };
345
346 static char __posix1e_doc__[] = \
347 "POSIX.1e ACLs manipulation\n" \
348 "\n" \
349 "This module provides support for manipulating POSIX.1e ACLS\n" \
350 ;
351
352 DL_EXPORT(void) initposix1e(void) {
353     PyObject *m, *d;
354
355     ACLType.ob_type = &PyType_Type;
356
357     if(PyType_Ready(&ACLType) < 0)
358         return;
359
360     m = Py_InitModule3("posix1e", aclmodule_methods, __posix1e_doc__);
361
362     d = PyModule_GetDict(m);
363     if (d == NULL)
364         return;
365
366     Py_INCREF(&ACLType);
367     if (PyDict_SetItemString(d, "ACL",
368                              (PyObject *) &ACLType) < 0)
369         return;
370 }