Merge in r3497 and r3498 from sogo branch
[jelmer/openchange.git] / mapiproxy / dcesrv_mapiproxy_nspi.c
1 /*
2    MAPI Proxy - NSPI
3
4    OpenChange Project
5
6    Copyright (C) Julien Kerihuel 2008
7
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.
12    
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.
17    
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/>.
20  */
21
22 #include "mapiproxy/dcesrv_mapiproxy.h"
23 #include "mapiproxy/dcesrv_mapiproxy_proto.h"
24
25 /**
26    \file dcesrv_mapiproxy_nspi.c
27
28    \brief NSPI hook functions
29  */
30
31 /**
32    \details Retrieve the servername from a DN string
33  
34    \param dn the DN string
35
36    \return a talloc'd server name
37  */
38 static char *x500_get_servername(const char *dn)
39 {
40         char *pdn;
41         char *servername;
42
43         if (!dn) {
44                 return NULL;
45         }
46
47         pdn = strcasestr(dn, SERVERNAME);
48         if (pdn == NULL) return NULL;
49
50         pdn += strlen(SERVERNAME);
51         servername = strsep(&pdn, "/");
52
53         return (talloc_strdup(NULL, servername));
54 }
55
56
57 /**
58    \details This function replaces network address from the binding
59    strings returned by Exchange for the PR_EMS_AB_NETWORK_ADDRESS
60    property and limit the binding strings scope to ncacn_ip_tcp.
61
62    \param dce_call pointer to the session context
63    \param r pointer to the NspiGetProps structure
64
65    \return true on success, otherwise false
66  */
67 bool mapiproxy_NspiGetProps(struct dcesrv_call_state *dce_call, struct NspiGetProps *r)
68 {
69         uint32_t                i;
70         uint32_t                propID = -1;
71         struct SPropTagArray    *SPropTagArray = NULL;
72         struct SRow             *SRow;
73         struct StringArray_r    *slpstr;
74         struct SPropValue       *lpProp;
75
76         /* Sanity checks */
77         if (!r->out.ppRows) return false;
78         if (!(*r->out.ppRows)->cValues) return false;
79
80         /* Step 1. Find PR_EMS_AB_NETWORK_ADDRESS index */
81         propID = -1;
82         SPropTagArray = r->in.pPropTags;
83         for (i = 0; i < SPropTagArray->cValues; i++) {
84                 if (SPropTagArray->aulPropTag[i] == PR_EMS_AB_NETWORK_ADDRESS) {
85                         propID = i;
86                         break;
87                 }
88         }
89         if (propID == -1) return false;
90
91         /* Step 2. Retrieve the SLPSTRArray */
92         SRow = *r->out.ppRows;
93         lpProp = &SRow->lpProps[propID];
94
95         if (!lpProp) return false;
96         if (lpProp->ulPropTag != PR_EMS_AB_NETWORK_ADDRESS) return false;
97
98         slpstr = &(lpProp->value.MVszA);
99
100         /* Step 3. Modify Exchange binding strings and only return ncacn_ip_tcp */
101         slpstr->cValues = 1;
102         slpstr->lppszA[0] = talloc_asprintf(dce_call, "ncacn_ip_tcp:%s.%s", 
103                                             lpcfg_netbios_name(dce_call->conn->dce_ctx->lp_ctx), 
104                                             lpcfg_realm(dce_call->conn->dce_ctx->lp_ctx));
105         slpstr->lppszA[0] = strlower_talloc(dce_call, slpstr->lppszA[0]);
106
107         return true;
108 }
109
110
111 /**
112    \details This function replaces the Exchange server name with
113    mapiproxy netbios name for the PR_EMS_AB_HOME_MDB property and
114    saves the original name in a global variable for further usage -
115    such as mapiproxy_NspiDNToMId.
116
117    \param dce_call pointer to the session context
118    \param r pointer to the NspiQueryRows structure
119
120    \sa mapiproxy_NspiDNToMId
121 */
122 bool mapiproxy_NspiQueryRows(struct dcesrv_call_state *dce_call, struct NspiQueryRows *r)
123 {
124         struct dcesrv_mapiproxy_private *private;
125         uint32_t                i;
126         uint32_t                propID = -1;
127         struct SPropTagArray    *SPropTagArray = NULL;
128         struct SRowSet          *SRowSet;
129         struct SPropValue       *lpProp;
130         char                    *lpszA;
131         char                    *exchname;
132
133         private = dce_call->context->private_data;
134
135         /* Sanity checks */
136         if (!r->out.ppRows) return false;
137         if (!(*r->out.ppRows)->cRows) return false;
138         if (!r->in.pPropTags) return false;
139
140         /* Step 1. Find PR_EMS_AB_HOME_MDB index */
141         propID = -1;
142         SPropTagArray = r->in.pPropTags;
143         for (i = 0; i < SPropTagArray->cValues; i++) {
144                 if (SPropTagArray->aulPropTag[i] == PR_EMS_AB_HOME_MDB) {
145                         propID = i;
146                         break;
147                 }
148         }
149         if (propID == -1) return false;
150
151         /* Retrieve the lpszA */
152         SRowSet = *r->out.ppRows;
153         lpProp = &(SRowSet->aRow->lpProps[propID]);
154
155         if (!lpProp) return false;
156         if (lpProp->ulPropTag != PR_EMS_AB_HOME_MDB) return false;
157
158         if (private->exchname) {
159                 if (strstr(lpProp->value.lpszA, private->exchname)) {
160                         lpProp->value.lpszA = string_sub_talloc((TALLOC_CTX *) dce_call, lpProp->value.lpszA, private->exchname, 
161                                                                 lpcfg_netbios_name(dce_call->conn->dce_ctx->lp_ctx));   
162                 }
163         } else {
164                 lpszA = talloc_strdup(dce_call, lpProp->value.lpszA);
165                 if ((exchname = x500_get_servername(lpszA))) {
166                         private->exchname = talloc_strdup(NULL, exchname);
167                         lpProp->value.lpszA = string_sub_talloc((TALLOC_CTX *) dce_call, lpProp->value.lpszA, exchname, 
168                                                                 lpcfg_netbios_name(dce_call->conn->dce_ctx->lp_ctx));
169                         talloc_free(exchname);
170                 }
171                 talloc_free(lpszA);
172         }
173
174         return true;
175 }
176
177
178 /**
179    \details This function looks if the server DN string in the request
180    holds the mapiproxy netbios name and replaces it with the original
181    Exchange server one fetched from NspiQueryRows or NspiGetProps.
182
183    \param dce_call pointer to the session context
184    \param r pointer to the NspiDNToMId structure
185
186    \return true on success or false if no occurrence of the mapiproxy
187    netbios name was found.
188 */
189 bool mapiproxy_NspiDNToMId(struct dcesrv_call_state *dce_call, struct NspiDNToMId *r)
190 {
191         struct dcesrv_mapiproxy_private *private;
192         const char                      *proxyname;
193         uint32_t                        i;
194
195         private = dce_call->context->private_data;
196         proxyname = lpcfg_netbios_name(dce_call->conn->dce_ctx->lp_ctx);
197
198         if (!private->exchname) return false;
199
200         for (i = 0; i < r->in.pNames->Count; i++) {
201                 if (strstr(r->in.pNames->Strings[i], proxyname)) {
202                         r->in.pNames->Strings[i] = string_sub_talloc((TALLOC_CTX *) dce_call, r->in.pNames->Strings[i], proxyname, private->exchname);
203                         return true;
204                 }
205         }
206
207         return false;
208 }