Yesterday I posted a problem report with some diagnostics. I seem to have found a solution on my own and provide a patch here. [I didn't post this as a follow-up because nobody responded to my original post and I wanted to make sure someone reads at least this one.] The patch makes the winbind client (libnss_winbind.so) code more robust. Consider the following fragment of broken application code. if( fork() == 0 ) { /* child */ close( 0 ); /* next open() will return 0 (stdin) */ getpwent(...); /* pid changed, so wb_common.c will open the pipe to winbindd, the handle will be 0 */ fd = open( ... ); /* returned fd isn't 0 although the code assumes this */ execve( ... ); /* executed program reads from stdin which - unintentionally - is the winbind pipe */ } else { /* parent */ ... } Obviously, this code is broken and could be easily fixed by doing the getpwent() before the close(). Unfortunately the version of cron installed on my system is broken in a more complex but similar way. There is probably more broken code like this in other standard unix software, especially since it's such a subtle mistake. The provided patch to wb_common.c makes sure that the handle to the winbindd pipe is not 0, 1 or 2. Even if this is complete crap, I would appreciate any feedback. *** /root/samba-2.2.5/source/nsswitch/wb_common.c Wed Jun 19 03:13:44 2002 --- wb_common.c Thu Jul 25 16:36:39 2002 *************** *** 94,99 **** --- 94,120 ---- } } + /* Returns a duplicate of the given file descriptor that is guranteed + not to be 0, 1 or 2 (stdin, stdout or stderr respectively), unless + an error occurs. If the given fd is invalid, it will be returned + unchanged. If a different error occurs, the returned file handle + will still be valid but it may be 0, 1 or 2. If a valid file + handle is returned and the returned handle is different to the + original one, the original one will be closed. If dup() is broken, + this function might never return. */ + + int make_nonstd_fd(int fd) + { + int saved_fd; + if (0 >= fd && fd <= 2) { + fd = dup(saved_fd = fd); + if (fd == -1) return saved_fd; + fd = make_nonstd_fd(fd); + close(saved_fd); + } + return fd; + } + /* Connect to winbindd socket */ int winbind_open_pipe_sock(void) *************** *** 158,164 **** if ((winbindd_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { return -1; } ! if (connect(winbindd_fd, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) { close_sock(); --- 179,188 ---- if ((winbindd_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { return -1; } ! ! winbindd_fd = make_nonstd_fd( winbindd_fd ); ! ! if (connect(winbindd_fd, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) { close_sock(); *************** *** 167,172 **** --- 191,197 ---- return winbindd_fd; } + /* Write data to winbindd socket */