I've found an interesting little quirk that doesn't seem like it
should be working this way.  If I:

        fd = open(file)
        write(fd, data)
        fchmod(fd, 04711) /* or anything set{u,g}id */
        close(fd)

The set{u,g}id bits get cleared by the close, but only if the amount
of data is not a multiple of the page size, and the target file is on
an nfs mount.  It would seem to reduce the utility of fchmod()
somewhat....

A demonstration program is included below.  I've verified this on a
fairly recently 5.4 client system, with both Linux and FBSD 5.4 NFS
servers.  I don't have 6 or -current available to me at the moment.
There's the obvious work-around of doing a chmod() after the close,
but that has security implications.

Sticking an fsync() in between the fchmod() and the close() causes the
bits to be cleared as a side-effect of the fsync().  Doing another
fchmod() after the fsync() produces the final expected set{u,g}id
results even after the close.  Unfortunately, fsync() is a rather
expensive operation.

        Dworkin
================================================================
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

char buf[25 * 1024];

int
main(int argc, char **argv)
{
        int fd;
        int count;
        char *file;
        struct stat sbuf;

        if (argc != 2) {
                fprintf(stderr, "usage: %s /file/name\n", argv[0]);
                exit(1);
        }

        file = argv[1];
        fd = open(file, O_RDWR | O_CREAT, 0666);
        if (fd == -1) {
                fprintf(stderr, "could not open %s: %s\n",
                    file, strerror(errno));
                exit(1);
        }

        if (write(fd, buf, sizeof (buf)) == -1) {
                fprintf(stderr, "could not write to %s: %s\n",
                    file, strerror(errno));
                exit(1);
        }

        if (fstat(fd, &sbuf) == -1) {
                fprintf(stderr, "could not fstat %s: %s\n",
                    file, strerror(errno));
                exit(1);
        }

        printf("Initial permissions: 0%o\n", sbuf.st_mode & ALLPERMS);

        if (fchmod(fd, 04711) == -1) {
                fprintf(stderr, "could not fchmod %s: %s\n",
                    file, strerror(errno));
                exit(1);
        }

        if (fstat(fd, &sbuf) == -1) {
                fprintf(stderr, "could not fstat %s: %s\n",
                    file, strerror(errno));
                exit(1);
        }

        printf("After write: 0%o\n", sbuf.st_mode & ALLPERMS);

        if (close(fd) == -1) {
                fprintf(stderr, "could not close %s: %s\n",
                    file, strerror(errno));
                exit(1);
        }

        if (stat(file, &sbuf) == -1) {
                fprintf(stderr, "could not stat %s: %s\n",
                    file, strerror(errno));
                exit(1);
        }

        printf("After close: 0%o\n", sbuf.st_mode & ALLPERMS);

        exit(0);
}

_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-stable
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to