Merge branch 'vendor/LIBEDIT'
[dragonfly.git] / contrib / amd / hlfsd / stubs.c
1 /*
2  * Copyright (c) 1997-1999 Erez Zadok
3  * Copyright (c) 1989 Jan-Simon Pendry
4  * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
5  * Copyright (c) 1989 The Regents of the University of California.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Jan-Simon Pendry at Imperial College, London.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgment:
21  *      This product includes software developed by the University of
22  *      California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  *      %W% (Berkeley) %G%
40  *
41  * $Id: stubs.c,v 1.3 1999/01/13 23:31:19 ezk Exp $
42  *
43  * HLFSD was written at Columbia University Computer Science Department, by
44  * Erez Zadok <ezk@cs.columbia.edu> and Alexander Dupuy <dupuy@cs.columbia.edu>
45  * It is being distributed under the same terms and conditions as amd does.
46  */
47
48 #ifdef HAVE_CONFIG_H
49 # include <config.h>
50 #endif /* HAVE_CONFIG_H */
51 #include <am_defs.h>
52 #include <hlfsd.h>
53
54 /*
55  * STATIC VARIABLES:
56  */
57 static nfsfattr rootfattr = {NFDIR, 0040555, 2, 0, 0, 512, 512, 0,
58                              1, 0, ROOTID};
59 static nfsfattr slinkfattr = {NFLNK, 0120777, 1, 0, 0, NFS_MAXPATHLEN, 512, 0,
60                               (NFS_MAXPATHLEN + 1) / 512, 0, SLINKID};
61                                 /* user name file attributes */
62 static nfsfattr un_fattr = {NFLNK, 0120777, 1, 0, 0, NFS_MAXPATHLEN, 512, 0,
63                             (NFS_MAXPATHLEN + 1) / 512, 0, INVALIDID};
64 static int getcreds(struct svc_req *, uid_t *, gid_t *);
65 static int started;
66 static am_nfs_fh slink;
67 static am_nfs_fh un_fhandle;
68
69 /*
70  * GLOBALS:
71  */
72 am_nfs_fh root;
73 am_nfs_fh *root_fhp =           &root;
74
75
76 /* initialize NFS file handles for hlfsd */
77 void
78 hlfsd_init_filehandles(void)
79 {
80   u_int ui;
81
82   ui = ROOTID;
83   memcpy(root.fh_data, &ui, sizeof(ui));
84
85   ui = SLINKID;
86   memcpy(slink.fh_data, &ui, sizeof(ui));
87
88   ui = INVALIDID;
89   memcpy(un_fhandle.fh_data, &ui, sizeof(ui));
90 }
91
92
93 voidp
94 nfsproc_null_2_svc(voidp argp, struct svc_req *rqstp)
95 {
96   static char res;
97
98   return (voidp) &res;
99 }
100
101
102 /* compare if two filehandles are equal */
103 static int
104 eq_fh(const am_nfs_fh *fh1, const am_nfs_fh *fh2)
105 {
106   return (!memcmp((char *) fh1, (char *) fh2, sizeof(am_nfs_fh)));
107 }
108
109
110 nfsattrstat *
111 nfsproc_getattr_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
112 {
113   static nfsattrstat res;
114   uid_t uid = (uid_t) INVALIDID;
115   gid_t gid = (gid_t) INVALIDID;
116
117   if (!started) {
118     started++;
119     rootfattr.na_ctime = startup;
120     rootfattr.na_mtime = startup;
121     slinkfattr.na_ctime = startup;
122     slinkfattr.na_mtime = startup;
123     un_fattr.na_ctime = startup;
124     un_fattr.na_mtime = startup;
125   }
126
127   if (eq_fh(argp, &root)) {
128     res.ns_status = NFS_OK;
129     res.ns_u.ns_attr_u = rootfattr;
130   } else if (eq_fh(argp, &slink)) {
131
132 #ifndef MNT2_NFS_OPT_SYMTTL
133     /*
134      * This code is needed to defeat Solaris 2.4's (and newer) symlink
135      * values cache.  It forces the last-modified time of the symlink to be
136      * current.  It is not needed if the O/S has an nfs flag to turn off the
137      * symlink-cache at mount time (such as Irix 5.x and 6.x). -Erez.
138      */
139     if (++slinkfattr.na_mtime.nt_useconds == 0)
140       ++slinkfattr.na_mtime.nt_seconds;
141 #endif /* not MNT2_NFS_OPT_SYMTTL */
142
143     res.ns_status = NFS_OK;
144     res.ns_u.ns_attr_u = slinkfattr;
145   } else {
146
147     if (getcreds(rqstp, &uid, &gid) < 0) {
148       res.ns_status = NFSERR_STALE;
149       return &res;
150     }
151     if (gid != hlfs_gid) {
152       res.ns_status = NFSERR_STALE;
153     } else {
154       memset((char *) &uid, 0, sizeof(int));
155       uid = *(u_int *) argp->fh_data;
156       if (plt_search(uid) != (uid2home_t *) NULL) {
157         res.ns_status = NFS_OK;
158         un_fattr.na_fileid = uid;
159         res.ns_u.ns_attr_u = un_fattr;
160 #ifdef DEBUG
161         dlog("nfs_getattr: successful search for uid=%ld, gid=%ld",
162              (long) uid, (long) gid);
163 #endif /* DEBUG */
164       } else {                  /* not found */
165         res.ns_status = NFSERR_STALE;
166       }
167     }
168   }
169   return &res;
170 }
171
172
173 nfsattrstat *
174 nfsproc_setattr_2_svc(nfssattrargs *argp, struct svc_req *rqstp)
175 {
176   static nfsattrstat res = {NFSERR_ROFS};
177
178   return &res;
179 }
180
181
182 voidp
183 nfsproc_root_2_svc(voidp argp, struct svc_req *rqstp)
184 {
185   static char res;
186
187   return (voidp) &res;
188 }
189
190
191 nfsdiropres *
192 nfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
193 {
194   static nfsdiropres res;
195   int idx;
196   uid_t uid = (uid_t) INVALIDID;
197   gid_t gid = (gid_t) INVALIDID;
198
199   if (!started) {
200     started++;
201     rootfattr.na_ctime = startup;
202     rootfattr.na_mtime = startup;
203     slinkfattr.na_ctime = startup;
204     slinkfattr.na_mtime = startup;
205     un_fattr.na_ctime = startup;
206     un_fattr.na_mtime = startup;
207   }
208
209   if (eq_fh(&argp->da_fhandle, &slink)) {
210     res.dr_status = NFSERR_NOTDIR;
211     return &res;
212   }
213
214   if (eq_fh(&argp->da_fhandle, &root)) {
215     if (argp->da_name[0] == '.' &&
216         (argp->da_name[1] == '\0' ||
217          (argp->da_name[1] == '.' &&
218           argp->da_name[2] == '\0'))) {
219       res.dr_u.dr_drok_u.drok_fhandle = root;
220       res.dr_u.dr_drok_u.drok_attributes = rootfattr;
221       res.dr_status = NFS_OK;
222       return &res;
223     }
224
225     if (STREQ(argp->da_name, slinkname)) {
226       res.dr_u.dr_drok_u.drok_fhandle = slink;
227       res.dr_u.dr_drok_u.drok_attributes = slinkfattr;
228       res.dr_status = NFS_OK;
229       return &res;
230     }
231
232     if (getcreds(rqstp, &uid, &gid) < 0 || gid != hlfs_gid) {
233       res.dr_status = NFSERR_NOENT;
234       return &res;
235     }
236
237     /* if gets here, gid == hlfs_gid */
238     if ((idx = untab_index(argp->da_name)) < 0) {
239       res.dr_status = NFSERR_NOENT;
240       return &res;
241     } else {                    /* entry found and gid is permitted */
242       un_fattr.na_fileid = untab[idx].uid;
243       res.dr_u.dr_drok_u.drok_attributes = un_fattr;
244       memset((char *) &un_fhandle, 0, sizeof(am_nfs_fh));
245       *(u_int *) un_fhandle.fh_data = (u_int) untab[idx].uid;
246       strncpy((char *) &un_fhandle.fh_data[sizeof(int)],
247               untab[idx].username,
248               sizeof(am_nfs_fh) - sizeof(int));
249       res.dr_u.dr_drok_u.drok_fhandle = un_fhandle;
250       res.dr_status = NFS_OK;
251 #ifdef DEBUG
252       dlog("nfs_lookup: successful lookup for uid=%ld, gid=%ld: username=%s",
253            (long) uid, (long) gid, untab[idx].username);
254 #endif /* DEBUG */
255       return &res;
256     }
257   } /* end of "if (eq_fh(argp->dir.data, root.data)) {" */
258
259   res.dr_status = NFSERR_STALE;
260   return &res;
261 }
262
263 static int
264 getcreds(struct svc_req *rp, uid_t *u, gid_t *g)
265 {
266   struct authunix_parms *aup = (struct authunix_parms *) NULL;
267 #ifdef HAVE_RPC_AUTH_DES_H
268   struct authdes_cred *adp;
269 #endif /* HAVE_RPC_AUTH_DES_H */
270
271   switch (rp->rq_cred.oa_flavor) {
272
273   case AUTH_UNIX:
274     aup = (struct authunix_parms *) rp->rq_clntcred;
275     *u = aup->aup_uid;
276     *g = aup->aup_gid;
277     break;
278
279 #ifdef HAVE_RPC_AUTH_DES_H
280   case AUTH_DES:
281     adp = (struct authdes_cred *) rp->rq_clntcred;
282     *g = INVALIDID;             /* some unknown group id */
283     if (sscanf(adp->adc_fullname.name, "unix.%lu@", (u_long *) u) == 1)
284         break;
285     /* fall through */
286 #endif /* HAVE_RPC_AUTH_DES_H */
287
288   default:
289     *u = *g = INVALIDID;        /* just in case */
290     svcerr_weakauth(nfsxprt);
291     return -1;
292   }
293
294   return 0;                     /* everything is ok */
295 }
296
297
298 nfsreadlinkres *
299 nfsproc_readlink_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
300 {
301   static nfsreadlinkres res;
302   uid_t userid = (uid_t) INVALIDID;
303   gid_t groupid = hlfs_gid + 1; /* anything not hlfs_gid */
304   int retval = 0;
305   char *path_val = (char *) NULL;
306   char *username;
307   static uid_t last_uid = (uid_t) INVALIDID;
308
309   if (eq_fh(argp, &root)) {
310     res.rlr_status = NFSERR_ISDIR;
311   } else if (eq_fh(argp, &slink)) {
312     if (getcreds(rqstp, &userid, &groupid) < 0)
313       return (nfsreadlinkres *) NULL;
314
315     gettimeofday((struct timeval *) &slinkfattr.na_atime, (struct timezone *) 0);
316
317     res.rlr_status = NFS_OK;
318     if (groupid == hlfs_gid) {
319       res.rlr_u.rlr_data_u = DOTSTRING;
320     } else if (!(res.rlr_u.rlr_data_u = path_val = homedir(userid))) {
321       /*
322        * parent process (fork in homedir()) continues
323        * processing, by getting a NULL returned as a
324        * "special".  Child returns result.
325        */
326       return (nfsreadlinkres *) NULL;
327     }
328
329   } else {                      /* check if asked for user mailbox */
330
331     if (getcreds(rqstp, &userid, &groupid) < 0) {
332       return (nfsreadlinkres *) NULL;
333     }
334
335     if (groupid == hlfs_gid) {
336       memset((char *) &userid, 0, sizeof(int));
337       userid = *(u_int *) argp->fh_data;
338       username = (char *) &argp->fh_data[sizeof(int)];
339       if (!(res.rlr_u.rlr_data_u = mailbox(userid, username)))
340         return (nfsreadlinkres *) NULL;
341     } else {
342       res.rlr_status = NFSERR_STALE;
343     }
344   }
345
346   /* print info, but try to avoid repetitions */
347   if (userid != last_uid) {
348     plog(XLOG_USER, "mailbox for uid=%ld, gid=%ld is %s",
349          (long) userid, (long) groupid, (char *) res.rlr_u.rlr_data_u);
350     last_uid = userid;
351   }
352
353   /* I don't think will pass this if -D nofork */
354   if (serverpid == getpid())
355     return &res;
356
357   if (!svc_sendreply(nfsxprt, (XDRPROC_T_TYPE) xdr_readlinkres, (SVC_IN_ARG_TYPE) &res))
358     svcerr_systemerr(nfsxprt);
359
360   /*
361    * Child exists here.   We need to determine which
362    * exist status to return.  The exit status
363    * is gathered using wait() and determines
364    * if we returned $HOME/.hlfsspool or $ALTDIR.  The parent
365    * needs this info so it can update the lookup table.
366    */
367   if (path_val && alt_spooldir && STREQ(path_val, alt_spooldir))
368     retval = 1;         /* could not get real home dir (or uid 0 user) */
369   else
370     retval = 0;
371
372 #ifdef DEBUG
373   /*
374    * If asked for -D nofork, then must return the value,
375    * NOT exit, or else the main hlfsd server exits.
376    * Bug where is that status information being collected?
377    */
378   amuDebugNo(D_FORK)
379     return &res;
380 #endif /* DEBUG */
381
382   exit(retval);
383 }
384
385
386 nfsreadres *
387 nfsproc_read_2_svc(nfsreadargs *argp, struct svc_req *rqstp)
388 {
389   static nfsreadres res = {NFSERR_ACCES};
390
391   return &res;
392 }
393
394
395 voidp
396 nfsproc_writecache_2_svc(voidp argp, struct svc_req *rqstp)
397 {
398   static char res;
399
400   return (voidp) &res;
401 }
402
403
404 nfsattrstat *
405 nfsproc_write_2_svc(nfswriteargs *argp, struct svc_req *rqstp)
406 {
407   static nfsattrstat res = {NFSERR_ROFS};
408
409   return &res;
410 }
411
412
413 nfsdiropres *
414 nfsproc_create_2_svc(nfscreateargs *argp, struct svc_req *rqstp)
415 {
416   static nfsdiropres res = {NFSERR_ROFS};
417
418   return &res;
419 }
420
421
422 nfsstat *
423 nfsproc_remove_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
424 {
425   static nfsstat res = {NFSERR_ROFS};
426
427   return &res;
428 }
429
430
431 nfsstat *
432 nfsproc_rename_2_svc(nfsrenameargs *argp, struct svc_req *rqstp)
433 {
434   static nfsstat res = {NFSERR_ROFS};
435
436   return &res;
437 }
438
439
440 nfsstat *
441 nfsproc_link_2_svc(nfslinkargs *argp, struct svc_req *rqstp)
442 {
443   static nfsstat res = {NFSERR_ROFS};
444
445   return &res;
446 }
447
448
449 nfsstat *
450 nfsproc_symlink_2_svc(nfssymlinkargs *argp, struct svc_req *rqstp)
451 {
452   static nfsstat res = {NFSERR_ROFS};
453
454   return &res;
455 }
456
457
458 nfsdiropres *
459 nfsproc_mkdir_2_svc(nfscreateargs *argp, struct svc_req *rqstp)
460 {
461   static nfsdiropres res = {NFSERR_ROFS};
462
463   return &res;
464 }
465
466
467 nfsstat *
468 nfsproc_rmdir_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
469 {
470   static nfsstat res = {NFSERR_ROFS};
471
472   return &res;
473 }
474
475
476 nfsreaddirres *
477 nfsproc_readdir_2_svc(nfsreaddirargs *argp, struct svc_req *rqstp)
478 {
479   static nfsreaddirres res;
480   static nfsentry slinkent = {SLINKID, 0, {SLINKCOOKIE}};
481   static nfsentry dotdotent = {ROOTID, "..", {DOTDOTCOOKIE}, &slinkent};
482   static nfsentry dotent = {ROOTID, ".", {DOTCOOKIE}, &dotdotent};
483
484   slinkent.ne_name = slinkname;
485
486   if (eq_fh(&argp->rda_fhandle, &slink)) {
487     res.rdr_status = NFSERR_NOTDIR;
488   } else if (eq_fh(&argp->rda_fhandle, &root)) {
489     gettimeofday((struct timeval *) &rootfattr.na_atime, (struct timezone *) 0);
490
491     res.rdr_status = NFS_OK;
492     switch (argp->rda_cookie[0]) {
493     case 0:
494       res.rdr_u.rdr_reply_u.dl_entries = &dotent;
495       break;
496     case DOTCOOKIE:
497       res.rdr_u.rdr_reply_u.dl_entries = &dotdotent;
498       break;
499     case DOTDOTCOOKIE:
500       res.rdr_u.rdr_reply_u.dl_entries = &slinkent;
501       break;
502     case SLINKCOOKIE:
503       res.rdr_u.rdr_reply_u.dl_entries = (nfsentry *) 0;
504       break;
505     }
506     res.rdr_u.rdr_reply_u.dl_eof = TRUE;
507   } else {
508     res.rdr_status = NFSERR_STALE;
509   }
510   return &res;
511 }
512
513
514 nfsstatfsres *
515 nfsproc_statfs_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
516 {
517   static nfsstatfsres res = {NFS_OK};
518
519   res.sfr_u.sfr_reply_u.sfrok_tsize = 1024;
520   res.sfr_u.sfr_reply_u.sfrok_bsize = 1024;
521
522   /*
523    * Some "df" programs automatically assume that file systems
524    * with zero blocks are meta-filesystems served by automounters.
525    */
526   res.sfr_u.sfr_reply_u.sfrok_blocks = 0;
527   res.sfr_u.sfr_reply_u.sfrok_bfree = 0;
528   res.sfr_u.sfr_reply_u.sfrok_bavail = 0;
529
530   return &res;
531 }