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