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