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