1<?php
2/**
3 * PHP LDAP CLASS FOR MANIPULATING ACTIVE DIRECTORY
4 * Version 4.0.4
5 *
6 * PHP Version 5 with SSL and LDAP support
7 *
8 * Written by Scott Barnett, Richard Hyland
9 *   email: scott@wiggumworld.com, adldap@richardhyland.com
10 *   http://adldap.sourceforge.net/
11 *
12 * Copyright (c) 2006-2012 Scott Barnett, Richard Hyland
13 *
14 * We'd appreciate any improvements or additions to be submitted back
15 * to benefit the entire community :)
16 *
17 * This library is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU Lesser General Public
19 * License as published by the Free Software Foundation; either
20 * version 2.1 of the License.
21 *
22 * This library is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25 * Lesser General Public License for more details.
26 *
27 * @category ToolsAndUtilities
28 * @package adLDAP
29 * @subpackage Exchange
30 * @author Scott Barnett, Richard Hyland
31 * @copyright (c) 2006-2012 Scott Barnett, Richard Hyland
32 * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html LGPLv2.1
33 * @revision $Revision: 97 $
34 * @version 4.0.4
35 * @link http://adldap.sourceforge.net/
36 */
37require_once(dirname(__FILE__) . '/../adLDAP.php');
38
39/**
40* MICROSOFT EXCHANGE FUNCTIONS
41*/
42class adLDAPExchange {
43    /**
44    * The current adLDAP connection via dependency injection
45    *
46    * @var adLDAP
47    */
48    protected $adldap;
49
50    public function __construct(adLDAP $adldap) {
51        $this->adldap = $adldap;
52    }
53
54    /**
55    * Create an Exchange account
56    *
57    * @param string $username The username of the user to add the Exchange account to
58    * @param array $storageGroup The mailbox, Exchange Storage Group, for the user account, this must be a full CN
59    *                            If the storage group has a different base_dn to the adLDAP configuration, set it using $base_dn
60    * @param string $emailAddress The primary email address to add to this user
61    * @param string $mailNickname The mail nick name.  If mail nickname is blank, the username will be used
62    * @param bool $mdbUseDefaults Indicates whether the store should use the default quota, rather than the per-mailbox quota.
63    * @param string $baseDn Specify an alternative base_dn for the Exchange storage group
64    * @param bool $isGUID Is the username passed a GUID or a samAccountName
65    * @return bool
66    */
67    public function createMailbox($username, $storageGroup, $emailAddress, $mailNickname=NULL, $useDefaults=TRUE, $baseDn=NULL, $isGUID=false)
68    {
69        if ($username === NULL){ return "Missing compulsory field [username]"; }
70        if ($storageGroup === NULL) { return "Missing compulsory array [storagegroup]"; }
71        if (!is_array($storageGroup)) { return "[storagegroup] must be an array"; }
72        if ($emailAddress === NULL) { return "Missing compulsory field [emailAddress]"; }
73
74        if ($baseDn === NULL) {
75            $baseDn = $this->adldap->getBaseDn();
76        }
77
78        $container = "CN=" . implode(",CN=", $storageGroup);
79
80        if ($mailNickname === NULL) {
81            $mailNickname = $username;
82        }
83        $mdbUseDefaults = $this->adldap->utilities()->boolToString($useDefaults);
84
85        $attributes = array(
86            'exchange_homemdb'=>$container.",".$baseDn,
87            'exchange_proxyaddress'=>'SMTP:' . $emailAddress,
88            'exchange_mailnickname'=>$mailNickname,
89            'exchange_usedefaults'=>$mdbUseDefaults
90        );
91        $result = $this->adldap->user()->modify($username, $attributes, $isGUID);
92        if ($result == false) {
93            return false;
94        }
95        return true;
96    }
97
98    /**
99    * Add an X400 address to Exchange
100    * See http://tools.ietf.org/html/rfc1685 for more information.
101    * An X400 Address looks similar to this X400:c=US;a= ;p=Domain;o=Organization;s=Doe;g=John;
102    *
103    * @param string $username The username of the user to add the X400 to to
104    * @param string $country Country
105    * @param string $admd Administration Management Domain
106    * @param string $pdmd Private Management Domain (often your AD domain)
107    * @param string $org Organization
108    * @param string $surname Surname
109    * @param string $givenName Given name
110    * @param bool $isGUID Is the username passed a GUID or a samAccountName
111    * @return bool
112    */
113    public function addX400($username, $country, $admd, $pdmd, $org, $surname, $givenName, $isGUID=false)
114    {
115        if ($username === NULL){ return "Missing compulsory field [username]"; }
116
117        $proxyValue = 'X400:';
118
119        // Find the dn of the user
120        $user = $this->adldap->user()->info($username, array("cn","proxyaddresses"), $isGUID);
121        if ($user[0]["dn"] === NULL) { return false; }
122        $userDn = $user[0]["dn"];
123
124        // We do not have to demote an email address from the default so we can just add the new proxy address
125        $attributes['exchange_proxyaddress'] = $proxyValue . 'c=' . $country . ';a=' . $admd . ';p=' . $pdmd . ';o=' . $org . ';s=' . $surname . ';g=' . $givenName . ';';
126
127        // Translate the update to the LDAP schema
128        $add = $this->adldap->adldap_schema($attributes);
129
130        if (!$add) { return false; }
131
132        // Do the update
133        // Take out the @ to see any errors, usually this error might occur because the address already
134        // exists in the list of proxyAddresses
135        $result = @ldap_mod_add($this->adldap->getLdapConnection(), $userDn, $add);
136        if ($result == false) {
137            return false;
138        }
139
140        return true;
141    }
142
143    /**
144    * Add an address to Exchange
145    *
146    * @param string $username The username of the user to add the Exchange account to
147    * @param string $emailAddress The email address to add to this user
148    * @param bool $default Make this email address the default address, this is a bit more intensive as we have to demote any existing default addresses
149    * @param bool $isGUID Is the username passed a GUID or a samAccountName
150    * @return bool
151    */
152    public function addAddress($username, $emailAddress, $default = FALSE, $isGUID = false)
153    {
154        if ($username === NULL) { return "Missing compulsory field [username]"; }
155        if ($emailAddress === NULL) { return "Missing compulsory fields [emailAddress]"; }
156
157        $proxyValue = 'smtp:';
158        if ($default === true) {
159            $proxyValue = 'SMTP:';
160        }
161
162        // Find the dn of the user
163        $user = $this->adldap->user()->info($username, array("cn","proxyaddresses"), $isGUID);
164        if ($user[0]["dn"] === NULL){ return false; }
165        $userDn = $user[0]["dn"];
166
167        // We need to scan existing proxy addresses and demote the default one
168        if (is_array($user[0]["proxyaddresses"]) && $default === true) {
169            $modAddresses = array();
170            for ($i=0;$i<sizeof($user[0]['proxyaddresses']);$i++) {
171                if (strstr($user[0]['proxyaddresses'][$i], 'SMTP:') !== false) {
172                    $user[0]['proxyaddresses'][$i] = str_replace('SMTP:', 'smtp:', $user[0]['proxyaddresses'][$i]);
173                }
174                if ($user[0]['proxyaddresses'][$i] != '') {
175                    $modAddresses['proxyAddresses'][$i] = $user[0]['proxyaddresses'][$i];
176                }
177            }
178            $modAddresses['proxyAddresses'][(sizeof($user[0]['proxyaddresses'])-1)] = 'SMTP:' . $emailAddress;
179
180            $result = @ldap_mod_replace($this->adldap->getLdapConnection(), $userDn, $modAddresses);
181            if ($result == false) {
182                return false;
183            }
184
185            return true;
186        }
187        else {
188            // We do not have to demote an email address from the default so we can just add the new proxy address
189            $attributes['exchange_proxyaddress'] = $proxyValue . $emailAddress;
190
191            // Translate the update to the LDAP schema
192            $add = $this->adldap->adldap_schema($attributes);
193
194            if (!$add) {
195                return false;
196            }
197
198            // Do the update
199            // Take out the @ to see any errors, usually this error might occur because the address already
200            // exists in the list of proxyAddresses
201            $result = @ldap_mod_add($this->adldap->getLdapConnection(), $userDn,$add);
202            if ($result == false) {
203                return false;
204            }
205
206            return true;
207        }
208    }
209
210    /**
211    * Remove an address to Exchange
212    * If you remove a default address the account will no longer have a default,
213    * we recommend changing the default address first
214    *
215    * @param string $username The username of the user to add the Exchange account to
216    * @param string $emailAddress The email address to add to this user
217    * @param bool $isGUID Is the username passed a GUID or a samAccountName
218    * @return bool
219    */
220    public function deleteAddress($username, $emailAddress, $isGUID=false)
221    {
222        if ($username === NULL) { return "Missing compulsory field [username]"; }
223        if ($emailAddress === NULL) { return "Missing compulsory fields [emailAddress]"; }
224
225        // Find the dn of the user
226        $user = $this->adldap->user()->info($username, array("cn","proxyaddresses"), $isGUID);
227        if ($user[0]["dn"] === NULL) { return false; }
228        $userDn = $user[0]["dn"];
229
230        if (is_array($user[0]["proxyaddresses"])) {
231            $mod = array();
232            for ($i=0;$i<sizeof($user[0]['proxyaddresses']);$i++) {
233                if (strstr($user[0]['proxyaddresses'][$i], 'SMTP:') !== false && $user[0]['proxyaddresses'][$i] == 'SMTP:' . $emailAddress) {
234                    $mod['proxyAddresses'][0] = 'SMTP:' . $emailAddress;
235                }
236                elseif (strstr($user[0]['proxyaddresses'][$i], 'smtp:') !== false && $user[0]['proxyaddresses'][$i] == 'smtp:' . $emailAddress) {
237                    $mod['proxyAddresses'][0] = 'smtp:' . $emailAddress;
238                }
239            }
240
241            $result = @ldap_mod_del($this->adldap->getLdapConnection(), $userDn,$mod);
242            if ($result == false) {
243                return false;
244            }
245
246            return true;
247        }
248        else {
249            return false;
250        }
251    }
252    /**
253    * Change the default address
254    *
255    * @param string $username The username of the user to add the Exchange account to
256    * @param string $emailAddress The email address to make default
257    * @param bool $isGUID Is the username passed a GUID or a samAccountName
258    * @return bool
259    */
260    public function primaryAddress($username, $emailAddress, $isGUID = false)
261    {
262        if ($username === NULL) { return "Missing compulsory field [username]"; }
263        if ($emailAddress === NULL) { return "Missing compulsory fields [emailAddress]"; }
264
265        // Find the dn of the user
266        $user = $this->adldap->user()->info($username, array("cn","proxyaddresses"), $isGUID);
267        if ($user[0]["dn"] === NULL){ return false; }
268        $userDn = $user[0]["dn"];
269
270        if (is_array($user[0]["proxyaddresses"])) {
271            $modAddresses = array();
272            for ($i=0;$i<sizeof($user[0]['proxyaddresses']);$i++) {
273                if (strstr($user[0]['proxyaddresses'][$i], 'SMTP:') !== false) {
274                    $user[0]['proxyaddresses'][$i] = str_replace('SMTP:', 'smtp:', $user[0]['proxyaddresses'][$i]);
275                }
276                if ($user[0]['proxyaddresses'][$i] == 'smtp:' . $emailAddress) {
277                    $user[0]['proxyaddresses'][$i] = str_replace('smtp:', 'SMTP:', $user[0]['proxyaddresses'][$i]);
278                }
279                if ($user[0]['proxyaddresses'][$i] != '') {
280                    $modAddresses['proxyAddresses'][$i] = $user[0]['proxyaddresses'][$i];
281                }
282            }
283
284            $result = @ldap_mod_replace($this->adldap->getLdapConnection(), $userDn, $modAddresses);
285            if ($result == false) {
286                return false;
287            }
288
289            return true;
290        }
291
292    }
293
294    /**
295    * Mail enable a contact
296    * Allows email to be sent to them through Exchange
297    *
298    * @param string $distinguishedName The contact to mail enable
299    * @param string $emailAddress The email address to allow emails to be sent through
300    * @param string $mailNickname The mailnickname for the contact in Exchange.  If NULL this will be set to the display name
301    * @return bool
302    */
303    public function contactMailEnable($distinguishedName, $emailAddress, $mailNickname = NULL)
304    {
305        if ($distinguishedName === NULL) { return "Missing compulsory field [distinguishedName]"; }
306        if ($emailAddress === NULL) { return "Missing compulsory field [emailAddress]"; }
307
308        if ($mailNickname !== NULL) {
309            // Find the dn of the user
310            $user = $this->adldap->contact()->info($distinguishedName, array("cn","displayname"));
311            if ($user[0]["displayname"] === NULL) { return false; }
312            $mailNickname = $user[0]['displayname'][0];
313        }
314
315        $attributes = array("email"=>$emailAddress,"contact_email"=>"SMTP:" . $emailAddress,"exchange_proxyaddress"=>"SMTP:" . $emailAddress,"exchange_mailnickname" => $mailNickname);
316
317        // Translate the update to the LDAP schema
318        $mod = $this->adldap->adldap_schema($attributes);
319
320        // Check to see if this is an enabled status update
321        if (!$mod) { return false; }
322
323        // Do the update
324        $result = ldap_modify($this->adldap->getLdapConnection(), $distinguishedName, $mod);
325        if ($result == false) { return false; }
326
327        return true;
328    }
329
330    /**
331    * Returns a list of Exchange Servers in the ConfigurationNamingContext of the domain
332    *
333    * @param array $attributes An array of the AD attributes you wish to return
334    * @return array
335    */
336    public function servers($attributes = array('cn','distinguishedname','serialnumber'))
337    {
338        if (!$this->adldap->getLdapBind()){ return false; }
339
340        $configurationNamingContext = $this->adldap->getRootDse(array('configurationnamingcontext'));
341        $sr = @ldap_search($this->adldap->getLdapConnection(), $configurationNamingContext[0]['configurationnamingcontext'][0],'(&(objectCategory=msExchExchangeServer))', $attributes);
342        $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
343        return $entries;
344    }
345
346    /**
347    * Returns a list of Storage Groups in Exchange for a given mail server
348    *
349    * @param string $exchangeServer The full DN of an Exchange server.  You can use exchange_servers() to find the DN for your server
350    * @param array $attributes An array of the AD attributes you wish to return
351    * @param bool $recursive If enabled this will automatically query the databases within a storage group
352    * @return array
353    */
354    public function storageGroups($exchangeServer, $attributes = array('cn','distinguishedname'), $recursive = NULL)
355    {
356        if (!$this->adldap->getLdapBind()){ return false; }
357        if ($exchangeServer === NULL) { return "Missing compulsory field [exchangeServer]"; }
358        if ($recursive === NULL) { $recursive = $this->adldap->getRecursiveGroups(); }
359
360        $filter = '(&(objectCategory=msExchStorageGroup))';
361        $sr = @ldap_search($this->adldap->getLdapConnection(), $exchangeServer, $filter, $attributes);
362        $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
363
364        if ($recursive === true) {
365            for ($i=0; $i<$entries['count']; $i++) {
366                $entries[$i]['msexchprivatemdb'] = $this->storageDatabases($entries[$i]['distinguishedname'][0]);
367            }
368        }
369
370        return $entries;
371    }
372
373    /**
374    * Returns a list of Databases within any given storage group in Exchange for a given mail server
375    *
376    * @param string $storageGroup The full DN of an Storage Group.  You can use exchange_storage_groups() to find the DN
377    * @param array $attributes An array of the AD attributes you wish to return
378    * @return array
379    */
380    public function storageDatabases($storageGroup, $attributes = array('cn','distinguishedname','displayname')) {
381        if (!$this->adldap->getLdapBind()){ return false; }
382        if ($storageGroup === NULL) { return "Missing compulsory field [storageGroup]"; }
383
384        $filter = '(&(objectCategory=msExchPrivateMDB))';
385        $sr = @ldap_search($this->adldap->getLdapConnection(), $storageGroup, $filter, $attributes);
386        $entries = @ldap_get_entries($this->adldap->getLdapConnection(), $sr);
387        return $entries;
388    }
389}
390?>