Fix OpenChange server code and access to Samba4 databases.
[OpenChange-git-clone.git] / mapiproxy / servers / default / nspi / dcesrv_exchange_nsp.c
blob48ac7d0263854bb413ca217900c6ea68bcb826d7
1 /*
2 MAPI Proxy - Exchange NSPI Server
4 OpenChange Project
6 Copyright (C) Julien Kerihuel 2009
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 /**
23 \file dcesrv_exchange_nsp.c
25 \brief OpenChange NSPI Server implementation
28 #include "mapiproxy/dcesrv_mapiproxy.h"
29 #include "dcesrv_exchange_nsp.h"
31 struct exchange_nsp_session *nsp_session = NULL;
32 TDB_CONTEXT *emsabp_tdb_ctx = NULL;
34 /**
35 \details exchange_nsp NspiBind (0x0) function, Initiates a NSPI
36 session with the client.
38 This function checks if the user is an Exchange user and input
39 parameters like codepage are valid. If it passes the tests, the
40 function initializes an emsabp context and returns to the client a
41 valid policy_handle and expected reply parameters.
43 \param dce_call pointer to the session context
44 \param mem_ctx pointer to the memory context
45 \param r pointer to the NspiBind call structure
47 \return MAPI_E_SUCCESS on success, otherwise a MAPI error
49 static enum MAPISTATUS dcesrv_NspiBind(struct dcesrv_call_state *dce_call,
50 TALLOC_CTX *mem_ctx,
51 struct NspiBind *r)
53 struct GUID *guid = (struct GUID *) NULL;
54 struct emsabp_context *emsabp_ctx;
55 struct dcesrv_handle *handle;
56 struct policy_handle wire_handle;
57 struct exchange_nsp_session *session;
59 DEBUG(5, ("exchange_nsp: NspiBind (0x0)\n"));
61 /* Step 0. Ensure incoming user is authenticated */
62 if (!NTLM_AUTH_IS_OK(dce_call)) {
63 DEBUG(1, ("No challenge requested by client, cannot authenticate\n"));
65 wire_handle.handle_type = EXCHANGE_HANDLE_NSP;
66 wire_handle.uuid = GUID_zero();
67 *r->out.handle = wire_handle;
69 r->out.mapiuid = r->in.mapiuid;
70 r->out.result = MAPI_E_LOGON_FAILED;
71 return MAPI_E_LOGON_FAILED;
74 /* Step 1. Initialize the emsabp context */
75 emsabp_ctx = emsabp_init(dce_call->conn->dce_ctx->lp_ctx, emsabp_tdb_ctx);
76 if (!emsabp_ctx) {
77 smb_panic("unable to initialize emsabp context");
78 OPENCHANGE_RETVAL_IF(!emsabp_ctx, MAPI_E_FAILONEPROVIDER, NULL);
81 /* Step 2. Check if incoming user belongs to the Exchange organization */
82 if (emsabp_verify_user(dce_call, emsabp_ctx) == false) {
83 talloc_free(emsabp_ctx);
85 wire_handle.handle_type = EXCHANGE_HANDLE_NSP;
86 wire_handle.uuid = GUID_zero();
87 *r->out.handle = wire_handle;
89 r->out.mapiuid = r->in.mapiuid;
90 r->out.result = MAPI_E_LOGON_FAILED;
91 return MAPI_E_LOGON_FAILED;
94 /* Step 3. Check if valid cpID has been supplied */
95 if (emsabp_verify_codepage(emsabp_ctx, r->in.pStat->CodePage) == false) {
96 talloc_free(emsabp_ctx);
98 wire_handle.handle_type = EXCHANGE_HANDLE_NSP;
99 wire_handle.uuid = GUID_zero();
100 *r->out.handle = wire_handle;
102 r->out.mapiuid = r->in.mapiuid;
103 r->out.result = MAPI_E_UNKNOWN_CPID;
104 return MAPI_E_UNKNOWN_CPID;
107 /* Step 4. Retrieve OpenChange server GUID */
108 guid = emsabp_get_server_GUID(emsabp_ctx);
109 OPENCHANGE_RETVAL_IF(!guid, MAPI_E_FAILONEPROVIDER, emsabp_ctx);
111 /* Step 5. Fill NspiBind reply */
112 handle = dcesrv_handle_new(dce_call->context, EXCHANGE_HANDLE_NSP);
113 OPENCHANGE_RETVAL_IF(!handle, MAPI_E_NOT_ENOUGH_RESOURCES, emsabp_ctx);
115 handle->data = (void *) emsabp_ctx;
116 *r->out.handle = handle->wire_handle;
117 r->out.mapiuid = guid;
118 r->out.result = MAPI_E_SUCCESS;
120 /* Step 6. Associate this emsabp context to the session */
121 session = talloc((TALLOC_CTX *)nsp_session, struct exchange_nsp_session);
122 OPENCHANGE_RETVAL_IF(!session, MAPI_E_NOT_ENOUGH_RESOURCES, emsabp_ctx);
124 session->session = mpm_session_init((TALLOC_CTX *)nsp_session, dce_call);
125 OPENCHANGE_RETVAL_IF(!session->session, MAPI_E_NOT_ENOUGH_RESOURCES, emsabp_ctx);
127 mpm_session_set_private_data(session->session, (void *) emsabp_ctx);
128 mpm_session_set_destructor(session->session, emsabp_destructor);
130 DLIST_ADD_END(nsp_session, session, struct exchange_nsp_session *);
132 return MAPI_E_SUCCESS;
137 \details exchange_nsp NspiUnbind (0x1) function, Terminates a NSPI
138 session with the client
140 \param dce_call pointer to the session context
141 \param mem_ctx pointer to the memory context
142 \param r pointer to the NspiUnbind call structure
144 static enum MAPISTATUS dcesrv_NspiUnbind(struct dcesrv_call_state *dce_call,
145 TALLOC_CTX *mem_ctx,
146 struct NspiUnbind *r)
148 struct dcesrv_handle *h;
149 struct exchange_nsp_session *session;
151 DEBUG(5, ("exchange_nsp: NspiUnbind (0x1)\n"));
153 /* Step 0. Ensure incoming user is authenticated */
154 if (!NTLM_AUTH_IS_OK(dce_call)) {
155 DEBUG(1, ("No challenge requested by client, cannot authenticate\n"));
156 return MAPI_E_LOGON_FAILED;
159 /* Step 1. Retrieve handle and free if emsabp context and session are available */
160 h = dcesrv_handle_fetch(dce_call->context, r->in.handle, DCESRV_HANDLE_ANY);
161 if (h) {
162 for (session = nsp_session; session; session = session->next) {
163 if ((mpm_session_cmp(session->session, dce_call) == true)) {
164 mpm_session_release(session->session);
165 DLIST_REMOVE(nsp_session, session);
166 DEBUG(6, ("[%s:%d]: Session found and released\n", __FUNCTION__, __LINE__));
171 r->out.result = 1;
173 return MAPI_E_SUCCESS;
178 \details exchange_nsp NspiUpdateStat (0x2) function
180 \param dce_call pointer to the session context
181 \param mem_ctx pointer to the memory context
182 \param r pointer to the NspiUpdateStat request data
184 \return MAPI_E_SUCCESS on success
186 static enum MAPISTATUS dcesrv_NspiUpdateStat(struct dcesrv_call_state *dce_call,
187 TALLOC_CTX *mem_ctx,
188 struct NspiUpdateStat *r)
190 DEBUG(3, ("exchange_nsp: NspiUpdateStat (0x2) not implemented\n"));
191 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
196 \details exchange_nsp NspiQueryRows (0x3) function
198 \param dce_call pointer to the session context
199 \param mem_ctx pointer to the memory context
200 \param r pointer to the NspiQueryRows request data
202 \return MAPI_E_SUCCESS on success
204 static enum MAPISTATUS dcesrv_NspiQueryRows(struct dcesrv_call_state *dce_call,
205 TALLOC_CTX *mem_ctx,
206 struct NspiQueryRows *r)
208 enum MAPISTATUS retval = MAPI_E_SUCCESS;
209 struct dcesrv_handle *h;
210 struct emsabp_context *emsabp_ctx;
211 struct SPropTagArray *pPropTags;
212 uint32_t i;
214 DEBUG(3, ("exchange_nsp: NspiQueryRows (0x3)\n"));
216 /* Step 0. Ensure incoming user is authenticated */
217 if (!NTLM_AUTH_IS_OK(dce_call)) {
218 DEBUG(1, ("No challenge requested by client, cannot authenticate\n"));
219 return MAPI_E_LOGON_FAILED;
222 h = dcesrv_handle_fetch(dce_call->context, r->in.handle, DCESRV_HANDLE_ANY);
223 if (!h) return MAPI_E_LOGON_FAILED;
224 emsabp_ctx = (struct emsabp_context *) h->data;
226 /* Step 1. Sanity Checks (MS-NSPI Server Processing Rules) */
227 if (r->in.pStat->ContainerID && (emsabp_tdb_lookup_MId(emsabp_ctx->tdb_ctx, r->in.pStat->ContainerID) == false)) {
228 retval = MAPI_E_INVALID_BOOKMARK;
229 goto failure;
232 if (r->in.pPropTags == NULL) {
233 pPropTags = set_SPropTagArray(mem_ctx, 0x7,
234 PR_EMS_AB_CONTAINERID,
235 PR_OBJECT_TYPE,
236 PR_DISPLAY_TYPE,
237 PR_DISPLAY_NAME,
238 PR_OFFICE_TELEPHONE_NUMBER,
239 PR_COMPANY_NAME,
240 PR_OFFICE_LOCATION);
241 } else {
242 pPropTags = r->in.pPropTags;
245 if (r->in.lpETable == NULL) {
246 /* FIXME */
247 retval = MAPI_E_INVALID_BOOKMARK;
250 if (retval != MAPI_E_SUCCESS) {
251 failure:
252 r->out.pStat = r->in.pStat;
253 r->out.ppRows = talloc(mem_ctx, struct SRowSet *);
254 r->out.ppRows[0] = NULL;
255 r->out.result = retval;
257 return retval;
260 /* Step 2. Fill ppRows */
261 r->out.ppRows = talloc(mem_ctx, struct SRowSet *);
262 r->out.ppRows[0] = talloc(mem_ctx, struct SRowSet);
263 r->out.ppRows[0]->cRows = r->in.Count;
264 r->out.ppRows[0]->aRow = talloc_array(mem_ctx, struct SRow, r->in.Count);
265 for (i = 0; i < r->in.Count; i++) {
266 retval = emsabp_fetch_attrs(mem_ctx, emsabp_ctx, &(r->out.ppRows[0]->aRow[i]), r->in.lpETable[i], pPropTags);
267 if (retval != MAPI_E_SUCCESS) {
268 goto failure;
272 return MAPI_E_SUCCESS;
277 \details exchange_nsp NspiSeekEntries (0x4) function
279 \param dce_call pointer to the session context
280 \param mem_ctx pointer to the memory context
281 \param r pointer to the NspiSeekEntries request data
283 \return MAPI_E_SUCCESS on success
285 static enum MAPISTATUS dcesrv_NspiSeekEntries(struct dcesrv_call_state *dce_call,
286 TALLOC_CTX *mem_ctx,
287 struct NspiSeekEntries *r)
289 DEBUG(3, ("exchange_nsp: NspiSeekEntries (0x4) not implemented\n"));
290 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
295 \details exchange_nsp NspiGetMatches (0x5) function
297 \param dce_call pointer to the session context
298 \param mem_ctx pointer to the memory context
299 \param r pointer to the NspiGetMatches request data
301 \return MAPI_E_SUCCESS on success
303 static enum MAPISTATUS dcesrv_NspiGetMatches(struct dcesrv_call_state *dce_call,
304 TALLOC_CTX *mem_ctx,
305 struct NspiGetMatches *r)
307 enum MAPISTATUS retval;
308 struct dcesrv_handle *h;
309 struct emsabp_context *emsabp_ctx;
310 struct SPropTagArray *ppOutMIds = NULL;
311 uint32_t i;
314 DEBUG(3, ("exchange_nsp: NspiGetMatches (0x5)\n"));
316 /* Step 0. Ensure incoming user is authenticated */
317 if (!NTLM_AUTH_IS_OK(dce_call)) {
318 DEBUG(1, ("No challenge requested by client, cannot authenticate\n"));
319 return MAPI_E_LOGON_FAILED;
322 h = dcesrv_handle_fetch(dce_call->context, r->in.handle, DCESRV_HANDLE_ANY);
323 if (!h) return MAPI_E_LOGON_FAILED;
324 emsabp_ctx = (struct emsabp_context *) h->data;
326 /* Step 1. Retrieve MIds array given search criterias */
327 ppOutMIds = talloc_zero(mem_ctx, struct SPropTagArray);
328 ppOutMIds->cValues = 0;
329 ppOutMIds->aulPropTag = NULL;
331 retval = emsabp_search(mem_ctx, emsabp_ctx, ppOutMIds, r->in.Filter, r->in.pStat, r->in.ulRequested);
332 if (retval != MAPI_E_SUCCESS) {
333 failure:
334 r->out.pStat = r->in.pStat;
335 *r->out.ppOutMIds = ppOutMIds;
336 r->out.ppRows = talloc(mem_ctx, struct SRowSet *);
337 r->out.ppRows[0] = NULL;
338 r->out.result = retval;
340 return retval;
343 *r->out.ppOutMIds = ppOutMIds;
345 /* Step 2. Retrieve requested properties for these MIds */
346 r->out.ppRows = talloc_zero(mem_ctx, struct SRowSet *);
347 r->out.ppRows[0] = talloc_zero(mem_ctx, struct SRowSet);
348 r->out.ppRows[0]->cRows = ppOutMIds->cValues;
349 r->out.ppRows[0]->aRow = talloc_array(mem_ctx, struct SRow, ppOutMIds->cValues);
352 for (i = 0; i < ppOutMIds->cValues; i++) {
353 retval = emsabp_fetch_attrs(mem_ctx, emsabp_ctx, &(r->out.ppRows[0]->aRow[i]),
354 ppOutMIds->aulPropTag[i], r->in.pPropTags);
355 if (retval) goto failure;
358 r->out.result = MAPI_E_SUCCESS;
360 return MAPI_E_SUCCESS;
365 \details exchange_nsp NspiResortRestriction (0x6) function
367 \param dce_call pointer to the session context
368 \param mem_ctx pointer to the memory context
369 \param r pointer to the NspiResortRestriction request data
371 \return MAPI_E_SUCCESS on success
373 static enum MAPISTATUS dcesrv_NspiResortRestriction(struct dcesrv_call_state *dce_call,
374 TALLOC_CTX *mem_ctx,
375 struct NspiResortRestriction *r)
377 DEBUG(3, ("exchange_nsp: NspiResortRestriction (0x6) not implemented\n"));
378 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
383 \details exchange_nsp NspiDNToMId (0x7) function
385 \param dce_call pointer to the session context
386 \param mem_ctx pointer to the memory context
387 \param r pointer to the NspiDNToMId request data
389 \note Only searches within configuration.ldb are supported at the
390 moment.
392 \return MAPI_E_SUCCESS on success
394 static enum MAPISTATUS dcesrv_NspiDNToMId(struct dcesrv_call_state *dce_call,
395 TALLOC_CTX *mem_ctx,
396 struct NspiDNToMId *r)
398 enum MAPISTATUS retval;
399 struct dcesrv_handle *h;
400 struct emsabp_context *emsabp_ctx;
401 struct ldb_message *msg;
402 uint32_t i;
403 uint32_t MId;
404 const char *dn;
406 DEBUG(3, ("exchange_nsp: NspiDNToMId (0x7)\n"));
408 /* Step 0. Ensure incoming user is authenticated */
409 if (!NTLM_AUTH_IS_OK(dce_call)) {
410 DEBUG(1, ("No challenge requested by client, cannot authenticate\n"));
411 return MAPI_E_LOGON_FAILED;
414 h = dcesrv_handle_fetch(dce_call->context, r->in.handle, DCESRV_HANDLE_ANY);
415 if (!h) return MAPI_E_LOGON_FAILED;
416 OPENCHANGE_RETVAL_IF(!h, MAPI_E_NOT_ENOUGH_RESOURCES, NULL);
418 emsabp_ctx = (struct emsabp_context *) h->data;
420 r->out.ppMIds = talloc_array(mem_ctx, struct SPropTagArray *, 2);
421 r->out.ppMIds[0] = talloc_zero(mem_ctx, struct SPropTagArray);
422 r->out.ppMIds[0]->cValues = r->in.pNames->Count;
423 r->out.ppMIds[0]->aulPropTag = talloc_array(mem_ctx, uint32_t, r->in.pNames->Count);
425 for (i = 0; i < r->in.pNames->Count; i++) {
426 /* Step 1. Check if the input legacyDN exists */
427 retval = emsabp_search_legacyExchangeDN(emsabp_ctx, r->in.pNames->Strings[i], &msg);
428 if (retval != MAPI_E_SUCCESS) {
429 r->out.ppMIds[0]->aulPropTag[i] = 0;
430 } else {
431 dn = ldb_msg_find_attr_as_string(msg, "distinguishedName", NULL);
432 retval = emsabp_tdb_fetch_MId(emsabp_ctx->tdb_ctx, dn, &MId);
433 if (retval) {
434 retval = emsabp_tdb_insert(emsabp_ctx->tdb_ctx, dn);
435 retval = emsabp_tdb_fetch_MId(emsabp_ctx->tdb_ctx, dn, &MId);
437 r->out.ppMIds[0]->aulPropTag[i] = MId;
441 r->out.result = MAPI_E_SUCCESS;
443 return MAPI_E_SUCCESS;
448 \details exchange_nsp NspiGetPropList (0x8) function
450 \param dce_call pointer to the session context
451 \param mem_ctx pointer to the memory context
452 \param r pointer to the NspiGetPropList request data
454 \return MAPI_E_SUCCESS on success
456 static enum MAPISTATUS dcesrv_NspiGetPropList(struct dcesrv_call_state *dce_call,
457 TALLOC_CTX *mem_ctx,
458 struct NspiGetPropList *r)
460 DEBUG(3, ("exchange_nsp: NspiGetPropList (0x8) not implemented\n"));
461 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
466 \details exchange_nsp NspiGetProps (0x9) function
468 \param dce_call pointer to the session context
469 \param mem_ctx pointer to the memory context
470 \param r pointer to the NspiGetProps request data
472 \return MAPI_E_SUCCESS on success
474 static enum MAPISTATUS dcesrv_NspiGetProps(struct dcesrv_call_state *dce_call,
475 TALLOC_CTX *mem_ctx,
476 struct NspiGetProps *r)
478 enum MAPISTATUS retval;
479 struct dcesrv_handle *h;
480 struct emsabp_context *emsabp_ctx;
481 uint32_t MId;
482 char *dn;
484 DEBUG(3, ("exchange_nsp: NspiGetProps (0x9)\n"));
486 /* Step 0. Ensure incoming user is authenticated */
487 if (!NTLM_AUTH_IS_OK(dce_call)) {
488 DEBUG(1, ("No challenge requested by client, cannot authenticate\n"));
489 return MAPI_E_LOGON_FAILED;
492 h = dcesrv_handle_fetch(dce_call->context, r->in.handle, DCESRV_HANDLE_ANY);
493 if (!h) return MAPI_E_LOGON_FAILED;
494 emsabp_ctx = (struct emsabp_context *) h->data;
496 MId = r->in.pStat->CurrentRec;
498 /* Step 1. Sanity Checks (MS-NSPI Server Processing Rules) */
499 if (r->in.pStat->ContainerID && (emsabp_tdb_lookup_MId(emsabp_ctx->tdb_ctx, r->in.pStat->ContainerID) == false)) {
500 retval = MAPI_E_INVALID_BOOKMARK;
501 goto failure;
504 retval = emsabp_tdb_fetch_dn_from_MId(mem_ctx, emsabp_ctx->tdb_ctx, MId, &dn);
505 if (retval != MAPI_E_SUCCESS) {
506 failure:
507 r->out.ppRows = talloc_array(mem_ctx, struct SRow *, 2);
508 r->out.ppRows[0] = NULL;
509 r->out.result = MAPI_E_INVALID_BOOKMARK;
510 return r->out.result;
513 /* Step 2. Fetch properties */
514 r->out.ppRows = talloc_array(mem_ctx, struct SRow *, 2);
515 r->out.ppRows[0] = talloc_zero(r->out.ppRows, struct SRow);
516 r->out.ppRows[0]->ulAdrEntryPad = 0;
517 r->out.ppRows[0]->cValues = r->in.pPropTags->cValues;
518 r->out.ppRows[0]->lpProps = talloc_array(r->out.ppRows[0], struct SPropValue, r->in.pPropTags->cValues);
520 retval = emsabp_fetch_attrs(mem_ctx, emsabp_ctx, r->out.ppRows[0], MId, r->in.pPropTags);
521 if (retval != MAPI_E_SUCCESS) {
522 talloc_free(r->out.ppRows);
523 r->out.result = MAPI_W_ERRORS_RETURNED;
524 goto failure;
527 r->out.result = MAPI_E_SUCCESS;
529 return MAPI_E_SUCCESS;
534 \details exchange_nsp NspiCompareMIds (0xA) function
536 \param dce_call pointer to the session context
537 \param mem_ctx pointer to the memory context
538 \param r pointer to the NspiCompareMIds request data
540 \return MAPI_E_SUCCESS on success
542 static enum MAPISTATUS dcesrv_NspiCompareMIds(struct dcesrv_call_state *dce_call,
543 TALLOC_CTX *mem_ctx,
544 struct NspiCompareMIds *r)
546 DEBUG(3, ("exchange_nsp: NspiCompareMIds (0xA) not implemented\n"));
547 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
552 \details exchange_nsp NspiModProps (0xB) function
554 \param dce_call pointer to the session context
555 \param mem_ctx pointer to the memory context
556 \param r pointer to the NspiModProps request data
558 \return MAPI_E_SUCCESS on success
561 static enum MAPISTATUS dcesrv_NspiModProps(struct dcesrv_call_state *dce_call,
562 TALLOC_CTX *mem_ctx,
563 struct NspiModProps *r)
565 DEBUG(3, ("exchange_nsp: NspiModProps (0xB) not implemented\n"));
566 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
571 \details exchange_nsp NspiGetSpecialTable (0xC) function
573 \param dce_call pointer to the session context
574 \param mem_ctx pointer to the memory context
575 \param r pointer to the NspiGetSpecialTable request data
577 \note MS-NSPI specifies lpVersion "holds the value of the version
578 number of the hierarchy table that the client has." We will ignore
579 this for the moment.
581 \return MAPI_E_SUCCESS on success
584 static enum MAPISTATUS dcesrv_NspiGetSpecialTable(struct dcesrv_call_state *dce_call,
585 TALLOC_CTX *mem_ctx,
586 struct NspiGetSpecialTable *r)
588 struct dcesrv_handle *h;
589 struct emsabp_context *emsabp_ctx;
591 DEBUG(3, ("exchange_nsp: NspiGetSpecialTable (0xC)\n"));
593 /* Step 0. Ensure incoming user is authenticated */
594 if (!NTLM_AUTH_IS_OK(dce_call)) {
595 DEBUG(1, ("No challenge requested by client, cannot authenticate\n"));
596 return MAPI_E_LOGON_FAILED;
599 h = dcesrv_handle_fetch(dce_call->context, r->in.handle, DCESRV_HANDLE_ANY);
600 if (!h) return MAPI_E_LOGON_FAILED;
601 emsabp_ctx = (struct emsabp_context *) h->data;
603 /* Step 1. (FIXME) We arbitrary set lpVersion to 0x1 */
604 r->out.lpVersion = talloc_zero(mem_ctx, uint32_t);
605 *r->out.lpVersion = 0x1;
607 /* Step 2. Allocate output SRowSet and call associated emsabp function */
608 r->out.ppRows = talloc_zero(mem_ctx, struct SRowSet *);
609 OPENCHANGE_RETVAL_IF(!r->out.ppRows, MAPI_E_NOT_ENOUGH_RESOURCES, NULL);
610 r->out.ppRows[0] = talloc_zero(mem_ctx, struct SRowSet);
611 OPENCHANGE_RETVAL_IF(!r->out.ppRows[0], MAPI_E_NOT_ENOUGH_RESOURCES, NULL);
613 switch (r->in.dwFlags) {
614 case NspiAddressCreationTemplates:
615 case NspiAddressCreationTemplates|NspiUnicodeStrings:
616 DEBUG(0, ("CreationTemplates Table requested\n"));
617 r->out.result = emsabp_get_CreationTemplatesTable(mem_ctx, emsabp_ctx, r->in.dwFlags, r->out.ppRows);
618 break;
619 case NspiUnicodeStrings:
620 case 0x0:
621 DEBUG(0, ("Hierarchy Table requested\n"));
622 r->out.result = emsabp_get_HierarchyTable(mem_ctx, emsabp_ctx, r->in.dwFlags, r->out.ppRows);
623 break;
624 default:
625 talloc_free(r->out.ppRows);
626 talloc_free(r->out.ppRows[0]);
627 return MAPI_E_NO_SUPPORT;
630 return r->out.result;
635 \details exchange_nsp NspiGetTemplateInfo (0xD) function
637 \param dce_call pointer to the session context
638 \param mem_ctx pointer to the memory context
639 \param r pointer to the NspiGetTemplateInfo request data
641 \return MAPI_E_SUCCESS on success
644 static enum MAPISTATUS dcesrv_NspiGetTemplateInfo(struct dcesrv_call_state *dce_call,
645 TALLOC_CTX *mem_ctx,
646 struct NspiGetTemplateInfo *r)
648 DEBUG(3, ("exchange_nsp: NspiGetTemplateInfo (0xD) not implemented\n"));
649 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
654 \details exchange_nsp NspiModLinkAtt (0xE) function
656 \param dce_call pointer to the session context
657 \param mem_ctx pointer to the memory context
658 \param r pointer to the NspiModLinkAtt request data
660 \return MAPI_E_SUCCESS on success
663 static enum MAPISTATUS dcesrv_NspiModLinkAtt(struct dcesrv_call_state *dce_call,
664 TALLOC_CTX *mem_ctx,
665 struct NspiModLinkAtt *r)
667 DEBUG(3, ("exchange_nsp: NspiModLinkAtt (0xE) not implemented\n"));
668 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
673 \details exchange_nsp NspiDeleteEntries (0xF) function
675 \param dce_call pointer to the session context
676 \param mem_ctx pointer to the memory context
677 \param r pointer to the NspiDeleteEntries request data
679 \return MAPI_E_SUCCESS on success
682 static enum MAPISTATUS dcesrv_NspiDeleteEntries(struct dcesrv_call_state *dce_call,
683 TALLOC_CTX *mem_ctx,
684 struct NspiDeleteEntries *r)
686 DEBUG(3, ("exchange_nsp: NspiDeleteEntries (0xF) not implemented\n"));
687 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
692 \details exchange_nsp NspiQueryColumns (0x10) function
694 \param dce_call pointer to the session context
695 \param mem_ctx pointer to the memory context
696 \param r pointer to the NspiQueryColumns request data
698 \return MAPI_E_SUCCESS on success
701 static enum MAPISTATUS dcesrv_NspiQueryColumns(struct dcesrv_call_state *dce_call,
702 TALLOC_CTX *mem_ctx,
703 struct NspiQueryColumns *r)
705 DEBUG(3, ("exchange_nsp: NspiQueryColumns (0x10) not implemented\n"));
706 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
711 \details exchange_nsp NspiGetNamesFromIDs (0x11) function
713 \param dce_call pointer to the session context
714 \param mem_ctx pointer to the memory context
715 \param r pointer to the NspiGetNamesFromIDs request data
717 \return MAPI_E_SUCCESS on success
720 static enum MAPISTATUS dcesrv_NspiGetNamesFromIDs(struct dcesrv_call_state *dce_call,
721 TALLOC_CTX *mem_ctx,
722 struct NspiGetNamesFromIDs *r)
724 DEBUG(3, ("exchange_nsp: NspiGetNamesFromIDs (0x11) not implemented\n"));
725 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
730 \details exchange_nsp NspiGetIDsFromNames (0x12) function
732 \param dce_call pointer to the session context
733 \param mem_ctx pointer to the memory context
734 \param r pointer to the NspiGetIDsFromNames request data
736 \return MAPI_E_SUCCESS on success
739 static enum MAPISTATUS dcesrv_NspiGetIDsFromNames(struct dcesrv_call_state *dce_call,
740 TALLOC_CTX *mem_ctx,
741 struct NspiGetIDsFromNames *r)
743 DEBUG(3, ("exchange_nsp: NspiGetIDsFromNames (0x12) not implemented\n"));
744 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
749 \details exchange_nsp NspiResolveNames (0x13) function
751 \param dce_call pointer to the session context
752 \param mem_ctx pointer to the memory context
753 \param r pointer to the NspiResolveNames request data
755 \return MAPI_E_SUCCESS on success
758 static enum MAPISTATUS dcesrv_NspiResolveNames(struct dcesrv_call_state *dce_call,
759 TALLOC_CTX *mem_ctx,
760 struct NspiResolveNames *r)
762 DEBUG(3, ("exchange_nsp: NspiResolveNames (0x13) not implemented\n"));
763 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
768 \details exchange_nsp NspiResolveNamesW (0x14) function
770 \param dce_call pointer to the session context
771 \param mem_ctx pointer to the memory context
772 \param r pointer to the NspiResolveNamesW request data
774 \return MAPI_E_SUCCESS on success
777 static enum MAPISTATUS dcesrv_NspiResolveNamesW(struct dcesrv_call_state *dce_call,
778 TALLOC_CTX *mem_ctx,
779 struct NspiResolveNamesW *r)
781 DEBUG(3, ("exchange_nsp: NspiResolveNamesW (0x14) not implemented\n"));
782 DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
787 \details Dispatch incoming NSPI call to the correct OpenChange
788 server function.
790 \param dce_call pointer to the session context
791 \param mem_ctx pointer to the memory context
792 \param r generic pointer on NSPI data
793 \param mapiproxy pointer to the mapiproxy structure controlling
794 mapiproxy behavior
796 \return NT_STATUS_OK
798 static NTSTATUS dcesrv_exchange_nsp_dispatch(struct dcesrv_call_state *dce_call,
799 TALLOC_CTX *mem_ctx,
800 void *r, struct mapiproxy *mapiproxy)
802 enum MAPISTATUS retval;
803 const struct ndr_interface_table *table;
804 uint16_t opnum;
806 table = (const struct ndr_interface_table *) dce_call->context->iface->private_data;
807 opnum = dce_call->pkt.u.request.opnum;
809 /* Sanity checks */
810 if (!table) return NT_STATUS_UNSUCCESSFUL;
811 if (table->name && strcmp(table->name, NDR_EXCHANGE_NSP_NAME)) return NT_STATUS_UNSUCCESSFUL;
813 switch (opnum) {
814 case NDR_NSPIBIND:
815 retval = dcesrv_NspiBind(dce_call, mem_ctx, (struct NspiBind *)r);
816 break;
817 case NDR_NSPIUNBIND:
818 retval = dcesrv_NspiUnbind(dce_call, mem_ctx, (struct NspiUnbind *)r);
819 break;
820 case NDR_NSPIUPDATESTAT:
821 retval = dcesrv_NspiUpdateStat(dce_call, mem_ctx, (struct NspiUpdateStat *)r);
822 break;
823 case NDR_NSPIQUERYROWS:
824 retval = dcesrv_NspiQueryRows(dce_call, mem_ctx, (struct NspiQueryRows *)r);
825 break;
826 case NDR_NSPISEEKENTRIES:
827 retval = dcesrv_NspiSeekEntries(dce_call, mem_ctx, (struct NspiSeekEntries *)r);
828 break;
829 case NDR_NSPIGETMATCHES:
830 retval = dcesrv_NspiGetMatches(dce_call, mem_ctx, (struct NspiGetMatches *)r);
831 break;
832 case NDR_NSPIRESORTRESTRICTION:
833 retval = dcesrv_NspiResortRestriction(dce_call, mem_ctx, (struct NspiResortRestriction *)r);
834 break;
835 case NDR_NSPIDNTOMID:
836 retval = dcesrv_NspiDNToMId(dce_call, mem_ctx, (struct NspiDNToMId *)r);
837 break;
838 case NDR_NSPIGETPROPLIST:
839 retval = dcesrv_NspiGetPropList(dce_call, mem_ctx, (struct NspiGetPropList *)r);
840 break;
841 case NDR_NSPIGETPROPS:
842 retval = dcesrv_NspiGetProps(dce_call, mem_ctx, (struct NspiGetProps *)r);
843 break;
844 case NDR_NSPICOMPAREMIDS:
845 retval = dcesrv_NspiCompareMIds(dce_call, mem_ctx, (struct NspiCompareMIds *)r);
846 break;
847 case NDR_NSPIMODPROPS:
848 retval = dcesrv_NspiModProps(dce_call, mem_ctx, (struct NspiModProps *)r);
849 break;
850 case NDR_NSPIGETSPECIALTABLE:
851 retval = dcesrv_NspiGetSpecialTable(dce_call, mem_ctx, (struct NspiGetSpecialTable *)r);
852 break;
853 case NDR_NSPIGETTEMPLATEINFO:
854 retval = dcesrv_NspiGetTemplateInfo(dce_call, mem_ctx, (struct NspiGetTemplateInfo *)r);
855 break;
856 case NDR_NSPIMODLINKATT:
857 retval = dcesrv_NspiModLinkAtt(dce_call, mem_ctx, (struct NspiModLinkAtt *)r);
858 break;
859 case NDR_NSPIDELETEENTRIES:
860 retval = dcesrv_NspiDeleteEntries(dce_call, mem_ctx, (struct NspiDeleteEntries *)r);
861 break;
862 case NDR_NSPIQUERYCOLUMNS:
863 retval = dcesrv_NspiQueryColumns(dce_call, mem_ctx, (struct NspiQueryColumns *)r);
864 break;
865 case NDR_NSPIGETNAMESFROMIDS:
866 retval = dcesrv_NspiGetNamesFromIDs(dce_call, mem_ctx, (struct NspiGetNamesFromIDs *)r);
867 break;
868 case NDR_NSPIGETIDSFROMNAMES:
869 retval = dcesrv_NspiGetIDsFromNames(dce_call, mem_ctx, (struct NspiGetIDsFromNames *)r);
870 break;
871 case NDR_NSPIRESOLVENAMES:
872 retval = dcesrv_NspiResolveNames(dce_call, mem_ctx, (struct NspiResolveNames *)r);
873 break;
874 case NDR_NSPIRESOLVENAMESW:
875 retval = dcesrv_NspiResolveNamesW(dce_call, mem_ctx, (struct NspiResolveNamesW *)r);
876 break;
879 return NT_STATUS_OK;
884 \details Initialize the NSPI OpenChange server
886 \param dce_ctx pointer to the server context
888 \return NT_STATUS_OK on success, otherwise NT_STATUS_NO_MEMORY
890 static NTSTATUS dcesrv_exchange_nsp_init(struct dcesrv_context *dce_ctx)
892 /* Initialize exchange_nsp session */
893 nsp_session = talloc_zero(dce_ctx, struct exchange_nsp_session);
894 if (!nsp_session) return NT_STATUS_NO_MEMORY;
895 nsp_session->session = NULL;
897 /* Open a read-write pointer on the EMSABP TDB database */
898 emsabp_tdb_ctx = emsabp_tdb_init((TALLOC_CTX *)dce_ctx, dce_ctx->lp_ctx);
899 if (!emsabp_tdb_ctx) {
900 smb_panic("unable to initialize EMSABP context");
903 return NT_STATUS_OK;
908 \details Terminates the NSPI connection and release the associated
909 session and context if still available. This case occurs when the
910 client doesn't call NspiUnbind but quit unexpectedly.
912 \param server_id reference to the server identifier structure
913 \param context_id the connection context identifier
915 \return NT_STATUS_OK on success
917 static NTSTATUS dcesrv_exchange_nsp_unbind(struct server_id server_id, uint32_t context_id)
919 struct exchange_nsp_session *session;
921 for (session = nsp_session; session; session = session->next) {
922 if ((mpm_session_cmp_sub(session->session, server_id, context_id) == true)) {
923 mpm_session_release(session->session);
924 DLIST_REMOVE(nsp_session, session);
925 DEBUG(6, ("[%s:%d]: Session found and released\n", __FUNCTION__, __LINE__));
926 return NT_STATUS_OK;
930 return NT_STATUS_OK;
935 \details Entry point for the default OpenChange NSPI server
937 \return NT_STATUS_OK on success, otherwise NTSTATUS error
939 NTSTATUS samba_init_module(void)
941 struct mapiproxy_module server;
942 NTSTATUS ret;
944 /* Fill in our name */
945 server.name = "exchange_nsp";
946 server.status = MAPIPROXY_DEFAULT;
947 server.description = "OpenChange NSPI server";
948 server.endpoint = "exchange_nsp";
950 /* Fill in all the operations */
951 server.init = dcesrv_exchange_nsp_init;
952 server.unbind = dcesrv_exchange_nsp_unbind;
953 server.dispatch = dcesrv_exchange_nsp_dispatch;
954 server.push = NULL;
955 server.pull = NULL;
956 server.ndr_pull = NULL;
958 /* Register ourselves with the MAPIPROXY server subsystem */
959 ret = mapiproxy_server_register(&server);
960 if (!NT_STATUS_IS_OK(ret)) {
961 DEBUG(0, ("Failed to register the 'exchange_nsp' default mapiproxy server!\n"));
962 return ret;
965 return ret;