s3:winbind: Remove SID_NAME_ALIAS code from rpc_lookup_groupmem()
[samba.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(dom->name, ctx, &ctx->ads);
69         if (!ADS_ERR_OK(status)) {
70                 return status;
71         }
72
73         /* if we have a valid ADS_STRUCT and the schema model is
74            defined, then we can return here. */
75
76         if ( ctx->ad_schema ) {
77                 return ADS_SUCCESS;
78         }
79
80         /* Otherwise, set the schema model */
81
82         if ( (ctx->ad_map_type ==  WB_POSIX_MAP_SFU) ||
83              (ctx->ad_map_type ==  WB_POSIX_MAP_SFU20) ||
84              (ctx->ad_map_type ==  WB_POSIX_MAP_RFC2307) )
85         {
86                 status = ads_check_posix_schema_mapping(
87                         ctx, ctx->ads, ctx->ad_map_type, &ctx->ad_schema);
88                 if ( !ADS_ERR_OK(status) ) {
89                         DEBUG(2,("ad_idmap_cached_connection: Failed to obtain schema details!\n"));
90                 }
91         }
92
93         return status;
94 }
95
96 /*
97  * nss_info_{sfu,sfu20,rfc2307}
98  */
99
100 /************************************************************************
101  Initialize the {sfu,sfu20,rfc2307} state
102  ***********************************************************************/
103
104 static const char *wb_posix_map_unknown_string = "WB_POSIX_MAP_UNKNOWN";
105 static const char *wb_posix_map_template_string = "WB_POSIX_MAP_TEMPLATE";
106 static const char *wb_posix_map_sfu_string = "WB_POSIX_MAP_SFU";
107 static const char *wb_posix_map_sfu20_string = "WB_POSIX_MAP_SFU20";
108 static const char *wb_posix_map_rfc2307_string = "WB_POSIX_MAP_RFC2307";
109 static const char *wb_posix_map_unixinfo_string = "WB_POSIX_MAP_UNIXINFO";
110
111 static const char *ad_map_type_string(enum wb_posix_mapping map_type)
112 {
113         switch (map_type) {
114                 case WB_POSIX_MAP_TEMPLATE:
115                         return wb_posix_map_template_string;
116                 case WB_POSIX_MAP_SFU:
117                         return wb_posix_map_sfu_string;
118                 case WB_POSIX_MAP_SFU20:
119                         return wb_posix_map_sfu20_string;
120                 case WB_POSIX_MAP_RFC2307:
121                         return wb_posix_map_rfc2307_string;
122                 case WB_POSIX_MAP_UNIXINFO:
123                         return wb_posix_map_unixinfo_string;
124                 default:
125                         return wb_posix_map_unknown_string;
126         }
127 }
128
129 static NTSTATUS nss_ad_generic_init(struct nss_domain_entry *e,
130                                     enum wb_posix_mapping new_ad_map_type)
131 {
132         struct idmap_domain *dom;
133         struct idmap_ad_context *ctx;
134
135         if (e->state != NULL) {
136                 dom = talloc_get_type(e->state, struct idmap_domain);
137         } else {
138                 dom = talloc_zero(e, struct idmap_domain);
139                 if (dom == NULL) {
140                         DEBUG(0, ("Out of memory!\n"));
141                         return NT_STATUS_NO_MEMORY;
142                 }
143                 e->state = dom;
144         }
145
146         if (e->domain != NULL) {
147                 dom->name = talloc_strdup(dom, e->domain);
148                 if (dom->name == NULL) {
149                         DEBUG(0, ("Out of memory!\n"));
150                         return NT_STATUS_NO_MEMORY;
151                 }
152         }
153
154         if (dom->private_data != NULL) {
155                 ctx = talloc_get_type(dom->private_data,
156                                       struct idmap_ad_context);
157         } else {
158                 ctx = talloc_zero(dom, struct idmap_ad_context);
159                 if (ctx == NULL) {
160                         DEBUG(0, ("Out of memory!\n"));
161                         return NT_STATUS_NO_MEMORY;
162                 }
163                 ctx->ad_map_type = WB_POSIX_MAP_RFC2307;
164                 dom->private_data = ctx;
165         }
166
167         if ((ctx->ad_map_type != WB_POSIX_MAP_UNKNOWN) &&
168             (ctx->ad_map_type != new_ad_map_type))
169         {
170                 DEBUG(2, ("nss_ad_generic_init: "
171                           "Warning: overriding previously set posix map type "
172                           "%s for domain %s with map type %s.\n",
173                           ad_map_type_string(ctx->ad_map_type),
174                           dom->name,
175                           ad_map_type_string(new_ad_map_type)));
176         }
177
178         ctx->ad_map_type = new_ad_map_type;
179
180         return NT_STATUS_OK;
181 }
182
183 static NTSTATUS nss_sfu_init( struct nss_domain_entry *e )
184 {
185         return nss_ad_generic_init(e, WB_POSIX_MAP_SFU);
186 }
187
188 static NTSTATUS nss_sfu20_init( struct nss_domain_entry *e )
189 {
190         return nss_ad_generic_init(e, WB_POSIX_MAP_SFU20);
191 }
192
193 static NTSTATUS nss_rfc2307_init( struct nss_domain_entry *e )
194 {
195         return nss_ad_generic_init(e, WB_POSIX_MAP_RFC2307);
196 }
197
198 /**********************************************************************
199  *********************************************************************/
200
201 static NTSTATUS nss_ad_map_to_alias(TALLOC_CTX *mem_ctx,
202                                     struct nss_domain_entry *e,
203                                     const char *name,
204                                     char **alias)
205 {
206         const char *attrs[] = {NULL, /* attr_uid */
207                                NULL };
208         char *filter = NULL;
209         LDAPMessage *msg = NULL;
210         ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
211         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
212         struct idmap_domain *dom;
213         struct idmap_ad_context *ctx = NULL;
214
215         /* Check incoming parameters */
216
217         if ( !e || !e->domain || !name || !*alias) {
218                 nt_status = NT_STATUS_INVALID_PARAMETER;
219                 goto done;
220         }
221
222         /* Only do query if we are online */
223
224         if (idmap_is_offline()) {
225                 nt_status = NT_STATUS_FILE_IS_OFFLINE;
226                 goto done;
227         }
228
229         dom = talloc_get_type(e->state, struct idmap_domain);
230         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
231
232         ads_status = ad_idmap_cached_connection(dom);
233         if (!ADS_ERR_OK(ads_status)) {
234                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
235         }
236
237         if (!ctx->ad_schema) {
238                 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
239                 goto done;
240         }
241
242         attrs[0] = ctx->ad_schema->posix_uid_attr;
243
244         filter = talloc_asprintf(mem_ctx,
245                                  "(sAMAccountName=%s)",
246                                  name);
247         if (!filter) {
248                 nt_status = NT_STATUS_NO_MEMORY;
249                 goto done;
250         }
251
252         ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs);
253         if (!ADS_ERR_OK(ads_status)) {
254                 nt_status = ads_ntstatus(ads_status);
255                 goto done;
256         }
257
258         *alias = ads_pull_string(ctx->ads, mem_ctx, msg, ctx->ad_schema->posix_uid_attr);
259
260         if (!*alias) {
261                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
262         }
263
264         nt_status = NT_STATUS_OK;
265
266 done:
267         if (filter) {
268                 talloc_destroy(filter);
269         }
270         if (msg) {
271                 ads_msgfree(ctx->ads, msg);
272         }
273
274         return nt_status;
275 }
276
277 /**********************************************************************
278  *********************************************************************/
279
280 static NTSTATUS nss_ad_map_from_alias( TALLOC_CTX *mem_ctx,
281                                              struct nss_domain_entry *e,
282                                              const char *alias,
283                                              char **name )
284 {
285         const char *attrs[] = {"sAMAccountName",
286                                NULL };
287         char *filter = NULL;
288         LDAPMessage *msg = NULL;
289         ADS_STATUS ads_status = ADS_ERROR_NT(NT_STATUS_UNSUCCESSFUL);
290         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
291         char *username = NULL;
292         struct idmap_domain *dom;
293         struct idmap_ad_context *ctx = NULL;
294
295         /* Check incoming parameters */
296
297         if ( !alias || !name) {
298                 nt_status = NT_STATUS_INVALID_PARAMETER;
299                 goto done;
300         }
301
302         /* Only do query if we are online */
303
304         if (idmap_is_offline()) {
305                 nt_status = NT_STATUS_FILE_IS_OFFLINE;
306                 goto done;
307         }
308
309         dom = talloc_get_type(e->state, struct idmap_domain);
310         ctx = talloc_get_type(dom->private_data, struct idmap_ad_context);
311
312         ads_status = ad_idmap_cached_connection(dom);
313         if (!ADS_ERR_OK(ads_status)) {
314                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
315         }
316
317         if (!ctx->ad_schema) {
318                 nt_status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
319                 goto done;
320         }
321
322         filter = talloc_asprintf(mem_ctx,
323                                  "(%s=%s)",
324                                  ctx->ad_schema->posix_uid_attr,
325                                  alias);
326         if (!filter) {
327                 nt_status = NT_STATUS_NO_MEMORY;
328                 goto done;
329         }
330
331         ads_status = ads_search_retry(ctx->ads, &msg, filter, attrs);
332         if (!ADS_ERR_OK(ads_status)) {
333                 nt_status = ads_ntstatus(ads_status);
334                 goto done;
335         }
336
337         username = ads_pull_string(ctx->ads, mem_ctx, msg,
338                                    "sAMAccountName");
339         if (!username) {
340                 nt_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
341                 goto done;
342         }
343
344         *name = talloc_asprintf(mem_ctx, "%s\\%s",
345                                 lp_workgroup(),
346                                 username);
347         if (!*name) {
348                 nt_status = NT_STATUS_NO_MEMORY;
349                 goto done;
350         }
351
352         nt_status = NT_STATUS_OK;
353
354 done:
355         TALLOC_FREE(username);
356         TALLOC_FREE(filter);
357         if (msg) {
358                 ads_msgfree(ctx->ads, msg);
359         }
360
361         return nt_status;
362 }
363
364 /************************************************************************
365  Function dispatch tables for the idmap and nss plugins
366  ***********************************************************************/
367
368 /* The SFU and RFC2307 NSS plugins share everything but the init
369    function which sets the intended schema model to use */
370
371 static const struct nss_info_methods nss_rfc2307_methods = {
372         .init           = nss_rfc2307_init,
373         .map_to_alias   = nss_ad_map_to_alias,
374         .map_from_alias = nss_ad_map_from_alias,
375 };
376
377 static const struct nss_info_methods nss_sfu_methods = {
378         .init           = nss_sfu_init,
379         .map_to_alias   = nss_ad_map_to_alias,
380         .map_from_alias = nss_ad_map_from_alias,
381 };
382
383 static const struct nss_info_methods nss_sfu20_methods = {
384         .init           = nss_sfu20_init,
385         .map_to_alias   = nss_ad_map_to_alias,
386         .map_from_alias = nss_ad_map_from_alias,
387 };
388
389
390
391 /************************************************************************
392  Initialize the plugins
393  ***********************************************************************/
394
395 NTSTATUS idmap_ad_nss_init(TALLOC_CTX *mem_ctx)
396 {
397         NTSTATUS status;
398
399         status = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
400                                         "rfc2307",  &nss_rfc2307_methods);
401         if (!NT_STATUS_IS_OK(status)) {
402                 return status;
403         }
404
405         status = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
406                                         "sfu",  &nss_sfu_methods);
407         if (!NT_STATUS_IS_OK(status)) {
408                 return status;
409         }
410
411         status = smb_register_idmap_nss(SMB_NSS_INFO_INTERFACE_VERSION,
412                                         "sfu20",  &nss_sfu20_methods);
413         if (!NT_STATUS_IS_OK(status)) {
414                 return status;
415         }
416
417         return NT_STATUS_OK;
418 }