`smbpasswd -a' doesn't operate correctly when samba is configured to use the ldap pdb and the user to be added exists in ldap but has not yet been configured as a Samba user (it lacks a sambaSamAccount objectclass and related attributes). smbpasswd enumerates all existing samba users with the search filter: (&(uid=)(objectclass=sambaSamAccount)) and uses that information to decide that the user being added does not exist. For example, a user: dn: uid=craig,ou=People,dc=mycompany uid: craig objectclass: person objectclass: inetOrgPerson objectclass: posixAccount ... blah blah ... will not be found. It then goes on to send an LDAP `add' operation to create a new object with the required Samba attributes, eg: dn: uid=craig,ou=People,dc=mycompany uid: craig displayName: Craig Ringer sambaSID: S-1-5-blah objectclass: sambaSamAccount objectclass: account Note that it's used PAM or nss to obtain information about the user's account. This operation fails, as `uid=craig,ou=People,dc=mycompany' already exists in the database. If the user being entered with `smbpasswd -a' does not already exist in the database, smbpasswd correctly creates a new entry containing only Samba account information. Expected behaviour: smbpasswd searches for (uid=$user-being-added) within `ldap user suffix' before concluding that the user does not exist in the database. If the user is not found, operation continues as normal. If it is found, however, smbpasswd issues an LDAP "modify" operation instead of an LDAP "add" operation. Current behaviour: smbpasswd tries to add the user even if it already exists. If smbpasswd is not intended to modify existing accounts, but only manage samba account information in a separate part of the LDAP tree, this should be documented and smbpasswd modified to explicitly check for and complain about an already existing uid. Useful details: OS: Debian 3.1 Samba version: 3.0.14a-3 (debian package) OpenLDAP version: 2.2.23-8 (debian package) I'll attach a libpcap format trace of the add attempt by smbpasswd with encryption disabled. The LDAP bind transaction has been omitted from the trace because it contains the dn admin password. My smb.conf will also be provided.
Created attachment 2137 [details] [global] section of smb.conf
Created attachment 2138 [details] A libpcap formatted dump showing `smbpasswd -a' running for a user who already exists in LDAP. The libpcap packet trace has the LDAP bind requests and responses omitted. This means that ethereal will see those as missing TCP segments. The trace is otherwise intact and unmodified. The system being used also uses libpam-ldap and libnss-ldap so the trace may contain queries from them as well. The to-follow `smbpasswd -D 10 -a' output will make it clearer which are smbpasswd's .
Created attachment 2139 [details] `smbpasswd -D 10 -a craig' output
Created attachment 2140 [details] Output of " ldapsearch '(uid=craig)' " to show conflicting dn. Some contact details omitted.
Works fine for me. Just tested. Would you mindretesting 3.0.23c ?
Despite having spent a while looking at this before filing this bug I have - inevitably - found that this is my own stupid fault while collecting more information for the bug report. The filter specified in my smb.conf : (uid=%U) is incorrect. The correct and default filter is: (uid=%u) Unfortunately there is quite a bit of documentation outside samba that specifies this filter incorrectly, including the Samba section of the Oreilly book "LDAP System Administration". It's possible all the documents I found were out of date - but since the smb.conf man page is correct I have no excuse.
And that is why we removed the ldap filter option in recent Samba releases. %U should be fine. But the filter option is basically broken.
Hopefully Google will find it and prevent future questions or bug reports on this issue. To that end, I'd like to note that without -D 10 smbpasswd's primary complaint is that the account "already exists". Sorry for the fuss. I should've noticed the problem earlier, since the answer is right there in the tcpdump. It DOES search by just uid - but because of my bad filter option it searches for (uid=) not (uid=craig) or (uid=*) to enumerate all users, and naturally gets an empty result set. Thanks for looking at this, and sorry for the wasted time. I'll waste no more of your time after this post.