r3290: allow SID_ANONYMOUS ( "S-1-5-7" ) to be the users sid
[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_ACCOUNT))) {
61                 DEBUG(0,("sid_to_unixuid: sid %s is not an 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         /* we don't use PASS_THRU_REQ here, as the connect operation runs with 
365            root privileges. This allows the backends to setup any database
366            links they might need during the connect. */
367         status = ntvfs_next_connect(ntvfs, req, sharename);
368
369         return status;
370 }
371
372 /*
373   disconnect from a share
374 */
375 static NTSTATUS unixuid_disconnect(struct ntvfs_module_context *ntvfs,
376                                    struct smbsrv_tcon *tcon)
377 {
378         struct unixuid_private *private = ntvfs->private_data;
379         NTSTATUS status;
380
381         talloc_free(private);
382
383         status = ntvfs_next_disconnect(ntvfs, tcon);
384  
385         return status;
386 }
387
388
389 /*
390   delete a file
391 */
392 static NTSTATUS unixuid_unlink(struct ntvfs_module_context *ntvfs,
393                               struct smbsrv_request *req, struct smb_unlink *unl)
394 {
395         NTSTATUS status;
396
397         PASS_THRU_REQ(ntvfs, req, unlink, (ntvfs, req, unl));
398
399         return status;
400 }
401
402 /*
403   ioctl interface
404 */
405 static NTSTATUS unixuid_ioctl(struct ntvfs_module_context *ntvfs,
406                              struct smbsrv_request *req, union smb_ioctl *io)
407 {
408         NTSTATUS status;
409
410         PASS_THRU_REQ(ntvfs, req, ioctl, (ntvfs, req, io));
411
412         return status;
413 }
414
415 /*
416   check if a directory exists
417 */
418 static NTSTATUS unixuid_chkpath(struct ntvfs_module_context *ntvfs,
419                                struct smbsrv_request *req, struct smb_chkpath *cp)
420 {
421         NTSTATUS status;
422
423         PASS_THRU_REQ(ntvfs, req, chkpath, (ntvfs, req, cp));
424
425         return status;
426 }
427
428 /*
429   return info on a pathname
430 */
431 static NTSTATUS unixuid_qpathinfo(struct ntvfs_module_context *ntvfs,
432                                  struct smbsrv_request *req, union smb_fileinfo *info)
433 {
434         NTSTATUS status;
435
436         PASS_THRU_REQ(ntvfs, req, qpathinfo, (ntvfs, req, info));
437
438         return status;
439 }
440
441 /*
442   query info on a open file
443 */
444 static NTSTATUS unixuid_qfileinfo(struct ntvfs_module_context *ntvfs,
445                                  struct smbsrv_request *req, union smb_fileinfo *info)
446 {
447         NTSTATUS status;
448
449         PASS_THRU_REQ(ntvfs, req, qfileinfo, (ntvfs, req, info));
450
451         return status;
452 }
453
454
455 /*
456   set info on a pathname
457 */
458 static NTSTATUS unixuid_setpathinfo(struct ntvfs_module_context *ntvfs,
459                                    struct smbsrv_request *req, union smb_setfileinfo *st)
460 {
461         NTSTATUS status;
462
463         PASS_THRU_REQ(ntvfs, req, setpathinfo, (ntvfs, req, st));
464
465         return status;
466 }
467
468 /*
469   open a file
470 */
471 static NTSTATUS unixuid_open(struct ntvfs_module_context *ntvfs,
472                             struct smbsrv_request *req, union smb_open *io)
473 {
474         NTSTATUS status;
475
476         PASS_THRU_REQ(ntvfs, req, open, (ntvfs, req, io));
477
478         return status;
479 }
480
481 /*
482   create a directory
483 */
484 static NTSTATUS unixuid_mkdir(struct ntvfs_module_context *ntvfs,
485                              struct smbsrv_request *req, union smb_mkdir *md)
486 {
487         NTSTATUS status;
488
489         PASS_THRU_REQ(ntvfs, req, mkdir, (ntvfs, req, md));
490
491         return status;
492 }
493
494 /*
495   remove a directory
496 */
497 static NTSTATUS unixuid_rmdir(struct ntvfs_module_context *ntvfs,
498                              struct smbsrv_request *req, struct smb_rmdir *rd)
499 {
500         NTSTATUS status;
501
502         PASS_THRU_REQ(ntvfs, req, rmdir, (ntvfs, req, rd));
503
504         return status;
505 }
506
507 /*
508   rename a set of files
509 */
510 static NTSTATUS unixuid_rename(struct ntvfs_module_context *ntvfs,
511                               struct smbsrv_request *req, union smb_rename *ren)
512 {
513         NTSTATUS status;
514
515         PASS_THRU_REQ(ntvfs, req, rename, (ntvfs, req, ren));
516
517         return status;
518 }
519
520 /*
521   copy a set of files
522 */
523 static NTSTATUS unixuid_copy(struct ntvfs_module_context *ntvfs,
524                             struct smbsrv_request *req, struct smb_copy *cp)
525 {
526         NTSTATUS status;
527
528         PASS_THRU_REQ(ntvfs, req, copy, (ntvfs, req, cp));
529
530         return status;
531 }
532
533 /*
534   read from a file
535 */
536 static NTSTATUS unixuid_read(struct ntvfs_module_context *ntvfs,
537                             struct smbsrv_request *req, union smb_read *rd)
538 {
539         NTSTATUS status;
540
541         PASS_THRU_REQ(ntvfs, req, read, (ntvfs, req, rd));
542
543         return status;
544 }
545
546 /*
547   write to a file
548 */
549 static NTSTATUS unixuid_write(struct ntvfs_module_context *ntvfs,
550                              struct smbsrv_request *req, union smb_write *wr)
551 {
552         NTSTATUS status;
553
554         PASS_THRU_REQ(ntvfs, req, write, (ntvfs, req, wr));
555
556         return status;
557 }
558
559 /*
560   seek in a file
561 */
562 static NTSTATUS unixuid_seek(struct ntvfs_module_context *ntvfs,
563                             struct smbsrv_request *req, struct smb_seek *io)
564 {
565         NTSTATUS status;
566
567         PASS_THRU_REQ(ntvfs, req, seek, (ntvfs, req, io));
568
569         return status;
570 }
571
572 /*
573   flush a file
574 */
575 static NTSTATUS unixuid_flush(struct ntvfs_module_context *ntvfs,
576                              struct smbsrv_request *req, struct smb_flush *io)
577 {
578         NTSTATUS status;
579
580         PASS_THRU_REQ(ntvfs, req, flush, (ntvfs, req, io));
581
582         return status;
583 }
584
585 /*
586   close a file
587 */
588 static NTSTATUS unixuid_close(struct ntvfs_module_context *ntvfs,
589                              struct smbsrv_request *req, union smb_close *io)
590 {
591         NTSTATUS status;
592
593         PASS_THRU_REQ(ntvfs, req, close, (ntvfs, req, io));
594
595         return status;
596 }
597
598 /*
599   exit - closing files
600 */
601 static NTSTATUS unixuid_exit(struct ntvfs_module_context *ntvfs,
602                             struct smbsrv_request *req)
603 {
604         NTSTATUS status;
605
606         PASS_THRU_REQ(ntvfs, req, exit, (ntvfs, req));
607
608         return status;
609 }
610
611 /*
612   logoff - closing files
613 */
614 static NTSTATUS unixuid_logoff(struct ntvfs_module_context *ntvfs,
615                               struct smbsrv_request *req)
616 {
617         struct unixuid_private *private = ntvfs->private_data;
618         NTSTATUS status;
619
620         PASS_THRU_REQ(ntvfs, req, logoff, (ntvfs, req));
621
622         private->last_token = NULL;
623
624         return status;
625 }
626
627 /*
628   async setup
629 */
630 static NTSTATUS unixuid_async_setup(struct ntvfs_module_context *ntvfs,
631                                     struct smbsrv_request *req, 
632                                     void *private)
633 {
634         NTSTATUS status;
635
636         PASS_THRU_REQ(ntvfs, req, async_setup, (ntvfs, req, private));
637
638         return status;
639 }
640
641 /*
642   lock a byte range
643 */
644 static NTSTATUS unixuid_lock(struct ntvfs_module_context *ntvfs,
645                             struct smbsrv_request *req, union smb_lock *lck)
646 {
647         NTSTATUS status;
648
649         PASS_THRU_REQ(ntvfs, req, lock, (ntvfs, req, lck));
650
651         return status;
652 }
653
654 /*
655   set info on a open file
656 */
657 static NTSTATUS unixuid_setfileinfo(struct ntvfs_module_context *ntvfs,
658                                    struct smbsrv_request *req, 
659                                    union smb_setfileinfo *info)
660 {
661         NTSTATUS status;
662
663         PASS_THRU_REQ(ntvfs, req, setfileinfo, (ntvfs, req, info));
664
665         return status;
666 }
667
668
669 /*
670   return filesystem space info
671 */
672 static NTSTATUS unixuid_fsinfo(struct ntvfs_module_context *ntvfs,
673                               struct smbsrv_request *req, union smb_fsinfo *fs)
674 {
675         NTSTATUS status;
676
677         PASS_THRU_REQ(ntvfs, req, fsinfo, (ntvfs, req, fs));
678
679         return status;
680 }
681
682 /*
683   return print queue info
684 */
685 static NTSTATUS unixuid_lpq(struct ntvfs_module_context *ntvfs,
686                            struct smbsrv_request *req, union smb_lpq *lpq)
687 {
688         NTSTATUS status;
689
690         PASS_THRU_REQ(ntvfs, req, lpq, (ntvfs, req, lpq));
691
692         return status;
693 }
694
695 /* 
696    list files in a directory matching a wildcard pattern
697 */
698 static NTSTATUS unixuid_search_first(struct ntvfs_module_context *ntvfs,
699                                     struct smbsrv_request *req, union smb_search_first *io, 
700                                     void *search_private, 
701                                     BOOL (*callback)(void *, union smb_search_data *))
702 {
703         NTSTATUS status;
704
705         PASS_THRU_REQ(ntvfs, req, search_first, (ntvfs, req, io, search_private, callback));
706
707         return status;
708 }
709
710 /* continue a search */
711 static NTSTATUS unixuid_search_next(struct ntvfs_module_context *ntvfs,
712                                    struct smbsrv_request *req, union smb_search_next *io, 
713                                    void *search_private, 
714                                    BOOL (*callback)(void *, union smb_search_data *))
715 {
716         NTSTATUS status;
717
718         PASS_THRU_REQ(ntvfs, req, search_next, (ntvfs, req, io, search_private, callback));
719
720         return status;
721 }
722
723 /* close a search */
724 static NTSTATUS unixuid_search_close(struct ntvfs_module_context *ntvfs,
725                                     struct smbsrv_request *req, union smb_search_close *io)
726 {
727         NTSTATUS status;
728
729         PASS_THRU_REQ(ntvfs, req, search_close, (ntvfs, req, io));
730
731         return status;
732 }
733
734 /* SMBtrans - not used on file shares */
735 static NTSTATUS unixuid_trans(struct ntvfs_module_context *ntvfs,
736                              struct smbsrv_request *req, struct smb_trans2 *trans2)
737 {
738         NTSTATUS status;
739
740         PASS_THRU_REQ(ntvfs, req, trans, (ntvfs, req, trans2));
741
742         return status;
743 }
744
745 /*
746   initialise the unixuid backend, registering ourselves with the ntvfs subsystem
747  */
748 NTSTATUS ntvfs_unixuid_init(void)
749 {
750         NTSTATUS ret;
751         struct ntvfs_ops ops;
752
753         ZERO_STRUCT(ops);
754
755         /* fill in all the operations */
756         ops.connect = unixuid_connect;
757         ops.disconnect = unixuid_disconnect;
758         ops.unlink = unixuid_unlink;
759         ops.chkpath = unixuid_chkpath;
760         ops.qpathinfo = unixuid_qpathinfo;
761         ops.setpathinfo = unixuid_setpathinfo;
762         ops.open = unixuid_open;
763         ops.mkdir = unixuid_mkdir;
764         ops.rmdir = unixuid_rmdir;
765         ops.rename = unixuid_rename;
766         ops.copy = unixuid_copy;
767         ops.ioctl = unixuid_ioctl;
768         ops.read = unixuid_read;
769         ops.write = unixuid_write;
770         ops.seek = unixuid_seek;
771         ops.flush = unixuid_flush;      
772         ops.close = unixuid_close;
773         ops.exit = unixuid_exit;
774         ops.lock = unixuid_lock;
775         ops.setfileinfo = unixuid_setfileinfo;
776         ops.qfileinfo = unixuid_qfileinfo;
777         ops.fsinfo = unixuid_fsinfo;
778         ops.lpq = unixuid_lpq;
779         ops.search_first = unixuid_search_first;
780         ops.search_next = unixuid_search_next;
781         ops.search_close = unixuid_search_close;
782         ops.trans = unixuid_trans;
783         ops.logoff = unixuid_logoff;
784         ops.async_setup = unixuid_async_setup;
785
786         ops.name = "unixuid";
787
788         /* we register under all 3 backend types, as we are not type specific */
789         ops.type = NTVFS_DISK;  
790         ret = register_backend("ntvfs", &ops);
791         if (!NT_STATUS_IS_OK(ret)) goto failed;
792
793         ops.type = NTVFS_PRINT; 
794         ret = register_backend("ntvfs", &ops);
795         if (!NT_STATUS_IS_OK(ret)) goto failed;
796
797         ops.type = NTVFS_IPC;   
798         ret = register_backend("ntvfs", &ops);
799         if (!NT_STATUS_IS_OK(ret)) goto failed;
800         
801 failed:
802         return ret;
803 }