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