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 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 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 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 * 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 * 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 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 * 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 * 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 * 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 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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