smbd: add twrp arg to synthetic_smb_fname()
[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->fsp_flags.can_lock = true;
197         fsp->fsp_flags.can_read = true;
198         fsp->fsp_flags.can_write = true;
199         fsp->print_file = NULL;
200         fsp->fsp_flags.modified = false;
201         fsp->sent_oplock_break = NO_BREAK_SENT;
202         fsp->fsp_flags.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                                         0,
266                                         lp_posix_pathnames() ?
267                                                 SMB_FILENAME_POSIX_PATH : 0);
268
269         if (smb_fname == NULL) {
270                 TALLOC_FREE(frame);
271                 return NT_STATUS_NO_MEMORY;
272         }
273
274         status = SMB_VFS_GET_NT_ACL(conn,
275                                 smb_fname,
276                                 security_info_wanted,
277                                 mem_ctx,
278                                 sd);
279         if (!NT_STATUS_IS_OK(status)) {
280                 DEBUG(0,("get_nt_acl_conn: get_nt_acl returned %s.\n", nt_errstr(status)));
281         }
282
283         TALLOC_FREE(frame);
284
285         return status;
286 }
287
288 static int set_acl_entry_perms(SMB_ACL_ENTRY_T entry, mode_t perm_mask)
289 {
290         SMB_ACL_PERMSET_T perms = NULL;
291
292         if (sys_acl_get_permset(entry, &perms) != 0) {
293                 return -1;
294         }
295
296         if (sys_acl_clear_perms(perms) != 0) {
297                 return -1;
298         }
299
300         if ((perm_mask & SMB_ACL_READ) != 0 &&
301             sys_acl_add_perm(perms, SMB_ACL_READ) != 0) {
302                 return -1;
303         }
304
305         if ((perm_mask & SMB_ACL_WRITE) != 0 &&
306             sys_acl_add_perm(perms, SMB_ACL_WRITE) != 0) {
307                 return -1;
308         }
309
310         if ((perm_mask & SMB_ACL_EXECUTE) != 0 &&
311             sys_acl_add_perm(perms, SMB_ACL_EXECUTE) != 0) {
312                 return -1;
313         }
314
315         if (sys_acl_set_permset(entry, perms) != 0) {
316                 return -1;
317         }
318
319         return 0;
320 }
321
322 static SMB_ACL_T make_simple_acl(TALLOC_CTX *mem_ctx,
323                         gid_t gid,
324                         mode_t chmod_mode)
325 {
326         mode_t mode = SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE;
327
328         mode_t mode_user = (chmod_mode & 0700) >> 6;
329         mode_t mode_group = (chmod_mode & 070) >> 3;
330         mode_t mode_other = chmod_mode &  07;
331         SMB_ACL_ENTRY_T entry;
332         SMB_ACL_T acl = sys_acl_init(mem_ctx);
333
334         if (!acl) {
335                 return NULL;
336         }
337
338         if (sys_acl_create_entry(&acl, &entry) != 0) {
339                 TALLOC_FREE(acl);
340                 return NULL;
341         }
342
343         if (sys_acl_set_tag_type(entry, SMB_ACL_USER_OBJ) != 0) {
344                 TALLOC_FREE(acl);
345                 return NULL;
346         }
347
348         if (set_acl_entry_perms(entry, mode_user) != 0) {
349                 TALLOC_FREE(acl);
350                 return NULL;
351         }
352
353         if (sys_acl_create_entry(&acl, &entry) != 0) {
354                 TALLOC_FREE(acl);
355                 return NULL;
356         }
357
358         if (sys_acl_set_tag_type(entry, SMB_ACL_GROUP_OBJ) != 0) {
359                 TALLOC_FREE(acl);
360                 return NULL;
361         }
362
363         if (set_acl_entry_perms(entry, mode_group) != 0) {
364                 TALLOC_FREE(acl);
365                 return NULL;
366         }
367
368         if (sys_acl_create_entry(&acl, &entry) != 0) {
369                 TALLOC_FREE(acl);
370                 return NULL;
371         }
372
373         if (sys_acl_set_tag_type(entry, SMB_ACL_OTHER) != 0) {
374                 TALLOC_FREE(acl);
375                 return NULL;
376         }
377
378         if (set_acl_entry_perms(entry, mode_other) != 0) {
379                 TALLOC_FREE(acl);
380                 return NULL;
381         }
382
383         if (gid != -1) {
384                 if (sys_acl_create_entry(&acl, &entry) != 0) {
385                         TALLOC_FREE(acl);
386                         return NULL;
387                 }
388
389                 if (sys_acl_set_tag_type(entry, SMB_ACL_GROUP) != 0) {
390                         TALLOC_FREE(acl);
391                         return NULL;
392                 }
393
394                 if (sys_acl_set_qualifier(entry, &gid) != 0) {
395                         TALLOC_FREE(acl);
396                         return NULL;
397                 }
398
399                 if (set_acl_entry_perms(entry, mode_group) != 0) {
400                         TALLOC_FREE(acl);
401                         return NULL;
402                 }
403         }
404
405         if (sys_acl_create_entry(&acl, &entry) != 0) {
406                 TALLOC_FREE(acl);
407                 return NULL;
408         }
409
410         if (sys_acl_set_tag_type(entry, SMB_ACL_MASK) != 0) {
411                 TALLOC_FREE(acl);
412                 return NULL;
413         }
414
415         if (set_acl_entry_perms(entry, mode) != 0) {
416                 TALLOC_FREE(acl);
417                 return NULL;
418         }
419
420         return acl;
421 }
422
423 /*
424   set a simple ACL on a file, as a test
425  */
426 static PyObject *py_smbd_set_simple_acl(PyObject *self, PyObject *args, PyObject *kwargs)
427 {
428         const char * const kwnames[] = {
429                 "fname",
430                 "mode",
431                 "session_info",
432                 "gid",
433                 "service",
434                 NULL
435         };
436         char *fname, *service = NULL;
437         PyObject *py_session = Py_None;
438         struct auth_session_info *session_info = NULL;
439         int ret;
440         int mode, gid = -1;
441         SMB_ACL_T acl;
442         TALLOC_CTX *frame;
443         connection_struct *conn;
444
445         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siO|iz",
446                                          discard_const_p(char *, kwnames),
447                                          &fname,
448                                          &mode,
449                                          &py_session,
450                                          &gid,
451                                          &service))
452                 return NULL;
453
454         if (!py_check_dcerpc_type(py_session,
455                                   "samba.dcerpc.auth",
456                                   "session_info")) {
457                 return NULL;
458         }
459         session_info = pytalloc_get_type(py_session,
460                                          struct auth_session_info);
461         if (session_info == NULL) {
462                 PyErr_Format(PyExc_TypeError,
463                              "Expected auth_session_info for session_info argument got %s",
464                              pytalloc_get_name(py_session));
465                 return NULL;
466         }
467
468         frame = talloc_stackframe();
469
470         acl = make_simple_acl(frame, gid, mode);
471         if (acl == NULL) {
472                 TALLOC_FREE(frame);
473                 return NULL;
474         }
475
476         conn = get_conn_tos(service, session_info);
477         if (!conn) {
478                 TALLOC_FREE(frame);
479                 return NULL;
480         }
481
482         ret = set_sys_acl_conn(fname, SMB_ACL_TYPE_ACCESS, acl, conn);
483
484         if (ret != 0) {
485                 TALLOC_FREE(frame);
486                 errno = ret;
487                 return PyErr_SetFromErrno(PyExc_OSError);
488         }
489
490         TALLOC_FREE(frame);
491
492         Py_RETURN_NONE;
493 }
494
495 /*
496   chown a file
497  */
498 static PyObject *py_smbd_chown(PyObject *self, PyObject *args, PyObject *kwargs)
499 {
500         const char * const kwnames[] = {
501                 "fname",
502                 "uid",
503                 "gid",
504                 "session_info",
505                 "service",
506                 NULL
507         };
508         connection_struct *conn;
509         int ret;
510         NTSTATUS status;
511         char *fname, *service = NULL;
512         PyObject *py_session = Py_None;
513         struct auth_session_info *session_info = NULL;
514         int uid, gid;
515         TALLOC_CTX *frame;
516         struct files_struct *fsp = NULL;
517
518         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siiO|z",
519                                          discard_const_p(char *, kwnames),
520                                          &fname,
521                                          &uid,
522                                          &gid,
523                                          &py_session,
524                                          &service))
525                 return NULL;
526
527         if (!py_check_dcerpc_type(py_session,
528                                   "samba.dcerpc.auth",
529                                   "session_info")) {
530                 return NULL;
531         }
532         session_info = pytalloc_get_type(py_session,
533                                          struct auth_session_info);
534         if (session_info == NULL) {
535                 PyErr_Format(PyExc_TypeError,
536                              "Expected auth_session_info for session_info argument got %s",
537                              pytalloc_get_name(py_session));
538                 return NULL;
539         }
540
541         frame = talloc_stackframe();
542
543         conn = get_conn_tos(service, session_info);
544         if (!conn) {
545                 TALLOC_FREE(frame);
546                 return NULL;
547         }
548
549         /* first, try to open it as a file with flag O_RDWR */
550         status = init_files_struct(frame,
551                                    fname,
552                                    conn,
553                                    O_RDWR,
554                                    &fsp);
555         if (!NT_STATUS_IS_OK(status) && errno == EISDIR) {
556                 /* if fail, try to open as dir */
557                 status = init_files_struct(frame,
558                                            fname,
559                                            conn,
560                                            DIRECTORY_FLAGS,
561                                            &fsp);
562         }
563
564         if (!NT_STATUS_IS_OK(status)) {
565                 DBG_ERR("init_files_struct failed: %s\n",
566                         nt_errstr(status));
567                 if (fsp != NULL) {
568                         SMB_VFS_CLOSE(fsp);
569                 }
570                 TALLOC_FREE(frame);
571                 /*
572                  * The following macro raises a python
573                  * error then returns NULL.
574                  */
575                 PyErr_NTSTATUS_IS_ERR_RAISE(status);
576         }
577
578         ret = SMB_VFS_FCHOWN(fsp, uid, gid);
579         if (ret != 0) {
580                 int saved_errno = errno;
581                 SMB_VFS_CLOSE(fsp);
582                 TALLOC_FREE(frame);
583                 errno = saved_errno;
584                 return PyErr_SetFromErrno(PyExc_OSError);
585         }
586
587         SMB_VFS_CLOSE(fsp);
588         TALLOC_FREE(frame);
589
590         Py_RETURN_NONE;
591 }
592
593 /*
594   unlink a file
595  */
596 static PyObject *py_smbd_unlink(PyObject *self, PyObject *args, PyObject *kwargs)
597 {
598         const char * const kwnames[] = {
599                 "fname",
600                 "session_info",
601                 "service",
602                 NULL
603         };
604         connection_struct *conn;
605         int ret;
606         struct smb_filename *smb_fname = NULL;
607         PyObject *py_session = Py_None;
608         struct auth_session_info *session_info = NULL;
609         char *fname, *service = NULL;
610         TALLOC_CTX *frame;
611
612         frame = talloc_stackframe();
613
614         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|z",
615                                          discard_const_p(char *, kwnames),
616                                          &fname,
617                                          &py_session ,
618                                          &service)) {
619                 TALLOC_FREE(frame);
620                 return NULL;
621         }
622
623         if (!py_check_dcerpc_type(py_session,
624                                   "samba.dcerpc.auth",
625                                   "session_info")) {
626                 TALLOC_FREE(frame);
627                 return NULL;
628         }
629         session_info = pytalloc_get_type(py_session,
630                                          struct auth_session_info);
631         if (session_info == NULL) {
632                 PyErr_Format(PyExc_TypeError,
633                              "Expected auth_session_info for session_info argument got %s",
634                              pytalloc_get_name(py_session));
635                 TALLOC_FREE(frame);
636                 return NULL;
637         }
638
639         conn = get_conn_tos(service, session_info);
640         if (!conn) {
641                 TALLOC_FREE(frame);
642                 return NULL;
643         }
644
645         smb_fname = synthetic_smb_fname_split(frame,
646                                         fname,
647                                         lp_posix_pathnames());
648         if (smb_fname == NULL) {
649                 TALLOC_FREE(frame);
650                 return PyErr_NoMemory();
651         }
652
653         ret = SMB_VFS_UNLINKAT(conn,
654                         conn->cwd_fsp,
655                         smb_fname,
656                         0);
657         if (ret != 0) {
658                 TALLOC_FREE(frame);
659                 errno = ret;
660                 return PyErr_SetFromErrno(PyExc_OSError);
661         }
662
663         TALLOC_FREE(frame);
664
665         Py_RETURN_NONE;
666 }
667
668 /*
669   check if we have ACL support
670  */
671 static PyObject *py_smbd_have_posix_acls(PyObject *self,
672                 PyObject *Py_UNUSED(ignored))
673 {
674 #ifdef HAVE_POSIX_ACLS
675         return PyBool_FromLong(true);
676 #else
677         return PyBool_FromLong(false);
678 #endif
679 }
680
681 /*
682   set the NT ACL on a file
683  */
684 static PyObject *py_smbd_set_nt_acl(PyObject *self, PyObject *args, PyObject *kwargs)
685 {
686         const char * const kwnames[] = {
687                 "fname",
688                 "security_info_sent",
689                 "sd",
690                 "session_info",
691                 "service",
692                 NULL
693         };
694
695         NTSTATUS status;
696         char *fname, *service = NULL;
697         int security_info_sent;
698         PyObject *py_sd;
699         struct security_descriptor *sd;
700         PyObject *py_session = Py_None;
701         struct auth_session_info *session_info = NULL;
702         connection_struct *conn;
703         TALLOC_CTX *frame;
704
705         frame = talloc_stackframe();
706
707         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siOO|z",
708                                          discard_const_p(char *, kwnames),
709                                          &fname,
710                                          &security_info_sent,
711                                          &py_sd,
712                                          &py_session,
713                                          &service)) {
714                 TALLOC_FREE(frame);
715                 return NULL;
716         }
717
718         if (!py_check_dcerpc_type(py_sd, "samba.dcerpc.security", "descriptor")) {
719                 TALLOC_FREE(frame);
720                 return NULL;
721         }
722
723         if (!py_check_dcerpc_type(py_session,
724                                   "samba.dcerpc.auth",
725                                   "session_info")) {
726                 TALLOC_FREE(frame);
727                 return NULL;
728         }
729         session_info = pytalloc_get_type(py_session,
730                                          struct auth_session_info);
731         if (session_info == NULL) {
732                 PyErr_Format(PyExc_TypeError,
733                              "Expected auth_session_info for session_info argument got %s",
734                              pytalloc_get_name(py_session));
735                 return NULL;
736         }
737
738         conn = get_conn_tos(service, session_info);
739         if (!conn) {
740                 TALLOC_FREE(frame);
741                 return NULL;
742         }
743
744         sd = pytalloc_get_type(py_sd, struct security_descriptor);
745
746         status = set_nt_acl_conn(fname, security_info_sent, sd, conn);
747         TALLOC_FREE(frame);
748         PyErr_NTSTATUS_IS_ERR_RAISE(status);
749
750         Py_RETURN_NONE;
751 }
752
753 /*
754   Return the NT ACL on a file
755  */
756 static PyObject *py_smbd_get_nt_acl(PyObject *self, PyObject *args, PyObject *kwargs)
757 {
758         const char * const kwnames[] = {
759                 "fname",
760                 "security_info_wanted",
761                 "session_info",
762                 "service",
763                 NULL
764         };
765         char *fname, *service = NULL;
766         int security_info_wanted;
767         PyObject *py_sd;
768         struct security_descriptor *sd;
769         TALLOC_CTX *frame = talloc_stackframe();
770         PyObject *py_session = Py_None;
771         struct auth_session_info *session_info = NULL;
772         connection_struct *conn;
773         NTSTATUS status;
774         int ret = 1;
775
776         ret = PyArg_ParseTupleAndKeywords(args,
777                                           kwargs,
778                                           "siO|z",
779                                           discard_const_p(char *, kwnames),
780                                           &fname,
781                                           &security_info_wanted,
782                                           &py_session,
783                                           &service);
784         if (!ret) {
785                 TALLOC_FREE(frame);
786                 return NULL;
787         }
788
789         if (!py_check_dcerpc_type(py_session,
790                                   "samba.dcerpc.auth",
791                                   "session_info")) {
792                 TALLOC_FREE(frame);
793                 return NULL;
794         }
795         session_info = pytalloc_get_type(py_session,
796                                          struct auth_session_info);
797         if (session_info == NULL) {
798                 PyErr_Format(
799                         PyExc_TypeError,
800                         "Expected auth_session_info for "
801                         "session_info argument got %s",
802                         pytalloc_get_name(py_session));
803                 return NULL;
804         }
805
806         conn = get_conn_tos(service, session_info);
807         if (!conn) {
808                 TALLOC_FREE(frame);
809                 return NULL;
810         }
811
812         status = get_nt_acl_conn(frame, fname, conn, security_info_wanted, &sd);
813         PyErr_NTSTATUS_IS_ERR_RAISE(status);
814
815         py_sd = py_return_ndr_struct("samba.dcerpc.security", "descriptor", sd, sd);
816
817         TALLOC_FREE(frame);
818
819         return py_sd;
820 }
821
822 /*
823   set the posix (or similar) ACL on a file
824  */
825 static PyObject *py_smbd_set_sys_acl(PyObject *self, PyObject *args, PyObject *kwargs)
826 {
827         const char * const kwnames[] = {
828                 "fname",
829                 "acl_type",
830                 "acl",
831                 "session_info",
832                 "service",
833                 NULL
834         };
835         TALLOC_CTX *frame = talloc_stackframe();
836         int ret;
837         char *fname, *service = NULL;
838         PyObject *py_acl;
839         PyObject *py_session = Py_None;
840         struct auth_session_info *session_info = NULL;
841         struct smb_acl_t *acl;
842         int acl_type;
843         connection_struct *conn;
844
845         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siOO|z",
846                                          discard_const_p(char *, kwnames),
847                                          &fname,
848                                          &acl_type,
849                                          &py_acl,
850                                          &py_session,
851                                          &service)) {
852                 TALLOC_FREE(frame);
853                 return NULL;
854         }
855
856         if (!py_check_dcerpc_type(py_acl, "samba.dcerpc.smb_acl", "t")) {
857                 TALLOC_FREE(frame);
858                 return NULL;
859         }
860
861         if (!py_check_dcerpc_type(py_session,
862                                   "samba.dcerpc.auth",
863                                   "session_info")) {
864                 TALLOC_FREE(frame);
865                 return NULL;
866         }
867         session_info = pytalloc_get_type(py_session,
868                                          struct auth_session_info);
869         if (session_info == NULL) {
870                 PyErr_Format(PyExc_TypeError,
871                              "Expected auth_session_info for session_info argument got %s",
872                              pytalloc_get_name(py_session));
873                 TALLOC_FREE(frame);
874                 return NULL;
875         }
876
877         conn = get_conn_tos(service, session_info);
878         if (!conn) {
879                 TALLOC_FREE(frame);
880                 return NULL;
881         }
882
883         acl = pytalloc_get_type(py_acl, struct smb_acl_t);
884
885         ret = set_sys_acl_conn(fname, acl_type, acl, conn);
886         if (ret != 0) {
887                 TALLOC_FREE(frame);
888                 errno = ret;
889                 return PyErr_SetFromErrno(PyExc_OSError);
890         }
891
892         TALLOC_FREE(frame);
893         Py_RETURN_NONE;
894 }
895
896 /*
897   Return the posix (or similar) ACL on a file
898  */
899 static PyObject *py_smbd_get_sys_acl(PyObject *self, PyObject *args, PyObject *kwargs)
900 {
901         const char * const kwnames[] = {
902                 "fname",
903                 "acl_type",
904                 "session_info",
905                 "service",
906                 NULL
907         };
908         char *fname;
909         PyObject *py_acl;
910         PyObject *py_session = Py_None;
911         struct auth_session_info *session_info = NULL;
912         struct smb_acl_t *acl;
913         int acl_type;
914         TALLOC_CTX *frame = talloc_stackframe();
915         connection_struct *conn;
916         char *service = NULL;
917         struct smb_filename *smb_fname = NULL;
918
919         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siO|z",
920                                          discard_const_p(char *, kwnames),
921                                          &fname,
922                                          &acl_type,
923                                          &py_session,
924                                          &service)) {
925                 TALLOC_FREE(frame);
926                 return NULL;
927         }
928
929         if (!py_check_dcerpc_type(py_session,
930                                   "samba.dcerpc.auth",
931                                   "session_info")) {
932                 TALLOC_FREE(frame);
933                 return NULL;
934         }
935         session_info = pytalloc_get_type(py_session,
936                                          struct auth_session_info);
937         if (session_info == NULL) {
938                 PyErr_Format(PyExc_TypeError,
939                              "Expected auth_session_info for session_info argument got %s",
940                              pytalloc_get_name(py_session));
941                 TALLOC_FREE(frame);
942                 return NULL;
943         }
944
945         conn = get_conn_tos(service, session_info);
946         if (!conn) {
947                 TALLOC_FREE(frame);
948                 return NULL;
949         }
950
951         smb_fname = synthetic_smb_fname_split(frame,
952                                         fname,
953                                         lp_posix_pathnames());
954         if (smb_fname == NULL) {
955                 TALLOC_FREE(frame);
956                 return NULL;
957         }
958         acl = SMB_VFS_SYS_ACL_GET_FILE( conn, smb_fname, acl_type, frame);
959         if (!acl) {
960                 TALLOC_FREE(frame);
961                 return PyErr_SetFromErrno(PyExc_OSError);
962         }
963
964         py_acl = py_return_ndr_struct("samba.dcerpc.smb_acl", "t", acl, acl);
965
966         TALLOC_FREE(frame);
967
968         return py_acl;
969 }
970
971 static PyObject *py_smbd_mkdir(PyObject *self, PyObject *args, PyObject *kwargs)
972 {
973         const char * const kwnames[] = {
974                 "fname",
975                 "session_info",
976                 "service",
977                 NULL
978         };
979         char *fname, *service = NULL;
980         PyObject *py_session = Py_None;
981         struct auth_session_info *session_info = NULL;
982         TALLOC_CTX *frame = talloc_stackframe();
983         struct connection_struct *conn = NULL;
984         struct smb_filename *smb_fname = NULL;
985         int ret;
986         mode_t saved_umask;
987
988         if (!PyArg_ParseTupleAndKeywords(args,
989                                          kwargs,
990                                          "sO|z",
991                                          discard_const_p(char *,
992                                                          kwnames),
993                                          &fname,
994                                          &py_session,
995                                          &service)) {
996                 TALLOC_FREE(frame);
997                 return NULL;
998         }
999
1000         if (!py_check_dcerpc_type(py_session,
1001                                   "samba.dcerpc.auth",
1002                                   "session_info")) {
1003                 TALLOC_FREE(frame);
1004                 return NULL;
1005         }
1006         session_info = pytalloc_get_type(py_session,
1007                                          struct auth_session_info);
1008         if (session_info == NULL) {
1009                 PyErr_Format(PyExc_TypeError,
1010                              "Expected auth_session_info for session_info argument got %s",
1011                              pytalloc_get_name(py_session));
1012                 TALLOC_FREE(frame);
1013                 return NULL;
1014         }
1015
1016         conn = get_conn_tos(service, session_info);
1017         if (!conn) {
1018                 TALLOC_FREE(frame);
1019                 return NULL;
1020         }
1021
1022         smb_fname = synthetic_smb_fname(talloc_tos(),
1023                                         fname,
1024                                         NULL,
1025                                         NULL,
1026                                         0,
1027                                         lp_posix_pathnames() ?
1028                                         SMB_FILENAME_POSIX_PATH : 0);
1029
1030         if (smb_fname == NULL) {
1031                 TALLOC_FREE(frame);
1032                 return NULL;
1033         }
1034
1035         /* we want total control over the permissions on created files,
1036            so set our umask to 0 */
1037         saved_umask = umask(0);
1038
1039         ret = SMB_VFS_MKDIRAT(conn,
1040                         conn->cwd_fsp,
1041                         smb_fname,
1042                         00755);
1043
1044         umask(saved_umask);
1045
1046         if (ret == -1) {
1047                 DBG_ERR("mkdirat error=%d (%s)\n", errno, strerror(errno));
1048                 TALLOC_FREE(frame);
1049                 return NULL;
1050         }
1051
1052         TALLOC_FREE(frame);
1053         Py_RETURN_NONE;
1054 }
1055
1056
1057 /*
1058   Create an empty file
1059  */
1060 static PyObject *py_smbd_create_file(PyObject *self, PyObject *args, PyObject *kwargs)
1061 {
1062         const char * const kwnames[] = {
1063                 "fname",
1064                 "session_info",
1065                 "service",
1066                 NULL
1067         };
1068         char *fname, *service = NULL;
1069         PyObject *py_session = Py_None;
1070         struct auth_session_info *session_info = NULL;
1071         TALLOC_CTX *frame = talloc_stackframe();
1072         struct connection_struct *conn = NULL;
1073         struct files_struct *fsp = NULL;
1074         NTSTATUS status;
1075
1076         if (!PyArg_ParseTupleAndKeywords(args,
1077                                          kwargs,
1078                                          "sO|z",
1079                                          discard_const_p(char *,
1080                                                          kwnames),
1081                                          &fname,
1082                                          &py_session,
1083                                          &service)) {
1084                 TALLOC_FREE(frame);
1085                 return NULL;
1086         }
1087
1088         if (!py_check_dcerpc_type(py_session,
1089                                   "samba.dcerpc.auth",
1090                                   "session_info")) {
1091                 TALLOC_FREE(frame);
1092                 return NULL;
1093         }
1094         session_info = pytalloc_get_type(py_session,
1095                                          struct auth_session_info);
1096         if (session_info == NULL) {
1097                 PyErr_Format(PyExc_TypeError,
1098                              "Expected auth_session_info for session_info argument got %s",
1099                              pytalloc_get_name(py_session));
1100                 TALLOC_FREE(frame);
1101                 return NULL;
1102         }
1103
1104         conn = get_conn_tos(service, session_info);
1105         if (!conn) {
1106                 TALLOC_FREE(frame);
1107                 return NULL;
1108         }
1109
1110         status = init_files_struct(frame,
1111                                    fname,
1112                                    conn,
1113                                    O_CREAT|O_EXCL|O_RDWR,
1114                                    &fsp);
1115         if (!NT_STATUS_IS_OK(status)) {
1116                 DBG_ERR("init_files_struct failed: %s\n",
1117                         nt_errstr(status));
1118         }
1119
1120         TALLOC_FREE(frame);
1121         Py_RETURN_NONE;
1122 }
1123
1124
1125 static PyMethodDef py_smbd_methods[] = {
1126         { "have_posix_acls",
1127                 (PyCFunction)py_smbd_have_posix_acls, METH_NOARGS,
1128                 NULL },
1129         { "set_simple_acl",
1130                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_set_simple_acl),
1131                 METH_VARARGS|METH_KEYWORDS,
1132                 NULL },
1133         { "set_nt_acl",
1134                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_set_nt_acl),
1135                 METH_VARARGS|METH_KEYWORDS,
1136                 NULL },
1137         { "get_nt_acl",
1138                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_get_nt_acl),
1139                 METH_VARARGS|METH_KEYWORDS,
1140                 NULL },
1141         { "get_sys_acl",
1142                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_get_sys_acl),
1143                 METH_VARARGS|METH_KEYWORDS,
1144                 NULL },
1145         { "set_sys_acl",
1146                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_set_sys_acl),
1147                 METH_VARARGS|METH_KEYWORDS,
1148                 NULL },
1149         { "chown",
1150                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_chown),
1151                 METH_VARARGS|METH_KEYWORDS,
1152                 NULL },
1153         { "unlink",
1154                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_unlink),
1155                 METH_VARARGS|METH_KEYWORDS,
1156                 NULL },
1157         { "mkdir",
1158                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_mkdir),
1159                 METH_VARARGS|METH_KEYWORDS,
1160                 NULL },
1161         { "create_file",
1162                 PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_create_file),
1163                 METH_VARARGS|METH_KEYWORDS,
1164                 NULL },
1165         { NULL }
1166 };
1167
1168 void initsmbd(void);
1169
1170 static struct PyModuleDef moduledef = {
1171     PyModuleDef_HEAD_INIT,
1172     .m_name = "smbd",
1173     .m_doc = "Python bindings for the smbd file server.",
1174     .m_size = -1,
1175     .m_methods = py_smbd_methods,
1176 };
1177
1178 MODULE_INIT_FUNC(smbd)
1179 {
1180         PyObject *m = NULL;
1181
1182         m = PyModule_Create(&moduledef);
1183         return m;
1184 }