lib/util: Simplify bitmap.c a bit
[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         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;
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         int uid, gid;
374         TALLOC_CTX *frame;
375         mode_t saved_umask;
376
377         if (!PyArg_ParseTuple(args, "s", &fname))
378                 return NULL;
379
380         frame = talloc_stackframe();
381
382         conn = talloc_zero(frame, connection_struct);
383         if (conn == NULL) {
384                 PyErr_NoMemory();
385                 return NULL;
386         }
387
388         if (!(conn->params = talloc(conn, struct share_params))) {
389                 PyErr_NoMemory();
390                 return NULL;
391         }
392
393         /* we want total control over the permissions on created files,
394            so set our umask to 0 */
395         saved_umask = umask(0);
396
397         conn->params->service = -1;
398
399         set_conn_connectpath(conn, "/");
400
401         smbd_vfs_init(conn);
402
403         status = create_synthetic_smb_fname_split(frame, fname, NULL,
404                                                   &smb_fname);
405         if (!NT_STATUS_IS_OK(status)) {
406                 TALLOC_FREE(frame);
407                 umask(saved_umask);
408                 PyErr_NTSTATUS_IS_ERR_RAISE(status);
409         }
410
411         ret = SMB_VFS_UNLINK(conn, smb_fname);
412         if (ret != 0) {
413                 status = map_nt_error_from_unix_common(errno);
414                 DEBUG(0,("unlink returned failure: %s\n", strerror(errno)));
415         }
416
417         umask(saved_umask);
418
419         conn_free(conn);
420
421         TALLOC_FREE(frame);
422
423         PyErr_NTSTATUS_IS_ERR_RAISE(status);
424
425         Py_RETURN_NONE;
426 }
427
428 /*
429   check if we have ACL support
430  */
431 static PyObject *py_smbd_have_posix_acls(PyObject *self, PyObject *args)
432 {
433 #ifdef HAVE_POSIX_ACLS
434         return PyBool_FromLong(true);
435 #else
436         return PyBool_FromLong(false);
437 #endif
438 }
439
440 /*
441   set the NT ACL on a file
442  */
443 static PyObject *py_smbd_set_nt_acl(PyObject *self, PyObject *args)
444 {
445         NTSTATUS status;
446         char *fname;
447         int security_info_sent;
448         PyObject *py_sd;
449         struct security_descriptor *sd;
450
451         if (!PyArg_ParseTuple(args, "siO", &fname, &security_info_sent, &py_sd))
452                 return NULL;
453
454         if (!py_check_dcerpc_type(py_sd, "samba.dcerpc.security", "descriptor")) {
455                 return NULL;
456         }
457
458         sd = pytalloc_get_type(py_sd, struct security_descriptor);
459
460         status = set_nt_acl_no_snum(fname, security_info_sent, sd);
461         PyErr_NTSTATUS_IS_ERR_RAISE(status);
462
463         Py_RETURN_NONE;
464 }
465
466 /*
467   Return the NT ACL on a file
468  */
469 static PyObject *py_smbd_get_nt_acl(PyObject *self, PyObject *args)
470 {
471         char *fname;
472         int security_info_wanted;
473         PyObject *py_sd;
474         struct security_descriptor *sd;
475         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
476
477         if (!PyArg_ParseTuple(args, "si", &fname, &security_info_wanted))
478                 return NULL;
479
480         sd = get_nt_acl_no_snum(tmp_ctx, fname, security_info_wanted);
481
482         py_sd = py_return_ndr_struct("samba.dcerpc.security", "descriptor", sd, sd);
483
484         talloc_free(tmp_ctx);
485
486         return py_sd;
487 }
488
489 /*
490   set the posix (or similar) ACL on a file
491  */
492 static PyObject *py_smbd_set_sys_acl(PyObject *self, PyObject *args)
493 {
494         NTSTATUS status;
495         char *fname;
496         PyObject *py_acl;
497         struct smb_acl_t *acl;
498         int acl_type;
499
500         if (!PyArg_ParseTuple(args, "siO", &fname, &acl_type, &py_acl))
501                 return NULL;
502
503         if (!py_check_dcerpc_type(py_acl, "samba.dcerpc.smb_acl", "t")) {
504                 return NULL;
505         }
506
507         acl = pytalloc_get_type(py_acl, struct smb_acl_t);
508
509         status = set_sys_acl_no_snum(fname, acl_type, acl);
510         PyErr_NTSTATUS_IS_ERR_RAISE(status);
511
512         Py_RETURN_NONE;
513 }
514
515 /*
516   Return the posix (or similar) ACL on a file
517  */
518 static PyObject *py_smbd_get_sys_acl(PyObject *self, PyObject *args)
519 {
520         char *fname;
521         PyObject *py_acl;
522         struct smb_acl_t *acl;
523         int acl_type;
524         TALLOC_CTX *frame = talloc_stackframe();
525         connection_struct *conn;
526         NTSTATUS status = NT_STATUS_OK;
527
528         if (!PyArg_ParseTuple(args, "si", &fname, &acl_type)) {
529                 TALLOC_FREE(frame);
530                 return NULL;
531         }
532
533         conn = talloc_zero(frame, connection_struct);
534         if (conn == NULL) {
535                 DEBUG(0, ("talloc failed\n"));
536                 PyErr_NoMemory();
537                 TALLOC_FREE(frame);
538                 return NULL;
539         }
540
541         if (!(conn->params = talloc(conn, struct share_params))) {
542                 DEBUG(0,("get_nt_acl_no_snum: talloc() failed!\n"));
543                 PyErr_NoMemory();
544                 TALLOC_FREE(frame);
545                 return NULL;
546         }
547
548         conn->params->service = -1;
549
550         set_conn_connectpath(conn, "/");
551
552         smbd_vfs_init(conn);
553
554         acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, acl_type, frame);
555         if (!acl) {
556                 TALLOC_FREE(frame);
557                 status = map_nt_error_from_unix_common(errno);
558                 DEBUG(0,("sys_acl_get_file returned NULL: %s\n", strerror(errno)));
559                 PyErr_NTSTATUS_IS_ERR_RAISE(status);
560         }
561
562         conn_free(conn);
563
564         py_acl = py_return_ndr_struct("samba.dcerpc.smb_acl", "t", acl, acl);
565
566         TALLOC_FREE(frame);
567
568         return py_acl;
569 }
570
571 static PyMethodDef py_smbd_methods[] = {
572         { "have_posix_acls",
573                 (PyCFunction)py_smbd_have_posix_acls, METH_VARARGS,
574                 NULL },
575         { "set_simple_acl",
576                 (PyCFunction)py_smbd_set_simple_acl, METH_VARARGS,
577                 NULL },
578         { "set_nt_acl",
579                 (PyCFunction)py_smbd_set_nt_acl, METH_VARARGS,
580                 NULL },
581         { "get_nt_acl",
582                 (PyCFunction)py_smbd_get_nt_acl, METH_VARARGS,
583                 NULL },
584         { "get_sys_acl",
585                 (PyCFunction)py_smbd_get_sys_acl, METH_VARARGS,
586                 NULL },
587         { "set_sys_acl",
588                 (PyCFunction)py_smbd_set_sys_acl, METH_VARARGS,
589                 NULL },
590         { "chown",
591                 (PyCFunction)py_smbd_chown, METH_VARARGS,
592                 NULL },
593         { "unlink",
594                 (PyCFunction)py_smbd_unlink, METH_VARARGS,
595                 NULL },
596         { NULL }
597 };
598
599 void initsmbd(void);
600 void initsmbd(void)
601 {
602         PyObject *m;
603
604         m = Py_InitModule3("smbd", py_smbd_methods,
605                            "Python bindings for the smbd file server.");
606         if (m == NULL)
607                 return;
608
609 }