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