pysmbd: fix some talloc_stackframe() memory leaks and clean up the frame hierarchy...
[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         TALLOC_FREE(frame);
198
199         umask(saved_umask);
200         return status;
201 }
202
203 static NTSTATUS get_nt_acl_conn(TALLOC_CTX *mem_ctx,
204                                 const char *fname,
205                                 connection_struct *conn,
206                                 uint32_t security_info_wanted,
207                                 struct security_descriptor **sd)
208 {
209         TALLOC_CTX *frame = talloc_stackframe();
210         NTSTATUS status;
211         struct smb_filename *smb_fname = synthetic_smb_fname(talloc_tos(),
212                                         fname,
213                                         NULL,
214                                         NULL,
215                                         lp_posix_pathnames() ?
216                                                 SMB_FILENAME_POSIX_PATH : 0);
217
218         if (smb_fname == NULL) {
219                 TALLOC_FREE(frame);
220                 return NT_STATUS_NO_MEMORY;
221         }
222
223         status = SMB_VFS_GET_NT_ACL(conn,
224                                 smb_fname,
225                                 security_info_wanted,
226                                 mem_ctx,
227                                 sd);
228         if (!NT_STATUS_IS_OK(status)) {
229                 DEBUG(0,("get_nt_acl_conn: get_nt_acl returned %s.\n", nt_errstr(status)));
230         }
231
232         TALLOC_FREE(frame);
233
234         return status;
235 }
236
237 static int set_acl_entry_perms(SMB_ACL_ENTRY_T entry, mode_t perm_mask)
238 {
239         SMB_ACL_PERMSET_T perms = NULL;
240
241         if (sys_acl_get_permset(entry, &perms) != 0) {
242                 return -1;
243         }
244
245         if (sys_acl_clear_perms(perms) != 0) {
246                 return -1;
247         }
248
249         if ((perm_mask & SMB_ACL_READ) != 0 &&
250             sys_acl_add_perm(perms, SMB_ACL_READ) != 0) {
251                 return -1;
252         }
253
254         if ((perm_mask & SMB_ACL_WRITE) != 0 &&
255             sys_acl_add_perm(perms, SMB_ACL_WRITE) != 0) {
256                 return -1;
257         }
258
259         if ((perm_mask & SMB_ACL_EXECUTE) != 0 &&
260             sys_acl_add_perm(perms, SMB_ACL_EXECUTE) != 0) {
261                 return -1;
262         }
263
264         if (sys_acl_set_permset(entry, perms) != 0) {
265                 return -1;
266         }
267
268         return 0;
269 }
270
271 static SMB_ACL_T make_simple_acl(TALLOC_CTX *mem_ctx,
272                         gid_t gid,
273                         mode_t chmod_mode)
274 {
275         mode_t mode = SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE;
276
277         mode_t mode_user = (chmod_mode & 0700) >> 6;
278         mode_t mode_group = (chmod_mode & 070) >> 3;
279         mode_t mode_other = chmod_mode &  07;
280         SMB_ACL_ENTRY_T entry;
281         SMB_ACL_T acl = sys_acl_init(mem_ctx);
282
283         if (!acl) {
284                 return NULL;
285         }
286
287         if (sys_acl_create_entry(&acl, &entry) != 0) {
288                 TALLOC_FREE(acl);
289                 return NULL;
290         }
291
292         if (sys_acl_set_tag_type(entry, SMB_ACL_USER_OBJ) != 0) {
293                 TALLOC_FREE(acl);
294                 return NULL;
295         }
296
297         if (set_acl_entry_perms(entry, mode_user) != 0) {
298                 TALLOC_FREE(acl);
299                 return NULL;
300         }
301
302         if (sys_acl_create_entry(&acl, &entry) != 0) {
303                 TALLOC_FREE(acl);
304                 return NULL;
305         }
306
307         if (sys_acl_set_tag_type(entry, SMB_ACL_GROUP_OBJ) != 0) {
308                 TALLOC_FREE(acl);
309                 return NULL;
310         }
311
312         if (set_acl_entry_perms(entry, mode_group) != 0) {
313                 TALLOC_FREE(acl);
314                 return NULL;
315         }
316
317         if (sys_acl_create_entry(&acl, &entry) != 0) {
318                 TALLOC_FREE(acl);
319                 return NULL;
320         }
321
322         if (sys_acl_set_tag_type(entry, SMB_ACL_OTHER) != 0) {
323                 TALLOC_FREE(acl);
324                 return NULL;
325         }
326
327         if (set_acl_entry_perms(entry, mode_other) != 0) {
328                 TALLOC_FREE(acl);
329                 return NULL;
330         }
331
332         if (gid != -1) {
333                 if (sys_acl_create_entry(&acl, &entry) != 0) {
334                         TALLOC_FREE(acl);
335                         return NULL;
336                 }
337
338                 if (sys_acl_set_tag_type(entry, SMB_ACL_GROUP) != 0) {
339                         TALLOC_FREE(acl);
340                         return NULL;
341                 }
342
343                 if (sys_acl_set_qualifier(entry, &gid) != 0) {
344                         TALLOC_FREE(acl);
345                         return NULL;
346                 }
347
348                 if (set_acl_entry_perms(entry, mode_group) != 0) {
349                         TALLOC_FREE(acl);
350                         return NULL;
351                 }
352         }
353
354         if (sys_acl_create_entry(&acl, &entry) != 0) {
355                 TALLOC_FREE(acl);
356                 return NULL;
357         }
358
359         if (sys_acl_set_tag_type(entry, SMB_ACL_MASK) != 0) {
360                 TALLOC_FREE(acl);
361                 return NULL;
362         }
363
364         if (set_acl_entry_perms(entry, mode) != 0) {
365                 TALLOC_FREE(acl);
366                 return NULL;
367         }
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         frame = talloc_stackframe();
391
392         acl = make_simple_acl(frame, gid, mode);
393         if (acl == NULL) {
394                 TALLOC_FREE(frame);
395                 return NULL;
396         }
397
398         conn = get_conn(frame, service);
399         if (!conn) {
400                 TALLOC_FREE(frame);
401                 return NULL;
402         }
403
404         ret = set_sys_acl_conn(fname, SMB_ACL_TYPE_ACCESS, acl, conn);
405
406         if (ret != 0) {
407                 TALLOC_FREE(frame);
408                 errno = ret;
409                 return PyErr_SetFromErrno(PyExc_OSError);
410         }
411
412         TALLOC_FREE(frame);
413
414         Py_RETURN_NONE;
415 }
416
417 /*
418   chown a file
419  */
420 static PyObject *py_smbd_chown(PyObject *self, PyObject *args, PyObject *kwargs)
421 {
422         const char * const kwnames[] = { "fname", "uid", "gid", "service", NULL };
423         connection_struct *conn;
424         int ret;
425
426         char *fname, *service = NULL;
427         int uid, gid;
428         TALLOC_CTX *frame;
429         mode_t saved_umask;
430         struct smb_filename *smb_fname = NULL;
431
432         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sii|z",
433                                          discard_const_p(char *, kwnames),
434                                          &fname, &uid, &gid, &service))
435                 return NULL;
436
437         frame = talloc_stackframe();
438
439         conn = get_conn(frame, service);
440         if (!conn) {
441                 TALLOC_FREE(frame);
442                 return NULL;
443         }
444
445         /* we want total control over the permissions on created files,
446            so set our umask to 0 */
447         saved_umask = umask(0);
448
449         smb_fname = synthetic_smb_fname(talloc_tos(),
450                                         fname,
451                                         NULL,
452                                         NULL,
453                                         lp_posix_pathnames() ?
454                                                 SMB_FILENAME_POSIX_PATH : 0);
455         if (smb_fname == NULL) {
456                 umask(saved_umask);
457                 TALLOC_FREE(frame);
458                 errno = ENOMEM;
459                 return PyErr_SetFromErrno(PyExc_OSError);
460         }
461
462         ret = SMB_VFS_CHOWN(conn, smb_fname, uid, gid);
463         if (ret != 0) {
464                 umask(saved_umask);
465                 TALLOC_FREE(frame);
466                 errno = ret;
467                 return PyErr_SetFromErrno(PyExc_OSError);
468         }
469
470         umask(saved_umask);
471
472         TALLOC_FREE(frame);
473
474         Py_RETURN_NONE;
475 }
476
477 /*
478   unlink a file
479  */
480 static PyObject *py_smbd_unlink(PyObject *self, PyObject *args, PyObject *kwargs)
481 {
482         const char * const kwnames[] = { "fname", "service", NULL };
483         connection_struct *conn;
484         int ret;
485         struct smb_filename *smb_fname = NULL;
486         char *fname, *service = NULL;
487         TALLOC_CTX *frame;
488
489         frame = talloc_stackframe();
490
491         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|z",
492                                          discard_const_p(char *, kwnames),
493                                          &fname, &service)) {
494                 TALLOC_FREE(frame);
495                 return NULL;
496         }
497
498         conn = get_conn(frame, service);
499         if (!conn) {
500                 TALLOC_FREE(frame);
501                 return NULL;
502         }
503
504         smb_fname = synthetic_smb_fname_split(frame,
505                                         fname,
506                                         lp_posix_pathnames());
507         if (smb_fname == NULL) {
508                 TALLOC_FREE(frame);
509                 return PyErr_NoMemory();
510         }
511
512         ret = SMB_VFS_UNLINK(conn, smb_fname);
513         if (ret != 0) {
514                 TALLOC_FREE(frame);
515                 errno = ret;
516                 return PyErr_SetFromErrno(PyExc_OSError);
517         }
518
519         TALLOC_FREE(frame);
520
521         Py_RETURN_NONE;
522 }
523
524 /*
525   check if we have ACL support
526  */
527 static PyObject *py_smbd_have_posix_acls(PyObject *self)
528 {
529 #ifdef HAVE_POSIX_ACLS
530         return PyBool_FromLong(true);
531 #else
532         return PyBool_FromLong(false);
533 #endif
534 }
535
536 /*
537   set the NT ACL on a file
538  */
539 static PyObject *py_smbd_set_nt_acl(PyObject *self, PyObject *args, PyObject *kwargs)
540 {
541         const char * const kwnames[] = { "fname", "security_info_sent", "sd", "service", NULL };
542         NTSTATUS status;
543         char *fname, *service = NULL;
544         int security_info_sent;
545         PyObject *py_sd;
546         struct security_descriptor *sd;
547         connection_struct *conn;
548         TALLOC_CTX *frame;
549
550         frame = talloc_stackframe();
551
552         if (!PyArg_ParseTupleAndKeywords(args, kwargs,
553                                          "siO|z", discard_const_p(char *, kwnames),
554                                          &fname, &security_info_sent, &py_sd, &service)) {
555                 TALLOC_FREE(frame);
556                 return NULL;
557         }
558
559         if (!py_check_dcerpc_type(py_sd, "samba.dcerpc.security", "descriptor")) {
560                 TALLOC_FREE(frame);
561                 return NULL;
562         }
563
564         conn = get_conn(frame, service);
565         if (!conn) {
566                 TALLOC_FREE(frame);
567                 return NULL;
568         }
569
570         sd = pytalloc_get_type(py_sd, struct security_descriptor);
571
572         status = set_nt_acl_conn(fname, security_info_sent, sd, conn);
573         TALLOC_FREE(frame);
574         PyErr_NTSTATUS_IS_ERR_RAISE(status);
575
576         Py_RETURN_NONE;
577 }
578
579 /*
580   Return the NT ACL on a file
581  */
582 static PyObject *py_smbd_get_nt_acl(PyObject *self, PyObject *args, PyObject *kwargs)
583 {
584         const char * const kwnames[] = { "fname", "security_info_wanted", "service", NULL };
585         char *fname, *service = NULL;
586         int security_info_wanted;
587         PyObject *py_sd;
588         struct security_descriptor *sd;
589         TALLOC_CTX *frame = talloc_stackframe();
590         connection_struct *conn;
591         NTSTATUS status;
592
593         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|z", discard_const_p(char *, kwnames),
594                                          &fname, &security_info_wanted, &service)) {
595                 TALLOC_FREE(frame);
596                 return NULL;
597         }
598
599         conn = get_conn(frame, service);
600         if (!conn) {
601                 TALLOC_FREE(frame);
602                 return NULL;
603         }
604
605         status = get_nt_acl_conn(frame, fname, conn, security_info_wanted, &sd);
606         PyErr_NTSTATUS_IS_ERR_RAISE(status);
607
608         py_sd = py_return_ndr_struct("samba.dcerpc.security", "descriptor", sd, sd);
609
610         TALLOC_FREE(frame);
611
612         return py_sd;
613 }
614
615 /*
616   set the posix (or similar) ACL on a file
617  */
618 static PyObject *py_smbd_set_sys_acl(PyObject *self, PyObject *args, PyObject *kwargs)
619 {
620         const char * const kwnames[] = { "fname", "acl_type", "acl", "service", NULL };
621         TALLOC_CTX *frame = talloc_stackframe();
622         int ret;
623         char *fname, *service = NULL;
624         PyObject *py_acl;
625         struct smb_acl_t *acl;
626         int acl_type;
627         connection_struct *conn;
628
629         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siO|z",
630                                          discard_const_p(char *, kwnames),
631                                          &fname, &acl_type, &py_acl, &service)) {
632                 TALLOC_FREE(frame);
633                 return NULL;
634         }
635
636         if (!py_check_dcerpc_type(py_acl, "samba.dcerpc.smb_acl", "t")) {
637                 TALLOC_FREE(frame);
638                 return NULL;
639         }
640
641         conn = get_conn(frame, service);
642         if (!conn) {
643                 TALLOC_FREE(frame);
644                 return NULL;
645         }
646
647         acl = pytalloc_get_type(py_acl, struct smb_acl_t);
648
649         ret = set_sys_acl_conn(fname, acl_type, acl, conn);
650         if (ret != 0) {
651                 TALLOC_FREE(frame);
652                 errno = ret;
653                 return PyErr_SetFromErrno(PyExc_OSError);
654         }
655
656         TALLOC_FREE(frame);
657         Py_RETURN_NONE;
658 }
659
660 /*
661   Return the posix (or similar) ACL on a file
662  */
663 static PyObject *py_smbd_get_sys_acl(PyObject *self, PyObject *args, PyObject *kwargs)
664 {
665         const char * const kwnames[] = { "fname", "acl_type", "service", NULL };
666         char *fname;
667         PyObject *py_acl;
668         struct smb_acl_t *acl;
669         int acl_type;
670         TALLOC_CTX *frame = talloc_stackframe();
671         connection_struct *conn;
672         char *service = NULL;
673         struct smb_filename *smb_fname = NULL;
674
675         if (!PyArg_ParseTupleAndKeywords(args, kwargs, "si|z",
676                                          discard_const_p(char *, kwnames),
677                                          &fname, &acl_type, &service)) {
678                 TALLOC_FREE(frame);
679                 return NULL;
680         }
681
682         conn = get_conn(frame, service);
683         if (!conn) {
684                 TALLOC_FREE(frame);
685                 return NULL;
686         }
687
688         smb_fname = synthetic_smb_fname_split(frame,
689                                         fname,
690                                         lp_posix_pathnames());
691         if (smb_fname == NULL) {
692                 TALLOC_FREE(frame);
693                 return NULL;
694         }
695         acl = SMB_VFS_SYS_ACL_GET_FILE( conn, smb_fname, acl_type, frame);
696         if (!acl) {
697                 TALLOC_FREE(frame);
698                 return PyErr_SetFromErrno(PyExc_OSError);
699         }
700
701         py_acl = py_return_ndr_struct("samba.dcerpc.smb_acl", "t", acl, acl);
702
703         TALLOC_FREE(frame);
704
705         return py_acl;
706 }
707
708 static PyMethodDef py_smbd_methods[] = {
709         { "have_posix_acls",
710                 (PyCFunction)py_smbd_have_posix_acls, METH_NOARGS,
711                 NULL },
712         { "set_simple_acl",
713                 (PyCFunction)py_smbd_set_simple_acl, METH_VARARGS|METH_KEYWORDS,
714                 NULL },
715         { "set_nt_acl",
716                 (PyCFunction)py_smbd_set_nt_acl, METH_VARARGS|METH_KEYWORDS,
717                 NULL },
718         { "get_nt_acl",
719                 (PyCFunction)py_smbd_get_nt_acl, METH_VARARGS|METH_KEYWORDS,
720                 NULL },
721         { "get_sys_acl",
722                 (PyCFunction)py_smbd_get_sys_acl, METH_VARARGS|METH_KEYWORDS,
723                 NULL },
724         { "set_sys_acl",
725                 (PyCFunction)py_smbd_set_sys_acl, METH_VARARGS|METH_KEYWORDS,
726                 NULL },
727         { "chown",
728                 (PyCFunction)py_smbd_chown, METH_VARARGS|METH_KEYWORDS,
729                 NULL },
730         { "unlink",
731                 (PyCFunction)py_smbd_unlink, METH_VARARGS|METH_KEYWORDS,
732                 NULL },
733         { NULL }
734 };
735
736 void initsmbd(void);
737
738 static struct PyModuleDef moduledef = {
739     PyModuleDef_HEAD_INIT,
740     .m_name = "smbd",
741     .m_doc = "Python bindings for the smbd file server.",
742     .m_size = -1,
743     .m_methods = py_smbd_methods,
744 };
745
746 MODULE_INIT_FUNC(smbd)
747 {
748         PyObject *m = NULL;
749
750         m = PyModule_Create(&moduledef);
751         return m;
752 }