# Win32::Exchange::Mailbox
# Freely Distribute the code without modification.
#
# Creates and Modifies Exchange 5.5 and 2K Mailboxes
#
# This is the culmination of 3 years of work in building Exchange Mailboxes, but now as a module.
# It uses Win32::OLE exclusively (and technically is just a wrapper for the underlying OLE calls).
#
# This build is tested and works with ActivePerl build 633 (and Win32::OLE .1502)
# There is not currently a package that is tested on older (non-multi-threading versions of
# ActivePerl)... My guess is that it may work except for the SetPerms and SetOwner subs but,
# remember.. That's a guess.
#
# Sorry... :(
#
package Win32::Exchange::Mailbox;
use strict;
use vars qw ($VERSION $Version $DEBUG);
use Win32::OLE qw (in);
use Win32::OLE::Variant;
Win32::OLE->Initialize(Win32::OLE::COINIT_OLEINITIALIZE);
use Win32::Exchange::Const;
Win32::OLE->Option('_Unique' => 1);
#@ISA = qw(Win32::OLE);
my $Version;
my $VERSION = $Version = "0.046";
my $DEBUG = 1;
sub new {
my $server;
my $ver;
if (scalar(@_) == 1) {
$server = $_[0];
} elsif (scalar(@_) == 2 && $_[0] eq "Win32::Exchange::Mailbox") {
$server = $_[1];
} else {
_ReportArgError("new",scalar(@_));
return 0;
}
my $class = "Win32::Exchange::Mailbox";
my $provider = {};
my %version;
if (!Win32::Exchange::GetVersion($server,\%version)) {
_DebugComment("Please make sure you are passing new a servername now.. ver nums are no longer valid",0);
return undef;
}
bless $provider,$class;
$provider->{server} = $server;
$provider->{version} = $version{'ver'};
$provider->{ad_provider} = Win32::OLE->new('ADsNamespaces');
if (Win32::OLE->LastError() != 0) {
_DebugComment("Failed creating ADsNamespaces object\n",1);
return undef;
}
if ($provider->{version} eq "5.5") {
if (!$provider->GetLDAPPath()) {
_DebugComment("Failed calling GetLDAPPath for server org and ou determination\n",1);
return undef;
}
} else {
$provider->{cdo_provider} = Win32::OLE->new('CDO.Person');
if (Win32::OLE->LastError() != 0) {
_DebugComment("Failed creating CDO.Person object\n",1);
return undef;
}
my %data;
if (!Win32::Exchange::_E2kVersionInfo($server,\%data)) {
return undef;
} else {
$provider->{dc} = $data{dc};
}
}
return $provider;
}
sub DESTROY {
my $object = shift;
bless $object,"Win32::OLE";
#might want to look at putting a FreeUnusedLibraries here
return undef;
}
sub GetLDAPPath {
#changing it so you only send GetLDAPPath as an OO function
#only send the provider
my $provider;
if (scalar(@_) == 1) {
$provider = \%{$_[0]} ;
} else {
_ReportArgError("GetLDAPPath",scalar(@_));
return 0;
}
my $result;
if (Win32::Exchange::_AdodbExtendedSearch($provider->{server},"LDAP://$provider->{server}","(&(objectClass=Computer)(rdn=$provider->{server}))","rdn,distinguishedName",$result)) {
_DebugComment("result = $result\n",2);
if ($result =~ /cn=.*,cn=Servers,cn=Configuration,ou=(.*),o=(.*)/) {
$provider->{ou}=$1;
$provider->{org}=$2;
_DebugComment("ou=$provider->{ou}\no=$provider->{org}\n",2);
$_[0] = $provider;
return 1;
} else {
_DebugComment("result = $result\n",2);
_DebugComment("result from ADODB search failed to produce an acceptable match\n",1);
return 0;
}
} else {
_DebugComment("ADODB search failed\n",1);
return 0;
}
}
sub CreateMailbox {
my $mbx;
my $provider;
$provider = \%{$_[0]} ;
if ($provider->{version} =~ /^6\./) {
if ($mbx = _E2KCreateMailbox(@_)) {
return $mbx;
}
} else {
if ($mbx = _E55CreateMailbox(@_)) {
return $mbx;
}
}
return 0;
}
sub _E55CreateMailbox {
#removed $_[1] -- information_store_server -- unneeded
#removed $_[2] -- org -- unneeded (unneeded)
#removed $_[3] -- ou -- unneeded (unneeded)
my $provider;
my $information_store_server;
my $mailbox_alias_name;
my $org;
my $ou;
my $error_num;
my $error_name;
my $container = "";
my $recipients_path;
if (scalar(@_) > 2) {
$provider = \%{$_[0]} ;
$information_store_server = $provider->{server};
$org = $provider->{org};
$ou = $provider->{ou};
$mailbox_alias_name = $_[1];
if (scalar(@_) == 2) {
#placeholder
} elsif (scalar(@_) == 3) {
$container = $_[2];
} else {
_ReportArgError("CreateMailbox [5.5] (".scalar(@_));
return 0;
}
} else {
_ReportArgError("CreateMailbox [5.5] (".scalar(@_));
return 0;
}
if ($container ne "") {
$recipients_path = "LDAP://$information_store_server/$container";
} else {
$recipients_path = "LDAP://$information_store_server/cn=Recipients,ou=$ou,o=$org";
}
_DebugComment("path to create mailbox in: $recipients_path\n",3);
my $ldap_provider = $provider->{ad_provider};
my $original_ole_warn_value = $Win32::OLE::Warn;
$Win32::OLE::Warn = 0; #Turn STDERR warnings off because we probably are going to get an error (0x80072030)
my $Recipients = $ldap_provider->GetObject("",$recipients_path);
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Failed opening recipients path ($recipients_path)\nError: $error_num ($error_name)\n",1);
return 0;
}
$Recipients->GetObject("organizationalPerson", "cn=$mailbox_alias_name");
if (!ErrorCheck("0x80072030",$error_num,$error_name)) {
if ($error_num eq "0x00000000") {
_DebugComment("$error_num - Mailbox already exists on $information_store_server\n",1);
$Win32::OLE::Warn=$original_ole_warn_value;
return 0;
} else {
_DebugComment("Unable to lookup object $mailbox_alias_name on $information_store_server ($error_num)\n",1);
$Win32::OLE::Warn=$original_ole_warn_value;
return 0;
}
}
_DebugComment(" Box Does Not Exist (This is good)\n",3);
my $new_mailbox = $Recipients->Create("organizationalPerson", "cn=$mailbox_alias_name");
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error creating Mailbox -> $error_num ($error_name)\n",1);
$Win32::OLE::Warn=$original_ole_warn_value;
return 0;
}
my %attrs;
$attrs{'uid'}=$mailbox_alias_name;
$attrs{'mailPreferenceOption'}="0";
$attrs{'MAPI-Recipient'}='TRUE';
$attrs{'MDB-Use-Defaults'}="TRUE"; #By default set the box to adhere to Exchange Default settings
$attrs{'givenName'}="Exchange"; #Temporary Name (it doesn't like returning from the subroutine without setting something)
$attrs{'sn'}="Mailbox"; #Temporary Name
$attrs{'cn'}="Exchange $mailbox_alias_name Mailbox";#Temporary Name
$attrs{'Home-MTA'}="cn=Microsoft MTA,cn=$information_store_server,cn=Servers,cn=Configuration,ou=$ou,o=$org";
$attrs{'Home-MDB'}="cn=Microsoft Private MDB,cn=$information_store_server,cn=Servers,cn=Configuration,ou=$ou,o=$org";
foreach my $attr (keys %attrs) {
$new_mailbox->Put($attr => $attrs{$attr});
}
$new_mailbox->SetInfo;
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error setting attribute on mailbox -> $error_num ($error_name)\n",1);
$Win32::OLE::Warn=$original_ole_warn_value;
return 0;
}
_DebugComment(" -Mailbox created...\n",3);
$Win32::OLE::Warn=$original_ole_warn_value;
$provider->{ad_provider} = $new_mailbox;
return $provider;
}
sub _E2KCreateMailbox {
#removed info_store_server as parameter
#removed dc as a parameter
my $error_num;
my $error_name;
my $provider;
my $info_store_server;
my $dc;
my $nt_dc;
my $mailbox_alias_name;
my $mail_domain;
my $storage_group;
my $mb_store;
my $mailbox_ldap_path;
if (scalar(@_) > 1) {
$provider = \%{$_[0]} ;
$info_store_server = $provider->{server};
$nt_dc = $provider->{dc};
$mailbox_alias_name = $_[1];
if (scalar(@_) == 2) {
#placeholder..
} elsif (scalar(@_) == 3) {
$mailbox_ldap_path = $_[2]
} elsif (scalar(@_) == 4) {
$storage_group = $_[2];
$mb_store = $_[3];
} else {
_ReportArgError("CreateMailbox [E2K] (".scalar(@_));
return 0;
}
} else {
_ReportArgError("CreateMailbox [E2K] (".scalar(@_));
return 0;
}
Win32::Exchange::_StripBackslashes($nt_dc,$dc); #shouldn't need this any more but we'll leave it in.
my $user_dist_name;
if (!Win32::Exchange::_AdodbExtendedSearch($mailbox_alias_name,"LDAP://$dc","(samAccountName=$mailbox_alias_name)","samAccountName,distinguishedName",$user_dist_name)) {
_DebugComment("Error querying distinguished name for user in CreateMailbox (E2K)\n",1);
return 0;
}
_DebugComment("user_dist_name = $user_dist_name\n",3);
my $cdo_provider = $provider->{cdo_provider};
my $user_account = $cdo_provider->DataSource->Open("LDAP://$dc/$user_dist_name",undef,adModeReadWrite);
# http://support.microsoft.com/default.aspx?scid=kb;EN-US;q321039
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Failed opening NT user account for new mailbox creation on $dc ($error_num)\n",1);
return 0;
}
my $info_store = $cdo_provider->GetInterface("IMailboxStore");
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Failed opening mailbox interface on $dc ($error_num)\n",1);
if ($error_num eq "0x80004002") {
_DebugComment("Error: No such interface supported.\n Note: Make sure you have the Exchange System Manager loaded on this system\n",2);
}
return 0;
}
if ($mailbox_ldap_path eq "") {
if (!Win32::Exchange::LocateMailboxStore($info_store_server,$storage_group,$mb_store,$mailbox_ldap_path)) {
return 0;
}
}
_DebugComment("$mailbox_ldap_path\n",3);
$info_store->CreateMailbox($mailbox_ldap_path);
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Failed creating mailbox for $mailbox_alias_name ($error_num) $error_name\n",1);
return 0;
}
$cdo_provider->DataSource->Save();
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Failed saving mailbox for $mailbox_alias_name ($error_num) $error_name\n",1);
return 0;
}
$provider->{cdo_provider} = $cdo_provider;
return $provider;
}
sub DeleteMailbox {
my $error_num;
my $error_name;
my $provider;
$provider = \%{$_[0]} ;
my $rtn = 0;
if ($provider->{version} =~ /^6\./) {
if (_E2KDeleteMailbox(@_)) {
$rtn = 1;
}
} else {
if (_E55DeleteMailbox(@_)) {
$rtn = 1;
}
}
return $rtn;
}
sub _E2KDeleteMailbox {
if (scalar(@_) != 1) {
_ReportArgError("DeleteMailbox [E2K]",scalar(@_));
return 0;
}
my $provider;
$provider = \%{$_[0]} ;
my $cdo_provider = $provider->{cdo_provider};
my $error_num;
my $error_name;
my $interface = $cdo_provider->GetInterface("IMailboxStore");
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Error getting IMailboxStore interface for user mailbox deletion [E2K]\n",1);
return 0;
}
$interface->DeleteMailbox();
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Error deleting user mailbox (DeleteMailbox) [E2K]\n",1);
return 0;
}
$cdo_provider->Datasource->Save();
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Error deleting user mailbox (Save) [E2K]\n",1);
return 0;
}
_DebugComment("Mailbox deleted successfully",1);
return 1;
}
sub _E55DeleteMailbox {
#removed info_store_server -- not needed
my $provider;
my $information_store_server;
my $mailbox_alias_name;
my $error_num;
my $error_name;
my $find_mb;
if (scalar(@_) == 2) {
$provider = \%{$_[0]} ;
$information_store_server = $provider->{server};
$mailbox_alias_name = $_[1];
} else {
_ReportArgError("DeleteMailbox [5.5] ",scalar(@_));
return 0;
}
my $recipients_path;
my $exch_mb_dn;
my $path;
#my $ldap_provider = $provider->{ad_provider};#changed on 20040401 for delete issues (Protocol error)
#need fresh object
my $ldap_provider = Win32::OLE->new('ADsNamespaces');
my $Recipients = $provider->GetMailboxContainer($mailbox_alias_name);
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Failed opening recipients path on $information_store_server\n",1);
return 0;
}
my $original_ole_warn_value = $Win32::OLE::Warn;
$Win32::OLE::Warn = 0; #Turn STDERR warnings off because we probably are going to get an error (0x80072030) if we are creating a new box.
$Recipients->Delete("organizationalPerson", "cn=$mailbox_alias_name");
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Unable to Delete the mailbox object where the cn == $mailbox_alias_name on $information_store_server ($error_num)\n",1);
$Win32::OLE::Warn=$original_ole_warn_value;
return 0;
}
$Win32::OLE::Warn=$original_ole_warn_value;
return 1;
}
sub GetMailboxContainer {
my $error_num;
my $error_name;
my $mbx_container;
my $provider;
$provider = \%{$_[0]} ;
if ($provider->{version} =~ /^6\./) {
Win32::Exchange::_DebugComment("Not a valid Function E2K (GetMailboxContainer)\n",1);
return 0;
} else {
if ($mbx_container = $provider->_E55GetMailboxContainer($_[1])) {
return $mbx_container;
}
}
return 0;
}
sub _E55GetMailboxContainer {
#added this back in.. got deleted somewhere.
#removed info_store_server -- not needed
my $provider;
my $information_store_server;
my $mailbox_alias_name;
my $error_num;
my $error_name;
if (scalar(@_) > 2) {
$provider = \%{$_[0]} ;
$information_store_server = $provider->{server};
$mailbox_alias_name = $_[2];
} else {
_ReportArgError("GetMailboxContainer [5.5] ",scalar(@_));
return 0;
}
my $recipients_path;
my $exch_mb_dn;
my $path;
if (Win32::Exchange::_AdodbExtendedSearch($mailbox_alias_name,"LDAP://$information_store_server","(&(objectClass=organizationalPerson)(cn=$mailbox_alias_name))","cn,distinguishedName",1,$exch_mb_dn)) {
Win32::Exchange::_DebugComment("Exchange recipients path for mailbox found on the server\n".
" $exch_mb_dn\n",1);
$exch_mb_dn =~ /cn=$mailbox_alias_name,(.*)/i;
$path = $1;
$recipients_path = "LDAP://$information_store_server/$path";
} else {
Win32::Exchange::_DebugComment("Error locating Exchange Mailbox on the server.\n",1);
return 0;
}
#my $ldap_provider = $provider->{ad_provider};#changed on 20040401 for delete issues (Protocol error)
#need fresh object
my $ldap_provider = Win32::OLE->new('ADsNamespaces');
my $Recipients = $ldap_provider->GetObject("",$recipients_path);
if (!Win32::Exchange::ErrorCheck("0x00000000",$error_num,$error_name)) {
Win32::Exchange::_DebugComment("Failed opening recipients path on $information_store_server\n",1);
return 0;
}
return $Recipients;
}
sub GetMailbox {
my $error_num;
my $error_name;
my $mbx;
my $provider;
$provider = \%{$_[0]} ;
if ($provider->{version} =~ /^6\./) {
if ($mbx = _E2KGetMailbox(@_)) {
return $mbx;
}
} else {
if ($mbx = _E55GetMailbox(@_)) {
return $mbx;
}
}
return 0;
}
sub _E55GetMailbox {
#removed info_store_server - not needed
#removed org - not needed
#removed ou - not needed
#removed find_mb - not needed
my $provider;
my $information_store_server;
my $mailbox_alias_name;
my $org;
my $ou;
my $error_num;
my $error_name;
my $find_mb;
if (scalar(@_) > 1) {
$provider = \%{$_[0]} ;
$information_store_server = $provider->{server};
$mailbox_alias_name = $_[1];
if (scalar(@_) == 2) {
$ou = $provider->{ou};
$org = $provider->{org};
} else {
_ReportArgError("GetMailbox [5.5]",scalar(@_));
return 0;
}
} else {
_ReportArgError("GetMailbox [5.5] ",scalar(@_));
return 0;
}
my $recipients_path;
my $exch_mb_dn;
if (Win32::Exchange::_AdodbExtendedSearch($mailbox_alias_name,"LDAP://$information_store_server","(&(objectClass=organizationalPerson)(rdn=$mailbox_alias_name))","rdn,distinguishedName",1,$exch_mb_dn)) {
$recipients_path = "LDAP://$information_store_server/$exch_mb_dn";
} else {
_DebugComment("Error locating Exchange Mailbox on the server.\n",1);
return 0;
}
my $ldap_provider = $provider->{ad_provider};
my $original_ole_warn_value = $Win32::OLE::Warn;
$Win32::OLE::Warn = 0; #Turn STDERR warnings off because we probably are going to get an error (0x80072030)
my $mailbox = $ldap_provider->GetObject("",$recipients_path);
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Unable to Get the mailbox object where the rdn == $mailbox_alias_name on $information_store_server ($error_num)\n",1);
$Win32::OLE::Warn=$original_ole_warn_value;
return 0;
}
$Win32::OLE::Warn=$original_ole_warn_value;
$provider->{ad_provider} = $mailbox;
return $provider;
}
sub _E2KGetMailbox {
#removed nt_dc -- not needed
my $error_num;
my $error_name;
my $provider;
my $mailbox_alias_name;
my $nt_dc;
my $dc;
if (scalar(@_) == 2) {
$provider = \%{$_[0]} ;
$nt_dc = $provider->{dc};
$mailbox_alias_name = $_[1];
} else {
_ReportArgError("GetMailbox [E2K]",scalar(@_));
return 0;
}
Win32::Exchange::_StripBackslashes ($nt_dc,$dc); #probably not needed but leaving it in anyway
my $cdo_provider = $provider->{cdo_provider};
my $user_dist_name;
if (!Win32::Exchange::_AdodbExtendedSearch($mailbox_alias_name,"LDAP://$dc","(samAccountName=$mailbox_alias_name)","samAccountName,distinguishedName",$user_dist_name)) {
_DebugComment("Error querying distinguished name for user in GetMailbox (E2K)\n",1);
return 0;
}
$cdo_provider->DataSource->Open("LDAP://$dc/$user_dist_name",undef,adModeReadWrite);
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Failed opening AD user account for mailbox retrieval on $dc ($error_num)\n",1);
return 0;
}
my $user_obj_path = $cdo_provider->DataSource->{SourceURL};
my $user_obj = Win32::OLE->GetObject($user_obj_path);
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Failed opening SourceURL for GetMailbox ($error_num)\n",1);
return 0;
}
#this next part may be prone to issues if you are a native-mode Exchange install.
if (!$provider->_E2KIsMailAware($mailbox_alias_name)) {
_DebugComment("Error performing GetMailbox: user is not MAPI aware ($error_num)\n",2);
return 0;
} else {
$cdo_provider->DataSource->Save();
$provider->{cdo_provider} = $cdo_provider;
return $provider;
}
}
sub GetUserObject {
#removed nt_dc -- not needed
#Different from GetMailbox in that it gets the user object without a datasource->open.
my $error_num;
my $error_name;
my $provider;
my $mailbox_alias_name;
my $nt_dc;
my $dc;
if (scalar(@_) == 3) {
$provider = \%{$_[0]} ;
$nt_dc = $provider->{dc};
$mailbox_alias_name = $_[1];
} else {
_ReportArgError("GetMailbox [E2K]",scalar(@_));
return 0;
}
Win32::Exchange::_StripBackslashes ($nt_dc,$dc); #probably not needed but leaving it in anyway
my $user_dist_name;
if (!Win32::Exchange::_AdodbExtendedSearch($mailbox_alias_name,"LDAP://$dc","(samAccountName=$mailbox_alias_name)","samAccountName,distinguishedName",$user_dist_name)) {
_DebugComment("Error querying distinguished name for user in GetMailbox (E2K)\n",1);
return 0;
}
my $ldap_provider = $provider->{ad_provider};
my $user_obj = $ldap_provider->GetObject("","LDAP://$dc/$user_dist_name");
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Failed opening distinguishedname for GetUserObject ($error_num)\n",1);
return 0;
}
$provider->{ad_provider} = $user_obj;
return $provider;
}
sub _E2KIsMailAware {
#added provider
#removed nt_dc
my $provider;
my $mailbox_alias_name;
my $nt_dc;
my $dc;
if (scalar(@_) == 2) {
$provider = \%{$_[0]} ;
$nt_dc = $provider->{dc};
$mailbox_alias_name = $_[1];
} else {
_ReportArgError("IsMailAware [E2K]",scalar(@_));
return 0;
}
Win32::Exchange::_StripBackslashes ($nt_dc,$dc); #probably not needed but leaving it in anyway
my $user_dist_name;
if (Win32::Exchange::_AdodbExtendedSearch($mailbox_alias_name,"LDAP://$dc","(&(samAccountName=$mailbox_alias_name)(showinaddressbook=*))","samAccountName,distinguishedName",$user_dist_name)) {
return 1;
} else {
_DebugComment("This is not a Mail aware user account -- IsMailAware (E2K)\n",3);
return 0;
}
}
sub _E2KIsMailboxEnabled {
#added provider
#removed nt_dc
my $provider;
my $mailbox_alias_name;
my $nt_dc;
my $dc;
if (scalar(@_) == 2) {
$provider = \%{$_[0]} ;
$nt_dc = $provider->{dc};
$mailbox_alias_name = $_[1];
} else {
_ReportArgError("IsMailboxEnabled [E2K]",scalar(@_));
return 0;
}
Win32::Exchange::_StripBackslashes ($nt_dc,$dc); #probably not needed but leaving it in anyway
print $mailbox_alias_name."\n";
my $user_dist_name;
if (Win32::Exchange::_AdodbExtendedSearch($mailbox_alias_name,"LDAP://$dc","(&(samAccountName=$mailbox_alias_name)(showinaddressbook=*)(msExchHomeServerName=*))","samAccountName,distinguishedName",$user_dist_name)) {
return 1;
} else {
_DebugComment("This is not a MailboxEnabled user account -- IsMailboxEnabled (E2K)\n",3);
return 0;
}
}
sub _E2KIsMailEnabled {
#added provider
#removed nt_dc
my $provider;
my $mailbox_alias_name;
my $nt_dc;
my $dc;
if (scalar(@_) == 2) {
$provider = \%{$_[0]} ;
$nt_dc = $provider->{dc};
$mailbox_alias_name = $_[1];
} else {
_ReportArgError("IsMailEnabled [E2K]",scalar(@_));
return 0;
}
Win32::Exchange::_StripBackslashes ($nt_dc,$dc); #probably not needed but leaving it in anyway
my $user_dist_name;
if (Win32::Exchange::_AdodbExtendedSearch($mailbox_alias_name,"LDAP://$dc","(&(samAccountName=$mailbox_alias_name)(showinaddressbook=*))","samAccountName,distinguishedName",$user_dist_name)) {
if (Win32::Exchange::_AdodbExtendedSearch($mailbox_alias_name,"LDAP://$dc","(&(samAccountName=$mailbox_alias_name)(msExchHomeServerName=*))","samAccountName,distinguishedName",$user_dist_name)) {
return 0; #mailboxenabled.
} else {
return 1; #mailenabled (no home server)
}
} else {
_DebugComment("This is not a MailEnabled user account -- IsMailEnabled (E2K)\n",3);
return 0; #not even a valid addressable user
}
}
sub GetDLMembers {
my $error_num;
my $error_name;
my $provider;
$provider = \%{$_[0]} ;
my $rtn;
if ($provider->{version} =~ /^6\./) {
if ($rtn = _E2KGetDLMembers(@_)) {
return $rtn;
}
} else {
if ($rtn = _E55GetDLMembers(@_)) {
return $rtn;
}
}
return 0;
}
sub _E55GetDLMembers {
#removed server_name -- not needed
#removed org -- not needed
#removed ou -- not needed
my $error_num;
my $error_name;
my $provider;
my $server_name;
my $exch_dl_name;
my @members;
my $ou;
my $org;
my $find_dl;
my $return_prop;
if (scalar(@_) > 2) {
$provider = \%{$_[0]} ;
$server_name=$provider->{server};
$org=$provider->{org};
$ou=$provider->{ou};
$exch_dl_name=$_[1];
if (ref($_[2]) ne "ARRAY") {
_DebugComment("members list must be an array reference\n",1);
return 0;
}
if (scalar(@_) == 4) {
$return_prop = $_[3];
} else {
_ReportArgError("GetDLMembers [5.5]",scalar(@_));
return 0;
}
} else {
_ReportArgError("GetDLMembers [5.5]",scalar(@_));
return 0;
}
my $temp_exch_dl;
my $original_ole_warn_value = $Win32::OLE::Warn;
my $exch_dl_dn;
my $exch_dl_path;
if ($exch_dl_name =~ /^cn=.*ou=.*o=.*/) {
#a dn was sent
$exch_dl_path = "LDAP://$server_name/$exch_dl_name";
$exch_dl_dn = $exch_dl_name;
} else {
if (Win32::Exchange::_AdodbExtendedSearch($exch_dl_name,"LDAP://$server_name","(&(objectClass=groupOfNames)(cn=$exch_dl_name))","cn,distinguishedName",$exch_dl_dn)) {
$exch_dl_path = "LDAP://$server_name/$exch_dl_dn";
} else {
_DebugComment("Error locating Exchange DL on the server. Member information unavailable.\n",1);
return 0;
}
}
my $ldap_provider = $provider->{ad_provider};
my $exch_dl = $ldap_provider->GetObject("",$exch_dl_path);
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error querying distribution list ($exch_dl_name) -> $error_num ($error_name)\n",1);
return 0;
}
if (ref($exch_dl->{Members}) eq "ARRAY") {
_DebugComment(" -Array (2 or more members exist -- $return_prop)\n",3);
if (lc($return_prop) ne 'distinguishedname') {
foreach my $member (@{$exch_dl->{Members}}) {
my $search_prop;
if (!Win32::Exchange::_AdodbExtendedSearch($member,"LDAP://$server_name","(distinguishedName=$member)","distinguishedName,$return_prop",$search_prop)) {
_DebugComment("Failed Adodb search for member property ($return_prop)\n",1);
return 0;
}
push (@{$_[2]}, $search_prop);
}
return 1;
} else {
@{$_[2]} = @{$exch_dl->{Members}};
return 1;
}
} else {
_DebugComment(" -Less than 2 members are named in this distribution list -- $return_prop\n",3);
my $member = $exch_dl->{Members};
if ($member) {
_DebugComment(" -1 member exists -- $return_prop\n",3);
if (lc($return_prop) ne 'distinguishedname') {
my $search_prop;
if (!Win32::Exchange::_AdodbExtendedSearch($member,"LDAP://RootDSE/dnsHostName","(distinguishedName=$member)","distinguishedName,$return_prop",$search_prop)) {
_DebugComment("Failed Adodb search for member property ($return_prop)\n",1);
return 0;
}
push (@{$_[2]}, $search_prop);
} else {
push (@{$_[2]}, $member);
}
return 1;
} else {
_DebugComment(" -0 members exists -- $return_prop\n",1);
return 1;
}
}
}
sub _E2KGetDLMembers {
my $error_num;
my $error_name;
my $group_dn;
my $user_dn;
my $provider;
$provider = \%{$_[0]} ;
my $group = $_[1];
my $return_prop = 'distinguishedName';
if (scalar(@_) != 3) {
if (scalar(@_) == 4) {
$return_prop = $_[3];
} else {
_ReportArgError("GetdDLMembers (E2K)",scalar(@_));
return 0;
}
}
my $dc = $provider->{dc};
if (ref($_[2]) ne "ARRAY") {
_DebugComment("Third argument is the list of users you want return, and should be an array reference, but instead, it was a(an): ".ref($_[2])." reference\n",1);
return 0;
}
if (!Win32::Exchange::_AdodbExtendedSearch($group,"LDAP://$dc","(&(objectClass=group)(samAccountName=$group))","samAccountName,distinguishedName",$group_dn)) {
_DebugComment("Failed Adodb search for dist list\n",1);
return 0;
}
my $ldap_obj = $provider->{ad_provider};
my $group_obj = $ldap_obj->GetObject("","LDAP://$dc/$group_dn");
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Error opening distribution list on $dc ($error_num)\n",1);
return 0;
}
if (ref($group_obj->{Member}) eq "ARRAY") {
_DebugComment(" -Array (2 or more members exist -- $return_prop)\n",3);
if (lc($return_prop) ne 'distinguishedname') {
foreach my $member (@{$group_obj->{Member}}) {
my $search_prop;
if (!Win32::Exchange::_AdodbExtendedSearch($member,"LDAP://$dc","(distinguishedName=$member)","distinguishedName,$return_prop",$search_prop)) {
_DebugComment("Failed Adodb search for member property ($return_prop)\n",1);
return 0;
}
push (@{$_[2]}, $search_prop);
}
return 1;
} else {
@{$_[2]} = @{$group_obj->{Member}};
return 1;
}
} else {
_DebugComment(" -Less than 2 members are named in this distribution list -- $return_prop\n",3);
my $member = $group_obj->{Member};
if ($member) {
_DebugComment(" -1 member exists -- $return_prop\n",3);
if (lc($return_prop) ne 'distinguishedname') {
my $search_prop;
if (!Win32::Exchange::_AdodbExtendedSearch($member,"LDAP://$dc","(distinguishedName=$member)","distinguishedName,$return_prop",$search_prop)) {
_DebugComment("Failed Adodb search for member property ($return_prop)\n",1);
return 0;
}
push (@{$_[2]}, $search_prop);
} else {
push (@{$_[2]}, $member);
}
return 1;
} else {
_DebugComment(" -0 members exists -- $return_prop\n",1);
return 1;
}
}
}
sub SetAttributes {
my $provider;
$provider = \%{$_[0]} ;
my $rtn;
if ($provider->{version} =~ /^6\./) {
if ($rtn = _E2KSetAttributes(@_)) {
return $rtn;
}
} else {
if ($rtn = _E55SetAttributes(@_)) {
return $rtn;
}
}
return 0;
}
sub _E55SetAttributes {
my $error_num;
my $error_name;
my $provider;
my %attrs;
if (scalar(@_) == 2) {
$provider = \%{$_[0]} ;
if (ref($_[1]) ne "HASH") {
_DebugComment("second object passed to SetAttributes was not a HASH reference -> $error_num ($error_name)\n",1);
return 0;
} else {
%attrs = %{$_[1]};
}
} else {
_ReportArgError("SetAttributes [E55]",scalar(@_));
return 0;
}
my $mailbox = $provider->{ad_provider};
my $original_ole_warn_value=$Win32::OLE::Warn;
$Win32::OLE::Warn=0;
foreach my $attr (keys %attrs) {
$mailbox->Put($attr => $attrs{$attr});
}
$mailbox->SetInfo();
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error setting attribute on mailbox -> $error_num ($error_name)\n",1);
$Win32::OLE::Warn=$original_ole_warn_value;
return 0;
}
return 1;
}
sub _E2KSetAttributes {
my $error_num;
my $error_name;
my %attrs;
my $provider;
my $mailbox;
if (scalar(@_) == 2) {
$provider = \%{$_[0]} ;
if (ref($_[1]) ne "HASH") {
_DebugComment("second object passed to SetAttributes was not a HASH reference -> $error_num ($error_name)\n",1);
return 0;
} else {
%attrs = %{$_[1]};
}
} else {
_ReportArgError("SetAttributes [2K]",scalar(@_));
return 0;
}
my $user_account = $provider->{cdo_provider};
foreach my $interface (keys %attrs) {
my $mailbox_interface = $user_account->GetInterface($interface);
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error getting mailbox interface -> $error_num ($error_name)\n",1);
return 0;
}
foreach my $attr (keys %{$attrs{$interface}}) {
$mailbox_interface->{$attr} = $attrs{$interface}{$attr};
}
$user_account->DataSource->Save();
}
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error setting attribute on mailbox -> $error_num ($error_name)\n",1);
return 0;
}
return 1;
# overriding defaults
#http://www.microsoft.com/technet/treeview/default.asp?url=/technet/prodtechnol/exchange/exchange2000/maintain/featusability/EX2KWSH.asp
# storage limits
#http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wss/wss/_cdo_imailboxstore_interface.asp
# proxy addresses
#http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wss/wss/_cdo_setting_proxy_addresses.asp
# interfaces and attributes:
#http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wss/wss/_cdo_recipient_management_interfaces.asp
}
sub GetOwner {
my $provider;
$provider = \%{$_[0]} ;
my $rtn;
if ($provider eq "6.0") {
#no available support for this operation yet
return 0;
} else {
if ($rtn = _E55GetOwner(@_)) {
return $rtn;
}
}
return 0;
}
sub _E55GetOwner {
my $error_num;
my $error_name;
my $provider;
my $returned_sid_type;
if (scalar(@_) > 1) {
$provider = \%{$_[0]} ;
if (scalar(@_) == 2) {
$returned_sid_type = ADS_SID_WINNT_PATH;
} elsif (scalar(@_) == 3) {
$returned_sid_type = $_[2];
} else {
_ReportArgError("GetOwner [5.5]",scalar(@_));
return 0;
}
} else {
_ReportArgError("GetOwner [5.5]",scalar(@_));
return 0;
}
my $mailbox = $provider->{ad_provider};
my $sid = Win32::OLE->new("ADsSID");
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error creating ADsSID object -> $error_num ($error_name)\n",1);
return 0;
}
$mailbox->GetInfoEx(["Assoc-NT-Account"],0);
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error populating the property cache for Assoc-NT-Account -> $error_num ($error_name)\n",1);
return 0;
}
$sid->SetAs(ADS_SID_HEXSTRING,$mailbox->{'Assoc-NT-Account'});
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error creating ADsSID object -> $error_num ($error_name)\n",1);
return 0;
}
my $siduser = $sid->GetAs($returned_sid_type);
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
if (ErrorCheck("0x80070534",$error_num,$error_name)) {
_DebugComment("there was an error validating the SID from the Domain Controller (the account doesn't seem to exist anymore) -> $error_num ($error_name)\n",1);
return 0;
}
_DebugComment("error getting SID to prepare for output -> $error_num ($error_name)\n",1);
return 0;
}
$_[1] = $siduser;
return 1;
}
sub SetOwner {
my $error_num;
my $error_name;
my $dc;
if (scalar(@_) != 2) {
_ReportArgError("SetOwner [5.5]",scalar(@_));
return 0;
}
my $provider;
$provider = \%{$_[0]} ;
my $new_mailbox = $provider->{ad_provider};
my $username = $_[1];
if ($username =~ /(.*)\\(.*)/) {
#DOMAIN\Username
$dc=$1;
$username = $2;
} else {
_DebugComment("error parsing username to extract domain and username\n",1);
return 0;
}
my $sid = Win32::OLE->new("ADsSID");
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error creating security object (ADsSID) -> $error_num ($error_name)\n",1);
return 0;
}
$sid->SetAs(ADS_SID_WINNT_PATH, "WinNT://$dc/$username,user");
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error setting security object at an ADS_SID_WINNT_PATH -> $error_num ($error_name)\n",1);
return 0;
}
my $sidHex = $sid->GetAs(ADS_SID_HEXSTRING);
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error converting security object at an ADS_SID_HEXSTRING -> $error_num ($error_name)\n",1);
return 0;
}
$new_mailbox->Put("Assoc-NT-Account", $sidHex );
$new_mailbox->SetInfo;
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error setting owner information on mailbox -> $error_num ($error_name)\n",1);
return 0;
}
return 1;
}
sub GetPerms {
my $provider;
$provider = \%{$_[0]} ;
my $rtn;
if ($provider->{version} =~ /^6\./) {
#Sorry, not implemented yet
return 0;
} else {
if ($rtn = _E55GetPerms(@_)) {
return $rtn;
}
}
return 0;
}
sub _E55GetPerms {
#Need to work on this.
if (scalar(@_) != 2) {
_ReportArgError("GetPerms [5.5]",scalar(@_));
return 0;
}
if (ref($_[1]) ne "ARRAY") {
_DebugComment("permissions list must be an array reference (e55)\n",1);
return 0;
}
my $provider;
$provider = \%{$_[0]} ;
my $mailbox = $provider->{ad_provider};
my $sec = Win32::OLE->CreateObject("ADsSecurity");
my $error_num;
my $error_name;
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error creating security object (ADSSecurity) -> $error_num ($error_name)\n",1);
if ($error_num eq "0x80004002") {
_DebugComment("Error: No such interface supported.\n Note: Make sure you have the ADSSecurity.DLL from the ADSI SDK regisered on this system\n",2);
}
return 0;
}
my $sd = $sec->GetSecurityDescriptor($mailbox->{ADsPath});
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error querying security descriptor for mailbox -> $error_num ($error_name)\n",1);
return 0;
}
my $dacl = $sd->{DiscretionaryAcl};
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error querying discretionary acl for mailbox -> $error_num ($error_name)\n",1);
return 0;
}
@{$_[1]} = Win32::OLE::in($dacl);
return 1;
}
sub SetPerms {
my $provider;
$provider = \%{$_[0]} ;
my $rtn;
if ($provider->{version} =~ /^6\./) {
if ($rtn = _E2KSetPerms(@_)) {
return $rtn;
}
} else {
if ($rtn = _E55SetPerms(@_)) {
return $rtn;
}
}
return 0;
}
sub _E55SetPerms {
if (scalar(@_) != 2) {
_ReportArgError("SetPerms [5.5]",scalar(@_));
return 0;
}
if (ref($_[1]) ne "ARRAY") {
_DebugComment("permissions list must be an array reference (e55)\n",1);
return 0;
}
my $provider;
$provider = \%{$_[0]} ;
my $new_mailbox = $provider->{ad_provider};
my @perms_list = @{$_[1]};
my $sec = Win32::OLE->CreateObject("ADsSecurity");
my $error_num;
my $error_name;
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error creating security object (ADSSecurity) -> $error_num ($error_name)\n",1);
if ($error_num eq "0x80004002") {
_DebugComment("Error: No such interface supported.\n Note: Make sure you have the ADSSecurity.DLL from the ADSI SDK regisered on this system\n",2);
}
return 0;
}
my $sd = $sec->GetSecurityDescriptor($new_mailbox->{ADsPath});
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error querying security descriptor for mailbox -> $error_num ($error_name)\n",1);
return 0;
}
my $dacl = $sd->{DiscretionaryAcl};
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error querying discretionary acl for mailbox -> $error_num ($error_name)\n",1);
return 0;
}
foreach my $userid (@perms_list) {
_DebugComment(" -Setting perms for $userid\n",3);
my $ace = Win32::OLE->CreateObject("AccessControlEntry");
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error creating access control entry for mailbox -> $error_num ($error_name)\n",1);
return 0;
}
my %properties;
$properties{Trustee}=$userid;
$properties{AccessMask}=ADS_RIGHT_EXCH_MODIFY_USER_ATT | ADS_RIGHT_EXCH_MAIL_SEND_AS | ADS_RIGHT_EXCH_MAIL_RECEIVE_AS;
$properties{AceType}=ADS_ACETYPE_ACCESS_ALLOWED;
foreach my $property (keys %properties) {
$ace->LetProperty($property,$properties{$property});
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error setting $property for mailbox -> $error_num ($error_name)\n",1);
return 0;
}
}
$dacl->AddAce($ace);
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error adding access control entry to perms list -> $error_num ($error_name)\n",1);
return 0;
}
}
$sd->LetProperty("DiscretionaryAcl",$dacl);
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error setting discretionary acl on security security descriptor -> $error_num ($error_name)\n",1);
return 0;
}
$sec->SetSecurityDescriptor($sd);
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error setting security descriptor on security object -> $error_num ($error_name)\n",1);
return 0;
}
$new_mailbox->SetInfo;
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error setting permissions on mailbox -> $error_num ($error_name)\n",1);
return 0;
}
return 1;
}
sub _E2KSetPerms {
my $error_num;
my $error_name;
if (scalar(@_) != 2) {
_ReportArgError("SetPerms [2K]",scalar(@_));
return 0;
}
if (ref($_[1]) ne "ARRAY") {
_DebugComment("permissions list must be an array reference (e2k)\n",1);
return 0;
}
my $provider;
$provider = \%{$_[0]} ;
my $cdo_user_obj = $provider->{cdo_provider};
my @perms_list = @{$_[1]};
my $ldap_user_path = $cdo_user_obj->{DataSource}->{SourceURL};
my $ldap_user_obj = Win32::OLE->GetObject($ldap_user_path);
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Error querying Source URL for CDO.Person object ($error_num)\n",1);
return 0;
}
#http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q310866
my $sd = $ldap_user_obj->{'MailboxRights'};
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Error querying MailboxRights property ($error_num)\n",1);
_DebugComment("- make sure you are using Exchange 2000 SP1+hotfix or higher [server & client]\n",2);
_DebugComment(' http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q302926'."\n",3);
return 0;
}
my $dacl = $sd->{DiscretionaryAcl};
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Error getting DiscretionaryAcl ($error_num)\n",1);
return 0;
}
foreach my $user_account (@perms_list) {
my $domain;
my $username;
if ($user_account =~ /(.*)\\(.*)/) {
$domain = $1;
$username = $2;
} else {
_DebugComment("error parsing user object (expected DOMAIN\\Username) -> $error_num ($error_name)\n",1);
return 0;
}
my $Ace = Win32::OLE->new("AccessControlEntry");
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Error creating new ACE ($error_num)\n",1);
return 0;
}
my %properties;
$properties{AccessMask}=ADS_RIGHT_DS_CREATE_CHILD;
$properties{AceType}=ADS_ACETYPE_ACCESS_ALLOWED;
$properties{AceFlags}=ADS_ACEFLAG_INHERIT_ACE;
$properties{Flags}=0;
$properties{Trustee}=$user_account;
$properties{ObjectType}=0;
$properties{InheritedObjectType}=0;
foreach my $property (keys %properties) {
if ($property =~ /(ObjectType|InheritedObjectType)/ && $properties{$property} == 0) {
next;
}
$Ace->LetProperty($property,$properties{$property});
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Error setting $property ($error_num)\n",1);
return 0;
}
}
$dacl->AddAce($Ace);
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Error adding AccessControlEntry to AccessControlList: ($error_num)\n",1);
return 0;
}
}
$sd->LetProperty('DiscretionaryAcl',$dacl);
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Error setting AccessControlList to Security Descriptor: ($error_num)\n",1);
return 0;
}
$ldap_user_obj->LetProperty('MailboxRights',$sd);
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Error modfying Mailbox Security entry: ($error_num)\n",1);
return 0;
}
$ldap_user_obj->SetInfo();
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Error setting information to Mailbox Security entry: ($error_num)\n",1);
return 0;
}
return 1;
}
sub MailEnable {
my $provider;
$provider = \%{$_[0]} ;
my $rtn;
if ($provider->{version} =~ /^6\./) {
if ($rtn = _E2KMailEnable(@_)) {
return $rtn;
}
} else {
if ($rtn = _E55MailEnable(@_)) {
return $rtn;
}
}
return 0;
}
sub _E2KMailEnable {
#removed user_object - not needed
my $provider;
my $user_obj;
my $interface;
my $smtp_address = "";
my $error_num;
my $error_name;
if (scalar(@_) > 0) {
$provider = \%{$_[0]} ;
$user_obj = $provider->{ad_provider};
if (scalar(@_) == 2) {
$smtp_address = $_[2];
if (!($smtp_address =~ /^smtp:.*/i && $smtp_address ne "")) {
$smtp_address = "smtp:".$smtp_address;
}
} else {
_ReportArgError("MailEnable (E2K)",scalar(@_));
return 0;
}
} else {
_ReportArgError("MailEnable (E2K)",scalar(@_));
return 0;
}
my $dn = $user_obj->{ADsPath};
my $dc = $provider->{dc};
if (_E2KIsMailAware($dc,$user_obj->{samaccountname})) {
_DebugComment("user account is already MAPI aware. Cannot proceed with MailEnable (E2K)\n",0);
return 0;
}
$interface = $user_obj->GetInterface("IMailRecipient");
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error querying mailbox interface during MailEnable (E2K) -> $error_num ($error_name)\n",1);
return 0;
}
if ($smtp_address eq "") {
$interface->MailEnable();
} else {
$interface->MailEnable($smtp_address);
}
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error performing MailEnable on AD user object (E2K) -> $error_num ($error_name)\n",1);
return 0;
}
$user_obj->Datasource->Save();
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error performing Save on AD User object during MailEnable (E2K) -> $error_num ($error_name)\n",1);
return 0;
}
if ($smtp_address eq "") {
return 1;
} else {
if (ref($user_obj->{proxyaddresses}) eq "ARRAY") {
_DebugComment(" -Array (2 or more addresses exist)\n",3);
my @proxy_addr = @{$user_obj->{proxyaddresses}};
my $found_addr = 0;
foreach my $proxyaddr (@proxy_addr) {
if (lc($proxyaddr) eq lc($smtp_address)) {
$found_addr = 1;
}
}
if ($found_addr == 0) {
push (@proxy_addr,$smtp_address);
$user_obj->{proxyaddresses} = @proxy_addr;
}
return 1;
} else {
_DebugComment(" -Less than 2 addresses exist\n",3);
my $proxyaddresses = $user_obj->{proxyaddresses};
if ($proxyaddresses) {
_DebugComment(" -1 address exists\n",3);
my @proxy_addr;
push (@proxy_addr,$user_obj->{proxyaddresses});
if (lc($user_obj->{proxyaddresses}) ne lc($smtp_address)) {
push (@proxy_addr,$smtp_address);
}
$user_obj->{proxyaddresses} = @proxy_addr;
return 1;
} else {
_DebugComment(" -0 addresses exists\n",3);
$user_obj->{proxyaddresses}= $smtp_address;
return 1;
}
}
}
}
sub _E55MailEnable {
#sorry, no function yet.
return 0;
}
sub MailDisable {
my $provider;
$provider = \%{$_[0]} ;
my $rtn;
if ($provider->{version} =~ /^6\./) {
if ($rtn = _E2KMailDisable(@_)) {
return $rtn;
}
} else {
#nothing returns for ADsNamespaces (E5.5)
if ($rtn = _E55MailDisable(@_)) {
return $rtn;
}
}
return 0;
}
sub _E2KMailDisable {
my $user_obj;
my $provider;
my $interface;
my $smtp_address = "";
my $error_num;
my $error_name;
if (scalar(@_) > 0) {
$provider = \%{$_[0]} ;
$user_obj = $provider->{ad_provider};
} else {
_ReportArgError("MailDisable (E2K)",scalar(@_));
return 0;
}
my $dn = $user_obj->{ADsPath};
$dn =~ /LDAP:\/\/(.*)\/.*/;
my $dc = $1;
if (!$provider->_E2KIsMailEnabled($user_obj->{samaccountname})) {
_DebugComment("user account is not MailEnabled. Cannot proceed with MailDisable (E2K)\n",0);
return 0;
}
$interface = $user_obj->GetInterface("IMailRecipient");
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error querying mailbox interface during MailDisable (E2K) -> $error_num ($error_name)\n",1);
return 0;
}
$interface->MailDisable();
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error performing MailDisable on AD user object (E2K) -> $error_num ($error_name)\n",1);
return 0;
}
$user_obj->Datasource->Save();
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error performing Save on AD User object during MailDisable (E2K) -> $error_num ($error_name)\n",1);
return 0;
} else {
return 1;
}
}
sub _E55MailDisable {
#sorry, no function yet.
return 0;
}
sub MoveMailbox {
my $mbx;
my $provider;
$provider = \%{$_[0]} ;
if ($provider->{version} =~ /^6\./) {
if ($mbx = _E2KMoveMailbox(@_)) {
return $mbx;
}
} else {
_DebugComment("Sorry, there's no Exchange 5.5 version of this call (MoveMailbox). Try using EXMERGE.\n",0);
return 0;
}
return 0;
}
sub _E2KMoveMailbox {
my $provider;
my $mailbox_alias_name;
my $move_to_server;
my $move_to_sg;
my $move_to_ms;
my $error_num;
my $error_name;
my $dc;
my $cdo_provider;
if (scalar(@_) == 5) {
$provider = \%{$_[0]} ;
$cdo_provider = $provider->{cdo_provider};
$dc = $provider->{dc};
$mailbox_alias_name = $_[1];
$move_to_server = $_[2];
$move_to_sg = $_[3];
$move_to_ms = $_[4];
} else {
_ReportArgError("MoveMailbox [E2K]",scalar(@_));
return 0;
}
my $store_dn;
if (Win32::Exchange::LocateMailboxStore($move_to_server,$move_to_sg,$move_to_ms,$store_dn)) {
_DebugComment("Success finding MB Store at $store_dn\n",3);
} else {
_DebugComment("Failed finding MB Store for $move_to_ms (message store) and $move_to_sg (storage_group)\n",1);
return 0;
}
my $user_dn;
if (!Win32::Exchange::_AdodbExtendedSearch($mailbox_alias_name,"LDAP://$dc","(samAccountName=$mailbox_alias_name)","samAccountName,distinguishedName",$user_dn)) {
_DebugComment("Error querying user mailbox in MoveMailbox (E2K)\n",1);
return 0;
}
my $objMailbox = $cdo_provider;
$objMailbox->{DataSource}->Open("LDAP://".$user_dn,undef,adModeReadWrite);
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Error Opening mailbox for user ($mailbox_alias_name) in MoveMailbox (E2K)\n",1);
return 0;
}
my $info_store = $objMailbox->GetInterface("IMailboxStore");
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Error using GetInterface for $mailbox_alias_name in MoveMailbox (E2K)\n",1);
return 0;
}
if ($info_store->{homeMDB} eq "") {
_DebugComment ("This user has no mailbox (homeMDB is empty).\n",2);
return 0;
}
if (lc("LDAP://".$info_store->{homeMDB}) eq lc($store_dn)) {
_DebugComment ("Mailbox paths for source and destination are identical (nothing to move) in MoveMailbox (E2K).\n",2);
return 0;
}
$info_store->MoveMailbox($store_dn);
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Error Moving mailbox for user ($mailbox_alias_name) in MoveMailbox (E2K) -- $error_num\n",1);
if (ErrorCheck("0x8000ffff",$error_num,$error_name)) {
_DebugComment("This error usually has to do with a newly created user -- MoveMailbox (E2K)\n",1);
_DebugComment(" -Waiting for replication to complete can correct this issue\n",1);
_DebugComment(" -Mailboxes that have never logged into can also cause this error\n",1);
}
return 0;
}
$objMailbox->{DataSource}->Save();
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Error Saving changes for for user ($mailbox_alias_name) in MoveMailbox (E2K)\n",1);
return 0;
} else {
_DebugComment ("Mailbox has been moved to " . $move_to_ms . " successfully.\n",4);
return 1;
}
}
sub AddDLMembers {
my $provider;
$provider = \%{$_[0]} ;
my $rtn;
if ($provider->{version} =~ /^6\./) {
if ($rtn = _E2KAddDLMembers(@_)) {
return $rtn;
}
} else {
#nothing returns for ADsNamespaces (E5.5)
if ($rtn = _E55AddDLMembers(@_)) {
return $rtn;
}
}
return 0;
}
sub _E55AddDLMembers {
#removed servername -- not needed
#removed org -- not needed
#removed ou -- not needed
#removed find_dl -- not needed
my $provider;
my $server_name;
my $exch_dl_name;
my @new_members;
my $ou;
my $org;
my $find_dl;
if (scalar(@_) == 3) {
$provider = \%{$_[0]} ;
$server_name=$provider->{server};
$org = $provider->{org};
$ou = $provider->{ou};
$exch_dl_name=$_[1];
if (ref($_[2]) ne "ARRAY") {
_DebugComment("members list must be an array reference\n",1);
return 0;
}
@new_members=@{$_[2]};
} else {
_ReportArgError("AddDLMembers [5.5]",scalar(@_));
return 0;
}
my $temp_exch_dl;
my $original_ole_warn_value = $Win32::OLE::Warn;
my $exch_dl_dn;
my $exch_dl_path;
if ($exch_dl_name =~ /^cn=.*ou=.*o=.*/) {
#a dn was sent
$exch_dl_path = "LDAP://$server_name/$exch_dl_name";
$exch_dl_dn = $exch_dl_name;
} else {
$find_dl = 1; #hard-coding this for now -- searching guarantees the object path (if it exists somewhere)
if ($find_dl == 1) {
if (Win32::Exchange::_AdodbExtendedSearch($exch_dl_name,"LDAP://$server_name","(&(objectClass=groupOfNames)(uid=$exch_dl_name))","uid,distinguishedName",$exch_dl_dn)) {
$exch_dl_path = "LDAP://$server_name/$exch_dl_dn";
} else {
_DebugComment("Error locating Exchange DL on the server. Member addition cannot proceed.\n",1);
return 0;
}
} else {
#an alias was sent (name only, check default container)
$exch_dl_path = "LDAP://$server_name/cn=$exch_dl_name,cn=Distribution Lists,ou=$ou,o=$org";
$exch_dl_dn = "cn=$exch_dl_name,cn=Distribution Lists,ou=$ou,o=$org";
}
}
my $ldap_provider = $provider->{ad_provider};
my $exch_dl = $ldap_provider->GetObject("",$exch_dl_path);
my $error_num;
my $error_name;
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error querying distribution list ($exch_dl_name) -> $error_num ($error_name)\n",1);
return 0;
}
my $exch_members = $exch_dl->{'member'}; #get the list
if (ref($exch_members) eq "ARRAY") {
_DebugComment(" -Array (2 or more members exist)\n",3);
} else {
_DebugComment(" -(Less than 2 members are named in this distribution list)\n",3);
my $temp_exch_dl=$exch_members;
undef ($exch_members);
if ($temp_exch_dl) {
_DebugComment(" -1 member exists\n",3);
#So push the existing name to the Array
push (@$exch_members, $temp_exch_dl);
} else {
_DebugComment(" -0 members exists\n",3);
}
}
my $exch_mb_dn;
foreach my $username (@new_members) {
_DebugComment(" -Adding $username to Distribution List: $exch_dl_name\n",2);
if ($username =~ /^cn=.*ou=.*o=.*$/) {
$exch_mb_dn = $username;
} else {
if (!Win32::Exchange::_AdodbExtendedSearch($username,"LDAP://$server_name","(&(objectClass=organizationalPerson)(uid=$username))","uid,distinguishedName",$exch_mb_dn)) {
_DebugComment("Error locating Exchange mailbox on the server. Member addition cannot proceed.\n",1);
return 0;
}
}
my $duplicate;
foreach my $dup (@$exch_members) {
if (lc($dup) eq lc($exch_mb_dn)) {
_DebugComment("Error adding user ($username) to distribution list [they are already a member]\n",1);
$duplicate = 1;
last;
}
}
if ($duplicate != 1) {
push (@$exch_members, $exch_mb_dn);
}
}
$exch_dl->Put('member', $exch_members);
$exch_dl->SetInfo;
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("error setting new member for distribution list ($exch_dl_name) -> $error_num ($error_name)\n",1);
return 0;
}
return 1;
}
sub _E2KAddDLMembers {
if (scalar(@_) != 3) {
_ReportArgError("AddDLMembers (E2K)",scalar(@_));
return 0;
}
if (ref($_[2]) ne "ARRAY") {
_DebugComment("Third argument is the list of users you want to add to this DL, and should be an array reference, but instead, it was a(an): ".ref($_[2])." reference\n",1);
return 0;
}
my $error_num;
my $error_name;
my $group_dn;
my $user_dn;
my $provider;
$provider = \%{$_[0]} ;
my $dc = $provider->{dc};
my $ldap_provider = $provider->{ad_provider};
my $group = $_[1];
my @user_list = @{$_[2]};
if (!Win32::Exchange::_AdodbExtendedSearch($group,"LDAP://$dc","(&(objectClass=Group)(samAccountName=$group))","samAccountName,distinguishedName",$group_dn)) {
_DebugComment("Failed Adodb search for dist list\n",1);
return 0;
}
foreach my $username (@user_list) {
_DebugComment("Adding $username to $group\n",4);
if (!Win32::Exchange::_AdodbExtendedSearch($username,"LDAP://$dc","(&(objectClass=user)(samAccountName=$username))","samAccountName,distinguishedName",$user_dn)) {
_DebugComment("Failed Adodb search for user: $username\n",1);
return 0;
}
my $group_obj = $ldap_provider->GetObject("","LDAP://$dc/$group_dn");
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Error opening distribution list on $dc ($error_num)\n",1);
return 0;
}
$group_obj->Add("LDAP://$dc/$user_dn");
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
if ($error_num eq "0x80071392") {
_DebugComment("Error adding user ($username) to distribution list [they are already a member]\n",1);
} else {
_DebugComment("Error adding user ($username) to distribution list ($error_num)\n",1);
return 0;
}
}
$group_obj->SetInfo;
if (!ErrorCheck("0x00000000",$error_num,$error_name)) {
_DebugComment("Error committing addition to distribution list ($error_num)\n",1);
return 0;
}
}
return 1;
}
sub _ReportArgError {
my $rtn = Win32::Exchange::_ReportArgError($_[0],$_[1]);
return $rtn;
}
sub _DebugComment {
my $rtn = Win32::Exchange::_DebugComment($_[0],$_[1],$DEBUG);
return $rtn;
}
sub ErrorCheck {
my $rtn = Win32::Exchange::ErrorCheck($_[0],$_[1],$_[2]);
return $rtn;
}
1;