Winbind patch fixes broken client. Please have a look.

Hannes Schmidt mail at schmidt-net.via.t-online.de
Sun Jul 28 13:28:01 GMT 2002


Andrew Bartlett wrote:
> Hannes Schmidt wrote:
>> 
>> Even if this is complete crap, I would appreciate any feedback
>> saying so. 
> 
> Firstly, don't expect instant responses - particularly over the
> weekend...

Sure, I guess I was getting a little too excited.

> 
>> A couple of days ago I posted a problem report to the samba list
>> with some diagnostics. I seem to have found a
>> solution on my own and provide a patch here. The problem is related
>> to the fact that the winbind client code in
>> libnss_winbind.so leaves the handle to the winbind pipe open, for
>> obvious reasons. This is perfectly ok, but some
>> programs get confused if this handle is 0,1 or 2, which they expect
>> to be a handle to a different file. 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
>> re-open the pipe to winbindd, the handle will be 0 */
>>     fd = open( ... );     /* returned fd is *not* 0 although the
>> code below 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.
> 
> It is rather - well spotted for figuring it out.
> 
> How do other nss libraries deal with this?  NIS and LDAP both open
> sockets - find out if there is a standard solution to the problem.
> Personally, I don't like the idea of messing with a program's file
> descriptors - but this is a problem we will have to cope with.

I'll have a look at it. 

Regarding messing around with fds: An alternative would be to only 
leave the pipe handle open if it is > 2. It will get re-opened next time. 
This might slow down daemon processes which detach themselves 
from stdin and stdout.
 
>> The provided patch to wb_common.c makes sure that the handle to the
>> winbindd pipe is not 0, 1 or 2.
> 
> For future reference, patches should be in 'diff -u' format, if
> possible.

Makes sense.
 
>> *** /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. */ 
> 
> I don't like that idea.  It should fail - infinite loops are bad...

Yes, if we decide to use this solution I will have to limit the
recursion or turn it into a loop with a limited amount of
iterations.

>> + 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 */





More information about the samba-technical mailing list