s3: pysmbd: Change py_smbd_mkdir() to call SMB_VFS_MKDIRAT().
[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[] = { "fname", "mode", "gid", "service", NULL };
428         char *fname, *service = NULL;
429         int ret;
430         int mode, gid = -1;
431         SMB_ACL_T acl;
432         TALLOC_CTX *frame;
433         connection_struct *conn;
434
435         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|iz",
436                                          discard_const_p(char *, kwnames),
437                                          &fname, &mode, &gid, &service))
438                 return NULL;
439
440         frame = talloc_stackframe();
441
442         acl = make_simple_acl(frame, gid, mode);
443         if (acl == NULL) {
444                 TALLOC_FREE(frame);
445                 return NULL;
446         }
447
448         conn = get_conn_tos(service, NULL);
449         if (!conn) {
450                 TALLOC_FREE(frame);
451                 return NULL;
452         }
453
454         ret = set_sys_acl_conn(fname, SMB_ACL_TYPE_ACCESS, acl, conn);
455
456         if (ret != 0) {
457                 TALLOC_FREE(frame);
458                 errno = ret;
459                 return PyErr_SetFromErrno(PyExc_OSError);
460         }
461
462         TALLOC_FREE(frame);
463
464         Py_RETURN_NONE;
465 }
466
467 /*
468   chown a file
469  */
470 static PyObject *py_smbd_chown(PyObject *self, PyObject *args, PyObject *kwargs)
471 {
472         const char * const kwnames[] = { "fname", "uid", "gid", "service", NULL };
473         connection_struct *conn;
474         int ret;
475
476         char *fname, *service = NULL;
477         int uid, gid;
478         TALLOC_CTX *frame;
479         struct smb_filename *smb_fname = NULL;
480
481         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sii|z",
482                                          discard_const_p(char *, kwnames),
483                                          &fname, &uid, &gid, &service))
484                 return NULL;
485
486         frame = talloc_stackframe();
487
488         conn = get_conn_tos(service, NULL);
489         if (!conn) {
490                 TALLOC_FREE(frame);
491                 return NULL;
492         }
493
494         smb_fname = synthetic_smb_fname(talloc_tos(),
495                                         fname,
496                                         NULL,
497                                         NULL,
498                                         lp_posix_pathnames() ?
499                                                 SMB_FILENAME_POSIX_PATH : 0);
500         if (smb_fname == NULL) {
501                 TALLOC_FREE(frame);
502                 errno = ENOMEM;
503                 return PyErr_SetFromErrno(PyExc_OSError);
504         }
505
506         ret = SMB_VFS_CHOWN(conn, smb_fname, uid, gid);
507         if (ret != 0) {
508                 TALLOC_FREE(frame);
509                 errno = ret;
510                 return PyErr_SetFromErrno(PyExc_OSError);
511         }
512
513         TALLOC_FREE(frame);
514
515         Py_RETURN_NONE;
516 }
517
518 /*
519   unlink a file
520  */
521 static PyObject *py_smbd_unlink(PyObject *self, PyObject *args, PyObject *kwargs)
522 {
523         const char * const kwnames[] = { "fname", "service", NULL };
524         connection_struct *conn;
525         int ret;
526         struct smb_filename *smb_fname = NULL;
527         char *fname, *service = NULL;
528         TALLOC_CTX *frame;
529
530         frame = talloc_stackframe();
531
532         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|z",
533                                          discard_const_p(char *, kwnames),
534                                          &fname, &service)) {
535                 TALLOC_FREE(frame);
536                 return NULL;
537         }
538
539         conn = get_conn_tos(service, NULL);
540         if (!conn) {
541                 TALLOC_FREE(frame);
542                 return NULL;
543         }
544
545         smb_fname = synthetic_smb_fname_split(frame,
546                                         fname,
547                                         lp_posix_pathnames());
548         if (smb_fname == NULL) {
549                 TALLOC_FREE(frame);
550                 return PyErr_NoMemory();
551         }
552
553         ret = SMB_VFS_UNLINK(conn, smb_fname);
554         if (ret != 0) {
555                 TALLOC_FREE(frame);
556                 errno = ret;
557                 return PyErr_SetFromErrno(PyExc_OSError);
558         }
559
560         TALLOC_FREE(frame);
561
562         Py_RETURN_NONE;
563 }
564
565 /*
566   check if we have ACL support
567  */
568 static PyObject *py_smbd_have_posix_acls(PyObject *self,
569                 PyObject *Py_UNUSED(ignored))
570 {
571 #ifdef HAVE_POSIX_ACLS
572         return PyBool_FromLong(true);
573 #else
574         return PyBool_FromLong(false);
575 #endif
576 }
577
578 /*
579   set the NT ACL on a file
580  */
581 static PyObject *py_smbd_set_nt_acl(PyObject *self, PyObject *args, PyObject *kwargs)
582 {
583         const char * const kwnames[] = {
584                 "fname", "security_info_sent", "sd",
585                 "service", "session_info", NULL };
586
587         NTSTATUS status;
588         char *fname, *service = NULL;
589         int security_info_sent;
590         PyObject *py_sd;
591         struct security_descriptor *sd;
592         PyObject *py_session = Py_None;
593         struct auth_session_info *session_info = NULL;
594         connection_struct *conn;
595         TALLOC_CTX *frame;
596
597         frame = talloc_stackframe();
598
599         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siO|zO",
600                                          discard_const_p(char *, kwnames),
601                                          &fname, &security_info_sent, &py_sd,
602                                          &service, &py_session)) {
603                 TALLOC_FREE(frame);
604                 return NULL;
605         }
606
607         if (!py_check_dcerpc_type(py_sd, "samba.dcerpc.security", "descriptor")) {
608                 TALLOC_FREE(frame);
609                 return NULL;
610         }
611
612         if (py_session != Py_None) {
613                 if (!py_check_dcerpc_type(py_session,
614                                           "samba.dcerpc.auth",
615                                           "session_info")) {
616                         TALLOC_FREE(frame);
617                         return NULL;
618                 }
619                 session_info = pytalloc_get_type(py_session,
620                                                  struct auth_session_info);
621                 if (!session_info) {
622                         PyErr_Format(PyExc_TypeError,
623                                      "Expected auth_session_info for session_info argument got %s",
624                                      pytalloc_get_name(py_session));
625                         return NULL;
626                 }
627         }
628
629         conn = get_conn_tos(service, session_info);
630         if (!conn) {
631                 TALLOC_FREE(frame);
632                 return NULL;
633         }
634
635         sd = pytalloc_get_type(py_sd, struct security_descriptor);
636
637         status = set_nt_acl_conn(fname, security_info_sent, sd, conn);
638         TALLOC_FREE(frame);
639         PyErr_NTSTATUS_IS_ERR_RAISE(status);
640
641         Py_RETURN_NONE;
642 }
643
644 /*
645   Return the NT ACL on a file
646  */
647 static PyObject *py_smbd_get_nt_acl(PyObject *self, PyObject *args, PyObject *kwargs)
648 {
649         const char * const kwnames[] = { "fname",
650                                          "security_info_wanted",
651                                          "service",
652                                          "session_info",
653                                          NULL };
654         char *fname, *service = NULL;
655         int security_info_wanted;
656         PyObject *py_sd;
657         struct security_descriptor *sd;
658         TALLOC_CTX *frame = talloc_stackframe();
659         PyObject *py_session = Py_None;
660         struct auth_session_info *session_info = NULL;
661         connection_struct *conn;
662         NTSTATUS status;
663         int ret = 1;
664
665         ret = PyArg_ParseTupleAndKeywords(args,
666                                           kwargs,
667                                           "si|zO",
668                                           discard_const_p(char *, kwnames),
669                                           &fname,
670                                           &security_info_wanted,
671                                           &service,
672                                           &py_session);
673         if (!ret) {
674                 TALLOC_FREE(frame);
675                 return NULL;
676         }
677
678         if (py_session != Py_None) {
679                 if (!py_check_dcerpc_type(py_session,
680                                           "samba.dcerpc.auth",
681                                           "session_info")) {
682                         TALLOC_FREE(frame);
683                         return NULL;
684                 }
685                 session_info = pytalloc_get_type(py_session,
686                                                  struct auth_session_info);
687                 if (!session_info) {
688                         PyErr_Format(
689                                 PyExc_TypeError,
690                                 "Expected auth_session_info for "
691                                 "session_info argument got %s",
692                                 pytalloc_get_name(py_session));
693                         return NULL;
694                 }
695         }
696
697         conn = get_conn_tos(service, session_info);
698         if (!conn) {
699                 TALLOC_FREE(frame);
700                 return NULL;
701         }
702
703         status = get_nt_acl_conn(frame, fname, conn, security_info_wanted, &sd);
704         PyErr_NTSTATUS_IS_ERR_RAISE(status);
705
706         py_sd = py_return_ndr_struct("samba.dcerpc.security", "descriptor", sd, sd);
707
708         TALLOC_FREE(frame);
709
710         return py_sd;
711 }
712
713 /*
714   set the posix (or similar) ACL on a file
715  */
716 static PyObject *py_smbd_set_sys_acl(PyObject *self, PyObject *args, PyObject *kwargs)
717 {
718         const char * const kwnames[] = { "fname", "acl_type", "acl", "service", NULL };
719         TALLOC_CTX *frame = talloc_stackframe();
720         int ret;
721         char *fname, *service = NULL;
722         PyObject *py_acl;
723         struct smb_acl_t *acl;
724         int acl_type;
725         connection_struct *conn;
726
727         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siO|z",
728                                          discard_const_p(char *, kwnames),
729                                          &fname, &acl_type, &py_acl, &service)) {
730                 TALLOC_FREE(frame);
731                 return NULL;
732         }
733
734         if (!py_check_dcerpc_type(py_acl, "samba.dcerpc.smb_acl", "t")) {
735                 TALLOC_FREE(frame);
736                 return NULL;
737         }
738
739         conn = get_conn_tos(service, NULL);
740         if (!conn) {
741                 TALLOC_FREE(frame);
742                 return NULL;
743         }
744
745         acl = pytalloc_get_type(py_acl, struct smb_acl_t);
746
747         ret = set_sys_acl_conn(fname, acl_type, acl, conn);
748         if (ret != 0) {
749                 TALLOC_FREE(frame);
750                 errno = ret;
751                 return PyErr_SetFromErrno(PyExc_OSError);
752         }
753
754         TALLOC_FREE(frame);
755         Py_RETURN_NONE;
756 }
757
758 /*
759   Return the posix (or similar) ACL on a file
760  */
761 static PyObject *py_smbd_get_sys_acl(PyObject *self, PyObject *args, PyObject *kwargs)
762 {
763         const char * const kwnames[] = { "fname", "acl_type", "service", NULL };
764         char *fname;
765         PyObject *py_acl;
766         struct smb_acl_t *acl;
767         int acl_type;
768         TALLOC_CTX *frame = talloc_stackframe();
769         connection_struct *conn;
770         char *service = NULL;
771         struct smb_filename *smb_fname = NULL;
772
773         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|z",
774                                          discard_const_p(char *, kwnames),
775                                          &fname, &acl_type, &service)) {
776                 TALLOC_FREE(frame);
777                 return NULL;
778         }
779
780         conn = get_conn_tos(service, NULL);
781         if (!conn) {
782                 TALLOC_FREE(frame);
783                 return NULL;
784         }
785
786         smb_fname = synthetic_smb_fname_split(frame,
787                                         fname,
788                                         lp_posix_pathnames());
789         if (smb_fname == NULL) {
790                 TALLOC_FREE(frame);
791                 return NULL;
792         }
793         acl = SMB_VFS_SYS_ACL_GET_FILE( conn, smb_fname, acl_type, frame);
794         if (!acl) {
795                 TALLOC_FREE(frame);
796                 return PyErr_SetFromErrno(PyExc_OSError);
797         }
798
799         py_acl = py_return_ndr_struct("samba.dcerpc.smb_acl", "t", acl, acl);
800
801         TALLOC_FREE(frame);
802
803         return py_acl;
804 }
805
806 static PyObject *py_smbd_mkdir(PyObject *self, PyObject *args, PyObject *kwargs)
807 {
808         const char * const kwnames[] = { "fname", "service", NULL };
809         char *fname, *service = NULL;
810         TALLOC_CTX *frame = talloc_stackframe();
811         struct connection_struct *conn = NULL;
812         struct smb_filename *smb_fname = NULL;
813         int ret;
814         mode_t saved_umask;
815
816         if (!PyArg_ParseTupleAndKeywords(args,
817                                          kwargs,
818                                          "s|z",
819                                          discard_const_p(char *,
820                                                          kwnames),
821                                          &fname,
822                                          &service)) {
823                 TALLOC_FREE(frame);
824                 return NULL;
825         }
826
827         conn = get_conn_tos(service, NULL);
828         if (!conn) {
829                 TALLOC_FREE(frame);
830                 return NULL;
831         }
832
833         smb_fname = synthetic_smb_fname(talloc_tos(),
834                                         fname,
835                                         NULL,
836                                         NULL,
837                                         lp_posix_pathnames() ?
838                                         SMB_FILENAME_POSIX_PATH : 0);
839
840         if (smb_fname == NULL) {
841                 TALLOC_FREE(frame);
842                 return NULL;
843         }
844
845         /* we want total control over the permissions on created files,
846            so set our umask to 0 */
847         saved_umask = umask(0);
848
849         ret = SMB_VFS_MKDIRAT(conn,
850                         conn->cwd_fsp,
851                         smb_fname,
852                         00755);
853
854         umask(saved_umask);
855
856         if (ret == -1) {
857                 DBG_ERR("mkdirat error=%d (%s)\n", errno, strerror(errno));
858                 TALLOC_FREE(frame);
859                 return NULL;
860         }
861
862         TALLOC_FREE(frame);
863         Py_RETURN_NONE;
864 }
865
866
867 /*
868   Create an empty file
869  */
870 static PyObject *py_smbd_create_file(PyObject *self, PyObject *args, PyObject *kwargs)
871 {
872         const char * const kwnames[] = { "fname", "service", NULL };
873         char *fname, *service = NULL;
874         TALLOC_CTX *frame = talloc_stackframe();
875         struct connection_struct *conn = NULL;
876         struct files_struct *fsp = NULL;
877         NTSTATUS status;
878
879         if (!PyArg_ParseTupleAndKeywords(args,
880                                          kwargs,
881                                          "s|z",
882                                          discard_const_p(char *,
883                                                          kwnames),
884                                          &fname,
885                                          &service)) {
886                 TALLOC_FREE(frame);
887                 return NULL;
888         }
889
890         conn = get_conn_tos(service, NULL);
891         if (!conn) {
892                 TALLOC_FREE(frame);
893                 return NULL;
894         }
895
896         status = init_files_struct(frame,
897                                    fname,
898                                    conn,
899                                    O_CREAT|O_EXCL|O_RDWR,
900                                    &fsp);
901         if (!NT_STATUS_IS_OK(status)) {
902                 DBG_ERR("init_files_struct failed: %s\n",
903                         nt_errstr(status));
904         }
905
906         TALLOC_FREE(frame);
907         Py_RETURN_NONE;
908 }
909
910
911 static PyMethodDef py_smbd_methods[] = {
912         { "have_posix_acls",
913                 (PyCFunction)py_smbd_have_posix_acls, METH_NOARGS,
914                 NULL },
915         { "set_simple_acl",
916                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_set_simple_acl),
917                 METH_VARARGS|METH_KEYWORDS,
918                 NULL },
919         { "set_nt_acl",
920                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_set_nt_acl),
921                 METH_VARARGS|METH_KEYWORDS,
922                 NULL },
923         { "get_nt_acl",
924                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_get_nt_acl),
925                 METH_VARARGS|METH_KEYWORDS,
926                 NULL },
927         { "get_sys_acl",
928                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_get_sys_acl),
929                 METH_VARARGS|METH_KEYWORDS,
930                 NULL },
931         { "set_sys_acl",
932                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_set_sys_acl),
933                 METH_VARARGS|METH_KEYWORDS,
934                 NULL },
935         { "chown",
936                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_chown),
937                 METH_VARARGS|METH_KEYWORDS,
938                 NULL },
939         { "unlink",
940                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_unlink),
941                 METH_VARARGS|METH_KEYWORDS,
942                 NULL },
943         { "mkdir",
944                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_mkdir),
945                 METH_VARARGS|METH_KEYWORDS,
946                 NULL },
947         { "create_file",
948                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_create_file),
949                 METH_VARARGS|METH_KEYWORDS,
950                 NULL },
951         { NULL }
952 };
953
954 void initsmbd(void);
955
956 static struct PyModuleDef moduledef = {
957     PyModuleDef_HEAD_INIT,
958     .m_name = "smbd",
959     .m_doc = "Python bindings for the smbd file server.",
960     .m_size = -1,
961     .m_methods = py_smbd_methods,
962 };
963
964 MODULE_INIT_FUNC(smbd)
965 {
966         PyObject *m = NULL;
967
968         m = PyModule_Create(&moduledef);
969         return m;
970 }