pysmbd: reformat py_smbd_set_simple_acl() kwnames and PyArg_ParseTupleAndKeywords...
[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 "python/py3compat.h"
29 #include "python/modules.h"
30 #include "smbd/smbd.h"
31 #include "libcli/util/pyerrors.h"
32 #include "librpc/rpc/pyrpc_util.h"
33 #include <pytalloc.h>
34 #include "system/filesys.h"
35 #include "passdb.h"
36 #include "secrets.h"
37 #include "auth.h"
38
39 extern const struct generic_mapping file_generic_mapping;
40
41 #undef  DBGC_CLASS
42 #define DBGC_CLASS DBGC_ACLS
43
44 #ifdef O_DIRECTORY
45 #define DIRECTORY_FLAGS O_RDONLY|O_DIRECTORY
46 #else
47 /* POSIX allows us to open a directory with O_RDONLY. */
48 #define DIRECTORY_FLAGS O_RDONLY
49 #endif
50
51
52 static connection_struct *get_conn_tos(
53         const char *service,
54         const struct auth_session_info *session_info)
55 {
56         struct conn_struct_tos *c = NULL;
57         int snum = -1;
58         NTSTATUS status;
59         char *cwd = NULL;
60         struct smb_filename cwd_fname = {0};
61         int ret;
62
63         if (!posix_locking_init(false)) {
64                 PyErr_NoMemory();
65                 return NULL;
66         }
67
68         if (service) {
69                 snum = lp_servicenumber(service);
70                 if (snum == -1) {
71                         PyErr_SetString(PyExc_RuntimeError, "unknown service");
72                         return NULL;
73                 }
74         }
75
76         status = create_conn_struct_tos(NULL,
77                                         snum,
78                                         "/",
79                                         session_info,
80                                         &c);
81         PyErr_NTSTATUS_IS_ERR_RAISE(status);
82
83         /* Ignore read-only and share restrictions */
84         c->conn->read_only = false;
85         c->conn->share_access = SEC_RIGHTS_FILE_ALL;
86
87         /* Provided by libreplace if not present. Always mallocs. */
88         cwd = get_current_dir_name();
89         if (cwd == NULL) {
90                 PyErr_NoMemory();
91                 return NULL;
92         }
93
94         cwd_fname.base_name = cwd;
95         /*
96          * We need to call vfs_ChDir() to initialize
97          * conn->cwd_fsp correctly. Change directory
98          * to current directory (so no change for process).
99          */
100         ret = vfs_ChDir(c->conn, &cwd_fname);
101         if (ret != 0) {
102                 status = map_nt_error_from_unix(errno);
103                 SAFE_FREE(cwd);
104                 PyErr_NTSTATUS_IS_ERR_RAISE(status);
105         }
106
107         SAFE_FREE(cwd);
108
109         return c->conn;
110 }
111
112 static int set_sys_acl_conn(const char *fname,
113                                  SMB_ACL_TYPE_T acltype,
114                                  SMB_ACL_T theacl, connection_struct *conn)
115 {
116         int ret;
117         struct smb_filename *smb_fname = NULL;
118
119         TALLOC_CTX *frame = talloc_stackframe();
120
121         smb_fname = synthetic_smb_fname_split(frame,
122                                         fname,
123                                         lp_posix_pathnames());
124         if (smb_fname == NULL) {
125                 TALLOC_FREE(frame);
126                 return -1;
127         }
128
129         ret = SMB_VFS_SYS_ACL_SET_FILE( conn, smb_fname, acltype, theacl);
130
131         TALLOC_FREE(frame);
132         return ret;
133 }
134
135
136 static NTSTATUS init_files_struct(TALLOC_CTX *mem_ctx,
137                                   const char *fname,
138                                   struct connection_struct *conn,
139                                   int flags,
140                                   struct files_struct **_fsp)
141 {
142         struct smb_filename *smb_fname = NULL;
143         int ret;
144         mode_t saved_umask;
145         struct files_struct *fsp;
146
147         fsp = talloc_zero(mem_ctx, struct files_struct);
148         if (fsp == NULL) {
149                 return NT_STATUS_NO_MEMORY;
150         }
151         fsp->fh = talloc(fsp, struct fd_handle);
152         if (fsp->fh == NULL) {
153                 return NT_STATUS_NO_MEMORY;
154         }
155         fsp->conn = conn;
156
157         smb_fname = synthetic_smb_fname_split(fsp,
158                                               fname,
159                                               lp_posix_pathnames());
160         if (smb_fname == NULL) {
161                 return NT_STATUS_NO_MEMORY;
162         }
163
164         fsp->fsp_name = smb_fname;
165
166         /*
167          * we want total control over the permissions on created files,
168          * so set our umask to 0 (this matters if flags contains O_CREAT)
169          */
170         saved_umask = umask(0);
171
172         fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, 00644);
173
174         umask(saved_umask);
175
176         if (fsp->fh->fd == -1) {
177                 int err = errno;
178                 if (err == ENOENT) {
179                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
180                 }
181                 return NT_STATUS_INVALID_PARAMETER;
182         }
183
184         ret = SMB_VFS_FSTAT(fsp, &smb_fname->st);
185         if (ret == -1) {
186                 /* If we have an fd, this stat should succeed. */
187                 DEBUG(0,("Error doing fstat on open file %s (%s)\n",
188                          smb_fname_str_dbg(smb_fname),
189                          strerror(errno) ));
190                 return map_nt_error_from_unix(errno);
191         }
192
193         fsp->file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
194         fsp->vuid = UID_FIELD_INVALID;
195         fsp->file_pid = 0;
196         fsp->can_lock = True;
197         fsp->can_read = True;
198         fsp->can_write = True;
199         fsp->print_file = NULL;
200         fsp->modified = False;
201         fsp->sent_oplock_break = NO_BREAK_SENT;
202         fsp->is_directory = S_ISDIR(smb_fname->st.st_ex_mode);
203
204         *_fsp = fsp;
205
206         return NT_STATUS_OK;
207 }
208
209 static NTSTATUS set_nt_acl_conn(const char *fname,
210                                 uint32_t security_info_sent, const struct security_descriptor *sd,
211                                 connection_struct *conn)
212 {
213         TALLOC_CTX *frame = talloc_stackframe();
214         struct files_struct *fsp = NULL;
215         NTSTATUS status = NT_STATUS_OK;
216
217         /* first, try to open it as a file with flag O_RDWR */
218         status = init_files_struct(frame,
219                                    fname,
220                                    conn,
221                                    O_RDWR,
222                                    &fsp);
223         if (!NT_STATUS_IS_OK(status) && errno == EISDIR) {
224                 /* if fail, try to open as dir */
225                 status = init_files_struct(frame,
226                                            fname,
227                                            conn,
228                                            DIRECTORY_FLAGS,
229                                            &fsp);
230         }
231
232         if (!NT_STATUS_IS_OK(status)) {
233                 DBG_ERR("init_files_struct failed: %s\n",
234                         nt_errstr(status));
235                 if (fsp != NULL) {
236                         SMB_VFS_CLOSE(fsp);
237                 }
238                 TALLOC_FREE(frame);
239                 return status;
240         }
241
242         status = SMB_VFS_FSET_NT_ACL(fsp, security_info_sent, sd);
243         if (!NT_STATUS_IS_OK(status)) {
244                 DEBUG(0,("set_nt_acl_no_snum: fset_nt_acl returned %s.\n", nt_errstr(status)));
245         }
246
247         SMB_VFS_CLOSE(fsp);
248
249         TALLOC_FREE(frame);
250         return status;
251 }
252
253 static NTSTATUS get_nt_acl_conn(TALLOC_CTX *mem_ctx,
254                                 const char *fname,
255                                 connection_struct *conn,
256                                 uint32_t security_info_wanted,
257                                 struct security_descriptor **sd)
258 {
259         TALLOC_CTX *frame = talloc_stackframe();
260         NTSTATUS status;
261         struct smb_filename *smb_fname = synthetic_smb_fname(talloc_tos(),
262                                         fname,
263                                         NULL,
264                                         NULL,
265                                         lp_posix_pathnames() ?
266                                                 SMB_FILENAME_POSIX_PATH : 0);
267
268         if (smb_fname == NULL) {
269                 TALLOC_FREE(frame);
270                 return NT_STATUS_NO_MEMORY;
271         }
272
273         status = SMB_VFS_GET_NT_ACL(conn,
274                                 smb_fname,
275                                 security_info_wanted,
276                                 mem_ctx,
277                                 sd);
278         if (!NT_STATUS_IS_OK(status)) {
279                 DEBUG(0,("get_nt_acl_conn: get_nt_acl returned %s.\n", nt_errstr(status)));
280         }
281
282         TALLOC_FREE(frame);
283
284         return status;
285 }
286
287 static int set_acl_entry_perms(SMB_ACL_ENTRY_T entry, mode_t perm_mask)
288 {
289         SMB_ACL_PERMSET_T perms = NULL;
290
291         if (sys_acl_get_permset(entry, &perms) != 0) {
292                 return -1;
293         }
294
295         if (sys_acl_clear_perms(perms) != 0) {
296                 return -1;
297         }
298
299         if ((perm_mask & SMB_ACL_READ) != 0 &&
300             sys_acl_add_perm(perms, SMB_ACL_READ) != 0) {
301                 return -1;
302         }
303
304         if ((perm_mask & SMB_ACL_WRITE) != 0 &&
305             sys_acl_add_perm(perms, SMB_ACL_WRITE) != 0) {
306                 return -1;
307         }
308
309         if ((perm_mask & SMB_ACL_EXECUTE) != 0 &&
310             sys_acl_add_perm(perms, SMB_ACL_EXECUTE) != 0) {
311                 return -1;
312         }
313
314         if (sys_acl_set_permset(entry, perms) != 0) {
315                 return -1;
316         }
317
318         return 0;
319 }
320
321 static SMB_ACL_T make_simple_acl(TALLOC_CTX *mem_ctx,
322                         gid_t gid,
323                         mode_t chmod_mode)
324 {
325         mode_t mode = SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE;
326
327         mode_t mode_user = (chmod_mode & 0700) >> 6;
328         mode_t mode_group = (chmod_mode & 070) >> 3;
329         mode_t mode_other = chmod_mode &  07;
330         SMB_ACL_ENTRY_T entry;
331         SMB_ACL_T acl = sys_acl_init(mem_ctx);
332
333         if (!acl) {
334                 return NULL;
335         }
336
337         if (sys_acl_create_entry(&acl, &entry) != 0) {
338                 TALLOC_FREE(acl);
339                 return NULL;
340         }
341
342         if (sys_acl_set_tag_type(entry, SMB_ACL_USER_OBJ) != 0) {
343                 TALLOC_FREE(acl);
344                 return NULL;
345         }
346
347         if (set_acl_entry_perms(entry, mode_user) != 0) {
348                 TALLOC_FREE(acl);
349                 return NULL;
350         }
351
352         if (sys_acl_create_entry(&acl, &entry) != 0) {
353                 TALLOC_FREE(acl);
354                 return NULL;
355         }
356
357         if (sys_acl_set_tag_type(entry, SMB_ACL_GROUP_OBJ) != 0) {
358                 TALLOC_FREE(acl);
359                 return NULL;
360         }
361
362         if (set_acl_entry_perms(entry, mode_group) != 0) {
363                 TALLOC_FREE(acl);
364                 return NULL;
365         }
366
367         if (sys_acl_create_entry(&acl, &entry) != 0) {
368                 TALLOC_FREE(acl);
369                 return NULL;
370         }
371
372         if (sys_acl_set_tag_type(entry, SMB_ACL_OTHER) != 0) {
373                 TALLOC_FREE(acl);
374                 return NULL;
375         }
376
377         if (set_acl_entry_perms(entry, mode_other) != 0) {
378                 TALLOC_FREE(acl);
379                 return NULL;
380         }
381
382         if (gid != -1) {
383                 if (sys_acl_create_entry(&acl, &entry) != 0) {
384                         TALLOC_FREE(acl);
385                         return NULL;
386                 }
387
388                 if (sys_acl_set_tag_type(entry, SMB_ACL_GROUP) != 0) {
389                         TALLOC_FREE(acl);
390                         return NULL;
391                 }
392
393                 if (sys_acl_set_qualifier(entry, &gid) != 0) {
394                         TALLOC_FREE(acl);
395                         return NULL;
396                 }
397
398                 if (set_acl_entry_perms(entry, mode_group) != 0) {
399                         TALLOC_FREE(acl);
400                         return NULL;
401                 }
402         }
403
404         if (sys_acl_create_entry(&acl, &entry) != 0) {
405                 TALLOC_FREE(acl);
406                 return NULL;
407         }
408
409         if (sys_acl_set_tag_type(entry, SMB_ACL_MASK) != 0) {
410                 TALLOC_FREE(acl);
411                 return NULL;
412         }
413
414         if (set_acl_entry_perms(entry, mode) != 0) {
415                 TALLOC_FREE(acl);
416                 return NULL;
417         }
418
419         return acl;
420 }
421
422 /*
423   set a simple ACL on a file, as a test
424  */
425 static PyObject *py_smbd_set_simple_acl(PyObject *self, PyObject *args, PyObject *kwargs)
426 {
427         const char * const kwnames[] = {
428                 "fname",
429                 "mode",
430                 "gid",
431                 "service",
432                 NULL
433         };
434         char *fname, *service = NULL;
435         int ret;
436         int mode, gid = -1;
437         SMB_ACL_T acl;
438         TALLOC_CTX *frame;
439         connection_struct *conn;
440
441         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|iz",
442                                          discard_const_p(char *, kwnames),
443                                          &fname,
444                                          &mode,
445                                          &gid,
446                                          &service))
447                 return NULL;
448
449         frame = talloc_stackframe();
450
451         acl = make_simple_acl(frame, gid, mode);
452         if (acl == NULL) {
453                 TALLOC_FREE(frame);
454                 return NULL;
455         }
456
457         conn = get_conn_tos(service, NULL);
458         if (!conn) {
459                 TALLOC_FREE(frame);
460                 return NULL;
461         }
462
463         ret = set_sys_acl_conn(fname, SMB_ACL_TYPE_ACCESS, acl, conn);
464
465         if (ret != 0) {
466                 TALLOC_FREE(frame);
467                 errno = ret;
468                 return PyErr_SetFromErrno(PyExc_OSError);
469         }
470
471         TALLOC_FREE(frame);
472
473         Py_RETURN_NONE;
474 }
475
476 /*
477   chown a file
478  */
479 static PyObject *py_smbd_chown(PyObject *self, PyObject *args, PyObject *kwargs)
480 {
481         const char * const kwnames[] = { "fname", "uid", "gid", "service", NULL };
482         connection_struct *conn;
483         int ret;
484         NTSTATUS status;
485         char *fname, *service = NULL;
486         int uid, gid;
487         TALLOC_CTX *frame;
488         struct files_struct *fsp = NULL;
489
490         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sii|z",
491                                          discard_const_p(char *, kwnames),
492                                          &fname, &uid, &gid, &service))
493                 return NULL;
494
495         frame = talloc_stackframe();
496
497         conn = get_conn_tos(service, NULL);
498         if (!conn) {
499                 TALLOC_FREE(frame);
500                 return NULL;
501         }
502
503         /* first, try to open it as a file with flag O_RDWR */
504         status = init_files_struct(frame,
505                                    fname,
506                                    conn,
507                                    O_RDWR,
508                                    &fsp);
509         if (!NT_STATUS_IS_OK(status) && errno == EISDIR) {
510                 /* if fail, try to open as dir */
511                 status = init_files_struct(frame,
512                                            fname,
513                                            conn,
514                                            DIRECTORY_FLAGS,
515                                            &fsp);
516         }
517
518         if (!NT_STATUS_IS_OK(status)) {
519                 DBG_ERR("init_files_struct failed: %s\n",
520                         nt_errstr(status));
521                 if (fsp != NULL) {
522                         SMB_VFS_CLOSE(fsp);
523                 }
524                 TALLOC_FREE(frame);
525                 /*
526                  * The following macro raises a python
527                  * error then returns NULL.
528                  */
529                 PyErr_NTSTATUS_IS_ERR_RAISE(status);
530         }
531
532         ret = SMB_VFS_FCHOWN(fsp, uid, gid);
533         if (ret != 0) {
534                 int saved_errno = errno;
535                 SMB_VFS_CLOSE(fsp);
536                 TALLOC_FREE(frame);
537                 errno = saved_errno;
538                 return PyErr_SetFromErrno(PyExc_OSError);
539         }
540
541         SMB_VFS_CLOSE(fsp);
542         TALLOC_FREE(frame);
543
544         Py_RETURN_NONE;
545 }
546
547 /*
548   unlink a file
549  */
550 static PyObject *py_smbd_unlink(PyObject *self, PyObject *args, PyObject *kwargs)
551 {
552         const char * const kwnames[] = { "fname", "service", NULL };
553         connection_struct *conn;
554         int ret;
555         struct smb_filename *smb_fname = NULL;
556         char *fname, *service = NULL;
557         TALLOC_CTX *frame;
558
559         frame = talloc_stackframe();
560
561         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|z",
562                                          discard_const_p(char *, kwnames),
563                                          &fname, &service)) {
564                 TALLOC_FREE(frame);
565                 return NULL;
566         }
567
568         conn = get_conn_tos(service, NULL);
569         if (!conn) {
570                 TALLOC_FREE(frame);
571                 return NULL;
572         }
573
574         smb_fname = synthetic_smb_fname_split(frame,
575                                         fname,
576                                         lp_posix_pathnames());
577         if (smb_fname == NULL) {
578                 TALLOC_FREE(frame);
579                 return PyErr_NoMemory();
580         }
581
582         ret = SMB_VFS_UNLINKAT(conn,
583                         conn->cwd_fsp,
584                         smb_fname,
585                         0);
586         if (ret != 0) {
587                 TALLOC_FREE(frame);
588                 errno = ret;
589                 return PyErr_SetFromErrno(PyExc_OSError);
590         }
591
592         TALLOC_FREE(frame);
593
594         Py_RETURN_NONE;
595 }
596
597 /*
598   check if we have ACL support
599  */
600 static PyObject *py_smbd_have_posix_acls(PyObject *self,
601                 PyObject *Py_UNUSED(ignored))
602 {
603 #ifdef HAVE_POSIX_ACLS
604         return PyBool_FromLong(true);
605 #else
606         return PyBool_FromLong(false);
607 #endif
608 }
609
610 /*
611   set the NT ACL on a file
612  */
613 static PyObject *py_smbd_set_nt_acl(PyObject *self, PyObject *args, PyObject *kwargs)
614 {
615         const char * const kwnames[] = {
616                 "fname", "security_info_sent", "sd",
617                 "service", "session_info", NULL };
618
619         NTSTATUS status;
620         char *fname, *service = NULL;
621         int security_info_sent;
622         PyObject *py_sd;
623         struct security_descriptor *sd;
624         PyObject *py_session = Py_None;
625         struct auth_session_info *session_info = NULL;
626         connection_struct *conn;
627         TALLOC_CTX *frame;
628
629         frame = talloc_stackframe();
630
631         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siO|zO",
632                                          discard_const_p(char *, kwnames),
633                                          &fname, &security_info_sent, &py_sd,
634                                          &service, &py_session)) {
635                 TALLOC_FREE(frame);
636                 return NULL;
637         }
638
639         if (!py_check_dcerpc_type(py_sd, "samba.dcerpc.security", "descriptor")) {
640                 TALLOC_FREE(frame);
641                 return NULL;
642         }
643
644         if (py_session != Py_None) {
645                 if (!py_check_dcerpc_type(py_session,
646                                           "samba.dcerpc.auth",
647                                           "session_info")) {
648                         TALLOC_FREE(frame);
649                         return NULL;
650                 }
651                 session_info = pytalloc_get_type(py_session,
652                                                  struct auth_session_info);
653                 if (!session_info) {
654                         PyErr_Format(PyExc_TypeError,
655                                      "Expected auth_session_info for session_info argument got %s",
656                                      pytalloc_get_name(py_session));
657                         return NULL;
658                 }
659         }
660
661         conn = get_conn_tos(service, session_info);
662         if (!conn) {
663                 TALLOC_FREE(frame);
664                 return NULL;
665         }
666
667         sd = pytalloc_get_type(py_sd, struct security_descriptor);
668
669         status = set_nt_acl_conn(fname, security_info_sent, sd, conn);
670         TALLOC_FREE(frame);
671         PyErr_NTSTATUS_IS_ERR_RAISE(status);
672
673         Py_RETURN_NONE;
674 }
675
676 /*
677   Return the NT ACL on a file
678  */
679 static PyObject *py_smbd_get_nt_acl(PyObject *self, PyObject *args, PyObject *kwargs)
680 {
681         const char * const kwnames[] = { "fname",
682                                          "security_info_wanted",
683                                          "service",
684                                          "session_info",
685                                          NULL };
686         char *fname, *service = NULL;
687         int security_info_wanted;
688         PyObject *py_sd;
689         struct security_descriptor *sd;
690         TALLOC_CTX *frame = talloc_stackframe();
691         PyObject *py_session = Py_None;
692         struct auth_session_info *session_info = NULL;
693         connection_struct *conn;
694         NTSTATUS status;
695         int ret = 1;
696
697         ret = PyArg_ParseTupleAndKeywords(args,
698                                           kwargs,
699                                           "si|zO",
700                                           discard_const_p(char *, kwnames),
701                                           &fname,
702                                           &security_info_wanted,
703                                           &service,
704                                           &py_session);
705         if (!ret) {
706                 TALLOC_FREE(frame);
707                 return NULL;
708         }
709
710         if (py_session != Py_None) {
711                 if (!py_check_dcerpc_type(py_session,
712                                           "samba.dcerpc.auth",
713                                           "session_info")) {
714                         TALLOC_FREE(frame);
715                         return NULL;
716                 }
717                 session_info = pytalloc_get_type(py_session,
718                                                  struct auth_session_info);
719                 if (!session_info) {
720                         PyErr_Format(
721                                 PyExc_TypeError,
722                                 "Expected auth_session_info for "
723                                 "session_info argument got %s",
724                                 pytalloc_get_name(py_session));
725                         return NULL;
726                 }
727         }
728
729         conn = get_conn_tos(service, session_info);
730         if (!conn) {
731                 TALLOC_FREE(frame);
732                 return NULL;
733         }
734
735         status = get_nt_acl_conn(frame, fname, conn, security_info_wanted, &sd);
736         PyErr_NTSTATUS_IS_ERR_RAISE(status);
737
738         py_sd = py_return_ndr_struct("samba.dcerpc.security", "descriptor", sd, sd);
739
740         TALLOC_FREE(frame);
741
742         return py_sd;
743 }
744
745 /*
746   set the posix (or similar) ACL on a file
747  */
748 static PyObject *py_smbd_set_sys_acl(PyObject *self, PyObject *args, PyObject *kwargs)
749 {
750         const char * const kwnames[] = { "fname", "acl_type", "acl", "service", NULL };
751         TALLOC_CTX *frame = talloc_stackframe();
752         int ret;
753         char *fname, *service = NULL;
754         PyObject *py_acl;
755         struct smb_acl_t *acl;
756         int acl_type;
757         connection_struct *conn;
758
759         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siO|z",
760                                          discard_const_p(char *, kwnames),
761                                          &fname, &acl_type, &py_acl, &service)) {
762                 TALLOC_FREE(frame);
763                 return NULL;
764         }
765
766         if (!py_check_dcerpc_type(py_acl, "samba.dcerpc.smb_acl", "t")) {
767                 TALLOC_FREE(frame);
768                 return NULL;
769         }
770
771         conn = get_conn_tos(service, NULL);
772         if (!conn) {
773                 TALLOC_FREE(frame);
774                 return NULL;
775         }
776
777         acl = pytalloc_get_type(py_acl, struct smb_acl_t);
778
779         ret = set_sys_acl_conn(fname, acl_type, acl, conn);
780         if (ret != 0) {
781                 TALLOC_FREE(frame);
782                 errno = ret;
783                 return PyErr_SetFromErrno(PyExc_OSError);
784         }
785
786         TALLOC_FREE(frame);
787         Py_RETURN_NONE;
788 }
789
790 /*
791   Return the posix (or similar) ACL on a file
792  */
793 static PyObject *py_smbd_get_sys_acl(PyObject *self, PyObject *args, PyObject *kwargs)
794 {
795         const char * const kwnames[] = { "fname", "acl_type", "service", NULL };
796         char *fname;
797         PyObject *py_acl;
798         struct smb_acl_t *acl;
799         int acl_type;
800         TALLOC_CTX *frame = talloc_stackframe();
801         connection_struct *conn;
802         char *service = NULL;
803         struct smb_filename *smb_fname = NULL;
804
805         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|z",
806                                          discard_const_p(char *, kwnames),
807                                          &fname, &acl_type, &service)) {
808                 TALLOC_FREE(frame);
809                 return NULL;
810         }
811
812         conn = get_conn_tos(service, NULL);
813         if (!conn) {
814                 TALLOC_FREE(frame);
815                 return NULL;
816         }
817
818         smb_fname = synthetic_smb_fname_split(frame,
819                                         fname,
820                                         lp_posix_pathnames());
821         if (smb_fname == NULL) {
822                 TALLOC_FREE(frame);
823                 return NULL;
824         }
825         acl = SMB_VFS_SYS_ACL_GET_FILE( conn, smb_fname, acl_type, frame);
826         if (!acl) {
827                 TALLOC_FREE(frame);
828                 return PyErr_SetFromErrno(PyExc_OSError);
829         }
830
831         py_acl = py_return_ndr_struct("samba.dcerpc.smb_acl", "t", acl, acl);
832
833         TALLOC_FREE(frame);
834
835         return py_acl;
836 }
837
838 static PyObject *py_smbd_mkdir(PyObject *self, PyObject *args, PyObject *kwargs)
839 {
840         const char * const kwnames[] = { "fname", "service", NULL };
841         char *fname, *service = NULL;
842         TALLOC_CTX *frame = talloc_stackframe();
843         struct connection_struct *conn = NULL;
844         struct smb_filename *smb_fname = NULL;
845         int ret;
846         mode_t saved_umask;
847
848         if (!PyArg_ParseTupleAndKeywords(args,
849                                          kwargs,
850                                          "s|z",
851                                          discard_const_p(char *,
852                                                          kwnames),
853                                          &fname,
854                                          &service)) {
855                 TALLOC_FREE(frame);
856                 return NULL;
857         }
858
859         conn = get_conn_tos(service, NULL);
860         if (!conn) {
861                 TALLOC_FREE(frame);
862                 return NULL;
863         }
864
865         smb_fname = synthetic_smb_fname(talloc_tos(),
866                                         fname,
867                                         NULL,
868                                         NULL,
869                                         lp_posix_pathnames() ?
870                                         SMB_FILENAME_POSIX_PATH : 0);
871
872         if (smb_fname == NULL) {
873                 TALLOC_FREE(frame);
874                 return NULL;
875         }
876
877         /* we want total control over the permissions on created files,
878            so set our umask to 0 */
879         saved_umask = umask(0);
880
881         ret = SMB_VFS_MKDIRAT(conn,
882                         conn->cwd_fsp,
883                         smb_fname,
884                         00755);
885
886         umask(saved_umask);
887
888         if (ret == -1) {
889                 DBG_ERR("mkdirat error=%d (%s)\n", errno, strerror(errno));
890                 TALLOC_FREE(frame);
891                 return NULL;
892         }
893
894         TALLOC_FREE(frame);
895         Py_RETURN_NONE;
896 }
897
898
899 /*
900   Create an empty file
901  */
902 static PyObject *py_smbd_create_file(PyObject *self, PyObject *args, PyObject *kwargs)
903 {
904         const char * const kwnames[] = { "fname", "service", NULL };
905         char *fname, *service = NULL;
906         TALLOC_CTX *frame = talloc_stackframe();
907         struct connection_struct *conn = NULL;
908         struct files_struct *fsp = NULL;
909         NTSTATUS status;
910
911         if (!PyArg_ParseTupleAndKeywords(args,
912                                          kwargs,
913                                          "s|z",
914                                          discard_const_p(char *,
915                                                          kwnames),
916                                          &fname,
917                                          &service)) {
918                 TALLOC_FREE(frame);
919                 return NULL;
920         }
921
922         conn = get_conn_tos(service, NULL);
923         if (!conn) {
924                 TALLOC_FREE(frame);
925                 return NULL;
926         }
927
928         status = init_files_struct(frame,
929                                    fname,
930                                    conn,
931                                    O_CREAT|O_EXCL|O_RDWR,
932                                    &fsp);
933         if (!NT_STATUS_IS_OK(status)) {
934                 DBG_ERR("init_files_struct failed: %s\n",
935                         nt_errstr(status));
936         }
937
938         TALLOC_FREE(frame);
939         Py_RETURN_NONE;
940 }
941
942
943 static PyMethodDef py_smbd_methods[] = {
944         { "have_posix_acls",
945                 (PyCFunction)py_smbd_have_posix_acls, METH_NOARGS,
946                 NULL },
947         { "set_simple_acl",
948                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_set_simple_acl),
949                 METH_VARARGS|METH_KEYWORDS,
950                 NULL },
951         { "set_nt_acl",
952                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_set_nt_acl),
953                 METH_VARARGS|METH_KEYWORDS,
954                 NULL },
955         { "get_nt_acl",
956                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_get_nt_acl),
957                 METH_VARARGS|METH_KEYWORDS,
958                 NULL },
959         { "get_sys_acl",
960                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_get_sys_acl),
961                 METH_VARARGS|METH_KEYWORDS,
962                 NULL },
963         { "set_sys_acl",
964                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_set_sys_acl),
965                 METH_VARARGS|METH_KEYWORDS,
966                 NULL },
967         { "chown",
968                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_chown),
969                 METH_VARARGS|METH_KEYWORDS,
970                 NULL },
971         { "unlink",
972                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_unlink),
973                 METH_VARARGS|METH_KEYWORDS,
974                 NULL },
975         { "mkdir",
976                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_mkdir),
977                 METH_VARARGS|METH_KEYWORDS,
978                 NULL },
979         { "create_file",
980                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_create_file),
981                 METH_VARARGS|METH_KEYWORDS,
982                 NULL },
983         { NULL }
984 };
985
986 void initsmbd(void);
987
988 static struct PyModuleDef moduledef = {
989     PyModuleDef_HEAD_INIT,
990     .m_name = "smbd",
991     .m_doc = "Python bindings for the smbd file server.",
992     .m_size = -1,
993     .m_methods = py_smbd_methods,
994 };
995
996 MODULE_INIT_FUNC(smbd)
997 {
998         PyObject *m = NULL;
999
1000         m = PyModule_Create(&moduledef);
1001         return m;
1002 }