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