s3-auth Change type of num_sids to uint32_t
[samba.git] / source3 / passdb / pdb_ldap.c
1 /* 
2    Unix SMB/CIFS implementation.
3    LDAP protocol helper functions for SAMBA
4    Copyright (C) Jean Fran├žois Micouleau        1998
5    Copyright (C) Gerald Carter                  2001-2003
6    Copyright (C) Shahms King                    2001
7    Copyright (C) Andrew Bartlett                2002-2003
8    Copyright (C) Stefan (metze) Metzmacher      2002-2003
9    Copyright (C) Simo Sorce                     2006
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23
24 */
25
26 /* TODO:
27 *  persistent connections: if using NSS LDAP, many connections are made
28 *      however, using only one within Samba would be nice
29 *  
30 *  Clean up SSL stuff, compile on OpenLDAP 1.x, 2.x, and Netscape SDK
31 *
32 *  Other LDAP based login attributes: accountExpires, etc.
33 *  (should be the domain of Samba proper, but the sam_password/struct samu
34 *  structures don't have fields for some of these attributes)
35 *
36 *  SSL is done, but can't get the certificate based authentication to work
37 *  against on my test platform (Linux 2.4, OpenLDAP 2.x)
38 */
39
40 /* NOTE: this will NOT work against an Active Directory server
41 *  due to the fact that the two password fields cannot be retrieved
42 *  from a server; recommend using security = domain in this situation
43 *  and/or winbind
44 */
45
46 #include "includes.h"
47 #include "../libcli/auth/libcli_auth.h"
48 #include "secrets.h"
49 #include "idmap_cache.h"
50
51 #undef DBGC_CLASS
52 #define DBGC_CLASS DBGC_PASSDB
53
54 #include <lber.h>
55 #include <ldap.h>
56
57 /*
58  * Work around versions of the LDAP client libs that don't have the OIDs
59  * defined, or have them defined under the old name.  
60  * This functionality is really a factor of the server, not the client 
61  *
62  */
63
64 #if defined(LDAP_EXOP_X_MODIFY_PASSWD) && !defined(LDAP_EXOP_MODIFY_PASSWD)
65 #define LDAP_EXOP_MODIFY_PASSWD LDAP_EXOP_X_MODIFY_PASSWD
66 #elif !defined(LDAP_EXOP_MODIFY_PASSWD)
67 #define LDAP_EXOP_MODIFY_PASSWD "1.3.6.1.4.1.4203.1.11.1"
68 #endif
69
70 #if defined(LDAP_EXOP_X_MODIFY_PASSWD_ID) && !defined(LDAP_EXOP_MODIFY_PASSWD_ID)
71 #define LDAP_TAG_EXOP_MODIFY_PASSWD_ID LDAP_EXOP_X_MODIFY_PASSWD_ID
72 #elif !defined(LDAP_EXOP_MODIFY_PASSWD_ID)
73 #define LDAP_TAG_EXOP_MODIFY_PASSWD_ID        ((ber_tag_t) 0x80U)
74 #endif
75
76 #if defined(LDAP_EXOP_X_MODIFY_PASSWD_NEW) && !defined(LDAP_EXOP_MODIFY_PASSWD_NEW)
77 #define LDAP_TAG_EXOP_MODIFY_PASSWD_NEW LDAP_EXOP_X_MODIFY_PASSWD_NEW
78 #elif !defined(LDAP_EXOP_MODIFY_PASSWD_NEW)
79 #define LDAP_TAG_EXOP_MODIFY_PASSWD_NEW       ((ber_tag_t) 0x82U)
80 #endif
81
82
83 #include "smbldap.h"
84
85 /**********************************************************************
86  Simple helper function to make stuff better readable
87  **********************************************************************/
88
89 static LDAP *priv2ld(struct ldapsam_privates *priv)
90 {
91         return priv->smbldap_state->ldap_struct;
92 }
93
94 /**********************************************************************
95  Get the attribute name given a user schame version.
96  **********************************************************************/
97  
98 static const char* get_userattr_key2string( int schema_ver, int key )
99 {
100         switch ( schema_ver ) {
101                 case SCHEMAVER_SAMBAACCOUNT:
102                         return get_attr_key2string( attrib_map_v22, key );
103
104                 case SCHEMAVER_SAMBASAMACCOUNT:
105                         return get_attr_key2string( attrib_map_v30, key );
106
107                 default:
108                         DEBUG(0,("get_userattr_key2string: unknown schema version specified\n"));
109                         break;
110         }
111         return NULL;
112 }
113
114 /**********************************************************************
115  Return the list of attribute names given a user schema version.
116 **********************************************************************/
117
118 const char** get_userattr_list( TALLOC_CTX *mem_ctx, int schema_ver )
119 {
120         switch ( schema_ver ) {
121                 case SCHEMAVER_SAMBAACCOUNT:
122                         return get_attr_list( mem_ctx, attrib_map_v22 );
123
124                 case SCHEMAVER_SAMBASAMACCOUNT:
125                         return get_attr_list( mem_ctx, attrib_map_v30 );
126                 default:
127                         DEBUG(0,("get_userattr_list: unknown schema version specified!\n"));
128                         break;
129         }
130
131         return NULL;
132 }
133
134 /**************************************************************************
135  Return the list of attribute names to delete given a user schema version.
136 **************************************************************************/
137
138 static const char** get_userattr_delete_list( TALLOC_CTX *mem_ctx,
139                                               int schema_ver )
140 {
141         switch ( schema_ver ) {
142                 case SCHEMAVER_SAMBAACCOUNT:
143                         return get_attr_list( mem_ctx,
144                                               attrib_map_to_delete_v22 );
145
146                 case SCHEMAVER_SAMBASAMACCOUNT:
147                         return get_attr_list( mem_ctx,
148                                               attrib_map_to_delete_v30 );
149                 default:
150                         DEBUG(0,("get_userattr_delete_list: unknown schema version specified!\n"));
151                         break;
152         }
153
154         return NULL;
155 }
156
157
158 /*******************************************************************
159  Generate the LDAP search filter for the objectclass based on the 
160  version of the schema we are using.
161 ******************************************************************/
162
163 static const char* get_objclass_filter( int schema_ver )
164 {
165         fstring objclass_filter;
166         char *result;
167
168         switch( schema_ver ) {
169                 case SCHEMAVER_SAMBAACCOUNT:
170                         fstr_sprintf( objclass_filter, "(objectclass=%s)", LDAP_OBJ_SAMBAACCOUNT );
171                         break;
172                 case SCHEMAVER_SAMBASAMACCOUNT:
173                         fstr_sprintf( objclass_filter, "(objectclass=%s)", LDAP_OBJ_SAMBASAMACCOUNT );
174                         break;
175                 default:
176                         DEBUG(0,("get_objclass_filter: Invalid schema version specified!\n"));
177                         objclass_filter[0] = '\0';
178                         break;
179         }
180
181         result = talloc_strdup(talloc_tos(), objclass_filter);
182         SMB_ASSERT(result != NULL);
183         return result;
184 }
185
186 /*****************************************************************
187  Scan a sequence number off OpenLDAP's syncrepl contextCSN
188 ******************************************************************/
189
190 static NTSTATUS ldapsam_get_seq_num(struct pdb_methods *my_methods, time_t *seq_num)
191 {
192         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
193         NTSTATUS ntstatus = NT_STATUS_UNSUCCESSFUL;
194         LDAPMessage *msg = NULL;
195         LDAPMessage *entry = NULL;
196         TALLOC_CTX *mem_ctx;
197         char **values = NULL;
198         int rc, num_result, num_values, rid;
199         char *suffix = NULL;
200         char *tok;
201         const char *p;
202         const char **attrs;
203
204         /* Unfortunatly there is no proper way to detect syncrepl-support in
205          * smbldap_connect_system(). The syncrepl OIDs are submitted for publication
206          * but do not show up in the root-DSE yet. Neither we can query the
207          * subschema-context for the syncProviderSubentry or syncConsumerSubentry
208          * objectclass. Currently we require lp_ldap_suffix() to show up as
209          * namingContext.  -  Guenther
210          */
211
212         if (!lp_parm_bool(-1, "ldapsam", "syncrepl_seqnum", False)) {
213                 return ntstatus;
214         }
215
216         if (!seq_num) {
217                 DEBUG(3,("ldapsam_get_seq_num: no sequence_number\n"));
218                 return ntstatus;
219         }
220
221         if (!smbldap_has_naming_context(ldap_state->smbldap_state->ldap_struct, lp_ldap_suffix())) {
222                 DEBUG(3,("ldapsam_get_seq_num: DIT not configured to hold %s "
223                          "as top-level namingContext\n", lp_ldap_suffix()));
224                 return ntstatus;
225         }
226
227         mem_ctx = talloc_init("ldapsam_get_seq_num");
228
229         if (mem_ctx == NULL)
230                 return NT_STATUS_NO_MEMORY;
231
232         if ((attrs = TALLOC_ARRAY(mem_ctx, const char *, 2)) == NULL) {
233                 ntstatus = NT_STATUS_NO_MEMORY;
234                 goto done;
235         }
236
237         /* if we got a syncrepl-rid (up to three digits long) we speak with a consumer */
238         rid = lp_parm_int(-1, "ldapsam", "syncrepl_rid", -1);
239         if (rid > 0) {
240
241                 /* consumer syncreplCookie: */
242                 /* csn=20050126161620Z#0000001#00#00000 */
243                 attrs[0] = talloc_strdup(mem_ctx, "syncreplCookie");
244                 attrs[1] = NULL;
245                 suffix = talloc_asprintf(mem_ctx,
246                                 "cn=syncrepl%d,%s", rid, lp_ldap_suffix());
247                 if (!suffix) {
248                         ntstatus = NT_STATUS_NO_MEMORY;
249                         goto done;
250                 }
251         } else {
252
253                 /* provider contextCSN */
254                 /* 20050126161620Z#000009#00#000000 */
255                 attrs[0] = talloc_strdup(mem_ctx, "contextCSN");
256                 attrs[1] = NULL;
257                 suffix = talloc_asprintf(mem_ctx,
258                                 "cn=ldapsync,%s", lp_ldap_suffix());
259
260                 if (!suffix) {
261                         ntstatus = NT_STATUS_NO_MEMORY;
262                         goto done;
263                 }
264         }
265
266         rc = smbldap_search(ldap_state->smbldap_state, suffix,
267                             LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0, &msg);
268
269         if (rc != LDAP_SUCCESS) {
270                 goto done;
271         }
272
273         num_result = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, msg);
274         if (num_result != 1) {
275                 DEBUG(3,("ldapsam_get_seq_num: Expected one entry, got %d\n", num_result));
276                 goto done;
277         }
278
279         entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, msg);
280         if (entry == NULL) {
281                 DEBUG(3,("ldapsam_get_seq_num: Could not retrieve entry\n"));
282                 goto done;
283         }
284
285         values = ldap_get_values(ldap_state->smbldap_state->ldap_struct, entry, attrs[0]);
286         if (values == NULL) {
287                 DEBUG(3,("ldapsam_get_seq_num: no values\n"));
288                 goto done;
289         }
290
291         num_values = ldap_count_values(values);
292         if (num_values == 0) {
293                 DEBUG(3,("ldapsam_get_seq_num: not a single value\n"));
294                 goto done;
295         }
296
297         p = values[0];
298         if (!next_token_talloc(mem_ctx, &p, &tok, "#")) {
299                 DEBUG(0,("ldapsam_get_seq_num: failed to parse sequence number\n"));
300                 goto done;
301         }
302
303         p = tok;
304         if (!strncmp(p, "csn=", strlen("csn=")))
305                 p += strlen("csn=");
306
307         DEBUG(10,("ldapsam_get_seq_num: got %s: %s\n", attrs[0], p));
308
309         *seq_num = generalized_to_unix_time(p);
310
311         /* very basic sanity check */
312         if (*seq_num <= 0) {
313                 DEBUG(3,("ldapsam_get_seq_num: invalid sequence number: %d\n", 
314                         (int)*seq_num));
315                 goto done;
316         }
317
318         ntstatus = NT_STATUS_OK;
319
320  done:
321         if (values != NULL)
322                 ldap_value_free(values);
323         if (msg != NULL)
324                 ldap_msgfree(msg);
325         if (mem_ctx)
326                 talloc_destroy(mem_ctx);
327
328         return ntstatus;
329 }
330
331 /*******************************************************************
332  Run the search by name.
333 ******************************************************************/
334
335 int ldapsam_search_suffix_by_name(struct ldapsam_privates *ldap_state,
336                                           const char *user,
337                                           LDAPMessage ** result,
338                                           const char **attr)
339 {
340         char *filter = NULL;
341         char *escape_user = escape_ldap_string(talloc_tos(), user);
342         int ret = -1;
343
344         if (!escape_user) {
345                 return LDAP_NO_MEMORY;
346         }
347
348         /*
349          * in the filter expression, replace %u with the real name
350          * so in ldap filter, %u MUST exist :-)
351          */
352         filter = talloc_asprintf(talloc_tos(), "(&%s%s)", "(uid=%u)",
353                 get_objclass_filter(ldap_state->schema_ver));
354         if (!filter) {
355                 TALLOC_FREE(escape_user);
356                 return LDAP_NO_MEMORY;
357         }
358         /*
359          * have to use this here because $ is filtered out
360          * in string_sub
361          */
362
363         filter = talloc_all_string_sub(talloc_tos(),
364                                 filter, "%u", escape_user);
365         TALLOC_FREE(escape_user);
366         if (!filter) {
367                 return LDAP_NO_MEMORY;
368         }
369
370         ret = smbldap_search_suffix(ldap_state->smbldap_state,
371                         filter, attr, result);
372         TALLOC_FREE(filter);
373         return ret;
374 }
375
376 /*******************************************************************
377  Run the search by rid.
378 ******************************************************************/
379
380 static int ldapsam_search_suffix_by_rid (struct ldapsam_privates *ldap_state,
381                                          uint32_t rid, LDAPMessage ** result,
382                                          const char **attr)
383 {
384         char *filter = NULL;
385         int rc;
386
387         filter = talloc_asprintf(talloc_tos(), "(&(rid=%i)%s)", rid,
388                 get_objclass_filter(ldap_state->schema_ver));
389         if (!filter) {
390                 return LDAP_NO_MEMORY;
391         }
392
393         rc = smbldap_search_suffix(ldap_state->smbldap_state,
394                         filter, attr, result);
395         TALLOC_FREE(filter);
396         return rc;
397 }
398
399 /*******************************************************************
400  Run the search by SID.
401 ******************************************************************/
402
403 static int ldapsam_search_suffix_by_sid (struct ldapsam_privates *ldap_state,
404                                  const struct dom_sid *sid, LDAPMessage ** result,
405                                  const char **attr)
406 {
407         char *filter = NULL;
408         int rc;
409         fstring sid_string;
410
411         filter = talloc_asprintf(talloc_tos(), "(&(%s=%s)%s)",
412                 get_userattr_key2string(ldap_state->schema_ver,
413                         LDAP_ATTR_USER_SID),
414                 sid_to_fstring(sid_string, sid),
415                 get_objclass_filter(ldap_state->schema_ver));
416         if (!filter) {
417                 return LDAP_NO_MEMORY;
418         }
419
420         rc = smbldap_search_suffix(ldap_state->smbldap_state,
421                         filter, attr, result);
422
423         TALLOC_FREE(filter);
424         return rc;
425 }
426
427 /*******************************************************************
428  Delete complete object or objectclass and attrs from
429  object found in search_result depending on lp_ldap_delete_dn
430 ******************************************************************/
431
432 static int ldapsam_delete_entry(struct ldapsam_privates *priv,
433                                 TALLOC_CTX *mem_ctx,
434                                 LDAPMessage *entry,
435                                 const char *objectclass,
436                                 const char **attrs)
437 {
438         LDAPMod **mods = NULL;
439         char *name;
440         const char *dn;
441         BerElement *ptr = NULL;
442
443         dn = smbldap_talloc_dn(mem_ctx, priv2ld(priv), entry);
444         if (dn == NULL) {
445                 return LDAP_NO_MEMORY;
446         }
447
448         if (lp_ldap_delete_dn()) {
449                 return smbldap_delete(priv->smbldap_state, dn);
450         }
451
452         /* Ok, delete only the SAM attributes */
453
454         for (name = ldap_first_attribute(priv2ld(priv), entry, &ptr);
455              name != NULL;
456              name = ldap_next_attribute(priv2ld(priv), entry, ptr)) {
457                 const char **attrib;
458
459                 /* We are only allowed to delete the attributes that
460                    really exist. */
461
462                 for (attrib = attrs; *attrib != NULL; attrib++) {
463                         if (strequal(*attrib, name)) {
464                                 DEBUG(10, ("ldapsam_delete_entry: deleting "
465                                            "attribute %s\n", name));
466                                 smbldap_set_mod(&mods, LDAP_MOD_DELETE, name,
467                                                 NULL);
468                         }
469                 }
470                 ldap_memfree(name);
471         }
472
473         if (ptr != NULL) {
474                 ber_free(ptr, 0);
475         }
476
477         smbldap_set_mod(&mods, LDAP_MOD_DELETE, "objectClass", objectclass);
478         talloc_autofree_ldapmod(mem_ctx, mods);
479
480         return smbldap_modify(priv->smbldap_state, dn, mods);
481 }
482
483 static time_t ldapsam_get_entry_timestamp( struct ldapsam_privates *ldap_state, LDAPMessage * entry)
484 {
485         char *temp;
486         struct tm tm;
487
488         temp = smbldap_talloc_single_attribute(ldap_state->smbldap_state->ldap_struct, entry,
489                         get_userattr_key2string(ldap_state->schema_ver,LDAP_ATTR_MOD_TIMESTAMP),
490                         talloc_tos());
491         if (!temp) {
492                 return (time_t) 0;
493         }
494
495         if ( !strptime(temp, "%Y%m%d%H%M%SZ", &tm)) {
496                 DEBUG(2,("ldapsam_get_entry_timestamp: strptime failed on: %s\n",
497                         (char*)temp));
498                 TALLOC_FREE(temp);
499                 return (time_t) 0;
500         }
501         TALLOC_FREE(temp);
502         tzset();
503         return timegm(&tm);
504 }
505
506 /**********************************************************************
507  Initialize struct samu from an LDAP query.
508  (Based on init_sam_from_buffer in pdb_tdb.c)
509 *********************************************************************/
510
511 static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state,
512                                 struct samu * sampass,
513                                 LDAPMessage * entry)
514 {
515         time_t  logon_time,
516                         logoff_time,
517                         kickoff_time,
518                         pass_last_set_time,
519                         pass_can_change_time,
520                         pass_must_change_time,
521                         ldap_entry_time,
522                         bad_password_time;
523         char *username = NULL,
524                         *domain = NULL,
525                         *nt_username = NULL,
526                         *fullname = NULL,
527                         *homedir = NULL,
528                         *dir_drive = NULL,
529                         *logon_script = NULL,
530                         *profile_path = NULL,
531                         *acct_desc = NULL,
532                         *workstations = NULL,
533                         *munged_dial = NULL;
534         uint32_t                user_rid;
535         uint8           smblmpwd[LM_HASH_LEN],
536                         smbntpwd[NT_HASH_LEN];
537         bool            use_samba_attrs = True;
538         uint32_t                acct_ctrl = 0;
539         uint16_t                logon_divs;
540         uint16_t                bad_password_count = 0,
541                         logon_count = 0;
542         uint32_t hours_len;
543         uint8           hours[MAX_HOURS_LEN];
544         char *temp = NULL;
545         struct login_cache cache_entry;
546         uint32_t                pwHistLen;
547         bool expand_explicit = lp_passdb_expand_explicit();
548         bool ret = false;
549         TALLOC_CTX *ctx = talloc_init("init_sam_from_ldap");
550
551         if (!ctx) {
552                 return false;
553         }
554         if (sampass == NULL || ldap_state == NULL || entry == NULL) {
555                 DEBUG(0, ("init_sam_from_ldap: NULL parameters found!\n"));
556                 goto fn_exit;
557         }
558
559         if (priv2ld(ldap_state) == NULL) {
560                 DEBUG(0, ("init_sam_from_ldap: ldap_state->smbldap_state->"
561                           "ldap_struct is NULL!\n"));
562                 goto fn_exit;
563         }
564
565         if (!(username = smbldap_talloc_first_attribute(priv2ld(ldap_state),
566                                         entry,
567                                         "uid",
568                                         ctx))) {
569                 DEBUG(1, ("init_sam_from_ldap: No uid attribute found for "
570                           "this user!\n"));
571                 goto fn_exit;
572         }
573
574         DEBUG(2, ("init_sam_from_ldap: Entry found for user: %s\n", username));
575
576         nt_username = talloc_strdup(ctx, username);
577         if (!nt_username) {
578                 goto fn_exit;
579         }
580
581         domain = talloc_strdup(ctx, ldap_state->domain_name);
582         if (!domain) {
583                 goto fn_exit;
584         }
585
586         pdb_set_username(sampass, username, PDB_SET);
587
588         pdb_set_domain(sampass, domain, PDB_DEFAULT);
589         pdb_set_nt_username(sampass, nt_username, PDB_SET);
590
591         /* deal with different attributes between the schema first */
592
593         if ( ldap_state->schema_ver == SCHEMAVER_SAMBASAMACCOUNT ) {
594                 if ((temp = smbldap_talloc_single_attribute(
595                                 ldap_state->smbldap_state->ldap_struct,
596                                 entry,
597                                 get_userattr_key2string(ldap_state->schema_ver,
598                                         LDAP_ATTR_USER_SID),
599                                 ctx))!=NULL) {
600                         pdb_set_user_sid_from_string(sampass, temp, PDB_SET);
601                 }
602         } else {
603                 if ((temp = smbldap_talloc_single_attribute(
604                                 ldap_state->smbldap_state->ldap_struct,
605                                 entry,
606                                 get_userattr_key2string(ldap_state->schema_ver,
607                                         LDAP_ATTR_USER_RID),
608                                 ctx))!=NULL) {
609                         user_rid = (uint32_t)atol(temp);
610                         pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
611                 }
612         }
613
614         if (IS_SAM_DEFAULT(sampass, PDB_USERSID)) {
615                 DEBUG(1, ("init_sam_from_ldap: no %s or %s attribute found for this user %s\n", 
616                         get_userattr_key2string(ldap_state->schema_ver,
617                                 LDAP_ATTR_USER_SID),
618                         get_userattr_key2string(ldap_state->schema_ver,
619                                 LDAP_ATTR_USER_RID),
620                         username));
621                 return False;
622         }
623
624         temp = smbldap_talloc_single_attribute(
625                         ldap_state->smbldap_state->ldap_struct,
626                         entry,
627                         get_userattr_key2string(ldap_state->schema_ver,
628                                 LDAP_ATTR_PWD_LAST_SET),
629                         ctx);
630         if (temp) {
631                 pass_last_set_time = (time_t) atol(temp);
632                 pdb_set_pass_last_set_time(sampass,
633                                 pass_last_set_time, PDB_SET);
634         }
635
636         temp = smbldap_talloc_single_attribute(
637                         ldap_state->smbldap_state->ldap_struct,
638                         entry,
639                         get_userattr_key2string(ldap_state->schema_ver,
640                                 LDAP_ATTR_LOGON_TIME),
641                         ctx);
642         if (temp) {
643                 logon_time = (time_t) atol(temp);
644                 pdb_set_logon_time(sampass, logon_time, PDB_SET);
645         }
646
647         temp = smbldap_talloc_single_attribute(
648                         ldap_state->smbldap_state->ldap_struct,
649                         entry,
650                         get_userattr_key2string(ldap_state->schema_ver,
651                                 LDAP_ATTR_LOGOFF_TIME),
652                         ctx);
653         if (temp) {
654                 logoff_time = (time_t) atol(temp);
655                 pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
656         }
657
658         temp = smbldap_talloc_single_attribute(
659                         ldap_state->smbldap_state->ldap_struct,
660                         entry,
661                         get_userattr_key2string(ldap_state->schema_ver,
662                                 LDAP_ATTR_KICKOFF_TIME),
663                         ctx);
664         if (temp) {
665                 kickoff_time = (time_t) atol(temp);
666                 pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
667         }
668
669         temp = smbldap_talloc_single_attribute(
670                         ldap_state->smbldap_state->ldap_struct,
671                         entry,
672                         get_userattr_key2string(ldap_state->schema_ver,
673                                 LDAP_ATTR_PWD_CAN_CHANGE),
674                         ctx);
675         if (temp) {
676                 pass_can_change_time = (time_t) atol(temp);
677                 pdb_set_pass_can_change_time(sampass,
678                                 pass_can_change_time, PDB_SET);
679         }
680
681         temp = smbldap_talloc_single_attribute(
682                         ldap_state->smbldap_state->ldap_struct,
683                         entry,
684                         get_userattr_key2string(ldap_state->schema_ver,
685                                 LDAP_ATTR_PWD_MUST_CHANGE),
686                         ctx);
687         if (temp) {
688                 pass_must_change_time = (time_t) atol(temp);
689                 pdb_set_pass_must_change_time(sampass,
690                                 pass_must_change_time, PDB_SET);
691         }
692
693         /* recommend that 'gecos' and 'displayName' should refer to the same
694          * attribute OID.  userFullName depreciated, only used by Samba
695          * primary rules of LDAP: don't make a new attribute when one is already defined
696          * that fits your needs; using cn then displayName rather than 'userFullName'
697          */
698
699         fullname = smbldap_talloc_single_attribute(
700                         ldap_state->smbldap_state->ldap_struct,
701                         entry,
702                         get_userattr_key2string(ldap_state->schema_ver,
703                                 LDAP_ATTR_DISPLAY_NAME),
704                         ctx);
705         if (fullname) {
706                 pdb_set_fullname(sampass, fullname, PDB_SET);
707         } else {
708                 fullname = smbldap_talloc_single_attribute(
709                                 ldap_state->smbldap_state->ldap_struct,
710                                 entry,
711                                 get_userattr_key2string(ldap_state->schema_ver,
712                                         LDAP_ATTR_CN),
713                                 ctx);
714                 if (fullname) {
715                         pdb_set_fullname(sampass, fullname, PDB_SET);
716                 }
717         }
718
719         dir_drive = smbldap_talloc_single_attribute(
720                         ldap_state->smbldap_state->ldap_struct,
721                         entry,
722                         get_userattr_key2string(ldap_state->schema_ver,
723                                 LDAP_ATTR_HOME_DRIVE),
724                         ctx);
725         if (dir_drive) {
726                 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
727         } else {
728                 pdb_set_dir_drive( sampass, lp_logon_drive(), PDB_DEFAULT );
729         }
730
731         homedir = smbldap_talloc_single_attribute(
732                         ldap_state->smbldap_state->ldap_struct,
733                         entry,
734                         get_userattr_key2string(ldap_state->schema_ver,
735                                 LDAP_ATTR_HOME_PATH),
736                         ctx);
737         if (homedir) {
738                 if (expand_explicit) {
739                         homedir = talloc_sub_basic(ctx,
740                                                 username,
741                                                 domain,
742                                                 homedir);
743                         if (!homedir) {
744                                 goto fn_exit;
745                         }
746                 }
747                 pdb_set_homedir(sampass, homedir, PDB_SET);
748         } else {
749                 pdb_set_homedir(sampass,
750                         talloc_sub_basic(ctx, username, domain,
751                                          lp_logon_home()),
752                         PDB_DEFAULT);
753         }
754
755         logon_script = smbldap_talloc_single_attribute(
756                         ldap_state->smbldap_state->ldap_struct,
757                         entry,
758                         get_userattr_key2string(ldap_state->schema_ver,
759                                 LDAP_ATTR_LOGON_SCRIPT),
760                         ctx);
761         if (logon_script) {
762                 if (expand_explicit) {
763                         logon_script = talloc_sub_basic(ctx,
764                                                 username,
765                                                 domain,
766                                                 logon_script);
767                         if (!logon_script) {
768                                 goto fn_exit;
769                         }
770                 }
771                 pdb_set_logon_script(sampass, logon_script, PDB_SET);
772         } else {
773                 pdb_set_logon_script(sampass,
774                         talloc_sub_basic(ctx, username, domain,
775                                          lp_logon_script()),
776                         PDB_DEFAULT );
777         }
778
779         profile_path = smbldap_talloc_single_attribute(
780                         ldap_state->smbldap_state->ldap_struct,
781                         entry,
782                         get_userattr_key2string(ldap_state->schema_ver,
783                                 LDAP_ATTR_PROFILE_PATH),
784                         ctx);
785         if (profile_path) {
786                 if (expand_explicit) {
787                         profile_path = talloc_sub_basic(ctx,
788                                                 username,
789                                                 domain,
790                                                 profile_path);
791                         if (!profile_path) {
792                                 goto fn_exit;
793                         }
794                 }
795                 pdb_set_profile_path(sampass, profile_path, PDB_SET);
796         } else {
797                 pdb_set_profile_path(sampass,
798                         talloc_sub_basic(ctx, username, domain,
799                                           lp_logon_path()),
800                         PDB_DEFAULT );
801         }
802
803         acct_desc = smbldap_talloc_single_attribute(
804                         ldap_state->smbldap_state->ldap_struct,
805                         entry,
806                         get_userattr_key2string(ldap_state->schema_ver,
807                                 LDAP_ATTR_DESC),
808                         ctx);
809         if (acct_desc) {
810                 pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
811         }
812
813         workstations = smbldap_talloc_single_attribute(
814                         ldap_state->smbldap_state->ldap_struct,
815                         entry,
816                         get_userattr_key2string(ldap_state->schema_ver,
817                                 LDAP_ATTR_USER_WKS),
818                         ctx);
819         if (workstations) {
820                 pdb_set_workstations(sampass, workstations, PDB_SET);
821         }
822
823         munged_dial = smbldap_talloc_single_attribute(
824                         ldap_state->smbldap_state->ldap_struct,
825                         entry,
826                         get_userattr_key2string(ldap_state->schema_ver,
827                                 LDAP_ATTR_MUNGED_DIAL),
828                         ctx);
829         if (munged_dial) {
830                 pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
831         }
832
833         /* FIXME: hours stuff should be cleaner */
834
835         logon_divs = 168;
836         hours_len = 21;
837         memset(hours, 0xff, hours_len);
838
839         if (ldap_state->is_nds_ldap) {
840                 char *user_dn;
841                 size_t pwd_len;
842                 char clear_text_pw[512];
843
844                 /* Make call to Novell eDirectory ldap extension to get clear text password.
845                         NOTE: This will only work if we have an SSL connection to eDirectory. */
846                 user_dn = smbldap_talloc_dn(ctx, ldap_state->smbldap_state->ldap_struct, entry);
847                 if (user_dn != NULL) {
848                         DEBUG(3, ("init_sam_from_ldap: smbldap_talloc_dn(ctx, %s) returned '%s'\n", username, user_dn));
849
850                         pwd_len = sizeof(clear_text_pw);
851                         if (pdb_nds_get_password(ldap_state->smbldap_state, user_dn, &pwd_len, clear_text_pw) == LDAP_SUCCESS) {
852                                 nt_lm_owf_gen(clear_text_pw, smbntpwd, smblmpwd);
853                                 if (!pdb_set_lanman_passwd(sampass, smblmpwd, PDB_SET)) {
854                                         TALLOC_FREE(user_dn);
855                                         return False;
856                                 }
857                                 ZERO_STRUCT(smblmpwd);
858                                 if (!pdb_set_nt_passwd(sampass, smbntpwd, PDB_SET)) {
859                                         TALLOC_FREE(user_dn);
860                                         return False;
861                                 }
862                                 ZERO_STRUCT(smbntpwd);
863                                 use_samba_attrs = False;
864                         }
865
866                         TALLOC_FREE(user_dn);
867
868                 } else {
869                         DEBUG(0, ("init_sam_from_ldap: failed to get user_dn for '%s'\n", username));
870                 }
871         }
872
873         if (use_samba_attrs) {
874                 temp = smbldap_talloc_single_attribute(
875                                 ldap_state->smbldap_state->ldap_struct,
876                                 entry,
877                                 get_userattr_key2string(ldap_state->schema_ver,
878                                         LDAP_ATTR_LMPW),
879                                 ctx);
880                 if (temp) {
881                         pdb_gethexpwd(temp, smblmpwd);
882                         memset((char *)temp, '\0', strlen(temp)+1);
883                         if (!pdb_set_lanman_passwd(sampass, smblmpwd, PDB_SET)) {
884                                 goto fn_exit;
885                         }
886                         ZERO_STRUCT(smblmpwd);
887                 }
888
889                 temp = smbldap_talloc_single_attribute(
890                                 ldap_state->smbldap_state->ldap_struct,
891                                 entry,
892                                 get_userattr_key2string(ldap_state->schema_ver,
893                                         LDAP_ATTR_NTPW),
894                                 ctx);
895                 if (temp) {
896                         pdb_gethexpwd(temp, smbntpwd);
897                         memset((char *)temp, '\0', strlen(temp)+1);
898                         if (!pdb_set_nt_passwd(sampass, smbntpwd, PDB_SET)) {
899                                 goto fn_exit;
900                         }
901                         ZERO_STRUCT(smbntpwd);
902                 }
903         }
904
905         pwHistLen = 0;
906
907         pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHistLen);
908         if (pwHistLen > 0){
909                 uint8 *pwhist = NULL;
910                 int i;
911                 char *history_string = TALLOC_ARRAY(ctx, char,
912                                                 MAX_PW_HISTORY_LEN*64);
913
914                 if (!history_string) {
915                         goto fn_exit;
916                 }
917
918                 pwHistLen = MIN(pwHistLen, MAX_PW_HISTORY_LEN);
919
920                 pwhist = TALLOC_ARRAY(ctx, uint8,
921                                       pwHistLen * PW_HISTORY_ENTRY_LEN);
922                 if (pwhist == NULL) {
923                         DEBUG(0, ("init_sam_from_ldap: talloc failed!\n"));
924                         goto fn_exit;
925                 }
926                 memset(pwhist, '\0', pwHistLen * PW_HISTORY_ENTRY_LEN);
927
928                 if (smbldap_get_single_attribute(
929                                 ldap_state->smbldap_state->ldap_struct,
930                                 entry,
931                                 get_userattr_key2string(ldap_state->schema_ver,
932                                         LDAP_ATTR_PWD_HISTORY),
933                                 history_string,
934                                 MAX_PW_HISTORY_LEN*64)) {
935                         bool hex_failed = false;
936                         for (i = 0; i < pwHistLen; i++){
937                                 /* Get the 16 byte salt. */
938                                 if (!pdb_gethexpwd(&history_string[i*64],
939                                         &pwhist[i*PW_HISTORY_ENTRY_LEN])) {
940                                         hex_failed = true;
941                                         break;
942                                 }
943                                 /* Get the 16 byte MD5 hash of salt+passwd. */
944                                 if (!pdb_gethexpwd(&history_string[(i*64)+32],
945                                         &pwhist[(i*PW_HISTORY_ENTRY_LEN)+
946                                                 PW_HISTORY_SALT_LEN])) {
947                                         hex_failed = True;
948                                         break;
949                                 }
950                         }
951                         if (hex_failed) {
952                                 DEBUG(2,("init_sam_from_ldap: Failed to get password history for user %s\n",
953                                         username));
954                                 memset(pwhist, '\0', pwHistLen * PW_HISTORY_ENTRY_LEN);
955                         }
956                 }
957                 if (!pdb_set_pw_history(sampass, pwhist, pwHistLen, PDB_SET)){
958                         goto fn_exit;
959                 }
960         }
961
962         temp = smbldap_talloc_single_attribute(
963                         ldap_state->smbldap_state->ldap_struct,
964                         entry,
965                         get_userattr_key2string(ldap_state->schema_ver,
966                                 LDAP_ATTR_ACB_INFO),
967                         ctx);
968         if (temp) {
969                 acct_ctrl = pdb_decode_acct_ctrl(temp);
970
971                 if (acct_ctrl == 0) {
972                         acct_ctrl |= ACB_NORMAL;
973                 }
974
975                 pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
976         } else {
977                 acct_ctrl |= ACB_NORMAL;
978         }
979
980         pdb_set_hours_len(sampass, hours_len, PDB_SET);
981         pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
982
983         temp = smbldap_talloc_single_attribute(
984                         ldap_state->smbldap_state->ldap_struct,
985                         entry,
986                         get_userattr_key2string(ldap_state->schema_ver,
987                                 LDAP_ATTR_BAD_PASSWORD_COUNT),
988                         ctx);
989         if (temp) {
990                 bad_password_count = (uint32_t) atol(temp);
991                 pdb_set_bad_password_count(sampass,
992                                 bad_password_count, PDB_SET);
993         }
994
995         temp = smbldap_talloc_single_attribute(
996                         ldap_state->smbldap_state->ldap_struct,
997                         entry,
998                         get_userattr_key2string(ldap_state->schema_ver,
999                                 LDAP_ATTR_BAD_PASSWORD_TIME),
1000                         ctx);
1001         if (temp) {
1002                 bad_password_time = (time_t) atol(temp);
1003                 pdb_set_bad_password_time(sampass, bad_password_time, PDB_SET);
1004         }
1005
1006
1007         temp = smbldap_talloc_single_attribute(
1008                         ldap_state->smbldap_state->ldap_struct,
1009                         entry,
1010                         get_userattr_key2string(ldap_state->schema_ver,
1011                                 LDAP_ATTR_LOGON_COUNT),
1012                         ctx);
1013         if (temp) {
1014                 logon_count = (uint32_t) atol(temp);
1015                 pdb_set_logon_count(sampass, logon_count, PDB_SET);
1016         }
1017
1018         /* pdb_set_unknown_6(sampass, unknown6, PDB_SET); */
1019
1020         temp = smbldap_talloc_single_attribute(
1021                         ldap_state->smbldap_state->ldap_struct,
1022                         entry,
1023                         get_userattr_key2string(ldap_state->schema_ver,
1024                                 LDAP_ATTR_LOGON_HOURS),
1025                         ctx);
1026         if (temp) {
1027                 pdb_gethexhours(temp, hours);
1028                 memset((char *)temp, '\0', strlen(temp) +1);
1029                 pdb_set_hours(sampass, hours, PDB_SET);
1030                 ZERO_STRUCT(hours);
1031         }
1032
1033         if (lp_parm_bool(-1, "ldapsam", "trusted", False)) {
1034                 struct passwd unix_pw;
1035                 bool have_uid = false;
1036                 bool have_gid = false;
1037                 struct dom_sid mapped_gsid;
1038                 const struct dom_sid *primary_gsid;
1039
1040                 ZERO_STRUCT(unix_pw);
1041
1042                 unix_pw.pw_name = username;
1043                 unix_pw.pw_passwd = discard_const_p(char, "x");
1044
1045                 temp = smbldap_talloc_single_attribute(
1046                                 priv2ld(ldap_state),
1047                                 entry,
1048                                 "uidNumber",
1049                                 ctx);
1050                 if (temp) {
1051                         /* We've got a uid, feed the cache */
1052                         unix_pw.pw_uid = strtoul(temp, NULL, 10);
1053                         have_uid = true;
1054                 }
1055                 temp = smbldap_talloc_single_attribute(
1056                                 priv2ld(ldap_state),
1057                                 entry,
1058                                 "gidNumber",
1059                                 ctx);
1060                 if (temp) {
1061                         /* We've got a uid, feed the cache */
1062                         unix_pw.pw_gid = strtoul(temp, NULL, 10);
1063                         have_gid = true;
1064                 }
1065                 unix_pw.pw_gecos = smbldap_talloc_single_attribute(
1066                                 priv2ld(ldap_state),
1067                                 entry,
1068                                 "gecos",
1069                                 ctx);
1070                 if (unix_pw.pw_gecos) {
1071                         unix_pw.pw_gecos = fullname;
1072                 }
1073                 unix_pw.pw_dir = smbldap_talloc_single_attribute(
1074                                 priv2ld(ldap_state),
1075                                 entry,
1076                                 "homeDirectory",
1077                                 ctx);
1078                 if (unix_pw.pw_dir) {
1079                         unix_pw.pw_dir = discard_const_p(char, "");
1080                 }
1081                 unix_pw.pw_shell = smbldap_talloc_single_attribute(
1082                                 priv2ld(ldap_state),
1083                                 entry,
1084                                 "loginShell",
1085                                 ctx);
1086                 if (unix_pw.pw_shell) {
1087                         unix_pw.pw_shell = discard_const_p(char, "");
1088                 }
1089
1090                 if (have_uid && have_gid) {
1091                         sampass->unix_pw = tcopy_passwd(sampass, &unix_pw);
1092                 } else {
1093                         sampass->unix_pw = Get_Pwnam_alloc(sampass, unix_pw.pw_name);
1094                 }
1095
1096                 if (sampass->unix_pw == NULL) {
1097                         DEBUG(0,("init_sam_from_ldap: Failed to find Unix account for %s\n",
1098                                  pdb_get_username(sampass)));
1099                         goto fn_exit;
1100                 }
1101
1102                 store_uid_sid_cache(pdb_get_user_sid(sampass),
1103                                     sampass->unix_pw->pw_uid);
1104                 idmap_cache_set_sid2uid(pdb_get_user_sid(sampass),
1105                                         sampass->unix_pw->pw_uid);
1106
1107                 gid_to_sid(&mapped_gsid, sampass->unix_pw->pw_gid);
1108                 primary_gsid = pdb_get_group_sid(sampass);
1109                 if (primary_gsid && sid_equal(primary_gsid, &mapped_gsid)) {
1110                         store_gid_sid_cache(primary_gsid,
1111                                             sampass->unix_pw->pw_gid);
1112                         idmap_cache_set_sid2gid(primary_gsid,
1113                                                 sampass->unix_pw->pw_gid);
1114                 }
1115         }
1116
1117         /* check the timestamp of the cache vs ldap entry */
1118         if (!(ldap_entry_time = ldapsam_get_entry_timestamp(ldap_state,
1119                                                             entry))) {
1120                 ret = true;
1121                 goto fn_exit;
1122         }
1123
1124         /* see if we have newer updates */
1125         if (!login_cache_read(sampass, &cache_entry)) {
1126                 DEBUG (9, ("No cache entry, bad count = %u, bad time = %u\n",
1127                            (unsigned int)pdb_get_bad_password_count(sampass),
1128                            (unsigned int)pdb_get_bad_password_time(sampass)));
1129                 ret = true;
1130                 goto fn_exit;
1131         }
1132
1133         DEBUG(7, ("ldap time is %u, cache time is %u, bad time = %u\n",
1134                   (unsigned int)ldap_entry_time,
1135                   (unsigned int)cache_entry.entry_timestamp,
1136                   (unsigned int)cache_entry.bad_password_time));
1137
1138         if (ldap_entry_time > cache_entry.entry_timestamp) {
1139                 /* cache is older than directory , so
1140                    we need to delete the entry but allow the
1141                    fields to be written out */
1142                 login_cache_delentry(sampass);
1143         } else {
1144                 /* read cache in */
1145                 pdb_set_acct_ctrl(sampass,
1146                                   pdb_get_acct_ctrl(sampass) |
1147                                   (cache_entry.acct_ctrl & ACB_AUTOLOCK),
1148                                   PDB_SET);
1149                 pdb_set_bad_password_count(sampass,
1150                                            cache_entry.bad_password_count,
1151                                            PDB_SET);
1152                 pdb_set_bad_password_time(sampass,
1153                                           cache_entry.bad_password_time,
1154                                           PDB_SET);
1155         }
1156
1157         ret = true;
1158
1159   fn_exit:
1160
1161         TALLOC_FREE(ctx);
1162         return ret;
1163 }
1164
1165 /**********************************************************************
1166  Initialize the ldap db from a struct samu. Called on update.
1167  (Based on init_buffer_from_sam in pdb_tdb.c)
1168 *********************************************************************/
1169
1170 static bool init_ldap_from_sam (struct ldapsam_privates *ldap_state,
1171                                 LDAPMessage *existing,
1172                                 LDAPMod *** mods, struct samu * sampass,
1173                                 bool (*need_update)(const struct samu *,
1174                                                     enum pdb_elements))
1175 {
1176         char *temp = NULL;
1177         uint32_t rid;
1178
1179         if (mods == NULL || sampass == NULL) {
1180                 DEBUG(0, ("init_ldap_from_sam: NULL parameters found!\n"));
1181                 return False;
1182         }
1183
1184         *mods = NULL;
1185
1186         /*
1187          * took out adding "objectclass: sambaAccount"
1188          * do this on a per-mod basis
1189          */
1190         if (need_update(sampass, PDB_USERNAME)) {
1191                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods, 
1192                               "uid", pdb_get_username(sampass));
1193                 if (ldap_state->is_nds_ldap) {
1194                         smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods, 
1195                                       "cn", pdb_get_username(sampass));
1196                         smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods, 
1197                                       "sn", pdb_get_username(sampass));
1198                 }
1199         }
1200
1201         DEBUG(2, ("init_ldap_from_sam: Setting entry for user: %s\n", pdb_get_username(sampass)));
1202
1203         /* only update the RID if we actually need to */
1204         if (need_update(sampass, PDB_USERSID)) {
1205                 fstring sid_string;
1206                 const struct dom_sid *user_sid = pdb_get_user_sid(sampass);
1207
1208                 switch ( ldap_state->schema_ver ) {
1209                         case SCHEMAVER_SAMBAACCOUNT:
1210                                 if (!sid_peek_check_rid(&ldap_state->domain_sid, user_sid, &rid)) {
1211                                         DEBUG(1, ("init_ldap_from_sam: User's SID (%s) is not for this domain (%s), cannot add to LDAP!\n", 
1212                                                   sid_string_dbg(user_sid),
1213                                                   sid_string_dbg(
1214                                                           &ldap_state->domain_sid)));
1215                                         return False;
1216                                 }
1217                                 if (asprintf(&temp, "%i", rid) < 0) {
1218                                         return false;
1219                                 }
1220                                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1221                                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_RID), 
1222                                         temp);
1223                                 SAFE_FREE(temp);
1224                                 break;
1225
1226                         case SCHEMAVER_SAMBASAMACCOUNT:
1227                                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1228                                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_SID), 
1229                                         sid_to_fstring(sid_string, user_sid));
1230                                 break;
1231
1232                         default:
1233                                 DEBUG(0,("init_ldap_from_sam: unknown schema version specified\n"));
1234                                 break;
1235                 }
1236         }
1237
1238         /* we don't need to store the primary group RID - so leaving it
1239            'free' to hang off the unix primary group makes life easier */
1240
1241         if (need_update(sampass, PDB_GROUPSID)) {
1242                 fstring sid_string;
1243                 const struct dom_sid *group_sid = pdb_get_group_sid(sampass);
1244
1245                 switch ( ldap_state->schema_ver ) {
1246                         case SCHEMAVER_SAMBAACCOUNT:
1247                                 if (!sid_peek_check_rid(&ldap_state->domain_sid, group_sid, &rid)) {
1248                                         DEBUG(1, ("init_ldap_from_sam: User's Primary Group SID (%s) is not for this domain (%s), cannot add to LDAP!\n",
1249                                                   sid_string_dbg(group_sid),
1250                                                   sid_string_dbg(
1251                                                           &ldap_state->domain_sid)));
1252                                         return False;
1253                                 }
1254
1255                                 if (asprintf(&temp, "%i", rid) < 0) {
1256                                         return false;
1257                                 }
1258                                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1259                                         get_userattr_key2string(ldap_state->schema_ver, 
1260                                         LDAP_ATTR_PRIMARY_GROUP_RID), temp);
1261                                 SAFE_FREE(temp);
1262                                 break;
1263
1264                         case SCHEMAVER_SAMBASAMACCOUNT:
1265                                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1266                                         get_userattr_key2string(ldap_state->schema_ver, 
1267                                         LDAP_ATTR_PRIMARY_GROUP_SID), sid_to_fstring(sid_string, group_sid));
1268                                 break;
1269
1270                         default:
1271                                 DEBUG(0,("init_ldap_from_sam: unknown schema version specified\n"));
1272                                 break;
1273                 }
1274
1275         }
1276
1277         /* displayName, cn, and gecos should all be the same
1278          *  most easily accomplished by giving them the same OID
1279          *  gecos isn't set here b/c it should be handled by the
1280          *  add-user script
1281          *  We change displayName only and fall back to cn if
1282          *  it does not exist.
1283          */
1284
1285         if (need_update(sampass, PDB_FULLNAME))
1286                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1287                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_DISPLAY_NAME), 
1288                         pdb_get_fullname(sampass));
1289
1290         if (need_update(sampass, PDB_ACCTDESC))
1291                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1292                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_DESC), 
1293                         pdb_get_acct_desc(sampass));
1294
1295         if (need_update(sampass, PDB_WORKSTATIONS))
1296                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1297                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_WKS), 
1298                         pdb_get_workstations(sampass));
1299
1300         if (need_update(sampass, PDB_MUNGEDDIAL))
1301                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1302                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_MUNGED_DIAL), 
1303                         pdb_get_munged_dial(sampass));
1304
1305         if (need_update(sampass, PDB_SMBHOME))
1306                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1307                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_HOME_PATH), 
1308                         pdb_get_homedir(sampass));
1309
1310         if (need_update(sampass, PDB_DRIVE))
1311                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1312                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_HOME_DRIVE), 
1313                         pdb_get_dir_drive(sampass));
1314
1315         if (need_update(sampass, PDB_LOGONSCRIPT))
1316                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1317                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGON_SCRIPT), 
1318                         pdb_get_logon_script(sampass));
1319
1320         if (need_update(sampass, PDB_PROFILE))
1321                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1322                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PROFILE_PATH), 
1323                         pdb_get_profile_path(sampass));
1324
1325         if (asprintf(&temp, "%li", (long int)pdb_get_logon_time(sampass)) < 0) {
1326                 return false;
1327         }
1328         if (need_update(sampass, PDB_LOGONTIME))
1329                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1330                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGON_TIME), temp);
1331         SAFE_FREE(temp);
1332
1333         if (asprintf(&temp, "%li", (long int)pdb_get_logoff_time(sampass)) < 0) {
1334                 return false;
1335         }
1336         if (need_update(sampass, PDB_LOGOFFTIME))
1337                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1338                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGOFF_TIME), temp);
1339         SAFE_FREE(temp);
1340
1341         if (asprintf(&temp, "%li", (long int)pdb_get_kickoff_time(sampass)) < 0) {
1342                 return false;
1343         }
1344         if (need_update(sampass, PDB_KICKOFFTIME))
1345                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1346                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_KICKOFF_TIME), temp);
1347         SAFE_FREE(temp);
1348
1349         if (asprintf(&temp, "%li", (long int)pdb_get_pass_can_change_time_noncalc(sampass)) < 0) {
1350                 return false;
1351         }
1352         if (need_update(sampass, PDB_CANCHANGETIME))
1353                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1354                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_CAN_CHANGE), temp);
1355         SAFE_FREE(temp);
1356
1357         if (asprintf(&temp, "%li", (long int)pdb_get_pass_must_change_time(sampass)) < 0) {
1358                 return false;
1359         }
1360         if (need_update(sampass, PDB_MUSTCHANGETIME))
1361                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1362                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_MUST_CHANGE), temp);
1363         SAFE_FREE(temp);
1364
1365         if ((pdb_get_acct_ctrl(sampass)&(ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST))
1366                         || (lp_ldap_passwd_sync()!=LDAP_PASSWD_SYNC_ONLY)) {
1367
1368                 if (need_update(sampass, PDB_LMPASSWD)) {
1369                         const uchar *lm_pw = pdb_get_lanman_passwd(sampass);
1370                         if (lm_pw) {
1371                                 char pwstr[34];
1372                                 pdb_sethexpwd(pwstr, lm_pw,
1373                                               pdb_get_acct_ctrl(sampass));
1374                                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1375                                                  get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LMPW), 
1376                                                  pwstr);
1377                         } else {
1378                                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1379                                                  get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LMPW), 
1380                                                  NULL);
1381                         }
1382                 }
1383                 if (need_update(sampass, PDB_NTPASSWD)) {
1384                         const uchar *nt_pw = pdb_get_nt_passwd(sampass);
1385                         if (nt_pw) {
1386                                 char pwstr[34];
1387                                 pdb_sethexpwd(pwstr, nt_pw,
1388                                               pdb_get_acct_ctrl(sampass));
1389                                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1390                                                  get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_NTPW), 
1391                                                  pwstr);
1392                         } else {
1393                                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1394                                                  get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_NTPW), 
1395                                                  NULL);
1396                         }
1397                 }
1398
1399                 if (need_update(sampass, PDB_PWHISTORY)) {
1400                         char *pwstr = NULL;
1401                         uint32_t pwHistLen = 0;
1402                         pdb_get_account_policy(PDB_POLICY_PASSWORD_HISTORY, &pwHistLen);
1403
1404                         pwstr = SMB_MALLOC_ARRAY(char, 1024);
1405                         if (!pwstr) {
1406                                 return false;
1407                         }
1408                         if (pwHistLen == 0) {
1409                                 /* Remove any password history from the LDAP store. */
1410                                 memset(pwstr, '0', 64); /* NOTE !!!! '0' *NOT '\0' */
1411                                 pwstr[64] = '\0';
1412                         } else {
1413                                 int i;
1414                                 uint32_t currHistLen = 0;
1415                                 const uint8 *pwhist = pdb_get_pw_history(sampass, &currHistLen);
1416                                 if (pwhist != NULL) {
1417                                         /* We can only store (1024-1/64 password history entries. */
1418                                         pwHistLen = MIN(pwHistLen, ((1024-1)/64));
1419                                         for (i=0; i< pwHistLen && i < currHistLen; i++) {
1420                                                 /* Store the salt. */
1421                                                 pdb_sethexpwd(&pwstr[i*64], &pwhist[i*PW_HISTORY_ENTRY_LEN], 0);
1422                                                 /* Followed by the md5 hash of salt + md4 hash */
1423                                                 pdb_sethexpwd(&pwstr[(i*64)+32],
1424                                                         &pwhist[(i*PW_HISTORY_ENTRY_LEN)+PW_HISTORY_SALT_LEN], 0);
1425                                                 DEBUG(100, ("pwstr=%s\n", pwstr));
1426                                         }
1427                                 }
1428                         }
1429                         smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1430                                          get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_HISTORY), 
1431                                          pwstr);
1432                         SAFE_FREE(pwstr);
1433                 }
1434
1435                 if (need_update(sampass, PDB_PASSLASTSET)) {
1436                         if (asprintf(&temp, "%li",
1437                                 (long int)pdb_get_pass_last_set_time(sampass)) < 0) {
1438                                 return false;
1439                         }
1440                         smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1441                                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_LAST_SET), 
1442                                 temp);
1443                         SAFE_FREE(temp);
1444                 }
1445         }
1446
1447         if (need_update(sampass, PDB_HOURS)) {
1448                 const uint8 *hours = pdb_get_hours(sampass);
1449                 if (hours) {
1450                         char hourstr[44];
1451                         pdb_sethexhours(hourstr, hours);
1452                         smbldap_make_mod(ldap_state->smbldap_state->ldap_struct,
1453                                 existing,
1454                                 mods,
1455                                 get_userattr_key2string(ldap_state->schema_ver,
1456                                                 LDAP_ATTR_LOGON_HOURS),
1457                                 hourstr);
1458                 }
1459         }
1460
1461         if (need_update(sampass, PDB_ACCTCTRL))
1462                 smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, existing, mods,
1463                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_ACB_INFO), 
1464                         pdb_encode_acct_ctrl (pdb_get_acct_ctrl(sampass), NEW_PW_FORMAT_SPACE_PADDED_LEN));
1465
1466         /* password lockout cache:
1467            - If we are now autolocking or clearing, we write to ldap
1468            - If we are clearing, we delete the cache entry
1469            - If the count is > 0, we update the cache
1470
1471            This even means when autolocking, we cache, just in case the
1472            update doesn't work, and we have to cache the autolock flag */
1473
1474         if (need_update(sampass, PDB_BAD_PASSWORD_COUNT))  /* &&
1475             need_update(sampass, PDB_BAD_PASSWORD_TIME)) */ {
1476                 uint16_t badcount = pdb_get_bad_password_count(sampass);
1477                 time_t badtime = pdb_get_bad_password_time(sampass);
1478                 uint32_t pol;
1479                 pdb_get_account_policy(PDB_POLICY_BAD_ATTEMPT_LOCKOUT, &pol);
1480
1481                 DEBUG(3, ("updating bad password fields, policy=%u, count=%u, time=%u\n",
1482                         (unsigned int)pol, (unsigned int)badcount, (unsigned int)badtime));
1483
1484                 if ((badcount >= pol) || (badcount == 0)) {
1485                         DEBUG(7, ("making mods to update ldap, count=%u, time=%u\n",
1486                                 (unsigned int)badcount, (unsigned int)badtime));
1487                         if (asprintf(&temp, "%li", (long)badcount) < 0) {
1488                                 return false;
1489                         }
1490                         smbldap_make_mod(
1491                                 ldap_state->smbldap_state->ldap_struct,
1492                                 existing, mods,
1493                                 get_userattr_key2string(
1494                                         ldap_state->schema_ver,
1495                                         LDAP_ATTR_BAD_PASSWORD_COUNT),
1496                                 temp);
1497                         SAFE_FREE(temp);
1498
1499                         if (asprintf(&temp, "%li", (long int)badtime) < 0) {
1500                                 return false;
1501                         }
1502                         smbldap_make_mod(
1503                                 ldap_state->smbldap_state->ldap_struct,
1504                                 existing, mods,
1505                                 get_userattr_key2string(
1506                                         ldap_state->schema_ver,
1507                                         LDAP_ATTR_BAD_PASSWORD_TIME),
1508                                 temp);
1509                         SAFE_FREE(temp);
1510                 }
1511                 if (badcount == 0) {
1512                         DEBUG(7, ("bad password count is reset, deleting login cache entry for %s\n", pdb_get_nt_username(sampass)));
1513                         login_cache_delentry(sampass);
1514                 } else {
1515                         struct login_cache cache_entry;
1516
1517                         cache_entry.entry_timestamp = time(NULL);
1518                         cache_entry.acct_ctrl = pdb_get_acct_ctrl(sampass);
1519                         cache_entry.bad_password_count = badcount;
1520                         cache_entry.bad_password_time = badtime;
1521
1522                         DEBUG(7, ("Updating bad password count and time in login cache\n"));
1523                         login_cache_write(sampass, &cache_entry);
1524                 }
1525         }
1526
1527         return True;
1528 }
1529
1530 /**********************************************************************
1531  End enumeration of the LDAP password list.
1532 *********************************************************************/
1533
1534 static void ldapsam_endsampwent(struct pdb_methods *my_methods)
1535 {
1536         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
1537         if (ldap_state->result) {
1538                 ldap_msgfree(ldap_state->result);
1539                 ldap_state->result = NULL;
1540         }
1541 }
1542
1543 static void append_attr(TALLOC_CTX *mem_ctx, const char ***attr_list,
1544                         const char *new_attr)
1545 {
1546         int i;
1547
1548         if (new_attr == NULL) {
1549                 return;
1550         }
1551
1552         for (i=0; (*attr_list)[i] != NULL; i++) {
1553                 ;
1554         }
1555
1556         (*attr_list) = TALLOC_REALLOC_ARRAY(mem_ctx, (*attr_list),
1557                                             const char *,  i+2);
1558         SMB_ASSERT((*attr_list) != NULL);
1559         (*attr_list)[i] = talloc_strdup((*attr_list), new_attr);
1560         (*attr_list)[i+1] = NULL;
1561 }
1562
1563 static void ldapsam_add_unix_attributes(TALLOC_CTX *mem_ctx,
1564                                         const char ***attr_list)
1565 {
1566         append_attr(mem_ctx, attr_list, "uidNumber");
1567         append_attr(mem_ctx, attr_list, "gidNumber");
1568         append_attr(mem_ctx, attr_list, "homeDirectory");
1569         append_attr(mem_ctx, attr_list, "loginShell");
1570         append_attr(mem_ctx, attr_list, "gecos");
1571 }
1572
1573 /**********************************************************************
1574 Get struct samu entry from LDAP by username.
1575 *********************************************************************/
1576
1577 static NTSTATUS ldapsam_getsampwnam(struct pdb_methods *my_methods, struct samu *user, const char *sname)
1578 {
1579         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
1580         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
1581         LDAPMessage *result = NULL;
1582         LDAPMessage *entry = NULL;
1583         int count;
1584         const char ** attr_list;
1585         int rc;
1586
1587         attr_list = get_userattr_list( user, ldap_state->schema_ver );
1588         append_attr(user, &attr_list,
1589                     get_userattr_key2string(ldap_state->schema_ver,
1590                                             LDAP_ATTR_MOD_TIMESTAMP));
1591         ldapsam_add_unix_attributes(user, &attr_list);
1592         rc = ldapsam_search_suffix_by_name(ldap_state, sname, &result,
1593                                            attr_list);
1594         TALLOC_FREE( attr_list );
1595
1596         if ( rc != LDAP_SUCCESS ) 
1597                 return NT_STATUS_NO_SUCH_USER;
1598
1599         count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result);
1600
1601         if (count < 1) {
1602                 DEBUG(4, ("ldapsam_getsampwnam: Unable to locate user [%s] count=%d\n", sname, count));
1603                 ldap_msgfree(result);
1604                 return NT_STATUS_NO_SUCH_USER;
1605         } else if (count > 1) {
1606                 DEBUG(1, ("ldapsam_getsampwnam: Duplicate entries for this user [%s] Failing. count=%d\n", sname, count));
1607                 ldap_msgfree(result);
1608                 return NT_STATUS_NO_SUCH_USER;
1609         }
1610
1611         entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result);
1612         if (entry) {
1613                 if (!init_sam_from_ldap(ldap_state, user, entry)) {
1614                         DEBUG(1,("ldapsam_getsampwnam: init_sam_from_ldap failed for user '%s'!\n", sname));
1615                         ldap_msgfree(result);
1616                         return NT_STATUS_NO_SUCH_USER;
1617                 }
1618                 pdb_set_backend_private_data(user, result, NULL,
1619                                              my_methods, PDB_CHANGED);
1620                 talloc_autofree_ldapmsg(user, result);
1621                 ret = NT_STATUS_OK;
1622         } else {
1623                 ldap_msgfree(result);
1624         }
1625         return ret;
1626 }
1627
1628 static int ldapsam_get_ldap_user_by_sid(struct ldapsam_privates *ldap_state, 
1629                                    const struct dom_sid *sid, LDAPMessage **result)
1630 {
1631         int rc = -1;
1632         const char ** attr_list;
1633         uint32_t rid;
1634
1635         switch ( ldap_state->schema_ver ) {
1636                 case SCHEMAVER_SAMBASAMACCOUNT: {
1637                         TALLOC_CTX *tmp_ctx = talloc_new(NULL);
1638                         if (tmp_ctx == NULL) {
1639                                 return LDAP_NO_MEMORY;
1640                         }
1641
1642                         attr_list = get_userattr_list(tmp_ctx,
1643                                                       ldap_state->schema_ver);
1644                         append_attr(tmp_ctx, &attr_list,
1645                                     get_userattr_key2string(
1646                                             ldap_state->schema_ver,
1647                                             LDAP_ATTR_MOD_TIMESTAMP));
1648                         ldapsam_add_unix_attributes(tmp_ctx, &attr_list);
1649                         rc = ldapsam_search_suffix_by_sid(ldap_state, sid,
1650                                                           result, attr_list);
1651                         TALLOC_FREE(tmp_ctx);
1652
1653                         if ( rc != LDAP_SUCCESS ) 
1654                                 return rc;
1655                         break;
1656                 }
1657
1658                 case SCHEMAVER_SAMBAACCOUNT:
1659                         if (!sid_peek_check_rid(&ldap_state->domain_sid, sid, &rid)) {
1660                                 return rc;
1661                         }
1662
1663                         attr_list = get_userattr_list(NULL,
1664                                                       ldap_state->schema_ver);
1665                         rc = ldapsam_search_suffix_by_rid(ldap_state, rid, result, attr_list );
1666                         TALLOC_FREE( attr_list );
1667
1668                         if ( rc != LDAP_SUCCESS ) 
1669                                 return rc;
1670                         break;
1671         }
1672         return rc;
1673 }
1674
1675 /**********************************************************************
1676  Get struct samu entry from LDAP by SID.
1677 *********************************************************************/
1678
1679 static NTSTATUS ldapsam_getsampwsid(struct pdb_methods *my_methods, struct samu * user, const struct dom_sid *sid)
1680 {
1681         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
1682         LDAPMessage *result = NULL;
1683         LDAPMessage *entry = NULL;
1684         int count;
1685         int rc;
1686
1687         rc = ldapsam_get_ldap_user_by_sid(ldap_state, 
1688                                           sid, &result); 
1689         if (rc != LDAP_SUCCESS)
1690                 return NT_STATUS_NO_SUCH_USER;
1691
1692         count = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result);
1693
1694         if (count < 1) {
1695                 DEBUG(4, ("ldapsam_getsampwsid: Unable to locate SID [%s] "
1696                           "count=%d\n", sid_string_dbg(sid), count));
1697                 ldap_msgfree(result);
1698                 return NT_STATUS_NO_SUCH_USER;
1699         }  else if (count > 1) {
1700                 DEBUG(1, ("ldapsam_getsampwsid: More than one user with SID "
1701                           "[%s]. Failing. count=%d\n", sid_string_dbg(sid),
1702                           count));
1703                 ldap_msgfree(result);
1704                 return NT_STATUS_NO_SUCH_USER;
1705         }
1706
1707         entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result);
1708         if (!entry) {
1709                 ldap_msgfree(result);
1710                 return NT_STATUS_NO_SUCH_USER;
1711         }
1712
1713         if (!init_sam_from_ldap(ldap_state, user, entry)) {
1714                 DEBUG(1,("ldapsam_getsampwsid: init_sam_from_ldap failed!\n"));
1715                 ldap_msgfree(result);
1716                 return NT_STATUS_NO_SUCH_USER;
1717         }
1718
1719         pdb_set_backend_private_data(user, result, NULL,
1720                                      my_methods, PDB_CHANGED);
1721         talloc_autofree_ldapmsg(user, result);
1722         return NT_STATUS_OK;
1723 }       
1724
1725 /********************************************************************
1726  Do the actual modification - also change a plaintext passord if 
1727  it it set.
1728 **********************************************************************/
1729
1730 static NTSTATUS ldapsam_modify_entry(struct pdb_methods *my_methods, 
1731                                      struct samu *newpwd, char *dn,
1732                                      LDAPMod **mods, int ldap_op, 
1733                                      bool (*need_update)(const struct samu *, enum pdb_elements))
1734 {
1735         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
1736         int rc;
1737
1738         if (!newpwd || !dn) {
1739                 return NT_STATUS_INVALID_PARAMETER;
1740         }
1741
1742         if (!(pdb_get_acct_ctrl(newpwd)&(ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST)) &&
1743                         (lp_ldap_passwd_sync() != LDAP_PASSWD_SYNC_OFF) &&
1744                         need_update(newpwd, PDB_PLAINTEXT_PW) &&
1745                         (pdb_get_plaintext_passwd(newpwd)!=NULL)) {
1746                 BerElement *ber;
1747                 struct berval *bv;
1748                 char *retoid = NULL;
1749                 struct berval *retdata = NULL;
1750                 char *utf8_password;
1751                 char *utf8_dn;
1752                 size_t converted_size;
1753                 int ret;
1754
1755                 if (!ldap_state->is_nds_ldap) {
1756
1757                         if (!smbldap_has_extension(ldap_state->smbldap_state->ldap_struct, 
1758                                                    LDAP_EXOP_MODIFY_PASSWD)) {
1759                                 DEBUG(2, ("ldap password change requested, but LDAP "
1760                                           "server does not support it -- ignoring\n"));
1761                                 return NT_STATUS_OK;
1762                         }
1763                 }
1764
1765                 if (!push_utf8_talloc(talloc_tos(), &utf8_password,
1766                                         pdb_get_plaintext_passwd(newpwd),
1767                                         &converted_size))
1768                 {
1769                         return NT_STATUS_NO_MEMORY;
1770                 }
1771
1772                 if (!push_utf8_talloc(talloc_tos(), &utf8_dn, dn, &converted_size)) {
1773                         TALLOC_FREE(utf8_password);
1774                         return NT_STATUS_NO_MEMORY;
1775                 }
1776
1777                 if ((ber = ber_alloc_t(LBER_USE_DER))==NULL) {
1778                         DEBUG(0,("ber_alloc_t returns NULL\n"));
1779                         TALLOC_FREE(utf8_password);
1780                         TALLOC_FREE(utf8_dn);
1781                         return NT_STATUS_UNSUCCESSFUL;
1782                 }
1783
1784                 if ((ber_printf (ber, "{") < 0) ||
1785                     (ber_printf (ber, "ts", LDAP_TAG_EXOP_MODIFY_PASSWD_ID,
1786                                  utf8_dn) < 0)) {
1787                         DEBUG(0,("ldapsam_modify_entry: ber_printf returns a "
1788                                  "value <0\n"));
1789                         ber_free(ber,1);
1790                         TALLOC_FREE(utf8_dn);
1791                         TALLOC_FREE(utf8_password);
1792                         return NT_STATUS_UNSUCCESSFUL;
1793                 }
1794
1795                 if ((utf8_password != NULL) && (*utf8_password != '\0')) {
1796                         ret = ber_printf(ber, "ts}",
1797                                          LDAP_TAG_EXOP_MODIFY_PASSWD_NEW,
1798                                          utf8_password);
1799                 } else {
1800                         ret = ber_printf(ber, "}");
1801                 }
1802
1803                 if (ret < 0) {
1804                         DEBUG(0,("ldapsam_modify_entry: ber_printf returns a "
1805                                  "value <0\n"));
1806                         ber_free(ber,1);
1807                         TALLOC_FREE(utf8_dn);
1808                         TALLOC_FREE(utf8_password);
1809                         return NT_STATUS_UNSUCCESSFUL;
1810                 }
1811
1812                 if ((rc = ber_flatten (ber, &bv))<0) {
1813                         DEBUG(0,("ldapsam_modify_entry: ber_flatten returns a value <0\n"));
1814                         ber_free(ber,1);
1815                         TALLOC_FREE(utf8_dn);
1816                         TALLOC_FREE(utf8_password);
1817                         return NT_STATUS_UNSUCCESSFUL;
1818                 }
1819
1820                 TALLOC_FREE(utf8_dn);
1821                 TALLOC_FREE(utf8_password);
1822                 ber_free(ber, 1);
1823
1824                 if (!ldap_state->is_nds_ldap) {
1825                         rc = smbldap_extended_operation(ldap_state->smbldap_state, 
1826                                                         LDAP_EXOP_MODIFY_PASSWD,
1827                                                         bv, NULL, NULL, &retoid, 
1828                                                         &retdata);
1829                 } else {
1830                         rc = pdb_nds_set_password(ldap_state->smbldap_state, dn,
1831                                                         pdb_get_plaintext_passwd(newpwd));
1832                 }
1833                 if (rc != LDAP_SUCCESS) {
1834                         char *ld_error = NULL;
1835
1836                         if (rc == LDAP_OBJECT_CLASS_VIOLATION) {
1837                                 DEBUG(3, ("Could not set userPassword "
1838                                           "attribute due to an objectClass "
1839                                           "violation -- ignoring\n"));
1840                                 ber_bvfree(bv);
1841                                 return NT_STATUS_OK;
1842                         }
1843
1844                         ldap_get_option(ldap_state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
1845                                         &ld_error);
1846                         DEBUG(0,("ldapsam_modify_entry: LDAP Password could not be changed for user %s: %s\n\t%s\n",
1847                                 pdb_get_username(newpwd), ldap_err2string(rc), ld_error?ld_error:"unknown"));
1848                         SAFE_FREE(ld_error);
1849                         ber_bvfree(bv);
1850 #if defined(LDAP_CONSTRAINT_VIOLATION)
1851                         if (rc == LDAP_CONSTRAINT_VIOLATION)
1852                                 return NT_STATUS_PASSWORD_RESTRICTION;
1853 #endif
1854                         return NT_STATUS_UNSUCCESSFUL;
1855                 } else {
1856                         DEBUG(3,("ldapsam_modify_entry: LDAP Password changed for user %s\n",pdb_get_username(newpwd)));
1857 #ifdef DEBUG_PASSWORD
1858                         DEBUG(100,("ldapsam_modify_entry: LDAP Password changed to %s\n",pdb_get_plaintext_passwd(newpwd)));
1859 #endif    
1860                         if (retdata)
1861                                 ber_bvfree(retdata);
1862                         if (retoid)
1863                                 ldap_memfree(retoid);
1864                 }
1865                 ber_bvfree(bv);
1866         }
1867
1868         if (!mods) {
1869                 DEBUG(5,("ldapsam_modify_entry: mods is empty: nothing to modify\n"));
1870                 /* may be password change below however */
1871         } else {
1872                 switch(ldap_op) {
1873                         case LDAP_MOD_ADD:
1874                                 if (ldap_state->is_nds_ldap) {
1875                                         smbldap_set_mod(&mods, LDAP_MOD_ADD,
1876                                                         "objectclass",
1877                                                         "inetOrgPerson");
1878                                 } else {
1879                                         smbldap_set_mod(&mods, LDAP_MOD_ADD,
1880                                                         "objectclass",
1881                                                         LDAP_OBJ_ACCOUNT);
1882                                 }
1883                                 rc = smbldap_add(ldap_state->smbldap_state,
1884                                                  dn, mods);
1885                                 break;
1886                         case LDAP_MOD_REPLACE:
1887                                 rc = smbldap_modify(ldap_state->smbldap_state,
1888                                                     dn ,mods);
1889                                 break;
1890                         default:
1891                                 DEBUG(0,("ldapsam_modify_entry: Wrong LDAP operation type: %d!\n",
1892                                          ldap_op));
1893                                 return NT_STATUS_INVALID_PARAMETER;
1894                 }
1895
1896                 if (rc!=LDAP_SUCCESS) {
1897                         return NT_STATUS_UNSUCCESSFUL;
1898                 }
1899         }
1900
1901         return NT_STATUS_OK;
1902 }
1903
1904 /**********************************************************************
1905  Delete entry from LDAP for username.
1906 *********************************************************************/
1907
1908 static NTSTATUS ldapsam_delete_sam_account(struct pdb_methods *my_methods,
1909                                            struct samu * sam_acct)
1910 {
1911         struct ldapsam_privates *priv =
1912                 (struct ldapsam_privates *)my_methods->private_data;
1913         const char *sname;
1914         int rc;
1915         LDAPMessage *msg, *entry;
1916         NTSTATUS result = NT_STATUS_NO_MEMORY;
1917         const char **attr_list;
1918         TALLOC_CTX *mem_ctx;
1919
1920         if (!sam_acct) {
1921                 DEBUG(0, ("ldapsam_delete_sam_account: sam_acct was NULL!\n"));
1922                 return NT_STATUS_INVALID_PARAMETER;
1923         }
1924
1925         sname = pdb_get_username(sam_acct);
1926
1927         DEBUG(3, ("ldapsam_delete_sam_account: Deleting user %s from "
1928                   "LDAP.\n", sname));
1929
1930         mem_ctx = talloc_new(NULL);
1931         if (mem_ctx == NULL) {
1932                 DEBUG(0, ("talloc_new failed\n"));
1933                 goto done;
1934         }
1935
1936         attr_list = get_userattr_delete_list(mem_ctx, priv->schema_ver );
1937         if (attr_list == NULL) {
1938                 goto done;
1939         }
1940
1941         rc = ldapsam_search_suffix_by_name(priv, sname, &msg, attr_list);
1942
1943         if ((rc != LDAP_SUCCESS) ||
1944             (ldap_count_entries(priv2ld(priv), msg) != 1) ||
1945             ((entry = ldap_first_entry(priv2ld(priv), msg)) == NULL)) {
1946                 DEBUG(5, ("Could not find user %s\n", sname));
1947                 result = NT_STATUS_NO_SUCH_USER;
1948                 goto done;
1949         }
1950
1951         rc = ldapsam_delete_entry(
1952                 priv, mem_ctx, entry,
1953                 priv->schema_ver == SCHEMAVER_SAMBASAMACCOUNT ?
1954                 LDAP_OBJ_SAMBASAMACCOUNT : LDAP_OBJ_SAMBAACCOUNT,
1955                 attr_list);
1956
1957         result = (rc == LDAP_SUCCESS) ?
1958                 NT_STATUS_OK : NT_STATUS_ACCESS_DENIED;
1959
1960  done:
1961         TALLOC_FREE(mem_ctx);
1962         return result;
1963 }
1964
1965 /**********************************************************************
1966  Helper function to determine for update_sam_account whether
1967  we need LDAP modification.
1968 *********************************************************************/
1969
1970 static bool element_is_changed(const struct samu *sampass,
1971                                enum pdb_elements element)
1972 {
1973         return IS_SAM_CHANGED(sampass, element);
1974 }
1975
1976 /**********************************************************************
1977  Update struct samu.
1978 *********************************************************************/
1979
1980 static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, struct samu * newpwd)
1981 {
1982         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
1983         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
1984         int rc = 0;
1985         char *dn;
1986         LDAPMessage *result = NULL;
1987         LDAPMessage *entry = NULL;
1988         LDAPMod **mods = NULL;
1989         const char **attr_list;
1990
1991         result = (LDAPMessage *)pdb_get_backend_private_data(newpwd, my_methods);
1992         if (!result) {
1993                 attr_list = get_userattr_list(NULL, ldap_state->schema_ver);
1994                 if (pdb_get_username(newpwd) == NULL) {
1995                         return NT_STATUS_INVALID_PARAMETER;
1996                 }
1997                 rc = ldapsam_search_suffix_by_name(ldap_state, pdb_get_username(newpwd), &result, attr_list );
1998                 TALLOC_FREE( attr_list );
1999                 if (rc != LDAP_SUCCESS) {
2000                         return NT_STATUS_UNSUCCESSFUL;
2001                 }
2002                 pdb_set_backend_private_data(newpwd, result, NULL,
2003                                              my_methods, PDB_CHANGED);
2004                 talloc_autofree_ldapmsg(newpwd, result);
2005         }
2006
2007         if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) == 0) {
2008                 DEBUG(0, ("ldapsam_update_sam_account: No user to modify!\n"));
2009                 return NT_STATUS_UNSUCCESSFUL;
2010         }
2011
2012         entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result);
2013         dn = smbldap_talloc_dn(talloc_tos(), ldap_state->smbldap_state->ldap_struct, entry);
2014         if (!dn) {
2015                 return NT_STATUS_UNSUCCESSFUL;
2016         }
2017
2018         DEBUG(4, ("ldapsam_update_sam_account: user %s to be modified has dn: %s\n", pdb_get_username(newpwd), dn));
2019
2020         if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd,
2021                                 element_is_changed)) {
2022                 DEBUG(0, ("ldapsam_update_sam_account: init_ldap_from_sam failed!\n"));
2023                 TALLOC_FREE(dn);
2024                 if (mods != NULL)
2025                         ldap_mods_free(mods,True);
2026                 return NT_STATUS_UNSUCCESSFUL;
2027         }
2028
2029         if ((lp_ldap_passwd_sync() != LDAP_PASSWD_SYNC_ONLY)
2030             && (mods == NULL)) {
2031                 DEBUG(4,("ldapsam_update_sam_account: mods is empty: nothing to update for user: %s\n",
2032                          pdb_get_username(newpwd)));
2033                 TALLOC_FREE(dn);
2034                 return NT_STATUS_OK;
2035         }
2036
2037         ret = ldapsam_modify_entry(my_methods,newpwd,dn,mods,LDAP_MOD_REPLACE, element_is_changed);
2038
2039         if (mods != NULL) {
2040                 ldap_mods_free(mods,True);
2041         }
2042
2043         TALLOC_FREE(dn);
2044
2045         /*
2046          * We need to set the backend private data to NULL here. For example
2047          * setuserinfo level 25 does a pdb_update_sam_account twice on the
2048          * same one, and with the explicit delete / add logic for attribute
2049          * values the second time we would use the wrong "old" value which
2050          * does not exist in LDAP anymore. Thus the LDAP server would refuse
2051          * the update.
2052          * The existing LDAPMessage is still being auto-freed by the
2053          * destructor.
2054          */
2055         pdb_set_backend_private_data(newpwd, NULL, NULL, my_methods,
2056                                      PDB_CHANGED);
2057
2058         if (!NT_STATUS_IS_OK(ret)) {
2059                 return ret;
2060         }
2061
2062         DEBUG(2, ("ldapsam_update_sam_account: successfully modified uid = %s in the LDAP database\n",
2063                   pdb_get_username(newpwd)));
2064         return NT_STATUS_OK;
2065 }
2066
2067 /***************************************************************************
2068  Renames a struct samu
2069  - The "rename user script" has full responsibility for changing everything
2070 ***************************************************************************/
2071
2072 static NTSTATUS ldapsam_del_groupmem(struct pdb_methods *my_methods,
2073                                      TALLOC_CTX *tmp_ctx,
2074                                      uint32_t group_rid,
2075                                      uint32_t member_rid);
2076
2077 static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods,
2078                                                TALLOC_CTX *mem_ctx,
2079                                                struct samu *user,
2080                                                struct dom_sid **pp_sids,
2081                                                gid_t **pp_gids,
2082                                                size_t *p_num_groups);
2083
2084 static NTSTATUS ldapsam_rename_sam_account(struct pdb_methods *my_methods,
2085                                            struct samu *old_acct,
2086                                            const char *newname)
2087 {
2088         const char *oldname;
2089         int rc;
2090         char *rename_script = NULL;
2091         fstring oldname_lower, newname_lower;
2092
2093         if (!old_acct) {
2094                 DEBUG(0, ("ldapsam_rename_sam_account: old_acct was NULL!\n"));
2095                 return NT_STATUS_INVALID_PARAMETER;
2096         }
2097         if (!newname) {
2098                 DEBUG(0, ("ldapsam_rename_sam_account: newname was NULL!\n"));
2099                 return NT_STATUS_INVALID_PARAMETER;
2100         }
2101
2102         oldname = pdb_get_username(old_acct);
2103
2104         /* rename the posix user */
2105         rename_script = SMB_STRDUP(lp_renameuser_script());
2106         if (rename_script == NULL) {
2107                 return NT_STATUS_NO_MEMORY;
2108         }
2109
2110         if (!(*rename_script)) {
2111                 SAFE_FREE(rename_script);
2112                 return NT_STATUS_ACCESS_DENIED;
2113         }
2114
2115         DEBUG (3, ("ldapsam_rename_sam_account: Renaming user %s to %s.\n",
2116                    oldname, newname));
2117
2118         /* We have to allow the account name to end with a '$'.
2119            Also, follow the semantics in _samr_create_user() and lower case the
2120            posix name but preserve the case in passdb */
2121
2122         fstrcpy( oldname_lower, oldname );
2123         strlower_m( oldname_lower );
2124         fstrcpy( newname_lower, newname );
2125         strlower_m( newname_lower );
2126         rename_script = realloc_string_sub2(rename_script,
2127                                         "%unew",
2128                                         newname_lower,
2129                                         true,
2130                                         true);
2131         if (!rename_script) {
2132                 return NT_STATUS_NO_MEMORY;
2133         }
2134         rename_script = realloc_string_sub2(rename_script,
2135                                         "%uold",
2136                                         oldname_lower,
2137                                         true,
2138                                         true);
2139         rc = smbrun(rename_script, NULL);
2140
2141         DEBUG(rc ? 0 : 3,("Running the command `%s' gave %d\n",
2142                           rename_script, rc));
2143
2144         SAFE_FREE(rename_script);
2145
2146         if (rc == 0) {
2147                 smb_nscd_flush_user_cache();
2148         }
2149
2150         if (rc)
2151                 return NT_STATUS_UNSUCCESSFUL;
2152
2153         return NT_STATUS_OK;
2154 }
2155
2156 /**********************************************************************
2157  Helper function to determine for update_sam_account whether
2158  we need LDAP modification.
2159  *********************************************************************/
2160
2161 static bool element_is_set_or_changed(const struct samu *sampass,
2162                                       enum pdb_elements element)
2163 {
2164         return (IS_SAM_SET(sampass, element) ||
2165                 IS_SAM_CHANGED(sampass, element));
2166 }
2167
2168 /**********************************************************************
2169  Add struct samu to LDAP.
2170 *********************************************************************/
2171
2172 static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, struct samu * newpwd)
2173 {
2174         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
2175         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2176         int rc;
2177         LDAPMessage     *result = NULL;
2178         LDAPMessage     *entry  = NULL;
2179         LDAPMod         **mods = NULL;
2180         int             ldap_op = LDAP_MOD_REPLACE;
2181         uint32_t                num_result;
2182         const char      **attr_list;
2183         char *escape_user = NULL;
2184         const char      *username = pdb_get_username(newpwd);
2185         const struct dom_sid    *sid = pdb_get_user_sid(newpwd);
2186         char *filter = NULL;
2187         char *dn = NULL;
2188         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
2189         TALLOC_CTX *ctx = talloc_init("ldapsam_add_sam_account");
2190
2191         if (!ctx) {
2192                 return NT_STATUS_NO_MEMORY;
2193         }
2194
2195         if (!username || !*username) {
2196                 DEBUG(0, ("ldapsam_add_sam_account: Cannot add user without a username!\n"));
2197                 status = NT_STATUS_INVALID_PARAMETER;
2198                 goto fn_exit;
2199         }
2200
2201         /* free this list after the second search or in case we exit on failure */
2202         attr_list = get_userattr_list(ctx, ldap_state->schema_ver);
2203
2204         rc = ldapsam_search_suffix_by_name (ldap_state, username, &result, attr_list);
2205
2206         if (rc != LDAP_SUCCESS) {
2207                 goto fn_exit;
2208         }
2209
2210         if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) != 0) {
2211                 DEBUG(0,("ldapsam_add_sam_account: User '%s' already in the base, with samba attributes\n", 
2212                          username));
2213                 goto fn_exit;
2214         }
2215         ldap_msgfree(result);
2216         result = NULL;
2217
2218         if (element_is_set_or_changed(newpwd, PDB_USERSID)) {
2219                 rc = ldapsam_get_ldap_user_by_sid(ldap_state,
2220                                                   sid, &result);
2221                 if (rc == LDAP_SUCCESS) {
2222                         if (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result) != 0) {
2223                                 DEBUG(0,("ldapsam_add_sam_account: SID '%s' "
2224                                          "already in the base, with samba "
2225                                          "attributes\n", sid_string_dbg(sid)));
2226                                 goto fn_exit;
2227                         }
2228                         ldap_msgfree(result);
2229                         result = NULL;
2230                 }
2231         }
2232
2233         /* does the entry already exist but without a samba attributes?
2234            we need to return the samba attributes here */
2235
2236         escape_user = escape_ldap_string(talloc_tos(), username);
2237         filter = talloc_strdup(attr_list, "(uid=%u)");
2238         if (!filter) {
2239                 status = NT_STATUS_NO_MEMORY;
2240                 goto fn_exit;
2241         }
2242         filter = talloc_all_string_sub(attr_list, filter, "%u", escape_user);
2243         TALLOC_FREE(escape_user);
2244         if (!filter) {
2245                 status = NT_STATUS_NO_MEMORY;
2246                 goto fn_exit;
2247         }
2248
2249         rc = smbldap_search_suffix(ldap_state->smbldap_state,
2250                                    filter, attr_list, &result);
2251         if ( rc != LDAP_SUCCESS ) {
2252                 goto fn_exit;
2253         }
2254
2255         num_result = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result);
2256
2257         if (num_result > 1) {
2258                 DEBUG (0, ("ldapsam_add_sam_account: More than one user with that uid exists: bailing out!\n"));
2259                 goto fn_exit;
2260         }
2261
2262         /* Check if we need to update an existing entry */
2263         if (num_result == 1) {
2264                 DEBUG(3,("ldapsam_add_sam_account: User exists without samba attributes: adding them\n"));
2265                 ldap_op = LDAP_MOD_REPLACE;
2266                 entry = ldap_first_entry (ldap_state->smbldap_state->ldap_struct, result);
2267                 dn = smbldap_talloc_dn(ctx, ldap_state->smbldap_state->ldap_struct, entry);
2268                 if (!dn) {
2269                         status = NT_STATUS_NO_MEMORY;
2270                         goto fn_exit;
2271                 }
2272
2273         } else if (ldap_state->schema_ver == SCHEMAVER_SAMBASAMACCOUNT) {
2274
2275                 /* There might be a SID for this account already - say an idmap entry */
2276
2277                 filter = talloc_asprintf(ctx,
2278                                 "(&(%s=%s)(|(objectClass=%s)(objectClass=%s)))",
2279                                  get_userattr_key2string(ldap_state->schema_ver,
2280                                          LDAP_ATTR_USER_SID),
2281                                  sid_string_talloc(ctx, sid),
2282                                  LDAP_OBJ_IDMAP_ENTRY,
2283                                  LDAP_OBJ_SID_ENTRY);
2284                 if (!filter) {
2285                         status = NT_STATUS_NO_MEMORY;
2286                         goto fn_exit;
2287                 }
2288
2289                 /* free old result before doing a new search */
2290                 if (result != NULL) {
2291                         ldap_msgfree(result);
2292                         result = NULL;
2293                 }
2294                 rc = smbldap_search_suffix(ldap_state->smbldap_state,
2295                                            filter, attr_list, &result);
2296
2297                 if ( rc != LDAP_SUCCESS ) {
2298                         goto fn_exit;
2299                 }
2300
2301                 num_result = ldap_count_entries(ldap_state->smbldap_state->ldap_struct, result);
2302
2303                 if (num_result > 1) {
2304                         DEBUG (0, ("ldapsam_add_sam_account: More than one user with specified Sid exists: bailing out!\n"));
2305                         goto fn_exit;
2306                 }
2307
2308                 /* Check if we need to update an existing entry */
2309                 if (num_result == 1) {
2310
2311                         DEBUG(3,("ldapsam_add_sam_account: User exists without samba attributes: adding them\n"));
2312                         ldap_op = LDAP_MOD_REPLACE;
2313                         entry = ldap_first_entry (ldap_state->smbldap_state->ldap_struct, result);
2314                         dn = smbldap_talloc_dn (ctx, ldap_state->smbldap_state->ldap_struct, entry);
2315                         if (!dn) {
2316                                 status = NT_STATUS_NO_MEMORY;
2317                                 goto fn_exit;
2318                         }
2319                 }
2320         }
2321
2322         if (num_result == 0) {
2323                 char *escape_username;
2324                 /* Check if we need to add an entry */
2325                 DEBUG(3,("ldapsam_add_sam_account: Adding new user\n"));
2326                 ldap_op = LDAP_MOD_ADD;
2327
2328                 escape_username = escape_rdn_val_string_alloc(username);
2329                 if (!escape_username) {
2330                         status = NT_STATUS_NO_MEMORY;
2331                         goto fn_exit;
2332                 }
2333
2334                 if (username[strlen(username)-1] == '$') {
2335                         dn = talloc_asprintf(ctx,
2336                                         "uid=%s,%s",
2337                                         escape_username,
2338                                         lp_ldap_machine_suffix());
2339                 } else {
2340                         dn = talloc_asprintf(ctx,
2341                                         "uid=%s,%s",
2342                                         escape_username,
2343                                         lp_ldap_user_suffix());
2344                 }
2345
2346                 SAFE_FREE(escape_username);
2347                 if (!dn) {
2348                         status = NT_STATUS_NO_MEMORY;
2349                         goto fn_exit;
2350                 }
2351         }
2352
2353         if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd,
2354                                 element_is_set_or_changed)) {
2355                 DEBUG(0, ("ldapsam_add_sam_account: init_ldap_from_sam failed!\n"));
2356                 if (mods != NULL) {
2357                         ldap_mods_free(mods, true);
2358                 }
2359                 goto fn_exit;
2360         }
2361
2362         if (mods == NULL) {
2363                 DEBUG(0,("ldapsam_add_sam_account: mods is empty: nothing to add for user: %s\n",pdb_get_username(newpwd)));
2364                 goto fn_exit;
2365         }
2366         switch ( ldap_state->schema_ver ) {
2367                 case SCHEMAVER_SAMBAACCOUNT:
2368                         smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_SAMBAACCOUNT);
2369                         break;
2370                 case SCHEMAVER_SAMBASAMACCOUNT:
2371                         smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_SAMBASAMACCOUNT);
2372                         break;
2373                 default:
2374                         DEBUG(0,("ldapsam_add_sam_account: invalid schema version specified\n"));
2375                         break;
2376         }
2377
2378         ret = ldapsam_modify_entry(my_methods,newpwd,dn,mods,ldap_op, element_is_set_or_changed);
2379         if (!NT_STATUS_IS_OK(ret)) {
2380                 DEBUG(0,("ldapsam_add_sam_account: failed to modify/add user with uid = %s (dn = %s)\n",
2381                          pdb_get_username(newpwd),dn));
2382                 ldap_mods_free(mods, true);
2383                 goto fn_exit;
2384         }
2385
2386         DEBUG(2,("ldapsam_add_sam_account: added: uid == %s in the LDAP database\n", pdb_get_username(newpwd)));
2387         ldap_mods_free(mods, true);
2388
2389         status = NT_STATUS_OK;
2390
2391   fn_exit:
2392
2393         TALLOC_FREE(ctx);
2394         if (result) {
2395                 ldap_msgfree(result);
2396         }
2397         return status;
2398 }
2399
2400 /**********************************************************************
2401  *********************************************************************/
2402
2403 static int ldapsam_search_one_group (struct ldapsam_privates *ldap_state,
2404                                      const char *filter,
2405                                      LDAPMessage ** result)
2406 {
2407         int scope = LDAP_SCOPE_SUBTREE;
2408         int rc;
2409         const char **attr_list;
2410
2411         attr_list = get_attr_list(NULL, groupmap_attr_list);
2412         rc = smbldap_search(ldap_state->smbldap_state,
2413                             lp_ldap_suffix (), scope,
2414                             filter, attr_list, 0, result);
2415         TALLOC_FREE(attr_list);
2416
2417         return rc;
2418 }
2419
2420 /**********************************************************************
2421  *********************************************************************/
2422
2423 static bool init_group_from_ldap(struct ldapsam_privates *ldap_state,
2424                                  GROUP_MAP *map, LDAPMessage *entry)
2425 {
2426         char *temp = NULL;
2427         TALLOC_CTX *ctx = talloc_init("init_group_from_ldap");
2428
2429         if (ldap_state == NULL || map == NULL || entry == NULL ||
2430                         ldap_state->smbldap_state->ldap_struct == NULL) {
2431                 DEBUG(0, ("init_group_from_ldap: NULL parameters found!\n"));
2432                 TALLOC_FREE(ctx);
2433                 return false;
2434         }
2435
2436         temp = smbldap_talloc_single_attribute(
2437                         ldap_state->smbldap_state->ldap_struct,
2438                         entry,
2439                         get_attr_key2string(groupmap_attr_list,
2440                                 LDAP_ATTR_GIDNUMBER),
2441                         ctx);
2442         if (!temp) {
2443                 DEBUG(0, ("init_group_from_ldap: Mandatory attribute %s not found\n", 
2444                         get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GIDNUMBER)));
2445                 TALLOC_FREE(ctx);
2446                 return false;
2447         }
2448         DEBUG(2, ("init_group_from_ldap: Entry found for group: %s\n", temp));
2449
2450         map->gid = (gid_t)atol(temp);
2451
2452         TALLOC_FREE(temp);
2453         temp = smbldap_talloc_single_attribute(
2454                         ldap_state->smbldap_state->ldap_struct,
2455                         entry,
2456                         get_attr_key2string(groupmap_attr_list,
2457                                 LDAP_ATTR_GROUP_SID),
2458                         ctx);
2459         if (!temp) {
2460                 DEBUG(0, ("init_group_from_ldap: Mandatory attribute %s not found\n",
2461                         get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GROUP_SID)));
2462                 TALLOC_FREE(ctx);
2463                 return false;
2464         }
2465
2466         if (!string_to_sid(&map->sid, temp)) {
2467                 DEBUG(1, ("SID string [%s] could not be read as a valid SID\n", temp));
2468                 TALLOC_FREE(ctx);
2469                 return false;
2470         }
2471
2472         TALLOC_FREE(temp);
2473         temp = smbldap_talloc_single_attribute(
2474                         ldap_state->smbldap_state->ldap_struct,
2475                         entry,
2476                         get_attr_key2string(groupmap_attr_list,
2477                                 LDAP_ATTR_GROUP_TYPE),
2478                         ctx);
2479         if (!temp) {
2480                 DEBUG(0, ("init_group_from_ldap: Mandatory attribute %s not found\n",
2481                         get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GROUP_TYPE)));
2482                 TALLOC_FREE(ctx);
2483                 return false;
2484         }
2485         map->sid_name_use = (enum lsa_SidType)atol(temp);
2486
2487         if ((map->sid_name_use < SID_NAME_USER) ||
2488                         (map->sid_name_use > SID_NAME_UNKNOWN)) {
2489                 DEBUG(0, ("init_group_from_ldap: Unknown Group type: %d\n", map->sid_name_use));
2490                 TALLOC_FREE(ctx);
2491                 return false;
2492         }
2493
2494         TALLOC_FREE(temp);
2495         temp = smbldap_talloc_single_attribute(
2496                         ldap_state->smbldap_state->ldap_struct,
2497                         entry,
2498                         get_attr_key2string(groupmap_attr_list,
2499                                 LDAP_ATTR_DISPLAY_NAME),
2500                         ctx);
2501         if (!temp) {
2502                 temp = smbldap_talloc_single_attribute(
2503                                 ldap_state->smbldap_state->ldap_struct,
2504                                 entry,
2505                                 get_attr_key2string(groupmap_attr_list,
2506                                         LDAP_ATTR_CN),
2507                                 ctx);
2508                 if (!temp) {
2509                         DEBUG(0, ("init_group_from_ldap: Attributes cn not found either \
2510 for gidNumber(%lu)\n",(unsigned long)map->gid));
2511                         TALLOC_FREE(ctx);
2512                         return false;
2513                 }
2514         }
2515         fstrcpy(map->nt_name, temp);
2516
2517         TALLOC_FREE(temp);
2518         temp = smbldap_talloc_single_attribute(
2519                         ldap_state->smbldap_state->ldap_struct,
2520                         entry,
2521                         get_attr_key2string(groupmap_attr_list,
2522                                 LDAP_ATTR_DESC),
2523                         ctx);
2524         if (!temp) {
2525                 temp = talloc_strdup(ctx, "");
2526                 if (!temp) {
2527                         TALLOC_FREE(ctx);
2528                         return false;
2529                 }
2530         }
2531         fstrcpy(map->comment, temp);
2532
2533         if (lp_parm_bool(-1, "ldapsam", "trusted", false)) {
2534                 store_gid_sid_cache(&map->sid, map->gid);
2535                 idmap_cache_set_sid2gid(&map->sid, map->gid);
2536         }
2537
2538         TALLOC_FREE(ctx);
2539         return true;
2540 }
2541
2542 /**********************************************************************
2543  *********************************************************************/
2544
2545 static NTSTATUS ldapsam_getgroup(struct pdb_methods *methods,
2546                                  const char *filter,
2547                                  GROUP_MAP *map)
2548 {
2549         struct ldapsam_privates *ldap_state =
2550                 (struct ldapsam_privates *)methods->private_data;
2551         LDAPMessage *result = NULL;
2552         LDAPMessage *entry = NULL;
2553         int count;
2554
2555         if (ldapsam_search_one_group(ldap_state, filter, &result)
2556             != LDAP_SUCCESS) {
2557                 return NT_STATUS_NO_SUCH_GROUP;
2558         }
2559
2560         count = ldap_count_entries(priv2ld(ldap_state), result);
2561
2562         if (count < 1) {
2563                 DEBUG(4, ("ldapsam_getgroup: Did not find group, filter was "
2564                           "%s\n", filter));
2565                 ldap_msgfree(result);
2566                 return NT_STATUS_NO_SUCH_GROUP;
2567         }
2568
2569         if (count > 1) {
2570                 DEBUG(1, ("ldapsam_getgroup: Duplicate entries for filter %s: "
2571                           "count=%d\n", filter, count));
2572                 ldap_msgfree(result);
2573                 return NT_STATUS_NO_SUCH_GROUP;
2574         }
2575
2576         entry = ldap_first_entry(priv2ld(ldap_state), result);
2577
2578         if (!entry) {
2579                 ldap_msgfree(result);
2580                 return NT_STATUS_UNSUCCESSFUL;
2581         }
2582
2583         if (!init_group_from_ldap(ldap_state, map, entry)) {
2584                 DEBUG(1, ("ldapsam_getgroup: init_group_from_ldap failed for "
2585                           "group filter %s\n", filter));
2586                 ldap_msgfree(result);
2587                 return NT_STATUS_NO_SUCH_GROUP;
2588         }
2589
2590         ldap_msgfree(result);
2591         return NT_STATUS_OK;
2592 }
2593
2594 /**********************************************************************
2595  *********************************************************************/
2596
2597 static NTSTATUS ldapsam_getgrsid(struct pdb_methods *methods, GROUP_MAP *map,
2598                                  struct dom_sid sid)
2599 {
2600         char *filter = NULL;
2601         NTSTATUS status;
2602         fstring tmp;
2603
2604         if (asprintf(&filter, "(&(objectClass=%s)(%s=%s))",
2605                 LDAP_OBJ_GROUPMAP,
2606                 get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GROUP_SID),
2607                 sid_to_fstring(tmp, &sid)) < 0) {
2608                 return NT_STATUS_NO_MEMORY;
2609         }
2610
2611         status = ldapsam_getgroup(methods, filter, map);
2612         SAFE_FREE(filter);
2613         return status;
2614 }
2615
2616 /**********************************************************************
2617  *********************************************************************/
2618
2619 static NTSTATUS ldapsam_getgrgid(struct pdb_methods *methods, GROUP_MAP *map,
2620                                  gid_t gid)
2621 {
2622         char *filter = NULL;
2623         NTSTATUS status;
2624
2625         if (asprintf(&filter, "(&(objectClass=%s)(%s=%lu))",
2626                 LDAP_OBJ_GROUPMAP,
2627                 get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GIDNUMBER),
2628                 (unsigned long)gid) < 0) {
2629                 return NT_STATUS_NO_MEMORY;
2630         }
2631
2632         status = ldapsam_getgroup(methods, filter, map);
2633         SAFE_FREE(filter);
2634         return status;
2635 }
2636
2637 /**********************************************************************
2638  *********************************************************************/
2639
2640 static NTSTATUS ldapsam_getgrnam(struct pdb_methods *methods, GROUP_MAP *map,
2641                                  const char *name)
2642 {
2643         char *filter = NULL;
2644         char *escape_name = escape_ldap_string(talloc_tos(), name);
2645         NTSTATUS status;
2646
2647         if (!escape_name) {
2648                 return NT_STATUS_NO_MEMORY;
2649         }
2650
2651         if (asprintf(&filter, "(&(objectClass=%s)(|(%s=%s)(%s=%s)))",
2652                 LDAP_OBJ_GROUPMAP,
2653                 get_attr_key2string(groupmap_attr_list, LDAP_ATTR_DISPLAY_NAME), escape_name,
2654                 get_attr_key2string(groupmap_attr_list, LDAP_ATTR_CN),
2655                 escape_name) < 0) {
2656                 TALLOC_FREE(escape_name);
2657                 return NT_STATUS_NO_MEMORY;
2658         }
2659
2660         TALLOC_FREE(escape_name);
2661         status = ldapsam_getgroup(methods, filter, map);
2662         SAFE_FREE(filter);
2663         return status;
2664 }
2665
2666 static bool ldapsam_extract_rid_from_entry(LDAP *ldap_struct,
2667                                            LDAPMessage *entry,
2668                                            const struct dom_sid *domain_sid,
2669                                            uint32_t *rid)
2670 {
2671         fstring str;
2672         struct dom_sid sid;
2673
2674         if (!smbldap_get_single_attribute(ldap_struct, entry, "sambaSID",
2675                                           str, sizeof(str)-1)) {
2676                 DEBUG(10, ("Could not find sambaSID attribute\n"));
2677                 return False;
2678         }
2679
2680         if (!string_to_sid(&sid, str)) {
2681                 DEBUG(10, ("Could not convert string %s to sid\n", str));
2682                 return False;
2683         }
2684
2685         if (sid_compare_domain(&sid, domain_sid) != 0) {
2686                 DEBUG(10, ("SID %s is not in expected domain %s\n",
2687                            str, sid_string_dbg(domain_sid)));
2688                 return False;
2689         }
2690
2691         if (!sid_peek_rid(&sid, rid)) {
2692                 DEBUG(10, ("Could not peek into RID\n"));
2693                 return False;
2694         }
2695
2696         return True;
2697 }
2698
2699 static NTSTATUS ldapsam_enum_group_members(struct pdb_methods *methods,
2700                                            TALLOC_CTX *mem_ctx,
2701                                            const struct dom_sid *group,
2702                                            uint32_t **pp_member_rids,
2703                                            size_t *p_num_members)
2704 {
2705         struct ldapsam_privates *ldap_state =
2706                 (struct ldapsam_privates *)methods->private_data;
2707         struct smbldap_state *conn = ldap_state->smbldap_state;
2708         const char *id_attrs[] = { "memberUid", "gidNumber", NULL };
2709         const char *sid_attrs[] = { "sambaSID", NULL };
2710         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
2711         LDAPMessage *result = NULL;
2712         LDAPMessage *entry;
2713         char *filter;
2714         char **values = NULL;
2715         char **memberuid;
2716         char *gidstr;
2717         int rc, count;
2718
2719         *pp_member_rids = NULL;
2720         *p_num_members = 0;
2721
2722         filter = talloc_asprintf(mem_ctx,
2723                                  "(&(objectClass=%s)"
2724                                  "(objectClass=%s)"
2725                                  "(sambaSID=%s))",
2726                                  LDAP_OBJ_POSIXGROUP,
2727                                  LDAP_OBJ_GROUPMAP,
2728                                  sid_string_talloc(mem_ctx, group));
2729         if (filter == NULL) {
2730                 ret = NT_STATUS_NO_MEMORY;
2731                 goto done;
2732         }
2733
2734         rc = smbldap_search(conn, lp_ldap_suffix(),
2735                             LDAP_SCOPE_SUBTREE, filter, id_attrs, 0,
2736                             &result);
2737
2738         if (rc != LDAP_SUCCESS)
2739                 goto done;
2740
2741         talloc_autofree_ldapmsg(mem_ctx, result);
2742
2743         count = ldap_count_entries(conn->ldap_struct, result);
2744
2745         if (count > 1) {
2746                 DEBUG(1, ("Found more than one groupmap entry for %s\n",
2747                           sid_string_dbg(group)));
2748                 ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
2749                 goto done;
2750         }
2751
2752         if (count == 0) {
2753                 ret = NT_STATUS_NO_SUCH_GROUP;
2754                 goto done;
2755         }
2756
2757         entry = ldap_first_entry(conn->ldap_struct, result);
2758         if (entry == NULL)
2759                 goto done;
2760
2761         gidstr = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "gidNumber", mem_ctx);
2762         if (!gidstr) {
2763                 DEBUG (0, ("ldapsam_enum_group_members: Unable to find the group's gid!\n"));
2764                 ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
2765                 goto done;
2766         }
2767
2768         values = ldap_get_values(conn->ldap_struct, entry, "memberUid");
2769
2770         if ((values != NULL) && (values[0] != NULL)) {
2771
2772                 filter = talloc_asprintf(mem_ctx, "(&(objectClass=%s)(|", LDAP_OBJ_SAMBASAMACCOUNT);
2773                 if (filter == NULL) {
2774                         ret = NT_STATUS_NO_MEMORY;
2775                         goto done;
2776                 }
2777
2778                 for (memberuid = values; *memberuid != NULL; memberuid += 1) {
2779                         char *escape_memberuid;
2780
2781                         escape_memberuid = escape_ldap_string(talloc_tos(),
2782                                                               *memberuid);
2783                         if (escape_memberuid == NULL) {
2784                                 ret = NT_STATUS_NO_MEMORY;
2785                                 goto done;
2786                         }
2787
2788                         filter = talloc_asprintf_append_buffer(filter, "(uid=%s)", escape_memberuid);
2789                         TALLOC_FREE(escape_memberuid);
2790                         if (filter == NULL) {
2791                                 ret = NT_STATUS_NO_MEMORY;
2792                                 goto done;
2793                         }
2794                 }
2795
2796                 filter = talloc_asprintf_append_buffer(filter, "))");
2797                 if (filter == NULL) {
2798                         ret = NT_STATUS_NO_MEMORY;
2799                         goto done;
2800                 }
2801
2802                 rc = smbldap_search(conn, lp_ldap_suffix(),
2803                                     LDAP_SCOPE_SUBTREE, filter, sid_attrs, 0,
2804                                     &result);
2805
2806                 if (rc != LDAP_SUCCESS)
2807                         goto done;
2808
2809                 count = ldap_count_entries(conn->ldap_struct, result);
2810                 DEBUG(10,("ldapsam_enum_group_members: found %d accounts\n", count));
2811
2812                 talloc_autofree_ldapmsg(mem_ctx, result);
2813
2814                 for (entry = ldap_first_entry(conn->ldap_struct, result);
2815                      entry != NULL;
2816                      entry = ldap_next_entry(conn->ldap_struct, entry))
2817                 {
2818                         char *sidstr;
2819                         struct dom_sid sid;
2820                         uint32_t rid;
2821
2822                         sidstr = smbldap_talloc_single_attribute(conn->ldap_struct,
2823                                                                  entry, "sambaSID",
2824                                                                  mem_ctx);
2825                         if (!sidstr) {
2826                                 DEBUG(0, ("Severe DB error, %s can't miss the sambaSID"
2827                                           "attribute\n", LDAP_OBJ_SAMBASAMACCOUNT));
2828                                 ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
2829                                 goto done;
2830                         }
2831
2832                         if (!string_to_sid(&sid, sidstr))
2833                                 goto done;
2834
2835                         if (!sid_check_is_in_our_domain(&sid)) {
2836                                 DEBUG(0, ("Inconsistent SAM -- group member uid not "
2837                                           "in our domain\n"));
2838                                 ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
2839                                 goto done;
2840                         }
2841
2842                         sid_peek_rid(&sid, &rid);
2843
2844                         if (!add_rid_to_array_unique(mem_ctx, rid, pp_member_rids,
2845                                                 p_num_members)) {
2846                                 ret = NT_STATUS_NO_MEMORY;
2847                                 goto done;
2848                         }
2849                 }
2850         }
2851
2852         filter = talloc_asprintf(mem_ctx,
2853                                  "(&(objectClass=%s)"
2854                                  "(gidNumber=%s))",
2855                                  LDAP_OBJ_SAMBASAMACCOUNT,
2856                                  gidstr);
2857
2858         rc = smbldap_search(conn, lp_ldap_suffix(),
2859                             LDAP_SCOPE_SUBTREE, filter, sid_attrs, 0,
2860                             &result);
2861
2862         if (rc != LDAP_SUCCESS)
2863                 goto done;
2864
2865         talloc_autofree_ldapmsg(mem_ctx, result);
2866
2867         for (entry = ldap_first_entry(conn->ldap_struct, result);
2868              entry != NULL;
2869              entry = ldap_next_entry(conn->ldap_struct, entry))
2870         {
2871                 uint32_t rid;
2872
2873                 if (!ldapsam_extract_rid_from_entry(conn->ldap_struct,
2874                                                     entry,
2875                                                     get_global_sam_sid(),
2876                                                     &rid)) {
2877                         DEBUG(0, ("Severe DB error, %s can't miss the samba SID"                                                                "attribute\n", LDAP_OBJ_SAMBASAMACCOUNT));
2878                         ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
2879                         goto done;
2880                 }
2881
2882                 if (!add_rid_to_array_unique(mem_ctx, rid, pp_member_rids,
2883                                         p_num_members)) {
2884                         ret = NT_STATUS_NO_MEMORY;
2885                         goto done;
2886                 }
2887         }
2888
2889         ret = NT_STATUS_OK;
2890
2891  done:
2892
2893         if (values)
2894                 ldap_value_free(values);
2895
2896         return ret;
2897 }
2898
2899 static NTSTATUS ldapsam_enum_group_memberships(struct pdb_methods *methods,
2900                                                TALLOC_CTX *mem_ctx,
2901                                                struct samu *user,
2902                                                struct dom_sid **pp_sids,
2903                                                gid_t **pp_gids,
2904                                                size_t *p_num_groups)
2905 {
2906         struct ldapsam_privates *ldap_state =
2907                 (struct ldapsam_privates *)methods->private_data;
2908         struct smbldap_state *conn = ldap_state->smbldap_state;
2909         char *filter;
2910         const char *attrs[] = { "gidNumber", "sambaSID", NULL };
2911         char *escape_name;
2912         int rc, count;
2913         LDAPMessage *result = NULL;
2914         LDAPMessage *entry;
2915         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
2916         uint32_t num_sids;
2917         size_t num_gids;
2918         char *gidstr;
2919         gid_t primary_gid = -1;
2920
2921         *pp_sids = NULL;
2922         num_sids = 0;
2923
2924         if (pdb_get_username(user) == NULL) {
2925                 return NT_STATUS_INVALID_PARAMETER;
2926         }
2927
2928         escape_name = escape_ldap_string(talloc_tos(), pdb_get_username(user));
2929         if (escape_name == NULL)
2930                 return NT_STATUS_NO_MEMORY;
2931
2932         if (user->unix_pw) {
2933                 primary_gid = user->unix_pw->pw_gid;
2934         } else {
2935                 /* retrieve the users primary gid */
2936                 filter = talloc_asprintf(mem_ctx,
2937                                          "(&(objectClass=%s)(uid=%s))",
2938                                          LDAP_OBJ_SAMBASAMACCOUNT,
2939                                          escape_name);
2940                 if (filter == NULL) {
2941                         ret = NT_STATUS_NO_MEMORY;
2942                         goto done;
2943                 }
2944
2945                 rc = smbldap_search(conn, lp_ldap_suffix(),
2946                                     LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result);
2947
2948                 if (rc != LDAP_SUCCESS)
2949                         goto done;
2950
2951                 talloc_autofree_ldapmsg(mem_ctx, result);
2952
2953                 count = ldap_count_entries(priv2ld(ldap_state), result);
2954
2955                 switch (count) {
2956                 case 0:
2957                         DEBUG(1, ("User account [%s] not found!\n", pdb_get_username(user)));
2958                         ret = NT_STATUS_NO_SUCH_USER;
2959                         goto done;
2960                 case 1:
2961                         entry = ldap_first_entry(priv2ld(ldap_state), result);
2962
2963                         gidstr = smbldap_talloc_single_attribute(priv2ld(ldap_state), entry, "gidNumber", mem_ctx);
2964                         if (!gidstr) {
2965                                 DEBUG (1, ("Unable to find the member's gid!\n"));
2966                                 ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
2967                                 goto done;
2968                         }
2969                         primary_gid = strtoul(gidstr, NULL, 10);
2970                         break;
2971                 default:
2972                         DEBUG(1, ("found more than one account with the same user name ?!\n"));
2973                         ret = NT_STATUS_INTERNAL_DB_CORRUPTION;
2974                         goto done;
2975                 }
2976         }
2977
2978         filter = talloc_asprintf(mem_ctx,
2979                                  "(&(objectClass=%s)(|(memberUid=%s)(gidNumber=%u)))",
2980                                  LDAP_OBJ_POSIXGROUP, escape_name, (unsigned int)primary_gid);
2981         if (filter == NULL) {
2982                 ret = NT_STATUS_NO_MEMORY;
2983                 goto done;
2984         }
2985
2986         rc = smbldap_search(conn, lp_ldap_suffix(),
2987                             LDAP_SCOPE_SUBTREE, filter, attrs, 0, &result);
2988
2989         if (rc != LDAP_SUCCESS)
2990                 goto done;
2991
2992         talloc_autofree_ldapmsg(mem_ctx, result);
2993
2994         num_gids = 0;
2995         *pp_gids = NULL;
2996
2997         num_sids = 0;
2998         *pp_sids = NULL;
2999
3000         /* We need to add the primary group as the first gid/sid */
3001
3002         if (!add_gid_to_array_unique(mem_ctx, primary_gid, pp_gids, &num_gids)) {
3003                 ret = NT_STATUS_NO_MEMORY;
3004                 goto done;
3005         }
3006
3007         /* This sid will be replaced later */
3008
3009         ret = add_sid_to_array_unique(mem_ctx, &global_sid_NULL, pp_sids,
3010                                       &num_sids);
3011         if (!NT_STATUS_IS_OK(ret)) {
3012                 goto done;
3013         }
3014
3015         for (entry = ldap_first_entry(conn->ldap_struct, result);
3016              entry != NULL;
3017              entry = ldap_next_entry(conn->ldap_struct, entry))
3018         {
3019                 fstring str;
3020                 struct dom_sid sid;
3021                 gid_t gid;
3022                 char *end;
3023
3024                 if (!smbldap_get_single_attribute(conn->ldap_struct,
3025                                                   entry, "sambaSID",
3026                                                   str, sizeof(str)-1))
3027                         continue;
3028
3029                 if (!string_to_sid(&sid, str))
3030                         goto done;
3031
3032                 if (!smbldap_get_single_attribute(conn->ldap_struct,
3033                                                   entry, "gidNumber",
3034                                                   str, sizeof(str)-1))
3035                         continue;
3036
3037                 gid = strtoul(str, &end, 10);
3038
3039                 if (PTR_DIFF(end, str) != strlen(str))
3040                         goto done;
3041
3042                 if (gid == primary_gid) {
3043                         sid_copy(&(*pp_sids)[0], &sid);
3044                 } else {
3045                         if (!add_gid_to_array_unique(mem_ctx, gid, pp_gids,
3046                                                 &num_gids)) {
3047                                 ret = NT_STATUS_NO_MEMORY;
3048                                 goto done;
3049                         }
3050                         ret = add_sid_to_array_unique(mem_ctx, &sid, pp_sids,
3051                                                       &num_sids);
3052                         if (!NT_STATUS_IS_OK(ret)) {
3053                                 goto done;
3054                         }
3055                 }
3056         }
3057
3058         if (sid_compare(&global_sid_NULL, &(*pp_sids)[0]) == 0) {
3059                 DEBUG(3, ("primary group of [%s] not found\n",
3060                           pdb_get_username(user)));
3061                 goto done;
3062         }
3063
3064         *p_num_groups = num_sids;
3065
3066         ret = NT_STATUS_OK;
3067
3068  done:
3069
3070         TALLOC_FREE(escape_name);
3071         return ret;
3072 }
3073
3074 /**********************************************************************
3075  * Augment a posixGroup object with a sambaGroupMapping domgroup
3076  *********************************************************************/
3077
3078 static NTSTATUS ldapsam_map_posixgroup(TALLOC_CTX *mem_ctx,
3079                                        struct ldapsam_privates *ldap_state,
3080                                        GROUP_MAP *map)
3081 {
3082         const char *filter, *dn;
3083         LDAPMessage *msg, *entry;
3084         LDAPMod **mods;
3085         int rc;
3086
3087         filter = talloc_asprintf(mem_ctx,
3088                                  "(&(objectClass=%s)(gidNumber=%u))",
3089                                  LDAP_OBJ_POSIXGROUP, (unsigned int)map->gid);
3090         if (filter == NULL) {
3091                 return NT_STATUS_NO_MEMORY;
3092         }
3093
3094         rc = smbldap_search_suffix(ldap_state->smbldap_state, filter,
3095                                    get_attr_list(mem_ctx, groupmap_attr_list),
3096                                    &msg);
3097         talloc_autofree_ldapmsg(mem_ctx, msg);
3098
3099         if ((rc != LDAP_SUCCESS) ||
3100             (ldap_count_entries(ldap_state->smbldap_state->ldap_struct, msg) != 1) ||
3101             ((entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, msg)) == NULL)) {
3102                 return NT_STATUS_NO_SUCH_GROUP;
3103         }
3104
3105         dn = smbldap_talloc_dn(mem_ctx, ldap_state->smbldap_state->ldap_struct, entry);
3106         if (dn == NULL) {
3107                 return NT_STATUS_NO_MEMORY;
3108         }
3109
3110         mods = NULL;
3111         smbldap_set_mod(&mods, LDAP_MOD_ADD, "objectClass",
3112                         LDAP_OBJ_GROUPMAP);
3113         smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "sambaSid",
3114                          sid_string_talloc(mem_ctx, &map->sid));
3115         smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "sambaGroupType",
3116                          talloc_asprintf(mem_ctx, "%d", map->sid_name_use));
3117         smbldap_make_mod(ldap_state->smbldap_state->ldap_struct, entry, &mods, "displayName",