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