2ebdd59cfecb32d1618a280390f96493eaff1601
[jelmer/samba4-debian.git] / source / rpc_server / drsuapi / drsuapi_cracknames.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    endpoint server for the drsuapi pipe
5    DsCrackNames()
6
7    Copyright (C) Stefan Metzmacher 2004
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25 #include "librpc/gen_ndr/ndr_drsuapi.h"
26 #include "rpc_server/dcerpc_server.h"
27 #include "rpc_server/common/common.h"
28 #include "rpc_server/drsuapi/dcesrv_drsuapi.h"
29 #include "lib/ldb/include/ldb.h"
30
31 static WERROR DsCrackNameOneName(struct drsuapi_bind_state *b_state, TALLOC_CTX *mem_ctx,
32                         uint32 format_flags, uint32 format_offered, uint32 format_desired,
33                         const char *name, struct drsuapi_DsNameInfo1 *info1)
34 {
35         int ret;
36         const char *domain_filter = NULL;
37         const char * const *domain_attrs;
38         struct ldb_message **domain_res = NULL;
39         const char *result_basedn = NULL;
40         const char *result_filter = NULL;
41         const char * const *result_attrs;
42         struct ldb_message **result_res = NULL;
43
44         info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
45         info1->dns_domain_name = NULL;
46         info1->result_name = NULL;
47
48         if (!name) {
49                 return WERR_INVALID_PARAM;
50         }
51
52         /* TODO: - fill the correct names in all cases!
53          *       - handle format_flags
54          */
55
56         /* here we need to set the domain_filter and/or the result_filter */
57         switch (format_offered) {
58                 case DRSUAPI_DS_NAME_FORMAT_CANONICAL: {
59                         char *str;
60
61                         str = talloc_asprintf(mem_ctx, "%s/", lp_realm());
62                         WERR_TALLOC_CHECK(str);
63
64                         ret = strcasecmp(str, name);
65                         talloc_free(str);
66                         if (ret != 0) {
67                                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
68                                 return WERR_OK;
69                         }
70
71                         domain_filter = talloc_asprintf(mem_ctx, "(&(objectClass=domainDNS)(name=%s))",
72                                                                 lp_workgroup());
73                         WERR_TALLOC_CHECK(domain_filter);
74
75                         break;
76                 }
77                 case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
78                         char *p;
79                         char *domain;
80                         const char *account = NULL;
81
82                         domain = talloc_strdup(mem_ctx, name);
83                         WERR_TALLOC_CHECK(domain);
84
85                         p = strchr(domain, '\\');
86                         if (!p) {
87                                 /* invalid input format */
88                                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
89                                 return WERR_OK;
90                         }
91                         p[0] = '\0';
92
93                         if (p[1]) {
94                                 account = &p[1];
95                         }
96
97                         domain_filter = talloc_asprintf(mem_ctx, "(&(objectClass=domainDNS)(name=%s))",
98                                                                 domain);
99                         WERR_TALLOC_CHECK(domain_filter);
100                         if (account) {
101                                 result_filter = talloc_asprintf(mem_ctx, "(sAMAccountName=%s)",
102                                                                 account);
103                                 WERR_TALLOC_CHECK(result_filter);
104                         }
105
106                         talloc_free(domain);
107                         break;
108                 }
109                 default: {
110                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
111                         return WERR_OK;
112                 }
113         }
114
115         /* here we need to set the attrs lists for domain and result lookups */
116         switch (format_desired) {
117                 case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
118                         const char * const _domain_attrs[] = { "dn", "dnsDomain", NULL};
119                         const char * const _result_attrs[] = { "dn", NULL};
120                         
121                         domain_attrs = _domain_attrs;
122                         result_attrs = _result_attrs;
123                         break;
124                 }
125                 case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
126                         const char * const _domain_attrs[] = { "name", "dnsDomain", "dn", NULL};
127                         const char * const _result_attrs[] = { "sAMAccountName", NULL};
128                         
129                         domain_attrs = _domain_attrs;
130                         result_attrs = _result_attrs;
131                         break;
132                 }
133                 case DRSUAPI_DS_NAME_FORMAT_GUID: {
134                         const char * const _domain_attrs[] = { "objectGUID", "dnsDomain", "dn", NULL};
135                         const char * const _result_attrs[] = { "objectGUID", NULL};
136                         
137                         domain_attrs = _domain_attrs;
138                         result_attrs = _result_attrs;
139                         break;
140                 }
141                 default:
142                         return WERR_OK;
143         }
144
145         /* if we have a domain_filter look it up and set the result_basedn and the dns_domain_name */
146         ret = samdb_search(b_state->sam_ctx, mem_ctx, NULL, &domain_res, domain_attrs,
147                                 "%s", domain_filter);
148         switch (ret) {
149                 case 1:
150                         break;
151                 case 0:
152                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
153                         return WERR_OK;
154                 case -1:
155                         info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
156                         return WERR_OK;
157                 default:
158                         info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
159                         return WERR_OK;
160         }
161
162         info1->dns_domain_name  = samdb_result_string(domain_res[0], "dnsDomain", NULL);
163         WERR_TALLOC_CHECK(info1->dns_domain_name);
164         info1->status           = DRSUAPI_DS_NAME_STATUS_DOMAIN_ONLY;
165
166         if (result_filter) {
167                 result_basedn = samdb_result_string(domain_res[0], "dn", NULL);
168
169                 ret = samdb_search(b_state->sam_ctx, mem_ctx, result_basedn, &result_res,
170                                         result_attrs, "%s", result_filter);
171                 switch (ret) {
172                         case 1:
173                                 break;
174                         case 0:
175                                 return WERR_OK;
176                         case -1:
177                                 info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
178                                 return WERR_OK;
179                         default:
180                                 info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
181                                 return WERR_OK;
182                 }
183         } else {
184                 result_res = domain_res;
185         }
186
187         /* here we can use result_res[0] and domain_res[0] */
188         switch (format_desired) {
189                 case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
190                         info1->result_name      = samdb_result_string(result_res[0], "dn", NULL);
191                         WERR_TALLOC_CHECK(info1->result_name);
192
193                         info1->status           = DRSUAPI_DS_NAME_STATUS_OK;
194                         return WERR_OK;
195                 }
196                 case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
197                         const char *_dom;
198                         const char *_acc = "";
199
200                         _dom = samdb_result_string(domain_res[0], "name", NULL);
201                         WERR_TALLOC_CHECK(_dom);
202
203                         if (result_filter) {
204                                 _acc = samdb_result_string(result_res[0], "sAMAccountName", NULL);
205                                 WERR_TALLOC_CHECK(_acc);
206                         }
207
208                         info1->result_name      = talloc_asprintf(mem_ctx, "%s\\%s", _dom, _acc);
209                         WERR_TALLOC_CHECK(info1->result_name);
210
211                         info1->status           = DRSUAPI_DS_NAME_STATUS_OK;
212                         return WERR_OK;
213                 }
214                 case DRSUAPI_DS_NAME_FORMAT_GUID: {
215                         const char *result;
216
217                         result = samdb_result_string(result_res[0], "objectGUID", NULL);
218                         WERR_TALLOC_CHECK(result);
219                         
220                         info1->result_name      = talloc_asprintf(mem_ctx, "{%s}", result);
221                         WERR_TALLOC_CHECK(info1->result_name);
222
223                         info1->status           = DRSUAPI_DS_NAME_STATUS_OK;
224                         return WERR_OK;
225                 }
226                 default:
227                         return WERR_OK;
228         }
229
230         return WERR_INVALID_PARAM;
231 }
232
233 /* 
234   drsuapi_DsCrackNames 
235 */
236 WERROR dcesrv_drsuapi_DsCrackNames(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
237                        struct drsuapi_DsCrackNames *r)
238 {
239         WERROR status;
240         struct drsuapi_bind_state *b_state;
241         struct dcesrv_handle *h;
242
243         r->out.level = r->in.level;
244         ZERO_STRUCT(r->out.ctr);
245
246         DCESRV_PULL_HANDLE_WERR(h, r->in.bind_handle, DRSUAPI_BIND_HANDLE);
247         b_state = h->data;
248
249         switch (r->in.level) {
250                 case 1: {
251                         struct drsuapi_DsNameCtr1 *ctr1;
252                         struct drsuapi_DsNameInfo1 *names;
253                         int count;
254                         int i;
255
256                         ctr1 = talloc_p(mem_ctx, struct drsuapi_DsNameCtr1);
257                         WERR_TALLOC_CHECK(ctr1);
258
259                         count = r->in.req.req1.count;
260                         names = talloc_array_p(mem_ctx, struct drsuapi_DsNameInfo1, count);
261                         WERR_TALLOC_CHECK(names);
262
263                         for (i=0; i < count; i++) {
264                                 status = DsCrackNameOneName(b_state, mem_ctx,
265                                                             r->in.req.req1.format_flags,
266                                                             r->in.req.req1.format_offered,
267                                                             r->in.req.req1.format_desired,
268                                                             r->in.req.req1.names[i].str,
269                                                             &names[i]);
270                                 if (!W_ERROR_IS_OK(status)) {
271                                         return status;
272                                 }
273                         }
274
275                         ctr1->count = count;
276                         ctr1->array = names;
277                         r->out.ctr.ctr1 = ctr1;
278
279                         return WERR_OK;
280                 }
281         }
282         
283         return WERR_UNKNOWN_LEVEL;
284 }