stubs.c revision 310490
1/*
2 * Copyright (c) 1997-2014 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. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 *
36 * File: am-utils/hlfsd/stubs.c
37 *
38 * HLFSD was written at Columbia University Computer Science Department, by
39 * Erez Zadok <ezk@cs.columbia.edu> and Alexander Dupuy <dupuy@cs.columbia.edu>
40 * It is being distributed under the same terms and conditions as amd does.
41 */
42
43#ifdef HAVE_CONFIG_H
44# include <config.h>
45#endif /* HAVE_CONFIG_H */
46#include <am_defs.h>
47#include <hlfsd.h>
48
49/*
50 * STATIC VARIABLES:
51 */
52static nfsfattr rootfattr = {NFDIR, 0040555, 2, 0, 0, 512, 512, 0,
53			     1, 0, ROOTID};
54static nfsfattr slinkfattr = {NFLNK, 0120777, 1, 0, 0, NFS_MAXPATHLEN, 512, 0,
55			      (NFS_MAXPATHLEN + 1) / 512, 0, SLINKID};
56				/* user name file attributes */
57static nfsfattr un_fattr = {NFLNK, 0120777, 1, 0, 0, NFS_MAXPATHLEN, 512, 0,
58			    (NFS_MAXPATHLEN + 1) / 512, 0, INVALIDID};
59static int started;
60static am_nfs_fh slink;
61static am_nfs_fh un_fhandle;
62
63/*
64 * GLOBALS:
65 */
66am_nfs_fh root;
67am_nfs_fh *root_fhp =		&root;
68
69
70/* initialize NFS file handles for hlfsd */
71void
72hlfsd_init_filehandles(void)
73{
74  u_int ui;
75
76  ui = ROOTID;
77  memcpy(root.fh_data, &ui, sizeof(ui));
78
79  ui = SLINKID;
80  memcpy(slink.fh_data, &ui, sizeof(ui));
81
82  ui = INVALIDID;
83  memcpy(un_fhandle.fh_data, &ui, sizeof(ui));
84}
85
86
87voidp
88nfsproc_null_2_svc(voidp argp, struct svc_req *rqstp)
89{
90  static char res;
91
92  return (voidp) &res;
93}
94
95
96/* compare if two filehandles are equal */
97static int
98eq_fh(const am_nfs_fh *fh1, const am_nfs_fh *fh2)
99{
100  return (!memcmp((char *) fh1, (char *) fh2, sizeof(am_nfs_fh)));
101}
102
103
104nfsattrstat *
105nfsproc_getattr_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
106{
107  static nfsattrstat res;
108  uid_t uid = (uid_t) INVALIDID;
109  gid_t gid = (gid_t) INVALIDID;
110
111  if (!started) {
112    started++;
113    rootfattr.na_ctime = startup;
114    rootfattr.na_mtime = startup;
115    slinkfattr.na_ctime = startup;
116    slinkfattr.na_mtime = startup;
117    un_fattr.na_ctime = startup;
118    un_fattr.na_mtime = startup;
119  }
120
121  if (getcreds(rqstp, &uid, &gid, nfsxprt) < 0) {
122    res.ns_status = NFSERR_STALE;
123    return &res;
124  }
125  if (eq_fh(argp, &root)) {
126#if 0
127    /*
128     * XXX: increment mtime of parent directory, causes NFS clients to
129     * invalidate their cache for that directory.
130     * Some NFS clients may need this code.
131     */
132    if (uid != rootfattr.na_uid) {
133      clocktime(&rootfattr.na_mtime);
134      rootfattr.na_uid = uid;
135    }
136#endif /* 0 */
137    res.ns_status = NFS_OK;
138    res.ns_u.ns_attr_u = rootfattr;
139  } else if (eq_fh(argp, &slink)) {
140
141#ifndef MNT2_NFS_OPT_SYMTTL
142    /*
143     * This code is needed to defeat Solaris 2.4's (and newer) symlink
144     * values cache.  It forces the last-modified time of the symlink to be
145     * current.  It is not needed if the O/S has an nfs flag to turn off the
146     * symlink-cache at mount time (such as Irix 5.x and 6.x). -Erez.
147     *
148     * Additionally, Linux currently ignores the nt_useconds field,
149     * so we must update the nt_seconds field every time.
150     */
151    if (uid != slinkfattr.na_uid) {
152      clocktime(&slinkfattr.na_mtime);
153      slinkfattr.na_uid = uid;
154    }
155#endif /* not MNT2_NFS_OPT_SYMTTL */
156
157    res.ns_status = NFS_OK;
158    res.ns_u.ns_attr_u = slinkfattr;
159  } else {
160    if (gid != hlfs_gid) {
161      res.ns_status = NFSERR_STALE;
162    } else {
163      memset((char *) &uid, 0, sizeof(int));
164      uid = *(u_int *) argp->fh_data;
165      if (plt_search(uid) != (uid2home_t *) NULL) {
166	res.ns_status = NFS_OK;
167	un_fattr.na_fileid = uid;
168	res.ns_u.ns_attr_u = un_fattr;
169	dlog("nfs_getattr: successful search for uid=%ld, gid=%ld",
170	     (long) uid, (long) gid);
171      } else {			/* not found */
172	res.ns_status = NFSERR_STALE;
173      }
174    }
175  }
176  return &res;
177}
178
179
180nfsattrstat *
181nfsproc_setattr_2_svc(nfssattrargs *argp, struct svc_req *rqstp)
182{
183  static nfsattrstat res = {NFSERR_ROFS};
184
185  return &res;
186}
187
188
189voidp
190nfsproc_root_2_svc(voidp argp, struct svc_req *rqstp)
191{
192  static char res;
193
194  return (voidp) &res;
195}
196
197
198nfsdiropres *
199nfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
200{
201  static nfsdiropres res;
202  int idx;
203  uid_t uid = (uid_t) INVALIDID;
204  gid_t gid = (gid_t) INVALIDID;
205
206  if (!started) {
207    started++;
208    rootfattr.na_ctime = startup;
209    rootfattr.na_mtime = startup;
210    slinkfattr.na_ctime = startup;
211    slinkfattr.na_mtime = startup;
212    un_fattr.na_ctime = startup;
213    un_fattr.na_mtime = startup;
214  }
215
216  if (eq_fh(&argp->da_fhandle, &slink)) {
217    res.dr_status = NFSERR_NOTDIR;
218    return &res;
219  }
220
221  if (getcreds(rqstp, &uid, &gid, nfsxprt) < 0) {
222    res.dr_status = NFSERR_NOENT;
223    return &res;
224  }
225  if (eq_fh(&argp->da_fhandle, &root)) {
226    if (argp->da_name[0] == '.' &&
227	(argp->da_name[1] == '\0' ||
228	 (argp->da_name[1] == '.' &&
229	  argp->da_name[2] == '\0'))) {
230#if 0
231    /*
232     * XXX: increment mtime of parent directory, causes NFS clients to
233     * invalidate their cache for that directory.
234     * Some NFS clients may need this code.
235     */
236      if (uid != rootfattr.na_uid) {
237	clocktime(&rootfattr.na_mtime);
238	rootfattr.na_uid = uid;
239      }
240#endif /* 0 */
241      res.dr_u.dr_drok_u.drok_fhandle = root;
242      res.dr_u.dr_drok_u.drok_attributes = rootfattr;
243      res.dr_status = NFS_OK;
244      return &res;
245    }
246
247    if (STREQ(argp->da_name, slinkname)) {
248#ifndef MNT2_NFS_OPT_SYMTTL
249      /*
250       * This code is needed to defeat Solaris 2.4's (and newer) symlink
251       * values cache.  It forces the last-modified time of the symlink to be
252       * current.  It is not needed if the O/S has an nfs flag to turn off the
253       * symlink-cache at mount time (such as Irix 5.x and 6.x). -Erez.
254       *
255       * Additionally, Linux currently ignores the nt_useconds field,
256       * so we must update the nt_seconds field every time.
257       */
258      if (uid != slinkfattr.na_uid) {
259	clocktime(&slinkfattr.na_mtime);
260	slinkfattr.na_uid = uid;
261      }
262#endif /* not MNT2_NFS_OPT_SYMTTL */
263      res.dr_u.dr_drok_u.drok_fhandle = slink;
264      res.dr_u.dr_drok_u.drok_attributes = slinkfattr;
265      res.dr_status = NFS_OK;
266      return &res;
267    }
268
269    if (gid != hlfs_gid) {
270      res.dr_status = NFSERR_NOENT;
271      return &res;
272    }
273
274    /* if gets here, gid == hlfs_gid */
275    if ((idx = untab_index(argp->da_name)) < 0) {
276      res.dr_status = NFSERR_NOENT;
277      return &res;
278    } else {			/* entry found and gid is permitted */
279      un_fattr.na_fileid = untab[idx].uid;
280      res.dr_u.dr_drok_u.drok_attributes = un_fattr;
281      memset((char *) &un_fhandle, 0, sizeof(am_nfs_fh));
282      *(u_int *) un_fhandle.fh_data = (u_int) untab[idx].uid;
283      xstrlcpy((char *) &un_fhandle.fh_data[sizeof(int)],
284	       untab[idx].username,
285	       sizeof(am_nfs_fh) - sizeof(int));
286      res.dr_u.dr_drok_u.drok_fhandle = un_fhandle;
287      res.dr_status = NFS_OK;
288      dlog("nfs_lookup: successful lookup for uid=%ld, gid=%ld: username=%s",
289	   (long) uid, (long) gid, untab[idx].username);
290      return &res;
291    }
292  } /* end of "if (eq_fh(argp->dir.data, root.data)) {" */
293
294  res.dr_status = NFSERR_STALE;
295  return &res;
296}
297
298
299nfsreadlinkres *
300nfsproc_readlink_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
301{
302  static nfsreadlinkres res;
303  uid_t userid = (uid_t) INVALIDID;
304  gid_t groupid = hlfs_gid + 1;	/* anything not hlfs_gid */
305  int retval = 0;
306  char *path_val = NULL;
307  char *username;
308  static uid_t last_uid = (uid_t) INVALIDID;
309
310  if (eq_fh(argp, &root)) {
311    res.rlr_status = NFSERR_ISDIR;
312  } else if (eq_fh(argp, &slink)) {
313    if (getcreds(rqstp, &userid, &groupid, nfsxprt) < 0)
314      return (nfsreadlinkres *) NULL;
315
316    clocktime(&slinkfattr.na_atime);
317
318    res.rlr_status = NFS_OK;
319    if (groupid == hlfs_gid) {
320      res.rlr_u.rlr_data_u = DOTSTRING;
321    } else if (!(res.rlr_u.rlr_data_u = path_val = homedir(userid, groupid))) {
322      /*
323       * parent process (fork in homedir()) continues
324       * processing, by getting a NULL returned as a
325       * "special".  Child returns result.
326       */
327      return NULL;
328    }
329
330  } else {			/* check if asked for user mailbox */
331
332    if (getcreds(rqstp, &userid, &groupid, nfsxprt) < 0) {
333      return (nfsreadlinkres *) NULL;
334    }
335
336    if (groupid == hlfs_gid) {
337      memset((char *) &userid, 0, sizeof(int));
338      userid = *(u_int *) argp->fh_data;
339      username = (char *) &argp->fh_data[sizeof(int)];
340      if (!(res.rlr_u.rlr_data_u = mailbox(userid, username)))
341	return (nfsreadlinkres *) NULL;
342    } else {
343      res.rlr_status = NFSERR_STALE;
344    }
345  }
346
347  /* print info, but try to avoid repetitions */
348  if (userid != last_uid) {
349    plog(XLOG_USER, "mailbox for uid=%ld, gid=%ld is %s",
350	 (long) userid, (long) groupid, (char *) res.rlr_u.rlr_data_u);
351    last_uid = userid;
352  }
353
354  /* I don't think it will pass this if -D fork */
355  if (serverpid == getpid())
356    return &res;
357
358  if (!svc_sendreply(nfsxprt, (XDRPROC_T_TYPE) xdr_readlinkres, (SVC_IN_ARG_TYPE) &res))
359    svcerr_systemerr(nfsxprt);
360
361  /*
362   * Child exists here.   We need to determine which
363   * exist status to return.  The exit status
364   * is gathered using wait() and determines
365   * if we returned $HOME/.hlfsspool or $ALTDIR.  The parent
366   * needs this info so it can update the lookup table.
367   */
368  if (path_val && alt_spooldir && STREQ(path_val, alt_spooldir))
369    retval = 1;		/* could not get real home dir (or uid 0 user) */
370  else
371    retval = 0;
372
373  /*
374   * If asked for -D nofork, then must return the value,
375   * NOT exit, or else the main hlfsd server exits.
376   * If -D fork (default), then we do want to exit from the process.
377   * Bug: where is that status information being collected?
378   */
379  if (amuDebug(D_FORK))
380    exit(retval);
381  else
382    return &res;
383}
384
385
386nfsreadres *
387nfsproc_read_2_svc(nfsreadargs *argp, struct svc_req *rqstp)
388{
389  static nfsreadres res = {NFSERR_ACCES};
390
391  return &res;
392}
393
394
395voidp
396nfsproc_writecache_2_svc(voidp argp, struct svc_req *rqstp)
397{
398  static char res;
399
400  return (voidp) &res;
401}
402
403
404nfsattrstat *
405nfsproc_write_2_svc(nfswriteargs *argp, struct svc_req *rqstp)
406{
407  static nfsattrstat res = {NFSERR_ROFS};
408
409  return &res;
410}
411
412
413nfsdiropres *
414nfsproc_create_2_svc(nfscreateargs *argp, struct svc_req *rqstp)
415{
416  static nfsdiropres res = {NFSERR_ROFS};
417
418  return &res;
419}
420
421
422nfsstat *
423nfsproc_remove_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
424{
425  static nfsstat res = {NFSERR_ROFS};
426
427  return &res;
428}
429
430
431nfsstat *
432nfsproc_rename_2_svc(nfsrenameargs *argp, struct svc_req *rqstp)
433{
434  static nfsstat res = {NFSERR_ROFS};
435
436  return &res;
437}
438
439
440nfsstat *
441nfsproc_link_2_svc(nfslinkargs *argp, struct svc_req *rqstp)
442{
443  static nfsstat res = {NFSERR_ROFS};
444
445  return &res;
446}
447
448
449nfsstat *
450nfsproc_symlink_2_svc(nfssymlinkargs *argp, struct svc_req *rqstp)
451{
452  static nfsstat res = {NFSERR_ROFS};
453
454  return &res;
455}
456
457
458nfsdiropres *
459nfsproc_mkdir_2_svc(nfscreateargs *argp, struct svc_req *rqstp)
460{
461  static nfsdiropres res = {NFSERR_ROFS};
462
463  return &res;
464}
465
466
467nfsstat *
468nfsproc_rmdir_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
469{
470  static nfsstat res = {NFSERR_ROFS};
471
472  return &res;
473}
474
475
476nfsreaddirres *
477nfsproc_readdir_2_svc(nfsreaddirargs *argp, struct svc_req *rqstp)
478{
479  static nfsreaddirres res;
480  static nfsentry slinkent = {SLINKID, NULL, {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    clocktime(&rootfattr.na_atime);
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 *) NULL;
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
514nfsstatfsres *
515nfsproc_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}
532