r14173: change smb interface structures to always use
[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,
254                               union smb_unlink *unl)
255 {
256         NTSTATUS status;
257
258         PASS_THRU_REQ(ntvfs, req, unlink, (ntvfs, req, unl));
259
260         return status;
261 }
262
263 /*
264   ioctl interface
265 */
266 static NTSTATUS unixuid_ioctl(struct ntvfs_module_context *ntvfs,
267                              struct ntvfs_request *req, union smb_ioctl *io)
268 {
269         NTSTATUS status;
270
271         PASS_THRU_REQ(ntvfs, req, ioctl, (ntvfs, req, io));
272
273         return status;
274 }
275
276 /*
277   check if a directory exists
278 */
279 static NTSTATUS unixuid_chkpath(struct ntvfs_module_context *ntvfs,
280                                 struct ntvfs_request *req,
281                                 union smb_chkpath *cp)
282 {
283         NTSTATUS status;
284
285         PASS_THRU_REQ(ntvfs, req, chkpath, (ntvfs, req, cp));
286
287         return status;
288 }
289
290 /*
291   return info on a pathname
292 */
293 static NTSTATUS unixuid_qpathinfo(struct ntvfs_module_context *ntvfs,
294                                  struct ntvfs_request *req, union smb_fileinfo *info)
295 {
296         NTSTATUS status;
297
298         PASS_THRU_REQ(ntvfs, req, qpathinfo, (ntvfs, req, info));
299
300         return status;
301 }
302
303 /*
304   query info on a open file
305 */
306 static NTSTATUS unixuid_qfileinfo(struct ntvfs_module_context *ntvfs,
307                                  struct ntvfs_request *req, union smb_fileinfo *info)
308 {
309         NTSTATUS status;
310
311         PASS_THRU_REQ(ntvfs, req, qfileinfo, (ntvfs, req, info));
312
313         return status;
314 }
315
316
317 /*
318   set info on a pathname
319 */
320 static NTSTATUS unixuid_setpathinfo(struct ntvfs_module_context *ntvfs,
321                                    struct ntvfs_request *req, union smb_setfileinfo *st)
322 {
323         NTSTATUS status;
324
325         PASS_THRU_REQ(ntvfs, req, setpathinfo, (ntvfs, req, st));
326
327         return status;
328 }
329
330 /*
331   open a file
332 */
333 static NTSTATUS unixuid_open(struct ntvfs_module_context *ntvfs,
334                              struct ntvfs_request *req, union smb_open *io)
335 {
336         NTSTATUS status;
337
338         PASS_THRU_REQ(ntvfs, req, open, (ntvfs, req, io));
339
340         return status;
341 }
342
343 /*
344   create a directory
345 */
346 static NTSTATUS unixuid_mkdir(struct ntvfs_module_context *ntvfs,
347                              struct ntvfs_request *req, union smb_mkdir *md)
348 {
349         NTSTATUS status;
350
351         PASS_THRU_REQ(ntvfs, req, mkdir, (ntvfs, req, md));
352
353         return status;
354 }
355
356 /*
357   remove a directory
358 */
359 static NTSTATUS unixuid_rmdir(struct ntvfs_module_context *ntvfs,
360                              struct ntvfs_request *req, struct smb_rmdir *rd)
361 {
362         NTSTATUS status;
363
364         PASS_THRU_REQ(ntvfs, req, rmdir, (ntvfs, req, rd));
365
366         return status;
367 }
368
369 /*
370   rename a set of files
371 */
372 static NTSTATUS unixuid_rename(struct ntvfs_module_context *ntvfs,
373                               struct ntvfs_request *req, union smb_rename *ren)
374 {
375         NTSTATUS status;
376
377         PASS_THRU_REQ(ntvfs, req, rename, (ntvfs, req, ren));
378
379         return status;
380 }
381
382 /*
383   copy a set of files
384 */
385 static NTSTATUS unixuid_copy(struct ntvfs_module_context *ntvfs,
386                             struct ntvfs_request *req, struct smb_copy *cp)
387 {
388         NTSTATUS status;
389
390         PASS_THRU_REQ(ntvfs, req, copy, (ntvfs, req, cp));
391
392         return status;
393 }
394
395 /*
396   read from a file
397 */
398 static NTSTATUS unixuid_read(struct ntvfs_module_context *ntvfs,
399                             struct ntvfs_request *req, union smb_read *rd)
400 {
401         NTSTATUS status;
402
403         PASS_THRU_REQ(ntvfs, req, read, (ntvfs, req, rd));
404
405         return status;
406 }
407
408 /*
409   write to a file
410 */
411 static NTSTATUS unixuid_write(struct ntvfs_module_context *ntvfs,
412                              struct ntvfs_request *req, union smb_write *wr)
413 {
414         NTSTATUS status;
415
416         PASS_THRU_REQ(ntvfs, req, write, (ntvfs, req, wr));
417
418         return status;
419 }
420
421 /*
422   seek in a file
423 */
424 static NTSTATUS unixuid_seek(struct ntvfs_module_context *ntvfs,
425                              struct ntvfs_request *req,
426                              union smb_seek *io)
427 {
428         NTSTATUS status;
429
430         PASS_THRU_REQ(ntvfs, req, seek, (ntvfs, req, io));
431
432         return status;
433 }
434
435 /*
436   flush a file
437 */
438 static NTSTATUS unixuid_flush(struct ntvfs_module_context *ntvfs,
439                               struct ntvfs_request *req,
440                               union smb_flush *io)
441 {
442         NTSTATUS status;
443
444         PASS_THRU_REQ(ntvfs, req, flush, (ntvfs, req, io));
445
446         return status;
447 }
448
449 /*
450   close a file
451 */
452 static NTSTATUS unixuid_close(struct ntvfs_module_context *ntvfs,
453                              struct ntvfs_request *req, union smb_close *io)
454 {
455         NTSTATUS status;
456
457         PASS_THRU_REQ(ntvfs, req, close, (ntvfs, req, io));
458
459         return status;
460 }
461
462 /*
463   exit - closing files
464 */
465 static NTSTATUS unixuid_exit(struct ntvfs_module_context *ntvfs,
466                             struct ntvfs_request *req)
467 {
468         NTSTATUS status;
469
470         PASS_THRU_REQ(ntvfs, req, exit, (ntvfs, req));
471
472         return status;
473 }
474
475 /*
476   logoff - closing files
477 */
478 static NTSTATUS unixuid_logoff(struct ntvfs_module_context *ntvfs,
479                               struct ntvfs_request *req)
480 {
481         struct unixuid_private *private = ntvfs->private_data;
482         NTSTATUS status;
483
484         PASS_THRU_REQ(ntvfs, req, logoff, (ntvfs, req));
485
486         private->last_token = NULL;
487
488         return status;
489 }
490
491 /*
492   async setup
493 */
494 static NTSTATUS unixuid_async_setup(struct ntvfs_module_context *ntvfs,
495                                     struct ntvfs_request *req, 
496                                     void *private)
497 {
498         NTSTATUS status;
499
500         PASS_THRU_REQ(ntvfs, req, async_setup, (ntvfs, req, private));
501
502         return status;
503 }
504
505 /*
506   cancel an async request
507 */
508 static NTSTATUS unixuid_cancel(struct ntvfs_module_context *ntvfs,
509                                struct ntvfs_request *req)
510 {
511         NTSTATUS status;
512
513         PASS_THRU_REQ(ntvfs, req, cancel, (ntvfs, req));
514
515         return status;
516 }
517
518 /*
519   lock a byte range
520 */
521 static NTSTATUS unixuid_lock(struct ntvfs_module_context *ntvfs,
522                             struct ntvfs_request *req, union smb_lock *lck)
523 {
524         NTSTATUS status;
525
526         PASS_THRU_REQ(ntvfs, req, lock, (ntvfs, req, lck));
527
528         return status;
529 }
530
531 /*
532   set info on a open file
533 */
534 static NTSTATUS unixuid_setfileinfo(struct ntvfs_module_context *ntvfs,
535                                    struct ntvfs_request *req, 
536                                    union smb_setfileinfo *info)
537 {
538         NTSTATUS status;
539
540         PASS_THRU_REQ(ntvfs, req, setfileinfo, (ntvfs, req, info));
541
542         return status;
543 }
544
545
546 /*
547   return filesystem space info
548 */
549 static NTSTATUS unixuid_fsinfo(struct ntvfs_module_context *ntvfs,
550                               struct ntvfs_request *req, union smb_fsinfo *fs)
551 {
552         NTSTATUS status;
553
554         PASS_THRU_REQ(ntvfs, req, fsinfo, (ntvfs, req, fs));
555
556         return status;
557 }
558
559 /*
560   return print queue info
561 */
562 static NTSTATUS unixuid_lpq(struct ntvfs_module_context *ntvfs,
563                            struct ntvfs_request *req, union smb_lpq *lpq)
564 {
565         NTSTATUS status;
566
567         PASS_THRU_REQ(ntvfs, req, lpq, (ntvfs, req, lpq));
568
569         return status;
570 }
571
572 /* 
573    list files in a directory matching a wildcard pattern
574 */
575 static NTSTATUS unixuid_search_first(struct ntvfs_module_context *ntvfs,
576                                     struct ntvfs_request *req, union smb_search_first *io, 
577                                     void *search_private, 
578                                     BOOL (*callback)(void *, union smb_search_data *))
579 {
580         NTSTATUS status;
581
582         PASS_THRU_REQ(ntvfs, req, search_first, (ntvfs, req, io, search_private, callback));
583
584         return status;
585 }
586
587 /* continue a search */
588 static NTSTATUS unixuid_search_next(struct ntvfs_module_context *ntvfs,
589                                    struct ntvfs_request *req, union smb_search_next *io, 
590                                    void *search_private, 
591                                    BOOL (*callback)(void *, union smb_search_data *))
592 {
593         NTSTATUS status;
594
595         PASS_THRU_REQ(ntvfs, req, search_next, (ntvfs, req, io, search_private, callback));
596
597         return status;
598 }
599
600 /* close a search */
601 static NTSTATUS unixuid_search_close(struct ntvfs_module_context *ntvfs,
602                                     struct ntvfs_request *req, union smb_search_close *io)
603 {
604         NTSTATUS status;
605
606         PASS_THRU_REQ(ntvfs, req, search_close, (ntvfs, req, io));
607
608         return status;
609 }
610
611 /* SMBtrans - not used on file shares */
612 static NTSTATUS unixuid_trans(struct ntvfs_module_context *ntvfs,
613                              struct ntvfs_request *req, struct smb_trans2 *trans2)
614 {
615         NTSTATUS status;
616
617         PASS_THRU_REQ(ntvfs, req, trans, (ntvfs, req, trans2));
618
619         return status;
620 }
621
622 /*
623   initialise the unixuid backend, registering ourselves with the ntvfs subsystem
624  */
625 NTSTATUS ntvfs_unixuid_init(void)
626 {
627         NTSTATUS ret;
628         struct ntvfs_ops ops;
629
630         ZERO_STRUCT(ops);
631
632         /* fill in all the operations */
633         ops.connect = unixuid_connect;
634         ops.disconnect = unixuid_disconnect;
635         ops.unlink = unixuid_unlink;
636         ops.chkpath = unixuid_chkpath;
637         ops.qpathinfo = unixuid_qpathinfo;
638         ops.setpathinfo = unixuid_setpathinfo;
639         ops.open = unixuid_open;
640         ops.mkdir = unixuid_mkdir;
641         ops.rmdir = unixuid_rmdir;
642         ops.rename = unixuid_rename;
643         ops.copy = unixuid_copy;
644         ops.ioctl = unixuid_ioctl;
645         ops.read = unixuid_read;
646         ops.write = unixuid_write;
647         ops.seek = unixuid_seek;
648         ops.flush = unixuid_flush;      
649         ops.close = unixuid_close;
650         ops.exit = unixuid_exit;
651         ops.lock = unixuid_lock;
652         ops.setfileinfo = unixuid_setfileinfo;
653         ops.qfileinfo = unixuid_qfileinfo;
654         ops.fsinfo = unixuid_fsinfo;
655         ops.lpq = unixuid_lpq;
656         ops.search_first = unixuid_search_first;
657         ops.search_next = unixuid_search_next;
658         ops.search_close = unixuid_search_close;
659         ops.trans = unixuid_trans;
660         ops.logoff = unixuid_logoff;
661         ops.async_setup = unixuid_async_setup;
662         ops.cancel = unixuid_cancel;
663
664         ops.name = "unixuid";
665
666         /* we register under all 3 backend types, as we are not type specific */
667         ops.type = NTVFS_DISK;  
668         ret = ntvfs_register(&ops);
669         if (!NT_STATUS_IS_OK(ret)) goto failed;
670
671         ops.type = NTVFS_PRINT; 
672         ret = ntvfs_register(&ops);
673         if (!NT_STATUS_IS_OK(ret)) goto failed;
674
675         ops.type = NTVFS_IPC;   
676         ret = ntvfs_register(&ops);
677         if (!NT_STATUS_IS_OK(ret)) goto failed;
678         
679 failed:
680         return ret;
681 }