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