password (& host?) file lookups, daemons and stray descriptors - HP UX

This is a discussion on password (& host?) file lookups, daemons and stray descriptors - HP UX ; I've run into a strange problem on an HP11i system involving a daemon program which * calls getpwuid() as part of a security check during initialization * does the normal daemonization things: forks, setsid, etc., close all descriptors, redirect 0-2 ...

+ Reply to Thread
Results 1 to 9 of 9

Thread: password (& host?) file lookups, daemons and stray descriptors

  1. password (& host?) file lookups, daemons and stray descriptors

    I've run into a strange problem on an HP11i system involving
    a daemon program which

    * calls getpwuid() as part of a security check during
    initialization

    * does the normal daemonization things:
    forks, setsid, etc.,
    close all descriptors,
    redirect 0-2 to /dev/null.

    * opens a lockfile and does a lockf on it.

    * subsequently calls getpwnam() to obtain a uid.

    On this system, the getpwnam() call causes the
    lock to be lost on the lockfile. (We don't seem
    to have this problem on our various other *ix
    flavors, although that could be a matter of
    system configuration: nsswitch.conf, etc.)


    Debugging shows that getpwuid leaves a descriptor
    open after it is called. From truss, it looks as
    if it creates a socket and leaves it open on fd 3.
    It is not hard to believe that Bad Things Happen(tm)
    when the daemonizing closes all child fds and the
    lockfile winds up with file descriptor 3. Truss
    seems to show the getpwnam() call atempting a sendto()
    on fd 3, failing, then doing it's thing on 4 and
    closing 4.

    Well, I thought I could deal with this by calling
    endpwent() after the getwpuid(), but the extra
    descriptor does not go away and the problem persists.
    This is not the post I thought it would be...


    It took a while to figure out how to make it fail
    from a simple program, but I finally did:

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include

    int check_fds(char *where);

    main()
    {
    struct passwd *pw;
    int status, fd;

    check_fds("main");

    status = getuid();
    printf("getuid() is %d\n", status);
    if(status == -1)
    exit(11);
    pw = getpwuid(status);
    if (pw == NULL)
    exit(12);
    printf("user name is %s\n", pw->pw_name);

    check_fds("after getpwuid");
    endpwent();
    check_fds("after endpwent");

    /* simulate daemonize */
    close(3);
    close(4);

    fd = open("/tmp/mylock", O_RDWR);
    if (fd == -1)
    {
    perror("open");
    exit(1);
    }
    printf("locfile open on fd %d\n", fd);
    status = lockf(fd, F_TLOCK, 0);
    if (status == -1)
    exit(2);
    printf("locked\n");
    getc(stdin);

    pw = getpwnam("bin"); [ this call seems to lose the lock ]
    if (pw == NULL)
    exit(3);
    check_fds("after getpwnam");
    printf("got uid %d\n", pw->pw_uid);
    getc(stdin);

    printf("exiting\n");
    exit(0);
    }

    int check_fds(char *where)
    {
    int status, fd;

    for (fd = 0; fd < 10; fd++)
    {
    status = dup(fd);
    if (status != -1)
    {
    printf("%d ", fd);
    close(status);
    }
    }
    printf("- %s\n", where);
    return(0);
    }

    # gcc test2.c
    # ./a.out
    0 1 2 - main
    getuid() is 0
    user name is root
    0 1 2 3 - after getpwuid
    0 1 2 3 - after endpwent
    locfile open on fd 3
    locked
    [the file is locked at this point]

    0 1 2 3 - after getpwnam
    got uid 2
    [the file is unlocked at this point]

    exiting
    #
    [instead of here, when the program exits]

    If I run under truss, an extra fd
    seems to get injected:

    execve("./a.out", 0x7b0404a0, 0x7b0404a8) = 0
    [32-bit]
    open("/usr/lib/dld.sl", O_RDONLY, 02204) = 4
    read(4, "02\v010e0512@ \0\0\0\0\0\0\0\0\0".., 128) = 128
    lseek(4, 128, SEEK_SET) = 128
    read(4, "10\0\004\0\0\0( \002e884\0\0\0\0".., 48) = 48
    mmap(NULL, 190596, PROT_READ|PROT_EXEC,
    MAP_SHARED|MAP_SHLIB|MAP_STATICPREDICTION, 4, 0x9000) = 0xc0010000
    mmap(NULL, 16104, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_SHLIB,
    4, 0x38000) = 0x7b03c000
    close(4) = 0
    mmap(NULL, 8192, PROT_READ|PROT_WRITE|PROT_EXEC,
    MAP_PRIVATE|MAP_ANONYMOUS, -1, NULL) = 0x7b03a000
    sysconf(_SC_CPU_VERSION) = 532
    open("/opt/graphics/OpenGL/lib/libogltls.sl", O_RDONLY, 0) = 4
    fstat(4, 0x7b042f98) = 0
    read(4, "0210010e0512@ \0\0\0\0\0\0\0\0\0".., 128) = 128
    lseek(4, 128, SEEK_SET) = 128
    read(4, "10\0\004\0\0\0( \0\013\ \0\010\0".., 48) = 48
    read(4, "80\0\001\0\0\0 9 2 4 5 ", 12) = 12
    lseek(4, 8192, SEEK_SET) = 8192
    read(4, "058cy 10\0\0\0D \0\002$ \0\0\001".., 112) = 112
    mmap(NULL, 8192, PROT_READ|PROT_EXEC, MAP_SHARED|MAP_SHLIB, 4, 0x2000) =
    0xc0005000
    mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_SHLIB,
    4, 0x4000) = 0x7b039000
    close(4) = 0
    open("/usr/lib/libc.2", O_RDONLY, 0) = 4
    fstat(4, 0x7b043158) = 0
    read(4, "0214010e0512@ \0\0\0\0\0\0\0\0\0".., 128) = 128
    lseek(4, 128, SEEK_SET) = 128
    read(4, "10\0\004\0\0\0( \013y c4\0\010\0".., 48) = 48
    read(4, "80\0\0\v\0\0\004\0\0\0\0", 12) = 12
    lseek(4, 430080, SEEK_SET) = 430080
    read(4, "058cy 10\0\0\ad \0\0K L \0\0\002".., 112) = 112
    mmap(NULL, 1277952, PROT_READ|PROT_EXEC, MAP_SHARED|MAP_SHLIB, 4,
    0x69000) = 0xc0100000
    mmap(NULL, 45056, PROT_READ|PROT_WRITE|PROT_EXEC,
    MAP_PRIVATE|MAP_ANONYMOUS|MAP_SHLIB, -1, NULL) = 0x7b02e000
    mmap(0x7b026000, 32768, PROT_READ|PROT_WRITE|PROT_EXEC,
    MAP_PRIVATE|MAP_FIXED|MAP_SHLIB, 4, 0x1a1000) = 0x7b026000
    mmap(NULL, 16384, PROT_READ|PROT_WRITE|PROT_EXEC,
    MAP_PRIVATE|MAP_ANONYMOUS, -1, NULL) = 0x7b022000
    close(4) = 0
    open("/usr/lib/libdld.2", O_RDONLY, 0) = 4
    fstat(4, 0x7b043318) = 0
    read(4, "02\v010e0512@ \0\0\0\0\0\0\0\0\0".., 128) = 128
    lseek(4, 128, SEEK_SET) = 128
    read(4, "10\0\004\0\0\0( \0\0) \ \0\010\0".., 48) = 48
    read(4, "80\0\0\v\0\0\004\0\0\0\0", 12) = 12
    lseek(4, 8192, SEEK_SET) = 8192
    read(4, "058cy 10\0\0\0\f\0\00214\0\0\001".., 112) = 112
    mmap(NULL, 12288, PROT_READ|PROT_EXEC, MAP_SHARED|MAP_SHLIB, 4, 0x2000)
    = 0xc0007000
    mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_SHLIB,
    4, 0x5000) = 0x7b021000
    close(4) = 0
    open("/usr/lib/libc.2", O_RDONLY, 0) = 4
    fstat(4, 0x7b043498) = 0
    close(4) = 0
    mmap(NULL, 16384, PROT_READ|PROT_WRITE|PROT_EXEC,
    MAP_PRIVATE|MAP_ANONYMOUS, -1, NULL) = 0x7b01d000
    mmap(NULL, 3368, PROT_READ|PROT_WRITE|PROT_EXEC,
    MAP_PRIVATE|MAP_ANONYMOUS, -1, NULL) = 0x7b01c000
    sigsetreturn(0x7b023f36, 0x6211988, 1392) = 0

    looks like we start here...

    dup(0) = 4
    sysconf(_SC_CPU_VERSION) = 532
    brk(0x40001140) = 0
    brk(0x40003134) = 0
    brk(0x40006000) = 0
    ioctl(1, TCGETA, 0x7b040958) = 0
    close(4) = 0
    dup(1) = 4
    close(4) = 0
    dup(2) = 4
    close(4) = 0
    dup(3) = 4
    close(4) = 0
    dup(4) ERR#9 EBADF
    dup(5) ERR#9 EBADF
    dup(6) ERR#9 EBADF
    dup(7) ERR#9 EBADF
    dup(8) ERR#9 EBADF
    dup(9) ERR#9 EBADF
    write(1, "0 1 2 3 - m a i n \n", 15) = 15
    getuid() = 0 (0)
    write(1, "g e t u i d ( ) i s 0 \n", 14) = 14

    If I close(3) at the start of the program to get rid of the
    extraneous fd truss seems to give, the following winds up on
    fd 3.

    open("/var/spool/pwgr/status", O_RDONLY, 0) = 4
    mmap(NULL, 532, PROT_READ, MAP_SHARED|MAP_VARIABLE|MAP_FILE|MAP_ADDR32,
    4, NULL) = 0xc0057000
    close(4) = 0
    socket(AF_UNIX, SOCK_DGRAM, 0) = 4
    getpid() = 19401
    (19400)
    unlink("/var/spool/sockets/pwgr/client19401") ERR#2
    ENOENT
    bind(4, 0x7b02f580, 38) = 0
    fcntl(4, F_SETFD, 1) = 0
    time(NULL) =
    1119565603
    poll(0x7b041798, 1, 0) = 1
    sendto(4, "\0\0\00 \0\0\001\0\0\0\0\0\0\001".., 48, 0, NULL, NULL) = 48
    poll(0x7b041798, 1, 1000) = 1
    recv(4, "\0\0\03 \0\0\0\0\0\0\0\0\0\0\0# ".., 2064, 0) = 51
    write(1, "u s e r n a m e i s r o o ".., 18) = 18
    dup(0) = 5
    close(5) = 0
    dup(1) = 5
    close(5) = 0
    dup(2) = 5
    close(5) = 0
    dup(3) = 5
    close(5) = 0
    dup(4) = 5
    close(5) = 0
    dup(5) ERR#9 EBADF
    dup(6) ERR#9 EBADF
    dup(7) ERR#9 EBADF
    dup(8) ERR#9 EBADF
    dup(9) ERR#9 EBADF
    write(1, "0 1 2 3 4 - a f t e ".., 27) = 27
    dup(0) = 5
    close(5) = 0
    dup(1) = 5
    close(5) = 0
    dup(2) = 5
    close(5) = 0
    dup(3) = 5
    close(5) = 0
    dup(4) = 5
    close(5) = 0
    dup(5) ERR#9 EBADF
    dup(6) ERR#9 EBADF
    dup(7) ERR#9 EBADF
    dup(8) ERR#9 EBADF
    dup(9) ERR#9 EBADF
    write(1, "0 1 2 3 4 - a f t e ".., 27) = 27
    close(3) = 0
    close(4) = 0
    open("/tmp/mylock", O_RDWR, 0160100) = 3
    write(1, "l o c f i l e o p e n o n ".., 21) = 21
    lockf(3, 0x2, 0) = 0
    write(1, "l o c k e d \n", 7) = 7
    brk(0x40008000) = 0
    ioctl(0, TCGETA, 0x7b040718) = 0
    read(0, 0x400059a0, 8192) [sleeping]
    read(0, "\n", 8192) = 1
    getpid() = 19401
    (19400)
    poll(0x7b041798, 1, 0) = 1

    When I close(3) at the start of the program to get rid of the
    fd truss gives, this sendto is performed against the lockfile
    and results in ENOTSOCK. In this case, where we don't even
    touch 3, the lock STILL gets lost! I don't see how..

    sendto(4, "\0\0\00 \0\0\001\0\0\001\0\0\002".., 48, 0, NULL, NULL) ERR#9
    EBADF
    open("/etc/nsswitch.conf", O_RDONLY, 0666) = 4
    brk(0x4000a000) = 0
    ioctl(4, TCGETA, 0x7b041618) ERR#25
    ENOTTY
    read(4, "# \n# / e t c / n s s w i t c ".., 8192) = 376
    brk(0x4000b000) = 0
    read(4, 0x40007e58, 8192) = 0
    close(4) = 0
    open("/usr/lib/libnss_files.1", O_RDONLY, 0) = 4
    fstat(4, 0x7b041818) = 0
    read(4, "0210010e0512@ \0\0\0\0\0\0\0\0\0".., 128) = 128
    lseek(4, 128, SEEK_SET) = 128
    read(4, "10\0\004\0\0\0( \0\0k T \0\010\0".., 48) = 48
    read(4, "80\0\0\v\0\0\004\0\0\0\0", 12) = 12
    lseek(4, 12288, SEEK_SET) = 12288
    read(4, "058cy 10\0\0\0D \0\004f0\0\0\002".., 112) = 112
    mmap(NULL, 28672, PROT_READ|PROT_EXEC, MAP_SHARED|MAP_SHLIB, 4, 0x3000)
    = 0xc0058000
    mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_SHLIB,
    4, 0xa000) = 0x7b01b000
    close(4) = 0
    open("/usr/lib/libdld.2", O_RDONLY, 0) = 4
    fstat(4, 0x7b0419d8) = 0
    close(4) = 0
    open("/etc/passwd", O_RDONLY, 0666) = 4
    brk(0x4000d000) = 0
    ioctl(4, TCGETA, 0x7b041418) ERR#25
    ENOTTY
    read(4, "r o o t : R e 9 b n r j Y 8 i a ".., 8192) = 591
    lseek(4, 4294966794, SEEK_CUR) = 89
    close(4) = 0
    dup(0) = 4
    close(4) = 0
    dup(1) = 4
    close(4) = 0
    dup(2) = 4
    close(4) = 0
    dup(3) = 4
    close(4) = 0
    dup(4) ERR#9 EBADF
    dup(5) ERR#9 EBADF
    dup(6) ERR#9 EBADF
    dup(7) ERR#9 EBADF
    dup(8) ERR#9 EBADF
    dup(9) ERR#9 EBADF
    write(1, "0 1 2 3 - a f t e r ".., 25) = 25
    write(1, "g o t u i d 2 \n", 10) = 10
    read(0, 0x400059a0, 8192) [sleeping]
    read(0, "\n", 8192) = 1
    write(1, "e x i t i n g \n", 8) = 8
    getpid() = 19401
    (19400)
    unlink("/var/spool/sockets/pwgr/client19401") = 0
    exit(0)
    WIFEXITED(0)


    What the Fudd is going on ?? I'm stumped. I'd love
    to find out I'm doing Something Stupid(tm).


    --
    Clem
    "If you push something hard enough, it will fall over."
    - Fudd's first law of opposition

  2. Re: password (& host?) file lookups, daemons and stray descriptors

    Mr. Uh Clem wrote:
    > I've run into a strange problem on an HP11i system involving
    > a daemon program which
    >
    > * calls getpwuid() as part of a security check during
    > initialization
    >
    > * does the normal daemonization things:
    > forks, setsid, etc.,
    > close all descriptors,
    > redirect 0-2 to /dev/null.
    >
    > * opens a lockfile and does a lockf on it.
    >
    > * subsequently calls getpwnam() to obtain a uid.
    >
    > On this system, the getpwnam() call causes the
    > lock to be lost on the lockfile. (We don't seem
    > to have this problem on our various other *ix
    > flavors, although that could be a matter of
    > system configuration: nsswitch.conf, etc.)
    >
    >
    > Debugging shows that getpwuid leaves a descriptor
    > open after it is called. From truss, it looks as
    > if it creates a socket and leaves it open on fd 3.
    > It is not hard to believe that Bad Things Happen(tm)
    > when the daemonizing closes all child fds and the
    > lockfile winds up with file descriptor 3. Truss
    > seems to show the getpwnam() call atempting a sendto()
    > on fd 3, failing, then doing it's thing on 4 and
    > closing 4.
    >
    > Well, I thought I could deal with this by calling
    > endpwent() after the getwpuid(), but the extra
    > descriptor does not go away and the problem persists.
    > This is not the post I thought it would be...
    >
    >
    > It took a while to figure out how to make it fail
    > from a simple program, but I finally did:
    >
    > #include
    > #include
    > #include
    > #include
    > #include
    > #include
    > #include
    > #include
    > #include
    >
    > int check_fds(char *where);
    >
    > main()
    > {
    > struct passwd *pw;
    > int status, fd;
    >
    > check_fds("main");
    >
    > status = getuid();
    > printf("getuid() is %d\n", status);
    > if(status == -1)
    > exit(11);
    > pw = getpwuid(status);
    > if (pw == NULL)
    > exit(12);
    > printf("user name is %s\n", pw->pw_name);
    >
    > check_fds("after getpwuid");
    > endpwent();
    > check_fds("after endpwent");
    >
    > /* simulate daemonize */
    > close(3);
    > close(4);
    >
    > fd = open("/tmp/mylock", O_RDWR);
    > if (fd == -1)
    > {
    > perror("open");
    > exit(1);
    > }
    > printf("locfile open on fd %d\n", fd);
    > status = lockf(fd, F_TLOCK, 0);
    > if (status == -1)
    > exit(2);
    > printf("locked\n");
    > getc(stdin);
    >
    > pw = getpwnam("bin"); [ this call seems to lose the lock ]
    > if (pw == NULL)
    > exit(3);
    > check_fds("after getpwnam");
    > printf("got uid %d\n", pw->pw_uid);
    > getc(stdin);
    >
    > printf("exiting\n");
    > exit(0);
    > }
    >
    > int check_fds(char *where)
    > {
    > int status, fd;
    >
    > for (fd = 0; fd < 10; fd++)
    > {
    > status = dup(fd);
    > if (status != -1)
    > {
    > printf("%d ", fd);
    > close(status);
    > }
    > }
    > printf("- %s\n", where);
    > return(0);
    > }
    >
    > # gcc test2.c
    > # ./a.out
    > 0 1 2 - main
    > getuid() is 0
    > user name is root
    > 0 1 2 3 - after getpwuid
    > 0 1 2 3 - after endpwent
    > locfile open on fd 3
    > locked
    > [the file is locked at this point]
    >
    > 0 1 2 3 - after getpwnam
    > got uid 2
    > [the file is unlocked at this point]
    >
    > exiting
    > #
    > [instead of here, when the program exits]
    >
    > If I run under truss, an extra fd
    > seems to get injected:
    >
    > execve("./a.out", 0x7b0404a0, 0x7b0404a8) = 0
    > [32-bit]
    > open("/usr/lib/dld.sl", O_RDONLY, 02204) = 4
    > read(4, "02\v010e0512@ \0\0\0\0\0\0\0\0\0".., 128) = 128
    > lseek(4, 128, SEEK_SET) = 128
    > read(4, "10\0\004\0\0\0( \002e884\0\0\0\0".., 48) = 48
    > mmap(NULL, 190596, PROT_READ|PROT_EXEC,
    > MAP_SHARED|MAP_SHLIB|MAP_STATICPREDICTION, 4, 0x9000) = 0xc0010000
    > mmap(NULL, 16104, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_SHLIB,
    > 4, 0x38000) = 0x7b03c000
    > close(4) = 0
    > mmap(NULL, 8192, PROT_READ|PROT_WRITE|PROT_EXEC,
    > MAP_PRIVATE|MAP_ANONYMOUS, -1, NULL) = 0x7b03a000
    > sysconf(_SC_CPU_VERSION) = 532
    > open("/opt/graphics/OpenGL/lib/libogltls.sl", O_RDONLY, 0) = 4
    > fstat(4, 0x7b042f98) = 0
    > read(4, "0210010e0512@ \0\0\0\0\0\0\0\0\0".., 128) = 128
    > lseek(4, 128, SEEK_SET) = 128
    > read(4, "10\0\004\0\0\0( \0\013\ \0\010\0".., 48) = 48
    > read(4, "80\0\001\0\0\0 9 2 4 5 ", 12) = 12
    > lseek(4, 8192, SEEK_SET) = 8192
    > read(4, "058cy 10\0\0\0D \0\002$ \0\0\001".., 112) = 112
    > mmap(NULL, 8192, PROT_READ|PROT_EXEC, MAP_SHARED|MAP_SHLIB, 4, 0x2000) =
    > 0xc0005000
    > mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_SHLIB,
    > 4, 0x4000) = 0x7b039000
    > close(4) = 0
    > open("/usr/lib/libc.2", O_RDONLY, 0) = 4
    > fstat(4, 0x7b043158) = 0
    > read(4, "0214010e0512@ \0\0\0\0\0\0\0\0\0".., 128) = 128
    > lseek(4, 128, SEEK_SET) = 128
    > read(4, "10\0\004\0\0\0( \013y c4\0\010\0".., 48) = 48
    > read(4, "80\0\0\v\0\0\004\0\0\0\0", 12) = 12
    > lseek(4, 430080, SEEK_SET) = 430080
    > read(4, "058cy 10\0\0\ad \0\0K L \0\0\002".., 112) = 112
    > mmap(NULL, 1277952, PROT_READ|PROT_EXEC, MAP_SHARED|MAP_SHLIB, 4,
    > 0x69000) = 0xc0100000
    > mmap(NULL, 45056, PROT_READ|PROT_WRITE|PROT_EXEC,
    > MAP_PRIVATE|MAP_ANONYMOUS|MAP_SHLIB, -1, NULL) = 0x7b02e000
    > mmap(0x7b026000, 32768, PROT_READ|PROT_WRITE|PROT_EXEC,
    > MAP_PRIVATE|MAP_FIXED|MAP_SHLIB, 4, 0x1a1000) = 0x7b026000
    > mmap(NULL, 16384, PROT_READ|PROT_WRITE|PROT_EXEC,
    > MAP_PRIVATE|MAP_ANONYMOUS, -1, NULL) = 0x7b022000
    > close(4) = 0
    > open("/usr/lib/libdld.2", O_RDONLY, 0) = 4
    > fstat(4, 0x7b043318) = 0
    > read(4, "02\v010e0512@ \0\0\0\0\0\0\0\0\0".., 128) = 128
    > lseek(4, 128, SEEK_SET) = 128
    > read(4, "10\0\004\0\0\0( \0\0) \ \0\010\0".., 48) = 48
    > read(4, "80\0\0\v\0\0\004\0\0\0\0", 12) = 12
    > lseek(4, 8192, SEEK_SET) = 8192
    > read(4, "058cy 10\0\0\0\f\0\00214\0\0\001".., 112) = 112
    > mmap(NULL, 12288, PROT_READ|PROT_EXEC, MAP_SHARED|MAP_SHLIB, 4, 0x2000)
    > = 0xc0007000
    > mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_SHLIB,
    > 4, 0x5000) = 0x7b021000
    > close(4) = 0
    > open("/usr/lib/libc.2", O_RDONLY, 0) = 4
    > fstat(4, 0x7b043498) = 0
    > close(4) = 0
    > mmap(NULL, 16384, PROT_READ|PROT_WRITE|PROT_EXEC,
    > MAP_PRIVATE|MAP_ANONYMOUS, -1, NULL) = 0x7b01d000
    > mmap(NULL, 3368, PROT_READ|PROT_WRITE|PROT_EXEC,
    > MAP_PRIVATE|MAP_ANONYMOUS, -1, NULL) = 0x7b01c000
    > sigsetreturn(0x7b023f36, 0x6211988, 1392) = 0
    >
    > looks like we start here...
    >
    > dup(0) = 4
    > sysconf(_SC_CPU_VERSION) = 532
    > brk(0x40001140) = 0
    > brk(0x40003134) = 0
    > brk(0x40006000) = 0
    > ioctl(1, TCGETA, 0x7b040958) = 0
    > close(4) = 0
    > dup(1) = 4
    > close(4) = 0
    > dup(2) = 4
    > close(4) = 0
    > dup(3) = 4
    > close(4) = 0
    > dup(4) ERR#9
    > EBADF
    > dup(5) ERR#9
    > EBADF
    > dup(6) ERR#9
    > EBADF
    > dup(7) ERR#9
    > EBADF
    > dup(8) ERR#9
    > EBADF
    > dup(9) ERR#9
    > EBADF
    > write(1, "0 1 2 3 - m a i n \n", 15) = 15
    > getuid() = 0 (0)
    > write(1, "g e t u i d ( ) i s 0 \n", 14) = 14
    >
    > If I close(3) at the start of the program to get rid of the
    > extraneous fd truss seems to give, the following winds up on
    > fd 3.
    >
    > open("/var/spool/pwgr/status", O_RDONLY, 0) = 4
    > mmap(NULL, 532, PROT_READ, MAP_SHARED|MAP_VARIABLE|MAP_FILE|MAP_ADDR32,
    > 4, NULL) = 0xc0057000
    > close(4) = 0
    > socket(AF_UNIX, SOCK_DGRAM, 0) = 4
    > getpid() = 19401
    > (19400)
    > unlink("/var/spool/sockets/pwgr/client19401") ERR#2
    > ENOENT
    > bind(4, 0x7b02f580, 38) = 0
    > fcntl(4, F_SETFD, 1) = 0
    > time(NULL) =
    > 1119565603
    > poll(0x7b041798, 1, 0) = 1
    > sendto(4, "\0\0\00 \0\0\001\0\0\0\0\0\0\001".., 48, 0, NULL, NULL) = 48
    > poll(0x7b041798, 1, 1000) = 1
    > recv(4, "\0\0\03 \0\0\0\0\0\0\0\0\0\0\0# ".., 2064, 0) = 51
    > write(1, "u s e r n a m e i s r o o ".., 18) = 18
    > dup(0) = 5
    > close(5) = 0
    > dup(1) = 5
    > close(5) = 0
    > dup(2) = 5
    > close(5) = 0
    > dup(3) = 5
    > close(5) = 0
    > dup(4) = 5
    > close(5) = 0
    > dup(5) ERR#9
    > EBADF
    > dup(6) ERR#9
    > EBADF
    > dup(7) ERR#9
    > EBADF
    > dup(8) ERR#9
    > EBADF
    > dup(9) ERR#9
    > EBADF
    > write(1, "0 1 2 3 4 - a f t e ".., 27) = 27
    > dup(0) = 5
    > close(5) = 0
    > dup(1) = 5
    > close(5) = 0
    > dup(2) = 5
    > close(5) = 0
    > dup(3) = 5
    > close(5) = 0
    > dup(4) = 5
    > close(5) = 0
    > dup(5) ERR#9
    > EBADF
    > dup(6) ERR#9
    > EBADF
    > dup(7) ERR#9
    > EBADF
    > dup(8) ERR#9
    > EBADF
    > dup(9) ERR#9
    > EBADF
    > write(1, "0 1 2 3 4 - a f t e ".., 27) = 27
    > close(3) = 0
    > close(4) = 0
    > open("/tmp/mylock", O_RDWR, 0160100) = 3
    > write(1, "l o c f i l e o p e n o n ".., 21) = 21
    > lockf(3, 0x2, 0) = 0
    > write(1, "l o c k e d \n", 7) = 7
    > brk(0x40008000) = 0
    > ioctl(0, TCGETA, 0x7b040718) = 0
    > read(0, 0x400059a0, 8192) [sleeping]
    > read(0, "\n", 8192) = 1
    > getpid() = 19401
    > (19400)
    > poll(0x7b041798, 1, 0) = 1
    >
    > When I close(3) at the start of the program to get rid of the
    > fd truss gives, this sendto is performed against the lockfile
    > and results in ENOTSOCK. In this case, where we don't even
    > touch 3, the lock STILL gets lost! I don't see how..
    >
    > sendto(4, "\0\0\00 \0\0\001\0\0\001\0\0\002".., 48, 0, NULL, NULL) ERR#9
    > EBADF
    > open("/etc/nsswitch.conf", O_RDONLY, 0666) = 4
    > brk(0x4000a000) = 0
    > ioctl(4, TCGETA, 0x7b041618) ERR#25
    > ENOTTY
    > read(4, "# \n# / e t c / n s s w i t c ".., 8192) = 376
    > brk(0x4000b000) = 0
    > read(4, 0x40007e58, 8192) = 0
    > close(4) = 0
    > open("/usr/lib/libnss_files.1", O_RDONLY, 0) = 4
    > fstat(4, 0x7b041818) = 0
    > read(4, "0210010e0512@ \0\0\0\0\0\0\0\0\0".., 128) = 128
    > lseek(4, 128, SEEK_SET) = 128
    > read(4, "10\0\004\0\0\0( \0\0k T \0\010\0".., 48) = 48
    > read(4, "80\0\0\v\0\0\004\0\0\0\0", 12) = 12
    > lseek(4, 12288, SEEK_SET) = 12288
    > read(4, "058cy 10\0\0\0D \0\004f0\0\0\002".., 112) = 112
    > mmap(NULL, 28672, PROT_READ|PROT_EXEC, MAP_SHARED|MAP_SHLIB, 4, 0x3000)
    > = 0xc0058000
    > mmap(NULL, 4096, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_SHLIB,
    > 4, 0xa000) = 0x7b01b000
    > close(4) = 0
    > open("/usr/lib/libdld.2", O_RDONLY, 0) = 4
    > fstat(4, 0x7b0419d8) = 0
    > close(4) = 0
    > open("/etc/passwd", O_RDONLY, 0666) = 4
    > brk(0x4000d000) = 0
    > ioctl(4, TCGETA, 0x7b041418) ERR#25
    > ENOTTY
    > read(4, "r o o t : R e 9 b n r j Y 8 i a ".., 8192) = 591
    > lseek(4, 4294966794, SEEK_CUR) = 89
    > close(4) = 0
    > dup(0) = 4
    > close(4) = 0
    > dup(1) = 4
    > close(4) = 0
    > dup(2) = 4
    > close(4) = 0
    > dup(3) = 4
    > close(4) = 0
    > dup(4) ERR#9
    > EBADF
    > dup(5) ERR#9
    > EBADF
    > dup(6) ERR#9
    > EBADF
    > dup(7) ERR#9
    > EBADF
    > dup(8) ERR#9
    > EBADF
    > dup(9) ERR#9
    > EBADF
    > write(1, "0 1 2 3 - a f t e r ".., 25) = 25
    > write(1, "g o t u i d 2 \n", 10) = 10
    > read(0, 0x400059a0, 8192) [sleeping]
    > read(0, "\n", 8192) = 1
    > write(1, "e x i t i n g \n", 8) = 8
    > getpid() = 19401
    > (19400)
    > unlink("/var/spool/sockets/pwgr/client19401") = 0
    > exit(0) WIFEXITED(0)
    >
    >
    > What the Fudd is going on ?? I'm stumped. I'd love
    > to find out I'm doing Something Stupid(tm).
    >
    >

    I don't do programing, BUT... are you running on a trusted mode system
    or untrusted? There is a big difference, at least in to 11.0.

  3. Re: password (& host?) file lookups, daemons and stray descriptors

    Alan D Johnson wrote:
    > Mr. Uh Clem wrote:
    >

    [snip!]
    > I don't do programing, BUT... are you running on a trusted mode system
    > or untrusted? There is a big difference, at least in to 11.0.


    To be honest, I don't know. I did not set it up. I'll have to
    check tomorrow. I'm not sure what that would have to do with
    stray descriptors...

    Thanks!

    --
    Clem
    "If you push something hard enough, it will fall over."
    - Fudd's first law of opposition

  4. Re: password (& host?) file lookups, daemons and stray descriptors

    In article <42bb3ac4$0$5702$9a6e19ea@news.newshosting.com>,
    "Mr. Uh Clem" wrote:

    > I've run into a strange problem on an HP11i system involving
    > a daemon program which
    >
    > * calls getpwuid() as part of a security check during
    > initialization
    >
    > * does the normal daemonization things:
    > forks, setsid, etc.,
    > close all descriptors,
    > redirect 0-2 to /dev/null.
    >
    > * opens a lockfile and does a lockf on it.
    >
    > * subsequently calls getpwnam() to obtain a uid.
    >
    > On this system, the getpwnam() call causes the
    > lock to be lost on the lockfile. (We don't seem
    > to have this problem on our various other *ix
    > flavors, although that could be a matter of
    > system configuration: nsswitch.conf, etc.)
    >
    >
    > Debugging shows that getpwuid leaves a descriptor
    > open after it is called. From truss, it looks as
    > if it creates a socket and leaves it open on fd 3.
    > It is not hard to believe that Bad Things Happen(tm)
    > when the daemonizing closes all child fds and the
    > lockfile winds up with file descriptor 3. Truss
    > seems to show the getpwnam() call atempting a sendto()
    > on fd 3, failing, then doing it's thing on 4 and
    > closing 4.


    I think the solution is obvious: don't close all file descriptors, just
    redirect 0-2 to /dev/null. You shouldn't close random descriptors
    because you have no idea whether they're still in use by some library
    routines. You have to assume that if a descriptor was left open, it was
    for a reason.

    What you may want to do is set the close-on-exec flag on all the
    descriptors, if your daemon execs other programs.

    --
    Barry Margolin, barmar@alum.mit.edu
    Arlington, MA
    *** PLEASE post questions in newsgroups, not directly to me ***

  5. Re: password (& host?) file lookups, daemons and stray descriptors

    Barry Margolin wrote:
    > In article <42bb3ac4$0$5702$9a6e19ea@news.newshosting.com>,
    > "Mr. Uh Clem" wrote:
    >
    >
    >>I've run into a strange problem on an HP11i system involving
    >>a daemon program which
    >>
    >>* calls getpwuid() as part of a security check during
    >> initialization
    >>
    >>* does the normal daemonization things:
    >> forks, setsid, etc.,
    >> close all descriptors,
    >> redirect 0-2 to /dev/null.
    >>
    >>* opens a lockfile and does a lockf on it.
    >>
    >>* subsequently calls getpwnam() to obtain a uid.
    >>
    >>On this system, the getpwnam() call causes the
    >>lock to be lost on the lockfile. (We don't seem
    >>to have this problem on our various other *ix
    >>flavors, although that could be a matter of
    >>system configuration: nsswitch.conf, etc.)
    >>
    >>
    >>Debugging shows that getpwuid leaves a descriptor
    >>open after it is called. From truss, it looks as
    >>if it creates a socket and leaves it open on fd 3.
    >>It is not hard to believe that Bad Things Happen(tm)
    >>when the daemonizing closes all child fds and the
    >>lockfile winds up with file descriptor 3. Truss
    >>seems to show the getpwnam() call atempting a sendto()
    >>on fd 3, failing, then doing it's thing on 4 and
    >>closing 4.

    >
    >
    > I think the solution is obvious: don't close all file descriptors, just
    > redirect 0-2 to /dev/null. You shouldn't close random descriptors
    > because you have no idea whether they're still in use by some library
    > routines. You have to assume that if a descriptor was left open, it
    > was for a reason.


    Yeah, I guess so, but this is contrary to all I've ever
    seen on how to do a daemon. Consider these early hits
    from Googling for [unix daemon process] :

    http://www.enderunix.org/docs/eng/daemon.php
    http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
    http://www.unix.com/archive/index.php/t-3736.html

    I've never seen any cautionary text regarding fds from
    called routines which must be handled with care:
    Preserved across forks because there may be static
    references to them in the library routines, but
    can be closed on exec, because after the exec,
    the fds would be forgotten?

    I'm also rather surprised that the man pages for
    routines such as getpwuid() are silent on their
    creation of fds and the handling required. (And
    I still don't see anything in the truss which
    explains the lost lock.) I'm also surprised
    it is not possible to properly close such open
    fds, with routines such as endpwent().

    > What you may want to do is set the close-on-exec flag on all the
    > descriptors, if your daemon execs other programs.


    So generic daemonizing might be something like:

    - close all fds above 2 at the start of main (?)

    - fork; setsid; fork; chdir("/" or other safe place);
    close 0-2 and redirect (typically to /dev/null);
    set close-on-exec for fds above 2

    Thanks!

    --
    Clem
    "If you push something hard enough, it will fall over."
    - Fudd's first law of opposition

  6. Re: password (& host?) file lookups, daemons and stray descriptors

    In article <42bc1ccc$0$5791$9a6e19ea@news.newshosting.com>,
    "Mr. Uh Clem" wrote:

    > Yeah, I guess so, but this is contrary to all I've ever
    > seen on how to do a daemon. Consider these early hits
    > from Googling for [unix daemon process] :
    >
    > http://www.enderunix.org/docs/eng/daemon.php
    > http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
    > http://www.unix.com/archive/index.php/t-3736.html
    >
    > I've never seen any cautionary text regarding fds from
    > called routines which must be handled with care:


    I think everyone may assume that you do this so early in your program
    that nothing would have already opened fd's. Notice that the first page
    you referenced above refers to these as "inherited" fd's -- the
    expectation is that any fd's that are open were inherited from the
    calling process, not opened by this process. But when you call library
    routines, and they may have opened descriptors and stored them in static
    variables, this assumption is no longer valid.

    > I'm also rather surprised that the man pages for
    > routines such as getpwuid() are silent on their
    > creation of fds and the handling required. (And


    These fd's are internal implementation details, and the caller is not
    expected to "handle" them. They might change from release to release,
    and programs should not depend on them.

    > I still don't see anything in the truss which
    > explains the lost lock.) I'm also surprised
    > it is not possible to properly close such open
    > fds, with routines such as endpwent().


    Since it's a network socket, I think it's probably part of the NIS
    library, not anything specific to password lookup. Endpwent() doesn't
    have any way to make NIS discard the socket it uses to talk to the
    server.

    >
    > > What you may want to do is set the close-on-exec flag on all the
    > > descriptors, if your daemon execs other programs.

    >
    > So generic daemonizing might be something like:
    >
    > - close all fds above 2 at the start of main (?)


    Right. Then you can call getpwuid() to perform your validity check.
    Since stderr is still pointing to its original location, you can report
    an error.

    >
    > - fork; setsid; fork; chdir("/" or other safe place);
    > close 0-2 and redirect (typically to /dev/null);
    > set close-on-exec for fds above 2


    Seems right to me.

    --
    Barry Margolin, barmar@alum.mit.edu
    Arlington, MA
    *** PLEASE post questions in newsgroups, not directly to me ***

  7. Re: password (& host?) file lookups, daemons and stray descriptors

    Barry Margolin wrote:

    > In article <42bc1ccc$0$5791$9a6e19ea@news.newshosting.com>,
    > "Mr. Uh Clem" wrote:

    ....
    > These fd's are internal implementation details, and the caller is not
    > expected to "handle" them. They might change from release to release,
    > and programs should not depend on them.


    I agree in the sense that they are not part of the API.
    But they do consume a resource and can cause unexpected
    side effects. If many implementations commonly open a
    descriptor, perhaps the standards man pages should say
    that they _may_ do so in the Notes section. Makes even
    more sense in the man pages of specific implementations.

    >>>What you may want to do is set the close-on-exec flag on all the
    >>>descriptors, if your daemon execs other programs.


    Hmm, I wonder if library routines have already done this.
    It would be the right thing to do. I'll have to look.

    THANKS!

    --
    Clem
    "If you push something hard enough, it will fall over."
    - Fudd's first law of opposition

  8. Re: password (& host?) file lookups, daemons and stray descriptors

    In article <42bdca81$0$5795$9a6e19ea@news.newshosting.com>,
    "Mr. Uh Clem" wrote:

    > Barry Margolin wrote:
    >
    > > In article <42bc1ccc$0$5791$9a6e19ea@news.newshosting.com>,
    > > "Mr. Uh Clem" wrote:

    > ...
    > > These fd's are internal implementation details, and the caller is not
    > > expected to "handle" them. They might change from release to release,
    > > and programs should not depend on them.

    >
    > I agree in the sense that they are not part of the API.
    > But they do consume a resource and can cause unexpected
    > side effects.


    Static memory use also consumes a shared resource, but library functions
    don't normally document this, either.

    In general, library function documentation only describes behavior that
    the caller *needs* to be aware of. File descriptors that are used
    behind the scenes don't generally fall into that.

    BTW, does your fopen(3) man page mention that it leaves a file
    descriptor open?

    --
    Barry Margolin, barmar@alum.mit.edu
    Arlington, MA
    *** PLEASE post questions in newsgroups, not directly to me ***

  9. Re: password (& host?) file lookups, daemons and stray descriptors

    In comp.sys.hp.hpux Mr. Uh Clem wrote:

    > open("/var/spool/pwgr/status", O_RDONLY, 0) = 4
    > mmap(NULL, 532, PROT_READ, MAP_SHARED|MAP_VARIABLE|MAP_FILE|MAP_ADDR32,
    > 4, NULL) = 0xc0057000
    > close(4) = 0
    > socket(AF_UNIX, SOCK_DGRAM, 0) = 4


    Notice that this is an AF_UNIX socket, rather than AF_INET.

    > getpid() = 19401
    > (19400)
    > unlink("/var/spool/sockets/pwgr/client19401") ERR#2
    > ENOENT
    > bind(4, 0x7b02f580, 38) = 0


    Move verbosity would help here, but I believe this is the code's
    attempt to associate the socket with a daemon meant to "accelerate"
    lookups in the files - it builds (IIRC) some little internal DB rather
    than having the process go thgrough the files linearly all the time.

    Man pwgrd may have more details. Say on how to disable its use.

    I would have expected there to be some sort of setup to allow the
    connection to the daemon to be undone for the child of a fork. Might
    be time to ring the Response Centre and submit a defect - or peruse
    the patch listings at irtc.hp.com.

    rick jones
    --
    oxymoron n, Hummer H2 with California Save Our Coasts and Oceans plates
    these opinions are mine, all mine; HP might not want them anyway...
    feel free to post, OR email to rick.jones2 in hp.com but NOT BOTH...

+ Reply to Thread