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 <[email protected]> and Alexander Dupuy <[email protected]>
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 */
52 static nfsfattr rootfattr = {NFDIR, 0040555, 2, 0, 0, 512, 512, 0,
53 1, 0, ROOTID};
54 static nfsfattr slinkfattr = {NFLNK, 0120777, 1, 0, 0, NFS_MAXPATHLEN, 512, 0,
55 (NFS_MAXPATHLEN + 1) / 512, 0, SLINKID};
56 /* user name file attributes */
57 static nfsfattr un_fattr = {NFLNK, 0120777, 1, 0, 0, NFS_MAXPATHLEN, 512, 0,
58 (NFS_MAXPATHLEN + 1) / 512, 0, INVALIDID};
59 static int started;
60 static am_nfs_fh slink;
61 static am_nfs_fh un_fhandle;
62
63 /*
64 * GLOBALS:
65 */
66 am_nfs_fh root;
67 am_nfs_fh *root_fhp = &root;
68
69
70 /* initialize NFS file handles for hlfsd */
71 void
hlfsd_init_filehandles(void)72 hlfsd_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
87 voidp
nfsproc_null_2_svc(voidp argp,struct svc_req * rqstp)88 nfsproc_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 */
97 static int
eq_fh(const am_nfs_fh * fh1,const am_nfs_fh * fh2)98 eq_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
104 nfsattrstat *
nfsproc_getattr_2_svc(am_nfs_fh * argp,struct svc_req * rqstp)105 nfsproc_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 (void)memcpy(&uid, argp->fh_data, sizeof(uid));
164 if (plt_search(uid) != (uid2home_t *) NULL) {
165 res.ns_status = NFS_OK;
166 un_fattr.na_fileid = uid;
167 res.ns_u.ns_attr_u = un_fattr;
168 dlog("nfs_getattr: successful search for uid=%ld, gid=%ld",
169 (long) uid, (long) gid);
170 } else { /* not found */
171 res.ns_status = NFSERR_STALE;
172 }
173 }
174 }
175 return &res;
176 }
177
178
179 nfsattrstat *
nfsproc_setattr_2_svc(nfssattrargs * argp,struct svc_req * rqstp)180 nfsproc_setattr_2_svc(nfssattrargs *argp, struct svc_req *rqstp)
181 {
182 static nfsattrstat res = {NFSERR_ROFS};
183
184 return &res;
185 }
186
187
188 voidp
nfsproc_root_2_svc(voidp argp,struct svc_req * rqstp)189 nfsproc_root_2_svc(voidp argp, struct svc_req *rqstp)
190 {
191 static char res;
192
193 return (voidp) &res;
194 }
195
196
197 nfsdiropres *
nfsproc_lookup_2_svc(nfsdiropargs * argp,struct svc_req * rqstp)198 nfsproc_lookup_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
199 {
200 static nfsdiropres res;
201 int idx;
202 uid_t uid = (uid_t) INVALIDID;
203 gid_t gid = (gid_t) INVALIDID;
204
205 if (!started) {
206 started++;
207 rootfattr.na_ctime = startup;
208 rootfattr.na_mtime = startup;
209 slinkfattr.na_ctime = startup;
210 slinkfattr.na_mtime = startup;
211 un_fattr.na_ctime = startup;
212 un_fattr.na_mtime = startup;
213 }
214
215 if (eq_fh(&argp->da_fhandle, &slink)) {
216 res.dr_status = NFSERR_NOTDIR;
217 return &res;
218 }
219
220 if (getcreds(rqstp, &uid, &gid, nfsxprt) < 0) {
221 res.dr_status = NFSERR_NOENT;
222 return &res;
223 }
224 if (eq_fh(&argp->da_fhandle, &root)) {
225 if (argp->da_name[0] == '.' &&
226 (argp->da_name[1] == '\0' ||
227 (argp->da_name[1] == '.' &&
228 argp->da_name[2] == '\0'))) {
229 #if 0
230 /*
231 * XXX: increment mtime of parent directory, causes NFS clients to
232 * invalidate their cache for that directory.
233 * Some NFS clients may need this code.
234 */
235 if (uid != rootfattr.na_uid) {
236 clocktime(&rootfattr.na_mtime);
237 rootfattr.na_uid = uid;
238 }
239 #endif /* 0 */
240 res.dr_u.dr_drok_u.drok_fhandle = root;
241 res.dr_u.dr_drok_u.drok_attributes = rootfattr;
242 res.dr_status = NFS_OK;
243 return &res;
244 }
245
246 if (STREQ(argp->da_name, slinkname)) {
247 #ifndef MNT2_NFS_OPT_SYMTTL
248 /*
249 * This code is needed to defeat Solaris 2.4's (and newer) symlink
250 * values cache. It forces the last-modified time of the symlink to be
251 * current. It is not needed if the O/S has an nfs flag to turn off the
252 * symlink-cache at mount time (such as Irix 5.x and 6.x). -Erez.
253 *
254 * Additionally, Linux currently ignores the nt_useconds field,
255 * so we must update the nt_seconds field every time.
256 */
257 if (uid != slinkfattr.na_uid) {
258 clocktime(&slinkfattr.na_mtime);
259 slinkfattr.na_uid = uid;
260 }
261 #endif /* not MNT2_NFS_OPT_SYMTTL */
262 res.dr_u.dr_drok_u.drok_fhandle = slink;
263 res.dr_u.dr_drok_u.drok_attributes = slinkfattr;
264 res.dr_status = NFS_OK;
265 return &res;
266 }
267
268 if (gid != hlfs_gid) {
269 res.dr_status = NFSERR_NOENT;
270 return &res;
271 }
272
273 /* if gets here, gid == hlfs_gid */
274 if ((idx = untab_index(argp->da_name)) < 0) {
275 res.dr_status = NFSERR_NOENT;
276 return &res;
277 } else { /* entry found and gid is permitted */
278 un_fattr.na_fileid = untab[idx].uid;
279 res.dr_u.dr_drok_u.drok_attributes = un_fattr;
280 memset(&un_fhandle, 0, sizeof(un_fhandle));
281 memcpy(un_fhandle.fh_data, &untab[idx].uid, sizeof(untab[idx].uid));
282 xstrlcpy((char *) &un_fhandle.fh_data[sizeof(int)],
283 untab[idx].username,
284 sizeof(am_nfs_fh) - sizeof(int));
285 res.dr_u.dr_drok_u.drok_fhandle = un_fhandle;
286 res.dr_status = NFS_OK;
287 dlog("nfs_lookup: successful lookup for uid=%ld, gid=%ld: username=%s",
288 (long) uid, (long) gid, untab[idx].username);
289 return &res;
290 }
291 } /* end of "if (eq_fh(argp->dir.data, root.data)) {" */
292
293 res.dr_status = NFSERR_STALE;
294 return &res;
295 }
296
297
298 nfsreadlinkres *
nfsproc_readlink_2_svc(am_nfs_fh * argp,struct svc_req * rqstp)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 = 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, nfsxprt) < 0)
313 return (nfsreadlinkres *) NULL;
314
315 clocktime(&slinkfattr.na_atime);
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, groupid))) {
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 NULL;
327 }
328
329 } else { /* check if asked for user mailbox */
330
331 if (getcreds(rqstp, &userid, &groupid, nfsxprt) < 0) {
332 return (nfsreadlinkres *) NULL;
333 }
334
335 if (groupid == hlfs_gid) {
336 memcpy(&userid, argp->fh_data, sizeof(userid));
337 username = (char *) &argp->fh_data[sizeof(int)];
338 if (!(res.rlr_u.rlr_data_u = mailbox(userid, username)))
339 return (nfsreadlinkres *) NULL;
340 } else {
341 res.rlr_status = NFSERR_STALE;
342 }
343 }
344
345 /* print info, but try to avoid repetitions */
346 if (userid != last_uid) {
347 plog(XLOG_USER, "mailbox for uid=%ld, gid=%ld is %s",
348 (long) userid, (long) groupid, (char *) res.rlr_u.rlr_data_u);
349 last_uid = userid;
350 }
351
352 /* I don't think it will pass this if -D fork */
353 if (serverpid == getpid())
354 return &res;
355
356 if (!svc_sendreply(nfsxprt, (XDRPROC_T_TYPE) xdr_readlinkres, (SVC_IN_ARG_TYPE) &res))
357 svcerr_systemerr(nfsxprt);
358
359 /*
360 * Child exists here. We need to determine which
361 * exist status to return. The exit status
362 * is gathered using wait() and determines
363 * if we returned $HOME/.hlfsspool or $ALTDIR. The parent
364 * needs this info so it can update the lookup table.
365 */
366 if (path_val && alt_spooldir && STREQ(path_val, alt_spooldir))
367 retval = 1; /* could not get real home dir (or uid 0 user) */
368 else
369 retval = 0;
370
371 /*
372 * If asked for -D nofork, then must return the value,
373 * NOT exit, or else the main hlfsd server exits.
374 * If -D fork (default), then we do want to exit from the process.
375 * Bug: where is that status information being collected?
376 */
377 if (amuDebug(D_FORK))
378 exit(retval);
379 else
380 return &res;
381 }
382
383
384 nfsreadres *
nfsproc_read_2_svc(nfsreadargs * argp,struct svc_req * rqstp)385 nfsproc_read_2_svc(nfsreadargs *argp, struct svc_req *rqstp)
386 {
387 static nfsreadres res = {NFSERR_ACCES};
388
389 return &res;
390 }
391
392
393 voidp
nfsproc_writecache_2_svc(voidp argp,struct svc_req * rqstp)394 nfsproc_writecache_2_svc(voidp argp, struct svc_req *rqstp)
395 {
396 static char res;
397
398 return (voidp) &res;
399 }
400
401
402 nfsattrstat *
nfsproc_write_2_svc(nfswriteargs * argp,struct svc_req * rqstp)403 nfsproc_write_2_svc(nfswriteargs *argp, struct svc_req *rqstp)
404 {
405 static nfsattrstat res = {NFSERR_ROFS};
406
407 return &res;
408 }
409
410
411 nfsdiropres *
nfsproc_create_2_svc(nfscreateargs * argp,struct svc_req * rqstp)412 nfsproc_create_2_svc(nfscreateargs *argp, struct svc_req *rqstp)
413 {
414 static nfsdiropres res = {NFSERR_ROFS};
415
416 return &res;
417 }
418
419
420 nfsstat *
nfsproc_remove_2_svc(nfsdiropargs * argp,struct svc_req * rqstp)421 nfsproc_remove_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
422 {
423 static nfsstat res = {NFSERR_ROFS};
424
425 return &res;
426 }
427
428
429 nfsstat *
nfsproc_rename_2_svc(nfsrenameargs * argp,struct svc_req * rqstp)430 nfsproc_rename_2_svc(nfsrenameargs *argp, struct svc_req *rqstp)
431 {
432 static nfsstat res = {NFSERR_ROFS};
433
434 return &res;
435 }
436
437
438 nfsstat *
nfsproc_link_2_svc(nfslinkargs * argp,struct svc_req * rqstp)439 nfsproc_link_2_svc(nfslinkargs *argp, struct svc_req *rqstp)
440 {
441 static nfsstat res = {NFSERR_ROFS};
442
443 return &res;
444 }
445
446
447 nfsstat *
nfsproc_symlink_2_svc(nfssymlinkargs * argp,struct svc_req * rqstp)448 nfsproc_symlink_2_svc(nfssymlinkargs *argp, struct svc_req *rqstp)
449 {
450 static nfsstat res = {NFSERR_ROFS};
451
452 return &res;
453 }
454
455
456 nfsdiropres *
nfsproc_mkdir_2_svc(nfscreateargs * argp,struct svc_req * rqstp)457 nfsproc_mkdir_2_svc(nfscreateargs *argp, struct svc_req *rqstp)
458 {
459 static nfsdiropres res = {NFSERR_ROFS};
460
461 return &res;
462 }
463
464
465 nfsstat *
nfsproc_rmdir_2_svc(nfsdiropargs * argp,struct svc_req * rqstp)466 nfsproc_rmdir_2_svc(nfsdiropargs *argp, struct svc_req *rqstp)
467 {
468 static nfsstat res = {NFSERR_ROFS};
469
470 return &res;
471 }
472
473
474 nfsreaddirres *
nfsproc_readdir_2_svc(nfsreaddirargs * argp,struct svc_req * rqstp)475 nfsproc_readdir_2_svc(nfsreaddirargs *argp, struct svc_req *rqstp)
476 {
477 static nfsreaddirres res;
478 static nfsentry slinkent = {SLINKID, NULL, {SLINKCOOKIE}};
479 static nfsentry dotdotent = {ROOTID, "..", {DOTDOTCOOKIE}, &slinkent};
480 static nfsentry dotent = {ROOTID, ".", {DOTCOOKIE}, &dotdotent};
481
482 slinkent.ne_name = slinkname;
483
484 if (eq_fh(&argp->rda_fhandle, &slink)) {
485 res.rdr_status = NFSERR_NOTDIR;
486 } else if (eq_fh(&argp->rda_fhandle, &root)) {
487 clocktime(&rootfattr.na_atime);
488
489 res.rdr_status = NFS_OK;
490 switch (argp->rda_cookie[0]) {
491 case 0:
492 res.rdr_u.rdr_reply_u.dl_entries = &dotent;
493 break;
494 case DOTCOOKIE:
495 res.rdr_u.rdr_reply_u.dl_entries = &dotdotent;
496 break;
497 case DOTDOTCOOKIE:
498 res.rdr_u.rdr_reply_u.dl_entries = &slinkent;
499 break;
500 case SLINKCOOKIE:
501 res.rdr_u.rdr_reply_u.dl_entries = (nfsentry *) NULL;
502 break;
503 }
504 res.rdr_u.rdr_reply_u.dl_eof = TRUE;
505 } else {
506 res.rdr_status = NFSERR_STALE;
507 }
508 return &res;
509 }
510
511
512 nfsstatfsres *
nfsproc_statfs_2_svc(am_nfs_fh * argp,struct svc_req * rqstp)513 nfsproc_statfs_2_svc(am_nfs_fh *argp, struct svc_req *rqstp)
514 {
515 static nfsstatfsres res = {NFS_OK};
516
517 res.sfr_u.sfr_reply_u.sfrok_tsize = 1024;
518 res.sfr_u.sfr_reply_u.sfrok_bsize = 1024;
519
520 /*
521 * Some "df" programs automatically assume that file systems
522 * with zero blocks are meta-filesystems served by automounters.
523 */
524 res.sfr_u.sfr_reply_u.sfrok_blocks = 0;
525 res.sfr_u.sfr_reply_u.sfrok_bfree = 0;
526 res.sfr_u.sfr_reply_u.sfrok_bavail = 0;
527
528 return &res;
529 }
530