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