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