home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1996 May / PCOnline_05_1996.bin / linux / source / n / tcpip / nfs-serv.1 / nfs-serv / nfs-server-2.1 / nfsd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-03-11  |  24.3 KB  |  983 lines

  1. /*
  2.  * nfsd        This program handles RPC "NFS" data requests.
  3.  *
  4.  * Usage:    [rpc.]nfsd [-dhnprv] [-f authfile]
  5.  *
  6.  * Authors:    Mark A. Shand, May 1988
  7.  *        Donald J. Becker, <becker@super.org>
  8.  *        Rick Sladkey, <jrs@world.std.com>
  9.  *        Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  10.  *        Eric Kasten, <tigger@tigger.cl.msu.edu>
  11.  *
  12.  *        Copyright 1988 Mark A. Shand
  13.  *        This software maybe be used for any purpose provided
  14.  *        the above copyright notice is retained.  It is supplied
  15.  *        as is, with no warranty expressed or implied.
  16.  */
  17.  
  18. #include "nfsd.h"
  19. #include "getopt.h"
  20. #include "fsusage.h"
  21.  
  22. #define _RPCSVC_CLOSEDOWN 120
  23.  
  24. static char iobuf[NFS_MAXDATA];
  25. static char pathbuf[NFS_MAXPATHLEN + 1];
  26. static char pathbuf_1[NFS_MAXPATHLEN + 1];
  27. int _rpcpmstart = 0;
  28. int _rpcsvcdirty = 0;
  29. int _rpcfdtype = 0;
  30.  
  31. static _PRO(void usage, (FILE *, int));
  32.  
  33. extern char version[];
  34. static char *program_name;
  35. static struct option longopts[] =
  36. {
  37.     { "debug", 0, 0, 'd' },
  38.     { "exports-file", 1, 0, 'f' },
  39.     { "help", 0, 0, 'h' },
  40.     { "allow-non-root", 0, 0, 'n' },
  41.     { "promiscuous", 0, 0, 'p' },
  42.     { "re-export", 0, 0, 'r', },
  43.     { "no-spoof-trace", 0, 0, 's' },
  44.     { "version", 0, 0, 'v' },
  45.     { NULL, 0, 0, 0 }
  46. };
  47.  
  48. extern clnt_param *cp;        /* only for the option list    */
  49.  
  50. extern _PRO(void nfs_dispatch, (struct svc_req * rqstp, SVCXPRT * transp));
  51. static _PRO(nfsstat build_path, (char *buf, diropargs * da));
  52. static _PRO(int makesock, (int port, int proto, int socksz));
  53. static _PRO(void closedown, (int sig));
  54.  
  55. extern void xdr_free();        /* fill this in later */
  56. extern void pmap_unset();    /* why here??? */
  57.  
  58. /*
  59.  * check_ro_attrib -- tig
  60.  *
  61.  * This function will check to see if the nfs directory is mounted
  62.  * read only.  If it is an error status is returned.
  63.  *
  64.  * Parameters:
  65.  *    int auth - Where fs authentication is expected.
  66.  *    struct svc_req *rqstp - The RPC service request.
  67.  *    char *path - The file system path.
  68.  *    clnt_param *cp - The Client fs parameters as supplied from the
  69.  *       internal table of exported file systems.
  70.  *
  71.  * Returns:
  72.  *    NFS_OK - If authenication isn't needed or if fs is read/write.
  73.  *    NFSERR_ACCES - If the fs can't be found among the exported fs.
  74.  *    NFSERR_ROFS - If the fs is a read-only fs.
  75.  */
  76. static inline int check_ro_attrib(auth, rqstp, path, cp)
  77. int auth;
  78. struct svc_req *rqstp;
  79. char *path;
  80. clnt_param *cp;
  81. {
  82.     /* Now we attempt to authenticate the clients credentials. */
  83.     if (auth) {
  84.         /* Retrieve the client's parameters. */
  85.         if ((cp = auth_clnt(rqstp, path)) == NULL)
  86.             return (NFSERR_ACCES); 
  87.         /* If this is a read only mount, then we'd better punt. */ 
  88.         if (cp->o.read_only)
  89.             return (NFSERR_ROFS);
  90.     }
  91.     return (NFS_OK);
  92. }
  93.  
  94. static inline nfsstat build_path(buf, da)
  95. char *buf;
  96. diropargs *da;
  97. {
  98.     nfsstat status;
  99.     char *path, *fname;
  100.  
  101.     if ((path = fh_path(&(da->dir), &status)) == 0)
  102.         return (NFSERR_STALE);
  103.  
  104.     while (*path)        /* strcpy(buf, path); */
  105.         *buf++ = *path++;
  106.     *buf++ = '/';        /* strcat(buf, "/");  */
  107.     fname = da->name;
  108.     while (*fname)        /* strcat(pathbuf, argp->where.name); */
  109.         *buf++ = *fname++;
  110.     *buf = '\0';
  111.     return (NFS_OK);
  112. }
  113.  
  114. /*
  115.  * The "wrappers" of the following functions came from `rpcgen -l nfs_prot.x`.
  116.  * This normally generates the client routines, but it provides nice
  117.  * prototypes for the server routines also.
  118.  */
  119. #define CLIENT struct svc_req
  120.  
  121. int nfsd_nfsproc_null_2(argp)
  122. void *argp;
  123. {
  124.     return (0);
  125. }
  126.  
  127. int nfsd_nfsproc_getattr_2(argp)
  128. nfs_fh *argp;
  129. {
  130.     return (getattr(argp, &result.attrstat.attrstat_u.attributes, NULL));
  131. }
  132.  
  133. int nfsd_nfsproc_setattr_2(argp)
  134. sattrargs *argp;
  135. {
  136.     nfsstat status;
  137.     char *path;
  138.     struct stat buf;
  139.  
  140.     if ((path = fh_path(&(argp->file), &status)) == NULL) {
  141.         /* That means we can't get a path to the file.  Give up. */
  142.         return (NFSERR_STALE);
  143.     }
  144.     status = check_ro_attrib(client_authenticate, svc_rqstp, path, cp);
  145.     if (status != NFS_OK)
  146.         return(status);
  147.  
  148.     errno = 0;
  149.     /* Stat the file first and only change fields that are different. */
  150.     if (lstat(path, &buf) < 0)
  151.         goto failure;
  152.     if (((argp->attributes.uid != -1
  153.         && argp->attributes.uid != buf.st_uid)
  154.         || (argp->attributes.gid != -1
  155.         && argp->attributes.gid != buf.st_gid))
  156.         && lchown(path, argp->attributes.uid, argp->attributes.gid) < 0)
  157.         goto failure;
  158.     if (argp->attributes.mode != -1
  159.        && (argp->attributes.mode & 07777) != (buf.st_mode & 07777)
  160.        && chmod(path, argp->attributes.mode) < 0)
  161.         goto failure;
  162.     if (S_ISREG(buf.st_mode)
  163.         && argp->attributes.size != -1
  164.         && argp->attributes.size != buf.st_size
  165.         && truncate(path, argp->attributes.size) < 0)
  166.         goto failure;
  167.     if ((argp->attributes.atime.seconds != (unsigned) -1
  168.        && argp->attributes.atime.seconds != buf.st_atime)
  169.        || (argp->attributes.mtime.seconds != (unsigned) -1
  170.        && argp->attributes.mtime.seconds != buf.st_mtime)) {
  171.         struct timeval tvp[2];
  172.         tvp[0].tv_sec = argp->attributes.atime.seconds;
  173.         tvp[0].tv_usec = argp->attributes.atime.useconds;
  174.         tvp[1].tv_sec = argp->attributes.mtime.seconds;
  175.         tvp[1].tv_usec = argp->attributes.mtime.useconds;
  176.         if (utimes(path, tvp) < 0)
  177.             goto failure;
  178.     }
  179.     return (getattr(&(argp->file),
  180.         &(result.attrstat.attrstat_u.attributes), NULL));
  181.  
  182. failure:
  183.     return (nfs_errno());
  184. }
  185.  
  186. int nfsd_nfsproc_root_2(argp)
  187. void *argp;
  188. {
  189.     return (0);
  190. }
  191.  
  192. int nfsd_nfsproc_lookup_2(argp)
  193. diropargs *argp;
  194. {
  195.     int status;
  196.     struct stat sbuf;
  197.     struct stat *sbp = &sbuf;
  198.     diropokres *dp = &result.diropres.diropres_u.diropres;
  199.  
  200.     status = fh_compose(argp, &(dp->file), &sbp, -1, -1);
  201.     if (status == NFS_OK) {
  202.         status = getattr(&(dp->file), &(dp->attributes), sbp);
  203.         if (status == NFS_OK)
  204.             dprintf(1, "\tnew_fh = %s\n", fh_pr(&(dp->file)));
  205.     }
  206.     return (status);
  207. }
  208.  
  209. int nfsd_nfsproc_readlink_2(argp)
  210. nfs_fh *argp;
  211. {
  212.     nfsstat status;
  213.     char *path;
  214.     int cc;
  215.  
  216.     if ((path = fh_path(argp, &status)) == 0)
  217.         return (NFSERR_STALE);
  218.  
  219.     errno = 0;
  220.     if ((cc = readlink(path, pathbuf, NFS_MAXPATHLEN)) < 0) {
  221.         dprintf(1, " >>> %s\n", strerror(errno));
  222.         return (nfs_errno());
  223.     }
  224.     status = NFS_OK;
  225.     pathbuf[cc] = '\0';    /* readlink() doesn't null terminate!! */
  226.     result.readlinkres.readlinkres_u.data = pathbuf;
  227.  
  228.     /* Now we attempt to authenticate the clients credentials. */
  229.     if ((cp = auth_clnt(svc_rqstp, path)) == NULL)
  230.         return (NFSERR_ACCES);
  231.  
  232.     if (cp->o.link_relative && pathbuf[0] == '/') {
  233.         /*
  234.          * We've got an absolute (locally) pathname, and we should
  235.          * translate to a relative pathname for the client.  We do
  236.          * this by prepending the correct number of "../"es to the
  237.          * path. This cannot work if the client does not mount the
  238.          * specified subtree of the filesystem.
  239.          */
  240.         int slash_cnt = 0;
  241.         char *p, *q;
  242.  
  243.         /* Count how many directories down we are. */
  244.         for (p = path + 1; *p != '\0'; p++)
  245.             if (*p == '/')
  246.                 slash_cnt++;
  247.  
  248.         /*
  249.          * Ok, now we are finished with the orginal file `path'
  250.          * and will only deal with the link target.
  251.          */
  252.         p = &pathbuf[cc];    /* Point to the end and calculate */
  253.         if (slash_cnt == 0)
  254.             q = p + 1;    /* the extra space take by a    */
  255.         else        /* prepended '.'          */
  256.             q = p + 3 * slash_cnt - 1;    /* or '../.../..' */
  257.  
  258.         if (q >= pathbuf + NFS_MAXPATHLEN) {
  259.             dprintf(1, " [[NAME TOO LONG!!]]\n");
  260.             return (NFSERR_NAMETOOLONG);
  261.         } else {
  262.             /* Add some space at the beginning of the string. */
  263.             while (p >= pathbuf)
  264.                 *q-- = *p--;
  265.  
  266.             if (slash_cnt == 0)
  267.                 pathbuf[0] = '.';
  268.             else {
  269.                 /*
  270.                  * This overwrites the leading '/' on the
  271.                  * last iteration.
  272.                  */
  273.                 for (p = pathbuf; slash_cnt > 0; slash_cnt--) {
  274.                     *p++ = '.';
  275.                     *p++ = '.';
  276.                     *p++ = '/';
  277.                 }
  278.             }
  279.         }
  280.     }
  281.     dprintf(1, " %s\n", result.readlinkres.readlinkres_u.data);
  282.     return (NFS_OK);
  283. }
  284.  
  285. int nfsd_nfsproc_read_2(argp)
  286. readargs *argp;
  287. {
  288.     nfsstat status;
  289.     int fd;
  290.  
  291.     if ((fd = fh_fd(&(argp->file), &status, O_RDONLY)) < 0) {
  292.         return ((int) status);
  293.     }
  294.     errno = 0;
  295.     (void) lseek(fd, (long) argp->offset, L_SET);
  296.     result.readres.readres_u.reply.data.data_val = iobuf;
  297.     if (!errno)
  298.         result.readres.readres_u.reply.data.data_len =
  299.             read(fd, iobuf, argp->count);
  300.     fd_inactive(fd);
  301.     if (errno)
  302.         return (nfs_errno());
  303.     return (getattr(&(argp->file),
  304.             &(result.readres.readres_u.reply.attributes), NULL));
  305. }
  306.  
  307. int nfsd_nfsproc_writecache_2(argp)
  308. void *argp;
  309. {
  310.     return (0);
  311. }
  312.  
  313. int nfsd_nfsproc_write_2(argp)
  314. writeargs *argp;
  315. {
  316.     nfsstat status;
  317.     int fd;
  318.  
  319.     if ((fd = fh_fd(&(argp->file), &status, O_WRONLY)) < 0) {
  320.         return ((int) status);
  321.     }
  322.     errno = 0;
  323.     (void) lseek(fd, (long) argp->offset, L_SET);
  324.     if (errno == 0) {    /* We should never fail. */
  325.         if (write(fd, argp->data.data_val, argp->data.data_len) !=
  326.             argp->data.data_len) {
  327.             dprintf(1, " Write failure, errno is %d.\n", errno);
  328.         }
  329.     }
  330.     fd_inactive(fd);
  331.     if (errno)
  332.         return (nfs_errno());
  333.     return (getattr(&(argp->file),
  334.             &(result.attrstat.attrstat_u.attributes), NULL));
  335. }
  336.  
  337. #define CREATE_OMODE O_RDWR
  338.  
  339. int nfsd_nfsproc_create_2(argp)
  340. createargs *argp;
  341. {
  342.     nfsstat status;
  343.     int tmpfd, flags;
  344.     struct stat sbuf;
  345.     struct stat *sbp = &sbuf;
  346.     uid_t target_uid;
  347.     gid_t target_gid;
  348.     int is_borc;
  349.     int dev;
  350.     int exists;
  351.  
  352.     status = build_path(pathbuf, &argp->where);
  353.     if (status != NFS_OK)
  354.         return ((int) status);
  355.     dprintf(1, "\tfullpath='%s'\n", pathbuf);
  356.     errno = 0;
  357.  
  358.     exists = lstat(pathbuf, &sbuf) == 0;
  359.  
  360.     /* Compensate for a really bizarre bug in SunOS derived clients. */
  361.     if ((argp->attributes.mode & S_IFMT) == 0)
  362.         argp->attributes.mode |= exists
  363.             ? (sbuf.st_mode & S_IFMT) : S_IFREG;
  364.  
  365.     /* First handle any unusual file-types. */
  366.     if (!S_ISREG(argp->attributes.mode)) {
  367.         if (S_ISBLK(argp->attributes.mode)
  368.             || S_ISCHR(argp->attributes.mode)) {
  369.             is_borc = 1;
  370.             /* This is probably better than just using
  371.                the size field by itself, but not by much. */
  372.             dev = makedev(((argp->attributes.size >> 8) & 0xff),
  373.                 (argp->attributes.size & 0xff));
  374.         }
  375.         else {
  376.             is_borc = 0;
  377.             dev = 0;
  378.         }
  379.         /* mknod will fail for EEXIST, we'll let it succeed. */
  380.         if (exists) {
  381.             /* But make sure it's the same kind of special file. */
  382.             if ((argp->attributes.mode & S_IFMT)
  383.                 != (sbuf.st_mode & S_IFMT))
  384.                 return (NFSERR_EXIST);
  385.             /* And that the major and minor numbers agree. */
  386.             if (is_borc && dev != sbuf.st_rdev)
  387.                 return (NFSERR_EXIST);
  388.         }
  389.         else {
  390.             status = check_ro_attrib(client_authenticate,
  391.                 svc_rqstp, pathbuf, cp);
  392.             if (status != NFS_OK)
  393.                 return (status);
  394.             if (mknod(pathbuf, argp->attributes.mode, dev) < 0)
  395.                 return (nfs_errno());
  396.             if (stat(pathbuf, &sbuf) < 0)
  397.                 return (nfs_errno());
  398.         }
  399.         tmpfd = -1;
  400.     }
  401.     else {
  402.         status = check_ro_attrib(client_authenticate,
  403.             svc_rqstp, pathbuf, cp);
  404.         if (status != NFS_OK)
  405.             return (status);
  406.         flags = (argp->attributes.size == 0 ?
  407.             CREATE_OMODE | O_CREAT | O_TRUNC :
  408.             CREATE_OMODE | O_CREAT);
  409.         tmpfd = path_open(pathbuf, flags, argp->attributes.mode);
  410.         if (tmpfd < 0)
  411.             goto failure;
  412.         (void) fstat(tmpfd, &sbuf);
  413.     }
  414.  
  415.     target_uid = argp->attributes.uid;
  416.     target_gid = argp->attributes.gid;
  417.  
  418.     if ((target_uid != (uid_t) -1 && sbuf.st_uid != target_uid) ||
  419.         (target_gid != (gid_t) -1 && sbuf.st_gid != target_gid)) {
  420.         if (lchown(pathbuf, target_uid, target_gid) < 0)
  421.             goto failure;
  422.         if (target_uid != (uid_t) -1)
  423.             sbuf.st_uid = target_uid;
  424.         if (target_gid != (gid_t) -1)
  425.             sbuf.st_gid = target_gid;
  426.     }
  427.  
  428.     if (S_ISREG(argp->attributes.mode)
  429.         && argp->attributes.size != -1
  430.         && argp->attributes.size != sbuf.st_size) {
  431.         if (truncate(pathbuf, argp->attributes.size) < 0)
  432.             goto failure;
  433.         sbuf.st_size = argp->attributes.size;
  434.     }
  435.     if ((argp->attributes.atime.seconds != -1 &&
  436.          argp->attributes.atime.seconds != sbuf.st_atime) ||
  437.         (argp->attributes.mtime.seconds != -1 &&
  438.          argp->attributes.mtime.seconds != sbuf.st_mtime)) {
  439.         struct timeval tvp[2];
  440.         tvp[0].tv_sec = argp->attributes.atime.seconds;
  441.         tvp[0].tv_usec = argp->attributes.atime.useconds;
  442.         tvp[1].tv_sec = argp->attributes.mtime.seconds;
  443.         tvp[1].tv_usec = argp->attributes.mtime.useconds;
  444.         if (utimes(pathbuf, tvp) < 0)
  445.             goto failure;
  446.         if (argp->attributes.atime.seconds != -1)
  447.             sbuf.st_atime = argp->attributes.atime.seconds;
  448.         if (argp->attributes.mtime.seconds != -1)
  449.             sbuf.st_mtime = argp->attributes.mtime.seconds;
  450.     }
  451.     if (argp->attributes.mode != -1
  452.        && (argp->attributes.mode & 07777) != (sbuf.st_mode & 07777)) {
  453.         if (chmod(pathbuf, argp->attributes.mode) < 0)
  454.             goto failure;
  455.         sbuf.st_mode = (sbuf.st_mode & S_IFMT)
  456.             | (argp->attributes.mode & 07777);
  457.     }
  458.     status = fh_compose(&(argp->where),
  459.         &(result.diropres.diropres_u.diropres.file), &sbp,
  460.         tmpfd, CREATE_OMODE);
  461.     if (status != NFS_OK)
  462.         goto failure;
  463.     status = getattr(&(result.diropres.diropres_u.diropres.file),
  464.         &(result.diropres.diropres_u.diropres.attributes),
  465.         sbp);
  466.     if (status != NFS_OK)
  467.         goto failure;
  468.     dprintf(1, "\tnew_fh = %s\n",
  469.         fh_pr(&(result.diropres.diropres_u.diropres.file)));
  470.     return (status);
  471.  
  472. failure:
  473.     dprintf(1, "\tcreate failed -- errno returned=%d.\n", errno);
  474.     if (tmpfd != -1)
  475.         close(tmpfd);
  476.     return (nfs_errno());
  477. }
  478.  
  479. #undef CREATE_OMODE
  480.  
  481. int nfsd_nfsproc_remove_2(argp)
  482. diropargs *argp;
  483. {
  484.     nfsstat status;
  485.  
  486.     status = build_path(pathbuf, argp);
  487.     if (status != NFS_OK)
  488.         return ((int) status);
  489.  
  490.     dprintf(1, "\tfullpath='%s'\n", pathbuf);
  491.  
  492.     status = check_ro_attrib(client_authenticate, svc_rqstp, pathbuf, cp);
  493.     if (status != NFS_OK)
  494.         return (status);
  495.  
  496.     /* Remove the file handle from our cache. */
  497.     fh_remove(pathbuf);
  498.  
  499.     if (unlink(pathbuf) != 0)
  500.         return (nfs_errno());
  501.     else
  502.         return (NFS_OK);
  503. }
  504.  
  505. int nfsd_nfsproc_rename_2(argp)
  506. renameargs *argp;
  507. {
  508.     nfsstat status;
  509.  
  510.     status = build_path(pathbuf, &argp->from);
  511.     if (status != NFS_OK)
  512.         return ((int) status);
  513.     status = build_path(pathbuf_1, &argp->to);
  514.     if (status != NFS_OK)
  515.         return ((int) status);
  516.  
  517.     dprintf(1, "\tpathfrom='%s' pathto='%s'\n", pathbuf, pathbuf_1);
  518.  
  519.     status = check_ro_attrib(client_authenticate, svc_rqstp, pathbuf, cp);
  520.     if (status != NFS_OK)
  521.         return (status);
  522.  
  523.     /* Remove any file handle from our cache. */
  524.     fh_remove(pathbuf);
  525.     fh_remove(pathbuf_1);
  526.  
  527.     if (rename(pathbuf, pathbuf_1) != 0)
  528.         return (nfs_errno());
  529.  
  530.     return (NFS_OK);
  531. }
  532.  
  533. int nfsd_nfsproc_link_2(argp)
  534. linkargs *argp;
  535. {
  536.     nfsstat status;
  537.     char *path;
  538.  
  539.     if ((path = fh_path(&(argp->from), &status)) == 0)
  540.         return (NFSERR_STALE);
  541.  
  542.     status = build_path(pathbuf_1, &argp->to);
  543.     if (status != NFS_OK)
  544.         return ((int) status);
  545.  
  546.     dprintf(1, "\tpathfrom='%s' pathto='%s'\n", path, pathbuf_1);
  547.  
  548.     status = check_ro_attrib(client_authenticate, svc_rqstp, pathbuf, cp);
  549.     if (status != NFS_OK)
  550.         return (status);
  551.  
  552.     if (link(path, pathbuf_1) != 0)
  553.         return (nfs_errno());
  554.     return (NFS_OK);
  555. }
  556.  
  557. int nfsd_nfsproc_symlink_2(argp)
  558. symlinkargs *argp;
  559. {
  560.     nfsstat status;
  561.  
  562.     status = build_path(pathbuf, &argp->from);
  563.     if (status != NFS_OK)
  564.         return ((int) status);
  565.  
  566.     dprintf(1, "\tstring='%s' filename='%s'\n", argp->to, pathbuf);
  567.  
  568.     status = check_ro_attrib(client_authenticate, svc_rqstp, pathbuf, cp);
  569.     if (status != NFS_OK)
  570.         return (status);
  571.  
  572.     /*
  573.          * Ignore the attributes, as the NFS version 2 documentation says
  574.          * "On UNIX servers the attributes are never used...",
  575.          */
  576.     if (symlink(argp->to, pathbuf) != 0)
  577.         return (nfs_errno());
  578.     return (NFS_OK);
  579. }
  580.  
  581. int nfsd_nfsproc_mkdir_2(argp)
  582. createargs *argp;
  583. {
  584.     nfsstat status;
  585.     struct stat sbuf;
  586.     struct stat *sbp = &sbuf;
  587.  
  588.     status = build_path(pathbuf, &argp->where);
  589.     if (status != NFS_OK)
  590.         return ((int) status);
  591.  
  592.     dprintf(1, "\tfullpath='%s'\n", pathbuf);
  593.  
  594.     status = check_ro_attrib(client_authenticate, svc_rqstp, pathbuf, cp);
  595.     if (status != NFS_OK)
  596.         return (status);
  597.  
  598.     if (mkdir(pathbuf, argp->attributes.mode) != 0)
  599.         return (nfs_errno());
  600.     status = fh_compose(&(argp->where),
  601.                &(result.diropres.diropres_u.diropres.file), &sbp,
  602.                 -1, -1);
  603.     if (status != NFS_OK)
  604.         return ((int) status);
  605.  
  606.     /*
  607.          * Set up the correct ownership.  As with create, almost all mkdir
  608.          * requests from the current Sun implementation fail to include
  609.          * explicit uid/gid pairs for creates, so we have to use info
  610.          * from the request authication (now done during dispatch).
  611.          */
  612.     {
  613.         int target_uid = argp->attributes.uid;
  614.         int target_gid = argp->attributes.gid;
  615.  
  616.         if ((target_uid != -1 && sbuf.st_uid != target_uid) ||
  617.             (target_gid != -1 && sbuf.st_gid != target_gid))
  618.             if (lchown(pathbuf, target_uid, target_gid) != 0)
  619.                 return (nfs_errno());
  620.     }
  621.  
  622.     /* Note that the spb buffer is now invalid! */
  623.     status = getattr(&(result.diropres.diropres_u.diropres.file),
  624.         &(result.diropres.diropres_u.diropres.attributes), NULL);
  625.     if (status == NFS_OK)
  626.         dprintf(1, "\tnew_fh = %s\n",
  627.              fh_pr(&(result.diropres.diropres_u.diropres.file)));
  628.     return ((int) status);
  629. }
  630.  
  631. int nfsd_nfsproc_rmdir_2(argp)
  632. diropargs *argp;
  633. {
  634.     nfsstat status;
  635.  
  636.     status = build_path(pathbuf, argp);
  637.     if (status != NFS_OK)
  638.         return ((int) status);
  639.  
  640.     dprintf(1, "\tfullpath='%s'\n", pathbuf);
  641.  
  642.     status = check_ro_attrib(client_authenticate, svc_rqstp, pathbuf, cp);
  643.     if (status != NFS_OK)
  644.         return (status);
  645.  
  646.     /* Remove that file handle from our cache. */
  647.     fh_remove(pathbuf);
  648.  
  649.     if (rmdir(pathbuf) != 0)
  650.         return (nfs_errno());
  651.  
  652.     return (NFS_OK);
  653. }
  654.  
  655. /* More Mark Shand code. */
  656. static int dpsize(dp)
  657. struct dirent *dp;
  658. {
  659. #define DP_SLOP    16
  660. #define MAX_E_SIZE sizeof(entry) + NAME_MAX + DP_SLOP
  661.     return (sizeof(entry) + NLENGTH(dp) + DP_SLOP);
  662. }
  663.  
  664. int nfsd_nfsproc_readdir_2(argp)
  665. readdirargs *argp;
  666. {
  667.     static readdirres oldres;
  668.     entry **e;
  669.     long dloc;
  670.     DIR *dirp;
  671.     struct dirent *dp;
  672.     struct stat sbuf;
  673.     int res_size;
  674.     fhcache *h;
  675.     int hideit;
  676.  
  677.     /* Free the previous result, since it has 'malloc'ed strings.  */
  678.     xdr_free(xdr_readdirres, (caddr_t) & oldres);
  679.  
  680.     if ((h = fh_find((svc_fh *) &(argp->dir), 0)) == NULL)
  681.         return (NFSERR_STALE);
  682.     hideit = (!re_export && (h->flags & FHC_NFSMOUNTED));
  683.  
  684.     /* This code is from Mark Shand's version */
  685.     errno = 0;
  686.     if (lstat(h->path, &sbuf) < 0 || !(S_ISDIR(sbuf.st_mode)))
  687.         return (NFSERR_NOTDIR);
  688.     if ((dirp = opendir(h->path)) == NULL)
  689.         return ((errno ? nfs_errno() : NFSERR_NAMETOOLONG));
  690.  
  691.     res_size = 0;
  692.     memcpy(&dloc, argp->cookie, sizeof(dloc));
  693.     if (dloc != 0)
  694.         seekdir(dirp, ntohl(dloc));
  695.     e = &(result.readdirres.readdirres_u.reply.entries);
  696.     while (((res_size + MAX_E_SIZE) < argp->count
  697.         || e == &(result.readdirres.readdirres_u.reply.entries))
  698.            && (dp = readdir(dirp)) != NULL) {
  699.         if (hideit && strcmp(dp->d_name, ".") != 0
  700.             && strcmp(dp->d_name, "..") != 0) {
  701.             dp = NULL;
  702.             break;
  703.         }
  704.         if ((*e = (entry *) malloc(sizeof(entry))) == NULL)
  705.             mallocfailed();
  706.         (*e)->fileid = pseudo_inode(dp->d_ino, sbuf.st_dev);
  707.         if (((*e)->name = malloc(NLENGTH(dp) + 1)) == NULL)
  708.             mallocfailed();
  709.         strcpy((*e)->name, dp->d_name);
  710.         dloc = htonl(telldir(dirp));
  711.         memcpy(((*e)->cookie), &dloc, sizeof(nfscookie));
  712.         e = &((*e)->nextentry);
  713.         res_size += dpsize(dp);
  714.     }
  715.     *e = NULL;
  716.     result.readdirres.readdirres_u.reply.eof = (dp == NULL);
  717.     (void) closedir(dirp);
  718.     oldres = result.readdirres;
  719.     return (result.readdirres.status);
  720. }
  721.  
  722. /*
  723.  * Only reports free space correctly for the filesystem that the
  724.  * mount point is on.  Actually it will work fine for any file
  725.  * handle (e.g. sub mounts) but the NFS spec calls for root_fh
  726.  * to be used by the client when calling this.
  727.  */
  728. int nfsd_nfsproc_statfs_2(argp)
  729. nfs_fh *argp;
  730. {
  731.     nfsstat status;
  732.     char *path;
  733.     struct fs_usage fs;
  734.  
  735.     if ((path = fh_path(argp, &status)) == NULL)
  736.         return (NFSERR_STALE);
  737.  
  738.     if (get_fs_usage(path, NULL, &fs) < 0)
  739.         return (nfs_errno());
  740.     result.statfsres.status = NFS_OK;
  741.     result.statfsres.statfsres_u.reply.tsize = 8*1024;
  742.     result.statfsres.statfsres_u.reply.bsize = 512;
  743.     result.statfsres.statfsres_u.reply.blocks = fs.fsu_blocks;
  744.     result.statfsres.statfsres_u.reply.bfree = fs.fsu_bfree;
  745.     result.statfsres.statfsres_u.reply.bavail = fs.fsu_bavail;
  746.  
  747.     return (NFS_OK);
  748. }
  749.  
  750. static int makesock(port, proto, socksz)
  751. int port;
  752. int proto;
  753. int socksz;
  754. {
  755.     struct sockaddr_in sin;
  756.     int s;
  757.     int sock_type;
  758.  
  759.     sock_type = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
  760.     s = socket(AF_INET, sock_type, proto);
  761.     if (s < 0) {
  762.         dprintf(0, "Could not make a socket: %s\n", strerror(errno));
  763.         return (-1);
  764.     }
  765.     memset((char *) &sin, 0, sizeof(sin));
  766.     sin.sin_family = AF_INET;
  767.     sin.sin_addr.s_addr = INADDR_ANY;
  768.     sin.sin_port = htons(port);
  769.  
  770.     {
  771.         int val = 1;
  772.  
  773.         if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0)
  774.             dprintf(0, "setsockopt failed: %s\n", strerror(errno));
  775.     }
  776.  
  777. #ifdef SO_SNDBUF
  778.     {
  779.         int sblen, rblen;
  780.  
  781.         /* 1024 for rpc & transport overheads */
  782.         sblen = rblen = socksz + 1024;
  783.         if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sblen, sizeof sblen) < 0 ||
  784.             setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rblen, sizeof rblen) < 0)
  785.             dprintf(0, "setsockopt failed: %s\n", strerror(errno));
  786.     }
  787. #endif                /* SO_SNDBUF */
  788.  
  789.     if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
  790.         dprintf(0, "Could not bind name to socket: %s\n", strerror(errno));
  791.         return (-1);
  792.     }
  793.     return (s);
  794. }
  795.  
  796. /* This is taken from an rpcgen generated service file. */
  797. static void closedown(sig)
  798. int sig;
  799. {
  800.     (void) signal(sig, closedown);
  801.     if (_rpcsvcdirty == 0) {
  802.         extern fd_set svc_fdset;
  803.         static int size;
  804.         int i, openfd;
  805.  
  806.         if (_rpcfdtype == SOCK_DGRAM)
  807.             exit(0);
  808.         if (size == 0) {
  809.             size = getdtablesize();
  810.         }
  811.         for (i = 0, openfd = 0; i < size && openfd < 2; i++)
  812.             if (FD_ISSET(i, &svc_fdset))
  813.                 openfd++;
  814.         if (openfd <= 1)
  815.             exit(0);
  816.     }
  817.     (void) alarm(_RPCSVC_CLOSEDOWN);
  818. }
  819.  
  820. int main(argc, argv)
  821. int argc;
  822. char *argv[];
  823. {
  824.     int c;
  825.     struct sockaddr_in saddr;
  826.     int addr_size;
  827.     SVCXPRT *transp;
  828.     int nfs_socket;
  829.     char *auth_file = NULL;
  830.  
  831.     /*
  832.          * This code uses the RPC library functions in exactly the
  833.          * same way a regular RPC application would.
  834.          */
  835.     nfs_socket = 0;
  836.     _rpcfdtype = 0;
  837.     if (getsockname(0, (struct sockaddr *) &saddr, &addr_size) == 0) {
  838.         int ssize = sizeof(int);
  839.         if (saddr.sin_family != AF_INET)
  840.             exit(1);
  841.         if (getsockopt(0, SOL_SOCKET, SO_TYPE,
  842.                    (char *) &_rpcfdtype, &ssize) < 0)
  843.             exit(1);
  844.         _rpcpmstart = 1;
  845.     } else
  846.         pmap_unset(NFS_PROGRAM, NFS_VERSION);
  847.  
  848.     if (_rpcfdtype == 0 || _rpcfdtype == SOCK_DGRAM) {
  849.         if (_rpcfdtype == 0 &&
  850.             (nfs_socket = makesock(NFS_PORT, IPPROTO_UDP, NFS_MAXDATA)) < 0) {
  851.             fprintf(stderr, "nfsd: could not make a UDP socket.\n");
  852.             exit(1);
  853.         }
  854.         transp = svcudp_create(nfs_socket);
  855.         if (transp == NULL) {
  856.             fprintf(stderr, "nfsd: cannot create UDP service.\n");
  857.             exit(1);
  858.         }
  859.         if (!svc_register(transp, NFS_PROGRAM, NFS_VERSION, nfs_dispatch,
  860.                   IPPROTO_UDP)) {
  861.             fprintf(stderr,
  862.                 "unable to register(NFS_PROGRAM, NFS_VERSION, UDP).\n");
  863.             exit(1);
  864.         }
  865.     }
  866.     if (_rpcfdtype == 0 || _rpcfdtype == SOCK_STREAM) {
  867.         if (_rpcfdtype == 0 &&
  868.             (nfs_socket = makesock(NFS_PORT, IPPROTO_TCP, NFS_MAXDATA)) < 0) {
  869.             fprintf(stderr, "nfsd: could not make a TCP socket.\n");
  870.             exit(1);
  871.         }
  872.         transp = svctcp_create(nfs_socket, 0, 0);
  873.         if (transp == NULL) {
  874.             fprintf(stderr, "nfsd: cannot create TCP service.\n");
  875.             exit(1);
  876.         }
  877.         if (!svc_register(transp, NFS_PROGRAM, NFS_VERSION, nfs_dispatch,
  878.                   IPPROTO_TCP)) {
  879.             fprintf(stderr,
  880.                 "unable to register(NFS_PROGRAM, NFS_VERSION, TCP).\n");
  881.             exit(1);
  882.         }
  883.     }
  884.  
  885.     program_name = argv[0];
  886.  
  887.     /* Parse the command line options and arguments. */
  888.     opterr = 0;
  889.     while ((c = getopt_long(argc, argv, "df:hnprv", longopts, NULL)) != EOF)
  890.         switch (c) {
  891.         case 'h':
  892.             usage(stdout, 0);
  893.             break;
  894.         case 'd':
  895.             toggle_logging(0);
  896.             break;
  897.         case 'f':
  898.             auth_file = optarg;
  899.             break;
  900.         case 'n':
  901.             allow_non_root = 1;
  902.             break;
  903.         case 'p':
  904.             promiscuous = 1;
  905.             break;
  906.         case 'r':
  907.             re_export = 1;
  908.             break;
  909.         case 's':
  910.             trace_spoof = 0;
  911.             break;
  912.         case 'v':
  913.             printf("%s\n", version);
  914.             exit(0);
  915.         case 0:
  916.             break;
  917.         case '?':
  918.         default:
  919.             usage(stderr, 1);
  920.         }
  921.  
  922.     /* No more arguments allowed. */
  923.     if (optind != argc)
  924.         usage(stderr, 1);
  925.  
  926.     /* We first fork off a child. */
  927.     if ((c = fork()) > 0)
  928.         exit(0);
  929.     if (c < 0) {
  930.         fprintf(stderr, "nfsd: cannot fork: %s\n", strerror(errno));
  931.         exit(-1);
  932.     }
  933.     /* Now we remove ourselves from the foreground. */
  934.     (void) close(0);
  935.     (void) close(1);
  936.     (void) close(2);
  937. #ifdef HAVE_SETSID
  938.     setsid();
  939. #else
  940.     {
  941.         int fd;
  942.  
  943.         if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
  944.             (void) ioctl(fd, TIOCNOTTY, (char *) NULL);
  945.             (void) close(fd);
  946.         }
  947.     }
  948. #endif
  949.     /* Initialize logging. */
  950.     log_open("nfsd");
  951.  
  952.     /* Initialize the FH module. */
  953.     fh_init();
  954.  
  955.     /* Initialize the AUTH module. */
  956.     auth_init(auth_file);
  957.  
  958.     /* Enable the LOG toggle with a signal. */
  959.     signal(SIGUSR1, toggle_logging);
  960.  
  961.     if (_rpcpmstart) {
  962.         signal(SIGALRM, closedown);
  963.         alarm(_RPCSVC_CLOSEDOWN);
  964.     }
  965.     /* Run the NFS server. */
  966.     svc_run();
  967.  
  968.     dprintf(0, "Oh no Mr. Bill... nfs_server() returned!\n");
  969.     exit(1);
  970. }
  971.  
  972. static void usage(fp, n)
  973. FILE *fp;
  974. int n;
  975. {
  976.     fprintf(fp, "Usage: %s [-dhnpv] [-f exports-file]\n", program_name);
  977.     fprintf(fp, "       [--debug] [--help] [--allow-non-root]\n");
  978.     fprintf(fp, "       [--promiscuous] [--version]\n");
  979.     fprintf(fp, "       [--exports-file=file]\n");
  980.     exit(n);
  981. }
  982.  
  983.