For the example below, I used Visual Studio Express 2010 SP1 under Windows.
A lot of other options exist for the NTLM library and to handle SSL (like libcurl or WinHTTP) Exchange answer in XML, so you can use xmllite, minixml or just decode the XML manually, it's your choice.
#include <openssl/ssl.h> #include <openssl/err.h> #include <openssl/bio.h> #include "ntlm.h"
struct hostent *hp; struct sockaddr_in addr; WORD wVersionRequested = MAKEWORD(2,2); int sock; WSADATA wsaData; WSAStartup(wVersionRequested, &wsaData); if(!(hp=gethostbyname("server_host"))) return 0; memset(&addr,0, sizeof(addr)); addr.sin_addr=*(struct in_addr*) hp->h_addr_list[0]; addr.sin_family=AF_INET; addr.sin_port=htons(443); if((sock=socket(AF_INET,SOCK_STREAM, IPPROTO_TCP))<0) return 0; if(connect(sock,(struct sockaddr *)&addr, sizeof(addr))<0) return 0; return 1;
const SSL_METHOD *meth; SSL *ssl; BIO *sbio; BIO *rbio; BIO *wbio; SSL_CTX *ctx; SSL_library_init(); SSL_load_error_strings(); meth=SSLv23_method(); ctx=SSL_CTX_new(meth); ssl=SSL_new(ctx); sbio=BIO_new_socket(sock,BIO_NOCLOSE);
const SSL_METHOD *meth; SSL *ssl; BIO *sbio; BIO *rbio; BIO *wbio; SSL_CTX *ctx; SSL_library_init(); SSL_load_error_strings(); meth=SSLv23_method(); ctx=SSL_CTX_new(meth);
ssl=SSL_new(ctx); sbio=BIO_new_socket(sock,BIO_NOCLOSE);
SSL_set_bio(ssl,sbio,sbio); SSL_connect(ssl);
SSL_write(ssl,"GET /EWS/Services.wsdl HTTP/1.1\r\nUser-Agent: test\r\nHost: serverhost:443\r\n\r\n",strlen("GET /EWS/Services.wsdl HTTP/1.1\r\nUser-Agent: test\r\nHost: serverhost:443\r\n\r\n"));
Check the answer for "WWW-Authenticate: NTLM". If it's not there, be sure it's enabled on your IIS of your Exchange Server with the CAS role.
string encoded, encodedpass, decoded, sBuffer;
char cRequest[1024]; char cBuffer[1024]; tSmbNtlmAuthRequest request; tSmbNtlmAuthResponse response; ZeroMemory(cRequest, 1024); buildSmbNtlmAuthRequest (&request, "username", "domain"); if (SmbLength(&request) > 1024) return 0; encoded = enc.Base64enc((unsigned char *) &request, SmbLength(&request)); _snprintf(cRequest, 1024, "GET /EWS/Services.wsdl HTTP/1.1\r\nHost: serverhost\r\nConnection: Keep-Alive\r\nAuthorization: NTLM %s\r\n\r\n", encoded.c_str()); SSL_write(ssl, cRequest);
// read the answer, sBuffer = NTLM answer decoded = enc.Base64dec(sBuffer); buildSmbNtlmAuthResponse((tSmbNtlmAuthChallenge *)decoded.c_str(), &response, "username", "password"); encodedpass = enc.Base64enc((unsigned char *) &response, SmbLength(&response)); _snprintf(cRequest, 1024, "GET /EWS/Services.wsdl HTTP/1.1\r\nHost: servername\r\nConnection: Keep-Alive\r\nAuthorization: NTLM %s\r\n\r\n", encodedpass.c_str()); SSL_write(ssl, cRequest); // If IIS answer with 200 then your password was ok !
Like to receive a distribution group member's list: char cRequest[1024]; char request[1024] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" "<soap:Envelope xmlns:soap=\http://schemas.xmlsoap.org/soap/envelope// " xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">" " <soap:Body>" " <ExpandDL xmlns=\http://schemas.microsoft.com/exchange/services/2006/messages/ " xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">" " <Mailbox xmlns=\"http://schemas.microsoft.com/exchange/services/2006/messages\">" " <EmailAddress xmlns=\"http://schemas.microsoft.com/exchange/services/2006/types\">test@constoco.com</EmailAddress>" " </Mailbox>" " </ExpandDL>" " </soap:Body>" "</soap:Envelope>"; ZeroMemory(cRequest, 1024); _snprintf(cRequest, 1024, "POST /ews/Exchange.asmx HTTP/1.1\r\n" "Host: servername\r\n" "Content-Length: %d\r\n" "Content-Type: text/xml\r\n\r\n%s", strlen(request), request); // send it and decode the answer...
Like to receive a distribution group member's list: char cRequest[1024]; char request[1024] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" "<soap:Envelope xmlns:soap=\http://schemas.xmlsoap.org/soap/envelope// " xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">" " <soap:Body>" " <ExpandDL xmlns=\http://schemas.microsoft.com/exchange/services/2006/messages/ " xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">" " <Mailbox xmlns=\"http://schemas.microsoft.com/exchange/services/2006/messages\">" " <EmailAddress xmlns=\"http://schemas.microsoft.com/exchange/services/2006/types\">test@constoco.com</EmailAddress>" " </Mailbox>" " </ExpandDL>" " </soap:Body>" "</soap:Envelope>";
ZeroMemory(cRequest, 1024); _snprintf(cRequest, 1024, "POST /ews/Exchange.asmx HTTP/1.1\r\n" "Host: servername\r\n" "Content-Length: %d\r\n" "Content-Type: text/xml\r\n\r\n%s", strlen(request), request);
Quick and Dirty UNIX Shell Scripting with EWS - The idea that started it all for me was there. EWSEditor - To generate some SOAP message easily. Exchange Web Services (EWS) - MSDN referance with a lot of examples. theForger's Win32 API Programming Tutorial - A really good tutorial for direct API programming.
This article is also available the following languages:
Yagmoth555 edited Revision 6. Comment: added the fr-FR link
Yagmoth555 edited Revision 5. Comment: adding link to xmllite and minixml
Yagmoth555 edited Revision 4. Comment: added some link for base64 function, and corrected some typos
Yagmoth555 edited Revision 2. Comment: edited: removed again some typos..
Yagmoth555 edited Revision 1. Comment: edited: corrected the two aref, in a <li> it was not displaying ok
Yagmoth555 edited Original. Comment: edited: corrected some typos