spelling
[ira/wip.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
6    Copyright (C) Shahms King                    2001
7    Copyright (C) Andrew Bartlett                2002
8    Copyright (C) Stefan (metze) Metzmacher      2002
9     
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14    
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19    
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23    
24 */
25
26 #include "includes.h"
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_PASSDB
30
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 LDAP_OPT_SUCCESS
55 #define LDAP_OPT_SUCCESS 0
56 #endif
57
58 #ifndef SAM_ACCOUNT
59 #define SAM_ACCOUNT struct sam_passwd
60 #endif
61
62 struct ldapsam_privates {
63         /* Former statics */
64         LDAP *ldap_struct;
65         LDAPMessage *result;
66         LDAPMessage *entry;
67         int index;
68         
69         time_t last_ping;
70         /* retrive-once info */
71         const char *uri;
72         const char *domain_name;
73         DOM_SID domain_sid;
74         
75         /* configuration items */
76         BOOL use_ntsid;
77
78         BOOL permit_non_unix_accounts;
79         
80         uint32 low_allocated_user_rid; 
81         uint32 high_allocated_user_rid; 
82
83         uint32 low_allocated_group_rid; 
84         uint32 high_allocated_group_rid; 
85
86         char *bind_dn;
87         char *bind_secret;
88
89         unsigned int num_failures;
90 };
91
92 #define LDAPSAM_DONT_PING_TIME 10       /* ping only all 10 seconds */
93
94 static struct ldapsam_privates *static_ldap_state;
95
96 /*******************************************************************
97  find the ldap password
98 ******************************************************************/
99 static BOOL fetch_ldapsam_pw(char **dn, char** pw)
100 {
101         char *key = NULL;
102         size_t size;
103         
104         *dn = smb_xstrdup(lp_ldap_admin_dn());
105         
106         if (asprintf(&key, "%s/%s", SECRETS_LDAP_BIND_PW, *dn) < 0) {
107                 SAFE_FREE(*dn);
108                 DEBUG(0, ("fetch_ldapsam_pw: asprintf failed!\n"));
109         }
110         
111         *pw=secrets_fetch(key, &size);
112         SAFE_FREE(key);
113
114         if (!size) {
115                 /* Upgrade 2.2 style entry */
116                 char *p;
117                 char* old_style_key = strdup(*dn);
118                 char *data;
119                 fstring old_style_pw;
120                 
121                 if (!old_style_key) {
122                         DEBUG(0, ("fetch_ldapsam_pw: strdup failed!\n"));
123                         return False;
124                 }
125
126                 for (p=old_style_key; *p; p++)
127                         if (*p == ',') *p = '/';
128         
129                 data=secrets_fetch(old_style_key, &size);
130                 if (!size && size < sizeof(old_style_pw)) {
131                         DEBUG(0,("fetch_ldap_pw: neither ldap secret retrieved!\n"));
132                         SAFE_FREE(old_style_key);
133                         SAFE_FREE(*dn);
134                         return False;
135                 }
136
137                 strncpy(old_style_pw, data, size);
138                 old_style_pw[size] = 0;
139
140                 SAFE_FREE(data);
141
142                 if (!secrets_store_ldap_pw(*dn, old_style_pw)) {
143                         DEBUG(0,("fetch_ldap_pw: ldap secret could not be upgraded!\n"));
144                         SAFE_FREE(old_style_key);
145                         SAFE_FREE(*dn);
146                         return False;                   
147                 }
148                 if (!secrets_delete(old_style_key)) {
149                         DEBUG(0,("fetch_ldap_pw: old ldap secret could not be deleted!\n"));
150                 }
151
152                 SAFE_FREE(old_style_key);
153
154                 *pw = smb_xstrdup(old_style_pw);                
155         }
156         
157         return True;
158 }
159
160 static const char *attr[] = {"uid", "pwdLastSet", "logonTime",
161                              "logoffTime", "kickoffTime", "cn",
162                              "pwdCanChange", "pwdMustChange",
163                              "displayName", "homeDrive",
164                              "smbHome", "scriptPath",
165                              "profilePath", "description",
166                              "userWorkstations", "rid", "ntSid",
167                              "primaryGroupID", "lmPassword",
168                              "ntPassword", "acctFlags",
169                              "domain", "objectClass", 
170                              "uidNumber", "gidNumber", 
171                              "homeDirectory", NULL };
172
173 static const char *domain_info_attrs[] = {"domain", "nextUserRid", 
174                                           "nextGroupRid", "ntSid", NULL };
175
176 /*******************************************************************
177  open a connection to the ldap server.
178 ******************************************************************/
179 static int ldapsam_open_connection (struct ldapsam_privates *ldap_state, LDAP ** ldap_struct)
180 {
181         int rc = LDAP_SUCCESS;
182         int version;
183         BOOL ldap_v3 = False;
184
185 #ifdef HAVE_LDAP_INITIALIZE
186         DEBUG(10, ("ldapsam_open_connection: %s\n", ldap_state->uri));
187         
188         if ((rc = ldap_initialize(ldap_struct, ldap_state->uri)) != LDAP_SUCCESS) {
189                 DEBUG(0, ("ldap_initialize: %s\n", ldap_err2string(rc)));
190                 return rc;
191         }
192         
193 #else 
194
195         /* Parse the string manually */
196
197         {
198                 int port = 0;
199                 fstring protocol;
200                 fstring host;
201                 const char *p = ldap_state->uri; 
202                 SMB_ASSERT(sizeof(protocol)>10 && sizeof(host)>254);
203                 
204                 /* skip leading "URL:" (if any) */
205                 if ( strncasecmp( p, "URL:", 4 ) == 0 ) {
206                         p += 4;
207                 }
208                 
209                 sscanf(p, "%10[^:]://%254s[^:]:%d", protocol, host, &port);
210                 
211                 if (port == 0) {
212                         if (strequal(protocol, "ldap")) {
213                                 port = LDAP_PORT;
214                         } else if (strequal(protocol, "ldaps")) {
215                                 port = LDAPS_PORT;
216                         } else {
217                                 DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
218                         }
219                 }
220                 
221                 if ((*ldap_struct = ldap_init(host, port)) == NULL)     {
222                         DEBUG(0, ("ldap_init failed !\n"));
223                         return LDAP_OPERATIONS_ERROR;
224                 }
225                 
226                 if (strequal(protocol, "ldaps")) {
227 #ifdef LDAP_OPT_X_TLS
228                         int tls = LDAP_OPT_X_TLS_HARD;
229                         if (ldap_set_option (*ldap_struct, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
230                         {
231                                 DEBUG(0, ("Failed to setup a TLS session\n"));
232                         }
233                         
234                         DEBUG(3,("LDAPS option set...!\n"));
235 #else
236                         DEBUG(0,("ldapsam_open_connection: Secure connection not supported by LDAP client libraries!\n"));
237                         return LDAP_OPERATIONS_ERROR;
238 #endif
239                 }
240         }
241 #endif
242
243         if (ldap_get_option(*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS)
244         {
245                 if (version != LDAP_VERSION3)
246                 {
247                         version = LDAP_VERSION3;
248                         if (ldap_set_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS) {
249                                 ldap_v3 = True;
250                         }
251                 } else {
252                         ldap_v3 = True;
253                 }
254         }
255
256         if (lp_ldap_ssl() == LDAP_SSL_START_TLS) {
257 #ifdef LDAP_OPT_X_TLS
258                 if (ldap_v3) {
259                         if ((rc = ldap_start_tls_s (*ldap_struct, NULL, NULL)) != LDAP_SUCCESS)
260                         {
261                                 DEBUG(0,("Failed to issue the StartTLS instruction: %s\n",
262                                          ldap_err2string(rc)));
263                                 return rc;
264                         }
265                         DEBUG (3, ("StartTLS issued: using a TLS connection\n"));
266                 } else {
267                         
268                         DEBUG(0, ("Need LDAPv3 for Start TLS\n"));
269                         return LDAP_OPERATIONS_ERROR;
270                 }
271 #else
272                 DEBUG(0,("ldapsam_open_connection: StartTLS not supported by LDAP client libraries!\n"));
273                 return LDAP_OPERATIONS_ERROR;
274 #endif
275         }
276
277         DEBUG(2, ("ldapsam_open_connection: connection opened\n"));
278         return rc;
279 }
280
281
282 /*******************************************************************
283  a rebind function for authenticated referrals
284  This version takes a void* that we can shove useful stuff in :-)
285 ******************************************************************/
286 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
287 #else
288 static int rebindproc_with_state  (LDAP * ld, char **whop, char **credp, 
289                                    int *methodp, int freeit, void *arg)
290 {
291         struct ldapsam_privates *ldap_state = arg;
292         
293         /** @TODO Should we be doing something to check what servers we rebind to?
294             Could we get a referral to a machine that we don't want to give our
295             username and password to? */
296         
297         if (freeit) {
298                 SAFE_FREE(*whop);
299                 memset(*credp, '\0', strlen(*credp));
300                 SAFE_FREE(*credp);
301         } else {
302                 DEBUG(5,("rebind_proc_with_state: Rebinding as \"%s\"\n", 
303                           ldap_state->bind_dn));
304
305                 *whop = strdup(ldap_state->bind_dn);
306                 if (!*whop) {
307                         return LDAP_NO_MEMORY;
308                 }
309                 *credp = strdup(ldap_state->bind_secret);
310                 if (!*credp) {
311                         SAFE_FREE(*whop);
312                         return LDAP_NO_MEMORY;
313                 }
314                 *methodp = LDAP_AUTH_SIMPLE;
315         }
316         return 0;
317 }
318 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
319
320 /*******************************************************************
321  a rebind function for authenticated referrals
322  This version takes a void* that we can shove useful stuff in :-)
323  and actually does the connection.
324 ******************************************************************/
325 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
326 static int rebindproc_connect_with_state (LDAP *ldap_struct, 
327                                           LDAP_CONST char *url, 
328                                           ber_tag_t request,
329                                           ber_int_t msgid, void *arg)
330 {
331         struct ldapsam_privates *ldap_state = arg;
332         int rc;
333         DEBUG(5,("rebindproc_connect_with_state: Rebinding as \"%s\"\n", 
334                  ldap_state->bind_dn));
335         
336         /** @TODO Should we be doing something to check what servers we rebind to?
337             Could we get a referral to a machine that we don't want to give our
338             username and password to? */
339
340         rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
341         
342         return rc;
343 }
344 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
345
346 /*******************************************************************
347  Add a rebind function for authenticated referrals
348 ******************************************************************/
349 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
350 #else
351 # if LDAP_SET_REBIND_PROC_ARGS == 2
352 static int rebindproc (LDAP *ldap_struct, char **whop, char **credp,
353                        int *method, int freeit )
354 {
355         return rebindproc_with_state(ldap_struct, whop, credp,
356                                    method, freeit, static_ldap_state);
357         
358 }
359 # endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
360 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
361
362 /*******************************************************************
363  a rebind function for authenticated referrals
364  this also does the connection, but no void*.
365 ******************************************************************/
366 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
367 # if LDAP_SET_REBIND_PROC_ARGS == 2
368 static int rebindproc_connect (LDAP * ld, LDAP_CONST char *url, int request,
369                                ber_int_t msgid)
370 {
371         return rebindproc_connect_with_state(ld, url, (ber_tag_t)request, msgid, 
372                                              static_ldap_state);
373 }
374 # endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
375 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
376
377 /*******************************************************************
378  connect to the ldap server under system privilege.
379 ******************************************************************/
380 static int ldapsam_connect_system(struct ldapsam_privates *ldap_state, LDAP * ldap_struct)
381 {
382         int rc;
383         char *ldap_dn;
384         char *ldap_secret;
385
386         /* The rebind proc needs this *HACK*.  We are not multithreaded, so
387            this will work, but it's not nice. */
388         static_ldap_state = ldap_state;
389
390         /* get the password */
391         if (!fetch_ldapsam_pw(&ldap_dn, &ldap_secret))
392         {
393                 DEBUG(0, ("ldap_connect_system: Failed to retrieve password from secrets.tdb\n"));
394                 return LDAP_INVALID_CREDENTIALS;
395         }
396
397         ldap_state->bind_dn = ldap_dn;
398         ldap_state->bind_secret = ldap_secret;
399
400         /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite 
401            (OpenLDAP) doesnt' seem to support it */
402            
403         DEBUG(10,("ldap_connect_system: Binding to ldap server %s as \"%s\"\n",
404                   ldap_state->uri, ldap_dn));
405
406 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
407 # if LDAP_SET_REBIND_PROC_ARGS == 2     
408         ldap_set_rebind_proc(ldap_struct, &rebindproc_connect); 
409 # endif
410 # if LDAP_SET_REBIND_PROC_ARGS == 3     
411         ldap_set_rebind_proc(ldap_struct, &rebindproc_connect_with_state, (void *)ldap_state);  
412 # endif
413 #else /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
414 # if LDAP_SET_REBIND_PROC_ARGS == 2     
415         ldap_set_rebind_proc(ldap_struct, &rebindproc); 
416 # endif
417 # if LDAP_SET_REBIND_PROC_ARGS == 3     
418         ldap_set_rebind_proc(ldap_struct, &rebindproc_with_state, (void *)ldap_state);  
419 # endif
420 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
421
422         rc = ldap_simple_bind_s(ldap_struct, ldap_dn, ldap_secret);
423
424         if (rc != LDAP_SUCCESS) {
425                 char *ld_error = NULL;
426                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
427                                 &ld_error);
428                 DEBUG(ldap_state->num_failures ? 2 : 0,
429                       ("failed to bind to server with dn= %s Error: %s\n\t%s\n",
430                                ldap_dn ? ld_error : "(unknown)", ldap_err2string(rc),
431                                ld_error));
432                 SAFE_FREE(ld_error);
433                 ldap_state->num_failures++;
434                 return rc;
435         }
436
437         ldap_state->num_failures = 0;
438
439         DEBUG(3, ("ldap_connect_system: succesful connection to the LDAP server\n"));
440         return rc;
441 }
442
443 /**********************************************************************
444 Connect to LDAP server 
445 *********************************************************************/
446 static int ldapsam_open(struct ldapsam_privates *ldap_state)
447 {
448         int rc;
449         SMB_ASSERT(ldap_state);
450                 
451 #ifndef NO_LDAP_SECURITY
452         if (geteuid() != 0) {
453                 DEBUG(0, ("ldapsam_open: cannot access LDAP when not root..\n"));
454                 return  LDAP_INSUFFICIENT_ACCESS;
455         }
456 #endif
457
458         if ((ldap_state->ldap_struct != NULL) && ((ldap_state->last_ping + LDAPSAM_DONT_PING_TIME) < time(NULL))) {
459                 struct sockaddr_un addr;
460                 socklen_t len = sizeof(addr);
461                 int sd;
462                 if (ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_DESC, &sd) == 0 &&
463                     getpeername(sd, (struct sockaddr *) &addr, &len) < 0) {
464                         /* the other end has died. reopen. */
465                         ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
466                         ldap_state->ldap_struct = NULL;
467                         ldap_state->last_ping = (time_t)0;
468                 } else {
469                         ldap_state->last_ping = time(NULL);
470                 } 
471         }
472
473         if (ldap_state->ldap_struct != NULL) {
474                 DEBUG(5,("ldapsam_open: already connected to the LDAP server\n"));
475                 return LDAP_SUCCESS;
476         }
477
478         if ((rc = ldapsam_open_connection(ldap_state, &ldap_state->ldap_struct))) {
479                 return rc;
480         }
481
482         if ((rc = ldapsam_connect_system(ldap_state, ldap_state->ldap_struct))) {
483                 ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
484                 ldap_state->ldap_struct = NULL;
485                 return rc;
486         }
487
488
489         ldap_state->last_ping = time(NULL);
490         DEBUG(4,("The LDAP server is succesful connected\n"));
491
492         return LDAP_SUCCESS;
493 }
494
495 /**********************************************************************
496 Disconnect from LDAP server 
497 *********************************************************************/
498 static NTSTATUS ldapsam_close(struct ldapsam_privates *ldap_state)
499 {
500         if (!ldap_state)
501                 return NT_STATUS_INVALID_PARAMETER;
502                 
503         if (ldap_state->ldap_struct != NULL) {
504                 ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
505                 ldap_state->ldap_struct = NULL;
506         }
507         
508         DEBUG(5,("The connection to the LDAP server was closed\n"));
509         /* maybe free the results here --metze */
510         
511         return NT_STATUS_OK;
512 }
513
514 static int ldapsam_retry_open(struct ldapsam_privates *ldap_state, int *attempts)
515 {
516         int rc;
517
518         SMB_ASSERT(ldap_state && attempts);
519                 
520         if (*attempts != 0) {
521                 unsigned int sleep_time;
522                 uint8 rand_byte = 128; /* a reasonable place to start */
523
524                 generate_random_buffer(&rand_byte, 1, False);
525
526                 sleep_time = (((*attempts)*(*attempts))/2)*rand_byte*2; 
527                 /* we retry after (0.5, 1, 2, 3, 4.5, 6) seconds
528                    on average.  
529                  */
530                 DEBUG(3, ("Sleeping for %u milliseconds before reconnecting\n", 
531                           sleep_time));
532                 msleep(sleep_time);
533         }
534         (*attempts)++;
535
536         if ((rc = ldapsam_open(ldap_state))) {
537                 DEBUG(1,("Connection to LDAP Server failed for the %d try!\n",*attempts));
538                 return rc;
539         } 
540         
541         return LDAP_SUCCESS;            
542 }
543
544
545 static int ldapsam_search(struct ldapsam_privates *ldap_state, 
546                           const char *base, int scope, const char *filter, 
547                           const char *attrs[], int attrsonly, 
548                           LDAPMessage **res)
549 {
550         int             rc = LDAP_SERVER_DOWN;
551         int             attempts = 0;
552         char           *utf8_filter;
553
554         SMB_ASSERT(ldap_state);
555
556         if (push_utf8_allocate(&utf8_filter, filter) == (size_t)-1) {
557                 return LDAP_NO_MEMORY;
558         }
559
560         while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
561                 
562                 if ((rc = ldapsam_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
563                         continue;
564                 
565                 rc = ldap_search_s(ldap_state->ldap_struct, base, scope, 
566                                    utf8_filter, (char **)attrs, attrsonly, res);
567         }
568         
569         if (rc == LDAP_SERVER_DOWN) {
570                 DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
571                 ldapsam_close(ldap_state);      
572         }
573
574         SAFE_FREE(utf8_filter);
575         return rc;
576 }
577
578 static int ldapsam_modify(struct ldapsam_privates *ldap_state, const char *dn, LDAPMod *attrs[])
579 {
580         int             rc = LDAP_SERVER_DOWN;
581         int             attempts = 0;
582         char           *utf8_dn;
583
584         SMB_ASSERT(ldap_state);
585
586         if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
587                 return LDAP_NO_MEMORY;
588         }
589
590         while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
591                 
592                 if ((rc = ldapsam_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
593                         continue;
594                 
595                 rc = ldap_modify_s(ldap_state->ldap_struct, utf8_dn, attrs);
596         }
597         
598         if (rc == LDAP_SERVER_DOWN) {
599                 DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
600                 ldapsam_close(ldap_state);      
601         }
602         
603         SAFE_FREE(utf8_dn);
604         return rc;
605 }
606
607 static int ldapsam_add(struct ldapsam_privates *ldap_state, const char *dn, LDAPMod *attrs[])
608 {
609         int             rc = LDAP_SERVER_DOWN;
610         int             attempts = 0;
611         char           *utf8_dn;
612         
613         SMB_ASSERT(ldap_state);
614
615         if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
616                 return LDAP_NO_MEMORY;
617         }
618
619         while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
620                 
621                 if ((rc = ldapsam_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
622                         continue;
623                 
624                 rc = ldap_add_s(ldap_state->ldap_struct, utf8_dn, attrs);
625         }
626         
627         if (rc == LDAP_SERVER_DOWN) {
628                 DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
629                 ldapsam_close(ldap_state);      
630         }
631                 
632         SAFE_FREE(utf8_dn);
633         return rc;
634 }
635
636 static int ldapsam_delete(struct ldapsam_privates *ldap_state, char *dn)
637 {
638         int             rc = LDAP_SERVER_DOWN;
639         int             attempts = 0;
640         char           *utf8_dn;
641         
642         SMB_ASSERT(ldap_state);
643
644         if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
645                 return LDAP_NO_MEMORY;
646         }
647
648         while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
649                 
650                 if ((rc = ldapsam_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
651                         continue;
652                 
653                 rc = ldap_delete_s(ldap_state->ldap_struct, utf8_dn);
654         }
655         
656         if (rc == LDAP_SERVER_DOWN) {
657                 DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
658                 ldapsam_close(ldap_state);      
659         }
660                 
661         SAFE_FREE(utf8_dn);
662         return rc;
663 }
664
665 #ifdef LDAP_EXOP_X_MODIFY_PASSWD
666 static int ldapsam_extended_operation(struct ldapsam_privates *ldap_state, LDAP_CONST char *reqoid, struct berval *reqdata, LDAPControl **serverctrls, LDAPControl **clientctrls, char **retoidp, struct berval **retdatap)
667 {
668         int             rc = LDAP_SERVER_DOWN;
669         int             attempts = 0;
670         
671         if (!ldap_state)
672                 return (-1);
673
674         while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
675                 
676                 if ((rc = ldapsam_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
677                         continue;
678                 
679                 rc = ldap_extended_operation_s(ldap_state->ldap_struct, reqoid, reqdata, serverctrls, clientctrls, retoidp, retdatap);
680         }
681         
682         if (rc == LDAP_SERVER_DOWN) {
683                 DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
684                 ldapsam_close(ldap_state);      
685         }
686                 
687         return rc;
688 }
689 #endif
690
691 /*******************************************************************
692  run the search by name.
693 ******************************************************************/
694 static int ldapsam_search_suffix (struct ldapsam_privates *ldap_state, const char *filter, const char **search_attr, LDAPMessage ** result)
695 {
696         int scope = LDAP_SCOPE_SUBTREE;
697         int rc;
698
699         DEBUG(2, ("ldapsam_search_suffix: searching for:[%s]\n", filter));
700
701         rc = ldapsam_search(ldap_state, lp_ldap_suffix (), scope, filter, search_attr, 0, result);
702
703         if (rc != LDAP_SUCCESS) {
704                 char *ld_error = NULL;
705                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
706                                 &ld_error);
707                 DEBUG(0,("ldapsam_search_suffix: Problem during the LDAP search: %s (%s)\n", 
708                         ld_error?ld_error:"(unknown)", ldap_err2string (rc)));
709                 DEBUG(3,("ldapsam_search_suffix: Query was: %s, %s\n", lp_ldap_suffix(), 
710                         filter));
711                 SAFE_FREE(ld_error);
712         }
713         
714         return rc;
715 }
716
717 /*******************************************************************
718  run the search by name.
719 ******************************************************************/
720 static int ldapsam_search_suffix_by_name (struct ldapsam_privates *ldap_state, const char *user,
721                              LDAPMessage ** result)
722 {
723         pstring filter;
724         char *escape_user = escape_ldap_string_alloc(user);
725
726         if (!escape_user) {
727                 return LDAP_NO_MEMORY;
728         }
729
730         /*
731          * in the filter expression, replace %u with the real name
732          * so in ldap filter, %u MUST exist :-)
733          */
734         pstrcpy(filter, lp_ldap_filter());
735
736         /* 
737          * have to use this here because $ is filtered out
738            * in pstring_sub
739          */
740         
741
742         all_string_sub(filter, "%u", escape_user, sizeof(pstring));
743         SAFE_FREE(escape_user);
744
745         return ldapsam_search_suffix(ldap_state, filter, attr, result);
746 }
747
748 /*******************************************************************
749  run the search by rid.
750 ******************************************************************/
751 static int ldapsam_search_suffix_by_rid (struct ldapsam_privates *ldap_state, 
752                                            uint32 rid,
753                                            LDAPMessage ** result)
754 {
755         pstring filter;
756         int rc;
757
758         /* check if the user rid exsists, if not, try searching on the uid */
759         
760         snprintf(filter, sizeof(filter) - 1, "rid=%i", rid);
761         rc = ldapsam_search_suffix(ldap_state, filter, attr, result);
762         
763         return rc;
764 }
765
766 /*******************************************************************
767  run the search by SID.
768 ******************************************************************/
769 static int ldapsam_search_suffix_by_sid (struct ldapsam_privates *ldap_state, 
770                                            const DOM_SID *sid,
771                                            LDAPMessage ** result)
772 {
773         pstring filter;
774         int rc;
775         fstring sid_string;
776
777         /* check if the user rid exsists, if not, try searching on the uid */
778
779         snprintf(filter, sizeof(filter) - 1, "ntSid=%s", sid_to_string(sid_string, sid));
780         rc = ldapsam_search_suffix(ldap_state, filter, attr, result);
781         
782         return rc;
783 }
784
785 /*******************************************************************
786 search an attribute and return the first value found.
787 ******************************************************************/
788 static BOOL get_single_attribute (LDAP * ldap_struct, LDAPMessage * entry,
789                                   const char *attribute, pstring value)
790 {
791         char **values;
792         value[0] = '\0';
793
794         if ((values = ldap_get_values (ldap_struct, entry, attribute)) == NULL) {
795                 DEBUG (10, ("get_single_attribute: [%s] = [<does not exist>]\n", attribute));
796                 
797                 return False;
798         }
799         
800         if (convert_string(CH_UTF8, CH_UNIX,
801                 values[0], -1,
802                 value, sizeof(pstring)) == (size_t)-1)
803         {
804                 DEBUG(1, ("get_single_attribute: string conversion of [%s] = [%s] failed!\n", 
805                           attribute, values[0]));
806                 ldap_value_free(values);
807                 return False;
808         }
809         
810         ldap_value_free(values);
811 #ifdef DEBUG_PASSWORDS
812         DEBUG (100, ("get_single_attribute: [%s] = [%s]\n", attribute, value));
813 #endif  
814         return True;
815 }
816
817 /************************************************************************
818 Routine to manage the LDAPMod structure array
819 manage memory used by the array, by each struct, and values
820
821 ************************************************************************/
822 static void make_a_mod (LDAPMod *** modlist, int modop, const char *attribute, const char *value)
823 {
824         LDAPMod **mods;
825         int i;
826         int j;
827
828         mods = *modlist;
829
830         if (attribute == NULL || *attribute == '\0')
831                 return;
832
833 #if 0
834         /* Why do we need this??? -- vl */
835         if (value == NULL || *value == '\0')
836                 return;
837 #endif
838
839         if (mods == NULL) 
840         {
841                 mods = (LDAPMod **) malloc(sizeof(LDAPMod *));
842                 if (mods == NULL)
843                 {
844                         DEBUG(0, ("make_a_mod: out of memory!\n"));
845                         return;
846                 }
847                 mods[0] = NULL;
848         }
849
850         for (i = 0; mods[i] != NULL; ++i) {
851                 if (mods[i]->mod_op == modop && !strcasecmp(mods[i]->mod_type, attribute))
852                         break;
853         }
854
855         if (mods[i] == NULL)
856         {
857                 mods = (LDAPMod **) Realloc (mods, (i + 2) * sizeof (LDAPMod *));
858                 if (mods == NULL)
859                 {
860                         DEBUG(0, ("make_a_mod: out of memory!\n"));
861                         return;
862                 }
863                 mods[i] = (LDAPMod *) malloc(sizeof(LDAPMod));
864                 if (mods[i] == NULL)
865                 {
866                         DEBUG(0, ("make_a_mod: out of memory!\n"));
867                         return;
868                 }
869                 mods[i]->mod_op = modop;
870                 mods[i]->mod_values = NULL;
871                 mods[i]->mod_type = strdup(attribute);
872                 mods[i + 1] = NULL;
873         }
874
875         if (value != NULL)
876         {
877                 char *utf8_value = NULL;
878
879                 j = 0;
880                 if (mods[i]->mod_values != NULL) {
881                         for (; mods[i]->mod_values[j] != NULL; j++);
882                 }
883                 mods[i]->mod_values = (char **)Realloc(mods[i]->mod_values,
884                                                (j + 2) * sizeof (char *));
885                                                
886                 if (mods[i]->mod_values == NULL) {
887                         DEBUG (0, ("make_a_mod: Memory allocation failure!\n"));
888                         return;
889                 }
890
891                 if (push_utf8_allocate(&utf8_value, value) == (size_t)-1) {
892                         DEBUG (0, ("make_a_mod: String conversion failure!\n"));
893                         return;
894                 }
895
896                 mods[i]->mod_values[j] = utf8_value;
897
898                 mods[i]->mod_values[j + 1] = NULL;
899         }
900         *modlist = mods;
901 }
902
903 /**********************************************************************
904   Set attribute to newval in LDAP, regardless of what value the
905   attribute had in LDAP before.
906 *********************************************************************/
907 static void make_ldap_mod(LDAP *ldap_struct, LDAPMessage *existing,
908                           LDAPMod ***mods,
909                           const char *attribute, const char *newval)
910 {
911         char **values = NULL;
912
913         if (existing != NULL) {
914                 values = ldap_get_values(ldap_struct, existing, attribute);
915         }
916
917         if ((values != NULL) && (values[0] != NULL) &&
918             strcmp(values[0], newval) == 0) {
919                 
920                 /* Believe it or not, but LDAP will deny a delete and
921                    an add at the same time if the values are the
922                    same... */
923
924                 ldap_value_free(values);
925                 return;
926         }
927
928         /* Regardless of the real operation (add or modify)
929            we add the new value here. We rely on deleting
930            the old value, should it exist. */
931
932         if ((newval != NULL) && (strlen(newval) > 0)) {
933                 make_a_mod(mods, LDAP_MOD_ADD, attribute, newval);
934         }
935
936         if (values == NULL) {
937                 /* There has been no value before, so don't delete it.
938                    Here's a possible race: We might end up with
939                    duplicate attributes */
940                 return;
941         }
942
943         /* By deleting exactly the value we found in the entry this
944            should be race-free in the sense that the LDAP-Server will
945            deny the complete operation if somebody changed the
946            attribute behind our back. */
947
948         make_a_mod(mods, LDAP_MOD_DELETE, attribute, values[0]);
949         ldap_value_free(values);
950 }
951
952 /*******************************************************************
953  Delete complete object or objectclass and attrs from
954  object found in search_result depending on lp_ldap_delete_dn
955 ******************************************************************/
956 static NTSTATUS ldapsam_delete_entry(struct ldapsam_privates *ldap_state,
957                                      LDAPMessage *result,
958                                      const char *objectclass,
959                                      const char **attrs)
960 {
961         int rc;
962         LDAPMessage *entry;
963         LDAPMod **mods = NULL;
964         char *name, *dn;
965         BerElement *ptr = NULL;
966
967         rc = ldap_count_entries(ldap_state->ldap_struct, result);
968
969         if (rc != 1) {
970                 DEBUG(0, ("Entry must exist exactly once!\n"));
971                 return NT_STATUS_UNSUCCESSFUL;
972         }
973
974         entry = ldap_first_entry(ldap_state->ldap_struct, result);
975         dn    = ldap_get_dn(ldap_state->ldap_struct, entry);
976
977         if (lp_ldap_delete_dn()) {
978                 NTSTATUS ret = NT_STATUS_OK;
979                 rc = ldapsam_delete(ldap_state, dn);
980
981                 if (rc != LDAP_SUCCESS) {
982                         DEBUG(0, ("Could not delete object %s\n", dn));
983                         ret = NT_STATUS_UNSUCCESSFUL;
984                 }
985                 ldap_memfree(dn);
986                 return ret;
987         }
988
989         /* Ok, delete only the SAM attributes */
990
991         for (name = ldap_first_attribute(ldap_state->ldap_struct, entry, &ptr);
992              name != NULL;
993              name = ldap_next_attribute(ldap_state->ldap_struct, entry, ptr)) {
994
995                 const char **attrib;
996
997                 /* We are only allowed to delete the attributes that
998                    really exist. */
999
1000                 for (attrib = attrs; *attrib != NULL; attrib++) {
1001                         if (StrCaseCmp(*attrib, name) == 0) {
1002                                 DEBUG(10, ("deleting attribute %s\n", name));
1003                                 make_a_mod(&mods, LDAP_MOD_DELETE, name, NULL);
1004                         }
1005                 }
1006
1007                 ldap_memfree(name);
1008         }
1009
1010         if (ptr != NULL) {
1011                 ber_free(ptr, 0);
1012         }
1013         
1014         make_a_mod(&mods, LDAP_MOD_DELETE, "objectClass", objectclass);
1015
1016         rc = ldapsam_modify(ldap_state, dn, mods);
1017         ldap_mods_free(mods, 1);
1018
1019         if (rc != LDAP_SUCCESS) {
1020                 char *ld_error = NULL;
1021                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
1022                                 &ld_error);
1023                 
1024                 DEBUG(0, ("could not delete attributes for %s, error: %s (%s)\n",
1025                           dn, ldap_err2string(rc), ld_error?ld_error:"unknown"));
1026                 SAFE_FREE(ld_error);
1027                 ldap_memfree(dn);
1028                 return NT_STATUS_UNSUCCESSFUL;
1029         }
1030
1031         ldap_memfree(dn);
1032         return NT_STATUS_OK;
1033 }
1034                                           
1035 /**********************************************************************
1036 Search for the domain info entry
1037 *********************************************************************/
1038 static int ldapsam_search_domain_info(struct ldapsam_privates *ldap_state,
1039                                       LDAPMessage ** result)
1040 {
1041         pstring filter;
1042         int rc;
1043
1044         slprintf(filter, sizeof(filter)-1,
1045                  "(&(objectClass=sambaDomain)(domain=%s))",
1046                  ldap_state->domain_name);
1047
1048         DEBUG(2, ("Searching for:[%s]\n", filter));
1049
1050         rc = ldapsam_search_suffix(ldap_state, filter,
1051                                    domain_info_attrs, result);
1052
1053         if (rc != LDAP_SUCCESS) {
1054                 DEBUG(2,("Problem during LDAPsearch: %s\n", ldap_err2string (rc)));
1055                 DEBUG(2,("Query was: %s, %s\n", lp_ldap_suffix(), filter));
1056         }
1057         
1058         return rc;
1059 }
1060
1061 /**********************************************************************
1062  If this entry is is the 'allocated' range, extract the RID and return 
1063  it, so we can find the 'next' rid to allocate.
1064
1065  Do this, no matter what type of object holds the RID - be it a user,
1066  group or somthing else.
1067 *********************************************************************/
1068 static uint32 entry_to_rid(struct ldapsam_privates *ldap_state, LDAPMessage *entry, int rid_type) 
1069 {
1070         pstring sid_string;
1071         DOM_SID dom_sid;
1072         uint32 rid;
1073
1074         if (!get_single_attribute(ldap_state->ldap_struct, entry, "ntSid",
1075                                   sid_string)) {
1076                 return 0;
1077         }
1078         
1079         if (!string_to_sid(&dom_sid, sid_string)) {
1080                 return 0;
1081         }
1082
1083         if (!sid_peek_check_rid(&dom_sid, get_global_sam_sid(), &rid)) {
1084                 /* not our domain, so we don't care */
1085                 return 0;
1086         }
1087
1088         switch (rid_type) {
1089         case USER_RID_TYPE:
1090                 if (rid >= ldap_state->low_allocated_user_rid && 
1091                     rid <= ldap_state->high_allocated_user_rid) {
1092                         return rid;
1093                 }
1094                 break;
1095         case GROUP_RID_TYPE:
1096                 if (rid >= ldap_state->low_allocated_group_rid && 
1097                     rid <= ldap_state->high_allocated_group_rid) {
1098                         return rid;
1099                 }
1100                 break;
1101         }
1102         return 0;
1103 }
1104
1105
1106 /**********************************************************************
1107 Connect to LDAP server and find the next available 'allocated' RID.
1108
1109 The search is done 'per type' as we allocate seperate pools for the
1110 EVEN and ODD (user and group) RIDs.  
1111
1112 This is only done once, so that we can fill out the sambaDomain.
1113 *********************************************************************/
1114 static uint32 search_next_allocated_rid(struct ldapsam_privates *ldap_state, int rid_type)
1115 {
1116         int rc;
1117         LDAPMessage *result;
1118         LDAPMessage *entry;
1119         uint32 top_rid = 0;
1120         uint32 next_rid;
1121         uint32 count;
1122         uint32 rid;
1123         const char *sid_attr[] = {"ntSid", NULL};
1124         const char *filter = "(ntSid=*)";
1125
1126         DEBUG(2, ("search_top_allocated_rid: searching for:[%s]\n", filter));
1127
1128         rc = ldapsam_search_suffix(ldap_state, filter, 
1129                                    sid_attr, &result);
1130
1131         if (rc != LDAP_SUCCESS) {
1132                 DEBUG(3, ("LDAP search failed! cannot find base for NUA RIDs: %s\n", ldap_err2string(rc)));
1133                 DEBUGADD(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
1134
1135                 result = NULL;
1136                 return 0;
1137         }
1138         
1139         count = ldap_count_entries(ldap_state->ldap_struct, result);
1140         DEBUG(2, ("search_top_allocated_rid: %d entries in the base!\n", count));
1141         
1142         if (count == 0) {
1143                 DEBUG(3, ("LDAP search returned no records, assuming no allocated RIDs present!: %s\n", ldap_err2string(rc)));
1144                 DEBUGADD(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
1145         } else {
1146                 entry = ldap_first_entry(ldap_state->ldap_struct,result);
1147                 
1148                 top_rid = entry_to_rid(ldap_state, entry, rid_type);
1149                 
1150                 while ((entry = ldap_next_entry(ldap_state->ldap_struct, entry))) {
1151                         
1152                         rid = entry_to_rid(ldap_state, entry, rid_type);
1153                         if (((rid & ~RID_TYPE_MASK) == rid_type) && (rid > top_rid)) {
1154                                 top_rid = rid;
1155                         }
1156                 }
1157         }
1158
1159         switch (rid_type) {
1160         case USER_RID_TYPE:
1161                 if (top_rid < ldap_state->low_allocated_user_rid) {
1162                         return ldap_state->low_allocated_user_rid;
1163                 }
1164                 break;
1165         case GROUP_RID_TYPE:
1166                 if (top_rid < ldap_state->low_allocated_group_rid) 
1167                         return ldap_state->low_allocated_group_rid;
1168                 break;
1169         }
1170
1171         next_rid = (top_rid & ~RID_TYPE_MASK) + rid_type + RID_MULTIPLIER;
1172
1173         switch (rid_type) {
1174         case USER_RID_TYPE:
1175                 if (next_rid > ldap_state->high_allocated_user_rid) {
1176                         return 0;
1177                 }
1178                 break;
1179         case GROUP_RID_TYPE:
1180                 if (next_rid > ldap_state->high_allocated_group_rid) {
1181                         return 0;
1182                 }
1183                 break;
1184         }
1185         return next_rid;
1186 }
1187
1188 /**********************************************************************
1189  Add the sambaDomain to LDAP, so we don't have to search for this stuff
1190  again.  This is a once-add operation for now.
1191
1192  TODO:  Add other attributes, and allow modification.
1193 *********************************************************************/
1194 static NTSTATUS add_new_domain_info(struct ldapsam_privates *ldap_state) 
1195 {
1196         pstring tmp;
1197         pstring filter;
1198         LDAPMod **mods = NULL;
1199         int rc;
1200         int ldap_op;
1201         LDAPMessage *result = NULL;
1202         LDAPMessage *entry  = NULL;
1203         char *dn = NULL;
1204         int num_result;
1205
1206         uint32 next_allocated_user_rid;
1207         uint32 next_allocated_group_rid;
1208
1209         next_allocated_user_rid = search_next_allocated_rid(ldap_state, USER_RID_TYPE);
1210         if (!next_allocated_user_rid) {
1211                 return NT_STATUS_UNSUCCESSFUL;
1212         }
1213
1214         next_allocated_group_rid = search_next_allocated_rid(ldap_state, GROUP_RID_TYPE);
1215         if (!next_allocated_group_rid) {
1216                 return NT_STATUS_UNSUCCESSFUL;
1217         }
1218
1219         slprintf (filter, sizeof (filter) - 1, "domain=%s", ldap_state->domain_name);
1220         rc = ldapsam_search_suffix(ldap_state, filter, domain_info_attrs, &result);
1221         if (rc != LDAP_SUCCESS) {
1222                 return NT_STATUS_UNSUCCESSFUL;
1223         }
1224
1225         num_result = ldap_count_entries(ldap_state->ldap_struct, result);
1226         
1227         if (num_result > 1) {
1228                 DEBUG (0, ("More than domain with that name exists: bailing out!\n"));
1229                 ldap_msgfree(result);
1230                 return NT_STATUS_UNSUCCESSFUL;
1231         }
1232         
1233         /* Check if we need to update an existing entry */
1234         if (num_result == 1) {
1235                 char *tmp_dn;
1236                 
1237                 DEBUG(3,("Domain exists without samba properties: adding them\n"));
1238                 ldap_op = LDAP_MOD_REPLACE;
1239                 entry = ldap_first_entry (ldap_state->ldap_struct, result);
1240                 tmp_dn = ldap_get_dn (ldap_state->ldap_struct, entry);
1241                 asprintf (&dn, "%s", tmp_dn);
1242                 ldap_memfree (tmp_dn);
1243         } else {
1244                 /* Check if we need to add an entry */
1245                 DEBUG(3,("Adding new domain\n"));
1246                 ldap_op = LDAP_MOD_ADD;
1247                 asprintf (&dn, "domain=%s,%s", ldap_state->domain_name, lp_ldap_suffix ());
1248         }
1249
1250         /* Free original search */
1251         ldap_msgfree(result);
1252
1253         if (!dn) {
1254                 return NT_STATUS_NO_MEMORY;
1255         }
1256
1257         /* make the changes - the entry *must* not already have samba attributes */
1258         make_a_mod(&mods, LDAP_MOD_ADD, "domain", ldap_state->domain_name);
1259
1260         sid_to_string(tmp, &ldap_state->domain_sid);
1261         make_a_mod(&mods, LDAP_MOD_ADD, "ntSid", tmp);
1262
1263         snprintf(tmp, sizeof(tmp)-1, "%i", next_allocated_user_rid);
1264         make_a_mod(&mods, LDAP_MOD_ADD, "nextUserRid", tmp);
1265
1266         snprintf(tmp, sizeof(tmp)-1, "%i", next_allocated_group_rid);
1267         make_a_mod(&mods, LDAP_MOD_ADD, "nextGroupRid", tmp);
1268
1269         make_a_mod(&mods, LDAP_MOD_ADD, "objectclass", "sambaDomain");
1270
1271         switch(ldap_op)
1272         {
1273         case LDAP_MOD_ADD: 
1274                 rc = ldapsam_add(ldap_state, dn, mods);
1275                 break;
1276         case LDAP_MOD_REPLACE: 
1277                 rc = ldapsam_modify(ldap_state, dn, mods);
1278                 break;
1279         default:        
1280                 DEBUG(0,("Wrong LDAP operation type: %d!\n", ldap_op));
1281                 return NT_STATUS_INVALID_PARAMETER;
1282         }
1283         
1284         if (rc!=LDAP_SUCCESS) {
1285                 char *ld_error = NULL;
1286                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
1287                                 &ld_error);
1288                 DEBUG(1,
1289                       ("failed to %s domain dn= %s with: %s\n\t%s\n",
1290                        ldap_op == LDAP_MOD_ADD ? "add" : "modify",
1291                        dn, ldap_err2string(rc),
1292                        ld_error?ld_error:"unknown"));
1293                 SAFE_FREE(ld_error);
1294
1295                 ldap_mods_free(mods,1);
1296                 return NT_STATUS_UNSUCCESSFUL;
1297         }
1298
1299         DEBUG(2,("added: domain = %s in the LDAP database\n", ldap_state->domain_name));
1300         ldap_mods_free(mods, 1);
1301         return NT_STATUS_OK;
1302 }
1303
1304 /**********************************************************************
1305  Even if the sambaAccount attribute in LDAP tells us that this RID is 
1306  safe to use, always check before use.  
1307 *********************************************************************/
1308 static BOOL sid_in_use(struct ldapsam_privates *ldap_state, 
1309                        const DOM_SID *sid, int *error) 
1310 {
1311         pstring filter;
1312         fstring sid_string;
1313         LDAPMessage *result = NULL;
1314         int count;
1315         int rc;
1316         const char *sid_attr[] = {"ntSid", NULL};
1317
1318         slprintf(filter, sizeof(filter)-1, "(ntSid=%s)", sid_to_string(sid_string, sid));
1319
1320         rc = ldapsam_search_suffix(ldap_state, filter, sid_attr, &result);
1321
1322         if (rc != LDAP_SUCCESS) {
1323                 char *ld_error = NULL;
1324                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
1325                 DEBUG(2, ("Failed to check if sid %s is alredy in use: %s\n", 
1326                           sid_string, ld_error));
1327                 SAFE_FREE(ld_error);
1328
1329                 *error = rc;
1330                 return True;
1331         }
1332         
1333         if ((count = ldap_count_entries(ldap_state->ldap_struct, result)) > 0) {
1334                 DEBUG(3, ("Sid %s already in use - trying next RID\n",
1335                           sid_string));
1336                 ldap_msgfree(result);
1337                 return True;
1338         }
1339
1340         ldap_msgfree(result);
1341
1342         /* good, sid is not in use */
1343         return False;
1344 }
1345
1346 /**********************************************************************
1347  Set the new nextRid attribute, and return one we can use.
1348
1349  This also checks that this RID is actually free - in case the admin
1350  manually stole it :-).
1351 *********************************************************************/
1352 static NTSTATUS ldapsam_next_rid(struct ldapsam_privates *ldap_state, uint32 *rid, int rid_type)
1353 {
1354         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
1355         int rc;
1356         LDAPMessage *result = NULL;
1357         LDAPMessage *entry  = NULL;
1358         char *dn;
1359         LDAPMod **mods = NULL;
1360         int count;
1361         fstring old_rid_string;
1362         fstring next_rid_string;
1363         uint32 next_rid;
1364         int attempts = 0;
1365
1366         if (!ldap_state->use_ntsid) {
1367                 DEBUG(0, ("Allocated RIDs require 'ldap use ntSid' to be set in smb.conf\n"));
1368                 return NT_STATUS_UNSUCCESSFUL;
1369         }
1370         
1371         while (attempts < 10) {
1372                 char *ld_error;
1373                 if (ldapsam_search_domain_info(ldap_state, &result)) {
1374                         return ret;
1375                 }
1376
1377                 if (ldap_count_entries(ldap_state->ldap_struct, result) < 1) {
1378                         DEBUG(3, ("Got no domain info entries for domain %s\n",
1379                                   ldap_state->domain_name));
1380                         ldap_msgfree(result);
1381                         if (NT_STATUS_IS_OK(ret = add_new_domain_info(ldap_state))) {
1382                                 continue;
1383                         } else {
1384                                 DEBUG(0, ("Adding domain info failed with %s\n", nt_errstr(ret)));
1385                                 return ret;
1386                         }
1387                 }
1388                 
1389                 if ((count = ldap_count_entries(ldap_state->ldap_struct, result)) > 1) {
1390                         DEBUG(0, ("Got too many (%d) domain info entries for domain %s\n",
1391                                   count, ldap_state->domain_name));
1392                         ldap_msgfree(result);
1393                         return ret;
1394                 }
1395
1396                 entry = ldap_first_entry(ldap_state->ldap_struct, result);
1397                 if (!entry) {
1398                         ldap_msgfree(result);
1399                         return ret;
1400                 }
1401
1402                 if ((dn = ldap_get_dn(ldap_state->ldap_struct, entry)) == NULL) {
1403                         DEBUG(0, ("Could not get domain info DN\n"));
1404                         ldap_msgfree(result);
1405                         return ret;
1406                 }
1407
1408                 /* yes, we keep 2 seperate counters, to avoid stomping on the two
1409                    different sets of algorithmic RIDs */
1410
1411                 switch (rid_type) {
1412                 case USER_RID_TYPE:
1413                         if (!get_single_attribute(ldap_state->ldap_struct, 
1414                                                   entry, "nextUserRid",
1415                                                   old_rid_string)) {
1416                                 ldap_memfree(dn);
1417                                 ldap_msgfree(result);
1418                                 return ret;
1419                         }
1420                         break;
1421                 case GROUP_RID_TYPE:
1422                         if (!get_single_attribute(ldap_state->ldap_struct, 
1423                                                   entry, "nextGroupRid",
1424                                                   old_rid_string)) {
1425                                 ldap_memfree(dn);
1426                                 ldap_msgfree(result);
1427                                 return ret;
1428                         }
1429                         break;
1430                 }
1431
1432                 /* This is the core of the whole routine. If we had
1433                    scheme-style closures, there would be a *lot* less code
1434                    duplication... */
1435                 *rid = (uint32)atol(old_rid_string);
1436                 next_rid = *rid+RID_MULTIPLIER;
1437
1438                 slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
1439
1440                 switch (rid_type) {
1441                 case USER_RID_TYPE:
1442                         if (next_rid > ldap_state->high_allocated_user_rid) {
1443                                 return NT_STATUS_UNSUCCESSFUL;
1444                         }
1445
1446                         /* Try to make the modification atomically by enforcing the
1447                            old value in the delete mod. */
1448                         make_ldap_mod(ldap_state->ldap_struct, entry, &mods, "nextUserRid", next_rid_string);
1449                         break;
1450
1451                 case GROUP_RID_TYPE:
1452                         if (next_rid > ldap_state->high_allocated_group_rid) {
1453                                 return NT_STATUS_UNSUCCESSFUL;
1454                         }
1455
1456                         /* Try to make the modification atomically by enforcing the
1457                            old value in the delete mod. */
1458                         make_ldap_mod(ldap_state->ldap_struct, entry, &mods, "nextGroupRid", next_rid_string);
1459                         break;
1460                 }
1461
1462                 if ((rc = ldap_modify_s(ldap_state->ldap_struct, dn, mods)) == LDAP_SUCCESS) {
1463                         DOM_SID dom_sid;
1464                         DOM_SID sid;
1465                         pstring domain_sid_string;
1466                         int error = 0;
1467
1468                         if (!get_single_attribute(ldap_state->ldap_struct, result, "ntSid",
1469                                                   domain_sid_string)) {
1470                                 ldap_mods_free(mods, 1);
1471                                 ldap_memfree(dn);
1472                                 ldap_msgfree(result);
1473                                 return ret;
1474                         }
1475
1476                         if (!string_to_sid(&dom_sid, domain_sid_string)) { 
1477                                 ldap_mods_free(mods, 1);
1478                                 ldap_memfree(dn);
1479                                 ldap_msgfree(result);
1480                                 return ret;
1481                         }
1482
1483                         ldap_mods_free(mods, 1);
1484                         mods = NULL;
1485                         ldap_memfree(dn);
1486                         ldap_msgfree(result);
1487
1488                         sid_copy(&sid, &dom_sid);
1489                         sid_append_rid(&sid, *rid);
1490
1491                         /* check RID is not in use */
1492                         if (sid_in_use(ldap_state, &sid, &error)) {
1493                                 if (error) {
1494                                         return ret;
1495                                 }
1496                                 continue;
1497                         }
1498
1499                         return NT_STATUS_OK;
1500                 }
1501
1502                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
1503                 DEBUG(2, ("Failed to modify rid: %s\n", ld_error));
1504                 SAFE_FREE(ld_error);
1505
1506                 ldap_mods_free(mods, 1);
1507                 mods = NULL;
1508
1509                 ldap_memfree(dn);
1510                 dn = NULL;
1511
1512                 ldap_msgfree(result);
1513                 result = NULL;
1514
1515                 {
1516                         /* Sleep for a random timeout */
1517                         unsigned sleeptime = (sys_random()*sys_getpid()*attempts);
1518                         attempts += 1;
1519                         
1520                         sleeptime %= 100;
1521                         msleep(sleeptime);
1522                 }
1523         }
1524
1525         DEBUG(0, ("Failed to set new RID\n"));
1526         return ret;
1527 }
1528
1529 /* New Interface is being implemented here */
1530
1531 /**********************************************************************
1532 Initialize SAM_ACCOUNT from an LDAP query (unix attributes only)
1533 *********************************************************************/
1534 static BOOL get_unix_attributes (struct ldapsam_privates *ldap_state, 
1535                                 SAM_ACCOUNT * sampass,
1536                                 LDAPMessage * entry,
1537                                 gid_t *gid)
1538 {
1539         pstring  homedir;
1540         pstring  temp;
1541         char **ldap_values;
1542         char **values;
1543
1544         if ((ldap_values = ldap_get_values (ldap_state->ldap_struct, entry, "objectClass")) == NULL) {
1545                 DEBUG (1, ("get_unix_attributes: no objectClass! \n"));
1546                 return False;
1547         }
1548
1549         for (values=ldap_values;*values;values++) {
1550                 if (strcasecmp(*values, "posixAccount") == 0) {
1551                         break;
1552                 }
1553         }
1554         
1555         if (!*values) { /*end of array, no posixAccount */
1556                 DEBUG(10, ("user does not have posixAcccount attributes\n"));
1557                 ldap_value_free(ldap_values);
1558                 return False;
1559         }
1560         ldap_value_free(ldap_values);
1561
1562         if (!get_single_attribute(ldap_state->ldap_struct, entry, "homeDirectory", homedir)) 
1563                 return False;
1564         
1565         if (!get_single_attribute(ldap_state->ldap_struct, entry, "gidNumber", temp))
1566                 return False;
1567         
1568         gid = (gid_t)atol(temp);
1569
1570         pdb_set_unix_homedir(sampass, homedir, PDB_SET);
1571         
1572         DEBUG(10, ("user has posixAcccount attributes\n"));
1573         return True;
1574 }
1575
1576
1577 /**********************************************************************
1578 Initialize SAM_ACCOUNT from an LDAP query
1579 (Based on init_sam_from_buffer in pdb_tdb.c)
1580 *********************************************************************/
1581 static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state, 
1582                                 SAM_ACCOUNT * sampass,
1583                                 LDAPMessage * entry)
1584 {
1585         time_t  logon_time,
1586                         logoff_time,
1587                         kickoff_time,
1588                         pass_last_set_time, 
1589                         pass_can_change_time, 
1590                         pass_must_change_time;
1591         pstring         username, 
1592                         domain,
1593                         nt_username,
1594                         fullname,
1595                         homedir,
1596                         dir_drive,
1597                         logon_script,
1598                         profile_path,
1599                         acct_desc,
1600                         munged_dial,
1601                         workstations;
1602         uint32          user_rid; 
1603         uint8           smblmpwd[LM_HASH_LEN],
1604                         smbntpwd[NT_HASH_LEN];
1605         uint16          acct_ctrl = 0, 
1606                         logon_divs;
1607         uint32 hours_len;
1608         uint8           hours[MAX_HOURS_LEN];
1609         pstring temp;
1610         uid_t           uid = -1;
1611         gid_t           gid = getegid();
1612
1613         /*
1614          * do a little initialization
1615          */
1616         username[0]     = '\0';
1617         domain[0]       = '\0';
1618         nt_username[0]  = '\0';
1619         fullname[0]     = '\0';
1620         homedir[0]      = '\0';
1621         dir_drive[0]    = '\0';
1622         logon_script[0] = '\0';
1623         profile_path[0] = '\0';
1624         acct_desc[0]    = '\0';
1625         munged_dial[0]  = '\0';
1626         workstations[0] = '\0';
1627          
1628
1629         if (sampass == NULL || ldap_state == NULL || entry == NULL) {
1630                 DEBUG(0, ("init_sam_from_ldap: NULL parameters found!\n"));
1631                 return False;
1632         }
1633
1634         if (ldap_state->ldap_struct == NULL) {
1635                 DEBUG(0, ("init_sam_from_ldap: ldap_state->ldap_struct is NULL!\n"));
1636                 return False;
1637         }
1638         
1639         if (!get_single_attribute(ldap_state->ldap_struct, entry, "uid", username)) {
1640                 DEBUG(1, ("No uid attribute found for this user!\n"));
1641                 return False;
1642         }
1643
1644         DEBUG(2, ("Entry found for user: %s\n", username));
1645
1646         pstrcpy(nt_username, username);
1647
1648         pstrcpy(domain, ldap_state->domain_name);
1649         
1650         pdb_set_username(sampass, username, PDB_SET);
1651
1652         pdb_set_domain(sampass, domain, PDB_DEFAULT);
1653         pdb_set_nt_username(sampass, nt_username, PDB_SET);
1654         
1655         if (ldap_state->use_ntsid) {
1656                 if (get_single_attribute(ldap_state->ldap_struct, entry, "ntSid", temp)) {
1657                         pdb_set_user_sid_from_string(sampass, temp, PDB_SET);
1658                 }
1659         } else {
1660                 if (get_single_attribute(ldap_state->ldap_struct, entry, "rid", temp)) {
1661                         user_rid = (uint32)atol(temp);
1662                         pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
1663                 }
1664         }
1665
1666         if (pdb_get_init_flags(sampass,PDB_USERSID) == PDB_DEFAULT) {
1667                 DEBUG(1, ("no rid or ntSid attribute found for this user %s\n", username));
1668                 return False;
1669         }
1670
1671         if (!get_single_attribute(ldap_state->ldap_struct, entry, "primaryGroupID", temp)) {
1672                 pdb_set_group_sid_from_rid(sampass, DOMAIN_GROUP_RID_USERS, PDB_DEFAULT);
1673         } else {
1674                 uint32 group_rid;
1675                 group_rid = (uint32)atol(temp);
1676                 pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
1677         }
1678
1679         /* 
1680          * If so configured, try and get the values from LDAP 
1681          */
1682
1683         if (!lp_ldap_trust_ids() && (get_unix_attributes(ldap_state, sampass, entry, &gid))) {
1684                 
1685                 if (pdb_get_init_flags(sampass,PDB_GROUPSID) == PDB_DEFAULT) {
1686                         GROUP_MAP map;
1687                         /* call the mapping code here */
1688                         if(pdb_getgrgid(&map, gid, MAPPING_WITHOUT_PRIV)) {
1689                                 pdb_set_group_sid(sampass, &map.sid, PDB_SET);
1690                         } 
1691                         else {
1692                                 pdb_set_group_sid_from_rid(sampass, pdb_gid_to_group_rid(gid), PDB_SET);
1693                         }
1694                 }
1695         }
1696
1697         if (!get_single_attribute(ldap_state->ldap_struct, entry, "pwdLastSet", temp)) {
1698                 /* leave as default */
1699         } else {
1700                 pass_last_set_time = (time_t) atol(temp);
1701                 pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
1702         }
1703
1704         if (!get_single_attribute(ldap_state->ldap_struct, entry, "logonTime", temp)) {
1705                 /* leave as default */
1706         } else {
1707                 logon_time = (time_t) atol(temp);
1708                 pdb_set_logon_time(sampass, logon_time, PDB_SET);
1709         }
1710
1711         if (!get_single_attribute(ldap_state->ldap_struct, entry, "logoffTime", temp)) {
1712                 /* leave as default */
1713         } else {
1714                 logoff_time = (time_t) atol(temp);
1715                 pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
1716         }
1717
1718         if (!get_single_attribute(ldap_state->ldap_struct, entry, "kickoffTime", temp)) {
1719                 /* leave as default */
1720         } else {
1721                 kickoff_time = (time_t) atol(temp);
1722                 pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
1723         }
1724
1725         if (!get_single_attribute(ldap_state->ldap_struct, entry, "pwdCanChange", temp)) {
1726                 /* leave as default */
1727         } else {
1728                 pass_can_change_time = (time_t) atol(temp);
1729                 pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
1730         }
1731
1732         if (!get_single_attribute(ldap_state->ldap_struct, entry, "pwdMustChange", temp)) {
1733                 /* leave as default */
1734         } else {
1735                 pass_must_change_time = (time_t) atol(temp);
1736                 pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
1737         }
1738
1739         /* recommend that 'gecos' and 'displayName' should refer to the same
1740          * attribute OID.  userFullName depreciated, only used by Samba
1741          * primary rules of LDAP: don't make a new attribute when one is already defined
1742          * that fits your needs; using cn then displayName rather than 'userFullName'
1743          */
1744
1745         if (!get_single_attribute(ldap_state->ldap_struct, entry,
1746                                   "displayName", fullname)) {
1747                 if (!get_single_attribute(ldap_state->ldap_struct, entry,
1748                                           "cn", fullname)) {
1749                         /* leave as default */
1750                 } else {
1751                         pdb_set_fullname(sampass, fullname, PDB_SET);
1752                 }
1753         } else {
1754                 pdb_set_fullname(sampass, fullname, PDB_SET);
1755         }
1756
1757         if (!get_single_attribute(ldap_state->ldap_struct, entry, "homeDrive", dir_drive)) {
1758                 pdb_set_dir_drive(sampass, talloc_sub_specified(sampass->mem_ctx, 
1759                                                                   lp_logon_drive(),
1760                                                                   username, domain, 
1761                                                                   uid, gid),
1762                                   PDB_DEFAULT);
1763         } else {
1764                 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
1765         }
1766
1767         if (!get_single_attribute(ldap_state->ldap_struct, entry, "smbHome", homedir)) {
1768                 pdb_set_homedir(sampass, talloc_sub_specified(sampass->mem_ctx, 
1769                                                                   lp_logon_home(),
1770                                                                   username, domain, 
1771                                                                   uid, gid), 
1772                                   PDB_DEFAULT);
1773         } else {
1774                 pdb_set_homedir(sampass, homedir, PDB_SET);
1775         }
1776
1777         if (!get_single_attribute(ldap_state->ldap_struct, entry, "scriptPath", logon_script)) {
1778                 pdb_set_logon_script(sampass, talloc_sub_specified(sampass->mem_ctx, 
1779                                                                      lp_logon_script(),
1780                                                                      username, domain, 
1781                                                                      uid, gid), 
1782                                      PDB_DEFAULT);
1783         } else {
1784                 pdb_set_logon_script(sampass, logon_script, PDB_SET);
1785         }
1786
1787         if (!get_single_attribute(ldap_state->ldap_struct, entry, "profilePath", profile_path)) {
1788                 pdb_set_profile_path(sampass, talloc_sub_specified(sampass->mem_ctx, 
1789                                                                      lp_logon_path(),
1790                                                                      username, domain, 
1791                                                                      uid, gid), 
1792                                      PDB_DEFAULT);
1793         } else {
1794                 pdb_set_profile_path(sampass, profile_path, PDB_SET);
1795         }
1796
1797         if (!get_single_attribute(ldap_state->ldap_struct, entry, "description", acct_desc)) {
1798                 /* leave as default */
1799         } else {
1800                 pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
1801         }
1802
1803         if (!get_single_attribute(ldap_state->ldap_struct, entry, "userWorkstations", workstations)) {
1804                 /* leave as default */;
1805         } else {
1806                 pdb_set_workstations(sampass, workstations, PDB_SET);
1807         }
1808
1809         /* FIXME: hours stuff should be cleaner */
1810         
1811         logon_divs = 168;
1812         hours_len = 21;
1813         memset(hours, 0xff, hours_len);
1814
1815         if (!get_single_attribute (ldap_state->ldap_struct, entry, "lmPassword", temp)) {
1816                 /* leave as default */
1817         } else {
1818                 pdb_gethexpwd(temp, smblmpwd);
1819                 memset((char *)temp, '\0', strlen(temp)+1);
1820                 if (!pdb_set_lanman_passwd(sampass, smblmpwd, PDB_SET))
1821                         return False;
1822                 ZERO_STRUCT(smblmpwd);
1823         }
1824
1825         if (!get_single_attribute (ldap_state->ldap_struct, entry, "ntPassword", temp)) {
1826                 /* leave as default */
1827         } else {
1828                 pdb_gethexpwd(temp, smbntpwd);
1829                 memset((char *)temp, '\0', strlen(temp)+1);
1830                 if (!pdb_set_nt_passwd(sampass, smbntpwd, PDB_SET))
1831                         return False;
1832                 ZERO_STRUCT(smbntpwd);
1833         }
1834
1835         if (!get_single_attribute (ldap_state->ldap_struct, entry, "acctFlags", temp)) {
1836                 acct_ctrl |= ACB_NORMAL;
1837         } else {
1838                 acct_ctrl = pdb_decode_acct_ctrl(temp);
1839
1840                 if (acct_ctrl == 0)
1841                         acct_ctrl |= ACB_NORMAL;
1842
1843                 pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
1844         }
1845
1846         pdb_set_hours_len(sampass, hours_len, PDB_SET);
1847         pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
1848
1849         pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
1850         
1851         /* pdb_set_unknown_3(sampass, unknown3, PDB_SET); */
1852         /* pdb_set_unknown_5(sampass, unknown5, PDB_SET); */
1853         /* pdb_set_unknown_6(sampass, unknown6, PDB_SET); */
1854
1855         pdb_set_hours(sampass, hours, PDB_SET);
1856
1857         return True;
1858 }
1859
1860 /**********************************************************************
1861 Initialize SAM_ACCOUNT from an LDAP query
1862 (Based on init_buffer_from_sam in pdb_tdb.c)
1863 *********************************************************************/
1864 static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state, 
1865                                 LDAPMessage *existing,
1866                                 LDAPMod *** mods, SAM_ACCOUNT * sampass,
1867                                 BOOL (*need_update)(const SAM_ACCOUNT *,
1868                                                     enum pdb_elements))
1869 {
1870         pstring temp;
1871         uint32 rid;
1872
1873         if (mods == NULL || sampass == NULL) {
1874                 DEBUG(0, ("init_ldap_from_sam: NULL parameters found!\n"));
1875                 return False;
1876         }
1877
1878         *mods = NULL;
1879
1880         /* 
1881          * took out adding "objectclass: sambaAccount"
1882          * do this on a per-mod basis
1883          */
1884         if (need_update(sampass, PDB_USERNAME))
1885                 make_ldap_mod(ldap_state->ldap_struct, existing, mods, 
1886                               "uid", pdb_get_username(sampass));
1887
1888         DEBUG(2, ("Setting entry for user: %s\n", pdb_get_username(sampass)));
1889
1890         if (pdb_get_init_flags(sampass, PDB_USERSID) == PDB_DEFAULT) {
1891                 if (ldap_state->permit_non_unix_accounts) {
1892                         if (!NT_STATUS_IS_OK(ldapsam_next_rid(ldap_state, &rid, USER_RID_TYPE))) {
1893                                 DEBUG(0, ("NO user RID specified on account %s, and "
1894                                           "finding next available NUA RID failed, "
1895                                           "cannot store!\n",
1896                                           pdb_get_username(sampass)));
1897                                 ldap_mods_free(*mods, 1);
1898                                 return False;
1899                         }
1900                 } else {
1901                         DEBUG(0, ("NO user RID specified on account %s, "
1902                                   "cannot store!\n", pdb_get_username(sampass)));
1903                         ldap_mods_free(*mods, 1);
1904                         return False;
1905                 }
1906
1907                 /* now that we have figured out the RID, always store it, as
1908                    the schema requires it */
1909                 if (!pdb_set_user_sid_from_rid(sampass, rid, PDB_CHANGED)) {
1910                         DEBUG(0, ("Could not store RID back onto SAM_ACCOUNT for user %s!\n", 
1911                                   pdb_get_username(sampass)));
1912                         ldap_mods_free(*mods, 1);
1913                         return False;
1914                 }
1915         }
1916
1917         /* only update the RID if we actually need to */
1918         if (need_update(sampass, PDB_USERSID)) {
1919                 fstring sid_string;
1920                 fstring dom_sid_string;
1921                 const DOM_SID *user_sid;
1922                 user_sid = pdb_get_user_sid(sampass);
1923                 
1924                 if (ldap_state->use_ntsid) {
1925                         make_ldap_mod(ldap_state->ldap_struct, existing, mods,
1926                                       "ntSid", sid_to_string(sid_string, user_sid));
1927                 } else {
1928                         if (!sid_peek_check_rid(get_global_sam_sid(), user_sid, &rid)) {
1929                                 DEBUG(1, ("User's SID (%s) is not for this domain (%s), cannot add to LDAP!\n", sid_to_string(sid_string, user_sid), sid_to_string(dom_sid_string, get_global_sam_sid())));
1930                                 return False;
1931                         }
1932                         slprintf(temp, sizeof(temp) - 1, "%i", rid);
1933                         make_ldap_mod(ldap_state->ldap_struct, existing, mods,
1934                                       "rid", temp);
1935                 }
1936                 
1937         }
1938
1939         /* we don't need to store the primary group RID - so leaving it
1940            'free' to hang off the unix primary group makes life easier */
1941
1942         if (need_update(sampass, PDB_GROUPSID)) {
1943                 rid = pdb_get_group_rid(sampass);
1944                 slprintf(temp, sizeof(temp) - 1, "%i", rid);
1945                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
1946                               "primaryGroupID", temp);
1947         }
1948
1949         /* displayName, cn, and gecos should all be the same
1950          *  most easily accomplished by giving them the same OID
1951          *  gecos isn't set here b/c it should be handled by the 
1952          *  add-user script
1953          *  We change displayName only and fall back to cn if
1954          *  it does not exist.
1955          */
1956
1957         if (need_update(sampass, PDB_FULLNAME))
1958                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
1959                               "displayName", pdb_get_fullname(sampass));
1960
1961         if (need_update(sampass, PDB_ACCTDESC))
1962                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
1963                               "description", pdb_get_acct_desc(sampass));
1964
1965         if (need_update(sampass, PDB_WORKSTATIONS))
1966                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
1967                               "userWorkstations", pdb_get_workstations(sampass));
1968
1969         if (need_update(sampass, PDB_SMBHOME))
1970                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
1971                               "smbHome", pdb_get_homedir(sampass));
1972                         
1973         if (need_update(sampass, PDB_DRIVE))
1974                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
1975                               "homeDrive", pdb_get_dir_drive(sampass));
1976
1977         if (need_update(sampass, PDB_LOGONSCRIPT))
1978                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
1979                               "scriptPath", pdb_get_logon_script(sampass));
1980
1981         if (need_update(sampass, PDB_PROFILE))
1982                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
1983                               "profilePath", pdb_get_profile_path(sampass));
1984
1985         slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logon_time(sampass));
1986
1987         if (need_update(sampass, PDB_LOGONTIME))
1988                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
1989                               "logonTime", temp);
1990
1991         slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logoff_time(sampass));
1992
1993         if (need_update(sampass, PDB_LOGOFFTIME))
1994                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
1995                               "logoffTime", temp);
1996
1997         slprintf (temp, sizeof (temp) - 1, "%li",
1998                   pdb_get_kickoff_time(sampass));
1999
2000         if (need_update(sampass, PDB_KICKOFFTIME))
2001                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2002                               "kickoffTime", temp);
2003
2004         slprintf (temp, sizeof (temp) - 1, "%li",
2005                   pdb_get_pass_can_change_time(sampass));
2006
2007         if (need_update(sampass, PDB_CANCHANGETIME))
2008                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2009                               "pwdCanChange", temp);
2010
2011         slprintf (temp, sizeof (temp) - 1, "%li",
2012                   pdb_get_pass_must_change_time(sampass));
2013
2014         if (need_update(sampass, PDB_MUSTCHANGETIME))
2015                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2016                               "pwdMustChange", temp);
2017
2018         if ((pdb_get_acct_ctrl(sampass)&(ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST))||
2019             (lp_ldap_passwd_sync()!=LDAP_PASSWD_SYNC_ONLY)) {
2020
2021                 pdb_sethexpwd (temp, pdb_get_lanman_passwd(sampass),
2022                                pdb_get_acct_ctrl(sampass));
2023
2024                 if (need_update(sampass, PDB_LMPASSWD))
2025                         make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2026                                       "lmPassword", temp);
2027
2028                 pdb_sethexpwd (temp, pdb_get_nt_passwd(sampass),
2029                                pdb_get_acct_ctrl(sampass));
2030
2031                 if (need_update(sampass, PDB_NTPASSWD))
2032                         make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2033                                       "ntPassword", temp);
2034
2035                 slprintf (temp, sizeof (temp) - 1, "%li",
2036                           pdb_get_pass_last_set_time(sampass));
2037
2038                 if (need_update(sampass, PDB_PASSLASTSET))
2039                         make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2040                                       "pwdLastSet", temp);
2041         }
2042
2043         /* FIXME: Hours stuff goes in LDAP  */
2044
2045         if (need_update(sampass, PDB_ACCTCTRL))
2046                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2047                               "acctFlags",
2048                               pdb_encode_acct_ctrl (pdb_get_acct_ctrl(sampass),
2049                                                     NEW_PW_FORMAT_SPACE_PADDED_LEN));
2050
2051         return True;
2052 }
2053
2054
2055
2056 /**********************************************************************
2057 Connect to LDAP server for password enumeration
2058 *********************************************************************/
2059 static NTSTATUS ldapsam_setsampwent(struct pdb_methods *my_methods, BOOL update)
2060 {
2061         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2062         int rc;
2063         pstring filter;
2064
2065         pstrcpy(filter, lp_ldap_filter());
2066         all_string_sub(filter, "%u", "*", sizeof(pstring));
2067
2068         rc = ldapsam_search_suffix(ldap_state, 
2069                                    filter, attr,
2070                                    &ldap_state->result);
2071
2072         if (rc != LDAP_SUCCESS) {
2073                 DEBUG(0, ("LDAP search failed: %s\n", ldap_err2string(rc)));
2074                 DEBUG(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
2075                 ldap_msgfree(ldap_state->result);
2076                 ldap_state->result = NULL;
2077                 return NT_STATUS_UNSUCCESSFUL;
2078         }
2079
2080         DEBUG(2, ("ldapsam_setsampwent: %d entries in the base!\n",
2081                 ldap_count_entries(ldap_state->ldap_struct,
2082                 ldap_state->result)));
2083
2084         ldap_state->entry = ldap_first_entry(ldap_state->ldap_struct,
2085                                  ldap_state->result);
2086         ldap_state->index = 0;
2087
2088         return NT_STATUS_OK;
2089 }
2090
2091 /**********************************************************************
2092 End enumeration of the LDAP password list 
2093 *********************************************************************/
2094 static void ldapsam_endsampwent(struct pdb_methods *my_methods)
2095 {
2096         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2097         if (ldap_state->result) {
2098                 ldap_msgfree(ldap_state->result);
2099                 ldap_state->result = NULL;
2100         }
2101 }
2102
2103 /**********************************************************************
2104 Get the next entry in the LDAP password database 
2105 *********************************************************************/
2106 static NTSTATUS ldapsam_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT *user)
2107 {
2108         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
2109         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2110         BOOL bret = False;
2111
2112         /* The rebind proc needs this *HACK*.  We are not multithreaded, so
2113            this will work, but it's not nice. */
2114         static_ldap_state = ldap_state;
2115
2116         while (!bret) {
2117                 if (!ldap_state->entry)
2118                         return ret;
2119                 
2120                 ldap_state->index++;
2121                 bret = init_sam_from_ldap(ldap_state, user, ldap_state->entry);
2122                 
2123                 ldap_state->entry = ldap_next_entry(ldap_state->ldap_struct,
2124                                             ldap_state->entry); 
2125         }
2126
2127         return NT_STATUS_OK;
2128 }
2129
2130 /**********************************************************************
2131 Get SAM_ACCOUNT entry from LDAP by username 
2132 *********************************************************************/
2133 static NTSTATUS ldapsam_getsampwnam(struct pdb_methods *my_methods, SAM_ACCOUNT *user, const char *sname)
2134 {
2135         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
2136         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2137         LDAPMessage *result;
2138         LDAPMessage *entry;
2139         int count;
2140         
2141         if (ldapsam_search_suffix_by_name(ldap_state, sname, &result) != LDAP_SUCCESS) {
2142                 return NT_STATUS_NO_SUCH_USER;
2143         }
2144         
2145         count = ldap_count_entries(ldap_state->ldap_struct, result);
2146         
2147         if (count < 1) {
2148                 DEBUG(4,
2149                       ("We don't find this user [%s] count=%d\n", sname,
2150                        count));
2151                 return NT_STATUS_NO_SUCH_USER;
2152         } else if (count > 1) {
2153                 DEBUG(1,
2154                       ("Duplicate entries for this user [%s] Failing. count=%d\n", sname,
2155                        count));
2156                 return NT_STATUS_NO_SUCH_USER;
2157         }
2158
2159         entry = ldap_first_entry(ldap_state->ldap_struct, result);
2160         if (entry) {
2161                 if (!init_sam_from_ldap(ldap_state, user, entry)) {
2162                         DEBUG(1,("ldapsam_getsampwnam: init_sam_from_ldap failed for user '%s'!\n", sname));
2163                         ldap_msgfree(result);
2164                         return NT_STATUS_NO_SUCH_USER;
2165                 }
2166                 ldap_msgfree(result);
2167                 ret = NT_STATUS_OK;
2168         } else {
2169                 ldap_msgfree(result);
2170         }
2171         return ret;
2172 }
2173
2174 /**********************************************************************
2175 Get SAM_ACCOUNT entry from LDAP by SID
2176 *********************************************************************/
2177 static NTSTATUS ldapsam_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT * user, const DOM_SID *sid)
2178 {
2179         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
2180         struct ldapsam_privates *ldap_state = 
2181                 (struct ldapsam_privates *)my_methods->private_data;
2182         LDAPMessage *result;
2183         LDAPMessage *entry;
2184         fstring sid_string;
2185         int count;
2186         
2187         if (ldap_state->use_ntsid) {
2188                 if (ldapsam_search_suffix_by_sid(ldap_state, sid, &result) != LDAP_SUCCESS) {
2189                         return NT_STATUS_NO_SUCH_USER;
2190                 }
2191         } else {
2192                 uint32 rid;
2193                 if (!sid_peek_check_rid(get_global_sam_sid(), sid, &rid)) {
2194                         return NT_STATUS_NO_SUCH_USER;
2195                 }
2196                 
2197                 if (ldapsam_search_suffix_by_rid(ldap_state, rid, &result) != LDAP_SUCCESS) {
2198                         return NT_STATUS_NO_SUCH_USER;
2199                 }
2200         }
2201         
2202         count = ldap_count_entries(ldap_state->ldap_struct, result);
2203         
2204         if (count < 1) {
2205                 DEBUG(4,
2206                       ("We don't find this SID [%s] count=%d\n", sid_to_string(sid_string, sid),
2207                        count));
2208                 return NT_STATUS_NO_SUCH_USER;
2209         } else if (count > 1) {
2210                 DEBUG(1,
2211                       ("More than one user with SID [%s]. Failing. count=%d\n", sid_to_string(sid_string, sid),
2212                        count));
2213                 return NT_STATUS_NO_SUCH_USER;
2214         }
2215
2216         entry = ldap_first_entry(ldap_state->ldap_struct, result);
2217         if (entry) {
2218                 if (!init_sam_from_ldap(ldap_state, user, entry)) {
2219                         DEBUG(1,("ldapsam_getsampwrid: init_sam_from_ldap failed!\n"));
2220                         ldap_msgfree(result);
2221                         return NT_STATUS_NO_SUCH_USER;
2222                 }
2223                 ldap_msgfree(result);
2224                 ret = NT_STATUS_OK;
2225         } else {
2226                 ldap_msgfree(result);
2227         }
2228         return ret;
2229 }       
2230
2231 /********************************************************************
2232 Do the actual modification - also change a plaittext passord if 
2233 it it set.
2234 **********************************************************************/
2235
2236 static NTSTATUS ldapsam_modify_entry(struct pdb_methods *my_methods, 
2237                                      SAM_ACCOUNT *newpwd, char *dn,
2238                                      LDAPMod **mods, int ldap_op, 
2239                                      BOOL (*need_update)(const SAM_ACCOUNT *,
2240                                                          enum pdb_elements))
2241 {
2242         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2243         int rc;
2244         
2245         if (!my_methods || !newpwd || !dn) {
2246                 return NT_STATUS_INVALID_PARAMETER;
2247         }
2248         
2249         if (!mods) {
2250                 DEBUG(5,("mods is empty: nothing to modify\n"));
2251                 /* may be password change below however */
2252         } else {
2253                 switch(ldap_op)
2254                 {
2255                         case LDAP_MOD_ADD: 
2256                                 make_a_mod(&mods, LDAP_MOD_ADD, "objectclass", "account");
2257                                 rc = ldapsam_add(ldap_state, dn, mods);
2258                                 break;
2259                         case LDAP_MOD_REPLACE: 
2260                                 rc = ldapsam_modify(ldap_state, dn ,mods);
2261                                 break;
2262                         default:        
2263                                 DEBUG(0,("Wrong LDAP operation type: %d!\n", ldap_op));
2264                                 return NT_STATUS_INVALID_PARAMETER;
2265                 }
2266                 
2267                 if (rc!=LDAP_SUCCESS) {
2268                         char *ld_error = NULL;
2269                         ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
2270                                         &ld_error);
2271                         DEBUG(1,
2272                               ("failed to %s user dn= %s with: %s\n\t%s\n",
2273                                ldap_op == LDAP_MOD_ADD ? "add" : "modify",
2274                                dn, ldap_err2string(rc),
2275                                ld_error?ld_error:"unknown"));
2276                         SAFE_FREE(ld_error);
2277                         return NT_STATUS_UNSUCCESSFUL;
2278                 }  
2279         }
2280         
2281 #ifdef LDAP_EXOP_X_MODIFY_PASSWD
2282         if (!(pdb_get_acct_ctrl(newpwd)&(ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST)) &&
2283                 (lp_ldap_passwd_sync() != LDAP_PASSWD_SYNC_OFF) &&
2284                 need_update(newpwd, PDB_PLAINTEXT_PW) &&
2285                 (pdb_get_plaintext_passwd(newpwd)!=NULL)) {
2286                 BerElement *ber;
2287                 struct berval *bv;
2288                 char *retoid;
2289                 struct berval *retdata;
2290                 char *utf8_password;
2291                 char *utf8_dn;
2292
2293                 if (push_utf8_allocate(&utf8_password, pdb_get_plaintext_passwd(newpwd)) == (size_t)-1) {
2294                         return NT_STATUS_NO_MEMORY;
2295                 }
2296
2297                 if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
2298                         return NT_STATUS_NO_MEMORY;
2299                 }
2300
2301                 if ((ber = ber_alloc_t(LBER_USE_DER))==NULL) {
2302                         DEBUG(0,("ber_alloc_t returns NULL\n"));
2303                         SAFE_FREE(utf8_password);
2304                         return NT_STATUS_UNSUCCESSFUL;
2305                 }
2306
2307                 ber_printf (ber, "{");
2308                 ber_printf (ber, "ts", LDAP_TAG_EXOP_X_MODIFY_PASSWD_ID, utf8_dn);
2309                 ber_printf (ber, "ts", LDAP_TAG_EXOP_X_MODIFY_PASSWD_NEW, utf8_password);
2310                 ber_printf (ber, "N}");
2311
2312                 if ((rc = ber_flatten (ber, &bv))<0) {
2313                         DEBUG(0,("ber_flatten returns a value <0\n"));
2314                         ber_free(ber,1);
2315                         SAFE_FREE(utf8_dn);
2316                         SAFE_FREE(utf8_password);
2317                         return NT_STATUS_UNSUCCESSFUL;
2318                 }
2319                 
2320                 SAFE_FREE(utf8_dn);
2321                 SAFE_FREE(utf8_password);
2322                 ber_free(ber, 1);
2323
2324                 if ((rc = ldapsam_extended_operation(ldap_state, LDAP_EXOP_X_MODIFY_PASSWD,
2325                                                     bv, NULL, NULL, &retoid, &retdata))!=LDAP_SUCCESS) {
2326                         DEBUG(0,("LDAP Password could not be changed for user %s: %s\n",
2327                                 pdb_get_username(newpwd),ldap_err2string(rc)));
2328                 } else {
2329                         DEBUG(3,("LDAP Password changed for user %s\n",pdb_get_username(newpwd)));
2330 #ifdef DEBUG_PASSWORD
2331                         DEBUG(100,("LDAP Password changed to %s\n",pdb_get_plaintext_passwd(newpwd)));
2332 #endif    
2333                         ber_bvfree(retdata);
2334                         ber_memfree(retoid);
2335                 }
2336                 ber_bvfree(bv);
2337         }
2338 #else
2339         DEBUG(10,("LDAP PASSWORD SYNC is not supported!\n"));
2340 #endif /* LDAP_EXOP_X_MODIFY_PASSWD */
2341         return NT_STATUS_OK;
2342 }
2343
2344 /**********************************************************************
2345 Delete entry from LDAP for username 
2346 *********************************************************************/
2347 static NTSTATUS ldapsam_delete_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT * sam_acct)
2348 {
2349         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2350         const char *sname;
2351         int rc;
2352         LDAPMessage *result;
2353         NTSTATUS ret;
2354         const char *sam_user_attrs[] =
2355         { "lmPassword", "ntPassword", "pwdLastSet", "logonTime", "logoffTime",
2356           "kickoffTime", "pwdCanChange", "pwdMustChange", "acctFlags",
2357           "displayName", "smbHome", "homeDrive", "scriptPath", "profilePath",
2358           "userWorkstations", "primaryGroupID", "domain", "rid", "ntSid", NULL };
2359
2360         if (!sam_acct) {
2361                 DEBUG(0, ("sam_acct was NULL!\n"));
2362                 return NT_STATUS_INVALID_PARAMETER;
2363         }
2364
2365         sname = pdb_get_username(sam_acct);
2366
2367         DEBUG (3, ("Deleting user %s from LDAP.\n", sname));
2368
2369         rc = ldapsam_search_suffix_by_name(ldap_state, sname, &result);
2370         if (rc != LDAP_SUCCESS) {
2371                 return NT_STATUS_NO_SUCH_USER;
2372         }
2373
2374         ret = ldapsam_delete_entry(ldap_state, result, "sambaAccount",
2375                                    sam_user_attrs);
2376         ldap_msgfree(result);
2377         return ret;
2378 }
2379
2380 /**********************************************************************
2381   Helper function to determine for update_sam_account whether
2382   we need LDAP modification.
2383 *********************************************************************/
2384 static BOOL element_is_changed(const SAM_ACCOUNT *sampass,
2385                                enum pdb_elements element)
2386 {
2387         return IS_SAM_CHANGED(sampass, element);
2388 }
2389
2390 /**********************************************************************
2391 Update SAM_ACCOUNT 
2392 *********************************************************************/
2393 static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT * newpwd)
2394 {
2395         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
2396         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2397         int rc;
2398         char *dn;
2399         LDAPMessage *result;
2400         LDAPMessage *entry;
2401         LDAPMod **mods;
2402
2403         rc = ldapsam_search_suffix_by_name(ldap_state, pdb_get_username(newpwd), &result);
2404         if (rc != LDAP_SUCCESS) {
2405                 return NT_STATUS_UNSUCCESSFUL;
2406         }
2407
2408         if (ldap_count_entries(ldap_state->ldap_struct, result) == 0) {
2409                 DEBUG(0, ("No user to modify!\n"));
2410                 ldap_msgfree(result);
2411                 return NT_STATUS_UNSUCCESSFUL;
2412         }
2413
2414         entry = ldap_first_entry(ldap_state->ldap_struct, result);
2415         dn = ldap_get_dn(ldap_state->ldap_struct, entry);
2416
2417         if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd,
2418                                 element_is_changed)) {
2419                 DEBUG(0, ("ldapsam_update_sam_account: init_ldap_from_sam failed!\n"));
2420                 ldap_msgfree(result);
2421                 return NT_STATUS_UNSUCCESSFUL;
2422         }
2423         
2424         ldap_msgfree(result);
2425         
2426         if (mods == NULL) {
2427                 DEBUG(4,("mods is empty: nothing to update for user: %s\n",
2428                          pdb_get_username(newpwd)));
2429                 ldap_mods_free(mods, 1);
2430                 return NT_STATUS_OK;
2431         }
2432         
2433         ret = ldapsam_modify_entry(my_methods,newpwd,dn,mods,LDAP_MOD_REPLACE, element_is_changed);
2434         ldap_mods_free(mods,1);
2435
2436         if (!NT_STATUS_IS_OK(ret)) {
2437                 char *ld_error = NULL;
2438                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
2439                                 &ld_error);
2440                 DEBUG(0,("failed to modify user with uid = %s, error: %s (%s)\n",
2441                          pdb_get_username(newpwd), ld_error?ld_error:"(unknwon)", ldap_err2string(rc)));
2442                 SAFE_FREE(ld_error);
2443                 return ret;
2444         }
2445
2446         DEBUG(2, ("successfully modified uid = %s in the LDAP database\n",
2447                   pdb_get_username(newpwd)));
2448         return NT_STATUS_OK;
2449 }
2450
2451 /**********************************************************************
2452   Helper function to determine for update_sam_account whether
2453   we need LDAP modification.
2454 *********************************************************************/
2455 static BOOL element_is_set_or_changed(const SAM_ACCOUNT *sampass,
2456                                       enum pdb_elements element)
2457 {
2458         return (IS_SAM_SET(sampass, element) ||
2459                 IS_SAM_CHANGED(sampass, element));
2460 }
2461
2462 /**********************************************************************
2463 Add SAM_ACCOUNT to LDAP 
2464 *********************************************************************/
2465 static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT * newpwd)
2466 {
2467         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
2468         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2469         int rc;
2470         pstring filter;
2471         LDAPMessage *result = NULL;
2472         LDAPMessage *entry  = NULL;
2473         pstring dn;
2474         LDAPMod **mods = NULL;
2475         int             ldap_op;
2476         uint32          num_result;
2477         
2478         const char *username = pdb_get_username(newpwd);
2479         if (!username || !*username) {
2480                 DEBUG(0, ("Cannot add user without a username!\n"));
2481                 return NT_STATUS_INVALID_PARAMETER;
2482         }
2483
2484         rc = ldapsam_search_suffix_by_name (ldap_state, username, &result);
2485         if (rc != LDAP_SUCCESS) {
2486                 return NT_STATUS_UNSUCCESSFUL;
2487         }
2488
2489         if (ldap_count_entries(ldap_state->ldap_struct, result) != 0) {
2490                 DEBUG(0,("User '%s' already in the base, with samba properties\n", 
2491                          username));
2492                 ldap_msgfree(result);
2493                 return NT_STATUS_UNSUCCESSFUL;
2494         }
2495         ldap_msgfree(result);
2496
2497         slprintf (filter, sizeof (filter) - 1, "uid=%s", username);
2498         rc = ldapsam_search_suffix(ldap_state, filter, attr, &result);
2499         if (rc != LDAP_SUCCESS) {
2500                 return NT_STATUS_UNSUCCESSFUL;
2501         }
2502
2503         num_result = ldap_count_entries(ldap_state->ldap_struct, result);
2504         
2505         if (num_result > 1) {
2506                 DEBUG (0, ("More than one user with that uid exists: bailing out!\n"));
2507                 ldap_msgfree(result);
2508                 return NT_STATUS_UNSUCCESSFUL;
2509         }
2510         
2511         /* Check if we need to update an existing entry */
2512         if (num_result == 1) {
2513                 char *tmp;
2514                 
2515                 DEBUG(3,("User exists without samba properties: adding them\n"));
2516                 ldap_op = LDAP_MOD_REPLACE;
2517                 entry = ldap_first_entry (ldap_state->ldap_struct, result);
2518                 tmp = ldap_get_dn (ldap_state->ldap_struct, entry);
2519                 slprintf (dn, sizeof (dn) - 1, "%s", tmp);
2520                 ldap_memfree (tmp);
2521         } else {
2522                 /* Check if we need to add an entry */
2523                 DEBUG(3,("Adding new user\n"));
2524                 ldap_op = LDAP_MOD_ADD;
2525                 if (username[strlen(username)-1] == '$') {
2526                         slprintf (dn, sizeof (dn) - 1, "uid=%s,%s", username, lp_ldap_machine_suffix ());
2527                 } else {
2528                         slprintf (dn, sizeof (dn) - 1, "uid=%s,%s", username, lp_ldap_user_suffix ());
2529                 }
2530         }
2531
2532         if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd,
2533                                 element_is_set_or_changed)) {
2534                 DEBUG(0, ("ldapsam_add_sam_account: init_ldap_from_sam failed!\n"));
2535                 ldap_msgfree(result);
2536                 return NT_STATUS_UNSUCCESSFUL;          
2537         }
2538         
2539         ldap_msgfree(result);
2540
2541         if (mods == NULL) {
2542                 DEBUG(0,("mods is empty: nothing to add for user: %s\n",pdb_get_username(newpwd)));
2543                 return NT_STATUS_UNSUCCESSFUL;
2544         }
2545         
2546         make_a_mod(&mods, LDAP_MOD_ADD, "objectclass", "sambaAccount");
2547
2548         ret = ldapsam_modify_entry(my_methods,newpwd,dn,mods,ldap_op, element_is_set_or_changed);
2549         if (NT_STATUS_IS_ERR(ret)) {
2550                 DEBUG(0,("failed to modify/add user with uid = %s (dn = %s)\n",
2551                          pdb_get_username(newpwd),dn));
2552                 ldap_mods_free(mods,1);
2553                 return ret;
2554         }
2555
2556         DEBUG(2,("added: uid = %s in the LDAP database\n", pdb_get_username(newpwd)));
2557         ldap_mods_free(mods, 1);
2558         return NT_STATUS_OK;
2559 }
2560
2561 static void free_private_data(void **vp) 
2562 {
2563         struct ldapsam_privates **ldap_state = (struct ldapsam_privates **)vp;
2564
2565         ldapsam_close(*ldap_state);
2566
2567         if ((*ldap_state)->bind_secret) {
2568                 memset((*ldap_state)->bind_secret, '\0', strlen((*ldap_state)->bind_secret));
2569         }
2570
2571         ldapsam_close(*ldap_state);
2572                 
2573         SAFE_FREE((*ldap_state)->bind_dn);
2574         SAFE_FREE((*ldap_state)->bind_secret);
2575
2576         *ldap_state = NULL;
2577
2578         /* No need to free any further, as it is talloc()ed */
2579 }
2580
2581 static const char *group_attr[] = {"cn", "ntSid", "ntGroupType",
2582                                    "gidNumber",
2583                                    "displayName", "description",
2584                                    NULL };
2585                                    
2586 static int ldapsam_search_one_group (struct ldapsam_privates *ldap_state,
2587                                      const char *filter,
2588                                      LDAPMessage ** result)
2589 {
2590         int scope = LDAP_SCOPE_SUBTREE;
2591         int rc;
2592
2593         DEBUG(2, ("ldapsam_search_one_group: searching for:[%s]\n", filter));
2594
2595         rc = ldapsam_search(ldap_state, lp_ldap_suffix (), scope,
2596                             filter, group_attr, 0, result);
2597
2598         if (rc != LDAP_SUCCESS) {
2599                 char *ld_error = NULL;
2600                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
2601                                 &ld_error);
2602                 DEBUG(0, ("ldapsam_search_one_group: "
2603                           "Problem during the LDAP search: LDAP error: %s (%s)",
2604                           ld_error?ld_error:"(unknown)", ldap_err2string(rc)));
2605                 DEBUG(3, ("ldapsam_search_one_group: Query was: %s, %s\n",
2606                           lp_ldap_suffix(), filter));
2607                 SAFE_FREE(ld_error);
2608         }
2609
2610         return rc;
2611 }
2612
2613 static BOOL init_group_from_ldap(struct ldapsam_privates *ldap_state,
2614                                  GROUP_MAP *map, LDAPMessage *entry)
2615 {
2616         pstring temp;
2617
2618         if (ldap_state == NULL || map == NULL || entry == NULL ||
2619             ldap_state->ldap_struct == NULL) {
2620                 DEBUG(0, ("init_group_from_ldap: NULL parameters found!\n"));
2621                 return False;
2622         }
2623
2624         if (!get_single_attribute(ldap_state->ldap_struct, entry, "gidNumber",
2625                                   temp)) {
2626                 DEBUG(0, ("Mandatory attribute gidNumber not found\n"));
2627                 return False;
2628         }
2629         DEBUG(2, ("Entry found for group: %s\n", temp));
2630
2631         map->gid = (gid_t)atol(temp);
2632
2633         if (!get_single_attribute(ldap_state->ldap_struct, entry, "ntSid",
2634                                   temp)) {
2635                 DEBUG(0, ("Mandatory attribute ntSid not found\n"));
2636                 return False;
2637         }
2638         string_to_sid(&map->sid, temp);
2639
2640         if (!get_single_attribute(ldap_state->ldap_struct, entry, "ntGroupType",
2641                                   temp)) {
2642                 DEBUG(0, ("Mandatory attribute ntGroupType not found\n"));
2643                 return False;
2644         }
2645         map->sid_name_use = (uint32)atol(temp);
2646
2647         if ((map->sid_name_use < SID_NAME_USER) ||
2648             (map->sid_name_use > SID_NAME_UNKNOWN)) {
2649                 DEBUG(0, ("Unknown Group type: %d\n", map->sid_name_use));
2650                 return False;
2651         }
2652
2653         if (!get_single_attribute(ldap_state->ldap_struct, entry, "displayName",
2654                                   temp)) {
2655                 DEBUG(3, ("Attribute displayName not found\n"));
2656                 temp[0] = '\0';
2657                 if (!get_single_attribute(ldap_state->ldap_struct, entry, "cn",
2658                                           temp)) {
2659                         DEBUG(0, ("Attributes cn not found either "
2660                                   "for gidNumber(%i)\n",map->gid));
2661                         return False;
2662                 }
2663         }
2664         fstrcpy(map->nt_name, temp);
2665
2666         if (!get_single_attribute(ldap_state->ldap_struct, entry, "description",
2667                                   temp)) {
2668                 DEBUG(3, ("Attribute description not found\n"));
2669                 temp[0] = '\0';
2670         }
2671         fstrcpy(map->comment, temp);
2672
2673         map->systemaccount = 0;
2674         init_privilege(&map->priv_set);
2675
2676         return True;
2677 }
2678
2679 static BOOL init_ldap_from_group(LDAP *ldap_struct,
2680                                  LDAPMessage *existing,
2681                                  LDAPMod ***mods,
2682                                  const GROUP_MAP *map)
2683 {
2684         pstring tmp;
2685
2686         if (mods == NULL || map == NULL) {
2687                 DEBUG(0, ("init_ldap_from_group: NULL parameters found!\n"));
2688                 return False;
2689         }
2690
2691         *mods = NULL;
2692
2693         sid_to_string(tmp, &map->sid);
2694         make_ldap_mod(ldap_struct, existing, mods, "ntSid", tmp);
2695         snprintf(tmp, sizeof(tmp)-1, "%i", map->sid_name_use);
2696         make_ldap_mod(ldap_struct, existing, mods, "ntGroupType", tmp);
2697
2698         make_ldap_mod(ldap_struct, existing, mods, "displayName", map->nt_name);
2699         make_ldap_mod(ldap_struct, existing, mods, "description", map->comment);
2700
2701         return True;
2702 }
2703
2704 static NTSTATUS ldapsam_getgroup(struct pdb_methods *methods,
2705                                  const char *filter,
2706                                  GROUP_MAP *map)
2707 {
2708         struct ldapsam_privates *ldap_state =
2709                 (struct ldapsam_privates *)methods->private_data;
2710         LDAPMessage *result;
2711         LDAPMessage *entry;
2712         int count;
2713
2714         if (ldapsam_search_one_group(ldap_state, filter, &result)
2715             != LDAP_SUCCESS) {
2716                 return NT_STATUS_NO_SUCH_GROUP;
2717         }
2718
2719         count = ldap_count_entries(ldap_state->ldap_struct, result);
2720
2721         if (count < 1) {
2722                 DEBUG(4, ("Did not find group for filter %s\n", filter));
2723                 return NT_STATUS_NO_SUCH_GROUP;
2724         }
2725
2726         if (count > 1) {
2727                 DEBUG(1, ("Duplicate entries for filter %s: count=%d\n",
2728                           filter, count));
2729                 return NT_STATUS_NO_SUCH_GROUP;
2730         }
2731
2732         entry = ldap_first_entry(ldap_state->ldap_struct, result);
2733
2734         if (!entry) {
2735                 ldap_msgfree(result);
2736                 return NT_STATUS_UNSUCCESSFUL;
2737         }
2738
2739         if (!init_group_from_ldap(ldap_state, map, entry)) {
2740                 DEBUG(1, ("init_group_from_ldap failed for group filter %s\n",
2741                           filter));
2742                 ldap_msgfree(result);
2743                 return NT_STATUS_NO_SUCH_GROUP;
2744         }
2745
2746         ldap_msgfree(result);
2747         return NT_STATUS_OK;
2748 }
2749
2750 static NTSTATUS ldapsam_getgrsid(struct pdb_methods *methods, GROUP_MAP *map,
2751                                  DOM_SID sid, BOOL with_priv)
2752 {
2753         pstring filter;
2754
2755         snprintf(filter, sizeof(filter)-1,
2756                  "(&(objectClass=sambaGroupMapping)(ntSid=%s))",
2757                  sid_string_static(&sid));
2758
2759         return ldapsam_getgroup(methods, filter, map);
2760 }
2761
2762 static NTSTATUS ldapsam_getgrgid(struct pdb_methods *methods, GROUP_MAP *map,
2763                                  gid_t gid, BOOL with_priv)
2764 {
2765         pstring filter;
2766
2767         snprintf(filter, sizeof(filter)-1,
2768                  "(&(objectClass=sambaGroupMapping)(gidNumber=%d))",
2769                  gid);
2770
2771         return ldapsam_getgroup(methods, filter, map);
2772 }
2773
2774 static NTSTATUS ldapsam_getgrnam(struct pdb_methods *methods, GROUP_MAP *map,
2775                                  char *name, BOOL with_priv)
2776 {
2777         pstring filter;
2778
2779         /* TODO: Escaping of name? */
2780
2781         snprintf(filter, sizeof(filter)-1,
2782                  "(&(objectClass=sambaGroupMapping)(|(displayName=%s)(cn=%s)))",
2783                  name, name);
2784
2785         return ldapsam_getgroup(methods, filter, map);
2786 }
2787
2788 static int ldapsam_search_one_group_by_gid(struct ldapsam_privates *ldap_state,
2789                                            gid_t gid,
2790                                            LDAPMessage **result)
2791 {
2792         pstring filter;
2793
2794         snprintf(filter, sizeof(filter)-1,
2795                  "(&(objectClass=posixGroup)(gidNumber=%i))", gid);
2796
2797         return ldapsam_search_one_group(ldap_state, filter, result);
2798 }
2799
2800 static NTSTATUS ldapsam_add_group_mapping_entry(struct pdb_methods *methods,
2801                                                 GROUP_MAP *map)
2802 {
2803         struct ldapsam_privates *ldap_state =
2804                 (struct ldapsam_privates *)methods->private_data;
2805         LDAPMessage *result = NULL;
2806         LDAPMod **mods = NULL;
2807
2808         char *tmp;
2809         pstring dn;
2810         LDAPMessage *entry;
2811
2812         GROUP_MAP dummy;
2813
2814         int rc;
2815
2816         if (NT_STATUS_IS_OK(ldapsam_getgrgid(methods, &dummy,
2817                                              map->gid, False))) {
2818                 DEBUG(0, ("Group %i already exists in LDAP\n", map->gid));
2819                 return NT_STATUS_UNSUCCESSFUL;
2820         }
2821
2822         rc = ldapsam_search_one_group_by_gid(ldap_state, map->gid, &result);
2823         if (rc != LDAP_SUCCESS) {
2824                 return NT_STATUS_UNSUCCESSFUL;
2825         }
2826
2827         if (ldap_count_entries(ldap_state->ldap_struct, result) != 1) {
2828                 DEBUG(2, ("Group %i must exist exactly once in LDAP\n",
2829                           map->gid));
2830                 ldap_msgfree(result);
2831                 return NT_STATUS_UNSUCCESSFUL;
2832         }
2833
2834         entry = ldap_first_entry(ldap_state->ldap_struct, result);
2835         tmp = ldap_get_dn(ldap_state->ldap_struct, entry);
2836         pstrcpy(dn, tmp);
2837         ldap_memfree(tmp);
2838
2839         if (!init_ldap_from_group(ldap_state->ldap_struct,
2840                                   result, &mods, map)) {
2841                 DEBUG(0, ("init_ldap_from_group failed!\n"));
2842                 ldap_mods_free(mods, 1);
2843                 ldap_msgfree(result);
2844                 return NT_STATUS_UNSUCCESSFUL;
2845         }
2846
2847         ldap_msgfree(result);
2848
2849         if (mods == NULL) {
2850                 DEBUG(0, ("mods is empty\n"));
2851                 return NT_STATUS_UNSUCCESSFUL;
2852         }
2853
2854         make_a_mod(&mods, LDAP_MOD_ADD, "objectClass",
2855                    "sambaGroupMapping");
2856
2857         rc = ldapsam_modify(ldap_state, dn, mods);
2858         ldap_mods_free(mods, 1);
2859
2860         if (rc != LDAP_SUCCESS) {
2861                 char *ld_error = NULL;
2862                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
2863                                 &ld_error);
2864                 DEBUG(0, ("failed to add group %i error: %s (%s)\n", map->gid, 
2865                           ld_error ? ld_error : "(unknown)", ldap_err2string(rc)));
2866                 SAFE_FREE(ld_error);
2867                 return NT_STATUS_UNSUCCESSFUL;
2868         }
2869
2870         DEBUG(2, ("successfully modified group %i in LDAP\n", map->gid));
2871         return NT_STATUS_OK;
2872 }
2873
2874 static NTSTATUS ldapsam_update_group_mapping_entry(struct pdb_methods *methods,
2875                                                    GROUP_MAP *map)
2876 {
2877         struct ldapsam_privates *ldap_state =
2878                 (struct ldapsam_privates *)methods->private_data;
2879         int rc;
2880         char *dn;
2881         LDAPMessage *result;
2882         LDAPMessage *entry;
2883         LDAPMod **mods;
2884
2885         rc = ldapsam_search_one_group_by_gid(ldap_state, map->gid, &result);
2886
2887         if (rc != LDAP_SUCCESS) {
2888                 return NT_STATUS_UNSUCCESSFUL;
2889         }
2890
2891         if (ldap_count_entries(ldap_state->ldap_struct, result) == 0) {
2892                 DEBUG(0, ("No group to modify!\n"));
2893                 ldap_msgfree(result);
2894                 return NT_STATUS_UNSUCCESSFUL;
2895         }
2896
2897         entry = ldap_first_entry(ldap_state->ldap_struct, result);
2898         dn = ldap_get_dn(ldap_state->ldap_struct, entry);
2899
2900         if (!init_ldap_from_group(ldap_state->ldap_struct,
2901                                   result, &mods, map)) {
2902                 DEBUG(0, ("init_ldap_from_group failed\n"));
2903                 ldap_msgfree(result);
2904                 return NT_STATUS_UNSUCCESSFUL;
2905         }
2906
2907         ldap_msgfree(result);
2908
2909         if (mods == NULL) {
2910                 DEBUG(4, ("mods is empty: nothing to do\n"));
2911                 return NT_STATUS_UNSUCCESSFUL;
2912         }
2913
2914         rc = ldapsam_modify(ldap_state, dn, mods);
2915
2916         ldap_mods_free(mods, 1);
2917
2918         if (rc != LDAP_SUCCESS) {
2919                 char *ld_error = NULL;
2920                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
2921                                 &ld_error);
2922                 DEBUG(0, ("failed to modify group %i error: %s (%s)\n", map->gid, 
2923                           ld_error ? ld_error : "(unknown)", ldap_err2string(rc)));
2924                 SAFE_FREE(ld_error);
2925         }
2926
2927         DEBUG(2, ("successfully modified group %i in LDAP\n", map->gid));
2928         return NT_STATUS_OK;
2929 }
2930
2931 static NTSTATUS ldapsam_delete_group_mapping_entry(struct pdb_methods *methods,
2932                                                    DOM_SID sid)
2933 {
2934         struct ldapsam_privates *ldap_state =
2935                 (struct ldapsam_privates *)methods->private_data;
2936         pstring sidstring, filter;
2937         LDAPMessage *result;
2938         int rc;
2939         NTSTATUS ret;
2940
2941         const char *sam_group_attrs[] = { "ntSid", "ntGroupType",
2942                                           "description", "displayName",
2943                                           NULL };
2944         sid_to_string(sidstring, &sid);
2945         snprintf(filter, sizeof(filter)-1,
2946                  "(&(objectClass=sambaGroupMapping)(ntSid=%s))", sidstring);
2947
2948         rc = ldapsam_search_one_group(ldap_state, filter, &result);
2949
2950         if (rc != LDAP_SUCCESS) {
2951                 return NT_STATUS_NO_SUCH_GROUP;
2952         }
2953
2954         ret = ldapsam_delete_entry(ldap_state, result, "sambaGroupMapping",
2955                                    sam_group_attrs);
2956         ldap_msgfree(result);
2957         return ret;
2958 }
2959
2960 static NTSTATUS ldapsam_setsamgrent(struct pdb_methods *my_methods,
2961                                     BOOL update)
2962 {
2963         struct ldapsam_privates *ldap_state =
2964                 (struct ldapsam_privates *)my_methods->private_data;
2965         const char *filter = "(objectClass=sambaGroupMapping)";
2966         int rc;
2967
2968         rc = ldapsam_search(ldap_state, lp_ldap_suffix(),
2969                             LDAP_SCOPE_SUBTREE, filter,
2970                             group_attr, 0, &ldap_state->result);
2971
2972         if (rc != LDAP_SUCCESS) {
2973                 DEBUG(0, ("LDAP search failed: %s\n", ldap_err2string(rc)));
2974                 DEBUG(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
2975                 ldap_msgfree(ldap_state->result);
2976                 ldap_state->result = NULL;
2977                 return NT_STATUS_UNSUCCESSFUL;
2978         }
2979
2980         DEBUG(2, ("ldapsam_setsampwent: %d entries in the base!\n",
2981                   ldap_count_entries(ldap_state->ldap_struct,
2982                                      ldap_state->result)));
2983
2984         ldap_state->entry = ldap_first_entry(ldap_state->ldap_struct,
2985                                  ldap_state->result);
2986         ldap_state->index = 0;
2987
2988         return NT_STATUS_OK;
2989 }
2990
2991 static void ldapsam_endsamgrent(struct pdb_methods *my_methods)
2992 {
2993         ldapsam_endsampwent(my_methods);
2994 }
2995
2996 static NTSTATUS ldapsam_getsamgrent(struct pdb_methods *my_methods,
2997                                     GROUP_MAP *map)
2998 {
2999         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
3000         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
3001         BOOL bret = False;
3002
3003         /* The rebind proc needs this *HACK*.  We are not multithreaded, so
3004            this will work, but it's not nice. */
3005         static_ldap_state = ldap_state;
3006
3007         while (!bret) {
3008                 if (!ldap_state->entry)
3009                         return ret;
3010                 
3011                 ldap_state->index++;
3012                 bret = init_group_from_ldap(ldap_state, map, ldap_state->entry);
3013                 
3014                 ldap_state->entry = ldap_next_entry(ldap_state->ldap_struct,
3015                                             ldap_state->entry); 
3016         }
3017
3018         return NT_STATUS_OK;
3019 }
3020
3021 static NTSTATUS ldapsam_enum_group_mapping(struct pdb_methods *methods,
3022                                            enum SID_NAME_USE sid_name_use,
3023                                            GROUP_MAP **rmap, int *num_entries,
3024                                            BOOL unix_only, BOOL with_priv)
3025 {
3026         GROUP_MAP map;
3027         GROUP_MAP *mapt;
3028         int entries = 0;
3029         NTSTATUS nt_status;
3030
3031         *num_entries = 0;
3032         *rmap = NULL;
3033
3034         if (!NT_STATUS_IS_OK(ldapsam_setsamgrent(methods, False))) {
3035                 DEBUG(0, ("Unable to open passdb\n"));
3036                 return NT_STATUS_ACCESS_DENIED;
3037         }
3038
3039         while (NT_STATUS_IS_OK(nt_status = ldapsam_getsamgrent(methods, &map))) {
3040                 if (sid_name_use != SID_NAME_UNKNOWN &&
3041                     sid_name_use != map.sid_name_use) {
3042                         DEBUG(11,("enum_group_mapping: group %s is not of the requested type\n", map.nt_name));
3043                         continue;
3044                 }
3045                 if (unix_only==ENUM_ONLY_MAPPED && map.gid==-1) {
3046                         DEBUG(11,("enum_group_mapping: group %s is non mapped\n", map.nt_name));
3047                         continue;
3048                 }
3049
3050                 mapt=(GROUP_MAP *)Realloc((*rmap), (entries+1)*sizeof(GROUP_MAP));
3051                 if (!mapt) {
3052                         DEBUG(0,("enum_group_mapping: Unable to enlarge group map!\n"));
3053                         SAFE_FREE(*rmap);
3054                         return NT_STATUS_UNSUCCESSFUL;
3055                 }
3056                 else
3057                         (*rmap) = mapt;
3058
3059                 mapt[entries] = map;
3060
3061                 entries += 1;
3062
3063         }
3064         ldapsam_endsamgrent(methods);
3065
3066         *num_entries = entries;
3067
3068         return NT_STATUS_OK;
3069 }
3070
3071 static NTSTATUS pdb_init_ldapsam_common(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
3072 {
3073         NTSTATUS nt_status;
3074         struct ldapsam_privates *ldap_state;
3075
3076         if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
3077                 return nt_status;
3078         }
3079
3080         (*pdb_method)->name = "ldapsam";
3081
3082         (*pdb_method)->setsampwent = ldapsam_setsampwent;
3083         (*pdb_method)->endsampwent = ldapsam_endsampwent;
3084         (*pdb_method)->getsampwent = ldapsam_getsampwent;
3085         (*pdb_method)->getsampwnam = ldapsam_getsampwnam;
3086         (*pdb_method)->getsampwsid = ldapsam_getsampwsid;
3087         (*pdb_method)->add_sam_account = ldapsam_add_sam_account;
3088         (*pdb_method)->update_sam_account = ldapsam_update_sam_account;
3089         (*pdb_method)->delete_sam_account = ldapsam_delete_sam_account;
3090
3091         (*pdb_method)->getgrsid = ldapsam_getgrsid;
3092         (*pdb_method)->getgrgid = ldapsam_getgrgid;
3093         (*pdb_method)->getgrnam = ldapsam_getgrnam;
3094         (*pdb_method)->add_group_mapping_entry = ldapsam_add_group_mapping_entry;
3095         (*pdb_method)->update_group_mapping_entry = ldapsam_update_group_mapping_entry;
3096         (*pdb_method)->delete_group_mapping_entry = ldapsam_delete_group_mapping_entry;
3097         (*pdb_method)->enum_group_mapping = ldapsam_enum_group_mapping;
3098
3099         /* TODO: Setup private data and free */
3100
3101         ldap_state = talloc_zero(pdb_context->mem_ctx, sizeof(struct ldapsam_privates));
3102
3103         if (!ldap_state) {
3104                 DEBUG(0, ("talloc() failed for ldapsam private_data!\n"));
3105                 return NT_STATUS_NO_MEMORY;
3106         }
3107
3108         if (location) {
3109                 ldap_state->uri = talloc_strdup(pdb_context->mem_ctx, location);
3110         } else {
3111                 ldap_state->uri = "ldap://localhost";
3112         }
3113
3114         ldap_state->domain_name = talloc_strdup(pdb_context->mem_ctx, lp_workgroup());
3115         if (!ldap_state->domain_name) {
3116                 return NT_STATUS_NO_MEMORY;
3117         }
3118
3119         sid_copy(&ldap_state->domain_sid, get_global_sam_sid());
3120
3121         ldap_state->use_ntsid = True;
3122
3123         (*pdb_method)->private_data = ldap_state;
3124
3125         (*pdb_method)->free_private_data = free_private_data;
3126
3127         return NT_STATUS_OK;
3128 }
3129
3130 static NTSTATUS pdb_init_ldapsam_compat(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
3131 {
3132         NTSTATUS nt_status;
3133         struct ldapsam_privates *ldap_state;
3134
3135         if (!NT_STATUS_IS_OK(nt_status = pdb_init_ldapsam_common(pdb_context, pdb_method, location))) {
3136                 return nt_status;
3137         }
3138
3139         (*pdb_method)->name = "ldapsam_compat";
3140
3141         ldap_state = (*pdb_method)->private_data;
3142         ldap_state->use_ntsid = False;
3143
3144         if (location) {
3145                 ldap_state->uri = talloc_strdup(pdb_context->mem_ctx, location);
3146         } else {
3147 #ifndef WITH_LDAP_SAMCONFIG
3148                 ldap_state->uri = "ldap://localhost";
3149 #else
3150                 int ldap_port = lp_ldap_port();
3151                         
3152                 /* remap default port if not using SSL (ie clear or TLS) */
3153                 if ( (lp_ldap_ssl() != LDAP_SSL_ON) && (ldap_port == 636) ) {
3154                         ldap_port = 389;
3155                 }
3156
3157                 ldap_state->uri = talloc_asprintf(pdb_context->mem_ctx, "%s://%s:%d", lp_ldap_ssl() == LDAP_SSL_ON ? "ldaps" : "ldap", lp_ldap_server(), ldap_port);
3158                 if (!ldap_state->uri) {
3159                         return NT_STATUS_NO_MEMORY;
3160                 }
3161 #endif
3162         }
3163
3164         return NT_STATUS_OK;
3165 }
3166
3167 static NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
3168 {
3169         NTSTATUS nt_status;
3170         struct ldapsam_privates *ldap_state;
3171         uint32 low_idmap_uid, high_idmap_uid;
3172         uint32 low_idmap_gid, high_idmap_gid;
3173
3174         if (!NT_STATUS_IS_OK(nt_status = pdb_init_ldapsam_common(pdb_context, pdb_method, location))) {
3175                 return nt_status;
3176         }
3177
3178         (*pdb_method)->name = "ldapsam";
3179
3180         ldap_state = (*pdb_method)->private_data;
3181         
3182         ldap_state->permit_non_unix_accounts = True;
3183
3184         /* We know these uids can't turn up as algorithmic RIDs */
3185         if (!lp_idmap_uid(&low_idmap_uid, &high_idmap_uid)) {
3186                 DEBUG(0, ("cannot use ldapsam_nua without 'idmap uid' range in smb.conf!\n"));
3187                 return NT_STATUS_UNSUCCESSFUL;
3188         }
3189
3190         /* We know these gids can't turn up as algorithmic RIDs */
3191         if (!lp_idmap_gid(&low_idmap_gid, &high_idmap_gid)) {
3192                 DEBUG(0, ("cannot use ldapsam_nua without 'wibnind gid' range in smb.conf!\n"));
3193                 return NT_STATUS_UNSUCCESSFUL;
3194         }
3195
3196         ldap_state->low_allocated_user_rid=fallback_pdb_uid_to_user_rid(low_idmap_uid);
3197
3198         ldap_state->high_allocated_user_rid=fallback_pdb_uid_to_user_rid(high_idmap_uid);
3199
3200         ldap_state->low_allocated_group_rid=pdb_gid_to_group_rid(low_idmap_gid);
3201
3202         ldap_state->high_allocated_group_rid=pdb_gid_to_group_rid(high_idmap_gid);
3203
3204         return NT_STATUS_OK;
3205 }
3206
3207 NTSTATUS pdb_ldap_init(void)
3208 {
3209         NTSTATUS nt_status;
3210         if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "ldapsam", pdb_init_ldapsam)))
3211                 return nt_status;
3212
3213         if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "ldapsam_compat", pdb_init_ldapsam_compat)))
3214                 return nt_status;
3215
3216         return NT_STATUS_OK;
3217 }