[Samba] Re: Simple question - Machine / User relationsip

Jim C jcllings at tsunamicomm.net
Wed Jan 22 05:07:03 GMT 2003

I've solved this.

Since a computer is a user (effectively), it must have a unique 
uidNumber (regardless of whether or not it lives in a different ou) and 
properly calculated rid and primaryGroupID attributes.  I've found that 
the scripts provided do not do an adequate job in this regards.  There 
is also a problem with getting the largest uidNumber from the system so 
that you can add 1 to it and set it as the uid for the new user.

What I did to solve this was add objectcalss's uidPool and gidPool to my 
proxyuser.  This results in the addition of attributes uidNumber and 
gidNumber to the proxyuser.  I then wrote a script to get the values of 
the largest uidNumber and the largest gidNumber and leave these values 
in the proxyuser's uidNumber and gidNumber.  Then I wrote another that 
adds one to those numbers and then updates the proxyuser with the new 
numbers.  Then in the script, I take the numbers and use them to build a 
new machine user.

I can send you the script but it will need modification.  For one thing 
it has to have the root dn's password and of course it needs to know 
where everything is.  I tried to put all of this at the top for ease of 
adaptation.  It is written in php.

I also discovered that /etc/ldap.conf on the server is not just for 
Linux's use locally.  When the system goes looking for *any* uid, it 
looks for the posix settings first in the ou specified in ldap.conf. 
That means that as far as the OS is concerned EVERY user is a posix 
user.  Consequently it cannot find users who do not exist in an ou 
spec'ed out in /etc/ldap.conf (i.e. ou=Computers is not in there) I now 
have my ldap.conf like so:

# The port.
# Optional: default is 389.
#port 389

# The search scope.
scope sub
#scope one
#scope base

and then later:

nss_base_passwd         dc=microverse,dc=net?sub
nss_base_shadow         dc=microverse,dc=net?sub
nss_base_group		ou=Group,dc=microverse,dc=net?one
nss_base_hosts		ou=Hosts,dc=microverse,dc=net?one

Basically this tells the system to start in dc=microverse,dc=net to look 
for password and shadow type records.  It proceeds to search every ou 
that exists at the dc=microverse,dc=net level for values of this type 
which basically means that it will be able to find our computers located 
in ou=Computers.  Previously these were set to ou=People?one which means 
it will only look in People.  It might be better though, for efficiency, 
if one made an ou=Usr and then put ou=People and ou=Computers 
underneath.  Then we can limit our passwd and shadow searches to ou=Usr.

Also don't forget that if you add an ou=Computers that you specifically 
grant your root user read/write privileges to it.  Might also be good to 
give the proxyuser read access.  Notice what I've done to protect the 
lmPassword and ntPassword attributes.

Here is the slapd.access.conf I am using:

# This is a good place to put slapd access-control directives
access to dn=".*,dc=microverse,dc=net" attr=*
	by dn="cn=root,dc=microverse,dc=net" write

access to dn=".*,dc=microverse,dc=net" attr=userPassword
	by dn="cn=root,dc=microverse,dc=net" write
	by dn="cn=Administrator,ou=People,dc=microverse,dc=net" write
	by dn="cn=proxyuser,dc=microverse,dc=net" read
	by self write
	by * auth

access to dn=".*,dc=microverse,dc=net" attrs=lmPassword,ntPassword
         by dn="cn=root,dc=microverse,dc=net" write
	by dn="uid=Administrator,ou=People,dc=microverse,dc=net" write
	by self write
	by * auth

access to dn=".*,dc=microverse,dc=net" attr=mail
	by dn="cn=root,dc=microverse,dc=net" write
	by dn="cn=Administrator,ou=People,dc=microverse,dc=net" write
	by self write
	by * read
access to dn=".*,ou=People,dc=microverse,dc=net"
	by * read

access to dn=".*,ou=Computers,dc=microverse,dc=net"
         by * read

access to dn=".*,dc=microverse,dc=net"
	by self write
	by * read

Bas Goes wrote:
> Hi Jim,
> I have had the exact same problem and didn't find a solution, now i am
> looking at samba tng, but that one won't compile and I'd rather use
> samba. If you have a solution or an idea, i would be quite grateful if
> you share it with me. 
> Thanks in advance.
> Regards,
> Bas

-------------- next part --------------
This script takes one parameter.  A userid.

Place it in smb.conf as the add user script like so:

add user script = php /usr/share/samba/scripts/addmachine.php %u

You can also test it from the command line like so:
php addmachine.php freddycruegar

Samba will append the "$" as required.

The maximum uidNumber value must also be held in proxyuser's uidNumber in
order for this to work.


// basic sequence with LDAP is connect, bind, search, interpret search
// result, close connection
define(ROOTPW,"placepasswordhere"); //<<<-------Need rootdn's PW.
define(MINUID, 500);
//The group "Machines" as mentioned below on my system is group 421.
define(NUMRETRIES, 4);

This function grabs the number of the greatest uid value in the system from
proxyuser's uidNumber and then increments it and updates proxyuser.

We then take the number and use it to make a new account since this new number
is, in theory, unique.
function getnewuid ($ds) {

	//We get a number of retries equal to NUMRTRIES
	for($idx=0; $idx < NUMRETRIES && !$booleantest ;$idx=$idx+1 )

		$entries=ldap_get_entries($ds, ldap_search($ds, PROXYDN ,"cn=*"));
		If another such script starts and finishes it's ldap_mod_replace before 
		we get ours started right here at this point, then we have a race condition
		at the script level.  This is why I've tried to condense this part as 
		much as possible.
		Nothing to be done about this. As far as I can tell there is no way
		to lock attributes or records in php-ldap.
		//Watch out.  In some cases like below "uidnumber" must be all lowercase.

		if($entries[0]["uidnumber"][0] < MINUID )
			$change_entry["uidnumber"] = MINUID;
			$change_entry["uidnumber"] = $entries[0]["uidnumber"][0] + 1;
		//This, at least, is atomic.
		$booleantest=ldap_mod_replace($ds, PROXYDN, $change_entry);

		return $change_entry["uidnumber"];
		die("Timeout error! Unable to set uidNumber in PROXYDN.  To many users being added from other sources?\n");
	}//end of function getnewuid ($ds)

//echo "LDAP query test\n";
//echo "Connecting ...\n";
$ds=ldap_connect(LDAPSERVER);  // must be a valid LDAP server!
//echo "connect result is ".$ds."\n";

if ($ds) {
//echo "Binding ...";    


//echo "Bind result is ".$r."\n";

} else die( "Unable to connect to LDAP server!\n");

Despite the fact that this is not a real user we must have a password.
Below we generate one based on a random number.
//Change the below to match where your Computer accounts are going.
$dn = "uid=$machine,ou=Computers,dc=microverse,dc=net";
$new_object["objectClass"][0] = "top";
$new_object["objectClass"][1] = "account";
$new_object["objectClass"][2] = "posixAccount";
//$new_object["objectClass"][3] = "shadowAccount";
$new_object["uidNumber"][0] = getnewuid($ds);
$new_object["uid"][0] = $machine;
$new_object["cn"][0] = $machine;
$new_object["gidNumber"][0] = MACHINEGROUP;
$new_object["homeDirectory"][0] = "/dev/null";
$new_object["loginShell"][0] = "/bin/false";
$new_object["gecos"][0] = "Machine Account";
$new_object["description"][0] = "Machine Account";
$new_object["userPassword"][0] = `slappasswd -h {CRYPT} -s $psswrd`;

//Samba takes care of the rest of the attributes.  They are calculated
//based on these.

if(!ldap_add($ds, $dn, $new_object))
	die("Error! Could not add new user. Most likely someone already has that userid.\n");

//echo "\nClosing connection\n";
#system(escapeshellcmd("smbpasswd -a -m $username$"));

More information about the samba mailing list