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