s3-ipasam: implement enum_trusted_domains
[mat/samba.git] / source3 / passdb / pdb_ipa.c
1 /*
2    Unix SMB/CIFS implementation.
3    IPA helper functions for SAMBA
4    Copyright (C) Sumit Bose <sbose@redhat.com> 2010
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 #include "includes.h"
22
23 #include "smbldap.h"
24
25 #define LDAP_TRUST_CONTAINER "ou=system"
26 #define LDAP_ATTRIBUTE_CN "cn"
27 #define LDAP_ATTRIBUTE_TRUST_TYPE "sambaTrustType"
28 #define LDAP_ATTRIBUTE_TRUST_ATTRIBUTES "sambaTrustAttributes"
29 #define LDAP_ATTRIBUTE_TRUST_DIRECTION "sambaTrustDirection"
30 #define LDAP_ATTRIBUTE_TRUST_PARTNER "sambaTrustPartner"
31 #define LDAP_ATTRIBUTE_FLAT_NAME "sambaFlatName"
32 #define LDAP_ATTRIBUTE_TRUST_AUTH_OUTGOING "sambaTrustAuthOutgoing"
33 #define LDAP_ATTRIBUTE_TRUST_AUTH_INCOMING "sambaTrustAuthIncoming"
34 #define LDAP_ATTRIBUTE_SECURITY_IDENTIFIER "sambaSecurityIdentifier"
35
36 static bool ipasam_get_trusteddom_pw(struct pdb_methods *methods,
37                                      const char *domain,
38                                      char** pwd,
39                                      struct dom_sid *sid,
40                                      time_t *pass_last_set_time)
41 {
42         return false;
43 }
44
45 static bool ipasam_set_trusteddom_pw(struct pdb_methods *methods,
46                                      const char* domain,
47                                      const char* pwd,
48                                      const struct dom_sid *sid)
49 {
50         return false;
51 }
52
53 static bool ipasam_del_trusteddom_pw(struct pdb_methods *methods,
54                                      const char *domain)
55 {
56         return false;
57 }
58
59 static NTSTATUS ipasam_enum_trusteddoms(struct pdb_methods *methods,
60                                         TALLOC_CTX *mem_ctx,
61                                         uint32_t *num_domains,
62                                         struct trustdom_info ***domains)
63 {
64         return NT_STATUS_NOT_IMPLEMENTED;
65 }
66
67 static char *trusted_domain_dn(struct ldapsam_privates *ldap_state,
68                                const char *domain)
69 {
70         return talloc_asprintf(talloc_tos(), "%s=%s,%s,%s",
71                                LDAP_ATTRIBUTE_CN, domain,
72                                LDAP_TRUST_CONTAINER, ldap_state->domain_dn);
73 }
74
75 static char *trusted_domain_base_dn(struct ldapsam_privates *ldap_state)
76 {
77         return talloc_asprintf(talloc_tos(), "%s,%s",
78                                LDAP_TRUST_CONTAINER, ldap_state->domain_dn);
79 }
80
81 static bool get_trusted_domain_int(struct ldapsam_privates *ldap_state,
82                                    TALLOC_CTX *mem_ctx,
83                                    const char *domain, LDAPMessage **entry)
84 {
85         int rc;
86         char *filter = NULL;
87         char *base_dn = NULL;
88         LDAPMessage *result = NULL;
89         uint32_t num_result;
90
91         filter = talloc_asprintf(talloc_tos(),
92                                  "(&(objectClass=%s)(|(sambaFlatName=%s)(cn=%s)(sambaTrustPartner=%s)))",
93                                  LDAP_OBJ_TRUSTED_DOMAIN, domain, domain, domain);
94         if (filter == NULL) {
95                 return false;
96         }
97
98         base_dn = trusted_domain_base_dn(ldap_state);
99         if (base_dn == NULL) {
100                 TALLOC_FREE(filter);
101                 return false;
102         }
103
104         rc = smbldap_search(ldap_state->smbldap_state, base_dn,
105                             LDAP_SCOPE_SUBTREE, filter, NULL, 0, &result);
106         TALLOC_FREE(filter);
107         TALLOC_FREE(base_dn);
108
109         if (result != NULL) {
110                 talloc_autofree_ldapmsg(mem_ctx, result);
111         }
112
113         if (rc == LDAP_NO_SUCH_OBJECT) {
114                 *entry = NULL;
115                 return true;
116         }
117
118         if (rc != LDAP_SUCCESS) {
119                 return false;
120         }
121
122         num_result = ldap_count_entries(priv2ld(ldap_state), result);
123
124         if (num_result > 1) {
125                 DEBUG(1, ("get_trusted_domain_int: more than one "
126                           "%s object for domain '%s'?!\n",
127                           LDAP_OBJ_TRUSTED_DOMAIN, domain));
128                 return false;
129         }
130
131         if (num_result == 0) {
132                 DEBUG(1, ("get_trusted_domain_int: no "
133                           "%s object for domain %s.\n",
134                           LDAP_OBJ_TRUSTED_DOMAIN, domain));
135                 *entry = NULL;
136         } else {
137                 *entry = ldap_first_entry(priv2ld(ldap_state), result);
138         }
139
140         return true;
141 }
142
143 static bool get_uint32_t_from_ldap_msg(struct ldapsam_privates *ldap_state,
144                                        LDAPMessage *entry,
145                                        const char *attr,
146                                        uint32_t *val)
147 {
148         char *dummy;
149         long int l;
150         char *endptr;
151
152         dummy = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry,
153                                                 attr, talloc_tos());
154         if (dummy == NULL) {
155                 DEBUG(9, ("Attribute %s not present.\n", attr));
156                 *val = 0;
157                 return true;
158         }
159
160         l = strtoul(dummy, &endptr, 10);
161         TALLOC_FREE(dummy);
162
163         if (l < 0 || l > UINT32_MAX || *endptr != '\0') {
164                 return false;
165         }
166
167         *val = l;
168
169         return true;
170 }
171
172 static void get_data_blob_from_ldap_msg(TALLOC_CTX *mem_ctx,
173                                         struct ldapsam_privates *ldap_state,
174                                         LDAPMessage *entry, const char *attr,
175                                         DATA_BLOB *_blob)
176 {
177         char *dummy;
178         DATA_BLOB blob;
179
180         dummy = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, attr,
181                                                 talloc_tos());
182         if (dummy == NULL) {
183                 DEBUG(9, ("Attribute %s not present.\n", attr));
184                 ZERO_STRUCTP(_blob);
185         } else {
186                 blob = base64_decode_data_blob(dummy);
187                 if (blob.length == 0) {
188                         ZERO_STRUCTP(_blob);
189                 } else {
190                         _blob->length = blob.length;
191                         _blob->data = talloc_steal(mem_ctx, blob.data);
192                 }
193         }
194         TALLOC_FREE(dummy);
195 }
196
197 static bool fill_pdb_trusted_domain(TALLOC_CTX *mem_ctx,
198                                     struct ldapsam_privates *ldap_state,
199                                     LDAPMessage *entry,
200                                     struct pdb_trusted_domain **_td)
201 {
202         char *dummy;
203         bool res;
204         struct pdb_trusted_domain *td;
205
206         if (entry == NULL) {
207                 return false;
208         }
209
210         td = talloc_zero(mem_ctx, struct pdb_trusted_domain);
211         if (td == NULL) {
212                 return false;
213         }
214
215         /* All attributes are MAY */
216
217         dummy = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry,
218                                                 LDAP_ATTRIBUTE_SECURITY_IDENTIFIER,
219                                                 talloc_tos());
220         if (dummy == NULL) {
221                 DEBUG(9, ("Attribute %s not present.\n",
222                           LDAP_ATTRIBUTE_SECURITY_IDENTIFIER));
223                 ZERO_STRUCT(td->security_identifier);
224         } else {
225                 res = string_to_sid(&td->security_identifier, dummy);
226                 TALLOC_FREE(dummy);
227                 if (!res) {
228                         return false;
229                 }
230         }
231
232         get_data_blob_from_ldap_msg(td, ldap_state, entry,
233                                     LDAP_ATTRIBUTE_TRUST_AUTH_INCOMING,
234                                     &td->trust_auth_incoming);
235
236         get_data_blob_from_ldap_msg(td, ldap_state, entry,
237                                     LDAP_ATTRIBUTE_TRUST_AUTH_OUTGOING,
238                                     &td->trust_auth_outgoing);
239
240         td->netbios_name = smbldap_talloc_single_attribute(priv2ld(ldap_state),
241                                                            entry,
242                                                            LDAP_ATTRIBUTE_FLAT_NAME,
243                                                            td);
244         if (td->netbios_name == NULL) {
245                 DEBUG(9, ("Attribute %s not present.\n",
246                           LDAP_ATTRIBUTE_FLAT_NAME));
247         }
248
249         td->domain_name = smbldap_talloc_single_attribute(priv2ld(ldap_state),
250                                                           entry,
251                                                           LDAP_ATTRIBUTE_TRUST_PARTNER,
252                                                           td);
253         if (td->domain_name == NULL) {
254                 DEBUG(9, ("Attribute %s not present.\n",
255                           LDAP_ATTRIBUTE_TRUST_PARTNER));
256         }
257
258         res = get_uint32_t_from_ldap_msg(ldap_state, entry,
259                                          LDAP_ATTRIBUTE_TRUST_DIRECTION,
260                                          &td->trust_direction);
261         if (!res) {
262                 return false;
263         }
264
265         res = get_uint32_t_from_ldap_msg(ldap_state, entry,
266                                          LDAP_ATTRIBUTE_TRUST_ATTRIBUTES,
267                                          &td->trust_attributes);
268         if (!res) {
269                 return false;
270         }
271
272         res = get_uint32_t_from_ldap_msg(ldap_state, entry,
273                                          LDAP_ATTRIBUTE_TRUST_TYPE,
274                                          &td->trust_type);
275         if (!res) {
276                 return false;
277         }
278
279         *_td = td;
280
281         return true;
282 }
283
284 static NTSTATUS ipasam_get_trusted_domain(struct pdb_methods *methods,
285                                           TALLOC_CTX *mem_ctx,
286                                           const char *domain,
287                                           struct pdb_trusted_domain **td)
288 {
289         struct ldapsam_privates *ldap_state =
290                 (struct ldapsam_privates *)methods->private_data;
291         LDAPMessage *entry = NULL;
292
293         DEBUG(10, ("ipasam_get_trusted_domain called for domain %s\n", domain));
294
295         if (!get_trusted_domain_int(ldap_state, talloc_tos(), domain, &entry)) {
296                 return NT_STATUS_UNSUCCESSFUL;
297         }
298         if (entry == NULL) {
299                 DEBUG(5, ("ipasam_get_trusted_domain: no such trusted domain: "
300                           "%s\n", domain));
301                 return NT_STATUS_NO_SUCH_DOMAIN;
302         }
303
304         if (!fill_pdb_trusted_domain(mem_ctx, ldap_state, entry, td)) {
305                 return NT_STATUS_UNSUCCESSFUL;
306         }
307
308         return NT_STATUS_OK;
309 }
310
311 static bool smbldap_make_mod_uint32_t(LDAP *ldap_struct, LDAPMessage *entry,
312                                       LDAPMod ***mods, const char *attribute,
313                                       const uint32_t val)
314 {
315         char *dummy;
316
317         dummy = talloc_asprintf(talloc_tos(), "%lu", (unsigned long) val);
318         if (dummy == NULL) {
319                 return false;
320         }
321         smbldap_make_mod(ldap_struct, entry, mods, attribute, dummy);
322         TALLOC_FREE(dummy);
323
324         return true;
325 }
326
327 static bool smbldap_make_mod_blob(LDAP *ldap_struct, LDAPMessage *entry,
328                                   LDAPMod ***mods, const char *attribute,
329                                   DATA_BLOB blob)
330 {
331         char *dummy;
332
333         dummy = base64_encode_data_blob(talloc_tos(), blob);
334         if (dummy == NULL) {
335                 return false;
336         }
337
338         smbldap_make_mod(ldap_struct, entry, mods, attribute, dummy);
339         TALLOC_FREE(dummy);
340
341         return true;
342 }
343
344 static NTSTATUS ipasam_set_trusted_domain(struct pdb_methods *methods,
345                                           const char* domain,
346                                           const struct pdb_trusted_domain *td)
347 {
348         struct ldapsam_privates *ldap_state =
349                 (struct ldapsam_privates *)methods->private_data;
350         LDAPMessage *entry = NULL;
351         LDAPMod **mods;
352         bool res;
353         char *trusted_dn = NULL;
354         int ret;
355
356         DEBUG(10, ("ipasam_set_trusted_domain called for domain %s\n", domain));
357
358         res = get_trusted_domain_int(ldap_state, talloc_tos(), domain, &entry);
359         if (!res) {
360                 return NT_STATUS_UNSUCCESSFUL;
361         }
362
363         mods = NULL;
364         smbldap_make_mod(priv2ld(ldap_state), entry, &mods, "objectClass",
365                          LDAP_OBJ_TRUSTED_DOMAIN);
366
367         if (td->netbios_name != NULL) {
368                 smbldap_make_mod(priv2ld(ldap_state), entry, &mods,
369                                  LDAP_ATTRIBUTE_FLAT_NAME,
370                                  td->netbios_name);
371         }
372
373         if (td->domain_name != NULL) {
374                 smbldap_make_mod(priv2ld(ldap_state), entry, &mods,
375                                  LDAP_ATTRIBUTE_TRUST_PARTNER,
376                                  td->domain_name);
377         }
378
379         if (!is_null_sid(&td->security_identifier)) {
380                 smbldap_make_mod(priv2ld(ldap_state), entry, &mods,
381                                  LDAP_ATTRIBUTE_SECURITY_IDENTIFIER,
382                                  sid_string_tos(&td->security_identifier));
383         }
384
385         if (td->trust_type != 0) {
386                 res = smbldap_make_mod_uint32_t(priv2ld(ldap_state), entry,
387                                                 &mods, LDAP_ATTRIBUTE_TRUST_TYPE,
388                                                 td->trust_type);
389                 if (!res) {
390                         return NT_STATUS_UNSUCCESSFUL;
391                 }
392         }
393
394         if (td->trust_attributes != 0) {
395                 res = smbldap_make_mod_uint32_t(priv2ld(ldap_state), entry,
396                                                 &mods,
397                                                 LDAP_ATTRIBUTE_TRUST_ATTRIBUTES,
398                                                 td->trust_attributes);
399                 if (!res) {
400                         return NT_STATUS_UNSUCCESSFUL;
401                 }
402         }
403
404         if (td->trust_direction != 0) {
405                 res = smbldap_make_mod_uint32_t(priv2ld(ldap_state), entry,
406                                                 &mods,
407                                                 LDAP_ATTRIBUTE_TRUST_DIRECTION,
408                                                 td->trust_direction);
409                 if (!res) {
410                         return NT_STATUS_UNSUCCESSFUL;
411                 }
412         }
413
414         if (td->trust_auth_outgoing.data != NULL) {
415                 res = smbldap_make_mod_blob(priv2ld(ldap_state), entry,
416                                             &mods,
417                                             LDAP_ATTRIBUTE_TRUST_AUTH_OUTGOING,
418                                             td->trust_auth_outgoing);
419                 if (!res) {
420                         return NT_STATUS_UNSUCCESSFUL;
421                 }
422         }
423
424         if (td->trust_auth_incoming.data != NULL) {
425                 res = smbldap_make_mod_blob(priv2ld(ldap_state), entry,
426                                             &mods,
427                                             LDAP_ATTRIBUTE_TRUST_AUTH_INCOMING,
428                                             td->trust_auth_incoming);
429                 if (!res) {
430                         return NT_STATUS_UNSUCCESSFUL;
431                 }
432         }
433
434         talloc_autofree_ldapmod(talloc_tos(), mods);
435
436         trusted_dn = trusted_domain_dn(ldap_state, domain);
437         if (trusted_dn == NULL) {
438                 return NT_STATUS_NO_MEMORY;
439         }
440         if (entry == NULL) {
441                 ret = smbldap_add(ldap_state->smbldap_state, trusted_dn, mods);
442         } else {
443                 ret = smbldap_modify(ldap_state->smbldap_state, trusted_dn, mods);
444         }
445
446         if (ret != LDAP_SUCCESS) {
447                 DEBUG(1, ("error writing trusted domain data!\n"));
448                 return NT_STATUS_UNSUCCESSFUL;
449         }
450         return NT_STATUS_OK;
451 }
452
453 static NTSTATUS ipasam_del_trusted_domain(struct pdb_methods *methods,
454                                           const char *domain)
455 {
456         int ret;
457         struct ldapsam_privates *ldap_state =
458                 (struct ldapsam_privates *)methods->private_data;
459         LDAPMessage *entry = NULL;
460         const char *dn;
461
462         if (!get_trusted_domain_int(ldap_state, talloc_tos(), domain, &entry)) {
463                 return NT_STATUS_UNSUCCESSFUL;
464         }
465
466         if (entry == NULL) {
467                 DEBUG(5, ("ipasam_del_trusted_domain: no such trusted domain: "
468                           "%s\n", domain));
469                 return NT_STATUS_NO_SUCH_DOMAIN;
470         }
471
472         dn = smbldap_talloc_dn(talloc_tos(), priv2ld(ldap_state), entry);
473         if (dn == NULL) {
474                 DEBUG(0,("ipasam_del_trusted_domain: Out of memory!\n"));
475                 return NT_STATUS_NO_MEMORY;
476         }
477
478         ret = smbldap_delete(ldap_state->smbldap_state, dn);
479         if (ret != LDAP_SUCCESS) {
480                 return NT_STATUS_UNSUCCESSFUL;
481         }
482
483         return NT_STATUS_OK;
484 }
485
486 static NTSTATUS ipasam_enum_trusted_domains(struct pdb_methods *methods,
487                                             TALLOC_CTX *mem_ctx,
488                                             uint32_t *num_domains,
489                                             struct pdb_trusted_domain ***domains)
490 {
491         int rc;
492         struct ldapsam_privates *ldap_state =
493                 (struct ldapsam_privates *)methods->private_data;
494         char *base_dn = NULL;
495         char *filter = NULL;
496         int scope = LDAP_SCOPE_SUBTREE;
497         LDAPMessage *result = NULL;
498         LDAPMessage *entry = NULL;
499
500         filter = talloc_asprintf(talloc_tos(), "(objectClass=%s)",
501                                  LDAP_OBJ_TRUSTED_DOMAIN);
502         if (filter == NULL) {
503                 return NT_STATUS_NO_MEMORY;
504         }
505
506         base_dn = trusted_domain_base_dn(ldap_state);
507         if (base_dn == NULL) {
508                 TALLOC_FREE(filter);
509                 return NT_STATUS_NO_MEMORY;
510         }
511
512         rc = smbldap_search(ldap_state->smbldap_state, base_dn, scope, filter,
513                             NULL, 0, &result);
514         TALLOC_FREE(filter);
515         TALLOC_FREE(base_dn);
516
517         if (result != NULL) {
518                 talloc_autofree_ldapmsg(mem_ctx, result);
519         }
520
521         if (rc == LDAP_NO_SUCH_OBJECT) {
522                 *num_domains = 0;
523                 *domains = NULL;
524                 return NT_STATUS_OK;
525         }
526
527         if (rc != LDAP_SUCCESS) {
528                 return NT_STATUS_UNSUCCESSFUL;
529         }
530
531         *num_domains = 0;
532         if (!(*domains = TALLOC_ARRAY(mem_ctx, struct pdb_trusted_domain *, 1))) {
533                 DEBUG(1, ("talloc failed\n"));
534                 return NT_STATUS_NO_MEMORY;
535         }
536
537         for (entry = ldap_first_entry(priv2ld(ldap_state), result);
538              entry != NULL;
539              entry = ldap_next_entry(priv2ld(ldap_state), entry))
540         {
541                 struct pdb_trusted_domain *dom_info;
542
543                 if (!fill_pdb_trusted_domain(*domains, ldap_state, entry,
544                                              &dom_info)) {
545                         return NT_STATUS_UNSUCCESSFUL;
546                 }
547
548                 ADD_TO_ARRAY(*domains, struct pdb_trusted_domain *, dom_info,
549                              domains, num_domains);
550
551                 if (*domains == NULL) {
552                         DEBUG(1, ("talloc failed\n"));
553                         return NT_STATUS_NO_MEMORY;
554                 }
555         }
556
557         DEBUG(5, ("ipasam_enum_trusted_domains: got %d domains\n", *num_domains));
558         return NT_STATUS_OK;
559 }
560
561 static NTSTATUS pdb_init_IPA_ldapsam(struct pdb_methods **pdb_method, const char *location)
562 {
563         struct ldapsam_privates *ldap_state;
564
565         NTSTATUS nt_status = pdb_init_ldapsam(pdb_method, location);
566
567         (*pdb_method)->name = "IPA_ldapsam";
568
569         ldap_state = (struct ldapsam_privates *)((*pdb_method)->private_data);
570         ldap_state->is_ipa_ldap = true;
571
572         (*pdb_method)->get_trusteddom_pw = ipasam_get_trusteddom_pw;
573         (*pdb_method)->set_trusteddom_pw = ipasam_set_trusteddom_pw;
574         (*pdb_method)->del_trusteddom_pw = ipasam_del_trusteddom_pw;
575         (*pdb_method)->enum_trusteddoms = ipasam_enum_trusteddoms;
576
577         (*pdb_method)->get_trusted_domain = ipasam_get_trusted_domain;
578         (*pdb_method)->set_trusted_domain = ipasam_set_trusted_domain;
579         (*pdb_method)->del_trusted_domain = ipasam_del_trusted_domain;
580         (*pdb_method)->enum_trusted_domains = ipasam_enum_trusted_domains;
581
582         return nt_status;
583 }
584
585 NTSTATUS pdb_ipa_init(void)
586 {
587         NTSTATUS nt_status;
588
589         if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "IPA_ldapsam", pdb_init_IPA_ldapsam)))
590                 return nt_status;
591
592         return NT_STATUS_OK;
593 }