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