s3-pysmbd: Add get/set functions for the posix ACL layer
[metze/samba/wip.git] / source3 / smbd / pysmbd.c
1 /*
2    Unix SMB/CIFS implementation.
3    Set NT and POSIX ACLs and other VFS operations from Python 
4    
5    Copyrigyt (C) Andrew Bartlett 2012
6    Copyright (C) Jeremy Allison 1994-2009.
7    Copyright (C) Andreas Gruenbacher 2002.
8    Copyright (C) Simo Sorce <idra@samba.org> 2009.
9    Copyright (C) Simo Sorce 2002
10    Copyright (C) Eric Lorimer 2002
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 3 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 #include "includes.h"
27 #include "smbd/smbd.h"
28 #include <Python.h>
29 #include "libcli/util/pyerrors.h"
30 #include "librpc/rpc/pyrpc_util.h"
31 #include <pytalloc.h>
32 #include "system/filesys.h"
33
34 extern const struct generic_mapping file_generic_mapping;
35
36 #undef  DBGC_CLASS
37 #define DBGC_CLASS DBGC_ACLS
38
39 static NTSTATUS set_sys_acl_no_snum(const char *fname,
40                                      SMB_ACL_TYPE_T acltype,
41                                      SMB_ACL_T theacl)
42 {
43         connection_struct *conn;
44         NTSTATUS status = NT_STATUS_OK;
45         int ret;
46
47         conn = talloc_zero(NULL, connection_struct);
48         if (conn == NULL) {
49                 DEBUG(0, ("talloc failed\n"));
50                 return NT_STATUS_NO_MEMORY;
51         }
52
53         if (!(conn->params = talloc(conn, struct share_params))) {
54                 DEBUG(0,("get_nt_acl_no_snum: talloc() failed!\n"));
55                 TALLOC_FREE(conn);
56                 return NT_STATUS_NO_MEMORY;
57         }
58
59         conn->params->service = -1;
60
61         set_conn_connectpath(conn, "/");
62
63         smbd_vfs_init(conn);
64
65         ret = SMB_VFS_SYS_ACL_SET_FILE( conn, fname, acltype, theacl);
66         if (ret != 0) {
67                 status = map_nt_error_from_unix_common(ret);
68                 DEBUG(0,("set_nt_acl_no_snum: fset_nt_acl returned zero.\n"));
69         }
70
71         conn_free(conn);
72
73         return status;
74 }
75
76 static NTSTATUS set_nt_acl_no_snum(const char *fname,
77                                    uint32 security_info_sent, const struct security_descriptor *sd)
78 {
79         TALLOC_CTX *frame = talloc_stackframe();
80         connection_struct *conn;
81         NTSTATUS status = NT_STATUS_OK;
82         files_struct *fsp;
83         struct smb_filename *smb_fname = NULL;
84         int flags;
85
86         conn = talloc_zero(frame, connection_struct);
87         if (conn == NULL) {
88                 DEBUG(0, ("talloc failed\n"));
89                 return NT_STATUS_NO_MEMORY;
90         }
91
92         if (!(conn->params = talloc(conn, struct share_params))) {
93                 DEBUG(0,("set_nt_acl_no_snum: talloc() failed!\n"));
94                 TALLOC_FREE(frame);
95                 return NT_STATUS_NO_MEMORY;
96         }
97
98         conn->params->service = -1;
99
100         set_conn_connectpath(conn, "/");
101
102         smbd_vfs_init(conn);
103
104         fsp = talloc_zero(frame, struct files_struct);
105         if (fsp == NULL) {
106                 TALLOC_FREE(frame);
107                 return NT_STATUS_NO_MEMORY;
108         }
109         fsp->fh = talloc(fsp, struct fd_handle);
110         if (fsp->fh == NULL) {
111                 TALLOC_FREE(frame);
112                 return NT_STATUS_NO_MEMORY;
113         }
114         fsp->conn = conn;
115
116         status = create_synthetic_smb_fname_split(fsp, fname, NULL,
117                                                   &smb_fname);
118         if (!NT_STATUS_IS_OK(status)) {
119                 TALLOC_FREE(frame);
120                 return status;
121         }
122
123         fsp->fsp_name = smb_fname;
124
125 #ifdef O_DIRECTORY
126         flags = O_RDONLY|O_DIRECTORY;
127 #else
128         /* POSIX allows us to open a directory with O_RDONLY. */
129         flags = O_RDONLY;
130 #endif
131
132         fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, O_RDWR, 00400);
133         if (fsp->fh->fd == -1 && errno == EISDIR) {
134                 fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, 00400);
135         }
136         if (fsp->fh->fd == -1) {
137                 printf("open: error=%d (%s)\n", errno, strerror(errno));
138                 TALLOC_FREE(frame);
139                 return NT_STATUS_UNSUCCESSFUL;
140         }
141
142         status = SMB_VFS_FSET_NT_ACL( fsp, security_info_sent, sd);
143         if (!NT_STATUS_IS_OK(status)) {
144                 DEBUG(0,("set_nt_acl_no_snum: fset_nt_acl returned %s.\n", nt_errstr(status)));
145         }
146
147         conn_free(conn);
148         TALLOC_FREE(frame);
149
150         return status;
151 }
152
153
154 static SMB_ACL_T make_simple_acl(uid_t uid, gid_t gid)
155 {
156         mode_t mode = SMB_ACL_READ|SMB_ACL_WRITE;
157         mode_t mode0 = 0;
158
159         SMB_ACL_ENTRY_T entry;
160         SMB_ACL_T acl = sys_acl_init(4);
161
162         if (!acl) {
163                 return NULL;
164         }
165
166         if (sys_acl_create_entry(&acl, &entry) != 0) {
167                 TALLOC_FREE(acl);
168                 return NULL;
169         }
170
171         if (sys_acl_set_tag_type(entry, SMB_ACL_USER_OBJ) != 0) {
172                 TALLOC_FREE(acl);
173                 return NULL;
174         }
175
176         if (sys_acl_set_permset(entry, &mode) != 0) {
177                 TALLOC_FREE(acl);
178                 return NULL;
179         }
180
181         if (sys_acl_create_entry(&acl, &entry) != 0) {
182                 TALLOC_FREE(acl);
183                 return NULL;
184         }
185
186         if (sys_acl_set_tag_type(entry, SMB_ACL_GROUP_OBJ) != 0) {
187                 TALLOC_FREE(acl);
188                 return NULL;
189         }
190
191         if (sys_acl_set_permset(entry, &mode) != 0) {
192                 TALLOC_FREE(acl);
193                 return NULL;
194         }
195
196         if (sys_acl_create_entry(&acl, &entry) != 0) {
197                 TALLOC_FREE(acl);
198                 return NULL;
199         }
200
201         if (sys_acl_set_tag_type(entry, SMB_ACL_OTHER) != 0) {
202                 TALLOC_FREE(acl);
203                 return NULL;
204         }
205
206         if (sys_acl_set_permset(entry, &mode0) != 0) {
207                 TALLOC_FREE(acl);
208                 return NULL;
209         }
210
211         if (sys_acl_create_entry(&acl, &entry) != 0) {
212                 TALLOC_FREE(acl);
213                 return NULL;
214         }
215
216         if (sys_acl_set_tag_type(entry, SMB_ACL_GROUP) != 0) {
217                 TALLOC_FREE(acl);
218                 return NULL;
219         }
220
221         if (sys_acl_set_qualifier(entry, &gid) != 0) {
222                 TALLOC_FREE(acl);
223                 return NULL;
224         }
225
226         if (sys_acl_set_permset(entry, &mode) != 0) {
227                 TALLOC_FREE(acl);
228                 return NULL;
229         }
230
231         if (sys_acl_create_entry(&acl, &entry) != 0) {
232                 TALLOC_FREE(acl);
233                 return NULL;
234         }
235
236         if (sys_acl_set_tag_type(entry, SMB_ACL_MASK) != 0) {
237                 TALLOC_FREE(acl);
238                 return NULL;
239         }
240
241         if (sys_acl_set_permset(entry, &mode0) != 0) {
242                 TALLOC_FREE(acl);
243                 return NULL;
244         }
245         return acl;
246 }
247
248 /*
249   set a simple ACL on a file, as a test
250  */
251 static PyObject *py_smbd_set_simple_acl(PyObject *self, PyObject *args)
252 {
253         NTSTATUS status;
254         char *fname;
255         int uid, gid;
256         SMB_ACL_T acl;
257         TALLOC_CTX *frame;
258
259         if (!PyArg_ParseTuple(args, "sii", &fname, &uid, &gid))
260                 return NULL;
261
262         acl = make_simple_acl(uid, gid);
263
264         frame = talloc_stackframe();
265
266         status = set_sys_acl_no_snum(fname, SMB_ACL_TYPE_ACCESS, acl);
267         TALLOC_FREE(acl);
268
269         TALLOC_FREE(frame);
270
271         PyErr_NTSTATUS_IS_ERR_RAISE(status);
272
273         Py_RETURN_NONE;
274 }
275
276 /*
277   chown a file
278  */
279 static PyObject *py_smbd_chown(PyObject *self, PyObject *args)
280 {
281         connection_struct *conn;
282         NTSTATUS status = NT_STATUS_OK;
283         int ret;
284
285         char *fname;
286         int uid, gid;
287         TALLOC_CTX *frame;
288
289         if (!PyArg_ParseTuple(args, "sii", &fname, &uid, &gid))
290                 return NULL;
291
292         frame = talloc_stackframe();
293
294         conn = talloc_zero(frame, connection_struct);
295         if (conn == NULL) {
296                 PyErr_NoMemory();
297                 return NULL;
298         }
299
300         if (!(conn->params = talloc(conn, struct share_params))) {
301                 PyErr_NoMemory();
302                 return NULL;
303         }
304
305         conn->params->service = -1;
306
307         set_conn_connectpath(conn, "/");
308
309         smbd_vfs_init(conn);
310
311         ret = SMB_VFS_CHOWN( conn, fname, uid, gid);
312         if (ret != 0) {
313                 status = map_nt_error_from_unix_common(ret);
314                 DEBUG(0,("chwon returned failure: %s\n", strerror(ret)));
315         }
316
317         conn_free(conn);
318
319         TALLOC_FREE(frame);
320
321         PyErr_NTSTATUS_IS_ERR_RAISE(status);
322
323         Py_RETURN_NONE;
324 }
325
326 /*
327   check if we have ACL support
328  */
329 static PyObject *py_smbd_have_posix_acls(PyObject *self, PyObject *args)
330 {
331 #ifdef HAVE_POSIX_ACLS
332         return PyBool_FromLong(true);
333 #else
334         return PyBool_FromLong(false);
335 #endif
336 }
337
338 /*
339   set the NT ACL on a file
340  */
341 static PyObject *py_smbd_set_nt_acl(PyObject *self, PyObject *args)
342 {
343         NTSTATUS status;
344         char *fname;
345         int security_info_sent;
346         PyObject *py_sd;
347         struct security_descriptor *sd;
348
349         if (!PyArg_ParseTuple(args, "siO", &fname, &security_info_sent, &py_sd))
350                 return NULL;
351
352         if (!py_check_dcerpc_type(py_sd, "samba.dcerpc.security", "descriptor")) {
353                 return NULL;
354         }
355
356         sd = pytalloc_get_type(py_sd, struct security_descriptor);
357
358         status = set_nt_acl_no_snum(fname, security_info_sent, sd);
359         PyErr_NTSTATUS_IS_ERR_RAISE(status);
360
361         Py_RETURN_NONE;
362 }
363
364 /*
365   Return the NT ACL on a file
366  */
367 static PyObject *py_smbd_get_nt_acl(PyObject *self, PyObject *args)
368 {
369         char *fname;
370         int security_info_sent;
371         PyObject *py_sd;
372         struct security_descriptor *sd;
373         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
374
375         if (!PyArg_ParseTuple(args, "si", &fname, &security_info_sent))
376                 return NULL;
377         
378         sd = get_nt_acl_no_snum(tmp_ctx, fname);
379
380         py_sd = py_return_ndr_struct("samba.dcerpc.security", "security_descriptor", sd, sd);
381
382         talloc_free(tmp_ctx);
383
384         return py_sd;
385 }
386
387 /*
388   set the posix (or similar) ACL on a file
389  */
390 static PyObject *py_smbd_set_sys_acl(PyObject *self, PyObject *args)
391 {
392         NTSTATUS status;
393         char *fname;
394         PyObject *py_acl;
395         struct smb_acl_t *acl;
396         int acl_type;
397
398         if (!PyArg_ParseTuple(args, "siO", &fname, &acl_type, &py_acl))
399                 return NULL;
400
401         if (!py_check_dcerpc_type(py_acl, "samba.dcerpc.smb_acl", "sys_acl_t")) {
402                 return NULL;
403         }
404
405         acl = pytalloc_get_type(py_acl, struct smb_acl_t);
406
407         status = set_sys_acl_no_snum(fname, acl_type, acl);
408         PyErr_NTSTATUS_IS_ERR_RAISE(status);
409
410         Py_RETURN_NONE;
411 }
412
413 /*
414   Return the posix (or similar) ACL on a file
415  */
416 static PyObject *py_smbd_get_sys_acl(PyObject *self, PyObject *args)
417 {
418         char *fname;
419         PyObject *py_acl;
420         struct smb_acl_t *acl;
421         int acl_type;
422         TALLOC_CTX *frame = talloc_stackframe();
423         connection_struct *conn;
424         NTSTATUS status = NT_STATUS_OK;
425
426         if (!PyArg_ParseTuple(args, "si", &fname, &acl_type)) {
427                 TALLOC_FREE(frame);
428                 return NULL;
429         }
430
431         conn = talloc_zero(frame, connection_struct);
432         if (conn == NULL) {
433                 DEBUG(0, ("talloc failed\n"));
434                 PyErr_NoMemory();
435                 TALLOC_FREE(frame);
436                 return NULL;
437         }
438
439         if (!(conn->params = talloc(conn, struct share_params))) {
440                 DEBUG(0,("get_nt_acl_no_snum: talloc() failed!\n"));
441                 PyErr_NoMemory();
442                 TALLOC_FREE(frame);
443                 return NULL;
444         }
445
446         conn->params->service = -1;
447
448         set_conn_connectpath(conn, "/");
449
450         smbd_vfs_init(conn);
451
452         acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, acl_type);
453         if (!acl) {
454                 TALLOC_FREE(frame);
455                 status = map_nt_error_from_unix_common(errno);
456                 DEBUG(0,("sys_acl_get_file returned NULL: %s\n", strerror(errno)));
457                 PyErr_NTSTATUS_IS_ERR_RAISE(status);
458         }
459
460         talloc_steal(frame, acl);
461         conn_free(conn);
462
463         py_acl = py_return_ndr_struct("samba.dcerpc.smb_acl", "sys_acl_t", acl, acl);
464
465         TALLOC_FREE(frame);
466
467         return py_acl;
468 }
469
470 static PyMethodDef py_smbd_methods[] = {
471         { "have_posix_acls",
472                 (PyCFunction)py_smbd_have_posix_acls, METH_VARARGS,
473                 NULL },
474         { "set_simple_acl",
475                 (PyCFunction)py_smbd_set_simple_acl, METH_VARARGS,
476                 NULL },
477         { "set_nt_acl",
478                 (PyCFunction)py_smbd_set_nt_acl, METH_VARARGS,
479                 NULL },
480         { "get_nt_acl",
481                 (PyCFunction)py_smbd_get_nt_acl, METH_VARARGS,
482                 NULL },
483         { "get_sys_acl",
484                 (PyCFunction)py_smbd_get_sys_acl, METH_VARARGS,
485                 NULL },
486         { "set_sys_acl",
487                 (PyCFunction)py_smbd_set_sys_acl, METH_VARARGS,
488                 NULL },
489         { "chown",
490                 (PyCFunction)py_smbd_chown, METH_VARARGS,
491                 NULL },
492         { NULL }
493 };
494
495 void initsmbd(void);
496 void initsmbd(void)
497 {
498         PyObject *m;
499
500         m = Py_InitModule3("smbd", py_smbd_methods,
501                            "Python bindings for the smbd file server.");
502         if (m == NULL)
503                 return;
504
505 }