5e2daa1f719644130776dbec10a050acf5d9e486
[kai/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
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   check if we have ACL support
335  */
336 static PyObject *py_smbd_have_posix_acls(PyObject *self, PyObject *args)
337 {
338 #ifdef HAVE_POSIX_ACLS
339         return PyBool_FromLong(true);
340 #else
341         return PyBool_FromLong(false);
342 #endif
343 }
344
345 /*
346   set the NT ACL on a file
347  */
348 static PyObject *py_smbd_set_nt_acl(PyObject *self, PyObject *args)
349 {
350         NTSTATUS status;
351         char *fname;
352         int security_info_sent;
353         PyObject *py_sd;
354         struct security_descriptor *sd;
355
356         if (!PyArg_ParseTuple(args, "siO", &fname, &security_info_sent, &py_sd))
357                 return NULL;
358
359         if (!py_check_dcerpc_type(py_sd, "samba.dcerpc.security", "descriptor")) {
360                 return NULL;
361         }
362
363         sd = pytalloc_get_type(py_sd, struct security_descriptor);
364
365         status = set_nt_acl_no_snum(fname, security_info_sent, sd);
366         PyErr_NTSTATUS_IS_ERR_RAISE(status);
367
368         Py_RETURN_NONE;
369 }
370
371 /*
372   Return the NT ACL on a file
373  */
374 static PyObject *py_smbd_get_nt_acl(PyObject *self, PyObject *args)
375 {
376         char *fname;
377         int security_info_wanted;
378         PyObject *py_sd;
379         struct security_descriptor *sd;
380         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
381
382         if (!PyArg_ParseTuple(args, "si", &fname, &security_info_wanted))
383                 return NULL;
384
385         sd = get_nt_acl_no_snum(tmp_ctx, fname, security_info_wanted);
386
387         py_sd = py_return_ndr_struct("samba.dcerpc.security", "descriptor", sd, sd);
388
389         talloc_free(tmp_ctx);
390
391         return py_sd;
392 }
393
394 /*
395   set the posix (or similar) ACL on a file
396  */
397 static PyObject *py_smbd_set_sys_acl(PyObject *self, PyObject *args)
398 {
399         NTSTATUS status;
400         char *fname;
401         PyObject *py_acl;
402         struct smb_acl_t *acl;
403         int acl_type;
404
405         if (!PyArg_ParseTuple(args, "siO", &fname, &acl_type, &py_acl))
406                 return NULL;
407
408         if (!py_check_dcerpc_type(py_acl, "samba.dcerpc.smb_acl", "t")) {
409                 return NULL;
410         }
411
412         acl = pytalloc_get_type(py_acl, struct smb_acl_t);
413
414         status = set_sys_acl_no_snum(fname, acl_type, acl);
415         PyErr_NTSTATUS_IS_ERR_RAISE(status);
416
417         Py_RETURN_NONE;
418 }
419
420 /*
421   Return the posix (or similar) ACL on a file
422  */
423 static PyObject *py_smbd_get_sys_acl(PyObject *self, PyObject *args)
424 {
425         char *fname;
426         PyObject *py_acl;
427         struct smb_acl_t *acl;
428         int acl_type;
429         TALLOC_CTX *frame = talloc_stackframe();
430         connection_struct *conn;
431         NTSTATUS status = NT_STATUS_OK;
432
433         if (!PyArg_ParseTuple(args, "si", &fname, &acl_type)) {
434                 TALLOC_FREE(frame);
435                 return NULL;
436         }
437
438         conn = talloc_zero(frame, connection_struct);
439         if (conn == NULL) {
440                 DEBUG(0, ("talloc failed\n"));
441                 PyErr_NoMemory();
442                 TALLOC_FREE(frame);
443                 return NULL;
444         }
445
446         if (!(conn->params = talloc(conn, struct share_params))) {
447                 DEBUG(0,("get_nt_acl_no_snum: talloc() failed!\n"));
448                 PyErr_NoMemory();
449                 TALLOC_FREE(frame);
450                 return NULL;
451         }
452
453         conn->params->service = -1;
454
455         set_conn_connectpath(conn, "/");
456
457         smbd_vfs_init(conn);
458
459         acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, acl_type, frame);
460         if (!acl) {
461                 TALLOC_FREE(frame);
462                 status = map_nt_error_from_unix_common(errno);
463                 DEBUG(0,("sys_acl_get_file returned NULL: %s\n", strerror(errno)));
464                 PyErr_NTSTATUS_IS_ERR_RAISE(status);
465         }
466
467         conn_free(conn);
468
469         py_acl = py_return_ndr_struct("samba.dcerpc.smb_acl", "t", acl, acl);
470
471         TALLOC_FREE(frame);
472
473         return py_acl;
474 }
475
476 static PyMethodDef py_smbd_methods[] = {
477         { "have_posix_acls",
478                 (PyCFunction)py_smbd_have_posix_acls, METH_VARARGS,
479                 NULL },
480         { "set_simple_acl",
481                 (PyCFunction)py_smbd_set_simple_acl, METH_VARARGS,
482                 NULL },
483         { "set_nt_acl",
484                 (PyCFunction)py_smbd_set_nt_acl, METH_VARARGS,
485                 NULL },
486         { "get_nt_acl",
487                 (PyCFunction)py_smbd_get_nt_acl, METH_VARARGS,
488                 NULL },
489         { "get_sys_acl",
490                 (PyCFunction)py_smbd_get_sys_acl, METH_VARARGS,
491                 NULL },
492         { "set_sys_acl",
493                 (PyCFunction)py_smbd_set_sys_acl, METH_VARARGS,
494                 NULL },
495         { "chown",
496                 (PyCFunction)py_smbd_chown, METH_VARARGS,
497                 NULL },
498         { NULL }
499 };
500
501 void initsmbd(void);
502 void initsmbd(void)
503 {
504         PyObject *m;
505
506         m = Py_InitModule3("smbd", py_smbd_methods,
507                            "Python bindings for the smbd file server.");
508         if (m == NULL)
509                 return;
510
511 }