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