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