f8ae30319c2070200dee178c83879839d4db5c37
[abartlet/samba.git/.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 #include "passdb.h"
23 #include "libcli/security/dom_sid.h"
24 #include "../librpc/ndr/libndr.h"
25
26 #include "smbldap.h"
27
28 #define LDAP_TRUST_CONTAINER "ou=system"
29 #define LDAP_ATTRIBUTE_CN "cn"
30 #define LDAP_ATTRIBUTE_TRUST_TYPE "sambaTrustType"
31 #define LDAP_ATTRIBUTE_TRUST_ATTRIBUTES "sambaTrustAttributes"
32 #define LDAP_ATTRIBUTE_TRUST_DIRECTION "sambaTrustDirection"
33 #define LDAP_ATTRIBUTE_TRUST_PARTNER "sambaTrustPartner"
34 #define LDAP_ATTRIBUTE_FLAT_NAME "sambaFlatName"
35 #define LDAP_ATTRIBUTE_TRUST_AUTH_OUTGOING "sambaTrustAuthOutgoing"
36 #define LDAP_ATTRIBUTE_TRUST_AUTH_INCOMING "sambaTrustAuthIncoming"
37 #define LDAP_ATTRIBUTE_SECURITY_IDENTIFIER "sambaSecurityIdentifier"
38 #define LDAP_ATTRIBUTE_TRUST_FOREST_TRUST_INFO "sambaTrustForestTrustInfo"
39
40 #define LDAP_OBJ_KRB_PRINCIPAL "krbPrincipal"
41 #define LDAP_OBJ_KRB_PRINCIPAL_AUX "krbPrincipalAux"
42 #define LDAP_ATTRIBUTE_KRB_PRINCIPAL "krbPrincipalName"
43
44 struct ipasam_privates {
45         NTSTATUS (*ldapsam_add_sam_account)(struct pdb_methods *,
46                                             struct samu *sampass);
47         NTSTATUS (*ldapsam_update_sam_account)(struct pdb_methods *,
48                                                struct samu *sampass);
49 };
50
51 static bool ipasam_get_trusteddom_pw(struct pdb_methods *methods,
52                                       const char *domain,
53                                       char** pwd,
54                                       struct dom_sid *sid,
55                                       time_t *pass_last_set_time)
56 {
57         return false;
58 }
59
60 static bool ipasam_set_trusteddom_pw(struct pdb_methods *methods,
61                                       const char* domain,
62                                       const char* pwd,
63                                       const struct dom_sid *sid)
64 {
65         return false;
66 }
67
68 static bool ipasam_del_trusteddom_pw(struct pdb_methods *methods,
69                                       const char *domain)
70 {
71         return false;
72 }
73
74 static char *get_account_dn(const char *name)
75 {
76         char *escape_name;
77         char *dn;
78
79         escape_name = escape_rdn_val_string_alloc(name);
80         if (!escape_name) {
81                 return NULL;
82         }
83
84         if (name[strlen(name)-1] == '$') {
85                 dn = talloc_asprintf(talloc_tos(), "uid=%s,%s", escape_name,
86                                      lp_ldap_machine_suffix());
87         } else {
88                 dn = talloc_asprintf(talloc_tos(), "uid=%s,%s", escape_name,
89                                      lp_ldap_user_suffix());
90         }
91
92         SAFE_FREE(escape_name);
93
94         return dn;
95 }
96
97 static char *trusted_domain_dn(struct ldapsam_privates *ldap_state,
98                                const char *domain)
99 {
100         return talloc_asprintf(talloc_tos(), "%s=%s,%s,%s",
101                                LDAP_ATTRIBUTE_CN, domain,
102                                LDAP_TRUST_CONTAINER, ldap_state->domain_dn);
103 }
104
105 static char *trusted_domain_base_dn(struct ldapsam_privates *ldap_state)
106 {
107         return talloc_asprintf(talloc_tos(), "%s,%s",
108                                LDAP_TRUST_CONTAINER, ldap_state->domain_dn);
109 }
110
111 static bool get_trusted_domain_int(struct ldapsam_privates *ldap_state,
112                                    TALLOC_CTX *mem_ctx,
113                                    const char *filter, LDAPMessage **entry)
114 {
115         int rc;
116         char *base_dn = NULL;
117         LDAPMessage *result = NULL;
118         uint32_t num_result;
119
120         base_dn = trusted_domain_base_dn(ldap_state);
121         if (base_dn == NULL) {
122                 return false;
123         }
124
125         rc = smbldap_search(ldap_state->smbldap_state, base_dn,
126                             LDAP_SCOPE_SUBTREE, filter, NULL, 0, &result);
127         TALLOC_FREE(base_dn);
128
129         if (result != NULL) {
130                 talloc_autofree_ldapmsg(mem_ctx, result);
131         }
132
133         if (rc == LDAP_NO_SUCH_OBJECT) {
134                 *entry = NULL;
135                 return true;
136         }
137
138         if (rc != LDAP_SUCCESS) {
139                 return false;
140         }
141
142         num_result = ldap_count_entries(priv2ld(ldap_state), result);
143
144         if (num_result > 1) {
145                 DEBUG(1, ("get_trusted_domain_int: more than one "
146                           "%s object with filter '%s'?!\n",
147                           LDAP_OBJ_TRUSTED_DOMAIN, filter));
148                 return false;
149         }
150
151         if (num_result == 0) {
152                 DEBUG(1, ("get_trusted_domain_int: no "
153                           "%s object with filter '%s'.\n",
154                           LDAP_OBJ_TRUSTED_DOMAIN, filter));
155                 *entry = NULL;
156         } else {
157                 *entry = ldap_first_entry(priv2ld(ldap_state), result);
158         }
159
160         return true;
161 }
162
163 static bool get_trusted_domain_by_name_int(struct ldapsam_privates *ldap_state,
164                                           TALLOC_CTX *mem_ctx,
165                                           const char *domain,
166                                           LDAPMessage **entry)
167 {
168         char *filter = NULL;
169
170         filter = talloc_asprintf(talloc_tos(),
171                                  "(&(objectClass=%s)(|(%s=%s)(%s=%s)(cn=%s)))",
172                                  LDAP_OBJ_TRUSTED_DOMAIN,
173                                  LDAP_ATTRIBUTE_FLAT_NAME, domain,
174                                  LDAP_ATTRIBUTE_TRUST_PARTNER, domain, domain);
175         if (filter == NULL) {
176                 return false;
177         }
178
179         return get_trusted_domain_int(ldap_state, mem_ctx, filter, entry);
180 }
181
182 static bool get_trusted_domain_by_sid_int(struct ldapsam_privates *ldap_state,
183                                            TALLOC_CTX *mem_ctx,
184                                            const char *sid, LDAPMessage **entry)
185 {
186         char *filter = NULL;
187
188         filter = talloc_asprintf(talloc_tos(), "(&(objectClass=%s)(%s=%s))",
189                                  LDAP_OBJ_TRUSTED_DOMAIN,
190                                  LDAP_ATTRIBUTE_SECURITY_IDENTIFIER, sid);
191         if (filter == NULL) {
192                 return false;
193         }
194
195         return get_trusted_domain_int(ldap_state, mem_ctx, filter, entry);
196 }
197
198 static bool get_uint32_t_from_ldap_msg(struct ldapsam_privates *ldap_state,
199                                        LDAPMessage *entry,
200                                        const char *attr,
201                                        uint32_t *val)
202 {
203         char *dummy;
204         long int l;
205         char *endptr;
206
207         dummy = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry,
208                                                 attr, talloc_tos());
209         if (dummy == NULL) {
210                 DEBUG(9, ("Attribute %s not present.\n", attr));
211                 *val = 0;
212                 return true;
213         }
214
215         l = strtoul(dummy, &endptr, 10);
216         TALLOC_FREE(dummy);
217
218         if (l < 0 || l > UINT32_MAX || *endptr != '\0') {
219                 return false;
220         }
221
222         *val = l;
223
224         return true;
225 }
226
227 static void get_data_blob_from_ldap_msg(TALLOC_CTX *mem_ctx,
228                                         struct ldapsam_privates *ldap_state,
229                                         LDAPMessage *entry, const char *attr,
230                                         DATA_BLOB *_blob)
231 {
232         char *dummy;
233         DATA_BLOB blob;
234
235         dummy = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, attr,
236                                                 talloc_tos());
237         if (dummy == NULL) {
238                 DEBUG(9, ("Attribute %s not present.\n", attr));
239                 ZERO_STRUCTP(_blob);
240         } else {
241                 blob = base64_decode_data_blob(dummy);
242                 if (blob.length == 0) {
243                         ZERO_STRUCTP(_blob);
244                 } else {
245                         _blob->length = blob.length;
246                         _blob->data = talloc_steal(mem_ctx, blob.data);
247                 }
248         }
249         TALLOC_FREE(dummy);
250 }
251
252 static bool fill_pdb_trusted_domain(TALLOC_CTX *mem_ctx,
253                                     struct ldapsam_privates *ldap_state,
254                                     LDAPMessage *entry,
255                                     struct pdb_trusted_domain **_td)
256 {
257         char *dummy;
258         bool res;
259         struct pdb_trusted_domain *td;
260
261         if (entry == NULL) {
262                 return false;
263         }
264
265         td = talloc_zero(mem_ctx, struct pdb_trusted_domain);
266         if (td == NULL) {
267                 return false;
268         }
269
270         /* All attributes are MAY */
271
272         dummy = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry,
273                                                 LDAP_ATTRIBUTE_SECURITY_IDENTIFIER,
274                                                 talloc_tos());
275         if (dummy == NULL) {
276                 DEBUG(9, ("Attribute %s not present.\n",
277                           LDAP_ATTRIBUTE_SECURITY_IDENTIFIER));
278                 ZERO_STRUCT(td->security_identifier);
279         } else {
280                 res = string_to_sid(&td->security_identifier, dummy);
281                 TALLOC_FREE(dummy);
282                 if (!res) {
283                         return false;
284                 }
285         }
286
287         get_data_blob_from_ldap_msg(td, ldap_state, entry,
288                                     LDAP_ATTRIBUTE_TRUST_AUTH_INCOMING,
289                                     &td->trust_auth_incoming);
290
291         get_data_blob_from_ldap_msg(td, ldap_state, entry,
292                                     LDAP_ATTRIBUTE_TRUST_AUTH_OUTGOING,
293                                     &td->trust_auth_outgoing);
294
295         td->netbios_name = smbldap_talloc_single_attribute(priv2ld(ldap_state),
296                                                            entry,
297                                                            LDAP_ATTRIBUTE_FLAT_NAME,
298                                                            td);
299         if (td->netbios_name == NULL) {
300                 DEBUG(9, ("Attribute %s not present.\n",
301                           LDAP_ATTRIBUTE_FLAT_NAME));
302         }
303
304         td->domain_name = smbldap_talloc_single_attribute(priv2ld(ldap_state),
305                                                           entry,
306                                                           LDAP_ATTRIBUTE_TRUST_PARTNER,
307                                                           td);
308         if (td->domain_name == NULL) {
309                 DEBUG(9, ("Attribute %s not present.\n",
310                           LDAP_ATTRIBUTE_TRUST_PARTNER));
311         }
312
313         res = get_uint32_t_from_ldap_msg(ldap_state, entry,
314                                          LDAP_ATTRIBUTE_TRUST_DIRECTION,
315                                          &td->trust_direction);
316         if (!res) {
317                 return false;
318         }
319
320         res = get_uint32_t_from_ldap_msg(ldap_state, entry,
321                                          LDAP_ATTRIBUTE_TRUST_ATTRIBUTES,
322                                          &td->trust_attributes);
323         if (!res) {
324                 return false;
325         }
326
327         res = get_uint32_t_from_ldap_msg(ldap_state, entry,
328                                          LDAP_ATTRIBUTE_TRUST_TYPE,
329                                          &td->trust_type);
330         if (!res) {
331                 return false;
332         }
333
334         get_data_blob_from_ldap_msg(td, ldap_state, entry,
335                                     LDAP_ATTRIBUTE_TRUST_FOREST_TRUST_INFO,
336                                     &td->trust_forest_trust_info);
337
338         *_td = td;
339
340         return true;
341 }
342
343 static NTSTATUS ipasam_get_trusted_domain(struct pdb_methods *methods,
344                                           TALLOC_CTX *mem_ctx,
345                                           const char *domain,
346                                           struct pdb_trusted_domain **td)
347 {
348         struct ldapsam_privates *ldap_state =
349                 (struct ldapsam_privates *)methods->private_data;
350         LDAPMessage *entry = NULL;
351
352         DEBUG(10, ("ipasam_get_trusted_domain called for domain %s\n", domain));
353
354         if (!get_trusted_domain_by_name_int(ldap_state, talloc_tos(), domain,
355                                             &entry)) {
356                 return NT_STATUS_UNSUCCESSFUL;
357         }
358         if (entry == NULL) {
359                 DEBUG(5, ("ipasam_get_trusted_domain: no such trusted domain: "
360                           "%s\n", domain));
361                 return NT_STATUS_NO_SUCH_DOMAIN;
362         }
363
364         if (!fill_pdb_trusted_domain(mem_ctx, ldap_state, entry, td)) {
365                 return NT_STATUS_UNSUCCESSFUL;
366         }
367
368         return NT_STATUS_OK;
369 }
370
371 static NTSTATUS ipasam_get_trusted_domain_by_sid(struct pdb_methods *methods,
372                                                  TALLOC_CTX *mem_ctx,
373                                                  struct dom_sid *sid,
374                                                  struct pdb_trusted_domain **td)
375 {
376         struct ldapsam_privates *ldap_state =
377                 (struct ldapsam_privates *)methods->private_data;
378         LDAPMessage *entry = NULL;
379         char *sid_str;
380
381         sid_str = sid_string_tos(sid);
382
383         DEBUG(10, ("ipasam_get_trusted_domain_by_sid called for sid %s\n",
384                    sid_str));
385
386         if (!get_trusted_domain_by_sid_int(ldap_state, talloc_tos(), sid_str,
387                                            &entry)) {
388                 return NT_STATUS_UNSUCCESSFUL;
389         }
390         if (entry == NULL) {
391                 DEBUG(5, ("ipasam_get_trusted_domain_by_sid: no trusted domain "
392                           "with sid: %s\n", sid_str));
393                 return NT_STATUS_NO_SUCH_DOMAIN;
394         }
395
396         if (!fill_pdb_trusted_domain(mem_ctx, ldap_state, entry, td)) {
397                 return NT_STATUS_UNSUCCESSFUL;
398         }
399
400         return NT_STATUS_OK;
401 }
402
403 static bool smbldap_make_mod_uint32_t(LDAP *ldap_struct, LDAPMessage *entry,
404                                       LDAPMod ***mods, const char *attribute,
405                                       const uint32_t val)
406 {
407         char *dummy;
408
409         dummy = talloc_asprintf(talloc_tos(), "%lu", (unsigned long) val);
410         if (dummy == NULL) {
411                 return false;
412         }
413         smbldap_make_mod(ldap_struct, entry, mods, attribute, dummy);
414         TALLOC_FREE(dummy);
415
416         return true;
417 }
418
419 static bool _smbldap_make_mod_blob(LDAP *ldap_struct, LDAPMessage *entry,
420                                   LDAPMod ***mods, const char *attribute,
421                                   DATA_BLOB blob)
422 {
423         char *dummy;
424
425         dummy = base64_encode_data_blob(talloc_tos(), blob);
426         if (dummy == NULL) {
427                 return false;
428         }
429
430         smbldap_make_mod(ldap_struct, entry, mods, attribute, dummy);
431         TALLOC_FREE(dummy);
432
433         return true;
434 }
435
436 static NTSTATUS ipasam_set_trusted_domain(struct pdb_methods *methods,
437                                           const char* domain,
438                                           const struct pdb_trusted_domain *td)
439 {
440         struct ldapsam_privates *ldap_state =
441                 (struct ldapsam_privates *)methods->private_data;
442         LDAPMessage *entry = NULL;
443         LDAPMod **mods;
444         bool res;
445         char *trusted_dn = NULL;
446         int ret;
447
448         DEBUG(10, ("ipasam_set_trusted_domain called for domain %s\n", domain));
449
450         res = get_trusted_domain_by_name_int(ldap_state, talloc_tos(), domain,
451                                              &entry);
452         if (!res) {
453                 return NT_STATUS_UNSUCCESSFUL;
454         }
455
456         mods = NULL;
457         smbldap_make_mod(priv2ld(ldap_state), entry, &mods, "objectClass",
458                          LDAP_OBJ_TRUSTED_DOMAIN);
459
460         if (td->netbios_name != NULL) {
461                 smbldap_make_mod(priv2ld(ldap_state), entry, &mods,
462                                  LDAP_ATTRIBUTE_FLAT_NAME,
463                                  td->netbios_name);
464         }
465
466         if (td->domain_name != NULL) {
467                 smbldap_make_mod(priv2ld(ldap_state), entry, &mods,
468                                  LDAP_ATTRIBUTE_TRUST_PARTNER,
469                                  td->domain_name);
470         }
471
472         if (!is_null_sid(&td->security_identifier)) {
473                 smbldap_make_mod(priv2ld(ldap_state), entry, &mods,
474                                  LDAP_ATTRIBUTE_SECURITY_IDENTIFIER,
475                                  sid_string_tos(&td->security_identifier));
476         }
477
478         if (td->trust_type != 0) {
479                 res = smbldap_make_mod_uint32_t(priv2ld(ldap_state), entry,
480                                                 &mods, LDAP_ATTRIBUTE_TRUST_TYPE,
481                                                 td->trust_type);
482                 if (!res) {
483                         return NT_STATUS_UNSUCCESSFUL;
484                 }
485         }
486
487         if (td->trust_attributes != 0) {
488                 res = smbldap_make_mod_uint32_t(priv2ld(ldap_state), entry,
489                                                 &mods,
490                                                 LDAP_ATTRIBUTE_TRUST_ATTRIBUTES,
491                                                 td->trust_attributes);
492                 if (!res) {
493                         return NT_STATUS_UNSUCCESSFUL;
494                 }
495         }
496
497         if (td->trust_direction != 0) {
498                 res = smbldap_make_mod_uint32_t(priv2ld(ldap_state), entry,
499                                                 &mods,
500                                                 LDAP_ATTRIBUTE_TRUST_DIRECTION,
501                                                 td->trust_direction);
502                 if (!res) {
503                         return NT_STATUS_UNSUCCESSFUL;
504                 }
505         }
506
507         if (td->trust_auth_outgoing.data != NULL) {
508                 res = _smbldap_make_mod_blob(priv2ld(ldap_state), entry,
509                                             &mods,
510                                             LDAP_ATTRIBUTE_TRUST_AUTH_OUTGOING,
511                                             td->trust_auth_outgoing);
512                 if (!res) {
513                         return NT_STATUS_UNSUCCESSFUL;
514                 }
515         }
516
517         if (td->trust_auth_incoming.data != NULL) {
518                 res = _smbldap_make_mod_blob(priv2ld(ldap_state), entry,
519                                             &mods,
520                                             LDAP_ATTRIBUTE_TRUST_AUTH_INCOMING,
521                                             td->trust_auth_incoming);
522                 if (!res) {
523                         return NT_STATUS_UNSUCCESSFUL;
524                 }
525         }
526
527         if (td->trust_forest_trust_info.data != NULL) {
528                 res = _smbldap_make_mod_blob(priv2ld(ldap_state), entry,
529                                             &mods,
530                                             LDAP_ATTRIBUTE_TRUST_FOREST_TRUST_INFO,
531                                             td->trust_forest_trust_info);
532                 if (!res) {
533                         return NT_STATUS_UNSUCCESSFUL;
534                 }
535         }
536
537         talloc_autofree_ldapmod(talloc_tos(), mods);
538
539         trusted_dn = trusted_domain_dn(ldap_state, domain);
540         if (trusted_dn == NULL) {
541                 return NT_STATUS_NO_MEMORY;
542         }
543         if (entry == NULL) {
544                 ret = smbldap_add(ldap_state->smbldap_state, trusted_dn, mods);
545         } else {
546                 ret = smbldap_modify(ldap_state->smbldap_state, trusted_dn, mods);
547         }
548
549         if (ret != LDAP_SUCCESS) {
550                 DEBUG(1, ("error writing trusted domain data!\n"));
551                 return NT_STATUS_UNSUCCESSFUL;
552         }
553         return NT_STATUS_OK;
554 }
555
556 static NTSTATUS ipasam_del_trusted_domain(struct pdb_methods *methods,
557                                            const char *domain)
558 {
559         int ret;
560         struct ldapsam_privates *ldap_state =
561                 (struct ldapsam_privates *)methods->private_data;
562         LDAPMessage *entry = NULL;
563         const char *dn;
564
565         if (!get_trusted_domain_by_name_int(ldap_state, talloc_tos(), domain,
566                                             &entry)) {
567                 return NT_STATUS_UNSUCCESSFUL;
568         }
569
570         if (entry == NULL) {
571                 DEBUG(5, ("ipasam_del_trusted_domain: no such trusted domain: "
572                           "%s\n", domain));
573                 return NT_STATUS_NO_SUCH_DOMAIN;
574         }
575
576         dn = smbldap_talloc_dn(talloc_tos(), priv2ld(ldap_state), entry);
577         if (dn == NULL) {
578                 DEBUG(0,("ipasam_del_trusted_domain: Out of memory!\n"));
579                 return NT_STATUS_NO_MEMORY;
580         }
581
582         ret = smbldap_delete(ldap_state->smbldap_state, dn);
583         if (ret != LDAP_SUCCESS) {
584                 return NT_STATUS_UNSUCCESSFUL;
585         }
586
587         return NT_STATUS_OK;
588 }
589
590 static NTSTATUS ipasam_enum_trusted_domains(struct pdb_methods *methods,
591                                             TALLOC_CTX *mem_ctx,
592                                             uint32_t *num_domains,
593                                             struct pdb_trusted_domain ***domains)
594 {
595         int rc;
596         struct ldapsam_privates *ldap_state =
597                 (struct ldapsam_privates *)methods->private_data;
598         char *base_dn = NULL;
599         char *filter = NULL;
600         int scope = LDAP_SCOPE_SUBTREE;
601         LDAPMessage *result = NULL;
602         LDAPMessage *entry = NULL;
603
604         filter = talloc_asprintf(talloc_tos(), "(objectClass=%s)",
605                                  LDAP_OBJ_TRUSTED_DOMAIN);
606         if (filter == NULL) {
607                 return NT_STATUS_NO_MEMORY;
608         }
609
610         base_dn = trusted_domain_base_dn(ldap_state);
611         if (base_dn == NULL) {
612                 TALLOC_FREE(filter);
613                 return NT_STATUS_NO_MEMORY;
614         }
615
616         rc = smbldap_search(ldap_state->smbldap_state, base_dn, scope, filter,
617                             NULL, 0, &result);
618         TALLOC_FREE(filter);
619         TALLOC_FREE(base_dn);
620
621         if (result != NULL) {
622                 talloc_autofree_ldapmsg(mem_ctx, result);
623         }
624
625         if (rc == LDAP_NO_SUCH_OBJECT) {
626                 *num_domains = 0;
627                 *domains = NULL;
628                 return NT_STATUS_OK;
629         }
630
631         if (rc != LDAP_SUCCESS) {
632                 return NT_STATUS_UNSUCCESSFUL;
633         }
634
635         *num_domains = 0;
636         if (!(*domains = TALLOC_ARRAY(mem_ctx, struct pdb_trusted_domain *, 1))) {
637                 DEBUG(1, ("talloc failed\n"));
638                 return NT_STATUS_NO_MEMORY;
639         }
640
641         for (entry = ldap_first_entry(priv2ld(ldap_state), result);
642              entry != NULL;
643              entry = ldap_next_entry(priv2ld(ldap_state), entry))
644         {
645                 struct pdb_trusted_domain *dom_info;
646
647                 if (!fill_pdb_trusted_domain(*domains, ldap_state, entry,
648                                              &dom_info)) {
649                         return NT_STATUS_UNSUCCESSFUL;
650                 }
651
652                 ADD_TO_ARRAY(*domains, struct pdb_trusted_domain *, dom_info,
653                              domains, num_domains);
654
655                 if (*domains == NULL) {
656                         DEBUG(1, ("talloc failed\n"));
657                         return NT_STATUS_NO_MEMORY;
658                 }
659         }
660
661         DEBUG(5, ("ipasam_enum_trusted_domains: got %d domains\n", *num_domains));
662         return NT_STATUS_OK;
663 }
664
665 static NTSTATUS ipasam_enum_trusteddoms(struct pdb_methods *methods,
666                                          TALLOC_CTX *mem_ctx,
667                                          uint32_t *num_domains,
668                                          struct trustdom_info ***domains)
669 {
670         NTSTATUS status;
671         struct pdb_trusted_domain **td;
672         int i;
673
674         status = ipasam_enum_trusted_domains(methods, talloc_tos(),
675                                              num_domains, &td);
676         if (!NT_STATUS_IS_OK(status)) {
677                 return status;
678         }
679
680         if (*num_domains == 0) {
681                 return NT_STATUS_OK;
682         }
683
684         if (!(*domains = TALLOC_ARRAY(mem_ctx, struct trustdom_info *,
685                                       *num_domains))) {
686                 DEBUG(1, ("talloc failed\n"));
687                 return NT_STATUS_NO_MEMORY;
688         }
689
690         for (i = 0; i < *num_domains; i++) {
691                 struct trustdom_info *dom_info;
692
693                 dom_info = TALLOC_P(*domains, struct trustdom_info);
694                 if (dom_info == NULL) {
695                         DEBUG(1, ("talloc failed\n"));
696                         return NT_STATUS_NO_MEMORY;
697                 }
698
699                 dom_info->name = talloc_steal(mem_ctx, td[i]->netbios_name);
700                 sid_copy(&dom_info->sid, &td[i]->security_identifier);
701
702                 (*domains)[i] = dom_info;
703         }
704
705         return NT_STATUS_OK;
706 }
707
708 static uint32_t pdb_ipasam_capabilities(struct pdb_methods *methods)
709 {
710         return PDB_CAP_STORE_RIDS | PDB_CAP_ADS | PDB_CAP_TRUSTED_DOMAINS_EX;
711 }
712
713 static struct pdb_domain_info *pdb_ipasam_get_domain_info(struct pdb_methods *pdb_methods,
714                                                           TALLOC_CTX *mem_ctx)
715 {
716         struct pdb_domain_info *info;
717         NTSTATUS status;
718         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)pdb_methods->private_data;
719
720         info = talloc(mem_ctx, struct pdb_domain_info);
721         if (info == NULL) {
722                 return NULL;
723         }
724
725         info->name = talloc_strdup(info, ldap_state->domain_name);
726         if (info->name == NULL) {
727                 goto fail;
728         }
729
730         /* TODO: read dns_domain, dns_forest and guid from LDAP */
731         info->dns_domain = talloc_strdup(info, lp_realm());
732         if (info->dns_domain == NULL) {
733                 goto fail;
734         }
735         strlower_m(info->dns_domain);
736         info->dns_forest = talloc_strdup(info, info->dns_domain);
737         sid_copy(&info->sid, &ldap_state->domain_sid);
738
739         status = GUID_from_string("testguid", &info->guid);
740
741         return info;
742
743 fail:
744         TALLOC_FREE(info);
745         return NULL;
746 }
747
748 static NTSTATUS modify_ipa_password_exop(struct ldapsam_privates *ldap_state,
749                                          struct samu *sampass)
750 {
751         int ret;
752         BerElement *ber = NULL;
753         struct berval *bv = NULL;
754         char *retoid = NULL;
755         struct berval *retdata = NULL;
756         const char *password;
757         char *dn;
758
759         password = pdb_get_plaintext_passwd(sampass);
760         if (password == NULL || *password == '\0') {
761                 return NT_STATUS_INVALID_PARAMETER;
762         }
763
764         dn = get_account_dn(pdb_get_username(sampass));
765         if (dn == NULL) {
766                 return NT_STATUS_INVALID_PARAMETER;
767         }
768
769         ber = ber_alloc_t( LBER_USE_DER );
770         if (ber == NULL) {
771                 DEBUG(7, ("ber_alloc_t failed.\n"));
772                 return NT_STATUS_NO_MEMORY;
773         }
774
775         ret = ber_printf(ber, "{tsts}", LDAP_TAG_EXOP_MODIFY_PASSWD_ID, dn,
776                          LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, password);
777         if (ret == -1) {
778                 DEBUG(7, ("ber_printf failed.\n"));
779                 ber_free(ber, 1);
780                 return NT_STATUS_UNSUCCESSFUL;
781         }
782
783         ret = ber_flatten(ber, &bv);
784         ber_free(ber, 1);
785         if (ret == -1) {
786                 DEBUG(1, ("ber_flatten failed.\n"));
787                 return NT_STATUS_UNSUCCESSFUL;
788         }
789
790         ret = smbldap_extended_operation(ldap_state->smbldap_state,
791                                          LDAP_EXOP_MODIFY_PASSWD, bv, NULL,
792                                          NULL, &retoid, &retdata);
793         ber_bvfree(bv);
794         if (retdata) {
795                 ber_bvfree(retdata);
796         }
797         if (retoid) {
798                 ldap_memfree(retoid);
799         }
800         if (ret != LDAP_SUCCESS) {
801                 DEBUG(1, ("smbldap_extended_operation LDAP_EXOP_MODIFY_PASSWD failed.\n"));
802                 return NT_STATUS_UNSUCCESSFUL;
803         }
804
805         return NT_STATUS_OK;
806 }
807
808 static NTSTATUS ipasam_add_objectclasses(struct ldapsam_privates *ldap_state,
809                                          struct samu *sampass)
810 {
811         char *dn;
812         LDAPMod **mods = NULL;
813         int ret;
814         char *princ;
815         const char *domain;
816         char *domain_with_dot;
817
818         dn = get_account_dn(pdb_get_username(sampass));
819         if (dn == NULL) {
820                 return NT_STATUS_INVALID_PARAMETER;
821         }
822
823         princ = talloc_asprintf(talloc_tos(), "%s@%s", pdb_get_username(sampass), lp_realm());
824         if (princ == NULL) {
825                 return NT_STATUS_NO_MEMORY;
826         }
827
828         domain = pdb_get_domain(sampass);
829         if (domain == NULL) {
830                 return NT_STATUS_INVALID_PARAMETER;
831         }
832
833         domain_with_dot = talloc_asprintf(talloc_tos(), "%s.", domain);
834         if (domain_with_dot == NULL) {
835                 return NT_STATUS_NO_MEMORY;
836         }
837
838         smbldap_set_mod(&mods, LDAP_MOD_ADD,
839                         "objectclass", LDAP_OBJ_KRB_PRINCIPAL);
840         smbldap_set_mod(&mods, LDAP_MOD_ADD,
841                         LDAP_ATTRIBUTE_KRB_PRINCIPAL, princ);
842         smbldap_set_mod(&mods, LDAP_MOD_ADD,
843                         "objectclass", LDAP_OBJ_KRB_PRINCIPAL_AUX);
844         smbldap_set_mod(&mods, LDAP_MOD_ADD,
845                         "objectclass", "ipaHost");
846         smbldap_set_mod(&mods, LDAP_MOD_ADD,
847                         "fqdn", domain);
848         smbldap_set_mod(&mods, LDAP_MOD_ADD,
849                         "objectclass", "posixAccount");
850         smbldap_set_mod(&mods, LDAP_MOD_ADD,
851                         "cn", pdb_get_username(sampass));
852         smbldap_set_mod(&mods, LDAP_MOD_ADD,
853                         "gidNumber", "12345");
854         smbldap_set_mod(&mods, LDAP_MOD_ADD,
855                         "homeDirectory", "/dev/null");
856         smbldap_set_mod(&mods, LDAP_MOD_ADD, "uid", domain);
857         smbldap_set_mod(&mods, LDAP_MOD_ADD, "uid", domain_with_dot);
858
859         ret = smbldap_modify(ldap_state->smbldap_state, dn, mods);
860         ldap_mods_free(mods, true);
861         if (ret != LDAP_SUCCESS) {
862                 DEBUG(1, ("failed to modify/add user with uid = %s (dn = %s)\n",
863                           pdb_get_username(sampass),dn));
864                 return NT_STATUS_LDAP(ret);
865         }
866
867         return NT_STATUS_OK;
868 }
869
870 static NTSTATUS pdb_ipasam_add_sam_account(struct pdb_methods *pdb_methods,
871                                            struct samu *sampass)
872 {
873         NTSTATUS status;
874         struct ldapsam_privates *ldap_state;
875
876         ldap_state = (struct ldapsam_privates *)(pdb_methods->private_data);
877
878         status =ldap_state->ipasam_privates->ldapsam_add_sam_account(pdb_methods,
879                                                                      sampass);
880         if (!NT_STATUS_IS_OK(status)) {
881                 return status;
882         }
883
884         status = ipasam_add_objectclasses(ldap_state, sampass);
885         if (!NT_STATUS_IS_OK(status)) {
886                 return status;
887         }
888
889         if (pdb_get_init_flags(sampass, PDB_PLAINTEXT_PW) == PDB_CHANGED) {
890                 status = modify_ipa_password_exop(ldap_state, sampass);
891                 if (!NT_STATUS_IS_OK(status)) {
892                         return status;
893                 }
894         }
895
896         return NT_STATUS_OK;
897 }
898
899 static NTSTATUS pdb_ipasam_update_sam_account(struct pdb_methods *pdb_methods,
900                                               struct samu *sampass)
901 {
902         NTSTATUS status;
903         struct ldapsam_privates *ldap_state;
904         ldap_state = (struct ldapsam_privates *)(pdb_methods->private_data);
905
906         status = ldap_state->ipasam_privates->ldapsam_update_sam_account(pdb_methods,
907                                                                          sampass);
908         if (!NT_STATUS_IS_OK(status)) {
909                 return status;
910         }
911
912         if (pdb_get_init_flags(sampass, PDB_PLAINTEXT_PW) == PDB_CHANGED) {
913                 status = modify_ipa_password_exop(ldap_state, sampass);
914                 if (!NT_STATUS_IS_OK(status)) {
915                         return status;
916                 }
917         }
918
919         return NT_STATUS_OK;
920 }
921
922 static NTSTATUS pdb_init_IPA_ldapsam(struct pdb_methods **pdb_method, const char *location)
923 {
924         struct ldapsam_privates *ldap_state;
925         NTSTATUS status;
926
927         status = pdb_init_ldapsam(pdb_method, location);
928         if (!NT_STATUS_IS_OK(status)) {
929                 return status;
930         }
931
932         (*pdb_method)->name = "IPA_ldapsam";
933
934         ldap_state = (struct ldapsam_privates *)((*pdb_method)->private_data);
935         ldap_state->ipasam_privates = talloc_zero(ldap_state,
936                                                   struct ipasam_privates);
937         if (ldap_state->ipasam_privates == NULL) {
938                 return NT_STATUS_NO_MEMORY;
939         }
940         ldap_state->is_ipa_ldap = true;
941         ldap_state->ipasam_privates->ldapsam_add_sam_account = (*pdb_method)->add_sam_account;
942         ldap_state->ipasam_privates->ldapsam_update_sam_account = (*pdb_method)->update_sam_account;
943
944         (*pdb_method)->add_sam_account = pdb_ipasam_add_sam_account;
945         (*pdb_method)->update_sam_account = pdb_ipasam_update_sam_account;
946
947         (*pdb_method)->capabilities = pdb_ipasam_capabilities;
948         (*pdb_method)->get_domain_info = pdb_ipasam_get_domain_info;
949
950         (*pdb_method)->get_trusteddom_pw = ipasam_get_trusteddom_pw;
951         (*pdb_method)->set_trusteddom_pw = ipasam_set_trusteddom_pw;
952         (*pdb_method)->del_trusteddom_pw = ipasam_del_trusteddom_pw;
953         (*pdb_method)->enum_trusteddoms = ipasam_enum_trusteddoms;
954
955         (*pdb_method)->get_trusted_domain = ipasam_get_trusted_domain;
956         (*pdb_method)->get_trusted_domain_by_sid = ipasam_get_trusted_domain_by_sid;
957         (*pdb_method)->set_trusted_domain = ipasam_set_trusted_domain;
958         (*pdb_method)->del_trusted_domain = ipasam_del_trusted_domain;
959         (*pdb_method)->enum_trusted_domains = ipasam_enum_trusted_domains;
960
961         return NT_STATUS_OK;
962 }
963
964 NTSTATUS pdb_ipa_init(void)
965 {
966         NTSTATUS nt_status;
967
968         if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "IPA_ldapsam", pdb_init_IPA_ldapsam)))
969                 return nt_status;
970
971         return NT_STATUS_OK;
972 }