868958d2073a48742d5c03c3552e9ede47d8d184
[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 char *trusted_domain_dn(struct ldapsam_privates *ldap_state,
60                                const char *domain)
61 {
62         return talloc_asprintf(talloc_tos(), "%s=%s,%s,%s",
63                                LDAP_ATTRIBUTE_CN, domain,
64                                LDAP_TRUST_CONTAINER, ldap_state->domain_dn);
65 }
66
67 static char *trusted_domain_base_dn(struct ldapsam_privates *ldap_state)
68 {
69         return talloc_asprintf(talloc_tos(), "%s,%s",
70                                LDAP_TRUST_CONTAINER, ldap_state->domain_dn);
71 }
72
73 static bool get_trusted_domain_int(struct ldapsam_privates *ldap_state,
74                                    TALLOC_CTX *mem_ctx,
75                                    const char *domain, LDAPMessage **entry)
76 {
77         int rc;
78         char *filter = NULL;
79         char *base_dn = NULL;
80         LDAPMessage *result = NULL;
81         uint32_t num_result;
82
83         filter = talloc_asprintf(talloc_tos(),
84                                  "(&(objectClass=%s)(|(sambaFlatName=%s)(cn=%s)(sambaTrustPartner=%s)))",
85                                  LDAP_OBJ_TRUSTED_DOMAIN, domain, domain, domain);
86         if (filter == NULL) {
87                 return false;
88         }
89
90         base_dn = trusted_domain_base_dn(ldap_state);
91         if (base_dn == NULL) {
92                 TALLOC_FREE(filter);
93                 return false;
94         }
95
96         rc = smbldap_search(ldap_state->smbldap_state, base_dn,
97                             LDAP_SCOPE_SUBTREE, filter, NULL, 0, &result);
98         TALLOC_FREE(filter);
99         TALLOC_FREE(base_dn);
100
101         if (result != NULL) {
102                 talloc_autofree_ldapmsg(mem_ctx, result);
103         }
104
105         if (rc == LDAP_NO_SUCH_OBJECT) {
106                 *entry = NULL;
107                 return true;
108         }
109
110         if (rc != LDAP_SUCCESS) {
111                 return false;
112         }
113
114         num_result = ldap_count_entries(priv2ld(ldap_state), result);
115
116         if (num_result > 1) {
117                 DEBUG(1, ("get_trusted_domain_int: more than one "
118                           "%s object for domain '%s'?!\n",
119                           LDAP_OBJ_TRUSTED_DOMAIN, domain));
120                 return false;
121         }
122
123         if (num_result == 0) {
124                 DEBUG(1, ("get_trusted_domain_int: no "
125                           "%s object for domain %s.\n",
126                           LDAP_OBJ_TRUSTED_DOMAIN, domain));
127                 *entry = NULL;
128         } else {
129                 *entry = ldap_first_entry(priv2ld(ldap_state), result);
130         }
131
132         return true;
133 }
134
135 static bool get_uint32_t_from_ldap_msg(struct ldapsam_privates *ldap_state,
136                                        LDAPMessage *entry,
137                                        const char *attr,
138                                        uint32_t *val)
139 {
140         char *dummy;
141         long int l;
142         char *endptr;
143
144         dummy = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry,
145                                                 attr, talloc_tos());
146         if (dummy == NULL) {
147                 DEBUG(9, ("Attribute %s not present.\n", attr));
148                 *val = 0;
149                 return true;
150         }
151
152         l = strtoul(dummy, &endptr, 10);
153         TALLOC_FREE(dummy);
154
155         if (l < 0 || l > UINT32_MAX || *endptr != '\0') {
156                 return false;
157         }
158
159         *val = l;
160
161         return true;
162 }
163
164 static void get_data_blob_from_ldap_msg(TALLOC_CTX *mem_ctx,
165                                         struct ldapsam_privates *ldap_state,
166                                         LDAPMessage *entry, const char *attr,
167                                         DATA_BLOB *_blob)
168 {
169         char *dummy;
170         DATA_BLOB blob;
171
172         dummy = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, attr,
173                                                 talloc_tos());
174         if (dummy == NULL) {
175                 DEBUG(9, ("Attribute %s not present.\n", attr));
176                 ZERO_STRUCTP(_blob);
177         } else {
178                 blob = base64_decode_data_blob(dummy);
179                 if (blob.length == 0) {
180                         ZERO_STRUCTP(_blob);
181                 } else {
182                         _blob->length = blob.length;
183                         _blob->data = talloc_steal(mem_ctx, blob.data);
184                 }
185         }
186         TALLOC_FREE(dummy);
187 }
188
189 static bool fill_pdb_trusted_domain(TALLOC_CTX *mem_ctx,
190                                     struct ldapsam_privates *ldap_state,
191                                     LDAPMessage *entry,
192                                     struct pdb_trusted_domain **_td)
193 {
194         char *dummy;
195         bool res;
196         struct pdb_trusted_domain *td;
197
198         if (entry == NULL) {
199                 return false;
200         }
201
202         td = talloc_zero(mem_ctx, struct pdb_trusted_domain);
203         if (td == NULL) {
204                 return false;
205         }
206
207         /* All attributes are MAY */
208
209         dummy = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry,
210                                                 LDAP_ATTRIBUTE_SECURITY_IDENTIFIER,
211                                                 talloc_tos());
212         if (dummy == NULL) {
213                 DEBUG(9, ("Attribute %s not present.\n",
214                           LDAP_ATTRIBUTE_SECURITY_IDENTIFIER));
215                 ZERO_STRUCT(td->security_identifier);
216         } else {
217                 res = string_to_sid(&td->security_identifier, dummy);
218                 TALLOC_FREE(dummy);
219                 if (!res) {
220                         return false;
221                 }
222         }
223
224         get_data_blob_from_ldap_msg(td, ldap_state, entry,
225                                     LDAP_ATTRIBUTE_TRUST_AUTH_INCOMING,
226                                     &td->trust_auth_incoming);
227
228         get_data_blob_from_ldap_msg(td, ldap_state, entry,
229                                     LDAP_ATTRIBUTE_TRUST_AUTH_OUTGOING,
230                                     &td->trust_auth_outgoing);
231
232         td->netbios_name = smbldap_talloc_single_attribute(priv2ld(ldap_state),
233                                                            entry,
234                                                            LDAP_ATTRIBUTE_FLAT_NAME,
235                                                            td);
236         if (td->netbios_name == NULL) {
237                 DEBUG(9, ("Attribute %s not present.\n",
238                           LDAP_ATTRIBUTE_FLAT_NAME));
239         }
240
241         td->domain_name = smbldap_talloc_single_attribute(priv2ld(ldap_state),
242                                                           entry,
243                                                           LDAP_ATTRIBUTE_TRUST_PARTNER,
244                                                           td);
245         if (td->domain_name == NULL) {
246                 DEBUG(9, ("Attribute %s not present.\n",
247                           LDAP_ATTRIBUTE_TRUST_PARTNER));
248         }
249
250         res = get_uint32_t_from_ldap_msg(ldap_state, entry,
251                                          LDAP_ATTRIBUTE_TRUST_DIRECTION,
252                                          &td->trust_direction);
253         if (!res) {
254                 return false;
255         }
256
257         res = get_uint32_t_from_ldap_msg(ldap_state, entry,
258                                          LDAP_ATTRIBUTE_TRUST_ATTRIBUTES,
259                                          &td->trust_attributes);
260         if (!res) {
261                 return false;
262         }
263
264         res = get_uint32_t_from_ldap_msg(ldap_state, entry,
265                                          LDAP_ATTRIBUTE_TRUST_TYPE,
266                                          &td->trust_type);
267         if (!res) {
268                 return false;
269         }
270
271         *_td = td;
272
273         return true;
274 }
275
276 static NTSTATUS ipasam_get_trusted_domain(struct pdb_methods *methods,
277                                           TALLOC_CTX *mem_ctx,
278                                           const char *domain,
279                                           struct pdb_trusted_domain **td)
280 {
281         struct ldapsam_privates *ldap_state =
282                 (struct ldapsam_privates *)methods->private_data;
283         LDAPMessage *entry = NULL;
284
285         DEBUG(10, ("ipasam_get_trusted_domain called for domain %s\n", domain));
286
287         if (!get_trusted_domain_int(ldap_state, talloc_tos(), domain, &entry)) {
288                 return NT_STATUS_UNSUCCESSFUL;
289         }
290         if (entry == NULL) {
291                 DEBUG(5, ("ipasam_get_trusted_domain: no such trusted domain: "
292                           "%s\n", domain));
293                 return NT_STATUS_NO_SUCH_DOMAIN;
294         }
295
296         if (!fill_pdb_trusted_domain(mem_ctx, ldap_state, entry, td)) {
297                 return NT_STATUS_UNSUCCESSFUL;
298         }
299
300         return NT_STATUS_OK;
301 }
302
303 static bool smbldap_make_mod_uint32_t(LDAP *ldap_struct, LDAPMessage *entry,
304                                       LDAPMod ***mods, const char *attribute,
305                                       const uint32_t val)
306 {
307         char *dummy;
308
309         dummy = talloc_asprintf(talloc_tos(), "%lu", (unsigned long) val);
310         if (dummy == NULL) {
311                 return false;
312         }
313         smbldap_make_mod(ldap_struct, entry, mods, attribute, dummy);
314         TALLOC_FREE(dummy);
315
316         return true;
317 }
318
319 static bool smbldap_make_mod_blob(LDAP *ldap_struct, LDAPMessage *entry,
320                                   LDAPMod ***mods, const char *attribute,
321                                   DATA_BLOB blob)
322 {
323         char *dummy;
324
325         dummy = base64_encode_data_blob(talloc_tos(), blob);
326         if (dummy == NULL) {
327                 return false;
328         }
329
330         smbldap_make_mod(ldap_struct, entry, mods, attribute, dummy);
331         TALLOC_FREE(dummy);
332
333         return true;
334 }
335
336 static NTSTATUS ipasam_set_trusted_domain(struct pdb_methods *methods,
337                                           const char* domain,
338                                           const struct pdb_trusted_domain *td)
339 {
340         struct ldapsam_privates *ldap_state =
341                 (struct ldapsam_privates *)methods->private_data;
342         LDAPMessage *entry = NULL;
343         LDAPMod **mods;
344         bool res;
345         char *trusted_dn = NULL;
346         int ret;
347
348         DEBUG(10, ("ipasam_set_trusted_domain called for domain %s\n", domain));
349
350         res = get_trusted_domain_int(ldap_state, talloc_tos(), domain, &entry);
351         if (!res) {
352                 return NT_STATUS_UNSUCCESSFUL;
353         }
354
355         mods = NULL;
356         smbldap_make_mod(priv2ld(ldap_state), entry, &mods, "objectClass",
357                          LDAP_OBJ_TRUSTED_DOMAIN);
358
359         if (td->netbios_name != NULL) {
360                 smbldap_make_mod(priv2ld(ldap_state), entry, &mods,
361                                  LDAP_ATTRIBUTE_FLAT_NAME,
362                                  td->netbios_name);
363         }
364
365         if (td->domain_name != NULL) {
366                 smbldap_make_mod(priv2ld(ldap_state), entry, &mods,
367                                  LDAP_ATTRIBUTE_TRUST_PARTNER,
368                                  td->domain_name);
369         }
370
371         if (!is_null_sid(&td->security_identifier)) {
372                 smbldap_make_mod(priv2ld(ldap_state), entry, &mods,
373                                  LDAP_ATTRIBUTE_SECURITY_IDENTIFIER,
374                                  sid_string_tos(&td->security_identifier));
375         }
376
377         if (td->trust_type != 0) {
378                 res = smbldap_make_mod_uint32_t(priv2ld(ldap_state), entry,
379                                                 &mods, LDAP_ATTRIBUTE_TRUST_TYPE,
380                                                 td->trust_type);
381                 if (!res) {
382                         return NT_STATUS_UNSUCCESSFUL;
383                 }
384         }
385
386         if (td->trust_attributes != 0) {
387                 res = smbldap_make_mod_uint32_t(priv2ld(ldap_state), entry,
388                                                 &mods,
389                                                 LDAP_ATTRIBUTE_TRUST_ATTRIBUTES,
390                                                 td->trust_attributes);
391                 if (!res) {
392                         return NT_STATUS_UNSUCCESSFUL;
393                 }
394         }
395
396         if (td->trust_direction != 0) {
397                 res = smbldap_make_mod_uint32_t(priv2ld(ldap_state), entry,
398                                                 &mods,
399                                                 LDAP_ATTRIBUTE_TRUST_DIRECTION,
400                                                 td->trust_direction);
401                 if (!res) {
402                         return NT_STATUS_UNSUCCESSFUL;
403                 }
404         }
405
406         if (td->trust_auth_outgoing.data != NULL) {
407                 res = smbldap_make_mod_blob(priv2ld(ldap_state), entry,
408                                             &mods,
409                                             LDAP_ATTRIBUTE_TRUST_AUTH_OUTGOING,
410                                             td->trust_auth_outgoing);
411                 if (!res) {
412                         return NT_STATUS_UNSUCCESSFUL;
413                 }
414         }
415
416         if (td->trust_auth_incoming.data != NULL) {
417                 res = smbldap_make_mod_blob(priv2ld(ldap_state), entry,
418                                             &mods,
419                                             LDAP_ATTRIBUTE_TRUST_AUTH_INCOMING,
420                                             td->trust_auth_incoming);
421                 if (!res) {
422                         return NT_STATUS_UNSUCCESSFUL;
423                 }
424         }
425
426         talloc_autofree_ldapmod(talloc_tos(), mods);
427
428         trusted_dn = trusted_domain_dn(ldap_state, domain);
429         if (trusted_dn == NULL) {
430                 return NT_STATUS_NO_MEMORY;
431         }
432         if (entry == NULL) {
433                 ret = smbldap_add(ldap_state->smbldap_state, trusted_dn, mods);
434         } else {
435                 ret = smbldap_modify(ldap_state->smbldap_state, trusted_dn, mods);
436         }
437
438         if (ret != LDAP_SUCCESS) {
439                 DEBUG(1, ("error writing trusted domain data!\n"));
440                 return NT_STATUS_UNSUCCESSFUL;
441         }
442         return NT_STATUS_OK;
443 }
444
445 static NTSTATUS ipasam_del_trusted_domain(struct pdb_methods *methods,
446                                           const char *domain)
447 {
448         int ret;
449         struct ldapsam_privates *ldap_state =
450                 (struct ldapsam_privates *)methods->private_data;
451         LDAPMessage *entry = NULL;
452         const char *dn;
453
454         if (!get_trusted_domain_int(ldap_state, talloc_tos(), domain, &entry)) {
455                 return NT_STATUS_UNSUCCESSFUL;
456         }
457
458         if (entry == NULL) {
459                 DEBUG(5, ("ipasam_del_trusted_domain: no such trusted domain: "
460                           "%s\n", domain));
461                 return NT_STATUS_NO_SUCH_DOMAIN;
462         }
463
464         dn = smbldap_talloc_dn(talloc_tos(), priv2ld(ldap_state), entry);
465         if (dn == NULL) {
466                 DEBUG(0,("ipasam_del_trusted_domain: Out of memory!\n"));
467                 return NT_STATUS_NO_MEMORY;
468         }
469
470         ret = smbldap_delete(ldap_state->smbldap_state, dn);
471         if (ret != LDAP_SUCCESS) {
472                 return NT_STATUS_UNSUCCESSFUL;
473         }
474
475         return NT_STATUS_OK;
476 }
477
478 static NTSTATUS ipasam_enum_trusted_domains(struct pdb_methods *methods,
479                                             TALLOC_CTX *mem_ctx,
480                                             uint32_t *num_domains,
481                                             struct pdb_trusted_domain ***domains)
482 {
483         int rc;
484         struct ldapsam_privates *ldap_state =
485                 (struct ldapsam_privates *)methods->private_data;
486         char *base_dn = NULL;
487         char *filter = NULL;
488         int scope = LDAP_SCOPE_SUBTREE;
489         LDAPMessage *result = NULL;
490         LDAPMessage *entry = NULL;
491
492         filter = talloc_asprintf(talloc_tos(), "(objectClass=%s)",
493                                  LDAP_OBJ_TRUSTED_DOMAIN);
494         if (filter == NULL) {
495                 return NT_STATUS_NO_MEMORY;
496         }
497
498         base_dn = trusted_domain_base_dn(ldap_state);
499         if (base_dn == NULL) {
500                 TALLOC_FREE(filter);
501                 return NT_STATUS_NO_MEMORY;
502         }
503
504         rc = smbldap_search(ldap_state->smbldap_state, base_dn, scope, filter,
505                             NULL, 0, &result);
506         TALLOC_FREE(filter);
507         TALLOC_FREE(base_dn);
508
509         if (result != NULL) {
510                 talloc_autofree_ldapmsg(mem_ctx, result);
511         }
512
513         if (rc == LDAP_NO_SUCH_OBJECT) {
514                 *num_domains = 0;
515                 *domains = NULL;
516                 return NT_STATUS_OK;
517         }
518
519         if (rc != LDAP_SUCCESS) {
520                 return NT_STATUS_UNSUCCESSFUL;
521         }
522
523         *num_domains = 0;
524         if (!(*domains = TALLOC_ARRAY(mem_ctx, struct pdb_trusted_domain *, 1))) {
525                 DEBUG(1, ("talloc failed\n"));
526                 return NT_STATUS_NO_MEMORY;
527         }
528
529         for (entry = ldap_first_entry(priv2ld(ldap_state), result);
530              entry != NULL;
531              entry = ldap_next_entry(priv2ld(ldap_state), entry))
532         {
533                 struct pdb_trusted_domain *dom_info;
534
535                 if (!fill_pdb_trusted_domain(*domains, ldap_state, entry,
536                                              &dom_info)) {
537                         return NT_STATUS_UNSUCCESSFUL;
538                 }
539
540                 ADD_TO_ARRAY(*domains, struct pdb_trusted_domain *, dom_info,
541                              domains, num_domains);
542
543                 if (*domains == NULL) {
544                         DEBUG(1, ("talloc failed\n"));
545                         return NT_STATUS_NO_MEMORY;
546                 }
547         }
548
549         DEBUG(5, ("ipasam_enum_trusted_domains: got %d domains\n", *num_domains));
550         return NT_STATUS_OK;
551 }
552
553 static NTSTATUS ipasam_enum_trusteddoms(struct pdb_methods *methods,
554                                         TALLOC_CTX *mem_ctx,
555                                         uint32_t *num_domains,
556                                         struct trustdom_info ***domains)
557 {
558         NTSTATUS status;
559         struct pdb_trusted_domain **td;
560         int i;
561
562         status = ipasam_enum_trusted_domains(methods, talloc_tos(),
563                                              num_domains, &td);
564         if (!NT_STATUS_IS_OK(status)) {
565                 return status;
566         }
567
568         if (*num_domains == 0) {
569                 return NT_STATUS_OK;
570         }
571
572         if (!(*domains = TALLOC_ARRAY(mem_ctx, struct trustdom_info *,
573                                       *num_domains))) {
574                 DEBUG(1, ("talloc failed\n"));
575                 return NT_STATUS_NO_MEMORY;
576         }
577
578         for (i = 0; i < *num_domains; i++) {
579                 struct trustdom_info *dom_info;
580
581                 dom_info = TALLOC_P(*domains, struct trustdom_info);
582                 if (dom_info == NULL) {
583                         DEBUG(1, ("talloc failed\n"));
584                         return NT_STATUS_NO_MEMORY;
585                 }
586
587                 dom_info->name = talloc_steal(mem_ctx, td[i]->netbios_name);
588                 sid_copy(&dom_info->sid, &td[i]->security_identifier);
589
590                 (*domains)[i] = dom_info;
591         }
592
593         return NT_STATUS_OK;
594 }
595
596 static NTSTATUS pdb_init_IPA_ldapsam(struct pdb_methods **pdb_method, const char *location)
597 {
598         struct ldapsam_privates *ldap_state;
599
600         NTSTATUS nt_status = pdb_init_ldapsam(pdb_method, location);
601
602         (*pdb_method)->name = "IPA_ldapsam";
603
604         ldap_state = (struct ldapsam_privates *)((*pdb_method)->private_data);
605         ldap_state->is_ipa_ldap = true;
606
607         (*pdb_method)->get_trusteddom_pw = ipasam_get_trusteddom_pw;
608         (*pdb_method)->set_trusteddom_pw = ipasam_set_trusteddom_pw;
609         (*pdb_method)->del_trusteddom_pw = ipasam_del_trusteddom_pw;
610         (*pdb_method)->enum_trusteddoms = ipasam_enum_trusteddoms;
611
612         (*pdb_method)->get_trusted_domain = ipasam_get_trusted_domain;
613         (*pdb_method)->set_trusted_domain = ipasam_set_trusted_domain;
614         (*pdb_method)->del_trusted_domain = ipasam_del_trusted_domain;
615         (*pdb_method)->enum_trusted_domains = ipasam_enum_trusted_domains;
616
617         return nt_status;
618 }
619
620 NTSTATUS pdb_ipa_init(void)
621 {
622         NTSTATUS nt_status;
623
624         if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "IPA_ldapsam", pdb_init_IPA_ldapsam)))
625                 return nt_status;
626
627         return NT_STATUS_OK;
628 }