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