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