Fixed log viewer bug that caused some entries to go missing from the dropdown of...
[openemr.git] / library / adldap / adLDAP.php
blob4855178916b244921d985832b27c36e4fe9733fd
1 <?php
2 /*
3 PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY
4 Version 2.1
6 Written by Scott Barnett
7 email: scott@wiggumworld.com
8 http://adldap.sourceforge.net/
10 Copyright (C) 2006-2007 Scott Barnett
12 I'd appreciate any improvements or additions to be submitted back
13 to benefit the entire community :)
15 Works with PHP 5, should be fine with PHP 4, let me know if/where it doesn't :)
17 Please visit the project website for a full list of the functions and
18 documentation on using them.
19 http://adldap.sourceforge.net/documentation.php
21 This library is free software; you can redistribute it and/or
22 modify it under the terms of the GNU Lesser General Public
23 License as published by the Free Software Foundation; either
24 version 2.1 of the License, or (at your option) any later version.
26 This library is distributed in the hope that it will be useful,
27 but WITHOUT ANY WARRANTY; without even the implied warranty of
28 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29 Lesser General Public License for more details.
31 ********************************************************************
32 Something to keep in mind is that Active Directory is a permissions
33 based directory. If you bind as a domain user, you can't fetch as
34 much information on other users as you could as a domain admin.
35 ********************************************************************
38 // Different type of accounts in AD
39 define ('ADLDAP_NORMAL_ACCOUNT', 805306368);
40 define ('ADLDAP_WORKSTATION_TRUST', 805306369);
41 define ('ADLDAP_INTERDOMAIN_TRUST', 805306370);
42 define ('ADLDAP_SECURITY_GLOBAL_GROUP', 268435456);
43 define ('ADLDAP_DISTRIBUTION_GROUP', 268435457);
44 define ('ADLDAP_SECURITY_LOCAL_GROUP', 536870912);
45 define ('ADLDAP_DISTRIBUTION_LOCAL_GROUP', 536870913);
47 class adLDAP {
48 // BEFORE YOU ASK A QUESTION, PLEASE READ THE DOCUMENTATION AND THE FAQ
49 // http://adldap.sourceforge.net/documentation.php
50 // http://adldap.sourceforge.net/faq.php
52 // You can set your default variables here, or when you invoke the class
53 var $_account_suffix="";
54 var $_base_dn = "";
56 // An array of domain controllers. Specify multiple controllers if you
57 // would like the class to balance the LDAP queries amongst multiple servers
58 var $_domain_controllers = array ("");
60 // optional account with higher privileges for searching
61 // not really that optional because you can't query much as a user
62 var $_ad_username="";
63 var $_ad_password="";
65 // AD does not return the primary group. http://support.microsoft.com/?kbid=321360
66 // This tweak will resolve the real primary group, but may be resource intensive.
67 // Setting to false will fudge "Domain Users" and is much faster. Keep in mind though that if
68 // someone's primary group is NOT domain users, this is obviously going to bollocks the results
69 var $_real_primarygroup=true;
71 // Use SSL, your server needs to be setup, please see - http://adldap.sourceforge.net/ldap_ssl.php
72 var $_use_ssl=false;
74 // When querying group memberships, do it recursively
75 // eg. User Fred is a member of Group A, which is a member of Group B, which is a member of Group C
76 // user_ingroup("Fred","C") will returns true with this option turned on, false if turned off
77 var $_recursive_groups=true;
79 // You should not need to edit anything below this line
80 //******************************************************************************************
82 //other variables
83 var $_conn;
84 var $_bind;
86 // default constructor
87 function adLDAP($options=array()){
88 //you can specifically overide any of the default configuration options setup above
89 if (count($options)>0){
90 if (array_key_exists("account_suffix",$options)){ $this->_account_suffix=$options["account_suffix"]; }
91 if (array_key_exists("base_dn",$options)){ $this->_base_dn=$options["base_dn"]; }
92 if (array_key_exists("domain_controllers",$options)){ $this->_domain_controllers=$options["domain_controllers"]; }
93 if (array_key_exists("ad_username",$options)){ $this->_ad_username=$options["ad_username"]; }
94 if (array_key_exists("ad_password",$options)){ $this->_ad_password=$options["ad_password"]; }
95 if (array_key_exists("real_primarygroup",$options)){ $this->_real_primarygroup=$options["real_primarygroup"]; }
96 if (array_key_exists("use_ssl",$options)){ $this->_use_ssl=$options["use_ssl"]; }
97 if (array_key_exists("recursive_groups",$options)){ $this->_recursive_groups=$options["recursive_groups"]; }
100 //connect to the LDAP server as the username/password
101 $dc=$this->random_controller();
102 if ($this->_use_ssl){
103 $this->_conn = ldap_connect("ldaps://".$dc);
104 } else {
105 $this->_conn = ldap_connect($dc);
108 //set some ldap options for talking to AD
109 ldap_set_option($this->_conn, LDAP_OPT_PROTOCOL_VERSION, 3);
110 ldap_set_option($this->_conn, LDAP_OPT_REFERRALS, 0);
112 //bind as a domain admin if they've set it up
113 if ($this->_ad_username!=NULL && $this->_ad_password!=NULL){
114 $this->_bind = @ldap_bind($this->_conn,$this->_ad_username.$this->_account_suffix,$this->_ad_password);
115 if (!$this->_bind){
116 if ($this->_use_ssl){
117 //if you have problems troubleshooting, remove the @ character from the ldap_bind command above to get the actual error message
118 echo ("FATAL: AD bind failed. Either the LDAPS connection failed or the login credentials are incorrect."); exit();
119 } else {
120 echo ("FATAL: AD bind failed. Check the login credentials."); exit();
125 return (true);
128 // default destructor
129 function __destruct(){ ldap_close ($this->_conn); }
131 //validate a users login credentials
132 function authenticate($username,$password,$prevent_rebind=false){
133 if ($username==NULL || $password==NULL){ return (false); } //prevent null binding
135 //bind as the user
136 $this->_bind = @ldap_bind($this->_conn,$username.$this->_account_suffix,$password);
137 if (!$this->_bind){ return (false); }
139 //once we've checked their details, kick back into admin mode if we have it
140 if ($this->_ad_username!=NULL && !$prevent_rebind){
141 $this->_bind = @ldap_bind($this->_conn,$this->_ad_username.$this->_account_suffix,$this->_ad_password);
142 if (!$this->_bind){ echo ("FATAL: AD rebind failed."); exit(); } //this should never happen in theory
145 return (true);
148 //*****************************************************************************************************************
149 // GROUP FUNCTIONS
151 // Add a group to a group
152 function group_add_group($parent,$child){
154 //find the parent group's dn
155 $parent_group=$this->group_info($parent,array("cn"));
156 if ($parent_group[0]["dn"]==NULL){ return (false); }
157 $parent_dn=$parent_group[0]["dn"];
159 //find the child group's dn
160 $child_group=$this->group_info($child,array("cn"));
161 if ($child_group[0]["dn"]==NULL){ return (false); }
162 $child_dn=$child_group[0]["dn"];
164 $add=array();
165 $add["member"] = $child_dn;
167 $result=@ldap_mod_add($this->_conn,$parent_dn,$add);
168 if ($result==false){ return (false); }
169 return (true);
172 // Add a user to a group
173 function group_add_user($group,$user){
174 //adding a user is a bit fiddly, we need to get the full DN of the user
175 //and add it using the full DN of the group
177 //find the user's dn
178 $user_info=$this->user_info($user,array("cn"));
179 if ($user_info[0]["dn"]==NULL){ return (false); }
180 $user_dn=$user_info[0]["dn"];
182 //find the group's dn
183 $group_info=$this->group_info($group,array("cn"));
184 if ($group_info[0]["dn"]==NULL){ return (false); }
185 $group_dn=$group_info[0]["dn"];
187 $add=array();
188 $add["member"] = $user_dn;
190 $result=@ldap_mod_add($this->_conn,$group_dn,$add);
191 if ($result==false){ return (false); }
192 return (true);
195 // Create a group
196 function group_create($attributes){
197 if (!is_array($attributes)){ return ("Attributes must be an array"); }
198 if (!array_key_exists("group_name",$attributes)){ return ("Missing compulsory field [group_name]"); }
199 if (!array_key_exists("container",$attributes)){ return ("Missing compulsory field [container]"); }
200 if (!array_key_exists("description",$attributes)){ return ("Missing compulsory field [description]"); }
201 if (!is_array($attributes["container"])){ return ("Container attribute must be an array."); }
202 $attributes["container"]=array_reverse($attributes["container"]);
204 //$member_array = array();
205 //$member_array[0] = "cn=user1,cn=Users,dc=yourdomain,dc=com";
206 //$member_array[1] = "cn=administrator,cn=Users,dc=yourdomain,dc=com";
208 $add=array();
209 $add["cn"] = $attributes["group_name"];
210 $add["samaccountname"] = $attributes["group_name"];
211 $add["objectClass"] = "Group";
212 $add["description"] = $attributes["description"];
213 //$add["member"] = $member_array; UNTESTED
215 $container="OU=".implode(",OU=",$attributes["container"]);
216 $result=ldap_add($this->_conn,"CN=".$add["cn"].", ".$container.",".$this->_base_dn,$add);
217 if ($result!=true){ return (false); }
219 return (true);
222 // Remove a group from a group
223 function group_del_group($parent,$child){
225 //find the parent dn
226 $parent_group=$this->group_info($parent,array("cn"));
227 if ($parent_group[0]["dn"]==NULL){ return (false); }
228 $parent_dn=$parent_group[0]["dn"];
230 //find the child dn
231 $child_group=$this->group_info($child,array("cn"));
232 if ($child_group[0]["dn"]==NULL){ return (false); }
233 $child_dn=$child_group[0]["dn"];
235 $del=array();
236 $del["member"] = $child_dn;
238 $result=@ldap_mod_del($this->_conn,$parent_dn,$del);
239 if ($result==false){ return (false); }
240 return (true);
243 // Remove a user from a group
244 function group_del_user($group,$user){
246 //find the parent dn
247 $group_info=$this->group_info($group,array("cn"));
248 if ($group_info[0]["dn"]==NULL){ return (false); }
249 $group_dn=$group_info[0]["dn"];
251 //find the child dn
252 $user_info=$this->user_info($user,array("cn"));
253 if ($user_info[0]["dn"]==NULL){ return (false); }
254 $user_dn=$user_info[0]["dn"];
256 $del=array();
257 $del["member"] = $user_dn;
259 $result=@ldap_mod_del($this->_conn,$group_dn,$del);
260 if ($result==false){ return (false); }
261 return (true);
264 // Returns an array of information for a specified group
265 function group_info($group_name,$fields=NULL){
266 if ($group_name==NULL){ return (false); }
267 if (!$this->_bind){ return (false); }
269 $filter="(&(objectCategory=group)(name=".$this->ldap_slashes($group_name)."))";
270 //echo ($filter."!!!<br>");
271 if ($fields==NULL){ $fields=array("member","memberof","cn","description","distinguishedname","objectcategory","samaccountname"); }
272 $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields);
273 $entries = ldap_get_entries($this->_conn, $sr);
274 //print_r($entries);
275 return ($entries);
278 // Retun a complete list of "groups in groups"
279 function recursive_groups($group){
280 if ($group==NULL){ return (false); }
282 $ret_groups=array();
284 $groups=$this->group_info($group,array("memberof"));
285 $groups=$groups[0]["memberof"];
287 if ($groups){
288 $group_names=$this->nice_names($groups);
289 $ret_groups=array_merge($ret_groups,$group_names); //final groups to return
291 foreach ($group_names as $id => $group_name){
292 $child_groups=$this->recursive_groups($group_name);
293 $ret_groups=array_merge($ret_groups,$child_groups);
297 return ($ret_groups);
300 //*****************************************************************************************************************
301 // USER FUNCTIONS
303 //create a user
304 function user_create($attributes){
305 //check for compulsory fields
306 if (!array_key_exists("username",$attributes)){ return ("Missing compulsory field [username]"); }
307 if (!array_key_exists("firstname",$attributes)){ return ("Missing compulsory field [firstname]"); }
308 if (!array_key_exists("surname",$attributes)){ return ("Missing compulsory field [surname]"); }
309 if (!array_key_exists("email",$attributes)){ return ("Missing compulsory field [email]"); }
310 if (!array_key_exists("container",$attributes)){ return ("Missing compulsory field [container]"); }
311 if (!is_array($attributes["container"])){ return ("Container attribute must be an array."); }
313 if (array_key_exists("password",$attributes) && !$this->_use_ssl){ echo ("FATAL: SSL must be configured on your webserver and enabled in the class to set passwords."); exit(); }
315 if (!array_key_exists("display_name",$attributes)){ $attributes["display_name"]=$attributes["firstname"]." ".$attributes["surname"]; }
317 //translate the schema
318 $add=$this->adldap_schema($attributes);
320 //additional stuff only used for adding accounts
321 $add["cn"][0]=$attributes["display_name"];
322 $add["samaccountname"][0]=$attributes["username"];
323 $add["objectclass"][0]="top";
324 $add["objectclass"][1]="person";
325 $add["objectclass"][2]="organizationalPerson";
326 $add["objectclass"][3]="user"; //person?
327 //$add["name"][0]=$attributes["firstname"]." ".$attributes["surname"];
329 //set the account control attribute
330 $control_options=array("NORMAL_ACCOUNT");
331 if (!$attributes["enabled"]){ $control_options[]="ACCOUNTDISABLE"; }
332 $add["userAccountControl"][0]=$this->account_control($control_options);
333 //echo ("<pre>"); print_r($add);
335 //determine the container
336 $attributes["container"]=array_reverse($attributes["container"]);
337 $container="OU=".implode(",OU=",$attributes["container"]);
339 //add the entry
340 $result=@ldap_add($this->_conn, "CN=".$add["cn"][0].", ".$container.",".$this->_base_dn, $add);
341 if ($result!=true){ return (false); }
343 return (true);
346 // user_groups($user)
347 // Returns an array of groups that a user is a member off
348 function user_groups($username,$recursive=NULL){
349 if ($username==NULL){ return (false); }
350 if ($recursive==NULL){ $recursive=$this->_recursive_groups; } //use the default option if they haven't set it
351 if (!$this->_bind){ return (false); }
353 //search the directory for their information
354 $info=@$this->user_info($username,array("memberof","primarygroupid"));
355 $groups=$this->nice_names($info[0]["memberof"]); //presuming the entry returned is our guy (unique usernames)
357 if ($recursive){
358 foreach ($groups as $id => $group_name){
359 $extra_groups=$this->recursive_groups($group_name);
360 $groups=array_merge($groups,$extra_groups);
364 return ($groups);
367 // Returns an array of information for a specific user
368 function user_info($username,$fields=NULL){
369 if ($username==NULL){ return (false); }
370 if (!$this->_bind){ return (false); }
372 $filter="samaccountname=".$username;
373 if ($fields==NULL){ $fields=array("samaccountname","mail","memberof","department","displayname","telephonenumber","primarygroupid"); }
374 $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields);
375 $entries = ldap_get_entries($this->_conn, $sr);
377 // AD does not return the primary group in the ldap query, we may need to fudge it
378 if ($this->_real_primarygroup){
379 $entries[0]["memberof"][]=$this->group_cn($entries[0]["primarygroupid"][0]);
380 } else {
381 $entries[0]["memberof"][]="CN=Domain Users,CN=Users,".$this->_base_dn;
384 $entries[0]["memberof"]["count"]++;
385 return ($entries);
388 // Returns true if the user is a member of the group
389 function user_ingroup($username,$group,$recursive=NULL){
390 if ($username==NULL){ return (false); }
391 if ($group==NULL){ return (false); }
392 if (!$this->_bind){ return (false); }
393 if ($recursive==NULL){ $recursive=$this->_recursive_groups; } //use the default option if they haven't set it
395 //get a list of the groups
396 $groups=$this->user_groups($username,array("memberof"),$recursive);
398 //return true if the specified group is in the group list
399 if (in_array($group,$groups)){ return (true); }
401 return (false);
404 //modify a user
405 function user_modify($username,$attributes){
406 if ($username==NULL){ return ("Missing compulsory field [username]"); }
407 if (array_key_exists("password",$attributes) && !$this->_use_ssl){ echo ("FATAL: SSL must be configured on your webserver and enabled in the class to set passwords."); exit(); }
408 //if (array_key_exists("container",$attributes)){
409 //if (!is_array($attributes["container"])){ return ("Container attribute must be an array."); }
410 //$attributes["container"]=array_reverse($attributes["container"]);
413 //find the dn of the user
414 $user=$this->user_info($username,array("cn"));
415 if ($user[0]["dn"]==NULL){ return (false); }
416 $user_dn=$user[0]["dn"];
418 //translate the update to the LDAP schema
419 $mod=$this->adldap_schema($attributes);
420 if (!$mod){ return (false); }
422 //set the account control attribute (only if specified)
423 if (array_key_exists("enabled",$attributes)){
424 if ($attributes["enabled"]){ $control_options=array("NORMAL_ACCOUNT"); }
425 else { $control_options=array("NORMAL_ACCOUNT","ACCOUNTDISABLE"); }
426 $mod["userAccountControl"][0]=$this->account_control($control_options);
429 //do the update
430 $result=ldap_modify($this->_conn,$user_dn,$mod);
431 if ($result==false){ return (false); }
433 return (true);
436 // Set the password of a user
437 function user_password($username,$password){
438 if ($username==NULL){ return (false); }
439 if ($password==NULL){ return (false); }
440 if (!$this->_bind){ return (false); }
441 if (!$this->_use_ssl){ echo ("FATAL: SSL must be configured on your webserver and enabled in the class to set passwords."); exit(); }
443 $user=$this->user_info($username,array("cn"));
444 if ($user[0]["dn"]==NULL){ return (false); }
445 $user_dn=$user[0]["dn"];
447 $add=array();
448 $add["unicodePwd"][0]=$this->encode_password($password);
450 $result=ldap_mod_replace($this->_conn,$user_dn,$add);
451 if ($result==false){ return (false); }
453 return (true);
456 //*****************************************************************************************************************
457 // COMPUTER FUNCTIONS
459 // Returns an array of information for a specific computer
460 function computer_info($computer_name,$fields=NULL){
461 if ($computer_name==NULL){ return (false); }
462 if (!$this->_bind){ return (false); }
464 $filter="(&(objectClass=computer)(cn=".$computer_name."))";
465 if ($fields==NULL){ $fields=array("memberof","cn","displayname","dnshostname","distinguishedname","objectcategory","operatingsystem","operatingsystemservicepack","operatingsystemversion"); }
466 $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields);
467 $entries = ldap_get_entries($this->_conn, $sr);
469 return ($entries);
472 // Returns all AD users
473 function all_users($include_desc = false, $search = "*", $sorted = true){
474 if (!$this->_bind){ return (false); }
476 //perform the search and grab all their details
477 $filter = "(&(objectClass=user)(samaccounttype=". ADLDAP_NORMAL_ACCOUNT .")(objectCategory=person)(cn=".$search."))";
478 $fields=array("samaccountname","displayname");
479 $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields);
480 $entries = ldap_get_entries($this->_conn, $sr);
482 $users_array = array();
483 for ($i=0; $i<$entries["count"]; $i++){
484 if ($include_desc && strlen($entries[$i]["displayname"][0])>0){
485 $users_array[ $entries[$i]["samaccountname"][0] ] = $entries[$i]["displayname"][0];
486 } elseif ($include_desc){
487 $users_array[ $entries[$i]["samaccountname"][0] ] = $entries[$i]["samaccountname"][0];
488 } else {
489 array_push($users_array, $entries[$i]["samaccountname"][0]);
492 if ($sorted){ asort($users_array); }
493 return ($users_array);
497 * custom LDAP search returning AD users
499 function find_users($include_desc = false, $filter = "*", $sorted = true){
500 if (!$this->_bind){ return (false); }
502 //perform the search and grab all their details
503 //$filter = "(&(objectClass=user)(samaccounttype=". ADLDAP_NORMAL_ACCOUNT .")(objectCategory=person)(cn=".$search."))";
504 $fields=array("samaccountname","displayname");
505 $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields);
506 $entries = ldap_get_entries($this->_conn, $sr);
508 $users_array = array();
509 for ($i=0; $i<$entries["count"]; $i++){
510 if ($include_desc && strlen($entries[$i]["displayname"][0])>0){
511 $users_array[ $entries[$i]["samaccountname"][0] ] = $entries[$i]["displayname"][0];
512 } elseif ($include_desc){
513 $users_array[ $entries[$i]["samaccountname"][0] ] = $entries[$i]["samaccountname"][0];
514 } else {
515 array_push($users_array, $entries[$i]["samaccountname"][0]);
518 if ($sorted){ asort($users_array); }
519 return ($users_array);
522 // Returns a complete list of the groups in AD
523 function all_groups($include_desc = false, $search = "*", $sorted = true){
524 if (!$this->_bind){ return (false); }
526 //perform the search and grab all their details
527 $filter = "(&(objectCategory=group)(samaccounttype=". ADLDAP_SECURITY_GLOBAL_GROUP .")(cn=".$search."))";
528 $fields=array("samaccountname","description");
529 $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields);
530 $entries = ldap_get_entries($this->_conn, $sr);
532 $groups_array = array();
533 for ($i=0; $i<$entries["count"]; $i++){
534 if ($include_desc && strlen($entries[$i]["description"][0]) > 0 ){
535 $groups_array[ $entries[$i]["samaccountname"][0] ] = $entries[$i]["description"][0];
536 } elseif ($include_desc){
537 $groups_array[ $entries[$i]["samaccountname"][0] ] = $entries[$i]["samaccountname"][0];
538 } else {
539 array_push($groups_array, $entries[$i]["samaccountname"][0]);
542 if( $sorted ){ asort($groups_array); }
543 return ($groups_array);
546 //************************************************************************************************************
547 // UTILITY FUNCTIONS (not intended to be called directly but I spose you could?)
549 function adldap_schema($attributes){
551 //ldap doesn't like NULL attributes, only set them if they have values
552 // I'd like to know how to set an LDAP attribute to NULL though, at the moment I set it to a space
553 $mod=array();
554 if ($attributes["address_city"]){ $mod["l"][0]=$attributes["address_city"]; }
555 if ($attributes["address_code"]){ $mod["postalCode"][0]=$attributes["address_code"]; }
556 //if ($attributes["address_country"]){ $mod["countryCode"][0]=$attributes["address_country"]; } // use country codes?
557 if ($attributes["address_pobox"]){ $mod["postOfficeBox"][0]=$attributes["address_pobox"]; }
558 if ($attributes["address_state"]){ $mod["st"][0]=$attributes["address_state"]; }
559 if ($attributes["address_street"]){ $mod["streetAddress"][0]=$attributes["address_street"]; }
560 if ($attributes["company"]){ $mod["company"][0]=$attributes["company"]; }
561 if ($attributes["change_password"]){ $mod["pwdLastSet"][0]=0; }
562 if ($attributes["company"]){ $mod["company"][0]=$attributes["company"]; }
563 if ($attributes["department"]){ $mod["department"][0]=$attributes["department"]; }
564 if ($attributes["description"]){ $mod["description"][0]=$attributes["description"]; }
565 if ($attributes["display_name"]){ $mod["displayName"][0]=$attributes["display_name"]; }
566 if ($attributes["email"]){ $mod["mail"][0]=$attributes["email"]; }
567 if ($attributes["expires"]){ $mod["accountExpires"][0]=$attributes["expires"]; } //unix epoch format?
568 if ($attributes["firstname"]){ $mod["givenName"][0]=$attributes["firstname"]; }
569 if ($attributes["home_directory"]){ $mod["homeDirectory"][0]=$attributes["home_directory"]; }
570 if ($attributes["home_drive"]){ $mod["homeDrive"][0]=$attributes["home_drive"]; }
571 if ($attributes["initials"]){ $mod["initials"][0]=$attributes["initials"]; }
572 if ($attributes["logon_name"]){ $mod["userPrincipalName"][0]=$attributes["logon_name"]; }
573 if ($attributes["manager"]){ $mod["manager"][0]=$attributes["manager"]; } //UNTESTED ***Use DistinguishedName***
574 if ($attributes["office"]){ $mod["physicalDeliveryOfficeName"][0]=$attributes["office"]; }
575 if ($attributes["password"]){ $mod["unicodePwd"][0]=$this->encode_password($attributes["password"]); }
576 if ($attributes["profile_path"]){ $mod["profilepath"][0]=$attributes["profile_path"]; }
577 if ($attributes["script_path"]){ $mod["scriptPath"][0]=$attributes["script_path"]; }
578 if ($attributes["surname"]){ $mod["sn"][0]=$attributes["surname"]; }
579 if ($attributes["title"]){ $mod["title"][0]=$attributes["title"]; }
580 if ($attributes["telephone"]){ $mod["telephoneNumber"][0]=$attributes["telephone"]; }
581 if ($attributes["web_page"]){ $mod["wWWHomePage"][0]=$attributes["web_page"]; }
583 // what if we actually use the REAL LDAP attribute names?! -- JRM
585 if ($attributes["givenname"]){ $mod["givenname"][0]=$attributes["givenname"]; } //JRM
586 if ($attributes["sn"]){ $mod["sn"][0]=$attributes["sn"]; } //JRM
587 if ($attributes["displayname"]){ $mod["displayname"][0]=$attributes["displayname"]; } //JRM
588 if ($attributes["physicaldeliveryofficename"]){ $mod["physicaldeliveryofficename"][0]=$attributes["physicaldeliveryofficename"]; } //JRM
589 if ($attributes["homephone"]){ $mod["homephone"][0]=$attributes["homephone"]; } //JRM
590 if ($attributes["telephonenumber"]){ $mod["telephonenumber"][0]=$attributes["telephonenumber"]; } //JRM
591 if ($attributes["mobile"]){ $mod["mobile"][0]=$attributes["mobile"]; } //JRM
592 if ($attributes["pager"]){ $mod["pager"][0]=$attributes["pager"]; } //JRM
593 if ($attributes["facsimiletelephonenumber"]){ $mod["facsimiletelephonenumber"][0]=$attributes["facsimiletelephonenumber"]; } //JRM
594 if ($attributes["mail"]){ $mod["mail"][0]=$attributes["mail"]; } //JRM
595 if ($attributes["title"]){ $mod["title"][0]=$attributes["title"]; } //JRM
596 if ($attributes["department"]){ $mod["department"][0]=$attributes["department"]; } //JRM
597 if ($attributes["streetaddress"]){ $mod["streetaddress"][0]=$attributes["streetaddress"]; } //JRM
598 if ($attributes["postofficebox"]){ $mod["postofficebox"][0]=$attributes["postofficebox"]; } //JRM
599 if ($attributes["l"]){ $mod["l"][0]=$attributes["l"]; } //JRM
600 if ($attributes["st"]){ $mod["st"][0]=$attributes["st"]; } //JRM
601 if ($attributes["postalcode"]){ $mod["postalcode"][0]=$attributes["postalcode"]; } //JRM
603 //echo ("<pre>"); print_r($mod);
605 // modifying a name is a bit fiddly
606 if ($attributes["firstname"] && $attributes["surname"]){
607 $mod["cn"][0]=$attributes["firstname"]." ".$attributes["surname"];
608 $mod["displayname"][0]=$attributes["firstname"]." ".$attributes["surname"];
609 $mod["name"][0]=$attributes["firstname"]." ".$attributes["surname"];
612 if (count($mod)==0){ return (false); }
613 return ($mod);
617 function group_cn($gid){
618 // coping with AD not returning the primary group
619 // http://support.microsoft.com/?kbid=321360
620 // for some reason it's not possible to search on primarygrouptoken=XXX
621 // if someone can show otherwise, I'd like to know about it :)
622 // this way is resource intensive and generally a pain in the @#%^
624 if ($gid==NULL){ return (false); }
625 $r=false;
627 $filter="(&(objectCategory=group)(samaccounttype=". ADLDAP_SECURITY_GLOBAL_GROUP ."))";
628 $fields=array("primarygrouptoken","samaccountname","distinguishedname");
629 $sr=ldap_search($this->_conn,$this->_base_dn,$filter,$fields);
630 $entries = ldap_get_entries($this->_conn, $sr);
632 for ($i=0; $i<$entries["count"]; $i++){
633 if ($entries[$i]["primarygrouptoken"][0]==$gid){
634 $r=$entries[$i]["distinguishedname"][0];
635 $i=$entries["count"];
639 return ($r);
642 // Encode a password for transmission over LDAP
643 function encode_password($password){
644 $password="\"".$password."\"";
645 $encoded="";
646 for ($i=0; $i <strlen($password); $i++){ $encoded.="{$password{$i}}\000"; }
647 return ($encoded);
650 // Escape bad characters
651 // DEVELOPERS SHOULD BE DOING PROPER FILTERING IF THEY'RE ACCEPTING USER INPUT
652 // this is just a list of characters with known problems and I'm trying not to strip out other languages
653 function ldap_slashes($str){
654 $illegal=array("(",")","#"); // the + character has problems too, but it's an illegal character
656 $legal=array();
657 foreach ($illegal as $id => $char){ $legal[$id]="\\".$char; } //make up the array of legal chars
659 $str=str_replace($illegal,$legal,$str); //replace them
660 return ($str);
663 // Return a random controller
664 function random_controller(){
665 //select a random domain controller
666 mt_srand(doubleval(microtime()) * 100000000); // for older php versions
667 return ($this->_domain_controllers[array_rand($this->_domain_controllers)]);
670 function account_control($options){
671 $val=0;
673 if (is_array($options)){
674 if (in_array("SCRIPT",$options)){ $val=$val+1; }
675 if (in_array("ACCOUNTDISABLE",$options)){ $val=$val+2; }
676 if (in_array("HOMEDIR_REQUIRED",$options)){ $val=$val+8; }
677 if (in_array("LOCKOUT",$options)){ $val=$val+16; }
678 if (in_array("PASSWD_NOTREQD",$options)){ $val=$val+32; }
679 //PASSWD_CANT_CHANGE Note You cannot assign this permission by directly modifying the UserAccountControl attribute.
680 //For information about how to set the permission programmatically, see the "Property flag descriptions" section.
681 if (in_array("ENCRYPTED_TEXT_PWD_ALLOWED",$options)){ $val=$val+128; }
682 if (in_array("TEMP_DUPLICATE_ACCOUNT",$options)){ $val=$val+256; }
683 if (in_array("NORMAL_ACCOUNT",$options)){ $val=$val+512; }
684 if (in_array("INTERDOMAIN_TRUST_ACCOUNT",$options)){ $val=$val+2048; }
685 if (in_array("WORKSTATION_TRUST_ACCOUNT",$options)){ $val=$val+4096; }
686 if (in_array("SERVER_TRUST_ACCOUNT",$options)){ $val=$val+8192; }
687 if (in_array("DONT_EXPIRE_PASSWORD",$options)){ $val=$val+65536; }
688 if (in_array("MNS_LOGON_ACCOUNT",$options)){ $val=$val+131072; }
689 if (in_array("SMARTCARD_REQUIRED",$options)){ $val=$val+262144; }
690 if (in_array("TRUSTED_FOR_DELEGATION",$options)){ $val=$val+524288; }
691 if (in_array("NOT_DELEGATED",$options)){ $val=$val+1048576; }
692 if (in_array("USE_DES_KEY_ONLY",$options)){ $val=$val+2097152; }
693 if (in_array("DONT_REQ_PREAUTH",$options)){ $val=$val+4194304; }
694 if (in_array("PASSWORD_EXPIRED",$options)){ $val=$val+8388608; }
695 if (in_array("TRUSTED_TO_AUTH_FOR_DELEGATION",$options)){ $val=$val+16777216; }
697 return ($val);
700 // Take an ldap query and return the nice names, without all the LDAP prefixes (eg. CN, DN)
701 function nice_names($groups){
703 $group_array=array();
704 for ($i=0; $i<$groups["count"]; $i++){ //for each group
705 $line=$groups[$i];
707 if (strlen($line)>0){
708 //more presumptions, they're all prefixed with CN=
709 //so we ditch the first three characters and the group
710 //name goes up to the first comma
711 $bits=explode(",",$line);
712 $group_array[]=substr($bits[0],3,(strlen($bits[0])-3));
715 return ($group_array);
718 // return the most recent LDAP error
719 function LastError() {
720 return ldap_error($this->_conn);
723 } // End class