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