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