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