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