unixuid: Use the tevent_context from the ntvfs_context
[sfrench/samba-autobuild/.git] / source4 / ntvfs / unixuid / vfs_unixuid.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    a pass-thru NTVFS module to setup a security context using unix
5    uid/gid
6
7    Copyright (C) Andrew Tridgell 2004
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "system/filesys.h"
25 #include "system/passwd.h"
26 #include "auth/auth.h"
27 #include "ntvfs/ntvfs.h"
28 #include "libcli/wbclient/wbclient.h"
29 #define TEVENT_DEPRECATED
30 #include <tevent.h>
31 #include "../lib/util/setid.h"
32
33 NTSTATUS ntvfs_unixuid_init(void);
34
35 struct unixuid_private {
36         struct wbc_context *wbc_ctx;
37         struct security_unix_token *last_sec_ctx;
38         struct security_token *last_token;
39 };
40
41
42 /*
43   pull the current security context into a security_unix_token
44 */
45 static struct security_unix_token *save_unix_security(TALLOC_CTX *mem_ctx)
46 {
47         struct security_unix_token *sec = talloc(mem_ctx, struct security_unix_token);
48         if (sec == NULL) {
49                 return NULL;
50         }
51         sec->uid = geteuid();
52         sec->gid = getegid();
53         sec->ngroups = getgroups(0, NULL);
54         if (sec->ngroups == -1) {
55                 talloc_free(sec);
56                 return NULL;
57         }
58         sec->groups = talloc_array(sec, gid_t, sec->ngroups);
59         if (sec->groups == NULL) {
60                 talloc_free(sec);
61                 return NULL;
62         }
63
64         if (getgroups(sec->ngroups, sec->groups) != sec->ngroups) {
65                 talloc_free(sec);
66                 return NULL;
67         }
68
69         return sec;
70 }
71
72 /*
73   set the current security context from a security_unix_token
74 */
75 static NTSTATUS set_unix_security(struct security_unix_token *sec)
76 {
77         samba_seteuid(0);
78
79         if (samba_setgroups(sec->ngroups, sec->groups) != 0) {
80                 return NT_STATUS_ACCESS_DENIED;
81         }
82         if (samba_setegid(sec->gid) != 0) {
83                 return NT_STATUS_ACCESS_DENIED;
84         }
85         if (samba_seteuid(sec->uid) != 0) {
86                 return NT_STATUS_ACCESS_DENIED;
87         }
88         return NT_STATUS_OK;
89 }
90
91 static int unixuid_nesting_level;
92
93 /*
94   called at the start and end of a tevent nesting loop. Needs to save/restore
95   unix security context
96  */
97 static int unixuid_event_nesting_hook(struct tevent_context *ev,
98                                       void *private_data,
99                                       uint32_t level,
100                                       bool begin,
101                                       void *stack_ptr,
102                                       const char *location)
103 {
104         struct security_unix_token *sec_ctx;
105
106         if (unixuid_nesting_level == 0) {
107                 /* we don't need to do anything unless we are nested
108                    inside of a call in this module */
109                 return 0;
110         }
111
112         if (begin) {
113                 sec_ctx = save_unix_security(ev);
114                 if (sec_ctx == NULL) {
115                         DEBUG(0,("%s: Failed to save security context\n", location));
116                         return -1;
117                 }
118                 *(struct security_unix_token **)stack_ptr = sec_ctx;
119                 if (samba_seteuid(0) != 0 || samba_setegid(0) != 0) {
120                         DEBUG(0,("%s: Failed to change to root\n", location));
121                         return -1;                      
122                 }
123         } else {
124                 /* called when we come out of a nesting level */
125                 NTSTATUS status;
126
127                 sec_ctx = *(struct security_unix_token **)stack_ptr;
128                 if (sec_ctx == NULL) {
129                         /* this happens the first time this function
130                            is called, as we install the hook while
131                            inside an event in unixuid_connect() */
132                         return 0;
133                 }
134
135                 sec_ctx = talloc_get_type_abort(sec_ctx, struct security_unix_token);
136                 status = set_unix_security(sec_ctx);
137                 talloc_free(sec_ctx);
138                 if (!NT_STATUS_IS_OK(status)) {
139                         DEBUG(0,("%s: Failed to revert security context (%s)\n", 
140                                  location, nt_errstr(status)));
141                         return -1;
142                 }
143         }
144
145         return 0;
146 }
147
148
149 /*
150   form a security_unix_token from the current security_token
151 */
152 static NTSTATUS nt_token_to_unix_security(struct ntvfs_module_context *ntvfs,
153                                           struct ntvfs_request *req,
154                                           struct security_token *token,
155                                           struct security_unix_token **sec)
156 {
157         return security_token_to_unix_token(req,
158                                             ntvfs->ctx->event_ctx,
159                                             token, sec);
160 }
161
162 /*
163   setup our unix security context according to the session authentication info
164 */
165 static NTSTATUS unixuid_setup_security(struct ntvfs_module_context *ntvfs,
166                                        struct ntvfs_request *req, struct security_unix_token **sec)
167 {
168         struct unixuid_private *priv = ntvfs->private_data;
169         struct security_token *token;
170         struct security_unix_token *newsec;
171         NTSTATUS status;
172
173         /* If we are asked to set up, but have not had a successful
174          * session setup or tree connect, then these may not be filled
175          * in.  ACCESS_DENIED is the right error code here */
176         if (req->session_info == NULL || priv == NULL) {
177                 return NT_STATUS_ACCESS_DENIED;
178         }
179
180         token = req->session_info->security_token;
181
182         *sec = save_unix_security(ntvfs);
183         if (*sec == NULL) {
184                 return NT_STATUS_NO_MEMORY;
185         }
186
187         if (token == priv->last_token) {
188                 newsec = priv->last_sec_ctx;
189         } else {
190                 status = nt_token_to_unix_security(ntvfs, req, token, &newsec);
191                 if (!NT_STATUS_IS_OK(status)) {
192                         talloc_free(*sec);
193                         return status;
194                 }
195                 if (priv->last_sec_ctx) {
196                         talloc_free(priv->last_sec_ctx);
197                 }
198                 priv->last_sec_ctx = newsec;
199                 priv->last_token = token;
200                 talloc_steal(priv, newsec);
201         }
202
203         status = set_unix_security(newsec);
204         if (!NT_STATUS_IS_OK(status)) {
205                 talloc_free(*sec);
206                 return status;
207         }
208
209         return NT_STATUS_OK;
210 }
211
212 /*
213   this pass through macro operates on request contexts
214 */
215 #define PASS_THRU_REQ(ntvfs, req, op, args) do { \
216         NTSTATUS status2; \
217         struct security_unix_token *sec; \
218         status = unixuid_setup_security(ntvfs, req, &sec); \
219         NT_STATUS_NOT_OK_RETURN(status); \
220         unixuid_nesting_level++; \
221         status = ntvfs_next_##op args; \
222         unixuid_nesting_level--; \
223         status2 = set_unix_security(sec); \
224         talloc_free(sec); \
225         if (!NT_STATUS_IS_OK(status2)) smb_panic("Unable to reset security context"); \
226 } while (0)
227
228
229
230 /*
231   connect to a share - used when a tree_connect operation comes in.
232 */
233 static NTSTATUS unixuid_connect(struct ntvfs_module_context *ntvfs,
234                                 struct ntvfs_request *req, union smb_tcon *tcon)
235 {
236         struct unixuid_private *priv;
237         NTSTATUS status;
238
239         priv = talloc(ntvfs, struct unixuid_private);
240         if (!priv) {
241                 return NT_STATUS_NO_MEMORY;
242         }
243
244         priv->wbc_ctx = wbc_init(priv, ntvfs->ctx->msg_ctx,
245                                     ntvfs->ctx->event_ctx);
246         if (priv->wbc_ctx == NULL) {
247                 talloc_free(priv);
248                 return NT_STATUS_INTERNAL_ERROR;
249         }
250
251         priv->last_sec_ctx = NULL;
252         priv->last_token = NULL;
253         ntvfs->private_data = priv;
254
255         tevent_loop_set_nesting_hook(ntvfs->ctx->event_ctx, 
256                                      unixuid_event_nesting_hook,
257                                      &unixuid_nesting_level);
258
259         /* we don't use PASS_THRU_REQ here, as the connect operation runs with 
260            root privileges. This allows the backends to setup any database
261            links they might need during the connect. */
262         status = ntvfs_next_connect(ntvfs, req, tcon);
263
264         return status;
265 }
266
267 /*
268   disconnect from a share
269 */
270 static NTSTATUS unixuid_disconnect(struct ntvfs_module_context *ntvfs)
271 {
272         struct unixuid_private *priv = ntvfs->private_data;
273         NTSTATUS status;
274
275         talloc_free(priv);
276         ntvfs->private_data = NULL;
277
278         status = ntvfs_next_disconnect(ntvfs);
279  
280         return status;
281 }
282
283
284 /*
285   delete a file
286 */
287 static NTSTATUS unixuid_unlink(struct ntvfs_module_context *ntvfs,
288                               struct ntvfs_request *req,
289                               union smb_unlink *unl)
290 {
291         NTSTATUS status;
292
293         PASS_THRU_REQ(ntvfs, req, unlink, (ntvfs, req, unl));
294
295         return status;
296 }
297
298 /*
299   ioctl interface
300 */
301 static NTSTATUS unixuid_ioctl(struct ntvfs_module_context *ntvfs,
302                              struct ntvfs_request *req, union smb_ioctl *io)
303 {
304         NTSTATUS status;
305
306         PASS_THRU_REQ(ntvfs, req, ioctl, (ntvfs, req, io));
307
308         return status;
309 }
310
311 /*
312   check if a directory exists
313 */
314 static NTSTATUS unixuid_chkpath(struct ntvfs_module_context *ntvfs,
315                                 struct ntvfs_request *req,
316                                 union smb_chkpath *cp)
317 {
318         NTSTATUS status;
319
320         PASS_THRU_REQ(ntvfs, req, chkpath, (ntvfs, req, cp));
321
322         return status;
323 }
324
325 /*
326   return info on a pathname
327 */
328 static NTSTATUS unixuid_qpathinfo(struct ntvfs_module_context *ntvfs,
329                                  struct ntvfs_request *req, union smb_fileinfo *info)
330 {
331         NTSTATUS status;
332
333         PASS_THRU_REQ(ntvfs, req, qpathinfo, (ntvfs, req, info));
334
335         return status;
336 }
337
338 /*
339   query info on a open file
340 */
341 static NTSTATUS unixuid_qfileinfo(struct ntvfs_module_context *ntvfs,
342                                  struct ntvfs_request *req, union smb_fileinfo *info)
343 {
344         NTSTATUS status;
345
346         PASS_THRU_REQ(ntvfs, req, qfileinfo, (ntvfs, req, info));
347
348         return status;
349 }
350
351
352 /*
353   set info on a pathname
354 */
355 static NTSTATUS unixuid_setpathinfo(struct ntvfs_module_context *ntvfs,
356                                    struct ntvfs_request *req, union smb_setfileinfo *st)
357 {
358         NTSTATUS status;
359
360         PASS_THRU_REQ(ntvfs, req, setpathinfo, (ntvfs, req, st));
361
362         return status;
363 }
364
365 /*
366   open a file
367 */
368 static NTSTATUS unixuid_open(struct ntvfs_module_context *ntvfs,
369                              struct ntvfs_request *req, union smb_open *io)
370 {
371         NTSTATUS status;
372
373         PASS_THRU_REQ(ntvfs, req, open, (ntvfs, req, io));
374
375         return status;
376 }
377
378 /*
379   create a directory
380 */
381 static NTSTATUS unixuid_mkdir(struct ntvfs_module_context *ntvfs,
382                              struct ntvfs_request *req, union smb_mkdir *md)
383 {
384         NTSTATUS status;
385
386         PASS_THRU_REQ(ntvfs, req, mkdir, (ntvfs, req, md));
387
388         return status;
389 }
390
391 /*
392   remove a directory
393 */
394 static NTSTATUS unixuid_rmdir(struct ntvfs_module_context *ntvfs,
395                              struct ntvfs_request *req, struct smb_rmdir *rd)
396 {
397         NTSTATUS status;
398
399         PASS_THRU_REQ(ntvfs, req, rmdir, (ntvfs, req, rd));
400
401         return status;
402 }
403
404 /*
405   rename a set of files
406 */
407 static NTSTATUS unixuid_rename(struct ntvfs_module_context *ntvfs,
408                               struct ntvfs_request *req, union smb_rename *ren)
409 {
410         NTSTATUS status;
411
412         PASS_THRU_REQ(ntvfs, req, rename, (ntvfs, req, ren));
413
414         return status;
415 }
416
417 /*
418   copy a set of files
419 */
420 static NTSTATUS unixuid_copy(struct ntvfs_module_context *ntvfs,
421                             struct ntvfs_request *req, struct smb_copy *cp)
422 {
423         NTSTATUS status;
424
425         PASS_THRU_REQ(ntvfs, req, copy, (ntvfs, req, cp));
426
427         return status;
428 }
429
430 /*
431   read from a file
432 */
433 static NTSTATUS unixuid_read(struct ntvfs_module_context *ntvfs,
434                             struct ntvfs_request *req, union smb_read *rd)
435 {
436         NTSTATUS status;
437
438         PASS_THRU_REQ(ntvfs, req, read, (ntvfs, req, rd));
439
440         return status;
441 }
442
443 /*
444   write to a file
445 */
446 static NTSTATUS unixuid_write(struct ntvfs_module_context *ntvfs,
447                              struct ntvfs_request *req, union smb_write *wr)
448 {
449         NTSTATUS status;
450
451         PASS_THRU_REQ(ntvfs, req, write, (ntvfs, req, wr));
452
453         return status;
454 }
455
456 /*
457   seek in a file
458 */
459 static NTSTATUS unixuid_seek(struct ntvfs_module_context *ntvfs,
460                              struct ntvfs_request *req,
461                              union smb_seek *io)
462 {
463         NTSTATUS status;
464
465         PASS_THRU_REQ(ntvfs, req, seek, (ntvfs, req, io));
466
467         return status;
468 }
469
470 /*
471   flush a file
472 */
473 static NTSTATUS unixuid_flush(struct ntvfs_module_context *ntvfs,
474                               struct ntvfs_request *req,
475                               union smb_flush *io)
476 {
477         NTSTATUS status;
478
479         PASS_THRU_REQ(ntvfs, req, flush, (ntvfs, req, io));
480
481         return status;
482 }
483
484 /*
485   close a file
486 */
487 static NTSTATUS unixuid_close(struct ntvfs_module_context *ntvfs,
488                              struct ntvfs_request *req, union smb_close *io)
489 {
490         NTSTATUS status;
491
492         PASS_THRU_REQ(ntvfs, req, close, (ntvfs, req, io));
493
494         return status;
495 }
496
497 /*
498   exit - closing files
499 */
500 static NTSTATUS unixuid_exit(struct ntvfs_module_context *ntvfs,
501                             struct ntvfs_request *req)
502 {
503         NTSTATUS status;
504
505         PASS_THRU_REQ(ntvfs, req, exit, (ntvfs, req));
506
507         return status;
508 }
509
510 /*
511   logoff - closing files
512 */
513 static NTSTATUS unixuid_logoff(struct ntvfs_module_context *ntvfs,
514                               struct ntvfs_request *req)
515 {
516         struct unixuid_private *priv = ntvfs->private_data;
517         NTSTATUS status;
518
519         PASS_THRU_REQ(ntvfs, req, logoff, (ntvfs, req));
520
521         priv->last_token = NULL;
522
523         return status;
524 }
525
526 /*
527   async setup
528 */
529 static NTSTATUS unixuid_async_setup(struct ntvfs_module_context *ntvfs,
530                                     struct ntvfs_request *req, 
531                                     void *private_data)
532 {
533         NTSTATUS status;
534
535         PASS_THRU_REQ(ntvfs, req, async_setup, (ntvfs, req, private_data));
536
537         return status;
538 }
539
540 /*
541   cancel an async request
542 */
543 static NTSTATUS unixuid_cancel(struct ntvfs_module_context *ntvfs,
544                                struct ntvfs_request *req)
545 {
546         NTSTATUS status;
547
548         PASS_THRU_REQ(ntvfs, req, cancel, (ntvfs, req));
549
550         return status;
551 }
552
553 /*
554   change notify
555 */
556 static NTSTATUS unixuid_notify(struct ntvfs_module_context *ntvfs,
557                                struct ntvfs_request *req, union smb_notify *info)
558 {
559         NTSTATUS status;
560
561         PASS_THRU_REQ(ntvfs, req, notify, (ntvfs, req, info));
562
563         return status;
564 }
565
566 /*
567   lock a byte range
568 */
569 static NTSTATUS unixuid_lock(struct ntvfs_module_context *ntvfs,
570                             struct ntvfs_request *req, union smb_lock *lck)
571 {
572         NTSTATUS status;
573
574         PASS_THRU_REQ(ntvfs, req, lock, (ntvfs, req, lck));
575
576         return status;
577 }
578
579 /*
580   set info on a open file
581 */
582 static NTSTATUS unixuid_setfileinfo(struct ntvfs_module_context *ntvfs,
583                                    struct ntvfs_request *req, 
584                                    union smb_setfileinfo *info)
585 {
586         NTSTATUS status;
587
588         PASS_THRU_REQ(ntvfs, req, setfileinfo, (ntvfs, req, info));
589
590         return status;
591 }
592
593
594 /*
595   return filesystem space info
596 */
597 static NTSTATUS unixuid_fsinfo(struct ntvfs_module_context *ntvfs,
598                               struct ntvfs_request *req, union smb_fsinfo *fs)
599 {
600         NTSTATUS status;
601
602         PASS_THRU_REQ(ntvfs, req, fsinfo, (ntvfs, req, fs));
603
604         return status;
605 }
606
607 /*
608   return print queue info
609 */
610 static NTSTATUS unixuid_lpq(struct ntvfs_module_context *ntvfs,
611                            struct ntvfs_request *req, union smb_lpq *lpq)
612 {
613         NTSTATUS status;
614
615         PASS_THRU_REQ(ntvfs, req, lpq, (ntvfs, req, lpq));
616
617         return status;
618 }
619
620 /* 
621    list files in a directory matching a wildcard pattern
622 */
623 static NTSTATUS unixuid_search_first(struct ntvfs_module_context *ntvfs,
624                                     struct ntvfs_request *req, union smb_search_first *io, 
625                                     void *search_private, 
626                                     bool (*callback)(void *, const union smb_search_data *))
627 {
628         NTSTATUS status;
629
630         PASS_THRU_REQ(ntvfs, req, search_first, (ntvfs, req, io, search_private, callback));
631
632         return status;
633 }
634
635 /* continue a search */
636 static NTSTATUS unixuid_search_next(struct ntvfs_module_context *ntvfs,
637                                    struct ntvfs_request *req, union smb_search_next *io, 
638                                    void *search_private, 
639                                    bool (*callback)(void *, const union smb_search_data *))
640 {
641         NTSTATUS status;
642
643         PASS_THRU_REQ(ntvfs, req, search_next, (ntvfs, req, io, search_private, callback));
644
645         return status;
646 }
647
648 /* close a search */
649 static NTSTATUS unixuid_search_close(struct ntvfs_module_context *ntvfs,
650                                     struct ntvfs_request *req, union smb_search_close *io)
651 {
652         NTSTATUS status;
653
654         PASS_THRU_REQ(ntvfs, req, search_close, (ntvfs, req, io));
655
656         return status;
657 }
658
659 /* SMBtrans - not used on file shares */
660 static NTSTATUS unixuid_trans(struct ntvfs_module_context *ntvfs,
661                              struct ntvfs_request *req, struct smb_trans2 *trans2)
662 {
663         NTSTATUS status;
664
665         PASS_THRU_REQ(ntvfs, req, trans, (ntvfs, req, trans2));
666
667         return status;
668 }
669
670 /*
671   initialise the unixuid backend, registering ourselves with the ntvfs subsystem
672  */
673 NTSTATUS ntvfs_unixuid_init(void)
674 {
675         NTSTATUS ret;
676         struct ntvfs_ops ops;
677         NTVFS_CURRENT_CRITICAL_SIZES(vers);
678
679         ZERO_STRUCT(ops);
680
681         /* fill in all the operations */
682         ops.connect_fn = unixuid_connect;
683         ops.disconnect_fn = unixuid_disconnect;
684         ops.unlink_fn = unixuid_unlink;
685         ops.chkpath_fn = unixuid_chkpath;
686         ops.qpathinfo_fn = unixuid_qpathinfo;
687         ops.setpathinfo_fn = unixuid_setpathinfo;
688         ops.open_fn = unixuid_open;
689         ops.mkdir_fn = unixuid_mkdir;
690         ops.rmdir_fn = unixuid_rmdir;
691         ops.rename_fn = unixuid_rename;
692         ops.copy_fn = unixuid_copy;
693         ops.ioctl_fn = unixuid_ioctl;
694         ops.read_fn = unixuid_read;
695         ops.write_fn = unixuid_write;
696         ops.seek_fn = unixuid_seek;
697         ops.flush_fn = unixuid_flush;
698         ops.close_fn = unixuid_close;
699         ops.exit_fn = unixuid_exit;
700         ops.lock_fn = unixuid_lock;
701         ops.setfileinfo_fn = unixuid_setfileinfo;
702         ops.qfileinfo_fn = unixuid_qfileinfo;
703         ops.fsinfo_fn = unixuid_fsinfo;
704         ops.lpq_fn = unixuid_lpq;
705         ops.search_first_fn = unixuid_search_first;
706         ops.search_next_fn = unixuid_search_next;
707         ops.search_close_fn = unixuid_search_close;
708         ops.trans_fn = unixuid_trans;
709         ops.logoff_fn = unixuid_logoff;
710         ops.async_setup_fn = unixuid_async_setup;
711         ops.cancel_fn = unixuid_cancel;
712         ops.notify_fn = unixuid_notify;
713
714         ops.name = "unixuid";
715
716         /* we register under all 3 backend types, as we are not type specific */
717         ops.type = NTVFS_DISK;  
718         ret = ntvfs_register(&ops, &vers);
719         if (!NT_STATUS_IS_OK(ret)) goto failed;
720
721         ops.type = NTVFS_PRINT; 
722         ret = ntvfs_register(&ops, &vers);
723         if (!NT_STATUS_IS_OK(ret)) goto failed;
724
725         ops.type = NTVFS_IPC;   
726         ret = ntvfs_register(&ops, &vers);
727         if (!NT_STATUS_IS_OK(ret)) goto failed;
728         
729 failed:
730         return ret;
731 }