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