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