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