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.
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
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.
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
42 * File: am-utils/hlfsd/stubs.c
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.
51 #endif /* HAVE_CONFIG_H */
58 static nfsfattr rootfattr
= {NFDIR
, 0040555, 2, 0, 0, 512, 512, 0,
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
};
66 static am_nfs_fh slink
;
67 static am_nfs_fh un_fhandle
;
73 am_nfs_fh
*root_fhp
= &root
;
76 /* initialize NFS file handles for hlfsd */
78 hlfsd_init_filehandles(void)
83 memcpy(root
.fh_data
, &ui
, sizeof(ui
));
86 memcpy(slink
.fh_data
, &ui
, sizeof(ui
));
89 memcpy(un_fhandle
.fh_data
, &ui
, sizeof(ui
));
94 nfsproc_null_2_svc(voidp argp
, struct svc_req
*rqstp
)
102 /* compare if two filehandles are equal */
104 eq_fh(const am_nfs_fh
*fh1
, const am_nfs_fh
*fh2
)
106 return (!memcmp((char *) fh1
, (char *) fh2
, sizeof(am_nfs_fh
)));
111 nfsproc_getattr_2_svc(am_nfs_fh
*argp
, struct svc_req
*rqstp
)
113 static nfsattrstat res
;
114 uid_t uid
= (uid_t
) INVALIDID
;
115 gid_t gid
= (gid_t
) INVALIDID
;
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
;
127 if (getcreds(rqstp
, &uid
, &gid
, nfsxprt
) < 0) {
128 res
.ns_status
= NFSERR_STALE
;
131 if (eq_fh(argp
, &root
)) {
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.
138 if (uid
!= rootfattr
.na_uid
) {
139 clocktime(&rootfattr
.na_mtime
);
140 rootfattr
.na_uid
= uid
;
143 res
.ns_status
= NFS_OK
;
144 res
.ns_u
.ns_attr_u
= rootfattr
;
145 } else if (eq_fh(argp
, &slink
)) {
147 #ifndef MNT2_NFS_OPT_SYMTTL
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.
154 * Additionally, Linux currently ignores the nt_useconds field,
155 * so we must update the nt_seconds field every time.
157 if (uid
!= slinkfattr
.na_uid
) {
158 clocktime(&slinkfattr
.na_mtime
);
159 slinkfattr
.na_uid
= uid
;
161 #endif /* not MNT2_NFS_OPT_SYMTTL */
163 res
.ns_status
= NFS_OK
;
164 res
.ns_u
.ns_attr_u
= slinkfattr
;
166 if (gid
!= hlfs_gid
) {
167 res
.ns_status
= NFSERR_STALE
;
169 memset((char *) &uid
, 0, sizeof(int));
170 uid
= *(u_int
*) argp
->fh_data
;
171 if (plt_search(uid
) != (uid2home_t
*) NULL
) {
172 res
.ns_status
= NFS_OK
;
173 un_fattr
.na_fileid
= uid
;
174 res
.ns_u
.ns_attr_u
= un_fattr
;
175 dlog("nfs_getattr: successful search for uid=%ld, gid=%ld",
176 (long) uid
, (long) gid
);
177 } else { /* not found */
178 res
.ns_status
= NFSERR_STALE
;
187 nfsproc_setattr_2_svc(nfssattrargs
*argp
, struct svc_req
*rqstp
)
189 static nfsattrstat res
= {NFSERR_ROFS
};
196 nfsproc_root_2_svc(voidp argp
, struct svc_req
*rqstp
)
205 nfsproc_lookup_2_svc(nfsdiropargs
*argp
, struct svc_req
*rqstp
)
207 static nfsdiropres res
;
209 uid_t uid
= (uid_t
) INVALIDID
;
210 gid_t gid
= (gid_t
) INVALIDID
;
214 rootfattr
.na_ctime
= startup
;
215 rootfattr
.na_mtime
= startup
;
216 slinkfattr
.na_ctime
= startup
;
217 slinkfattr
.na_mtime
= startup
;
218 un_fattr
.na_ctime
= startup
;
219 un_fattr
.na_mtime
= startup
;
222 if (eq_fh(&argp
->da_fhandle
, &slink
)) {
223 res
.dr_status
= NFSERR_NOTDIR
;
227 if (getcreds(rqstp
, &uid
, &gid
, nfsxprt
) < 0) {
228 res
.dr_status
= NFSERR_NOENT
;
231 if (eq_fh(&argp
->da_fhandle
, &root
)) {
232 if (argp
->da_name
[0] == '.' &&
233 (argp
->da_name
[1] == '\0' ||
234 (argp
->da_name
[1] == '.' &&
235 argp
->da_name
[2] == '\0'))) {
238 * XXX: increment mtime of parent directory, causes NFS clients to
239 * invalidate their cache for that directory.
240 * Some NFS clients may need this code.
242 if (uid
!= rootfattr
.na_uid
) {
243 clocktime(&rootfattr
.na_mtime
);
244 rootfattr
.na_uid
= uid
;
247 res
.dr_u
.dr_drok_u
.drok_fhandle
= root
;
248 res
.dr_u
.dr_drok_u
.drok_attributes
= rootfattr
;
249 res
.dr_status
= NFS_OK
;
253 if (STREQ(argp
->da_name
, slinkname
)) {
254 #ifndef MNT2_NFS_OPT_SYMTTL
256 * This code is needed to defeat Solaris 2.4's (and newer) symlink
257 * values cache. It forces the last-modified time of the symlink to be
258 * current. It is not needed if the O/S has an nfs flag to turn off the
259 * symlink-cache at mount time (such as Irix 5.x and 6.x). -Erez.
261 * Additionally, Linux currently ignores the nt_useconds field,
262 * so we must update the nt_seconds field every time.
264 if (uid
!= slinkfattr
.na_uid
) {
265 clocktime(&slinkfattr
.na_mtime
);
266 slinkfattr
.na_uid
= uid
;
268 #endif /* not MNT2_NFS_OPT_SYMTTL */
269 res
.dr_u
.dr_drok_u
.drok_fhandle
= slink
;
270 res
.dr_u
.dr_drok_u
.drok_attributes
= slinkfattr
;
271 res
.dr_status
= NFS_OK
;
275 if (gid
!= hlfs_gid
) {
276 res
.dr_status
= NFSERR_NOENT
;
280 /* if gets here, gid == hlfs_gid */
281 if ((idx
= untab_index(argp
->da_name
)) < 0) {
282 res
.dr_status
= NFSERR_NOENT
;
284 } else { /* entry found and gid is permitted */
285 un_fattr
.na_fileid
= untab
[idx
].uid
;
286 res
.dr_u
.dr_drok_u
.drok_attributes
= un_fattr
;
287 memset((char *) &un_fhandle
, 0, sizeof(am_nfs_fh
));
288 *(u_int
*) un_fhandle
.fh_data
= (u_int
) untab
[idx
].uid
;
289 xstrlcpy((char *) &un_fhandle
.fh_data
[sizeof(int)],
291 sizeof(am_nfs_fh
) - sizeof(int));
292 res
.dr_u
.dr_drok_u
.drok_fhandle
= un_fhandle
;
293 res
.dr_status
= NFS_OK
;
294 dlog("nfs_lookup: successful lookup for uid=%ld, gid=%ld: username=%s",
295 (long) uid
, (long) gid
, untab
[idx
].username
);
298 } /* end of "if (eq_fh(argp->dir.data, root.data)) {" */
300 res
.dr_status
= NFSERR_STALE
;
306 nfsproc_readlink_2_svc(am_nfs_fh
*argp
, struct svc_req
*rqstp
)
308 static nfsreadlinkres res
;
309 uid_t userid
= (uid_t
) INVALIDID
;
310 gid_t groupid
= hlfs_gid
+ 1; /* anything not hlfs_gid */
312 char *path_val
= (char *) NULL
;
314 static uid_t last_uid
= (uid_t
) INVALIDID
;
316 if (eq_fh(argp
, &root
)) {
317 res
.rlr_status
= NFSERR_ISDIR
;
318 } else if (eq_fh(argp
, &slink
)) {
319 if (getcreds(rqstp
, &userid
, &groupid
, nfsxprt
) < 0)
320 return (nfsreadlinkres
*) NULL
;
322 clocktime(&slinkfattr
.na_atime
);
324 res
.rlr_status
= NFS_OK
;
325 if (groupid
== hlfs_gid
) {
326 res
.rlr_u
.rlr_data_u
= DOTSTRING
;
327 } else if (!(res
.rlr_u
.rlr_data_u
= path_val
= homedir(userid
, groupid
))) {
329 * parent process (fork in homedir()) continues
330 * processing, by getting a NULL returned as a
331 * "special". Child returns result.
333 return (nfsreadlinkres
*) NULL
;
336 } else { /* check if asked for user mailbox */
338 if (getcreds(rqstp
, &userid
, &groupid
, nfsxprt
) < 0) {
339 return (nfsreadlinkres
*) NULL
;
342 if (groupid
== hlfs_gid
) {
343 memset((char *) &userid
, 0, sizeof(int));
344 userid
= *(u_int
*) argp
->fh_data
;
345 username
= (char *) &argp
->fh_data
[sizeof(int)];
346 if (!(res
.rlr_u
.rlr_data_u
= mailbox(userid
, username
)))
347 return (nfsreadlinkres
*) NULL
;
349 res
.rlr_status
= NFSERR_STALE
;
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
);
360 /* I don't think it will pass this if -D fork */
361 if (serverpid
== getpid())
364 if (!svc_sendreply(nfsxprt
, (XDRPROC_T_TYPE
) xdr_readlinkres
, (SVC_IN_ARG_TYPE
) &res
))
365 svcerr_systemerr(nfsxprt
);
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.
374 if (path_val
&& alt_spooldir
&& STREQ(path_val
, alt_spooldir
))
375 retval
= 1; /* could not get real home dir (or uid 0 user) */
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?
385 if (amuDebug(D_FORK
))
393 nfsproc_read_2_svc(nfsreadargs
*argp
, struct svc_req
*rqstp
)
395 static nfsreadres res
= {NFSERR_ACCES
};
402 nfsproc_writecache_2_svc(voidp argp
, struct svc_req
*rqstp
)
411 nfsproc_write_2_svc(nfswriteargs
*argp
, struct svc_req
*rqstp
)
413 static nfsattrstat res
= {NFSERR_ROFS
};
420 nfsproc_create_2_svc(nfscreateargs
*argp
, struct svc_req
*rqstp
)
422 static nfsdiropres res
= {NFSERR_ROFS
};
429 nfsproc_remove_2_svc(nfsdiropargs
*argp
, struct svc_req
*rqstp
)
431 static nfsstat res
= {NFSERR_ROFS
};
438 nfsproc_rename_2_svc(nfsrenameargs
*argp
, struct svc_req
*rqstp
)
440 static nfsstat res
= {NFSERR_ROFS
};
447 nfsproc_link_2_svc(nfslinkargs
*argp
, struct svc_req
*rqstp
)
449 static nfsstat res
= {NFSERR_ROFS
};
456 nfsproc_symlink_2_svc(nfssymlinkargs
*argp
, struct svc_req
*rqstp
)
458 static nfsstat res
= {NFSERR_ROFS
};
465 nfsproc_mkdir_2_svc(nfscreateargs
*argp
, struct svc_req
*rqstp
)
467 static nfsdiropres res
= {NFSERR_ROFS
};
474 nfsproc_rmdir_2_svc(nfsdiropargs
*argp
, struct svc_req
*rqstp
)
476 static nfsstat res
= {NFSERR_ROFS
};
483 nfsproc_readdir_2_svc(nfsreaddirargs
*argp
, struct svc_req
*rqstp
)
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
};
490 slinkent
.ne_name
= slinkname
;
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
);
497 res
.rdr_status
= NFS_OK
;
498 switch (argp
->rda_cookie
[0]) {
500 res
.rdr_u
.rdr_reply_u
.dl_entries
= &dotent
;
503 res
.rdr_u
.rdr_reply_u
.dl_entries
= &dotdotent
;
506 res
.rdr_u
.rdr_reply_u
.dl_entries
= &slinkent
;
509 res
.rdr_u
.rdr_reply_u
.dl_entries
= (nfsentry
*) NULL
;
512 res
.rdr_u
.rdr_reply_u
.dl_eof
= TRUE
;
514 res
.rdr_status
= NFSERR_STALE
;
521 nfsproc_statfs_2_svc(am_nfs_fh
*argp
, struct svc_req
*rqstp
)
523 static nfsstatfsres res
= {NFS_OK
};
525 res
.sfr_u
.sfr_reply_u
.sfrok_tsize
= 1024;
526 res
.sfr_u
.sfr_reply_u
.sfrok_bsize
= 1024;
529 * Some "df" programs automatically assume that file systems
530 * with zero blocks are meta-filesystems served by automounters.
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;