51aac14906c9e7697e0df22333950444d77173da
[samba.git] / source3 / libads / ldap_schema.c
1 /* 
2    Unix SMB/CIFS implementation.
3    ads (active directory) utility library
4    Copyright (C) Guenther Deschner 2005-2007
5    Copyright (C) Gerald (Jerry) Carter 2006
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "ads.h"
23 #include "libads/ldap_schema.h"
24 #include "../libcli/ldap/ldap_ndr.h"
25
26 #ifdef HAVE_LDAP
27
28 static ADS_STATUS ads_get_attrnames_by_oids(ADS_STRUCT *ads,
29                                             TALLOC_CTX *mem_ctx,
30                                             const char *schema_path,
31                                             const char **OIDs,
32                                             size_t num_OIDs,
33                                             char ***OIDs_out, char ***names,
34                                             size_t *count)
35 {
36         ADS_STATUS status;
37         LDAPMessage *res = NULL;
38         LDAPMessage *msg;
39         char *expr = NULL;
40         const char *attrs[] = { "lDAPDisplayName", "attributeId", NULL };
41         int i = 0, p = 0;
42         
43         if (!ads || !mem_ctx || !names || !count || !OIDs || !OIDs_out) {
44                 return ADS_ERROR(LDAP_PARAM_ERROR);
45         }
46
47         if (num_OIDs == 0 || OIDs[0] == NULL) {
48                 return ADS_ERROR_NT(NT_STATUS_NONE_MAPPED);
49         }
50
51         if ((expr = talloc_asprintf(mem_ctx, "(|")) == NULL) {
52                 return ADS_ERROR(LDAP_NO_MEMORY);
53         }
54
55         for (i=0; i<num_OIDs; i++) {
56
57                 if ((expr = talloc_asprintf_append_buffer(expr, "(attributeId=%s)", 
58                                                    OIDs[i])) == NULL) {
59                         return ADS_ERROR(LDAP_NO_MEMORY);
60                 }
61         }
62
63         if ((expr = talloc_asprintf_append_buffer(expr, ")")) == NULL) {
64                 return ADS_ERROR(LDAP_NO_MEMORY);
65         }
66
67         status = ads_do_search_retry(ads, schema_path, 
68                                      LDAP_SCOPE_SUBTREE, expr, attrs, &res);
69         if (!ADS_ERR_OK(status)) {
70                 return status;
71         }
72
73         *count = ads_count_replies(ads, res);
74         if (*count == 0 || !res) {
75                 status = ADS_ERROR_NT(NT_STATUS_NONE_MAPPED);
76                 goto out;
77         }
78
79         if (((*names) = TALLOC_ARRAY(mem_ctx, char *, *count)) == NULL) {
80                 status = ADS_ERROR(LDAP_NO_MEMORY);
81                 goto out;
82         }
83         if (((*OIDs_out) = TALLOC_ARRAY(mem_ctx, char *, *count)) == NULL) {
84                 status = ADS_ERROR(LDAP_NO_MEMORY);
85                 goto out;
86         }
87
88         for (msg = ads_first_entry(ads, res); msg != NULL; 
89              msg = ads_next_entry(ads, msg)) {
90
91                 (*names)[p]     = ads_pull_string(ads, mem_ctx, msg, 
92                                                   "lDAPDisplayName");
93                 (*OIDs_out)[p]  = ads_pull_string(ads, mem_ctx, msg, 
94                                                   "attributeId");
95                 if (((*names)[p] == NULL) || ((*OIDs_out)[p] == NULL)) {
96                         status = ADS_ERROR(LDAP_NO_MEMORY);
97                         goto out;
98                 }
99
100                 p++;
101         }
102
103         if (*count < num_OIDs) {
104                 status = ADS_ERROR_NT(STATUS_SOME_UNMAPPED);
105                 goto out;
106         }
107
108         status = ADS_ERROR(LDAP_SUCCESS);
109 out:
110         ads_msgfree(ads, res);
111
112         return status;
113 }
114
115 const char *ads_get_attrname_by_guid(ADS_STRUCT *ads, 
116                                      const char *schema_path, 
117                                      TALLOC_CTX *mem_ctx, 
118                                      const struct GUID *schema_guid)
119 {
120         ADS_STATUS rc;
121         LDAPMessage *res = NULL;
122         char *expr = NULL;
123         const char *attrs[] = { "lDAPDisplayName", NULL };
124         const char *result = NULL;
125         char *guid_bin = NULL;
126
127         if (!ads || !mem_ctx || !schema_guid) {
128                 goto done;
129         }
130
131         guid_bin = ldap_encode_ndr_GUID(mem_ctx, schema_guid);
132         if (!guid_bin) {
133                 goto done;
134         }
135
136         expr = talloc_asprintf(mem_ctx, "(schemaIDGUID=%s)", guid_bin);
137         if (!expr) {
138                 goto done;
139         }
140
141         rc = ads_do_search_retry(ads, schema_path, LDAP_SCOPE_SUBTREE, 
142                                  expr, attrs, &res);
143         if (!ADS_ERR_OK(rc)) {
144                 goto done;
145         }
146
147         if (ads_count_replies(ads, res) != 1) {
148                 goto done;
149         }
150
151         result = ads_pull_string(ads, mem_ctx, res, "lDAPDisplayName");
152
153  done:
154         TALLOC_FREE(guid_bin);
155         ads_msgfree(ads, res);
156         return result;
157         
158 }
159
160 /*********************************************************************
161 *********************************************************************/
162
163 ADS_STATUS ads_schema_path(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, char **schema_path)
164 {
165         ADS_STATUS status;
166         LDAPMessage *res;
167         const char *schema;
168         const char *attrs[] = { "schemaNamingContext", NULL };
169
170         status = ads_do_search(ads, "", LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res);
171         if (!ADS_ERR_OK(status)) {
172                 return status;
173         }
174
175         if ( (schema = ads_pull_string(ads, mem_ctx, res, "schemaNamingContext")) == NULL ) {
176                 ads_msgfree(ads, res);
177                 return ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
178         }
179
180         if ( (*schema_path = talloc_strdup(mem_ctx, schema)) == NULL ) {
181                 ads_msgfree(ads, res);
182                 return ADS_ERROR(LDAP_NO_MEMORY);
183         }
184
185         ads_msgfree(ads, res);
186
187         return status;
188 }
189
190 /**
191  * Check for "Services for Unix" or rfc2307 Schema and load some attributes into the ADS_STRUCT
192  * @param ads connection to ads server
193  * @param enum mapping type
194  * @return ADS_STATUS status of search (False if one or more attributes couldn't be
195  * found in Active Directory)
196  **/ 
197 ADS_STATUS ads_check_posix_schema_mapping(TALLOC_CTX *mem_ctx,
198                                           ADS_STRUCT *ads,
199                                           enum wb_posix_mapping map_type,
200                                           struct posix_schema **s ) 
201 {
202         TALLOC_CTX *ctx = NULL; 
203         ADS_STATUS status;
204         char **oids_out, **names_out;
205         size_t num_names;
206         char *schema_path = NULL;
207         int i;
208         struct posix_schema *schema = NULL;
209
210         const char *oids_sfu[] = {      ADS_ATTR_SFU_UIDNUMBER_OID,
211                                         ADS_ATTR_SFU_GIDNUMBER_OID,
212                                         ADS_ATTR_SFU_HOMEDIR_OID,
213                                         ADS_ATTR_SFU_SHELL_OID,
214                                         ADS_ATTR_SFU_GECOS_OID,
215                                         ADS_ATTR_SFU_UID_OID };
216
217         const char *oids_sfu20[] = {    ADS_ATTR_SFU20_UIDNUMBER_OID,
218                                         ADS_ATTR_SFU20_GIDNUMBER_OID,
219                                         ADS_ATTR_SFU20_HOMEDIR_OID,
220                                         ADS_ATTR_SFU20_SHELL_OID,
221                                         ADS_ATTR_SFU20_GECOS_OID,
222                                         ADS_ATTR_SFU20_UID_OID };
223
224         const char *oids_rfc2307[] = {  ADS_ATTR_RFC2307_UIDNUMBER_OID,
225                                         ADS_ATTR_RFC2307_GIDNUMBER_OID,
226                                         ADS_ATTR_RFC2307_HOMEDIR_OID,
227                                         ADS_ATTR_RFC2307_SHELL_OID,
228                                         ADS_ATTR_RFC2307_GECOS_OID,
229                                         ADS_ATTR_RFC2307_UID_OID };
230
231         DEBUG(10,("ads_check_posix_schema_mapping for schema mode: %d\n", map_type));
232
233         switch (map_type) {
234         
235                 case WB_POSIX_MAP_TEMPLATE:
236                 case WB_POSIX_MAP_UNIXINFO:
237                         DEBUG(10,("ads_check_posix_schema_mapping: nothing to do\n"));
238                         return ADS_ERROR(LDAP_SUCCESS);
239
240                 case WB_POSIX_MAP_SFU:
241                 case WB_POSIX_MAP_SFU20:
242                 case WB_POSIX_MAP_RFC2307:
243                         break;
244
245                 default:
246                         DEBUG(0,("ads_check_posix_schema_mapping: "
247                                  "unknown enum %d\n", map_type));
248                         return ADS_ERROR(LDAP_PARAM_ERROR);
249         }
250
251         if ( (ctx = talloc_init("ads_check_posix_schema_mapping")) == NULL ) {
252                 return ADS_ERROR(LDAP_NO_MEMORY);
253         }
254
255         if ( (schema = TALLOC_P(mem_ctx, struct posix_schema)) == NULL ) {
256                 TALLOC_FREE( ctx );
257                 return ADS_ERROR(LDAP_NO_MEMORY);
258         }
259         
260         status = ads_schema_path(ads, ctx, &schema_path);
261         if (!ADS_ERR_OK(status)) {
262                 DEBUG(3,("ads_check_posix_mapping: Unable to retrieve schema DN!\n"));
263                 goto done;
264         }
265
266         switch (map_type) {
267                 case WB_POSIX_MAP_SFU:
268                         status = ads_get_attrnames_by_oids(ads, ctx, schema_path, oids_sfu, 
269                                                            ARRAY_SIZE(oids_sfu), 
270                                                            &oids_out, &names_out, &num_names);
271                         break;
272                 case WB_POSIX_MAP_SFU20:
273                         status = ads_get_attrnames_by_oids(ads, ctx, schema_path, oids_sfu20, 
274                                                            ARRAY_SIZE(oids_sfu20), 
275                                                            &oids_out, &names_out, &num_names);
276                         break;
277                 case WB_POSIX_MAP_RFC2307:
278                         status = ads_get_attrnames_by_oids(ads, ctx, schema_path, oids_rfc2307, 
279                                                            ARRAY_SIZE(oids_rfc2307), 
280                                                            &oids_out, &names_out, &num_names);
281                         break;
282                 default:
283                         status = ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
284                         break;
285         }
286
287         if (!ADS_ERR_OK(status)) {
288                 DEBUG(3,("ads_check_posix_schema_mapping: failed %s\n", 
289                         ads_errstr(status)));
290                 goto done;
291         }
292
293         for (i=0; i<num_names; i++) {
294
295                 DEBUGADD(10,("\tOID %s has name: %s\n", oids_out[i], names_out[i]));
296
297                 if (strequal(ADS_ATTR_RFC2307_UIDNUMBER_OID, oids_out[i]) ||
298                     strequal(ADS_ATTR_SFU_UIDNUMBER_OID, oids_out[i]) ||
299                     strequal(ADS_ATTR_SFU20_UIDNUMBER_OID, oids_out[i])) {
300                         schema->posix_uidnumber_attr = talloc_strdup(schema, names_out[i]);
301                         continue;                      
302                 }
303
304                 if (strequal(ADS_ATTR_RFC2307_GIDNUMBER_OID, oids_out[i]) ||
305                     strequal(ADS_ATTR_SFU_GIDNUMBER_OID, oids_out[i]) ||
306                     strequal(ADS_ATTR_SFU20_GIDNUMBER_OID, oids_out[i])) {
307                         schema->posix_gidnumber_attr = talloc_strdup(schema, names_out[i]);
308                         continue;               
309                 }
310
311                 if (strequal(ADS_ATTR_RFC2307_HOMEDIR_OID, oids_out[i]) ||
312                     strequal(ADS_ATTR_SFU_HOMEDIR_OID, oids_out[i]) ||
313                     strequal(ADS_ATTR_SFU20_HOMEDIR_OID, oids_out[i])) {
314                         schema->posix_homedir_attr = talloc_strdup(schema, names_out[i]);
315                         continue;                       
316                 }
317
318                 if (strequal(ADS_ATTR_RFC2307_SHELL_OID, oids_out[i]) ||
319                     strequal(ADS_ATTR_SFU_SHELL_OID, oids_out[i]) ||
320                     strequal(ADS_ATTR_SFU20_SHELL_OID, oids_out[i])) {
321                         schema->posix_shell_attr = talloc_strdup(schema, names_out[i]);
322                         continue;                       
323                 }
324
325                 if (strequal(ADS_ATTR_RFC2307_GECOS_OID, oids_out[i]) ||
326                     strequal(ADS_ATTR_SFU_GECOS_OID, oids_out[i]) ||
327                     strequal(ADS_ATTR_SFU20_GECOS_OID, oids_out[i])) {
328                         schema->posix_gecos_attr = talloc_strdup(schema, names_out[i]);
329                 }
330
331                 if (strequal(ADS_ATTR_RFC2307_UID_OID, oids_out[i]) ||
332                     strequal(ADS_ATTR_SFU_UID_OID, oids_out[i]) ||
333                     strequal(ADS_ATTR_SFU20_UID_OID, oids_out[i])) {
334                         schema->posix_uid_attr = talloc_strdup(schema, names_out[i]);
335                 }
336         }
337
338         if (!schema->posix_uidnumber_attr ||
339             !schema->posix_gidnumber_attr ||
340             !schema->posix_homedir_attr ||
341             !schema->posix_shell_attr ||
342             !schema->posix_gecos_attr) {
343                 status = ADS_ERROR(LDAP_NO_MEMORY);
344                 TALLOC_FREE( schema );          
345                 goto done;
346         }
347
348         *s = schema;
349         
350         status = ADS_ERROR(LDAP_SUCCESS);
351         
352 done:
353         TALLOC_FREE(ctx);
354
355         return status;
356 }
357
358 #endif