pyldb: avoid segfault when adding an element with no name
[kai/samba-autobuild/.git] / source3 / winbindd / idmap_ad_nss.c
1 /*
2  *  idmap_ad: map between Active Directory and RFC 2307 or "Services for Unix" (SFU) Accounts
3  *
4  * Unix SMB/CIFS implementation.
5  *
6  * Winbind ADS backend functions
7  *
8  * Copyright (C) Andrew Tridgell 2001
9  * Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003
10  * Copyright (C) Gerald (Jerry) Carter 2004-2007
11  * Copyright (C) Luke Howard 2001-2004
12  * Copyright (C) Michael Adam 2008,2010
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, see <http://www.gnu.org/licenses/>.
26  */
27
28 #include "includes.h"
29 #include "winbindd.h"
30 #include "../libds/common/flags.h"
31 #include "winbindd_ads.h"
32 #include "libads/ldap_schema.h"
33 #include "nss_info.h"
34 #include "idmap.h"
35 #include "../libcli/ldap/ldap_ndr.h"
36 #include "../libcli/security/security.h"
37
38 #undef DBGC_CLASS
39 #define DBGC_CLASS DBGC_IDMAP
40
41 #define CHECK_ALLOC_DONE(mem) do { \
42      if (!mem) { \
43            DEBUG(0, ("Out of memory!\n")); \
44            ret = NT_STATUS_NO_MEMORY; \
45            goto done; \
46       } \
47 } while (0)
48
49 struct idmap_ad_context {
50         ADS_STRUCT *ads;
51         struct posix_schema *ad_schema;
52         enum wb_posix_mapping ad_map_type; /* WB_POSIX_MAP_UNKNOWN */
53 };
54
55 /************************************************************************
56  ***********************************************************************/
57
58 static ADS_STATUS ad_idmap_cached_connection(struct idmap_domain *dom)
59 {
60         ADS_STATUS status;
61         struct idmap_ad_context * ctx;
62
63         DEBUG(10, ("ad_idmap_cached_connection: called for domain '%s'\n",
64                    dom->name));
65
66         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
67
68         status = ads_idmap_cached_connection(&ctx->ads, dom->name);
69         if (!ADS_ERR_OK(status)) {
70                 return status;
71         }
72
73         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
74
75         /* if we have a valid ADS_STRUCT and the schema model is
76            defined, then we can return here. */
77
78         if ( ctx->ad_schema ) {
79                 return ADS_SUCCESS;
80         }
81
82         /* Otherwise, set the schema model */
83
84         if ( (ctx->ad_map_type ==  WB_POSIX_MAP_SFU) ||
85              (ctx->ad_map_type ==  WB_POSIX_MAP_SFU20) ||
86              (ctx->ad_map_type ==  WB_POSIX_MAP_RFC2307) )
87         {
88                 status = ads_check_posix_schema_mapping(
89                         ctx, ctx->ads, ctx->ad_map_type, &ctx->ad_schema);
90                 if ( !ADS_ERR_OK(status) ) {
91                         DEBUG(2,("ad_idmap_cached_connection: Failed to obtain schema details!\n"));
92                 }
93         }
94
95         return status;
96 }
97
98 /*
99  * nss_info_{sfu,sfu20,rfc2307}
100  */
101
102 /************************************************************************
103  Initialize the {sfu,sfu20,rfc2307} state
104  ***********************************************************************/
105
106 static const char *wb_posix_map_unknown_string = "WB_POSIX_MAP_UNKNOWN";
107 static const char *wb_posix_map_template_string = "WB_POSIX_MAP_TEMPLATE";
108 static const char *wb_posix_map_sfu_string = "WB_POSIX_MAP_SFU";
109 static const char *wb_posix_map_sfu20_string = "WB_POSIX_MAP_SFU20";
110 static const char *wb_posix_map_rfc2307_string = "WB_POSIX_MAP_RFC2307";
111 static const char *wb_posix_map_unixinfo_string = "WB_POSIX_MAP_UNIXINFO";
112
113 static const char *ad_map_type_string(enum wb_posix_mapping map_type)
114 {
115         switch (map_type) {
116                 case WB_POSIX_MAP_TEMPLATE:
117                         return wb_posix_map_template_string;
118                 case WB_POSIX_MAP_SFU:
119                         return wb_posix_map_sfu_string;
120                 case WB_POSIX_MAP_SFU20:
121                         return wb_posix_map_sfu20_string;
122                 case WB_POSIX_MAP_RFC2307:
123                         return wb_posix_map_rfc2307_string;
124                 case WB_POSIX_MAP_UNIXINFO:
125                         return wb_posix_map_unixinfo_string;
126                 default:
127                         return wb_posix_map_unknown_string;
128         }
129 }
130
131 static NTSTATUS nss_ad_generic_init(struct nss_domain_entry *e,
132                                     enum wb_posix_mapping new_ad_map_type)
133 {
134         struct idmap_domain *dom;
135         struct idmap_ad_context *ctx;
136
137         if (e->state != NULL) {
138                 dom = talloc_get_type(e->state, struct idmap_domain);
139         } else {
140                 dom = talloc_zero(e, struct idmap_domain);
141                 if (dom == NULL) {
142                         DEBUG(0, ("Out of memory!\n"));
143                         return NT_STATUS_NO_MEMORY;
144                 }
145                 e->state = dom;
146         }
147
148         if (e->domain != NULL) {
149                 dom->name = talloc_strdup(dom, e->domain);
150                 if (dom->name == NULL) {
151                         DEBUG(0, ("Out of memory!\n"));
152                         return NT_STATUS_NO_MEMORY;
153                 }
154         }
155
156         if (dom->private_data != NULL) {
157                 ctx = talloc_get_type(dom->private_data,
158                                       struct idmap_ad_context);
159         } else {
160                 ctx = talloc_zero(dom, struct idmap_ad_context);
161                 if (ctx == NULL) {
162                         DEBUG(0, ("Out of memory!\n"));
163                         return NT_STATUS_NO_MEMORY;
164                 }
165                 ctx->ad_map_type = WB_POSIX_MAP_RFC2307;
166                 dom->private_data = ctx;
167         }
168
169         if ((ctx->ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
170             (ctx->ad_map_type != new_ad_map_type))
171         {
172                 DEBUG(2, ("nss_ad_generic_init: "
173                           "Warning: overriding previously set posix map type "
174                           "%s for domain %s with map type %s.\n",
175                           ad_map_type_string(ctx->ad_map_type),
176                           dom->name,
177                           ad_map_type_string(new_ad_map_type)));
178         }
179
180         ctx->ad_map_type = new_ad_map_type;
181
182         return NT_STATUS_OK;
183 }
184
185 static NTSTATUS nss_sfu_init( struct nss_domain_entry *e )
186 {
187         return nss_ad_generic_init(e, WB_POSIX_MAP_SFU);
188 }
189
190 static NTSTATUS nss_sfu20_init( struct nss_domain_entry *e )
191 {
192         return nss_ad_generic_init(e, WB_POSIX_MAP_SFU20);
193 }
194
195 static NTSTATUS nss_rfc2307_init( struct nss_domain_entry *e )
196 {
197         return nss_ad_generic_init(e, WB_POSIX_MAP_RFC2307);
198 }
199
200 /**********************************************************************
201  *********************************************************************/
202
203 static NTSTATUS nss_ad_map_to_alias(TALLOC_CTX *mem_ctx,
204                                     struct nss_domain_entry *e,
205                                     const char *name,
206                                     char **alias)
207 {
208         const char *attrs[] = {NULL, /* attr_uid */
209                                NULL };
210         char *filter = NULL;
211         LDAPMessage *msg = NULL;
212         ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
213         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
214         struct idmap_domain *dom;
215         struct idmap_ad_context *ctx = NULL;
216
217         /* Check incoming parameters */
218
219         if ( !e || !e->domain || !name || !*alias) {
220                 nt_status = NT_STATUS_INVALID_PARAMETER;
221                 goto done;
222         }
223
224         /* Only do query if we are online */
225
226         if (idmap_is_offline()) {
227                 nt_status = NT_STATUS_FILE_IS_OFFLINE;
228                 goto done;
229         }
230
231         dom = talloc_get_type(e->state, struct idmap_domain);
232         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
233
234         ads_status = ad_idmap_cached_connection(dom);
235         if (!ADS_ERR_OK(ads_status)) {
236                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
237         }
238
239         if (!ctx->ad_schema) {
240                 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
241                 goto done;
242         }
243
244         attrs[0] = ctx->ad_schema->posix_uid_attr;
245
246         filter = talloc_asprintf(mem_ctx,
247                                  "(sAMAccountName=%s)",
248                                  name);
249         if (!filter) {
250                 nt_status = NT_STATUS_NO_MEMORY;
251                 goto done;
252         }
253
254         ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs);
255         if (!ADS_ERR_OK(ads_status)) {
256                 nt_status = ads_ntstatus(ads_status);
257                 goto done;
258         }
259
260         *alias = ads_pull_string(ctx->ads, mem_ctx, msg, ctx->ad_schema->posix_uid_attr);
261
262         if (!*alias) {
263                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
264         }
265
266         nt_status = NT_STATUS_OK;
267
268 done:
269         if (filter) {
270                 talloc_destroy(filter);
271         }
272         if (msg) {
273                 ads_msgfree(ctx->ads, msg);
274         }
275
276         return nt_status;
277 }
278
279 /**********************************************************************
280  *********************************************************************/
281
282 static NTSTATUS nss_ad_map_from_alias( TALLOC_CTX *mem_ctx,
283                                              struct nss_domain_entry *e,
284                                              const char *alias,
285                                              char **name )
286 {
287         const char *attrs[] = {"sAMAccountName",
288                                NULL };
289         char *filter = NULL;
290         LDAPMessage *msg = NULL;
291         ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
292         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
293         char *username = NULL;
294         struct idmap_domain *dom;
295         struct idmap_ad_context *ctx = NULL;
296
297         /* Check incoming parameters */
298
299         if ( !alias || !name) {
300                 nt_status = NT_STATUS_INVALID_PARAMETER;
301                 goto done;
302         }
303
304         /* Only do query if we are online */
305
306         if (idmap_is_offline()) {
307                 nt_status = NT_STATUS_FILE_IS_OFFLINE;
308                 goto done;
309         }
310
311         dom = talloc_get_type(e->state, struct idmap_domain);
312         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
313
314         ads_status = ad_idmap_cached_connection(dom);
315         if (!ADS_ERR_OK(ads_status)) {
316                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
317         }
318
319         if (!ctx->ad_schema) {
320                 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
321                 goto done;
322         }
323
324         filter = talloc_asprintf(mem_ctx,
325                                  "(%s=%s)",
326                                  ctx->ad_schema->posix_uid_attr,
327                                  alias);
328         if (!filter) {
329                 nt_status = NT_STATUS_NO_MEMORY;
330                 goto done;
331         }
332
333         ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs);
334         if (!ADS_ERR_OK(ads_status)) {
335                 nt_status = ads_ntstatus(ads_status);
336                 goto done;
337         }
338
339         username = ads_pull_string(ctx->ads, mem_ctx, msg,
340                                    "sAMAccountName");
341         if (!username) {
342                 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
343                 goto done;
344         }
345
346         *name = talloc_asprintf(mem_ctx, "%s\\%s",
347                                 lp_workgroup(),
348                                 username);
349         if (!*name) {
350                 nt_status = NT_STATUS_NO_MEMORY;
351                 goto done;
352         }
353
354         nt_status = NT_STATUS_OK;
355
356 done:
357         TALLOC_FREE(username);
358         TALLOC_FREE(filter);
359         if (msg) {
360                 ads_msgfree(ctx->ads, msg);
361         }
362
363         return nt_status;
364 }
365
366 /************************************************************************
367  Function dispatch tables for the idmap and nss plugins
368  ***********************************************************************/
369
370 /* The SFU and RFC2307 NSS plugins share everything but the init
371    function which sets the intended schema model to use */
372
373 static struct nss_info_methods nss_rfc2307_methods = {
374         .init           = nss_rfc2307_init,
375         .map_to_alias   = nss_ad_map_to_alias,
376         .map_from_alias = nss_ad_map_from_alias,
377 };
378
379 static struct nss_info_methods nss_sfu_methods = {
380         .init           = nss_sfu_init,
381         .map_to_alias   = nss_ad_map_to_alias,
382         .map_from_alias = nss_ad_map_from_alias,
383 };
384
385 static struct nss_info_methods nss_sfu20_methods = {
386         .init           = nss_sfu20_init,
387         .map_to_alias   = nss_ad_map_to_alias,
388         .map_from_alias = nss_ad_map_from_alias,
389 };
390
391
392
393 /************************************************************************
394  Initialize the plugins
395  ***********************************************************************/
396
397 NTSTATUS idmap_ad_nss_init(TALLOC_CTX *mem_ctx)
398 {
399         NTSTATUS status;
400
401         status = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
402                                         "rfc2307",  &nss_rfc2307_methods);
403         if (!NT_STATUS_IS_OK(status)) {
404                 return status;
405         }
406
407         status = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
408                                         "sfu",  &nss_sfu_methods);
409         if (!NT_STATUS_IS_OK(status)) {
410                 return status;
411         }
412
413         status = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
414                                         "sfu20",  &nss_sfu20_methods);
415         if (!NT_STATUS_IS_OK(status)) {
416                 return status;
417         }
418
419         return NT_STATUS_OK;
420 }