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