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