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