pysmbd: Add hook for unlink() so python scripts can remove xattr.tdb entries
[obnox/samba/samba-obnox.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,("set_sys_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_sys_acl_no_snum: SMB_VFS_SYS_ACL_SET_FILE "
69                          "returned zero.\n"));
70         }
71
72         conn_free(conn);
73
74         return status;
75 }
76
77 static NTSTATUS set_nt_acl_no_snum(const char *fname,
78                                    uint32 security_info_sent, const struct security_descriptor *sd)
79 {
80         TALLOC_CTX *frame = talloc_stackframe();
81         connection_struct *conn;
82         NTSTATUS status = NT_STATUS_OK;
83         files_struct *fsp;
84         struct smb_filename *smb_fname = NULL;
85         int flags;
86
87         conn = talloc_zero(frame, connection_struct);
88         if (conn == NULL) {
89                 DEBUG(0, ("talloc failed\n"));
90                 return NT_STATUS_NO_MEMORY;
91         }
92
93         if (!(conn->params = talloc(conn, struct share_params))) {
94                 DEBUG(0,("set_nt_acl_no_snum: talloc() failed!\n"));
95                 TALLOC_FREE(frame);
96                 return NT_STATUS_NO_MEMORY;
97         }
98
99         conn->params->service = -1;
100
101         set_conn_connectpath(conn, "/");
102
103         smbd_vfs_init(conn);
104
105         fsp = talloc_zero(frame, struct files_struct);
106         if (fsp == NULL) {
107                 TALLOC_FREE(frame);
108                 return NT_STATUS_NO_MEMORY;
109         }
110         fsp->fh = talloc(fsp, struct fd_handle);
111         if (fsp->fh == NULL) {
112                 TALLOC_FREE(frame);
113                 return NT_STATUS_NO_MEMORY;
114         }
115         fsp->conn = conn;
116
117         status = create_synthetic_smb_fname_split(fsp, fname, NULL,
118                                                   &smb_fname);
119         if (!NT_STATUS_IS_OK(status)) {
120                 TALLOC_FREE(frame);
121                 return status;
122         }
123
124         fsp->fsp_name = smb_fname;
125
126 #ifdef O_DIRECTORY
127         flags = O_RDONLY|O_DIRECTORY;
128 #else
129         /* POSIX allows us to open a directory with O_RDONLY. */
130         flags = O_RDONLY;
131 #endif
132
133         fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, O_RDWR, 00400);
134         if (fsp->fh->fd == -1 && errno == EISDIR) {
135                 fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, 00400);
136         }
137         if (fsp->fh->fd == -1) {
138                 printf("open: error=%d (%s)\n", errno, strerror(errno));
139                 TALLOC_FREE(frame);
140                 return NT_STATUS_UNSUCCESSFUL;
141         }
142
143         status = SMB_VFS_FSET_NT_ACL( fsp, security_info_sent, sd);
144         if (!NT_STATUS_IS_OK(status)) {
145                 DEBUG(0,("set_nt_acl_no_snum: fset_nt_acl returned %s.\n", nt_errstr(status)));
146         }
147
148         conn_free(conn);
149         TALLOC_FREE(frame);
150
151         return status;
152 }
153
154
155 static SMB_ACL_T make_simple_acl(gid_t gid, mode_t chmod_mode)
156 {
157         TALLOC_CTX *frame = talloc_stackframe();
158
159         mode_t mode = SMB_ACL_READ|SMB_ACL_WRITE;
160
161         mode_t mode_user = (chmod_mode & 0700) >> 6;
162         mode_t mode_group = (chmod_mode & 070) >> 3;
163         mode_t mode_other = chmod_mode &  07;
164         SMB_ACL_ENTRY_T entry;
165         SMB_ACL_T acl = sys_acl_init(frame);
166
167         if (!acl) {
168                 return NULL;
169         }
170
171         if (sys_acl_create_entry(&acl, &entry) != 0) {
172                 TALLOC_FREE(frame);
173                 return NULL;
174         }
175
176         if (sys_acl_set_tag_type(entry, SMB_ACL_USER_OBJ) != 0) {
177                 TALLOC_FREE(frame);
178                 return NULL;
179         }
180
181         if (sys_acl_set_permset(entry, &mode_user) != 0) {
182                 TALLOC_FREE(frame);
183                 return NULL;
184         }
185
186         if (sys_acl_create_entry(&acl, &entry) != 0) {
187                 TALLOC_FREE(frame);
188                 return NULL;
189         }
190
191         if (sys_acl_set_tag_type(entry, SMB_ACL_GROUP_OBJ) != 0) {
192                 TALLOC_FREE(frame);
193                 return NULL;
194         }
195
196         if (sys_acl_set_permset(entry, &mode_group) != 0) {
197                 TALLOC_FREE(frame);
198                 return NULL;
199         }
200
201         if (sys_acl_create_entry(&acl, &entry) != 0) {
202                 TALLOC_FREE(frame);
203                 return NULL;
204         }
205
206         if (sys_acl_set_tag_type(entry, SMB_ACL_OTHER) != 0) {
207                 TALLOC_FREE(frame);
208                 return NULL;
209         }
210
211         if (sys_acl_set_permset(entry, &mode_other) != 0) {
212                 TALLOC_FREE(frame);
213                 return NULL;
214         }
215
216         if (gid != -1) {
217                 if (sys_acl_create_entry(&acl, &entry) != 0) {
218                         TALLOC_FREE(frame);
219                         return NULL;
220                 }
221
222                 if (sys_acl_set_tag_type(entry, SMB_ACL_GROUP) != 0) {
223                         TALLOC_FREE(frame);
224                         return NULL;
225                 }
226
227                 if (sys_acl_set_qualifier(entry, &gid) != 0) {
228                         TALLOC_FREE(frame);
229                         return NULL;
230                 }
231
232                 if (sys_acl_set_permset(entry, &mode_group) != 0) {
233                         TALLOC_FREE(frame);
234                         return NULL;
235                 }
236         }
237
238         if (sys_acl_create_entry(&acl, &entry) != 0) {
239                 TALLOC_FREE(frame);
240                 return NULL;
241         }
242
243         if (sys_acl_set_tag_type(entry, SMB_ACL_MASK) != 0) {
244                 TALLOC_FREE(frame);
245                 return NULL;
246         }
247
248         if (sys_acl_set_permset(entry, &mode) != 0) {
249                 TALLOC_FREE(frame);
250                 return NULL;
251         }
252         return acl;
253 }
254
255 /*
256   set a simple ACL on a file, as a test
257  */
258 static PyObject *py_smbd_set_simple_acl(PyObject *self, PyObject *args)
259 {
260         NTSTATUS status;
261         char *fname;
262         int mode, gid = -1;
263         SMB_ACL_T acl;
264         TALLOC_CTX *frame;
265
266         if (!PyArg_ParseTuple(args, "si|i", &fname, &mode, &gid))
267                 return NULL;
268
269         acl = make_simple_acl(gid, mode);
270
271         frame = talloc_stackframe();
272
273         status = set_sys_acl_no_snum(fname, SMB_ACL_TYPE_ACCESS, acl);
274         TALLOC_FREE(acl);
275
276         TALLOC_FREE(frame);
277
278         PyErr_NTSTATUS_IS_ERR_RAISE(status);
279
280         Py_RETURN_NONE;
281 }
282
283 /*
284   chown a file
285  */
286 static PyObject *py_smbd_chown(PyObject *self, PyObject *args)
287 {
288         connection_struct *conn;
289         NTSTATUS status = NT_STATUS_OK;
290         int ret;
291
292         char *fname;
293         int uid, gid;
294         TALLOC_CTX *frame;
295
296         if (!PyArg_ParseTuple(args, "sii", &fname, &uid, &gid))
297                 return NULL;
298
299         frame = talloc_stackframe();
300
301         conn = talloc_zero(frame, connection_struct);
302         if (conn == NULL) {
303                 PyErr_NoMemory();
304                 return NULL;
305         }
306
307         if (!(conn->params = talloc(conn, struct share_params))) {
308                 PyErr_NoMemory();
309                 return NULL;
310         }
311
312         conn->params->service = -1;
313
314         set_conn_connectpath(conn, "/");
315
316         smbd_vfs_init(conn);
317
318         ret = SMB_VFS_CHOWN( conn, fname, uid, gid);
319         if (ret != 0) {
320                 status = map_nt_error_from_unix_common(errno);
321                 DEBUG(0,("chown returned failure: %s\n", strerror(errno)));
322         }
323
324         conn_free(conn);
325
326         TALLOC_FREE(frame);
327
328         PyErr_NTSTATUS_IS_ERR_RAISE(status);
329
330         Py_RETURN_NONE;
331 }
332
333 /*
334   chown a file
335  */
336 static PyObject *py_smbd_unlink(PyObject *self, PyObject *args)
337 {
338         connection_struct *conn;
339         NTSTATUS status = NT_STATUS_OK;
340         int ret;
341         struct smb_filename *smb_fname = NULL;
342         char *fname;
343         int uid, gid;
344         TALLOC_CTX *frame;
345         mode_t saved_umask;
346
347         if (!PyArg_ParseTuple(args, "s", &fname))
348                 return NULL;
349
350         frame = talloc_stackframe();
351
352         conn = talloc_zero(frame, connection_struct);
353         if (conn == NULL) {
354                 PyErr_NoMemory();
355                 return NULL;
356         }
357
358         if (!(conn->params = talloc(conn, struct share_params))) {
359                 PyErr_NoMemory();
360                 return NULL;
361         }
362
363         /* we want total control over the permissions on created files,
364            so set our umask to 0 */
365         saved_umask = umask(0);
366
367         conn->params->service = -1;
368
369         set_conn_connectpath(conn, "/");
370
371         smbd_vfs_init(conn);
372
373         status = create_synthetic_smb_fname_split(frame, fname, NULL,
374                                                   &smb_fname);
375         if (!NT_STATUS_IS_OK(status)) {
376                 TALLOC_FREE(frame);
377                 umask(saved_umask);
378                 PyErr_NTSTATUS_IS_ERR_RAISE(status);
379         }
380
381         ret = SMB_VFS_UNLINK(conn, smb_fname);
382         if (ret != 0) {
383                 status = map_nt_error_from_unix_common(errno);
384                 DEBUG(0,("unlink returned failure: %s\n", strerror(errno)));
385         }
386
387         umask(saved_umask);
388
389         conn_free(conn);
390
391         TALLOC_FREE(frame);
392
393         PyErr_NTSTATUS_IS_ERR_RAISE(status);
394
395         Py_RETURN_NONE;
396 }
397
398 /*
399   check if we have ACL support
400  */
401 static PyObject *py_smbd_have_posix_acls(PyObject *self, PyObject *args)
402 {
403 #ifdef HAVE_POSIX_ACLS
404         return PyBool_FromLong(true);
405 #else
406         return PyBool_FromLong(false);
407 #endif
408 }
409
410 /*
411   set the NT ACL on a file
412  */
413 static PyObject *py_smbd_set_nt_acl(PyObject *self, PyObject *args)
414 {
415         NTSTATUS status;
416         char *fname;
417         int security_info_sent;
418         PyObject *py_sd;
419         struct security_descriptor *sd;
420
421         if (!PyArg_ParseTuple(args, "siO", &fname, &security_info_sent, &py_sd))
422                 return NULL;
423
424         if (!py_check_dcerpc_type(py_sd, "samba.dcerpc.security", "descriptor")) {
425                 return NULL;
426         }
427
428         sd = pytalloc_get_type(py_sd, struct security_descriptor);
429
430         status = set_nt_acl_no_snum(fname, security_info_sent, sd);
431         PyErr_NTSTATUS_IS_ERR_RAISE(status);
432
433         Py_RETURN_NONE;
434 }
435
436 /*
437   Return the NT ACL on a file
438  */
439 static PyObject *py_smbd_get_nt_acl(PyObject *self, PyObject *args)
440 {
441         char *fname;
442         int security_info_wanted;
443         PyObject *py_sd;
444         struct security_descriptor *sd;
445         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
446
447         if (!PyArg_ParseTuple(args, "si", &fname, &security_info_wanted))
448                 return NULL;
449
450         sd = get_nt_acl_no_snum(tmp_ctx, fname, security_info_wanted);
451
452         py_sd = py_return_ndr_struct("samba.dcerpc.security", "descriptor", sd, sd);
453
454         talloc_free(tmp_ctx);
455
456         return py_sd;
457 }
458
459 /*
460   set the posix (or similar) ACL on a file
461  */
462 static PyObject *py_smbd_set_sys_acl(PyObject *self, PyObject *args)
463 {
464         NTSTATUS status;
465         char *fname;
466         PyObject *py_acl;
467         struct smb_acl_t *acl;
468         int acl_type;
469
470         if (!PyArg_ParseTuple(args, "siO", &fname, &acl_type, &py_acl))
471                 return NULL;
472
473         if (!py_check_dcerpc_type(py_acl, "samba.dcerpc.smb_acl", "t")) {
474                 return NULL;
475         }
476
477         acl = pytalloc_get_type(py_acl, struct smb_acl_t);
478
479         status = set_sys_acl_no_snum(fname, acl_type, acl);
480         PyErr_NTSTATUS_IS_ERR_RAISE(status);
481
482         Py_RETURN_NONE;
483 }
484
485 /*
486   Return the posix (or similar) ACL on a file
487  */
488 static PyObject *py_smbd_get_sys_acl(PyObject *self, PyObject *args)
489 {
490         char *fname;
491         PyObject *py_acl;
492         struct smb_acl_t *acl;
493         int acl_type;
494         TALLOC_CTX *frame = talloc_stackframe();
495         connection_struct *conn;
496         NTSTATUS status = NT_STATUS_OK;
497
498         if (!PyArg_ParseTuple(args, "si", &fname, &acl_type)) {
499                 TALLOC_FREE(frame);
500                 return NULL;
501         }
502
503         conn = talloc_zero(frame, connection_struct);
504         if (conn == NULL) {
505                 DEBUG(0, ("talloc failed\n"));
506                 PyErr_NoMemory();
507                 TALLOC_FREE(frame);
508                 return NULL;
509         }
510
511         if (!(conn->params = talloc(conn, struct share_params))) {
512                 DEBUG(0,("get_nt_acl_no_snum: talloc() failed!\n"));
513                 PyErr_NoMemory();
514                 TALLOC_FREE(frame);
515                 return NULL;
516         }
517
518         conn->params->service = -1;
519
520         set_conn_connectpath(conn, "/");
521
522         smbd_vfs_init(conn);
523
524         acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, acl_type, frame);
525         if (!acl) {
526                 TALLOC_FREE(frame);
527                 status = map_nt_error_from_unix_common(errno);
528                 DEBUG(0,("sys_acl_get_file returned NULL: %s\n", strerror(errno)));
529                 PyErr_NTSTATUS_IS_ERR_RAISE(status);
530         }
531
532         conn_free(conn);
533
534         py_acl = py_return_ndr_struct("samba.dcerpc.smb_acl", "t", acl, acl);
535
536         TALLOC_FREE(frame);
537
538         return py_acl;
539 }
540
541 static PyMethodDef py_smbd_methods[] = {
542         { "have_posix_acls",
543                 (PyCFunction)py_smbd_have_posix_acls, METH_VARARGS,
544                 NULL },
545         { "set_simple_acl",
546                 (PyCFunction)py_smbd_set_simple_acl, METH_VARARGS,
547                 NULL },
548         { "set_nt_acl",
549                 (PyCFunction)py_smbd_set_nt_acl, METH_VARARGS,
550                 NULL },
551         { "get_nt_acl",
552                 (PyCFunction)py_smbd_get_nt_acl, METH_VARARGS,
553                 NULL },
554         { "get_sys_acl",
555                 (PyCFunction)py_smbd_get_sys_acl, METH_VARARGS,
556                 NULL },
557         { "set_sys_acl",
558                 (PyCFunction)py_smbd_set_sys_acl, METH_VARARGS,
559                 NULL },
560         { "chown",
561                 (PyCFunction)py_smbd_chown, METH_VARARGS,
562                 NULL },
563         { "unlink",
564                 (PyCFunction)py_smbd_unlink, METH_VARARGS,
565                 NULL },
566         { NULL }
567 };
568
569 void initsmbd(void);
570 void initsmbd(void)
571 {
572         PyObject *m;
573
574         m = Py_InitModule3("smbd", py_smbd_methods,
575                            "Python bindings for the smbd file server.");
576         if (m == NULL)
577                 return;
578
579 }