clean:: mapiproxy-servers-clean
mapiproxy/servers/exchange_nsp.$(SHLIBEXT): mapiproxy/servers/default/nspi/dcesrv_exchange_nsp.po \
- mapiproxy/servers/default/nspi/emsabp.po
+ mapiproxy/servers/default/nspi/emsabp.po \
+ mapiproxy/servers/default/nspi/emsabp_tdb.po
@echo "Linking $@"
@$(CC) -o $@ $(DSOOPT) $^ -L. $(LIBS) -Lmapiproxy mapiproxy/libmapiproxy.$(SHLIBEXT).$(PACKAGE_VERSION) libmapi.$(SHLIBEXT).$(PACKAGE_VERSION)
case PT_STRING8:
case PT_UNICODE:
data = get_SPropValue_data(&lpProp);
- printf("%s%s: %s\n", sep?sep:"", proptag, (const char *)data);
+ printf("%s%s: %s\n", sep?sep:"", proptag, (data && (uint32_t)data != MAPI_E_NOT_FOUND) ? (const char *)data : "NULL");
break;
case PT_SYSTIME:
mapidump_date_SPropValue(lpProp, proptag);
data = get_SPropValue_data(&lpProp);
printf("%s%s: %u\n", sep?sep:"", proptag, (*(const uint32_t *)data));
break;
+ case PT_BINARY:
+ data = get_SPropValue_data(&lpProp);
+ printf("%s%s\n", sep?sep:"", proptag);
+ dump_data(0, ((const struct Binary_r *)data)->lpb, ((const struct Binary_r *)data)->cb);
+ break;
case PT_MV_STRING8:
StringArray_r = (const struct StringArray_r *) get_SPropValue_data(&lpProp);
printf("%s%s: ", sep?sep:"", proptag);
int num_server_modules;
static struct mapiproxy_module_list *server_list = NULL;
+static TDB_CONTEXT *emsabp_tdb_ctx = NULL;
+
NTSTATUS mapiproxy_server_dispatch(struct dcesrv_call_state *dce_call,
TALLOC_CTX *mem_ctx, void *r,
return NULL;
}
+
+
+/**
+ \details Initialize an EMSABP TDB context available to all
+ instances when Samba is not run in single mode.
+
+ \param mem_ctx pointer to the memory context
+ \param lp_ctx pointer to the loadparm context
+
+ \note TDB database can't be opened twice with O_RDWR flags. We
+ ensure here we have a general context initialized, which we'll
+ reopen within forked instances
+
+ return Allocated TDB context on success, otherwise NULL
+ */
+_PUBLIC_ TDB_CONTEXT *mapiproxy_server_emsabp_tdb_init(struct loadparm_context *lp_ctx)
+{
+ char *tdb_path;
+ TALLOC_CTX *mem_ctx;
+
+ if (emsabp_tdb_ctx) return emsabp_tdb_ctx;
+
+ mem_ctx = talloc_init("mapiproxy_server_emsabp_tdb_init");
+ if (!mem_ctx) return NULL;
+
+ /* Step 0. Retrieve a TDB context pointer on the emsabp_tdb database */
+ tdb_path = talloc_asprintf(mem_ctx, "%s/%s", lp_private_dir(lp_ctx), EMSABP_TDB_NAME);
+ emsabp_tdb_ctx = tdb_open(tdb_path, 0, 0, O_RDWR|O_CREAT, 0600);
+ talloc_free(tdb_path);
+ if (!emsabp_tdb_ctx) {
+ DEBUG(3, ("[%s:%d]: %s\n", __FUNCTION__, __LINE__, strerror(errno)));
+ talloc_free(mem_ctx);
+ return NULL;
+ }
+
+ talloc_free(mem_ctx);
+
+ return emsabp_tdb_ctx;
+}
#include <dcerpc_server.h>
#include <talloc.h>
#include <tevent.h>
+#include <tdb.h>
#include <libmapi/dlinklist.h>
+#include <fcntl.h>
+#include <errno.h>
struct mapiproxy {
bool norelay;
};
+/**
+ EMSABP server defines
+ */
+#define EMSABP_TDB_NAME "emsabp_tdb.tdb"
+
+
#define NTLM_AUTH_IS_OK(dce_call) \
(dce_call->conn->auth_state.session_info->server_info->authenticated == true)
const struct mapiproxy_module *mapiproxy_server_bystatus(const char *, enum mapiproxy_status);
const struct mapiproxy_module *mapiproxy_server_byname(const char *);
+TDB_CONTEXT *mapiproxy_server_emsabp_tdb_init(struct loadparm_context *);
/* definitions from dcesrv_mapiproxy_session. c */
struct mpm_session *mpm_session_new(TALLOC_CTX *, struct server_id, uint32_t);
#include "dcesrv_exchange_nsp.h"
struct exchange_nsp_session *nsp_session = NULL;
+TDB_CONTEXT *emsabp_tdb_ctx = NULL;
/**
\details exchange_nsp NspiBind (0x0) function, Initiates a NSPI
}
/* Step 1. Initialize the emsabp context */
- emsabp_ctx = emsabp_init(dce_call->conn->dce_ctx->lp_ctx);
- OPENCHANGE_RETVAL_IF(!emsabp_ctx, MAPI_E_FAILONEPROVIDER, NULL);
+ emsabp_ctx = emsabp_init(dce_call->conn->dce_ctx->lp_ctx, emsabp_tdb_ctx);
+ if (!emsabp_ctx) {
+ smb_panic("unable to initialize emsabp context");
+ OPENCHANGE_RETVAL_IF(!emsabp_ctx, MAPI_E_FAILONEPROVIDER, NULL);
+ }
/* Step 2. Check if incoming user belongs to the Exchange organization */
if (emsabp_verify_user(dce_call, emsabp_ctx) == false) {
\param mem_ctx pointer to the memory context
\param r pointer to the NspiGetSpecialTable request data
+ \note MS-NSPI specifies lpVersion "holds the value of the version
+ number of the hierarchy table that the client has." We will ignore
+ this for the moment.
+
\return MAPI_E_SUCCESS on success
*/
TALLOC_CTX *mem_ctx,
struct NspiGetSpecialTable *r)
{
- DEBUG(3, ("exchange_nsp: NspiGetSpecialTable (0xC) not implemented\n"));
- DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+ struct dcesrv_handle *h;
+ struct emsabp_context *emsabp_ctx;
+
+ DEBUG(3, ("exchange_nsp: NspiGetSpecialTable (0xC)\n"));
+
+ /* Step 0. Ensure incoming user is authenticated */
+ if (!NTLM_AUTH_IS_OK(dce_call)) {
+ DEBUG(1, ("No challenge requested by client, cannot authenticate\n"));
+ return MAPI_E_LOGON_FAILED;
+ }
+
+ h = dcesrv_handle_fetch(dce_call->context, r->in.handle, DCESRV_HANDLE_ANY);
+ emsabp_ctx = (struct emsabp_context *) h->data;
+
+ /* Step 1. (FIXME) We arbitrary set lpVersion to 0x1 */
+ r->out.lpVersion = talloc_zero(mem_ctx, uint32_t);
+ *r->out.lpVersion = 0x1;
+
+ /* Step 2. Allocate output SRowSet and call associated emsabp function */
+ r->out.ppRows = talloc_zero(mem_ctx, struct SRowSet *);
+ OPENCHANGE_RETVAL_IF(!r->out.ppRows, MAPI_E_NOT_ENOUGH_RESOURCES, NULL);
+ r->out.ppRows[0] = talloc_zero(mem_ctx, struct SRowSet);
+ OPENCHANGE_RETVAL_IF(!r->out.ppRows[0], MAPI_E_NOT_ENOUGH_RESOURCES, NULL);
+
+ switch (r->in.dwFlags) {
+ case NspiAddressCreationTemplates:
+ case NspiAddressCreationTemplates|NspiUnicodeStrings:
+ DEBUG(0, ("CreationTemplates Table requested\n"));
+ r->out.result = emsabp_get_CreationTemplatesTable(mem_ctx, emsabp_ctx, r->in.dwFlags, r->out.ppRows);
+ break;
+ case NspiUnicodeStrings:
+ case 0x0:
+ DEBUG(0, ("Hierarchy Table requested\n"));
+ r->out.result = emsabp_get_HierarchyTable(mem_ctx, emsabp_ctx, r->in.dwFlags, r->out.ppRows);
+ break;
+ default:
+ talloc_free(r->out.ppRows);
+ talloc_free(r->out.ppRows[0]);
+ return MAPI_E_NO_SUPPORT;
+ }
+
+ return r->out.result;
}
if (!nsp_session) return NT_STATUS_NO_MEMORY;
nsp_session->session = NULL;
+ /* Open a read-write pointer on the EMSABP TDB database */
+ emsabp_tdb_ctx = emsabp_tdb_init((TALLOC_CTX *)dce_ctx, dce_ctx->lp_ctx);
+ if (!emsabp_tdb_ctx) {
+ smb_panic("unable to initialize EMSABP context");
+ }
+
return NT_STATUS_OK;
}
#include <libmapi/libmapi.h>
#include <libmapi/proto_private.h>
+#include <mapiproxy/libmapiproxy.h>
+#include <ldb.h>
+#include <ldb_errors.h>
+#include <fcntl.h>
#include <util/debug.h>
#ifndef __BEGIN_DECLS
void *conf_ctx;
void *users_ctx;
void *ldb_ctx;
+ TDB_CONTEXT *tdb_ctx;
TALLOC_CTX *mem_ctx;
};
};
+/**
+ Represents the NSPI Protocol in Permanent Entry IDs.
+ */
+static const uint8_t GUID_NSPI[] = {
+0xDC, 0xA7, 0x40, 0xC8, 0xC0, 0x42, 0x10, 0x1A, 0xB4, 0xB9,
+0x08, 0x00, 0x2B, 0x2F, 0xE1, 0x82
+};
+
+
+/**
+ PermanentEntryID structure
+ */
+struct PermanentEntryID {
+ uint8_t ID_type; /* constant: 0x0 */
+ uint8_t R1; /* reserved: 0x0 */
+ uint8_t R2; /* reserved: 0x0 */
+ uint8_t R3; /* reserved: 0x0 */
+ struct FlatUID_r ProviderUID; /* constant: GUID_NSPI */
+ uint32_t R4; /* constant: 0x1 */
+ uint32_t DisplayType; /* must match one of the existing Display Type value */
+ char *dn; /* DN string representing the object GUID */
+};
+
+
+/**
+ EphemeralEntryID structure
+ */
+struct EphemeralEntryID {
+ uint8_t ID_type; /* constant: 0x87 */
+ uint8_t R1; /* reserved: 0x0 */
+ uint8_t R2; /* reserved: 0x0 */
+ uint8_t R3; /* reserved: 0x0 */
+ struct FlatUID_r ProviderUID; /* NSPI server GUID */
+ uint32_t R4; /* constant: 0x1 */
+ uint32_t DisplayType; /* must match one of the existing Display Type value */
+ uint32_t MId; /* MId of this object */
+};
+
+#define EMSABP_DN "/guid=%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X"
+
+/**
+ NSPI PR_CONTAINER_FLAGS values
+ */
+#define AB_RECIPIENTS 0x1
+#define AB_SUBCONTAINERS 0x2
+#define AB_UNMODIFIABLE 0x8
+
+#define EMSABP_TDB_MID_START 0x1b28
+#define EMSABP_TDB_DATA_REC "MId_index"
+
__BEGIN_DECLS
NTSTATUS samba_init_module(void);
/* definitions from emsabp.c */
-struct emsabp_context *emsabp_init(struct loadparm_context *);
+struct emsabp_context *emsabp_init(struct loadparm_context *, TDB_CONTEXT *);
bool emsabp_destructor(void *);
bool emsabp_verify_user(struct dcesrv_call_state *, struct emsabp_context *);
bool emsabp_verify_codepage(struct loadparm_context *, struct emsabp_context *, uint32_t);
bool emsabp_verify_lcid(struct loadparm_context *, struct emsabp_context *, uint32_t);
struct GUID *emsabp_get_server_GUID(struct loadparm_context *, struct emsabp_context *);
+enum MAPISTATUS emsabp_set_EphemeralEntryID(struct loadparm_context *, struct emsabp_context *, uint32_t, uint32_t, struct EphemeralEntryID *);
+enum MAPISTATUS emsabp_set_PermanentEntryID(struct emsabp_context *, uint32_t, struct ldb_message *, struct PermanentEntryID *);
+enum MAPISTATUS emsabp_PermanentEntryID_to_Binary_r(TALLOC_CTX *, struct PermanentEntryID *, struct Binary_r *);
+enum MAPISTATUS emsabp_get_HierarchyTable(TALLOC_CTX *, struct emsabp_context *, uint32_t, struct SRowSet **);
+enum MAPISTATUS emsabp_get_CreationTemplatesTable(TALLOC_CTX *, struct emsabp_context *, uint32_t, struct SRowSet **);
+enum MAPISTATUS emsabp_table_fetch_attrs(TALLOC_CTX *, struct emsabp_context *, struct SRow *, uint32_t, struct PermanentEntryID *,
+ struct PermanentEntryID *, struct ldb_message *, bool);
+
+/* definitiosn from emsabp_tdb.c */
+TDB_CONTEXT *emsabp_tdb_init(TALLOC_CTX *, struct loadparm_context *);
+enum MAPISTATUS emsabp_tdb_close(TDB_CONTEXT *);
+enum MAPISTATUS emsabp_tdb_fetch(TDB_CONTEXT *, const char *, TDB_DATA *);
+enum MAPISTATUS emsabp_tdb_insert(TDB_CONTEXT *, const char *);
+enum MAPISTATUS emsabp_tdb_fetch_MId(TDB_CONTEXT *, const char *, uint32_t *);
__END_DECLS
Samba databases.
\param lp_ctx pointer to the loadparm context
+ \param tdb_ctx pointer to the EMSABP TDB context
\return Allocated emsabp_context on success, otherwise NULL
*/
-_PUBLIC_ struct emsabp_context *emsabp_init(struct loadparm_context *lp_ctx)
+_PUBLIC_ struct emsabp_context *emsabp_init(struct loadparm_context *lp_ctx,
+ TDB_CONTEXT *tdb_ctx)
{
TALLOC_CTX *mem_ctx;
struct emsabp_context *emsabp_ctx;
return NULL;
}
+ /* Reference the global TDB context to the current emsabp context */
+ emsabp_ctx->tdb_ctx = tdb_ctx;
+
return emsabp_ctx;
}
return guid;
}
+
+
+/**
+ \details Build an EphemeralEntryID structure
+
+ \param lp_ctx pointer to the loadparm context
+ \param emsabp_ctx pointer to the EMSABP context
+ \param DisplayType the AB object display type
+ \param MId the MId value
+ \param ephEntryID pointer to the EphemeralEntryID returned by the
+ function
+
+ \return MAPI_E_SUCCESS on success, otherwise
+ MAPI_E_NOT_ENOUGH_RESOURCES or MAPI_E_CORRUPT_STORE
+ */
+_PUBLIC_ enum MAPISTATUS emsabp_set_EphemeralEntryID(struct loadparm_context *lp_ctx,
+ struct emsabp_context *emsabp_ctx,
+ uint32_t DisplayType, uint32_t MId,
+ struct EphemeralEntryID *ephEntryID)
+{
+ struct GUID *guid = (struct GUID *) NULL;
+
+ /* Sanity checks */
+ OPENCHANGE_RETVAL_IF(!ephEntryID, MAPI_E_NOT_ENOUGH_RESOURCES, NULL);
+
+ guid = emsabp_get_server_GUID(lp_ctx, emsabp_ctx);
+ OPENCHANGE_RETVAL_IF(!guid, MAPI_E_CORRUPT_STORE, NULL);
+
+ ephEntryID->ID_type = 0x87;
+ ephEntryID->R1 = 0x0;
+ ephEntryID->R2 = 0x0;
+ ephEntryID->R3 = 0x0;
+ ephEntryID->ProviderUID.ab[0] = (guid->time_low & 0xFF);
+ ephEntryID->ProviderUID.ab[1] = ((guid->time_low >> 8) & 0xFF);
+ ephEntryID->ProviderUID.ab[2] = ((guid->time_low >> 16) & 0xFF);
+ ephEntryID->ProviderUID.ab[3] = ((guid->time_low >> 24) & 0xFF);
+ ephEntryID->ProviderUID.ab[4] = (guid->time_mid & 0xFF);
+ ephEntryID->ProviderUID.ab[5] = ((guid->time_mid >> 8) & 0xFF);
+ ephEntryID->ProviderUID.ab[6] = (guid->time_hi_and_version & 0xFF);
+ ephEntryID->ProviderUID.ab[7] = ((guid->time_hi_and_version >> 8) & 0xFF);
+ memcpy(ephEntryID->ProviderUID.ab + 8, guid->clock_seq, sizeof (uint8_t) * 2);
+ memcpy(ephEntryID->ProviderUID.ab + 10, guid->node, sizeof (uint8_t) * 6);
+ ephEntryID->R4 = 0x1;
+ ephEntryID->DisplayType = DisplayType;
+ ephEntryID->MId = MId;
+
+ talloc_free(guid);
+
+ return MAPI_E_SUCCESS;
+}
+
+
+/**
+ \details Build a PermanentEntryID structure
+
+ \param emsabp_ctx pointer to the EMSABP context
+ \param DisplayType the AB object display type
+ \param ldb_recipient pointer on the LDB message
+ \param permEntryID pointer to the PermanentEntryID returned by the
+ function
+
+ \return MAPI_E_SUCCESS on success, otherwise
+ MAPI_E_NOT_ENOUGH_RESOURCES or MAPI_E_CORRUPT_STORE
+ */
+_PUBLIC_ enum MAPISTATUS emsabp_set_PermanentEntryID(struct emsabp_context *emsabp_ctx,
+ uint32_t DisplayType, struct ldb_message *msg,
+ struct PermanentEntryID *permEntryID)
+{
+ struct GUID *guid = (struct GUID *) NULL;
+ const char *guid_str;
+
+ /* Sanity checks */
+ OPENCHANGE_RETVAL_IF(!permEntryID, MAPI_E_NOT_ENOUGH_RESOURCES, NULL);
+
+
+ permEntryID->ID_type = 0x0;
+ permEntryID->R1 = 0x0;
+ permEntryID->R2 = 0x0;
+ permEntryID->R3 = 0x0;
+ memcpy(permEntryID->ProviderUID.ab, GUID_NSPI, 16);
+ permEntryID->R4 = 0x1;
+ permEntryID->DisplayType = DisplayType;
+
+ if (!msg) {
+ permEntryID->dn = talloc_strdup(emsabp_ctx->mem_ctx, "/");
+ } else {
+ guid_str = ldb_msg_find_attr_as_string(msg, "objectGUID", NULL);
+ OPENCHANGE_RETVAL_IF(!guid_str, MAPI_E_CORRUPT_STORE, NULL);
+ guid = talloc_zero(emsabp_ctx->mem_ctx, struct GUID);
+ GUID_from_string(guid_str, guid);
+ permEntryID->dn = talloc_asprintf(emsabp_ctx->mem_ctx, EMSABP_DN,
+ guid->time_low, guid->time_mid,
+ guid->time_hi_and_version,
+ guid->clock_seq[0],
+ guid->clock_seq[1],
+ guid->node[0], guid->node[1],
+ guid->node[2], guid->node[3],
+ guid->node[4], guid->node[5]);
+ talloc_free(guid);
+ }
+
+ return MAPI_E_SUCCESS;
+}
+
+
+/**
+ \details Map a PermanentEntryID structure into a SBinary_r
+ structure (for PR_ENTRYID and PR_EMS_AB_PARENT_ENTRYID properties)
+
+ \param mem_ctx pointer to the memory context
+ \param permEntryID pointer to the Permanent EntryID structure
+ \param pointer to the Binary_r structure the server will return
+
+ \return MAPI_E_SUCCESS on success, otherwise MAPI_E_INVALID_PARAMETER
+ */
+_PUBLIC_ enum MAPISTATUS emsabp_PermanentEntryID_to_Binary_r(TALLOC_CTX *mem_ctx,
+ struct PermanentEntryID *permEntryID,
+ struct Binary_r *bin)
+{
+ /* Sanity checks */
+ OPENCHANGE_RETVAL_IF(!permEntryID, MAPI_E_INVALID_PARAMETER, NULL);
+ OPENCHANGE_RETVAL_IF(!bin, MAPI_E_INVALID_PARAMETER, NULL);
+
+ /* Remove const char * size and replace it with effective dn string length */
+ bin->cb = sizeof (*permEntryID) - 4 + strlen(permEntryID->dn) + 1;
+ bin->lpb = talloc_array(mem_ctx, uint8_t, bin->cb);
+
+ /* Copy PermanantEntryID intro bin->lpb */
+ memset(bin->lpb, 0, bin->cb);
+ bin->lpb[0] = permEntryID->ID_type;
+ bin->lpb[1] = permEntryID->R1;
+ bin->lpb[2] = permEntryID->R2;
+ bin->lpb[3] = permEntryID->R3;
+ memcpy(bin->lpb + 4, permEntryID->ProviderUID.ab, 16);
+ bin->lpb[20] = (permEntryID->R4 & 0xFF);
+ bin->lpb[21] = ((permEntryID->R4 >> 8) & 0xFF);
+ bin->lpb[22] = ((permEntryID->R4 >> 16) & 0xFF);
+ bin->lpb[23] = ((permEntryID->R4 >> 24) & 0xFF);
+ bin->lpb[24] = (permEntryID->DisplayType & 0xFF);
+ bin->lpb[25] = ((permEntryID->DisplayType >> 8) & 0xFF);
+ bin->lpb[26] = ((permEntryID->DisplayType >> 16) & 0xFF);
+ bin->lpb[27] = ((permEntryID->DisplayType >> 24) & 0xFF);
+ memcpy(bin->lpb + 28, permEntryID->dn, strlen(permEntryID->dn) + 1);
+
+ return MAPI_E_SUCCESS;
+}
+
+
+/**
+ \details Builds the SRow array entry for the specified table
+ record.
+
+ \param mem_ctx pointer to the memory context
+ \param emsabp_ctx pointer to the EMSABP context
+ \param aRow pointer to the SRow structure where results will be
+ stored
+ \param dwFlags flags controlling whether strings should be unicode
+ encoded or not
+ \param permEntryID pointer to the current record Permanent
+ EntryID
+ \param parentPermEntryID pointer to the parent record Permanent
+ EntryID
+ \param msg pointer to the LDB message for current record
+ \param child boolean value specifying whether current record is
+ root or child within containers hierarchy
+
+ \return MAPI_E_SUCCESS on success, otherwise MAPI error
+ */
+_PUBLIC_ enum MAPISTATUS emsabp_table_fetch_attrs(TALLOC_CTX *mem_ctx, struct emsabp_context *emsabp_ctx,
+ struct SRow *aRow, uint32_t dwFlags,
+ struct PermanentEntryID *permEntryID,
+ struct PermanentEntryID *parentPermEntryID,
+ struct ldb_message *msg, bool child)
+{
+ enum MAPISTATUS retval;
+ struct SPropTagArray *SPropTagArray;
+ struct SPropValue lpProps;
+ uint32_t i;
+ uint32_t containerID = 0;
+ const char *dn = NULL;
+
+ /* Step 1. Build the array of properties to fetch and map */
+ if (child == false) {
+ SPropTagArray = set_SPropTagArray(mem_ctx, 0x6,
+ PR_ENTRYID,
+ PR_CONTAINER_FLAGS,
+ PR_DEPTH,
+ PR_EMS_AB_CONTAINERID,
+ ((dwFlags & NspiUnicodeStrings) ? PR_DISPLAY_NAME_UNICODE : PR_DISPLAY_NAME),
+ PR_EMS_AB_IS_MASTER);
+ } else {
+ SPropTagArray = set_SPropTagArray(mem_ctx, 0x7,
+ PR_ENTRYID,
+ PR_CONTAINER_FLAGS,
+ PR_DEPTH,
+ PR_EMS_AB_CONTAINERID,
+ ((dwFlags & NspiUnicodeStrings) ? PR_DISPLAY_NAME_UNICODE : PR_DISPLAY_NAME),
+ PR_EMS_AB_IS_MASTER,
+ PR_EMS_AB_PARENT_ENTRYID);
+ }
+
+ /* Step 2. Allocate SPropValue array and update SRow cValues field */
+ aRow->ulAdrEntryPad = 0x0;
+ aRow->cValues = 0x0;
+ aRow->lpProps = talloc_zero(mem_ctx, struct SPropValue);
+
+ /* Step 3. Global Address List or real container */
+ if (!msg) {
+ /* Global Address List record is constant */
+ for (i = 0; i < SPropTagArray->cValues; i++) {
+ lpProps.ulPropTag = SPropTagArray->aulPropTag[i];
+ lpProps.dwAlignPad = 0x0;
+
+ switch (SPropTagArray->aulPropTag[i]) {
+ case PR_ENTRYID:
+ emsabp_PermanentEntryID_to_Binary_r(mem_ctx, permEntryID, &(lpProps.value.bin));
+ break;
+ case PR_CONTAINER_FLAGS:
+ lpProps.value.l = AB_RECIPIENTS | AB_UNMODIFIABLE;
+ break;
+ case PR_DEPTH:
+ lpProps.value.l = 0x0;
+ break;
+ case PR_EMS_AB_CONTAINERID:
+ lpProps.value.l = 0x0;
+ break;
+ case PR_DISPLAY_NAME:
+ lpProps.value.lpszA = NULL;
+ break;
+ case PR_DISPLAY_NAME_UNICODE:
+ lpProps.value.lpszW = NULL;
+ break;
+ case PR_EMS_AB_IS_MASTER:
+ lpProps.value.b = false;
+ break;
+ default:
+ break;
+ }
+ SRow_addprop(aRow, lpProps);
+ /* SRow_addprop internals overwrite with MAPI_E_NOT_FOUND when data is NULL */
+ if (SPropTagArray->aulPropTag[i] == PR_DISPLAY_NAME ||
+ SPropTagArray->aulPropTag[i] == PR_DISPLAY_NAME_UNICODE) {
+ aRow->lpProps[aRow->cValues - 1].value.lpszA = NULL;
+ aRow->lpProps[aRow->cValues - 1].value.lpszW = NULL;
+ }
+ }
+ } else {
+ for (i = 0; i < SPropTagArray->cValues; i++) {
+ lpProps.ulPropTag = SPropTagArray->aulPropTag[i];
+ lpProps.dwAlignPad = 0x0;
+
+ switch (SPropTagArray->aulPropTag[i]) {
+ case PR_ENTRYID:
+ emsabp_PermanentEntryID_to_Binary_r(mem_ctx, permEntryID, &(lpProps.value.bin));
+ break;
+ case PR_CONTAINER_FLAGS:
+ switch (child) {
+ case true:
+ lpProps.value.l = AB_RECIPIENTS | AB_SUBCONTAINERS | AB_UNMODIFIABLE;
+ break;
+ case false:
+ lpProps.value.l = AB_RECIPIENTS | AB_UNMODIFIABLE;
+ }
+ break;
+ case PR_DEPTH:
+ switch (child) {
+ case true:
+ lpProps.value.l = 0x1;
+ break;
+ case false:
+ lpProps.value.l = 0x0;
+ break;
+ }
+ break;
+ case PR_EMS_AB_CONTAINERID:
+ dn = ldb_msg_find_attr_as_string(msg, "distinguishedName", NULL);
+ retval = emsabp_tdb_fetch_MId(emsabp_ctx->tdb_ctx, dn, &containerID);
+ if (retval) {
+ retval = emsabp_tdb_insert(emsabp_ctx->tdb_ctx, dn);
+ OPENCHANGE_RETVAL_IF(retval, MAPI_E_CORRUPT_STORE, NULL);
+ retval = emsabp_tdb_fetch_MId(emsabp_ctx->tdb_ctx, dn, &containerID);
+ OPENCHANGE_RETVAL_IF(retval, MAPI_E_CORRUPT_STORE, NULL);
+ }
+ lpProps.value.l = containerID;
+ break;
+ case PR_DISPLAY_NAME:
+ lpProps.value.lpszA = talloc_strdup(mem_ctx, ldb_msg_find_attr_as_string(msg, "displayName", NULL));
+ if (!lpProps.value.lpszA) {
+ lpProps.ulPropTag &= 0xFFFF0000;
+ lpProps.ulPropTag += PT_ERROR;
+ }
+ break;
+ case PR_DISPLAY_NAME_UNICODE:
+ lpProps.value.lpszW = talloc_strdup(mem_ctx, ldb_msg_find_attr_as_string(msg, "displayName", NULL));
+ if (!lpProps.value.lpszW) {
+ lpProps.ulPropTag &= 0xFFFF0000;
+ lpProps.ulPropTag += PT_ERROR;
+ }
+ break;
+ case PR_EMS_AB_IS_MASTER:
+ /* FIXME: harcoded value - no load balancing */
+ lpProps.value.l = 0x0;
+ break;
+ case PR_EMS_AB_PARENT_ENTRYID:
+ emsabp_PermanentEntryID_to_Binary_r(mem_ctx, parentPermEntryID, &lpProps.value.bin);
+ break;
+ default:
+ break;
+ }
+ SRow_addprop(aRow, lpProps);
+ }
+ }
+
+ return MAPI_E_SUCCESS;
+}
+
+
+/**
+ \details Retrieve and build the HierarchyTable requested by
+ GetSpecialTable NSPI call
+
+ \param mem_ctx pointer to the memory context
+ \param emsabp_ctx pointer to the EMSABP context
+ \param dwFlags flags controlling whether strings should be UNICODE
+ or not
+ \param SRowSet pointer on pointer to the output SRowSet array
+
+ \return MAPI_E_SUCCESS on success, otherwise MAPI_E_CORRUPT_STORE
+ */
+_PUBLIC_ enum MAPISTATUS emsabp_get_HierarchyTable(TALLOC_CTX *mem_ctx, struct emsabp_context *emsabp_ctx,
+ uint32_t dwFlags, struct SRowSet **SRowSet)
+{
+ enum MAPISTATUS retval;
+ struct SRow *aRow;
+ struct PermanentEntryID gal;
+ struct PermanentEntryID parentPermEntryID;
+ struct PermanentEntryID permEntryID;
+ enum ldb_scope scope = LDB_SCOPE_SUBTREE;
+ struct ldb_request *req;
+ struct ldb_result *res = NULL;
+ char *ldb_filter;
+ struct ldb_dn *ldb_dn = NULL;
+ struct ldb_control **controls;
+ const char * const recipient_attrs[] = { "*", NULL };
+ const char *control_strings[2] = { "server_sort:0:0:displayName", NULL };
+ const char *addressBookRoots;
+ int ret;
+ uint32_t aRow_idx;
+ uint32_t i;
+
+ /* Step 1. Build the 'Global Address List' object using PermanentEntryID */
+ aRow = talloc_zero(mem_ctx, struct SRow);
+ OPENCHANGE_RETVAL_IF(!aRow, MAPI_E_NOT_ENOUGH_RESOURCES, NULL);
+ aRow_idx = 0;
+
+ retval = emsabp_set_PermanentEntryID(emsabp_ctx, DT_CONTAINER, NULL, &gal);
+ OPENCHANGE_RETVAL_IF(retval, retval, aRow);
+
+ retval = emsabp_table_fetch_attrs(mem_ctx, emsabp_ctx, &aRow[aRow_idx], dwFlags, &gal, NULL, NULL, false);
+ aRow_idx++;
+
+ /* Step 2. Retrieve the object pointed by addressBookRoots attribute: 'All Address Lists' */
+ ldb_filter = talloc_strdup(emsabp_ctx->mem_ctx, "(addressBookRoots=*)");
+ ret = ldb_search(emsabp_ctx->conf_ctx, emsabp_ctx->mem_ctx, &res,
+ ldb_get_default_basedn(emsabp_ctx->conf_ctx),
+ scope, recipient_attrs, ldb_filter);
+ talloc_free(ldb_filter);
+ OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS || !res->count, MAPI_E_CORRUPT_STORE, aRow);
+
+ addressBookRoots = ldb_msg_find_attr_as_string(res->msgs[0], "addressBookRoots", NULL);
+ OPENCHANGE_RETVAL_IF(!addressBookRoots, MAPI_E_CORRUPT_STORE, aRow);
+ talloc_free(res);
+
+ ldb_dn = ldb_dn_new(emsabp_ctx->mem_ctx, emsabp_ctx->conf_ctx, addressBookRoots);
+ OPENCHANGE_RETVAL_IF(!ldb_dn_validate(ldb_dn), MAPI_E_CORRUPT_STORE, aRow);
+
+ scope = LDB_SCOPE_BASE;
+ ret = ldb_search(emsabp_ctx->conf_ctx, emsabp_ctx->mem_ctx, &res, ldb_dn,
+ scope, recipient_attrs, NULL);
+ OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS || !res->count || res->count != 1, MAPI_E_CORRUPT_STORE, aRow);
+
+ aRow = talloc_realloc(mem_ctx, aRow, struct SRow, aRow_idx + 1);
+ retval = emsabp_set_PermanentEntryID(emsabp_ctx, DT_CONTAINER, res->msgs[0], &parentPermEntryID);
+ emsabp_table_fetch_attrs(mem_ctx, emsabp_ctx, &aRow[aRow_idx], dwFlags, &parentPermEntryID, NULL, res->msgs[0], false);
+ aRow_idx++;
+ talloc_free(res);
+
+ /* Step 3. Retrieve 'All Address Lists' subcontainers */
+ res = talloc_zero(mem_ctx, struct ldb_result);
+ OPENCHANGE_RETVAL_IF(!res, MAPI_E_NOT_ENOUGH_RESOURCES, aRow);
+
+ controls = ldb_parse_control_strings(emsabp_ctx->conf_ctx, emsabp_ctx->mem_ctx, control_strings);
+ ret = ldb_build_search_req(&req, emsabp_ctx->conf_ctx, emsabp_ctx->mem_ctx,
+ ldb_dn, LDB_SCOPE_SUBTREE, "(purportedSearch=*)",
+ recipient_attrs, controls, res, ldb_search_default_callback, NULL);
+
+ if (ret != LDB_SUCCESS) {
+ talloc_free(res);
+ OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_CORRUPT_STORE, aRow);
+ }
+
+ ret = ldb_request(emsabp_ctx->conf_ctx, req);
+ if (ret == LDB_SUCCESS) {
+ ret = ldb_wait(req->handle, LDB_WAIT_ALL);
+ }
+ talloc_free(req);
+
+ if (ret != LDB_SUCCESS || !res->count) {
+ talloc_free(res);
+ OPENCHANGE_RETVAL_IF(1, MAPI_E_CORRUPT_STORE, aRow);
+ }
+
+ aRow = talloc_realloc(mem_ctx, aRow, struct SRow, aRow_idx + res->count + 1);
+
+ for (i = 0; res->msgs[i]; i++) {
+ retval = emsabp_set_PermanentEntryID(emsabp_ctx, DT_CONTAINER, res->msgs[i], &permEntryID);
+ emsabp_table_fetch_attrs(mem_ctx, emsabp_ctx, &aRow[aRow_idx], dwFlags, &permEntryID, &parentPermEntryID, res->msgs[i], true);
+ talloc_free(permEntryID.dn);
+ memset(&permEntryID, 0, sizeof (permEntryID));
+ aRow_idx++;
+ }
+ talloc_free(res);
+ talloc_free(parentPermEntryID.dn);
+
+ /* Step 4. Build output SRowSet */
+ SRowSet[0]->cRows = aRow_idx;
+ SRowSet[0]->aRow = aRow;
+
+ return MAPI_E_SUCCESS;
+}
+
+
+/**
+ \details Retrieve and build the CreationTemplates Table requested
+ by GetSpecialTable NSPI call
+
+ \param mem_ctx pointer to the memory context
+ \param emsabp_ctx pointer to the EMSABP context
+ \param dwFlags flags controlling whether strings should be UNICODE
+ or not
+ \param SRowSet pointer on pointer to the output SRowSet array
+
+ \return MAPI_E_SUCCESS on success, otherwise MAPI_E_CORRUPT_STORE
+ */
+_PUBLIC_ enum MAPISTATUS emsabp_get_CreationTemplatesTable(TALLOC_CTX *mem_ctx, struct emsabp_context *emsabp_ctx,
+ uint32_t dwFlags, struct SRowSet **SRowSet)
+{
+ return MAPI_E_SUCCESS;
+}
--- /dev/null
+/*
+ OpenChange Server implementation.
+
+ EMSABP: Address Book Provider implementation
+
+ Copyright (C) Julien Kerihuel 2006-2009.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ \file emsabp_tdb.c
+
+ \brief EMSABP TDB database API
+*/
+
+#include "mapiproxy/dcesrv_mapiproxy.h"
+#include "mapiproxy/libmapiproxy.h"
+#include "dcesrv_exchange_nsp.h"
+#include <util/debug.h>
+
+/* This hack only works for single mode - need to move the context
+ * somewhere else. Possible libmapiproxy and use tdb_reopen */
+/* static TDB_CONTEXT *tdb_ctx = NULL; */
+
+/**
+ \details Open EMSABP TDB database
+
+ \param mem_ctx pointer to the memory context
+ \param lp_ctx pointer to the loadparm context
+ \param ev pointer to the event context
+
+ \return MAPI_E_SUCCESS on success, otherwise MAPI error
+ */
+_PUBLIC_ TDB_CONTEXT *emsabp_tdb_init(TALLOC_CTX *mem_ctx,
+ struct loadparm_context *lp_ctx)
+{
+ enum MAPISTATUS retval;
+ TDB_CONTEXT *tdb_ctx;
+ TDB_DATA key;
+ TDB_DATA dbuf;
+ int ret;
+
+ /* Sanity checks */
+ if (!lp_ctx) return NULL;
+
+ /* Step 0. Retrieve a TDB context pointer on the emsabp_tdb database */
+ tdb_ctx = mapiproxy_server_emsabp_tdb_init(lp_ctx);
+ if (!tdb_ctx) return NULL;
+
+ /* Step 1. If EMSABP_TDB_DATA_REC doesn't exist, create it */
+ retval = emsabp_tdb_fetch(tdb_ctx, EMSABP_TDB_DATA_REC, &dbuf);
+ if (retval == MAPI_E_NOT_FOUND) {
+ key.dptr = (unsigned char *) EMSABP_TDB_DATA_REC;
+ key.dsize = strlen(EMSABP_TDB_DATA_REC);
+
+ dbuf.dptr = (unsigned char *) talloc_asprintf(mem_ctx, "0x%x", EMSABP_TDB_MID_START);
+ dbuf.dsize = strlen((const char *)dbuf.dptr);
+
+ ret = tdb_store(tdb_ctx, key, dbuf, TDB_INSERT);
+ if (ret == -1) {
+ DEBUG(3, ("[%s:%d]: Unable to create %s record: %s\n", __FUNCTION__, __LINE__,
+ EMSABP_TDB_DATA_REC, tdb_errorstr(tdb_ctx)));
+ tdb_close(tdb_ctx);
+ return NULL;
+ }
+ } else {
+ free (dbuf.dptr);
+ }
+
+ return tdb_ctx;
+}
+
+
+/**
+ \details Close EMSABP TDB database
+
+ \return MAPI_E_SUCCESS on success, otherwise
+ MAPI_E_INVALID_PARAMETER
+ */
+_PUBLIC_ enum MAPISTATUS emsabp_tdb_close(TDB_CONTEXT *tdb_ctx)
+{
+ /* Sanity checks */
+ OPENCHANGE_RETVAL_IF(!tdb_ctx, MAPI_E_INVALID_PARAMETER, NULL);
+
+ tdb_close(tdb_ctx);
+ DEBUG(0, ("TDB database closed\n"));
+
+ return MAPI_E_SUCCESS;
+}
+
+
+/**
+ \details Fetch an element within a TDB database given its key
+
+ \param keyname pointer to the TDB key to fetch
+ \param result pointer on TDB results
+
+ \return MAPI_E_SUCCESS on success, otherwise MAPI_E_NOT_FOUND
+ */
+_PUBLIC_ enum MAPISTATUS emsabp_tdb_fetch(TDB_CONTEXT *tdb_ctx,
+ const char *keyname,
+ TDB_DATA *result)
+{
+ TDB_DATA key;
+ TDB_DATA dbuf;
+ size_t keylen;
+
+ /* Sanity checks */
+ OPENCHANGE_RETVAL_IF(!tdb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
+ OPENCHANGE_RETVAL_IF(!keyname, MAPI_E_INVALID_PARAMETER, NULL);
+
+ keylen = strlen(keyname);
+ OPENCHANGE_RETVAL_IF(!keylen, MAPI_E_INVALID_PARAMETER, NULL);
+
+ key.dptr = (unsigned char *)keyname;
+ key.dsize = keylen;
+
+ dbuf = tdb_fetch(tdb_ctx, key);
+ OPENCHANGE_RETVAL_IF(!dbuf.dptr, MAPI_E_NOT_FOUND, NULL);
+ OPENCHANGE_RETVAL_IF(!dbuf.dsize, MAPI_E_NOT_FOUND, NULL);
+
+ if (!result) {
+ free (dbuf.dptr);
+ } else {
+ *result = dbuf;
+ }
+
+ return MAPI_E_SUCCESS;
+}
+
+
+/**
+ \details Retrieve the Minimal EntryID associated to a given DN
+
+ \param tdb_ctx pointer to the EMSABP TDB context
+ \param keyname pointer to the TDB key to search for
+ \param MId pointer on the integer the function returns
+
+ \return MAPI_E_SUCCESS on success, otherwise MAPI error
+ */
+_PUBLIC_ enum MAPISTATUS emsabp_tdb_fetch_MId(TDB_CONTEXT *tdb_ctx,
+ const char *keyname,
+ uint32_t *MId)
+{
+ TDB_DATA key;
+ TDB_DATA dbuf;
+
+ /* Sanity checks */
+ OPENCHANGE_RETVAL_IF(!tdb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
+ OPENCHANGE_RETVAL_IF(!keyname, MAPI_E_INVALID_PARAMETER, NULL);
+ OPENCHANGE_RETVAL_IF(!MId, MAPI_E_INVALID_PARAMETER, NULL);
+
+ key.dptr = (unsigned char *) keyname;
+ key.dsize = strlen(keyname);
+
+ dbuf = tdb_fetch(tdb_ctx, key);
+ OPENCHANGE_RETVAL_IF(!dbuf.dptr, MAPI_E_NOT_FOUND, NULL);
+ OPENCHANGE_RETVAL_IF(!dbuf.dsize, MAPI_E_NOT_FOUND, NULL);
+
+ *MId = strtol((const char *)dbuf.dptr, NULL, 16);
+ free(dbuf.dptr);
+
+ return MAPI_E_SUCCESS;
+}
+
+
+/**
+ \details Insert an element into TDB database
+
+ \param tdb_ctx pointer to the EMSABP TDB context
+ \param keyname pointer to the TDB key name string
+
+ \return MAPI_E_SUCCESS on success, otherwise MAPI error
+ */
+_PUBLIC_ enum MAPISTATUS emsabp_tdb_insert(TDB_CONTEXT *tdb_ctx,
+ const char *keyname)
+{
+ enum MAPISTATUS retval;
+ TALLOC_CTX *mem_ctx;
+ TDB_DATA key;
+ TDB_DATA dbuf;
+ int index;
+ int ret;
+
+ /* Sanity checks */
+ OPENCHANGE_RETVAL_IF(!tdb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
+ OPENCHANGE_RETVAL_IF(!keyname, MAPI_E_INVALID_PARAMETER, NULL);
+
+ mem_ctx = talloc_init("emsabp_tdb_insert");
+ OPENCHANGE_RETVAL_IF(!mem_ctx, MAPI_E_NOT_ENOUGH_RESOURCES, NULL);
+
+ /* Step 1. Check if the record already exists */
+ retval = emsabp_tdb_fetch(tdb_ctx, keyname, &dbuf);
+ OPENCHANGE_RETVAL_IF(!retval, ecExiting, mem_ctx);
+
+ /* Step 2. Retrieve the latest TDB data value inserted */
+ retval = emsabp_tdb_fetch(tdb_ctx, EMSABP_TDB_DATA_REC, &dbuf);
+ OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
+
+ index = strtol((const char *)dbuf.dptr, NULL, 16);
+ index += 1;
+
+ free(dbuf.dptr);
+
+ dbuf.dptr = (unsigned char *)talloc_asprintf(mem_ctx, "0x%x", index);
+ dbuf.dsize = strlen((const char *)dbuf.dptr);
+
+ /* Step 3. Insert the new record */
+ key.dptr = (unsigned char *)keyname;
+ key.dsize = strlen(keyname);
+
+ ret = tdb_store(tdb_ctx, key, dbuf, TDB_INSERT);
+ OPENCHANGE_RETVAL_IF(ret == -1, MAPI_E_CORRUPT_STORE, mem_ctx);
+
+ /* Step 4. Update Data record */
+ talloc_free(key.dptr);
+ key.dptr = (unsigned char *) EMSABP_TDB_DATA_REC;
+ key.dsize = strlen((const char *)key.dptr);
+
+ ret = tdb_store(tdb_ctx, key, dbuf, TDB_MODIFY);
+ OPENCHANGE_RETVAL_IF(ret == -1, MAPI_E_CORRUPT_STORE, mem_ctx);
+
+ talloc_free(mem_ctx);
+
+ return MAPI_E_SUCCESS;
+}