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