Another bug fix from metze.
[kai/samba.git] / source3 / passdb / pdb_ldap.c
1 /* 
2    Unix SMB/CIFS implementation.
3    LDAP protocol helper functions for SAMBA
4    Copyright (C) Gerald Carter 2001
5    Copyright (C) Shahms King 2001
6    Copyright (C) Jean François Micouleau 1998
7    Copyright (C) Andrew Bartlett 2002
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22    
23 */
24
25 #include "includes.h"
26
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_PASSDB
29
30 #ifdef HAVE_LDAP
31 /* TODO:
32 *  persistent connections: if using NSS LDAP, many connections are made
33 *      however, using only one within Samba would be nice
34 *  
35 *  Clean up SSL stuff, compile on OpenLDAP 1.x, 2.x, and Netscape SDK
36 *
37 *  Other LDAP based login attributes: accountExpires, etc.
38 *  (should be the domain of Samba proper, but the sam_password/SAM_ACCOUNT
39 *  structures don't have fields for some of these attributes)
40 *
41 *  SSL is done, but can't get the certificate based authentication to work
42 *  against on my test platform (Linux 2.4, OpenLDAP 2.x)
43 */
44
45 /* NOTE: this will NOT work against an Active Directory server
46 *  due to the fact that the two password fields cannot be retrieved
47 *  from a server; recommend using security = domain in this situation
48 *  and/or winbind
49 */
50
51 #include <lber.h>
52 #include <ldap.h>
53
54 #ifndef SAM_ACCOUNT
55 #define SAM_ACCOUNT struct sam_passwd
56 #endif
57
58 struct ldapsam_privates {
59
60         /* Former statics */
61         LDAP *ldap_struct;
62         LDAPMessage *result;
63         LDAPMessage *entry;
64         int index;
65         
66         /* retrive-once info */
67         const char *uri;
68         
69         BOOL permit_non_unix_accounts;
70         
71         uint32 low_nua_rid; 
72         uint32 high_nua_rid; 
73 };
74
75 static uint32 ldapsam_get_next_available_nua_rid(struct ldapsam_privates *ldap_state);
76
77 /*******************************************************************
78  find the ldap password
79 ******************************************************************/
80 static BOOL fetch_ldapsam_pw(char **dn, char** pw)
81 {
82         char *key = NULL;
83         size_t size;
84         
85         *dn = smb_xstrdup(lp_ldap_admin_dn());
86         
87         if (asprintf(&key, "%s/%s", SECRETS_LDAP_BIND_PW, *dn) < 0) {
88                 SAFE_FREE(*dn);
89                 DEBUG(0, ("fetch_ldapsam_pw: asprintf failed!\n"));
90         }
91         
92         *pw=secrets_fetch(key, &size);
93         if (!size) {
94                 /* Upgrade 2.2 style entry */
95                 char *p;
96                 char* old_style_key = strdup(*dn);
97                 char *data;
98                 fstring old_style_pw;
99                 
100                 if (!old_style_key) {
101                         DEBUG(0, ("fetch_ldapsam_pw: strdup failed!\n"));
102                         return False;
103                 }
104
105                 for (p=old_style_key; *p; p++)
106                         if (*p == ',') *p = '/';
107         
108                 data=secrets_fetch(old_style_key, &size);
109                 if (!size && size < sizeof(old_style_pw)) {
110                         DEBUG(0,("fetch_ldap_pw: neither ldap secret retrieved!\n"));
111                         SAFE_FREE(old_style_key);
112                         SAFE_FREE(*dn);
113                         return False;
114                 }
115
116                 strncpy(old_style_pw, data, size);
117                 old_style_pw[size] = 0;
118
119                 SAFE_FREE(data);
120
121                 if (!secrets_store_ldap_pw(*dn, old_style_pw)) {
122                         DEBUG(0,("fetch_ldap_pw: ldap secret could not be upgraded!\n"));
123                         SAFE_FREE(old_style_key);
124                         SAFE_FREE(*dn);
125                         return False;                   
126                 }
127                 if (!secrets_delete(old_style_key)) {
128                         DEBUG(0,("fetch_ldap_pw: old ldap secret could not be deleted!\n"));
129                 }
130
131                 SAFE_FREE(old_style_key);
132
133                 *pw = smb_xstrdup(old_style_pw);                
134         }
135         
136         return True;
137 }
138
139 char *attr[] = {"uid", "pwdLastSet", "logonTime",
140                 "logoffTime", "kickoffTime", "cn",
141                 "pwdCanChange", "pwdMustChange",
142                 "dislplayName", "homeDrive",
143                 "smbHome", "scriptPath",
144                 "profilePath", "description",
145                 "userWorkstation", "rid",
146                 "primaryGroupID", "lmPassword",
147                 "ntPassword", "acctFlags",
148                 "domain", "description", NULL };
149
150 /*******************************************************************
151  open a connection to the ldap server.
152 ******************************************************************/
153 static BOOL ldapsam_open_connection (struct ldapsam_privates *ldap_state, LDAP ** ldap_struct)
154 {
155
156         if (geteuid() != 0) {
157                 DEBUG(0, ("ldap_open_connection: cannot access LDAP when not root..\n"));
158                 return False;
159         }
160         
161 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
162         DEBUG(10, ("ldapsam_open_connection: %s\n", ldap_state->uri));
163         
164         if (ldap_initialize(ldap_struct, ldap_state->uri) != LDAP_SUCCESS) {
165                 DEBUG(0, ("ldap_initialize: %s\n", strerror(errno)));
166                 return (False);
167         }
168 #else 
169
170         /* Parse the string manually */
171
172         {
173                 int rc;
174                 int tls = LDAP_OPT_X_TLS_HARD;
175                 int port = 0;
176                 int version;
177                 fstring protocol;
178                 fstring host;
179                 const char *p = ldap_state->uri; 
180                 SMB_ASSERT(sizeof(protocol)>10 && sizeof(host)>254);
181                 
182                 /* skip leading "URL:" (if any) */
183                 if ( strncasecmp( p, "URL:", 4 ) == 0 ) {
184                         p += 4;
185                 }
186
187                 sscanf(p, "%10[^:]://%254s[^:]:%d", protocol, host, &port);
188                 
189                 if (port == 0) {
190                         if (strequal(protocol, "ldap")) {
191                                 port = LDAP_PORT;
192                         } else if (strequal(protocol, "ldaps")) {
193                                 port = LDAPS_PORT;
194                         } else {
195                                 DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
196                         }
197                 }
198
199                 if ((*ldap_struct = ldap_init(host, port)) == NULL)     {
200                         DEBUG(0, ("ldap_init failed !\n"));
201                         return False;
202                 }
203
204                 /* Connect to older servers using SSL and V2 rather than Start TLS */
205                 if (ldap_get_option(*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS)
206                 {
207                         if (version != LDAP_VERSION2)
208                         {
209                                 version = LDAP_VERSION2;
210                                 ldap_set_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version);
211                         }
212                 }
213
214                 if (strequal(protocol, "ldaps")) { 
215                         if (lp_ldap_ssl() == LDAP_SSL_START_TLS) {
216                                 if (ldap_get_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, 
217                                                      &version) == LDAP_OPT_SUCCESS)
218                                 {
219                                         if (version < LDAP_VERSION3)
220                                         {
221                                                 version = LDAP_VERSION3;
222                                                 ldap_set_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION,
223                                                                  &version);
224                                         }
225                                 }
226                                 if ((rc = ldap_start_tls_s (*ldap_struct, NULL, NULL)) != LDAP_SUCCESS)
227                                 {
228                                         DEBUG(0,("Failed to issue the StartTLS instruction: %s\n",
229                                                  ldap_err2string(rc)));
230                                         return False;
231                                 }
232                                 DEBUG (2, ("StartTLS issued: using a TLS connection\n"));
233                         } else {
234                                 
235                                 if (ldap_set_option (*ldap_struct, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
236                                 {
237                                         DEBUG(0, ("Failed to setup a TLS session\n"));
238                                 }
239                         }
240                 } else {
241                         /* 
242                          * No special needs to setup options prior to the LDAP
243                          * bind (which should be called next via ldap_connect_system()
244                          */
245                 }
246         }
247 #endif
248
249         DEBUG(2, ("ldap_open_connection: connection opened\n"));
250         return True;
251 }
252
253
254 /*******************************************************************
255  Add a rebind function for authenticated referrals
256 ******************************************************************/
257
258 static int rebindproc (LDAP *ldap_struct, char **whop, char **credp,
259                        int *method, int freeit )
260 {
261         int rc;
262         char *ldap_dn;
263         char *ldap_secret;
264         
265         /** @TODO Should we be doing something to check what servers we rebind to?
266             Could we get a referral to a machine that we don't want to give our
267             username and password to? */
268         
269         if (freeit != 0)
270         {
271                 
272                 if (!fetch_ldapsam_pw(&ldap_dn, &ldap_secret)) 
273                 {
274                         DEBUG(0, ("ldap_connect_system: Failed to retrieve password from secrets.tdb\n"));
275                         return LDAP_OPERATIONS_ERROR;  /* No idea what to return */
276                 }
277                 
278                 DEBUG(5,("ldap_connect_system: Rebinding as \"%s\"\n", 
279                           ldap_dn));
280
281                 rc = ldap_simple_bind_s(ldap_struct, ldap_dn, ldap_secret);
282                 
283                 SAFE_FREE(ldap_dn);
284                 SAFE_FREE(ldap_secret);
285
286                 return rc;
287         }
288         return 0;
289 }
290
291 /*******************************************************************
292  connect to the ldap server under system privilege.
293 ******************************************************************/
294 static BOOL ldapsam_connect_system(struct ldapsam_privates *ldap_state, LDAP * ldap_struct)
295 {
296         int rc;
297         char *ldap_dn;
298         char *ldap_secret;
299
300         /* get the password */
301         if (!fetch_ldapsam_pw(&ldap_dn, &ldap_secret))
302         {
303                 DEBUG(0, ("ldap_connect_system: Failed to retrieve password from secrets.tdb\n"));
304                 return False;
305         }
306
307         /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite 
308            (OpenLDAP) doesnt' seem to support it */
309            
310         DEBUG(10,("ldap_connect_system: Binding to ldap server as \"%s\"\n",
311                 ldap_dn));
312         
313         ldap_set_rebind_proc(ldap_struct, (LDAP_REBIND_PROC *)(&rebindproc));   
314
315         rc = ldap_simple_bind_s(ldap_struct, ldap_dn, ldap_secret);
316
317         SAFE_FREE(ldap_dn);
318         SAFE_FREE(ldap_secret);
319
320         if (rc != LDAP_SUCCESS)
321         {
322                 DEBUG(0, ("Bind failed: %s\n", ldap_err2string(rc)));
323                 return False;
324         }
325         
326         DEBUG(2, ("ldap_connect_system: succesful connection to the LDAP server\n"));
327         return True;
328 }
329
330 /*******************************************************************
331  run the search by name.
332 ******************************************************************/
333 static int ldapsam_search_one_user (struct ldapsam_privates *ldap_state, LDAP * ldap_struct, const char *filter, LDAPMessage ** result)
334 {
335         int scope = LDAP_SCOPE_SUBTREE;
336         int rc;
337
338         DEBUG(2, ("ldapsam_search_one_user: searching for:[%s]\n", filter));
339
340         rc = ldap_search_s(ldap_struct, lp_ldap_suffix (), scope, filter, attr, 0, result);
341
342         if (rc != LDAP_SUCCESS) {
343                 DEBUG(0,("ldapsam_search_one_user: Problem during the LDAP search: %s\n", 
344                         ldap_err2string (rc)));
345                 DEBUG(3,("ldapsam_search_one_user: Query was: %s, %s\n", lp_ldap_suffix(), 
346                         filter));
347         }
348         
349         return rc;
350 }
351
352 /*******************************************************************
353  run the search by name.
354 ******************************************************************/
355 static int ldapsam_search_one_user_by_name (struct ldapsam_privates *ldap_state, LDAP * ldap_struct, const char *user,
356                              LDAPMessage ** result)
357 {
358         pstring filter;
359         
360         /*
361          * in the filter expression, replace %u with the real name
362          * so in ldap filter, %u MUST exist :-)
363          */
364         pstrcpy(filter, lp_ldap_filter());
365
366         /* 
367          * have to use this here because $ is filtered out
368            * in pstring_sub
369          */
370         all_string_sub(filter, "%u", user, sizeof(pstring));
371
372         return ldapsam_search_one_user(ldap_state, ldap_struct, filter, result);
373 }
374
375 /*******************************************************************
376  run the search by uid.
377 ******************************************************************/
378 static int ldapsam_search_one_user_by_uid(struct ldapsam_privates *ldap_state, 
379                                           LDAP * ldap_struct, int uid,
380                                           LDAPMessage ** result)
381 {
382         struct passwd *user;
383         pstring filter;
384
385         /* Get the username from the system and look that up in the LDAP */
386         
387         if ((user = getpwuid_alloc(uid)) == NULL) {
388                 DEBUG(3,("ldapsam_search_one_user_by_uid: Failed to locate uid [%d]\n", uid));
389                 return LDAP_NO_SUCH_OBJECT;
390         }
391         
392         pstrcpy(filter, lp_ldap_filter());
393         
394         all_string_sub(filter, "%u", user->pw_name, sizeof(pstring));
395
396         passwd_free(&user);
397
398         return ldapsam_search_one_user(ldap_state, ldap_struct, filter, result);
399 }
400
401 /*******************************************************************
402  run the search by rid.
403 ******************************************************************/
404 static int ldapsam_search_one_user_by_rid (struct ldapsam_privates *ldap_state, 
405                                            LDAP * ldap_struct, uint32 rid,
406                                            LDAPMessage ** result)
407 {
408         pstring filter;
409         int rc;
410
411         /* check if the user rid exsists, if not, try searching on the uid */
412         
413         snprintf(filter, sizeof(filter) - 1, "rid=%i", rid);
414         rc = ldapsam_search_one_user(ldap_state, ldap_struct, filter, result);
415         
416         if (rc != LDAP_SUCCESS)
417                 rc = ldapsam_search_one_user_by_uid(ldap_state, ldap_struct, 
418                                                     fallback_pdb_user_rid_to_uid(rid), 
419                                                     result);
420
421         return rc;
422 }
423
424 /*******************************************************************
425 search an attribute and return the first value found.
426 ******************************************************************/
427 static BOOL get_single_attribute (LDAP * ldap_struct, LDAPMessage * entry,
428                                   char *attribute, pstring value)
429 {
430         char **values;
431
432         if ((values = ldap_get_values (ldap_struct, entry, attribute)) == NULL) {
433                 value = NULL;
434                 DEBUG (10, ("get_single_attribute: [%s] = [<does not exist>]\n", attribute));
435                 
436                 return False;
437         }
438         
439         pstrcpy(value, values[0]);
440         ldap_value_free(values);
441 #ifdef DEBUG_PASSWORDS
442         DEBUG (100, ("get_single_attribute: [%s] = [%s]\n", attribute, value));
443 #endif  
444         return True;
445 }
446
447 /************************************************************************
448 Routine to manage the LDAPMod structure array
449 manage memory used by the array, by each struct, and values
450
451 ************************************************************************/
452 static void make_a_mod (LDAPMod *** modlist, int modop, const char *attribute, const char *value)
453 {
454         LDAPMod **mods;
455         int i;
456         int j;
457
458         mods = *modlist;
459
460         if (attribute == NULL || *attribute == '\0')
461                 return;
462
463         if (value == NULL || *value == '\0')
464                 return;
465
466         if (mods == NULL) 
467         {
468                 mods = (LDAPMod **) malloc(sizeof(LDAPMod *));
469                 if (mods == NULL)
470                 {
471                         DEBUG(0, ("make_a_mod: out of memory!\n"));
472                         return;
473                 }
474                 mods[0] = NULL;
475         }
476
477         for (i = 0; mods[i] != NULL; ++i) {
478                 if (mods[i]->mod_op == modop && !strcasecmp(mods[i]->mod_type, attribute))
479                         break;
480         }
481
482         if (mods[i] == NULL)
483         {
484                 mods = (LDAPMod **) Realloc (mods, (i + 2) * sizeof (LDAPMod *));
485                 if (mods == NULL)
486                 {
487                         DEBUG(0, ("make_a_mod: out of memory!\n"));
488                         return;
489                 }
490                 mods[i] = (LDAPMod *) malloc(sizeof(LDAPMod));
491                 if (mods[i] == NULL)
492                 {
493                         DEBUG(0, ("make_a_mod: out of memory!\n"));
494                         return;
495                 }
496                 mods[i]->mod_op = modop;
497                 mods[i]->mod_values = NULL;
498                 mods[i]->mod_type = strdup(attribute);
499                 mods[i + 1] = NULL;
500         }
501
502         if (value != NULL)
503         {
504                 j = 0;
505                 if (mods[i]->mod_values != NULL) {
506                         for (; mods[i]->mod_values[j] != NULL; j++);
507                 }
508                 mods[i]->mod_values = (char **)Realloc(mods[i]->mod_values,
509                                                (j + 2) * sizeof (char *));
510                                                
511                 if (mods[i]->mod_values == NULL) {
512                         DEBUG (0, ("make_a_mod: Memory allocation failure!\n"));
513                         return;
514                 }
515                 mods[i]->mod_values[j] = strdup(value);
516                 mods[i]->mod_values[j + 1] = NULL;
517         }
518         *modlist = mods;
519 }
520
521 /* New Interface is being implemented here */
522
523 /**********************************************************************
524 Initialize SAM_ACCOUNT from an LDAP query
525 (Based on init_sam_from_buffer in pdb_tdb.c)
526 *********************************************************************/
527 static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state, 
528                                 SAM_ACCOUNT * sampass,
529                                 LDAP * ldap_struct, LDAPMessage * entry)
530 {
531         time_t  logon_time,
532                         logoff_time,
533                         kickoff_time,
534                         pass_last_set_time, 
535                         pass_can_change_time, 
536                         pass_must_change_time;
537         pstring         username, 
538                         domain,
539                         nt_username,
540                         fullname,
541                         homedir,
542                         dir_drive,
543                         logon_script,
544                         profile_path,
545                         acct_desc,
546                         munged_dial,
547                         workstations;
548         struct passwd   *pw;
549         uint32          user_rid, 
550                         group_rid;
551         uint8           smblmpwd[16],
552                         smbntpwd[16];
553         uint16          acct_ctrl, 
554                         logon_divs;
555         uint32 hours_len;
556         uint8           hours[MAX_HOURS_LEN];
557         pstring temp;
558         uid_t           uid = -1;
559         gid_t           gid = getegid();
560
561
562         /*
563          * do a little initialization
564          */
565         username[0]     = '\0';
566         domain[0]       = '\0';
567         nt_username[0]  = '\0';
568         fullname[0]     = '\0';
569         homedir[0]      = '\0';
570         dir_drive[0]    = '\0';
571         logon_script[0] = '\0';
572         profile_path[0] = '\0';
573         acct_desc[0]    = '\0';
574         munged_dial[0]  = '\0';
575         workstations[0] = '\0';
576          
577
578         if (sampass == NULL || ldap_struct == NULL || entry == NULL) {
579                 DEBUG(0, ("init_sam_from_ldap: NULL parameters found!\n"));
580                 return False;
581         }
582
583         get_single_attribute(ldap_struct, entry, "uid", username);
584         DEBUG(2, ("Entry found for user: %s\n", username));
585
586         pstrcpy(nt_username, username);
587
588         pstrcpy(domain, lp_workgroup());
589
590         get_single_attribute(ldap_struct, entry, "rid", temp);
591         user_rid = (uint32)atol(temp);
592         if (!get_single_attribute(ldap_struct, entry, "primaryGroupID", temp)) {
593                 group_rid = 0;
594         } else {
595                 group_rid = (uint32)atol(temp);
596         }
597
598         if ((ldap_state->permit_non_unix_accounts) 
599             && (user_rid >= ldap_state->low_nua_rid)
600             && (user_rid <= ldap_state->high_nua_rid)) {
601                 
602         } else {
603                 
604                 /* These values MAY be in LDAP, but they can also be retrieved through 
605                  *  sys_getpw*() which is how we're doing it 
606                  */
607         
608                 pw = getpwnam_alloc(username);
609                 if (pw == NULL) {
610                         DEBUG (2,("init_sam_from_ldap: User [%s] does not ave a uid!\n", username));
611                         return False;
612                 }
613                 uid = pw->pw_uid;
614                 gid = pw->pw_gid;
615
616                 pdb_set_unix_homedir(sampass, pw->pw_dir);
617
618                 passwd_free(&pw);
619
620                 pdb_set_uid(sampass, uid);
621                 pdb_set_gid(sampass, gid);
622
623                 if (group_rid == 0) {
624                         GROUP_MAP map;
625                         /* call the mapping code here */
626                         if(get_group_map_from_gid(gid, &map, MAPPING_WITHOUT_PRIV)) {
627                                 if (!sid_peek_check_rid(get_global_sam_sid(), &map.sid, &group_rid))
628                                         return False;
629                         } 
630                         else {
631                                 group_rid=pdb_gid_to_group_rid(gid);
632                         }
633                 }
634         }
635
636         if (!get_single_attribute(ldap_struct, entry, "pwdLastSet", temp)) {
637                 /* leave as default */
638         } else {
639                 pass_last_set_time = (time_t) atol(temp);
640                 pdb_set_pass_last_set_time(sampass, pass_last_set_time);
641         }
642
643         if (!get_single_attribute(ldap_struct, entry, "logonTime", temp)) {
644                 /* leave as default */
645         } else {
646                 logon_time = (time_t) atol(temp);
647                 pdb_set_logon_time(sampass, logon_time, True);
648         }
649
650         if (!get_single_attribute(ldap_struct, entry, "logoffTime", temp)) {
651                 /* leave as default */
652         } else {
653                 logoff_time = (time_t) atol(temp);
654                 pdb_set_logoff_time(sampass, logoff_time, True);
655         }
656
657         if (!get_single_attribute(ldap_struct, entry, "kickoffTime", temp)) {
658                 /* leave as default */
659         } else {
660                 kickoff_time = (time_t) atol(temp);
661                 pdb_set_kickoff_time(sampass, kickoff_time, True);
662         }
663
664         if (!get_single_attribute(ldap_struct, entry, "pwdCanChange", temp)) {
665                 /* leave as default */
666         } else {
667                 pass_can_change_time = (time_t) atol(temp);
668                 pdb_set_pass_can_change_time(sampass, pass_can_change_time, True);
669         }
670
671         if (!get_single_attribute(ldap_struct, entry, "pwdMustChange", temp)) {
672                 /* leave as default */
673         } else {
674                 pass_must_change_time = (time_t) atol(temp);
675                 pdb_set_pass_must_change_time(sampass, pass_must_change_time, True);
676         }
677
678         /* recommend that 'gecos' and 'displayName' should refer to the same
679          * attribute OID.  userFullName depreciated, only used by Samba
680          * primary rules of LDAP: don't make a new attribute when one is already defined
681          * that fits your needs; using cn then displayName rather than 'userFullName'
682          */
683
684         if (!get_single_attribute(ldap_struct, entry, "cn", fullname)) {
685                 if (!get_single_attribute(ldap_struct, entry, "displayName", fullname)) {
686                         /* leave as default */
687                 } else {
688                         pdb_set_fullname(sampass, fullname);
689                 }
690         } else {
691                 pdb_set_fullname(sampass, fullname);
692         }
693
694         if (!get_single_attribute(ldap_struct, entry, "homeDrive", dir_drive)) {
695                 pdb_set_dir_drive(sampass, standard_sub_specified(sampass->mem_ctx, 
696                                                                   lp_logon_drive(),
697                                                                   username, domain, 
698                                                                   uid, gid),
699                                   False);
700         } else {
701                 pdb_set_dir_drive(sampass, dir_drive, True);
702         }
703
704         if (!get_single_attribute(ldap_struct, entry, "smbHome", homedir)) {
705                 pdb_set_homedir(sampass, standard_sub_specified(sampass->mem_ctx, 
706                                                                   lp_logon_home(),
707                                                                   username, domain, 
708                                                                   uid, gid), 
709                                   False);
710         } else {
711                 pdb_set_homedir(sampass, homedir, True);
712         }
713
714         if (!get_single_attribute(ldap_struct, entry, "scriptPath", logon_script)) {
715                 pdb_set_logon_script(sampass, standard_sub_specified(sampass->mem_ctx, 
716                                                                      lp_logon_script(),
717                                                                      username, domain, 
718                                                                      uid, gid), 
719                                      False);
720         } else {
721                 pdb_set_logon_script(sampass, logon_script, True);
722         }
723
724         if (!get_single_attribute(ldap_struct, entry, "profilePath", profile_path)) {
725                 pdb_set_profile_path(sampass, standard_sub_specified(sampass->mem_ctx, 
726                                                                      lp_logon_path(),
727                                                                      username, domain, 
728                                                                      uid, gid), 
729                                      False);
730         } else {
731                 pdb_set_profile_path(sampass, profile_path, True);
732         }
733
734         if (!get_single_attribute(ldap_struct, entry, "description", acct_desc)) {
735                 /* leave as default */
736         } else {
737                 pdb_set_acct_desc(sampass, acct_desc);
738         }
739
740         if (!get_single_attribute(ldap_struct, entry, "userWorkstations", workstations)) {
741                 /* leave as default */;
742         } else {
743                 pdb_set_workstations(sampass, workstations);
744         }
745
746         /* FIXME: hours stuff should be cleaner */
747         
748         logon_divs = 168;
749         hours_len = 21;
750         memset(hours, 0xff, hours_len);
751
752         if (!get_single_attribute (ldap_struct, entry, "lmPassword", temp)) {
753                 /* leave as default */
754         } else {
755                 pdb_gethexpwd(temp, smblmpwd);
756                 memset((char *)temp, '\0', sizeof(temp));
757                 if (!pdb_set_lanman_passwd(sampass, smblmpwd))
758                         return False;
759         }
760
761         if (!get_single_attribute (ldap_struct, entry, "ntPassword", temp)) {
762                 /* leave as default */
763         } else {
764                 pdb_gethexpwd(temp, smbntpwd);
765                 memset((char *)temp, '\0', sizeof(temp));
766                 if (!pdb_set_nt_passwd(sampass, smbntpwd))
767                         return False;
768         }
769
770         if (!get_single_attribute (ldap_struct, entry, "acctFlags", temp)) {
771                 acct_ctrl |= ACB_NORMAL;
772         } else {
773                 acct_ctrl = pdb_decode_acct_ctrl(temp);
774
775                 if (acct_ctrl == 0)
776                         acct_ctrl |= ACB_NORMAL;
777
778                 pdb_set_acct_ctrl(sampass, acct_ctrl);
779         }
780
781         pdb_set_hours_len(sampass, hours_len);
782         pdb_set_logon_divs(sampass, logon_divs);
783
784         pdb_set_user_sid_from_rid(sampass, user_rid);
785         pdb_set_group_sid_from_rid(sampass, group_rid);
786
787         pdb_set_username(sampass, username);
788
789         pdb_set_domain(sampass, domain);
790         pdb_set_nt_username(sampass, nt_username);
791
792         pdb_set_munged_dial(sampass, munged_dial);
793         
794         /* pdb_set_unknown_3(sampass, unknown3); */
795         /* pdb_set_unknown_5(sampass, unknown5); */
796         /* pdb_set_unknown_6(sampass, unknown6); */
797
798         pdb_set_hours(sampass, hours);
799
800         return True;
801 }
802
803 /**********************************************************************
804 Initialize SAM_ACCOUNT from an LDAP query
805 (Based on init_buffer_from_sam in pdb_tdb.c)
806 *********************************************************************/
807 static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state, 
808                                 LDAPMod *** mods, int ldap_op, 
809                                 const SAM_ACCOUNT * sampass)
810 {
811         pstring temp;
812         uint32 rid;
813
814         if (mods == NULL || sampass == NULL) {
815                 DEBUG(0, ("init_ldap_from_sam: NULL parameters found!\n"));
816                 return False;
817         }
818
819         *mods = NULL;
820
821         /* 
822          * took out adding "objectclass: sambaAccount"
823          * do this on a per-mod basis
824          */
825
826         make_a_mod(mods, ldap_op, "uid", pdb_get_username(sampass));
827         DEBUG(2, ("Setting entry for user: %s\n", pdb_get_username(sampass)));
828
829         if ( pdb_get_user_rid(sampass) ) {
830                 rid = pdb_get_user_rid(sampass);
831         } else if (IS_SAM_SET(sampass, FLAG_SAM_UID)) {
832                 rid = fallback_pdb_uid_to_user_rid(pdb_get_uid(sampass));
833         } else if (ldap_state->permit_non_unix_accounts) {
834                 rid = ldapsam_get_next_available_nua_rid(ldap_state);
835                 if (rid == 0) {
836                         DEBUG(0, ("NO user RID specified on account %s, and findining next available NUA RID failed, cannot store!\n", pdb_get_username(sampass)));
837                         return False;
838                 }
839         } else {
840                 DEBUG(0, ("NO user RID specified on account %s, cannot store!\n", pdb_get_username(sampass)));
841                 return False;
842         }
843
844         slprintf(temp, sizeof(temp) - 1, "%i", rid);
845         make_a_mod(mods, ldap_op, "rid", temp);
846
847         if ( pdb_get_group_rid(sampass) ) {
848                 rid = pdb_get_group_rid(sampass);
849         } else if (IS_SAM_SET(sampass, FLAG_SAM_GID)) {
850                 rid = pdb_gid_to_group_rid(pdb_get_gid(sampass));
851         } else if (ldap_state->permit_non_unix_accounts) {
852                 rid = DOMAIN_GROUP_RID_USERS;
853         } else {
854                 DEBUG(0, ("NO group RID specified on account %s, cannot store!\n", pdb_get_username(sampass)));
855                 return False;
856         }
857
858         slprintf(temp, sizeof(temp) - 1, "%i", rid);
859         make_a_mod(mods, ldap_op, "primaryGroupID", temp);
860
861         slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_last_set_time(sampass));
862         make_a_mod(mods, ldap_op, "pwdLastSet", temp);
863
864         /* displayName, cn, and gecos should all be the same
865            *  most easily accomplished by giving them the same OID
866            *  gecos isn't set here b/c it should be handled by the 
867            *  add-user script
868          */
869
870         make_a_mod(mods, ldap_op, "displayName", pdb_get_fullname(sampass));
871         make_a_mod(mods, ldap_op, "cn", pdb_get_fullname(sampass));
872         make_a_mod(mods, ldap_op, "description", pdb_get_acct_desc(sampass));
873         make_a_mod(mods, ldap_op, "userWorkstations", pdb_get_workstations(sampass));
874
875         /*
876          * Only updates fields which have been set (not defaults from smb.conf)
877          */
878
879         if (IS_SAM_SET(sampass, FLAG_SAM_SMBHOME))
880                 make_a_mod(mods, ldap_op, "smbHome", pdb_get_homedir(sampass));
881                 
882         if (IS_SAM_SET(sampass, FLAG_SAM_DRIVE))
883                 make_a_mod(mods, ldap_op, "homeDrive", pdb_get_dirdrive(sampass));
884         
885         if (IS_SAM_SET(sampass, FLAG_SAM_LOGONSCRIPT))
886                 make_a_mod(mods, ldap_op, "scriptPath", pdb_get_logon_script(sampass));
887
888         if (IS_SAM_SET(sampass, FLAG_SAM_PROFILE))
889                 make_a_mod(mods, ldap_op, "profilePath", pdb_get_profile_path(sampass));
890
891         if (IS_SAM_SET(sampass, FLAG_SAM_LOGONTIME)) {
892                 slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logon_time(sampass));
893                 make_a_mod(mods, ldap_op, "logonTime", temp);
894         }
895
896         if (IS_SAM_SET(sampass, FLAG_SAM_LOGOFFTIME)) {
897                 slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logoff_time(sampass));
898                 make_a_mod(mods, ldap_op, "logoffTime", temp);
899         }
900
901         if (IS_SAM_SET(sampass, FLAG_SAM_KICKOFFTIME)) {
902                 slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_kickoff_time(sampass));
903                 make_a_mod(mods, ldap_op, "kickoffTime", temp);
904         }
905
906         if (IS_SAM_SET(sampass, FLAG_SAM_CANCHANGETIME)) {
907                 slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_can_change_time(sampass));
908                 make_a_mod(mods, ldap_op, "pwdCanChange", temp);
909         }
910
911         if (IS_SAM_SET(sampass, FLAG_SAM_MUSTCHANGETIME)) {
912                 slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_must_change_time(sampass));
913                 make_a_mod(mods, ldap_op, "pwdMustChange", temp);
914         }
915
916         /* FIXME: Hours stuff goes in LDAP  */
917         pdb_sethexpwd (temp, pdb_get_lanman_passwd(sampass), pdb_get_acct_ctrl(sampass));
918         make_a_mod (mods, ldap_op, "lmPassword", temp);
919         
920         pdb_sethexpwd (temp, pdb_get_nt_passwd(sampass), pdb_get_acct_ctrl(sampass));
921         make_a_mod (mods, ldap_op, "ntPassword", temp);
922         
923         make_a_mod (mods, ldap_op, "acctFlags", pdb_encode_acct_ctrl (pdb_get_acct_ctrl(sampass),
924                 NEW_PW_FORMAT_SPACE_PADDED_LEN));
925
926         return True;
927 }
928
929
930 /**********************************************************************
931 Connect to LDAP server and find the next available RID.
932 *********************************************************************/
933 static uint32 check_nua_rid_is_avail(struct ldapsam_privates *ldap_state, uint32 top_rid, LDAP *ldap_struct) 
934 {
935         LDAPMessage *result;
936         uint32 final_rid = (top_rid & (~USER_RID_TYPE)) + RID_MULTIPLIER;
937         if (top_rid == 0) {
938                 return 0;
939         }
940         
941         if (final_rid < ldap_state->low_nua_rid || final_rid > ldap_state->high_nua_rid) {
942                 return 0;
943         }
944
945         if (ldapsam_search_one_user_by_rid(ldap_state, ldap_struct, final_rid, &result) != LDAP_SUCCESS) {
946                 DEBUG(0, ("Cannot allocate NUA RID %d (0x%x), as the confirmation search failed!\n", final_rid, final_rid));
947                 final_rid = 0;
948                 ldap_msgfree(result);
949         }
950
951         if (ldap_count_entries(ldap_struct, result) != 0)
952         {
953                 DEBUG(0, ("Cannot allocate NUA RID %d (0x%x), as the RID is already in use!!\n", final_rid, final_rid));
954                 final_rid = 0;
955                 ldap_msgfree(result);
956         }
957
958         DEBUG(5, ("NUA RID %d (0x%x), declared valid\n", final_rid, final_rid));
959         return final_rid;
960 }
961
962 /**********************************************************************
963 Extract the RID from an LDAP entry
964 *********************************************************************/
965 static uint32 entry_to_user_rid(struct ldapsam_privates *ldap_state, LDAPMessage *entry, LDAP *ldap_struct) {
966         uint32 rid;
967         SAM_ACCOUNT *user = NULL;
968         if (!NT_STATUS_IS_OK(pdb_init_sam(&user))) {
969                 return 0;
970         }
971
972         if (init_sam_from_ldap(ldap_state, user, ldap_struct, entry)) {
973                 rid = pdb_get_user_rid(user);
974         } else {
975                 rid =0;
976         }
977         pdb_free_sam(&user);
978         if (rid >= ldap_state->low_nua_rid && rid <= ldap_state->high_nua_rid) {
979                 return rid;
980         }
981         return 0;
982 }
983
984
985 /**********************************************************************
986 Connect to LDAP server and find the next available RID.
987 *********************************************************************/
988 static uint32 search_top_nua_rid(struct ldapsam_privates *ldap_state, LDAP *ldap_struct)
989 {
990         int rc;
991         pstring filter;
992         LDAPMessage *result;
993         LDAPMessage *entry;
994         char *final_filter = NULL;
995         uint32 top_rid = 0;
996         uint32 count;
997         uint32 rid;
998
999         pstrcpy(filter, lp_ldap_filter());
1000         all_string_sub(filter, "%u", "*", sizeof(pstring));
1001
1002 #if 0
1003         asprintf(&final_filter, "(&(%s)(&(rid>=%d)(rid<=%d)))", filter, ldap_state->low_nua_rid, ldap_state->high_nua_rid);
1004 #else 
1005         final_filter = strdup(filter);
1006 #endif  
1007         DEBUG(2, ("ldapsam_get_next_available_nua_rid: searching for:[%s]\n", final_filter));
1008
1009         rc = ldap_search_s(ldap_struct, lp_ldap_suffix(),
1010                            LDAP_SCOPE_SUBTREE, final_filter, attr, 0,
1011                            &result);
1012
1013         if (rc != LDAP_SUCCESS)
1014         {
1015                 
1016                 DEBUG(3, ("LDAP search failed! cannot find base for NUA RIDs: %s\n", ldap_err2string(rc)));
1017                 DEBUGADD(3, ("Query was: %s, %s\n", lp_ldap_suffix(), final_filter));
1018
1019                 free(final_filter);
1020                 ldap_msgfree(result);
1021                 result = NULL;
1022                 return 0;
1023         }
1024         
1025         count = ldap_count_entries(ldap_struct, result);
1026         DEBUG(2, ("search_top_nua_rid: %d entries in the base!\n", count));
1027         
1028         if (count == 0) {
1029                 DEBUG(3, ("LDAP search returned no records, assuming no non-unix-accounts present!: %s\n", ldap_err2string(rc)));
1030                 DEBUGADD(3, ("Query was: %s, %s\n", lp_ldap_suffix(), final_filter));
1031                 free(final_filter);
1032                 ldap_msgfree(result);
1033                 result = NULL;
1034                 return ldap_state->low_nua_rid;
1035         }
1036         
1037         free(final_filter);
1038         entry = ldap_first_entry(ldap_struct,result);
1039
1040         top_rid = entry_to_user_rid(ldap_state, entry, ldap_struct);
1041
1042         while ((entry = ldap_next_entry(ldap_struct, entry))) {
1043
1044                 rid = entry_to_user_rid(ldap_state, entry, ldap_struct);
1045                 if (rid > top_rid) {
1046                         top_rid = rid;
1047                 }
1048         }
1049
1050         ldap_msgfree(result);
1051
1052         if (top_rid < ldap_state->low_nua_rid) 
1053                 top_rid = ldap_state->low_nua_rid;
1054
1055         return top_rid;
1056 }
1057
1058 /**********************************************************************
1059 Connect to LDAP server and find the next available RID.
1060 *********************************************************************/
1061 static uint32 ldapsam_get_next_available_nua_rid(struct ldapsam_privates *ldap_state) {
1062         LDAP *ldap_struct;
1063         uint32 next_nua_rid;
1064         uint32 top_nua_rid;
1065
1066         if (!ldapsam_open_connection(ldap_state, &ldap_struct))
1067         {
1068                 return 0;
1069         }
1070         if (!ldapsam_connect_system(ldap_state, ldap_struct))
1071         {
1072                 ldap_unbind(ldap_struct);
1073                 return 0;
1074         }
1075         
1076         top_nua_rid = search_top_nua_rid(ldap_state, ldap_struct);
1077
1078         next_nua_rid = check_nua_rid_is_avail(ldap_state, 
1079                                               top_nua_rid, ldap_struct);
1080         
1081         ldap_unbind(ldap_struct);
1082         return next_nua_rid;
1083 }
1084
1085 /**********************************************************************
1086 Connect to LDAP server for password enumeration
1087 *********************************************************************/
1088 static BOOL ldapsam_setsampwent(struct pdb_methods *my_methods, BOOL update)
1089 {
1090         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
1091         int rc;
1092         pstring filter;
1093
1094         if (!ldapsam_open_connection(ldap_state, &ldap_state->ldap_struct))
1095         {
1096                 return False;
1097         }
1098         if (!ldapsam_connect_system(ldap_state, ldap_state->ldap_struct))
1099         {
1100                 ldap_unbind(ldap_state->ldap_struct);
1101                 return False;
1102         }
1103
1104         pstrcpy(filter, lp_ldap_filter());
1105         all_string_sub(filter, "%u", "*", sizeof(pstring));
1106
1107         rc = ldap_search_s(ldap_state->ldap_struct, lp_ldap_suffix(),
1108                            LDAP_SCOPE_SUBTREE, filter, attr, 0,
1109                            &ldap_state->result);
1110
1111         if (rc != LDAP_SUCCESS)
1112         {
1113                 DEBUG(0, ("LDAP search failed: %s\n", ldap_err2string(rc)));
1114                 DEBUG(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
1115                 ldap_msgfree(ldap_state->result);
1116                 ldap_unbind(ldap_state->ldap_struct);
1117                 ldap_state->ldap_struct = NULL;
1118                 ldap_state->result = NULL;
1119                 return False;
1120         }
1121
1122         DEBUG(2, ("ldapsam_setsampwent: %d entries in the base!\n",
1123                 ldap_count_entries(ldap_state->ldap_struct,
1124                 ldap_state->result)));
1125
1126         ldap_state->entry = ldap_first_entry(ldap_state->ldap_struct,
1127                                  ldap_state->result);
1128         ldap_state->index = 0;
1129
1130         return True;
1131 }
1132
1133 /**********************************************************************
1134 End enumeration of the LDAP password list 
1135 *********************************************************************/
1136 static void ldapsam_endsampwent(struct pdb_methods *my_methods)
1137 {
1138         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
1139         if (ldap_state->ldap_struct && ldap_state->result)
1140         {
1141                 ldap_msgfree(ldap_state->result);
1142                 ldap_unbind(ldap_state->ldap_struct);
1143                 ldap_state->ldap_struct = NULL;
1144                 ldap_state->result = NULL;
1145         }
1146 }
1147
1148 /**********************************************************************
1149 Get the next entry in the LDAP password database 
1150 *********************************************************************/
1151 static BOOL ldapsam_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT * user)
1152 {
1153         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
1154         BOOL ret = False;
1155
1156         while (!ret) {
1157                 if (!ldap_state->entry)
1158                         return False;
1159                 
1160                 ldap_state->index++;
1161                 ret = init_sam_from_ldap(ldap_state, user, ldap_state->ldap_struct,
1162                                          ldap_state->entry);
1163                 
1164                 ldap_state->entry = ldap_next_entry(ldap_state->ldap_struct,
1165                                             ldap_state->entry);
1166                 
1167         }
1168
1169         return True;
1170 }
1171
1172 /**********************************************************************
1173 Get SAM_ACCOUNT entry from LDAP by username 
1174 *********************************************************************/
1175 static BOOL ldapsam_getsampwnam(struct pdb_methods *my_methods, SAM_ACCOUNT * user, const char *sname)
1176 {
1177         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
1178         LDAP *ldap_struct;
1179         LDAPMessage *result;
1180         LDAPMessage *entry;
1181
1182         if (!ldapsam_open_connection(ldap_state, &ldap_struct))
1183                 return False;
1184         if (!ldapsam_connect_system(ldap_state, ldap_struct))
1185         {
1186                 ldap_unbind(ldap_struct);
1187                 return False;
1188         }
1189         if (ldapsam_search_one_user_by_name(ldap_state, ldap_struct, sname, &result) != LDAP_SUCCESS)
1190         {
1191                 ldap_unbind(ldap_struct);
1192                 return False;
1193         }
1194         if (ldap_count_entries(ldap_struct, result) < 1)
1195         {
1196                 DEBUG(4,
1197                       ("We don't find this user [%s] count=%d\n", sname,
1198                        ldap_count_entries(ldap_struct, result)));
1199                 ldap_unbind(ldap_struct);
1200                 return False;
1201         }
1202         entry = ldap_first_entry(ldap_struct, result);
1203         if (entry)
1204         {
1205                 if (!init_sam_from_ldap(ldap_state, user, ldap_struct, entry)) {
1206                         DEBUG(0,("ldapsam_getsampwnam: init_sam_from_ldap failed!\n"));
1207                         ldap_msgfree(result);
1208                         ldap_unbind(ldap_struct);
1209                         return False;
1210                 }
1211                 ldap_msgfree(result);
1212                 ldap_unbind(ldap_struct);
1213                 return True;
1214         }
1215         else
1216         {
1217                 ldap_msgfree(result);
1218                 ldap_unbind(ldap_struct);
1219                 return False;
1220         }
1221 }
1222
1223 /**********************************************************************
1224 Get SAM_ACCOUNT entry from LDAP by rid 
1225 *********************************************************************/
1226 static BOOL ldapsam_getsampwrid(struct pdb_methods *my_methods, SAM_ACCOUNT * user, uint32 rid)
1227 {
1228         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
1229         LDAP *ldap_struct;
1230         LDAPMessage *result;
1231         LDAPMessage *entry;
1232
1233         if (!ldapsam_open_connection(ldap_state, &ldap_struct))
1234                 return False;
1235
1236         if (!ldapsam_connect_system(ldap_state, ldap_struct))
1237         {
1238                 ldap_unbind(ldap_struct);
1239                 return False;
1240         }
1241         if (ldapsam_search_one_user_by_rid(ldap_state, ldap_struct, rid, &result) !=
1242             LDAP_SUCCESS)
1243         {
1244                 ldap_unbind(ldap_struct);
1245                 return False;
1246         }
1247
1248         if (ldap_count_entries(ldap_struct, result) < 1)
1249         {
1250                 DEBUG(0,
1251                       ("We don't find this rid [%i] count=%d\n", rid,
1252                        ldap_count_entries(ldap_struct, result)));
1253                 ldap_unbind(ldap_struct);
1254                 return False;
1255         }
1256
1257         entry = ldap_first_entry(ldap_struct, result);
1258         if (entry)
1259         {
1260                 if (!init_sam_from_ldap(ldap_state, user, ldap_struct, entry)) {
1261                         DEBUG(0,("ldapsam_getsampwrid: init_sam_from_ldap failed!\n"));
1262                         ldap_msgfree(result);
1263                         ldap_unbind(ldap_struct);
1264                         return False;
1265                 }
1266                 ldap_msgfree(result);
1267                 ldap_unbind(ldap_struct);
1268                 return True;
1269         }
1270         else
1271         {
1272                 ldap_msgfree(result);
1273                 ldap_unbind(ldap_struct);
1274                 return False;
1275         }
1276 }
1277
1278 static BOOL ldapsam_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT * user, DOM_SID *sid)
1279 {
1280         uint32 rid;
1281         if (!sid_peek_check_rid(get_global_sam_sid(), sid, &rid))
1282                 return False;
1283         return ldapsam_getsampwrid(my_methods, user, rid);
1284 }       
1285
1286 /**********************************************************************
1287 Delete entry from LDAP for username 
1288 *********************************************************************/
1289 static BOOL ldapsam_delete_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT * sam_acct)
1290 {
1291         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
1292         const char *sname;
1293         int rc;
1294         char *dn;
1295         LDAP *ldap_struct;
1296         LDAPMessage *entry;
1297         LDAPMessage *result;
1298
1299         if (!sam_acct) {
1300                 DEBUG(0, ("sam_acct was NULL!\n"));
1301                 return False;
1302         }
1303
1304         sname = pdb_get_username(sam_acct);
1305
1306         if (!ldapsam_open_connection(ldap_state, &ldap_struct))
1307                 return False;
1308
1309         DEBUG (3, ("Deleting user %s from LDAP.\n", sname));
1310         
1311         if (!ldapsam_connect_system(ldap_state, ldap_struct)) {
1312                 ldap_unbind (ldap_struct);
1313                 DEBUG(0, ("Failed to delete user %s from LDAP.\n", sname));
1314                 return False;
1315         }
1316
1317         rc = ldapsam_search_one_user_by_name(ldap_state, ldap_struct, sname, &result);
1318         if (ldap_count_entries (ldap_struct, result) == 0) {
1319                 DEBUG (0, ("User doesn't exit!\n"));
1320                 ldap_msgfree (result);
1321                 ldap_unbind (ldap_struct);
1322                 return False;
1323         }
1324
1325         entry = ldap_first_entry (ldap_struct, result);
1326         dn = ldap_get_dn (ldap_struct, entry);
1327
1328         rc = ldap_delete_s (ldap_struct, dn);
1329
1330         ldap_memfree (dn);
1331         if (rc != LDAP_SUCCESS) {
1332                 char *ld_error;
1333                 ldap_get_option (ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
1334                 DEBUG (0,("failed to delete user with uid = %s with: %s\n\t%s\n",
1335                         sname, ldap_err2string (rc), ld_error));
1336                 free (ld_error);
1337                 ldap_unbind (ldap_struct);
1338                 return False;
1339         }
1340
1341         DEBUG (2,("successfully deleted uid = %s from the LDAP database\n", sname));
1342         ldap_unbind (ldap_struct);
1343         return True;
1344 }
1345
1346 /**********************************************************************
1347 Update SAM_ACCOUNT 
1348 *********************************************************************/
1349 static BOOL ldapsam_update_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT * newpwd)
1350 {
1351         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
1352         int rc;
1353         char *dn;
1354         LDAP *ldap_struct;
1355         LDAPMessage *result;
1356         LDAPMessage *entry;
1357         LDAPMod **mods;
1358
1359         if (!ldapsam_open_connection(ldap_state, &ldap_struct)) /* open a connection to the server */
1360                 return False;
1361
1362         if (!ldapsam_connect_system(ldap_state, ldap_struct))   /* connect as system account */
1363         {
1364                 ldap_unbind(ldap_struct);
1365                 return False;
1366         }
1367
1368         rc = ldapsam_search_one_user_by_name(ldap_state, ldap_struct,
1369                                              pdb_get_username(newpwd), &result);
1370
1371         if (ldap_count_entries(ldap_struct, result) == 0)
1372         {
1373                 DEBUG(0, ("No user to modify!\n"));
1374                 ldap_msgfree(result);
1375                 ldap_unbind(ldap_struct);
1376                 return False;
1377         }
1378
1379         if (!init_ldap_from_sam(ldap_state, &mods, LDAP_MOD_REPLACE, newpwd)) {
1380                 DEBUG(0, ("ldapsam_update_sam_account: init_ldap_from_sam failed!\n"));
1381                 ldap_msgfree(result);
1382                 ldap_unbind(ldap_struct);
1383                 return False;
1384         }
1385
1386         entry = ldap_first_entry(ldap_struct, result);
1387         dn = ldap_get_dn(ldap_struct, entry);
1388
1389         rc = ldap_modify_s(ldap_struct, dn, mods);
1390
1391         if (rc != LDAP_SUCCESS)
1392         {
1393                 char *ld_error;
1394                 ldap_get_option(ldap_struct, LDAP_OPT_ERROR_STRING,
1395                                 &ld_error);
1396                 DEBUG(0,
1397                       ("failed to modify user with uid = %s with: %s\n\t%s\n",
1398                        pdb_get_username(newpwd), ldap_err2string(rc),
1399                        ld_error));
1400                 free(ld_error);
1401                 ldap_unbind(ldap_struct);
1402                 return False;
1403         }
1404
1405         DEBUG(2,
1406               ("successfully modified uid = %s in the LDAP database\n",
1407                pdb_get_username(newpwd)));
1408         ldap_mods_free(mods, 1);
1409         ldap_unbind(ldap_struct);
1410         return True;
1411 }
1412
1413 /**********************************************************************
1414 Add SAM_ACCOUNT to LDAP 
1415 *********************************************************************/
1416 static BOOL ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT * newpwd)
1417 {
1418         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
1419         int rc;
1420         pstring filter;
1421         LDAP *ldap_struct = NULL;
1422         LDAPMessage *result = NULL;
1423         pstring dn;
1424         LDAPMod **mods = NULL;
1425         int             ldap_op;
1426         uint32          num_result;
1427
1428         const char *username = pdb_get_username(newpwd);
1429         if (!username || !*username) {
1430                 DEBUG(0, ("Cannot add user without a username!\n"));
1431                 return False;
1432         }
1433
1434         if (!ldapsam_open_connection(ldap_state, &ldap_struct)) /* open a connection to the server */
1435         {
1436                 return False;
1437         }
1438
1439         if (!ldapsam_connect_system(ldap_state, ldap_struct))   /* connect as system account */
1440         {
1441                 ldap_unbind(ldap_struct);
1442                 return False;
1443         }
1444
1445         rc = ldapsam_search_one_user_by_name (ldap_state, ldap_struct, username, &result);
1446
1447         if (ldap_count_entries(ldap_struct, result) != 0)
1448         {
1449                 DEBUG(0,("User already in the base, with samba properties\n"));
1450                 ldap_msgfree(result);
1451                 ldap_unbind(ldap_struct);
1452                 return False;
1453         }
1454         ldap_msgfree(result);
1455
1456         slprintf (filter, sizeof (filter) - 1, "uid=%s", username);
1457         rc = ldapsam_search_one_user(ldap_state, ldap_struct, filter, &result);
1458         num_result = ldap_count_entries(ldap_struct, result);
1459         
1460         if (num_result > 1) {
1461                 DEBUG (0, ("More than one user with that uid exists: bailing out!\n"));
1462                 ldap_msgfree(result);
1463                 return False;
1464         }
1465         
1466         /* Check if we need to update an existing entry */
1467         if (num_result == 1) {
1468                 char *tmp;
1469                 LDAPMessage *entry;
1470                 
1471                 DEBUG(3,("User exists without samba properties: adding them\n"));
1472                 ldap_op = LDAP_MOD_REPLACE;
1473                 entry = ldap_first_entry (ldap_struct, result);
1474                 tmp = ldap_get_dn (ldap_struct, entry);
1475                 slprintf (dn, sizeof (dn) - 1, "%s", tmp);
1476                 ldap_memfree (tmp);
1477         }
1478         else {
1479                 /* Check if we need to add an entry */
1480                 DEBUG(3,("Adding new user\n"));
1481                 ldap_op = LDAP_MOD_ADD;
1482                 if (username[strlen(username)-1] == '$') {
1483                         slprintf (dn, sizeof (dn) - 1, "uid=%s,%s", username, lp_ldap_machine_suffix ());
1484                 } else {
1485                         slprintf (dn, sizeof (dn) - 1, "uid=%s,%s", username, lp_ldap_user_suffix ());
1486                 }
1487         }
1488
1489         ldap_msgfree(result);
1490
1491         if (!init_ldap_from_sam(ldap_state, &mods, ldap_op, newpwd)) {
1492                 DEBUG(0, ("ldapsam_add_sam_account: init_ldap_from_sam failed!\n"));
1493                 ldap_mods_free(mods, 1);
1494                 ldap_unbind(ldap_struct);
1495                 return False;           
1496         }
1497         make_a_mod(&mods, LDAP_MOD_ADD, "objectclass", "sambaAccount");
1498
1499         if (ldap_op == LDAP_MOD_REPLACE) {
1500                 rc = ldap_modify_s(ldap_struct, dn, mods);
1501         }
1502         else {
1503                 rc = ldap_add_s(ldap_struct, dn, mods);
1504         }
1505
1506         if (rc != LDAP_SUCCESS)
1507         {
1508                 char *ld_error;
1509
1510                 ldap_get_option (ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
1511                 DEBUG(0,("failed to modify/add user with uid = %s (dn = %s) with: %s\n\t%s\n",
1512                         pdb_get_username(newpwd), dn, ldap_err2string (rc), ld_error));
1513                 free(ld_error);
1514                 ldap_mods_free(mods, 1);
1515                 ldap_unbind(ldap_struct);
1516                 return False;
1517         }
1518         
1519         DEBUG(2,("added: uid = %s in the LDAP database\n", pdb_get_username(newpwd)));
1520         ldap_mods_free(mods, 1);
1521         ldap_unbind(ldap_struct);
1522         return True;
1523 }
1524
1525 static void free_private_data(void **vp) 
1526 {
1527         struct ldapsam_privates **ldap_state = (struct ldapsam_privates **)vp;
1528
1529         if ((*ldap_state)->ldap_struct) {
1530                 ldap_unbind((*ldap_state)->ldap_struct);
1531         }
1532
1533         *ldap_state = NULL;
1534
1535         /* No need to free any further, as it is talloc()ed */
1536 }
1537
1538 NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
1539 {
1540         NTSTATUS nt_status;
1541         struct ldapsam_privates *ldap_state;
1542
1543         if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
1544                 return nt_status;
1545         }
1546
1547         (*pdb_method)->name = "ldapsam";
1548
1549         (*pdb_method)->setsampwent = ldapsam_setsampwent;
1550         (*pdb_method)->endsampwent = ldapsam_endsampwent;
1551         (*pdb_method)->getsampwent = ldapsam_getsampwent;
1552         (*pdb_method)->getsampwnam = ldapsam_getsampwnam;
1553         (*pdb_method)->getsampwsid = ldapsam_getsampwsid;
1554         (*pdb_method)->add_sam_account = ldapsam_add_sam_account;
1555         (*pdb_method)->update_sam_account = ldapsam_update_sam_account;
1556         (*pdb_method)->delete_sam_account = ldapsam_delete_sam_account;
1557
1558         /* TODO: Setup private data and free */
1559
1560         ldap_state = talloc_zero(pdb_context->mem_ctx, sizeof(struct ldapsam_privates));
1561
1562         if (!ldap_state) {
1563                 DEBUG(0, ("talloc() failed for ldapsam private_data!\n"));
1564                 return NT_STATUS_NO_MEMORY;
1565         }
1566
1567         if (location) {
1568                 ldap_state->uri = talloc_strdup(pdb_context->mem_ctx, location);
1569         } else {
1570                 ldap_state->uri = "ldap://localhost";
1571         }
1572
1573         (*pdb_method)->private_data = ldap_state;
1574
1575         (*pdb_method)->free_private_data = free_private_data;
1576
1577         return NT_STATUS_OK;
1578 }
1579
1580 NTSTATUS pdb_init_ldapsam_nua(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
1581 {
1582         NTSTATUS nt_status;
1583         struct ldapsam_privates *ldap_state;
1584         uint32 low_nua_uid, high_nua_uid;
1585
1586         if (!NT_STATUS_IS_OK(nt_status = pdb_init_ldapsam(pdb_context, pdb_method, location))) {
1587                 return nt_status;
1588         }
1589
1590         (*pdb_method)->name = "ldapsam_nua";
1591
1592         ldap_state = (*pdb_method)->private_data;
1593         
1594         ldap_state->permit_non_unix_accounts = True;
1595
1596         if (!lp_non_unix_account_range(&low_nua_uid, &high_nua_uid)) {
1597                 DEBUG(0, ("cannot use ldapsam_nua without 'non unix account range' in smb.conf!\n"));
1598                 return NT_STATUS_UNSUCCESSFUL;
1599         }
1600
1601         ldap_state->low_nua_rid=fallback_pdb_uid_to_user_rid(low_nua_uid);
1602
1603         ldap_state->high_nua_rid=fallback_pdb_uid_to_user_rid(high_nua_uid);
1604
1605         return NT_STATUS_OK;
1606 }
1607
1608
1609 #else
1610
1611 NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
1612 {
1613         DEBUG(0, ("ldap not detected at configure time, ldapsam not availalble!\n"));
1614         return NT_STATUS_UNSUCCESSFUL;
1615 }
1616
1617 NTSTATUS pdb_init_ldapsam_nua(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
1618 {
1619         DEBUG(0, ("ldap not dectected at configure time, ldapsam_nua not available!\n"));
1620         return NT_STATUS_UNSUCCESSFUL;
1621 }
1622
1623
1624 #endif