- Add implementation of the NSPI Referral protocol (exchangeRFR)
authorJulien Kerihuel <j.kerihuel@openchange.org>
Tue, 26 Aug 2008 14:38:03 +0000 (14:38 +0000)
committerJulien Kerihuel <j.kerihuel@openchange.org>
Tue, 26 Aug 2008 14:38:03 +0000 (14:38 +0000)
- update dcesrv_exchange and mapiproxy prototypes for RFR
- add references to the RFR pipe in mapiproxy
- prefix NSPI client connections with a RfrGetNewDSA call
- add RFR functions implementation in libmapi/IMSProvider.c
- add a --getfqdn option to mapiprofile
- fix a minor mapiprofile option parsing bug

exchange.idl
libmapi/IMSProvider.c
libmapi/cdo_mapi.c
mapiproxy/dcesrv_mapiproxy.c
mapiproxy/dcesrv_mapiproxy_proto.h
mapiproxy/dcesrv_mapiproxy_unused.c
server/dcesrv_exchange.c
server/dcesrv_exchange.h
utils/mapiprofile.c

index a27393c5890570bb6467dc4fe26a552e1d30886e..1a5d996d9e32f45b68a76bb16b356a6894cf748e 100644 (file)
@@ -40,18 +40,33 @@ import "misc.idl";
 
 [
   uuid("1544f5e0-613c-11d1-93df-00c04fd7bd09"),
+  endpoint("ncacn_np:[\\pipe\\lsass]","ncacn_np:[\\pipe\\protected_storage]","ncacn_ip_tcp:[]"),
   pointer_default(unique),
   version(1.0),
   helpstring("Exchange 2003 Directory Request For Response")
 ] interface exchange_ds_rfr
 {
+
+#include "mapitags_enum.h"
+#include "mapicodes_enum.h"
+
        /*****************/
        /* Function 0x00 */
-       void RfrGetNewDSA();
-
+       MAPISTATUS RfrGetNewDSA(
+               [in]                                    uint32  ulFlags,
+               [in,string,charset(DOS)]                uint8   *pUserDN,
+               [in,out,unique,string,charset(DOS)]     uint8   **ppszUnused,
+               [in,out,unique,string,charset(DOS)]     uint8   **ppszServer
+               );
+       
        /*****************/
        /* Function 0x01 */
-       void RfrGetFQDNFromLegacyDN();
+       MAPISTATUS RfrGetFQDNFromLegacyDN(
+               [in]                                                    uint32  ulFlags,
+               [in,range(10,1024)]                                     uint32  cbMailboxServerDN,
+               [in,string,charset(DOS),size_is(cbMailboxServerDN)]     uint8   *szMailboxServerDN,
+               [out,ref,string,charset(DOS)]                           uint8   **ppszServerFQDN
+               );
 }
 
 [
@@ -170,9 +185,6 @@ System Attendant Private Interface
 ] interface exchange_nsp
 {
 
-#include "mapitags_enum.h"
-#include "mapicodes_enum.h"
-
        /*****************/
        /* Function 0x00 */
 
index 8925ff8d5e8730d58012510750b4ff7254b9ee8e..53877946c05f5517f9dfcb11d7c1af1605b23234 100644 (file)
@@ -21,6 +21,7 @@
 #include <libmapi/mapicode.h>
 #include <libmapi/proto_private.h>
 #include <gen_ndr/ndr_exchange.h>
+#include <gen_ndr/ndr_exchange_c.h>
 #include <core/error.h>
 #include <param.h>
 #include <credentials.h>
@@ -68,28 +69,112 @@ static NTSTATUS provider_rpc_connection(TALLOC_CTX *parent_ctx,
        return status;
 }
 
-enum MAPISTATUS Logon(struct mapi_provider *provider, enum PROVIDER_ID provider_id)
+
+/**
+   \details Returns the name of an NSPI server
+
+   \param server the Exchange server address (IP or FQDN)
+   \param userDN optional user mailbox DN
+
+   \return a valid string on success, otherwise NULL
+ */
+_PUBLIC_ const char *RfrGetNewDSA(const char *server, const char *userDN)
 {
        NTSTATUS                status;
        TALLOC_CTX              *mem_ctx;
-       struct dcerpc_pipe      *pipe;
        struct mapi_profile     *profile;
+       struct RfrGetNewDSA     r;
+       struct dcerpc_pipe      *pipe;
        char                    *binding;
+       const char              *ppszServer = NULL;
+
+       /* Sanity Checks */
+       if (!global_mapi_ctx) return server;
+       if (!global_mapi_ctx->session) return server;
+
+       mem_ctx = (TALLOC_CTX *)global_mapi_ctx->session;
+       profile = global_mapi_ctx->session->profile;
 
+       binding = talloc_asprintf(mem_ctx, "ncacn_ip_tcp:%s%s", server, ((global_mapi_ctx->dumpdata == true) ? "[print]" : "[]"));
+       status = provider_rpc_connection(mem_ctx, &pipe, binding, profile->credentials, &ndr_table_exchange_ds_rfr, global_mapi_ctx->lp_ctx);
+       talloc_free(binding);
+
+       r.in.ulFlags = 0x0;
+       r.in.pUserDN = userDN ? userDN : "";
+       r.in.ppszUnused = NULL;
+       r.in.ppszServer = &ppszServer;
+
+       status = dcerpc_RfrGetNewDSA(pipe, mem_ctx, &r);
+       if (!NT_STATUS_IS_OK(status)) return server;
+
+       return (ppszServer ? ppszServer : server);
+}
+
+
+/**
+   \details Returns the FQDN of the NSPI server corresponding to a DN
+
+   \param pointer on pointer on the server FQDN returned
+
+   \return MAPI_E_SUCCESS on success, otherwise a MAPI error and
+   serverFQDN content set to NULL.
+ */
+_PUBLIC_ enum MAPISTATUS RfrGetFQDNFromLegacyDN(const char **serverFQDN)
+{
+       NTSTATUS                        status;
+       TALLOC_CTX                      *mem_ctx;
+       struct mapi_profile             *profile;
+       struct RfrGetFQDNFromLegacyDN   r;
+       struct dcerpc_pipe              *pipe;
+       char                            *binding;
+       const char                      *ppszServerFQDN;
+
+       /* Sanity Checks */
        MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
        MAPI_RETVAL_IF(!global_mapi_ctx->session, MAPI_E_NOT_INITIALIZED, NULL);
 
-       mem_ctx = (TALLOC_CTX *)provider;
+       mem_ctx = (TALLOC_CTX *)global_mapi_ctx->session;
        profile = global_mapi_ctx->session->profile;
+       *serverFQDN = NULL;
+
+       binding = talloc_asprintf(mem_ctx, "ncacn_ip_tcp:%s%s", profile->server, ((global_mapi_ctx->dumpdata == true) ? "[print]" : "[]"));
+       status = provider_rpc_connection(mem_ctx, &pipe, binding, profile->credentials, &ndr_table_exchange_ds_rfr, global_mapi_ctx->lp_ctx);
+       talloc_free(binding);
+
+       r.in.ulFlags = 0x0;
+       r.in.cbMailboxServerDN = strlen(profile->homemdb) + 1;
+       r.in.szMailboxServerDN = profile->homemdb;
+       r.out.ppszServerFQDN = &ppszServerFQDN;
+
+       status = dcerpc_RfrGetFQDNFromLegacyDN(pipe, mem_ctx, &r);
+       MAPI_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
        
-       if (global_mapi_ctx->dumpdata == false) {
-               binding = talloc_asprintf(mem_ctx, "ncacn_ip_tcp:%s", profile->server);
+       if (ppszServerFQDN) {
+               *serverFQDN = ppszServerFQDN;
        } else {
-               binding = talloc_asprintf(mem_ctx, "ncacn_ip_tcp:%s[print]", profile->server);
+               *serverFQDN = NULL;
        }
 
+       return MAPI_E_SUCCESS;
+}
+
+enum MAPISTATUS Logon(struct mapi_provider *provider, enum PROVIDER_ID provider_id)
+{
+       NTSTATUS                status;
+       TALLOC_CTX              *mem_ctx;
+       struct dcerpc_pipe      *pipe;
+       struct mapi_profile     *profile;
+       char                    *binding;
+
+       MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
+       MAPI_RETVAL_IF(!global_mapi_ctx->session, MAPI_E_NOT_INITIALIZED, NULL);
+
+       mem_ctx = (TALLOC_CTX *)provider;
+       profile = global_mapi_ctx->session->profile;
+       
        switch(provider_id) {
        case PROVIDER_ID_EMSMDB:
+               binding = talloc_asprintf(mem_ctx, "ncacn_ip_tcp:%s%s", profile->server, ((global_mapi_ctx->dumpdata == true) ? "[print]" : "[]"));
                status = provider_rpc_connection(mem_ctx, &pipe, binding, profile->credentials, &ndr_table_exchange_emsmdb, global_mapi_ctx->lp_ctx);
                talloc_free(binding);
                MAPI_RETVAL_IF(NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED), MAPI_E_NETWORK_ERROR, NULL);
@@ -101,6 +186,9 @@ enum MAPISTATUS Logon(struct mapi_provider *provider, enum PROVIDER_ID provider_
                MAPI_RETVAL_IF(!provider->ctx, MAPI_E_LOGON_FAILED, NULL);
                break;
        case PROVIDER_ID_NSPI:
+               /* Call RfrGetNewDSA prior any NSPI call */
+               binding = talloc_asprintf(mem_ctx, "ncacn_ip_tcp:%s%s", RfrGetNewDSA(profile->server, profile->mailbox), 
+                                         ((global_mapi_ctx->dumpdata == true) ? "[print]" : "[]"));
                status = provider_rpc_connection(mem_ctx, &pipe, binding, profile->credentials, &ndr_table_exchange_nsp, global_mapi_ctx->lp_ctx);
                talloc_free(binding);
                MAPI_RETVAL_IF(NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_REFUSED), MAPI_E_NETWORK_ERROR, NULL);
index 0b602d41abac88d06b2ea7bbb2c5f3d7bdb0ea07..074a8bf35f2b9bf11ed5ea139848a9b26f7099c3 100644 (file)
@@ -114,6 +114,7 @@ _PUBLIC_ enum MAPISTATUS MapiLogonProvider(struct mapi_session **session,
 
 
        MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
+       MAPI_RETVAL_IF(!session, MAPI_E_NOT_INITIALIZED, NULL);
 
        /* allocate session if it doesn't already exist */
        if (!*session || !global_mapi_ctx->session) {
index 444ee0e96cd812b23b82fdb84efa59af196246e1..03bed7a590a779641652686679df197db13546c1 100644 (file)
@@ -475,6 +475,9 @@ NTSTATUS samba_init_module(void)
        status = dcerpc_server_exchange_nsp_init();
        NT_STATUS_NOT_OK_RETURN(status);
 
+       status = dcerpc_server_exchange_ds_rfr_init();
+       NT_STATUS_NOT_OK_RETURN(status);
+
        /* Step2. Register Exchange ndr tables */
        status = ndr_table_register(&ndr_table_exchange_emsmdb);
        NT_STATUS_NOT_OK_RETURN(status);
@@ -482,6 +485,9 @@ NTSTATUS samba_init_module(void)
        status = ndr_table_register(&ndr_table_exchange_nsp);
        NT_STATUS_NOT_OK_RETURN(status);
 
+       status = ndr_table_register(&ndr_table_exchange_ds_rfr);
+       NT_STATUS_NOT_OK_RETURN(status);
+
        /* Step3. Finally register mapiproxy endpoint */
        status = dcerpc_server_mapiproxy_init();
        NT_STATUS_NOT_OK_RETURN(status);
index acabd69e4f2bee20083c9c9b6ebb286e7564adaf..7e3a660a67d7a79416bd10d8a71cd60ec51107dd 100644 (file)
@@ -72,8 +72,8 @@ const struct ndr_interface_table      *ndr_table_by_name(const char *);
 void dcesrv_ec_store_admin3_dummy(struct dcesrv_call_state *, TALLOC_CTX *,struct ec_store_admin3_dummy *);
 void dcesrv_ec_store_admin2_dummy(struct dcesrv_call_state *, TALLOC_CTX *,struct ec_store_admin2_dummy *);
 void dcesrv_ec_store_admin1_dummy(struct dcesrv_call_state *, TALLOC_CTX *,struct ec_store_admin1_dummy *);
-void dcesrv_RfrGetNewDSA(struct dcesrv_call_state *, TALLOC_CTX *,struct RfrGetNewDSA *);
-void dcesrv_RfrGetFQDNFromLegacyDN(struct dcesrv_call_state *, TALLOC_CTX *,struct RfrGetFQDNFromLegacyDN *);
+enum MAPISTATUS dcesrv_RfrGetNewDSA(struct dcesrv_call_state *, TALLOC_CTX *,struct RfrGetNewDSA *);
+enum MAPISTATUS dcesrv_RfrGetFQDNFromLegacyDN(struct dcesrv_call_state *, TALLOC_CTX *,struct RfrGetFQDNFromLegacyDN *);
 void dcesrv_sysatt_cluster_dummy(struct dcesrv_call_state *, TALLOC_CTX *,struct sysatt_cluster_dummy *);
 void dcesrv_sysatt_dummy(struct dcesrv_call_state *, TALLOC_CTX *,struct sysatt_dummy *);
 void dcesrv_MtaBind(struct dcesrv_call_state *, TALLOC_CTX *,struct MtaBind *);
index 7c3eeccb2571b2ae65f2bdb5d31130db868093a2..a09531ab0c9aeba7da53a7c5e615a659904214d5 100644 (file)
@@ -74,20 +74,20 @@ void dcesrv_ec_store_admin1_dummy(struct dcesrv_call_state *dce_call, TALLOC_CTX
 /*
   RfrGetNewDSA
 */
-void dcesrv_RfrGetNewDSA(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct RfrGetNewDSA *r)
+enum MAPISTATUS dcesrv_RfrGetNewDSA(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                                   struct RfrGetNewDSA *r)
 {
-       DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
 }
 
 
 /*
   RfrGetFQDNFromLegacyDN
 */
-void dcesrv_RfrGetFQDNFromLegacyDN(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct RfrGetFQDNFromLegacyDN *r)
+enum MAPISTATUS dcesrv_RfrGetFQDNFromLegacyDN(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                                             struct RfrGetFQDNFromLegacyDN *r)
 {
-       DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
 }
 
 /*
index 822f42948494a9c342de66283e7fb39b3bf158dc..51fa91eddd44f5e588cf6cfc31dc122da57f6b23 100644 (file)
@@ -88,20 +88,20 @@ void dcesrv_ec_store_admin1_dummy(struct dcesrv_call_state *dce_call, TALLOC_CTX
 /*
   RfrGetNewDSA
 */
-void dcesrv_RfrGetNewDSA(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct RfrGetNewDSA *r)
+enum MAPISTATUS dcesrv_RfrGetNewDSA(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                                   struct RfrGetNewDSA *r)
 {
-       DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
 }
 
 
 /*
   RfrGetFQDNFromLegacyDN
 */
-void dcesrv_RfrGetFQDNFromLegacyDN(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct RfrGetFQDNFromLegacyDN *r)
+enum MAPISTATUS dcesrv_RfrGetFQDNFromLegacyDN(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                                             struct RfrGetFQDNFromLegacyDN *r)
 {
-       DCESRV_FAULT_VOID(DCERPC_FAULT_OP_RNG_ERROR);
+       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
 }
 
 /*
index bee1174ca9ee4d563e15fd75b9b5c8fa10ef5a3a..f5782c2553f0df4309b561c918f978d1ceddc9b6 100644 (file)
@@ -139,10 +139,10 @@ void dcesrv_ec_store_admin2_dummy(struct dcesrv_call_state *dce_call, TALLOC_CTX
                       struct ec_store_admin2_dummy *r);
 void dcesrv_ec_store_admin1_dummy(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct ec_store_admin1_dummy *r);
-void dcesrv_RfrGetNewDSA(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct RfrGetNewDSA *r);
-void dcesrv_RfrGetFQDNFromLegacyDN(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct RfrGetFQDNFromLegacyDN *r);
+enum MAPISTATUS dcesrv_RfrGetNewDSA(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                                   struct RfrGetNewDSA *r);
+enum MAPISTATUS dcesrv_RfrGetFQDNFromLegacyDN(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                                             struct RfrGetFQDNFromLegacyDN *r);
 void dcesrv_sysatt_cluster_dummy(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
                       struct sysatt_cluster_dummy *r);
 void dcesrv_sysatt_dummy(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
index b511ca5587942d65ceb70da6890c52055d53ded4..00292703ba577a6f5559487f653a1572e08c6190 100644 (file)
@@ -118,7 +118,6 @@ static void mapiprofile_create(const char *profdb, const char *profname,
        }
 
        if (opt_dumpdata == true) {
-               printf("dumpdata is true\n");
                global_mapi_ctx->dumpdata = true;
        }
 
@@ -247,13 +246,55 @@ static void mapiprofile_get_default(const char *profdb)
        MAPIUninitialize();
 }
 
+static void mapiprofile_get_fqdn(const char *profdb, 
+                                const char *profname, 
+                                const char *password,
+                                bool opt_dumpdata)
+{
+       enum MAPISTATUS         retval;
+       struct mapi_session     *session;
+       const char              *serverFQDN;
+
+       if ((retval = MAPIInitialize(profdb)) != MAPI_E_SUCCESS) {
+               mapi_errstr("MAPIInitialize", GetLastError());
+               exit (1);
+       }
+
+       if (opt_dumpdata == true) {
+               global_mapi_ctx->dumpdata = true;
+       }
+
+       if (!profname) {
+               if ((retval = GetDefaultProfile(&profname)) != MAPI_E_SUCCESS) {
+                       mapi_errstr("GetDefaultProfile", GetLastError());
+                       exit (1);
+               }
+       }
+
+       retval = MapiLogonProvider(&session, profname, password, PROVIDER_ID_NSPI);
+       if (retval != MAPI_E_SUCCESS) {
+               mapi_errstr("MapiLogonProvider", GetLastError());
+               exit (1);
+       }
+
+       retval = RfrGetFQDNFromLegacyDN(&serverFQDN);
+       if (retval != MAPI_E_SUCCESS) {
+               mapi_errstr("RfrGetFQDNFromLegacyDN", GetLastError());
+               exit (1);
+       }
+
+       printf("%s is at %s\n", global_mapi_ctx->session->profile->homemdb, serverFQDN);
+
+       MAPIUninitialize();
+}
+
 static void mapiprofile_list(const char *profdb)
 {
        enum MAPISTATUS retval;
        struct SRowSet  proftable;
        uint32_t        count = 0;
 
-       if ((retval = MAPIInitialize(profdb))) {
+       if ((retval = MAPIInitialize(profdb)) != MAPI_E_SUCCESS) {
                mapi_errstr("MAPIInitialize", GetLastError());
                exit (1);
        }
@@ -381,6 +422,7 @@ int main(int argc, const char *argv[])
        bool            newdb = false;
        bool            setdflt = false;
        bool            getdflt = false;
+       bool            getfqdn = false;
        bool            opt_dumpdata = false;
        const char      *ldif = NULL;
        const char      *address = NULL;
@@ -400,7 +442,7 @@ int main(int argc, const char *argv[])
              OPT_DOMAIN, OPT_USERNAME, OPT_LCID, OPT_PASSWORD, OPT_CREATE_PROFILE, 
              OPT_DELETE_PROFILE, OPT_LIST_PROFILE, OPT_DUMP_PROFILE, 
              OPT_DUMP_ATTR, OPT_PROFILE_NEWDB, OPT_PROFILE_LDIF, OPT_LIST_LANGS,
-             OPT_PROFILE_SET_DFLT, OPT_PROFILE_GET_DFLT, OPT_PATTERN,
+             OPT_PROFILE_SET_DFLT, OPT_PROFILE_GET_DFLT, OPT_PATTERN, OPT_GETFQDN,
              OPT_NOPASS, OPT_DUMPDATA};
 
        struct poptOption long_options[] = {
@@ -426,6 +468,7 @@ int main(int argc, const char *argv[])
                {"dump", 'd', POPT_ARG_NONE, NULL, OPT_DUMP_PROFILE, "dump a profile entry"},
                {"attr", 'a', POPT_ARG_STRING, NULL, OPT_DUMP_ATTR, "print an attribute value"},
                {"dump-data", 0, POPT_ARG_NONE, NULL, OPT_DUMPDATA, "dump the hex data"},
+               {"getfqdn", 0, POPT_ARG_NONE, NULL, OPT_GETFQDN, "returns the DNS FQDN of the NSPI server matching the legacyDN"},
                { NULL }
        };
 
@@ -437,6 +480,7 @@ int main(int argc, const char *argv[])
                switch(opt) {
                case OPT_DUMPDATA:
                        opt_dumpdata = true;
+                       break;
                case OPT_PROFILE_LDIF:
                        ldif = poptGetOptArg(pc);
                        break;
@@ -497,6 +541,9 @@ int main(int argc, const char *argv[])
                case OPT_DUMP_ATTR:
                        attribute = poptGetOptArg(pc);
                        break;
+               case OPT_GETFQDN:
+                       getfqdn = true;
+                       break;
                }
        }
 
@@ -514,7 +561,7 @@ int main(int argc, const char *argv[])
                                         getenv("HOME"));
        }
 
-       if ((list == false) && (newdb == false) && (listlangs == false)
+       if ((list == false) && (getfqdn == false) && (newdb == false) && (listlangs == false)
            && (getdflt == false) && (dump == false) && 
            (!attribute) && (!profname || !profdb)) {
                poptPrintUsage(pc, stderr, 0);
@@ -551,6 +598,10 @@ int main(int argc, const char *argv[])
                                   lcid, workstation, domain, nopass, opt_dumpdata);
        }
 
+       if (getfqdn == true) {
+               mapiprofile_get_fqdn(profdb, profname, password, opt_dumpdata);
+       }
+
        if (listlangs == true) {
                lcid_print_languages();
        }