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