Implement abartlet's suggestion to add attribs to ldap if they
[tprouty/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, BOOL pdb_add,
1296                           enum pdb_elements element,
1297                           const char *attribute, const char *newval)
1298 {
1299         char **values = NULL;
1300
1301         if (!need_ldap_mod(pdb_add, sampass, element)) {
1302                 return;
1303         }
1304
1305         if (existing != NULL) {
1306                 values = ldap_get_values(ldap_struct, existing, attribute);
1307         }
1308
1309         if ((values != NULL) && (values[0] != NULL) &&
1310             strcmp(values[0], newval) == 0) {
1311                 
1312                 /* Believe it or not, but LDAP will deny a delete and
1313                    an add at the same time if the values are the
1314                    same... */
1315
1316                 ldap_value_free(values);
1317                 return;
1318         }
1319
1320         /* Regardless of the real operation (add or modify)
1321            we add the new value here. We rely on deleting
1322            the old value, should it exist. */
1323
1324         if ((newval != NULL) && (strlen(newval) > 0)) {
1325                 make_a_mod(mods, LDAP_MOD_ADD, attribute, newval);
1326         }
1327
1328         if (values == NULL) {
1329                 /* There has been no value before, so don't delete it.
1330                    Here's a possible race: We might end up with
1331                    duplicate attributes */
1332                 return;
1333         }
1334
1335         /* By deleting exactly the value we found in the entry this
1336            should be race-free in the sense that the LDAP-Server will
1337            deny the complete operation if somebody changed the
1338            attribute behind our back. */
1339
1340         make_a_mod(mods, LDAP_MOD_DELETE, attribute, values[0]);
1341         ldap_value_free(values);
1342 }
1343
1344 /**********************************************************************
1345 Initialize SAM_ACCOUNT from an LDAP query
1346 (Based on init_buffer_from_sam in pdb_tdb.c)
1347 *********************************************************************/
1348 static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state, 
1349                                 LDAPMessage *existing,
1350                                 LDAPMod *** mods, const SAM_ACCOUNT * sampass,
1351                                 BOOL pdb_add)
1352 {
1353         pstring temp;
1354         uint32 rid;
1355
1356         if (mods == NULL || sampass == NULL) {
1357                 DEBUG(0, ("init_ldap_from_sam: NULL parameters found!\n"));
1358                 return False;
1359         }
1360
1361         *mods = NULL;
1362
1363         /* 
1364          * took out adding "objectclass: sambaAccount"
1365          * do this on a per-mod basis
1366          */
1367         make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
1368                       PDB_USERNAME, "uid", pdb_get_username(sampass));
1369         DEBUG(2, ("Setting entry for user: %s\n", pdb_get_username(sampass)));
1370
1371         rid = pdb_get_user_rid(sampass);
1372
1373         if (rid == 0) {
1374                 if (!IS_SAM_DEFAULT(sampass, PDB_UID)) {
1375                         rid = fallback_pdb_uid_to_user_rid(pdb_get_uid(sampass));
1376                 } else if (ldap_state->permit_non_unix_accounts) {
1377                         rid = ldapsam_get_next_available_nua_rid(ldap_state);
1378                         if (rid == 0) {
1379                                 DEBUG(0, ("NO user RID specified on account %s, and "
1380                                           "findining next available NUA RID failed, "
1381                                           "cannot store!\n",
1382                                           pdb_get_username(sampass)));
1383                                 ldap_mods_free(*mods, 1);
1384                                 return False;
1385                         }
1386                 } else {
1387                         DEBUG(0, ("NO user RID specified on account %s, "
1388                                   "cannot store!\n", pdb_get_username(sampass)));
1389                         ldap_mods_free(*mods, 1);
1390                         return False;
1391                 }
1392         }
1393
1394         slprintf(temp, sizeof(temp) - 1, "%i", rid);
1395         make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
1396                       PDB_USERSID, "rid", temp);
1397
1398
1399         rid = pdb_get_group_rid(sampass);
1400
1401         if (rid == 0) {
1402                 if (!IS_SAM_DEFAULT(sampass, PDB_GID)) {
1403                         rid = pdb_gid_to_group_rid(pdb_get_gid(sampass));
1404                 } else if (ldap_state->permit_non_unix_accounts) {
1405                         rid = DOMAIN_GROUP_RID_USERS;
1406                 } else {
1407                         DEBUG(0, ("NO group RID specified on account %s, "
1408                                   "cannot store!\n", pdb_get_username(sampass)));
1409                         ldap_mods_free(*mods, 1);
1410                         return False;
1411                 }
1412         }
1413
1414         slprintf(temp, sizeof(temp) - 1, "%i", rid);
1415         make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
1416                       PDB_GROUPSID, "primaryGroupID", temp);
1417
1418         /* displayName, cn, and gecos should all be the same
1419          *  most easily accomplished by giving them the same OID
1420          *  gecos isn't set here b/c it should be handled by the 
1421          *  add-user script
1422          *  We change displayName only and fall back to cn if
1423          *  it does not exist.
1424          */
1425
1426         make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
1427                       PDB_FULLNAME, "displayName",
1428                       pdb_get_fullname(sampass));
1429
1430         make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
1431                       PDB_ACCTDESC, "description",
1432                       pdb_get_acct_desc(sampass));
1433
1434         make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
1435                       PDB_WORKSTATIONS, "userWorkstations",
1436                       pdb_get_workstations(sampass));
1437
1438         make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
1439                       PDB_SMBHOME, "smbHome",
1440                       pdb_get_homedir(sampass));
1441                         
1442         make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
1443                       PDB_DRIVE, "homeDrive",
1444                       pdb_get_dir_drive(sampass));
1445
1446         make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
1447                       PDB_LOGONSCRIPT, "scriptPath",
1448                       pdb_get_logon_script(sampass));
1449
1450         make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
1451                       PDB_PROFILE, "profilePath",
1452                       pdb_get_profile_path(sampass));
1453
1454         slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logon_time(sampass));
1455         make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
1456                       PDB_LOGONTIME, "logonTime", temp);
1457
1458         slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logoff_time(sampass));
1459         make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
1460                       PDB_LOGOFFTIME, "logoffTime", temp);
1461
1462         slprintf (temp, sizeof (temp) - 1, "%li",
1463                   pdb_get_kickoff_time(sampass));
1464         make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
1465                       PDB_KICKOFFTIME, "kickoffTime", temp);
1466
1467         slprintf (temp, sizeof (temp) - 1, "%li",
1468                   pdb_get_pass_can_change_time(sampass));
1469         make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
1470                       PDB_CANCHANGETIME, "pwdCanChange", temp);
1471
1472         slprintf (temp, sizeof (temp) - 1, "%li",
1473                   pdb_get_pass_must_change_time(sampass));
1474         make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
1475                       PDB_MUSTCHANGETIME, "pwdMustChange", temp);
1476
1477         if ((pdb_get_acct_ctrl(sampass)&(ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST))||
1478             (lp_ldap_passwd_sync()!=LDAP_PASSWD_SYNC_ONLY)) {
1479
1480                 pdb_sethexpwd (temp, pdb_get_lanman_passwd(sampass),
1481                                pdb_get_acct_ctrl(sampass));
1482                 make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
1483                               PDB_LMPASSWD, "lmPassword", temp);
1484
1485                 pdb_sethexpwd (temp, pdb_get_nt_passwd(sampass),
1486                                pdb_get_acct_ctrl(sampass));
1487                 make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
1488                               PDB_NTPASSWD, "ntPassword", temp);
1489
1490                 slprintf (temp, sizeof (temp) - 1, "%li",
1491                           pdb_get_pass_last_set_time(sampass));
1492                 make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
1493                               PDB_PASSLASTSET, "pwdLastSet", temp);
1494         }
1495
1496         /* FIXME: Hours stuff goes in LDAP  */
1497         make_ldap_mod(ldap_state->ldap_struct, existing, mods, sampass, pdb_add,
1498                       PDB_ACCTCTRL, "acctFlags",
1499                       pdb_encode_acct_ctrl (pdb_get_acct_ctrl(sampass),
1500                                             NEW_PW_FORMAT_SPACE_PADDED_LEN));
1501         return True;
1502 }
1503
1504
1505 /**********************************************************************
1506 Connect to LDAP server and find the next available RID.
1507 *********************************************************************/
1508 static uint32 check_nua_rid_is_avail(struct ldapsam_privates *ldap_state, uint32 top_rid) 
1509 {
1510         LDAPMessage *result;
1511         uint32 final_rid = (top_rid & (~USER_RID_TYPE)) + RID_MULTIPLIER;
1512         if (top_rid == 0) {
1513                 return 0;
1514         }
1515         
1516         if (final_rid < ldap_state->low_nua_rid || final_rid > ldap_state->high_nua_rid) {
1517                 return 0;
1518         }
1519
1520         if (ldapsam_search_one_user_by_rid(ldap_state, final_rid, &result) != LDAP_SUCCESS) {
1521                 DEBUG(0, ("Cannot allocate NUA RID %d (0x%x), as the confirmation search failed!\n", final_rid, final_rid));
1522                 return 0;
1523         }
1524
1525         if (ldap_count_entries(ldap_state->ldap_struct, result) != 0) {
1526                 DEBUG(0, ("Cannot allocate NUA RID %d (0x%x), as the RID is already in use!!\n", final_rid, final_rid));
1527                 ldap_msgfree(result);
1528                 return 0;
1529         }
1530
1531         DEBUG(5, ("NUA RID %d (0x%x), declared valid\n", final_rid, final_rid));
1532         ldap_msgfree(result);
1533         return final_rid;
1534 }
1535
1536 /**********************************************************************
1537 Extract the RID from an LDAP entry
1538 *********************************************************************/
1539 static uint32 entry_to_user_rid(struct ldapsam_privates *ldap_state, LDAPMessage *entry) {
1540         uint32 rid;
1541         SAM_ACCOUNT *user = NULL;
1542         if (!NT_STATUS_IS_OK(pdb_init_sam(&user))) {
1543                 return 0;
1544         }
1545
1546         if (init_sam_from_ldap(ldap_state, user, entry)) {
1547                 rid = pdb_get_user_rid(user);
1548         } else {
1549                 rid =0;
1550         }
1551         pdb_free_sam(&user);
1552         if (rid >= ldap_state->low_nua_rid && rid <= ldap_state->high_nua_rid) {
1553                 return rid;
1554         }
1555         return 0;
1556 }
1557
1558
1559 /**********************************************************************
1560 Connect to LDAP server and find the next available RID.
1561 *********************************************************************/
1562 static uint32 search_top_nua_rid(struct ldapsam_privates *ldap_state)
1563 {
1564         int rc;
1565         pstring filter;
1566         LDAPMessage *result;
1567         LDAPMessage *entry;
1568         char *final_filter = NULL;
1569         uint32 top_rid = 0;
1570         uint32 count;
1571         uint32 rid;
1572
1573         pstrcpy(filter, lp_ldap_filter());
1574         all_string_sub(filter, "%u", "*", sizeof(pstring));
1575
1576 #if 0
1577         asprintf(&final_filter, "(&(%s)(&(rid>=%d)(rid<=%d)))", filter, ldap_state->low_nua_rid, ldap_state->high_nua_rid);
1578 #else 
1579         final_filter = strdup(filter);
1580 #endif  
1581         DEBUG(2, ("ldapsam_get_next_available_nua_rid: searching for:[%s]\n", final_filter));
1582
1583         rc = ldapsam_search(ldap_state, lp_ldap_suffix(),
1584                            LDAP_SCOPE_SUBTREE, final_filter, attr, 0,
1585                            &result);
1586
1587         if (rc != LDAP_SUCCESS) {
1588                 DEBUG(3, ("LDAP search failed! cannot find base for NUA RIDs: %s\n", ldap_err2string(rc)));
1589                 DEBUGADD(3, ("Query was: %s, %s\n", lp_ldap_suffix(), final_filter));
1590
1591                 free(final_filter);
1592                 result = NULL;
1593                 return 0;
1594         }
1595         
1596         count = ldap_count_entries(ldap_state->ldap_struct, result);
1597         DEBUG(2, ("search_top_nua_rid: %d entries in the base!\n", count));
1598         
1599         if (count == 0) {
1600                 DEBUG(3, ("LDAP search returned no records, assuming no non-unix-accounts present!: %s\n", ldap_err2string(rc)));
1601                 DEBUGADD(3, ("Query was: %s, %s\n", lp_ldap_suffix(), final_filter));
1602                 free(final_filter);
1603                 ldap_msgfree(result);
1604                 result = NULL;
1605                 return ldap_state->low_nua_rid;
1606         }
1607         
1608         free(final_filter);
1609         entry = ldap_first_entry(ldap_state->ldap_struct,result);
1610
1611         top_rid = entry_to_user_rid(ldap_state, entry);
1612
1613         while ((entry = ldap_next_entry(ldap_state->ldap_struct, entry))) {
1614
1615                 rid = entry_to_user_rid(ldap_state, entry);
1616                 if (rid > top_rid) {
1617                         top_rid = rid;
1618                 }
1619         }
1620
1621         ldap_msgfree(result);
1622
1623         if (top_rid < ldap_state->low_nua_rid) 
1624                 top_rid = ldap_state->low_nua_rid;
1625
1626         return top_rid;
1627 }
1628
1629 /**********************************************************************
1630 Connect to LDAP server and find the next available RID.
1631 *********************************************************************/
1632 static uint32 ldapsam_get_next_available_nua_rid(struct ldapsam_privates *ldap_state) {
1633         uint32 next_nua_rid;
1634         uint32 top_nua_rid;
1635
1636         top_nua_rid = search_top_nua_rid(ldap_state);
1637
1638         next_nua_rid = check_nua_rid_is_avail(ldap_state, 
1639                                               top_nua_rid);
1640         
1641         return next_nua_rid;
1642 }
1643
1644 /**********************************************************************
1645 Connect to LDAP server for password enumeration
1646 *********************************************************************/
1647 static NTSTATUS ldapsam_setsampwent(struct pdb_methods *my_methods, BOOL update)
1648 {
1649         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
1650         int rc;
1651         pstring filter;
1652
1653         pstrcpy(filter, lp_ldap_filter());
1654         all_string_sub(filter, "%u", "*", sizeof(pstring));
1655
1656         rc = ldapsam_search(ldap_state, lp_ldap_suffix(),
1657                            LDAP_SCOPE_SUBTREE, filter, attr, 0,
1658                            &ldap_state->result);
1659
1660         if (rc != LDAP_SUCCESS) {
1661                 DEBUG(0, ("LDAP search failed: %s\n", ldap_err2string(rc)));
1662                 DEBUG(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
1663                 ldap_msgfree(ldap_state->result);
1664                 ldap_state->result = NULL;
1665                 return NT_STATUS_UNSUCCESSFUL;
1666         }
1667
1668         DEBUG(2, ("ldapsam_setsampwent: %d entries in the base!\n",
1669                 ldap_count_entries(ldap_state->ldap_struct,
1670                 ldap_state->result)));
1671
1672         ldap_state->entry = ldap_first_entry(ldap_state->ldap_struct,
1673                                  ldap_state->result);
1674         ldap_state->index = 0;
1675
1676         return NT_STATUS_OK;
1677 }
1678
1679 /**********************************************************************
1680 End enumeration of the LDAP password list 
1681 *********************************************************************/
1682 static void ldapsam_endsampwent(struct pdb_methods *my_methods)
1683 {
1684         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
1685         if (ldap_state->result) {
1686                 ldap_msgfree(ldap_state->result);
1687                 ldap_state->result = NULL;
1688         }
1689 }
1690
1691 /**********************************************************************
1692 Get the next entry in the LDAP password database 
1693 *********************************************************************/
1694 static NTSTATUS ldapsam_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT *user)
1695 {
1696         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
1697         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
1698         BOOL bret = False;
1699
1700         /* The rebind proc needs this *HACK*.  We are not multithreaded, so
1701            this will work, but it's not nice. */
1702         static_ldap_state = ldap_state;
1703
1704         while (!bret) {
1705                 if (!ldap_state->entry)
1706                         return ret;
1707                 
1708                 ldap_state->index++;
1709                 bret = init_sam_from_ldap(ldap_state, user, ldap_state->entry);
1710                 
1711                 ldap_state->entry = ldap_next_entry(ldap_state->ldap_struct,
1712                                             ldap_state->entry); 
1713         }
1714
1715         return NT_STATUS_OK;
1716 }
1717
1718 /**********************************************************************
1719 Get SAM_ACCOUNT entry from LDAP by username 
1720 *********************************************************************/
1721 static NTSTATUS ldapsam_getsampwnam(struct pdb_methods *my_methods, SAM_ACCOUNT *user, const char *sname)
1722 {
1723         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
1724         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
1725         LDAPMessage *result;
1726         LDAPMessage *entry;
1727         int count;
1728         
1729         if (ldapsam_search_one_user_by_name(ldap_state, sname, &result) != LDAP_SUCCESS) {
1730                 return NT_STATUS_NO_SUCH_USER;
1731         }
1732         
1733         count = ldap_count_entries(ldap_state->ldap_struct, result);
1734         
1735         if (count < 1) {
1736                 DEBUG(4,
1737                       ("We don't find this user [%s] count=%d\n", sname,
1738                        count));
1739                 return NT_STATUS_NO_SUCH_USER;
1740         } else if (count > 1) {
1741                 DEBUG(1,
1742                       ("Duplicate entries for this user [%s] Failing. count=%d\n", sname,
1743                        count));
1744                 return NT_STATUS_NO_SUCH_USER;
1745         }
1746
1747         entry = ldap_first_entry(ldap_state->ldap_struct, result);
1748         if (entry) {
1749                 if (!init_sam_from_ldap(ldap_state, user, entry)) {
1750                         DEBUG(1,("ldapsam_getsampwnam: init_sam_from_ldap failed for user '%s'!\n", sname));
1751                         ldap_msgfree(result);
1752                         return NT_STATUS_NO_SUCH_USER;
1753                 }
1754                 ldap_msgfree(result);
1755                 ret = NT_STATUS_OK;
1756         } else {
1757                 ldap_msgfree(result);
1758         }
1759         return ret;
1760 }
1761
1762 /**********************************************************************
1763 Get SAM_ACCOUNT entry from LDAP by rid 
1764 *********************************************************************/
1765 static NTSTATUS ldapsam_getsampwrid(struct pdb_methods *my_methods, SAM_ACCOUNT *user, uint32 rid)
1766 {
1767         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
1768         struct ldapsam_privates *ldap_state = 
1769                 (struct ldapsam_privates *)my_methods->private_data;
1770         LDAPMessage *result;
1771         LDAPMessage *entry;
1772         int count;
1773
1774         if (ldapsam_search_one_user_by_rid(ldap_state, rid, &result) != LDAP_SUCCESS) {
1775                 return NT_STATUS_NO_SUCH_USER;
1776         }
1777
1778         count = ldap_count_entries(ldap_state->ldap_struct, result);
1779                 
1780         if (count < 1) {
1781                 DEBUG(4,
1782                       ("We don't find this rid [%i] count=%d\n", rid,
1783                        count));
1784                 return NT_STATUS_NO_SUCH_USER;
1785         } else if (count > 1) {
1786                 DEBUG(1,
1787                       ("More than one user with rid [%i]. Failing. count=%d\n", rid,
1788                        count));
1789                 return NT_STATUS_NO_SUCH_USER;
1790         }
1791
1792         entry = ldap_first_entry(ldap_state->ldap_struct, result);
1793         if (entry) {
1794                 if (!init_sam_from_ldap(ldap_state, user, entry)) {
1795                         DEBUG(1,("ldapsam_getsampwrid: init_sam_from_ldap failed!\n"));
1796                         ldap_msgfree(result);
1797                         return NT_STATUS_NO_SUCH_USER;
1798                 }
1799                 ldap_msgfree(result);
1800                 ret = NT_STATUS_OK;
1801         } else {
1802                 ldap_msgfree(result);
1803         }
1804         return ret;
1805 }
1806
1807 static NTSTATUS ldapsam_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT * user, const DOM_SID *sid)
1808 {
1809         uint32 rid;
1810         if (!sid_peek_check_rid(get_global_sam_sid(), sid, &rid))
1811                 return NT_STATUS_NO_SUCH_USER;
1812         return ldapsam_getsampwrid(my_methods, user, rid);
1813 }       
1814
1815 /********************************************************************
1816 Do the actual modification - also change a plaittext passord if 
1817 it it set.
1818 **********************************************************************/
1819
1820 static NTSTATUS ldapsam_modify_entry(struct pdb_methods *my_methods, 
1821                                      SAM_ACCOUNT *newpwd, char *dn,
1822                                      LDAPMod **mods, int ldap_op, BOOL pdb_add)
1823 {
1824         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
1825         int rc;
1826         
1827         if (!my_methods || !newpwd || !dn) {
1828                 return NT_STATUS_INVALID_PARAMETER;
1829         }
1830         
1831         if (!mods) {
1832                 DEBUG(5,("mods is empty: nothing to modify\n"));
1833                 /* may be password change below however */
1834         } else {
1835                 switch(ldap_op)
1836                 {
1837                         case LDAP_MOD_ADD: 
1838                                 make_a_mod(&mods, LDAP_MOD_ADD, "objectclass", "account");
1839                                 rc = ldapsam_add(ldap_state, dn, mods);
1840                                 break;
1841                         case LDAP_MOD_REPLACE: 
1842                                 rc = ldapsam_modify(ldap_state, dn ,mods);
1843                                 break;
1844                         default:        
1845                                 DEBUG(0,("Wrong LDAP operation type: %d!\n", ldap_op));
1846                                 return NT_STATUS_UNSUCCESSFUL;
1847                 }
1848                 
1849                 if (rc!=LDAP_SUCCESS) {
1850                         char *ld_error;
1851                         ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
1852                                         &ld_error);
1853                         DEBUG(1,
1854                               ("failed to %s user dn= %s with: %s\n\t%s\n",
1855                                ldap_op == LDAP_MOD_ADD ? "add" : "modify",
1856                                dn, ldap_err2string(rc),
1857                                ld_error));
1858                         free(ld_error);
1859                         return NT_STATUS_UNSUCCESSFUL;
1860                 }  
1861         }
1862         
1863 #ifdef LDAP_EXOP_X_MODIFY_PASSWD
1864         if (!(pdb_get_acct_ctrl(newpwd)&(ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST))&&
1865                 (lp_ldap_passwd_sync()!=LDAP_PASSWD_SYNC_OFF)&&
1866                 need_ldap_mod(pdb_add, newpwd, PDB_PLAINTEXT_PW)&&
1867                 (pdb_get_plaintext_passwd(newpwd)!=NULL)) {
1868                 BerElement *ber;
1869                 struct berval *bv;
1870                 char *retoid;
1871                 struct berval *retdata;
1872
1873                 if ((ber = ber_alloc_t(LBER_USE_DER))==NULL) {
1874                         DEBUG(0,("ber_alloc_t returns NULL\n"));
1875                         return NT_STATUS_UNSUCCESSFUL;
1876                 }
1877                 ber_printf (ber, "{");
1878                 ber_printf (ber, "ts", LDAP_TAG_EXOP_X_MODIFY_PASSWD_ID,dn);
1879                 ber_printf (ber, "ts", LDAP_TAG_EXOP_X_MODIFY_PASSWD_NEW, pdb_get_plaintext_passwd(newpwd));
1880                 ber_printf (ber, "N}");
1881
1882                 if ((rc = ber_flatten (ber, &bv))<0) {
1883                         DEBUG(0,("ber_flatten returns a value <0\n"));
1884                         return NT_STATUS_UNSUCCESSFUL;
1885                 }
1886                 
1887                 ber_free(ber,1);
1888
1889                 if ((rc = ldapsam_extended_operation(ldap_state, LDAP_EXOP_X_MODIFY_PASSWD,
1890                                                     bv, NULL, NULL, &retoid, &retdata))!=LDAP_SUCCESS) {
1891                         DEBUG(0,("LDAP Password could not be changed for user %s: %s\n",
1892                                 pdb_get_username(newpwd),ldap_err2string(rc)));
1893                 } else {
1894                         DEBUG(3,("LDAP Password changed for user %s\n",pdb_get_username(newpwd)));
1895     
1896                         ber_bvfree(retdata);
1897                         ber_memfree(retoid);
1898                 }
1899                 ber_bvfree(bv);
1900         }
1901 #else
1902         DEBUG(10,("LDAP PASSWORD SYNC is not supported!\n"));
1903 #endif /* LDAP_EXOP_X_MODIFY_PASSWD */
1904         return NT_STATUS_OK;
1905 }
1906
1907 /**********************************************************************
1908 Delete entry from LDAP for username 
1909 *********************************************************************/
1910 static NTSTATUS ldapsam_delete_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT * sam_acct)
1911 {
1912         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
1913         const char *sname;
1914         int rc;
1915         LDAPMessage *result;
1916         NTSTATUS ret;
1917         const char *sam_user_attrs[] =
1918         { "lmPassword", "ntPassword", "pwdLastSet", "logonTime", "logoffTime",
1919           "kickoffTime", "pwdCanChange", "pwdMustChange", "acctFlags",
1920           "displayName", "smbHome", "homeDrive", "scriptPath", "profilePath",
1921           "userWorkstations", "primaryGroupID", "domain", "rid", NULL };
1922
1923         if (!sam_acct) {
1924                 DEBUG(0, ("sam_acct was NULL!\n"));
1925                 return NT_STATUS_INVALID_PARAMETER;
1926         }
1927
1928         sname = pdb_get_username(sam_acct);
1929
1930         DEBUG (3, ("Deleting user %s from LDAP.\n", sname));
1931
1932         rc = ldapsam_search_one_user_by_name(ldap_state, sname, &result);
1933         if (rc != LDAP_SUCCESS) {
1934                 return NT_STATUS_NO_SUCH_USER;
1935         }
1936
1937         ret = ldapsam_delete_entry(ldap_state, result, "sambaAccount",
1938                                    sam_user_attrs);
1939         ldap_msgfree(result);
1940         return ret;
1941 }
1942
1943 /**********************************************************************
1944 Update SAM_ACCOUNT 
1945 *********************************************************************/
1946 static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT * newpwd)
1947 {
1948         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
1949         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
1950         int rc;
1951         char *dn;
1952         LDAPMessage *result;
1953         LDAPMessage *entry;
1954         LDAPMod **mods;
1955
1956         rc = ldapsam_search_one_user_by_name(ldap_state, pdb_get_username(newpwd), &result);
1957         if (rc != LDAP_SUCCESS) {
1958                 return NT_STATUS_UNSUCCESSFUL;
1959         }
1960
1961         if (ldap_count_entries(ldap_state->ldap_struct, result) == 0) {
1962                 DEBUG(0, ("No user to modify!\n"));
1963                 ldap_msgfree(result);
1964                 return NT_STATUS_UNSUCCESSFUL;
1965         }
1966
1967         entry = ldap_first_entry(ldap_state->ldap_struct, result);
1968         dn = ldap_get_dn(ldap_state->ldap_struct, entry);
1969
1970         if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd, False)) {
1971                 DEBUG(0, ("ldapsam_update_sam_account: init_ldap_from_sam failed!\n"));
1972                 ldap_msgfree(result);
1973                 return NT_STATUS_UNSUCCESSFUL;
1974         }
1975         
1976         ldap_msgfree(result);
1977         
1978         if (mods == NULL) {
1979                 DEBUG(4,("mods is empty: nothing to update for user: %s\n",
1980                          pdb_get_username(newpwd)));
1981                 ldap_mods_free(mods, 1);
1982                 return NT_STATUS_OK;
1983         }
1984         
1985         ret = ldapsam_modify_entry(my_methods,newpwd,dn,mods,LDAP_MOD_REPLACE, False);
1986         ldap_mods_free(mods,1);
1987
1988         if (NT_STATUS_IS_ERR(ret)) {
1989                 DEBUG(0,("failed to modify user with uid = %s\n",
1990                                         pdb_get_username(newpwd)));
1991                 return ret;
1992         }
1993
1994         DEBUG(2, ("successfully modified uid = %s in the LDAP database\n",
1995                   pdb_get_username(newpwd)));
1996         return NT_STATUS_OK;
1997 }
1998
1999 /**********************************************************************
2000 Add SAM_ACCOUNT to LDAP 
2001 *********************************************************************/
2002 static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT * newpwd)
2003 {
2004         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
2005         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2006         int rc;
2007         pstring filter;
2008         LDAPMessage *result = NULL;
2009         LDAPMessage *entry  = NULL;
2010         pstring dn;
2011         LDAPMod **mods = NULL;
2012         int             ldap_op;
2013         uint32          num_result;
2014         
2015         const char *username = pdb_get_username(newpwd);
2016         if (!username || !*username) {
2017                 DEBUG(0, ("Cannot add user without a username!\n"));
2018                 return NT_STATUS_INVALID_PARAMETER;
2019         }
2020
2021         rc = ldapsam_search_one_user_by_name (ldap_state, username, &result);
2022         if (rc != LDAP_SUCCESS) {
2023                 return NT_STATUS_UNSUCCESSFUL;
2024         }
2025
2026         if (ldap_count_entries(ldap_state->ldap_struct, result) != 0) {
2027                 DEBUG(0,("User '%s' already in the base, with samba properties\n", 
2028                          username));
2029                 ldap_msgfree(result);
2030                 return NT_STATUS_UNSUCCESSFUL;
2031         }
2032         ldap_msgfree(result);
2033
2034         slprintf (filter, sizeof (filter) - 1, "uid=%s", username);
2035         rc = ldapsam_search_one_user(ldap_state, filter, &result);
2036         if (rc != LDAP_SUCCESS) {
2037                 return NT_STATUS_UNSUCCESSFUL;
2038         }
2039
2040         num_result = ldap_count_entries(ldap_state->ldap_struct, result);
2041         
2042         if (num_result > 1) {
2043                 DEBUG (0, ("More than one user with that uid exists: bailing out!\n"));
2044                 ldap_msgfree(result);
2045                 return NT_STATUS_UNSUCCESSFUL;
2046         }
2047         
2048         /* Check if we need to update an existing entry */
2049         if (num_result == 1) {
2050                 char *tmp;
2051                 
2052                 DEBUG(3,("User exists without samba properties: adding them\n"));
2053                 ldap_op = LDAP_MOD_REPLACE;
2054                 entry = ldap_first_entry (ldap_state->ldap_struct, result);
2055                 tmp = ldap_get_dn (ldap_state->ldap_struct, entry);
2056                 slprintf (dn, sizeof (dn) - 1, "%s", tmp);
2057                 ldap_memfree (tmp);
2058         } else {
2059                 /* Check if we need to add an entry */
2060                 DEBUG(3,("Adding new user\n"));
2061                 ldap_op = LDAP_MOD_ADD;
2062                 if (username[strlen(username)-1] == '$') {
2063                         slprintf (dn, sizeof (dn) - 1, "uid=%s,%s", username, lp_ldap_machine_suffix ());
2064                 } else {
2065                         slprintf (dn, sizeof (dn) - 1, "uid=%s,%s", username, lp_ldap_user_suffix ());
2066                 }
2067         }
2068
2069         if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd, True)) {
2070                 DEBUG(0, ("ldapsam_add_sam_account: init_ldap_from_sam failed!\n"));
2071                 ldap_msgfree(result);
2072                 ldap_mods_free(mods, 1);
2073                 return NT_STATUS_UNSUCCESSFUL;          
2074         }
2075         
2076         ldap_msgfree(result);
2077
2078         if (mods == NULL) {
2079                 DEBUG(0,("mods is empty: nothing to add for user: %s\n",pdb_get_username(newpwd)));
2080                 return NT_STATUS_UNSUCCESSFUL;
2081         }
2082         
2083         make_a_mod(&mods, LDAP_MOD_ADD, "objectclass", "sambaAccount");
2084
2085         ret = ldapsam_modify_entry(my_methods,newpwd,dn,mods,ldap_op, True);
2086         if (NT_STATUS_IS_ERR(ret)) {
2087                 DEBUG(0,("failed to modify/add user with uid = %s (dn = %s)\n",
2088                          pdb_get_username(newpwd),dn));
2089                 ldap_mods_free(mods,1);
2090                 return ret;
2091         }
2092
2093         DEBUG(2,("added: uid = %s in the LDAP database\n", pdb_get_username(newpwd)));
2094         ldap_mods_free(mods, 1);
2095         return NT_STATUS_OK;
2096 }
2097
2098 static void free_private_data(void **vp) 
2099 {
2100         struct ldapsam_privates **ldap_state = (struct ldapsam_privates **)vp;
2101
2102         ldapsam_close(*ldap_state);
2103
2104         if ((*ldap_state)->bind_secret) {
2105                 memset((*ldap_state)->bind_secret, '\0', strlen((*ldap_state)->bind_secret));
2106         }
2107
2108         ldapsam_close(*ldap_state);
2109                 
2110         SAFE_FREE((*ldap_state)->bind_dn);
2111         SAFE_FREE((*ldap_state)->bind_secret);
2112
2113         *ldap_state = NULL;
2114
2115         /* No need to free any further, as it is talloc()ed */
2116 }
2117
2118 static const char *group_attr[] = {"cn", "ntSid", "ntGroupType",
2119                                    "gidNumber",
2120                                    "displayName", "description",
2121                                    NULL };
2122                                    
2123 static int ldapsam_search_one_group (struct ldapsam_privates *ldap_state,
2124                                      const char *filter,
2125                                      LDAPMessage ** result)
2126 {
2127         int scope = LDAP_SCOPE_SUBTREE;
2128         int rc;
2129
2130         DEBUG(2, ("ldapsam_search_one_group: searching for:[%s]\n", filter));
2131
2132         rc = ldapsam_search(ldap_state, lp_ldap_suffix (), scope,
2133                             filter, group_attr, 0, result);
2134
2135         if (rc != LDAP_SUCCESS) {
2136                 DEBUG(0, ("ldapsam_search_one_group: "
2137                           "Problem during the LDAP search: %s\n",
2138                           ldap_err2string(rc)));
2139                 DEBUG(3, ("ldapsam_search_one_group: Query was: %s, %s\n",
2140                           lp_ldap_suffix(), filter));
2141         }
2142
2143         return rc;
2144 }
2145
2146 static BOOL init_group_from_ldap(struct ldapsam_privates *ldap_state,
2147                                  GROUP_MAP *map, LDAPMessage *entry)
2148 {
2149         pstring temp;
2150
2151         if (ldap_state == NULL || map == NULL || entry == NULL ||
2152             ldap_state->ldap_struct == NULL) {
2153                 DEBUG(0, ("init_group_from_ldap: NULL parameters found!\n"));
2154                 return False;
2155         }
2156
2157         if (!get_single_attribute(ldap_state->ldap_struct, entry, "gidNumber",
2158                                   temp)) {
2159                 DEBUG(0, ("Mandatory attribute gidNumber not found\n"));
2160                 return False;
2161         }
2162         DEBUG(2, ("Entry found for group: %s\n", temp));
2163
2164         map->gid = (gid_t)atol(temp);
2165
2166         if (!get_single_attribute(ldap_state->ldap_struct, entry, "ntSid",
2167                                   temp)) {
2168                 DEBUG(0, ("Mandatory attribute ntSid not found\n"));
2169                 return False;
2170         }
2171         string_to_sid(&map->sid, temp);
2172
2173         if (!get_single_attribute(ldap_state->ldap_struct, entry, "ntGroupType",
2174                                   temp)) {
2175                 DEBUG(0, ("Mandatory attribute ntGroupType not found\n"));
2176                 return False;
2177         }
2178         map->sid_name_use = (uint32)atol(temp);
2179
2180         if ((map->sid_name_use < SID_NAME_USER) ||
2181             (map->sid_name_use > SID_NAME_UNKNOWN)) {
2182                 DEBUG(0, ("Unknown Group type: %d\n", map->sid_name_use));
2183                 return False;
2184         }
2185
2186         if (!get_single_attribute(ldap_state->ldap_struct, entry, "displayName",
2187                                   temp)) {
2188                 DEBUG(3, ("Attribute displayName not found\n"));
2189                 temp[0] = '\0';
2190         }
2191         fstrcpy(map->nt_name, temp);
2192
2193         if (!get_single_attribute(ldap_state->ldap_struct, entry, "description",
2194                                   temp)) {
2195                 DEBUG(3, ("Attribute description not found\n"));
2196                 temp[0] = '\0';
2197                 if (!get_single_attribute(ldap_state->ldap_struct, entry, "cn",
2198                                           temp)) {
2199                         DEBUG(0, ("Attributes cn not found either "
2200                                   "for gidNumber(%i)\n",map->gid));
2201                         return False;
2202                 }
2203         }
2204         fstrcpy(map->comment, temp);
2205
2206         map->systemaccount = 0;
2207         init_privilege(&map->priv_set);
2208
2209         return True;
2210 }
2211
2212 static BOOL init_ldap_from_group(struct ldapsam_privates *ldap_state,
2213                                  LDAPMod ***mods, int ldap_op,
2214                                  const GROUP_MAP *map)
2215 {
2216         pstring tmp;
2217
2218         if (mods == NULL || map == NULL) {
2219                 DEBUG(0, ("init_ldap_from_group: NULL parameters found!\n"));
2220                 return False;
2221         }
2222
2223         *mods = NULL;
2224
2225         sid_to_string(tmp, &map->sid);
2226         make_a_mod(mods, ldap_op, "ntSid", tmp);
2227
2228         snprintf(tmp, sizeof(tmp)-1, "%i", map->sid_name_use);
2229         make_a_mod(mods, ldap_op, "ntGroupType", tmp);
2230
2231         make_a_mod(mods, ldap_op, "displayName", map->nt_name);
2232         make_a_mod(mods, ldap_op, "description", map->comment);
2233
2234         return True;
2235 }
2236
2237 static NTSTATUS ldapsam_getgroup(struct pdb_methods *methods,
2238                                  const char *filter,
2239                                  GROUP_MAP *map)
2240 {
2241         struct ldapsam_privates *ldap_state =
2242                 (struct ldapsam_privates *)methods->private_data;
2243         LDAPMessage *result;
2244         LDAPMessage *entry;
2245         int count;
2246
2247         if (ldapsam_search_one_group(ldap_state, filter, &result)
2248             != LDAP_SUCCESS) {
2249                 return NT_STATUS_NO_SUCH_GROUP;
2250         }
2251
2252         count = ldap_count_entries(ldap_state->ldap_struct, result);
2253
2254         if (count < 1) {
2255                 DEBUG(4, ("Did not find group for filter %s\n", filter));
2256                 return NT_STATUS_NO_SUCH_GROUP;
2257         }
2258
2259         if (count > 1) {
2260                 DEBUG(1, ("Duplicate entries for filter %s: count=%d\n",
2261                           filter, count));
2262                 return NT_STATUS_NO_SUCH_GROUP;
2263         }
2264
2265         entry = ldap_first_entry(ldap_state->ldap_struct, result);
2266
2267         if (!entry) {
2268                 ldap_msgfree(result);
2269                 return NT_STATUS_UNSUCCESSFUL;
2270         }
2271
2272         if (!init_group_from_ldap(ldap_state, map, entry)) {
2273                 DEBUG(1, ("init_group_from_ldap failed for group filter %s\n",
2274                           filter));
2275                 ldap_msgfree(result);
2276                 return NT_STATUS_NO_SUCH_GROUP;
2277         }
2278
2279         ldap_msgfree(result);
2280         return NT_STATUS_OK;
2281 }
2282
2283 static NTSTATUS ldapsam_getgrsid(struct pdb_methods *methods, GROUP_MAP *map,
2284                                  DOM_SID sid, BOOL with_priv)
2285 {
2286         pstring filter;
2287
2288         snprintf(filter, sizeof(filter)-1,
2289                  "(&(objectClass=sambaGroupMapping)(ntSid=%s))",
2290                  sid_string_static(&sid));
2291
2292         return ldapsam_getgroup(methods, filter, map);
2293 }
2294
2295 static NTSTATUS ldapsam_getgrgid(struct pdb_methods *methods, GROUP_MAP *map,
2296                                  gid_t gid, BOOL with_priv)
2297 {
2298         pstring filter;
2299
2300         snprintf(filter, sizeof(filter)-1,
2301                  "(&(objectClass=sambaGroupMapping)(gidNumber=%d))",
2302                  gid);
2303
2304         return ldapsam_getgroup(methods, filter, map);
2305 }
2306
2307 static NTSTATUS ldapsam_getgrnam(struct pdb_methods *methods, GROUP_MAP *map,
2308                                  char *name, BOOL with_priv)
2309 {
2310         pstring filter;
2311
2312         /* TODO: Escaping of name? */
2313
2314         snprintf(filter, sizeof(filter)-1,
2315                  "(&(objectClass=sambaGroupMapping)(|(displayName=%s)(cn=%s)))",
2316                  name, name);
2317
2318         return ldapsam_getgroup(methods, filter, map);
2319 }
2320
2321 static int ldapsam_search_one_group_by_gid(struct ldapsam_privates *ldap_state,
2322                                            gid_t gid,
2323                                            LDAPMessage **result)
2324 {
2325         pstring filter;
2326
2327         snprintf(filter, sizeof(filter)-1,
2328                  "(&(objectClass=posixGroup)(gidNumber=%i))", gid);
2329
2330         return ldapsam_search_one_group(ldap_state, filter, result);
2331 }
2332
2333 static NTSTATUS ldapsam_add_group_mapping_entry(struct pdb_methods *methods,
2334                                                 GROUP_MAP *map)
2335 {
2336         struct ldapsam_privates *ldap_state =
2337                 (struct ldapsam_privates *)methods->private_data;
2338         LDAPMessage *result = NULL;
2339         LDAPMod **mods = NULL;
2340
2341         char *tmp;
2342         pstring dn;
2343         LDAPMessage *entry;
2344
2345         GROUP_MAP dummy;
2346
2347         int rc;
2348
2349         if (NT_STATUS_IS_OK(ldapsam_getgrgid(methods, &dummy,
2350                                              map->gid, False))) {
2351                 DEBUG(0, ("Group %i already exists in LDAP\n", map->gid));
2352                 return NT_STATUS_UNSUCCESSFUL;
2353         }
2354
2355         rc = ldapsam_search_one_group_by_gid(ldap_state, map->gid, &result);
2356         if (rc != LDAP_SUCCESS) {
2357                 return NT_STATUS_UNSUCCESSFUL;
2358         }
2359
2360         if (ldap_count_entries(ldap_state->ldap_struct, result) != 1) {
2361                 DEBUG(2, ("Group %i must exist exactly once in LDAP\n",
2362                           map->gid));
2363                 ldap_msgfree(result);
2364                 return NT_STATUS_UNSUCCESSFUL;
2365         }
2366
2367         entry = ldap_first_entry(ldap_state->ldap_struct, result);
2368         tmp = ldap_get_dn(ldap_state->ldap_struct, entry);
2369         pstrcpy(dn, tmp);
2370         ldap_memfree(tmp);
2371         ldap_msgfree(result);
2372
2373         if (!init_ldap_from_group(ldap_state, &mods, LDAP_MOD_ADD, map)) {
2374                 DEBUG(0, ("init_ldap_from_group failed!\n"));
2375                 ldap_mods_free(mods, 1);
2376                 return NT_STATUS_UNSUCCESSFUL;
2377         }
2378
2379         if (mods == NULL) {
2380                 DEBUG(0, ("mods is empty\n"));
2381                 return NT_STATUS_UNSUCCESSFUL;
2382         }
2383
2384         make_a_mod(&mods, LDAP_MOD_ADD, "objectClass",
2385                    "sambaGroupMapping");
2386
2387         rc = ldapsam_modify(ldap_state, dn, mods);
2388         ldap_mods_free(mods, 1);
2389
2390         if (rc != LDAP_SUCCESS) {
2391                 DEBUG(0, ("failed to modify group %i\n", map->gid));
2392                 return NT_STATUS_UNSUCCESSFUL;
2393         }
2394
2395         DEBUG(2, ("successfully modified group %i in LDAP\n", map->gid));
2396         return NT_STATUS_OK;
2397 }
2398
2399 static NTSTATUS ldapsam_update_group_mapping_entry(struct pdb_methods *methods,
2400                                                    GROUP_MAP *map)
2401 {
2402         struct ldapsam_privates *ldap_state =
2403                 (struct ldapsam_privates *)methods->private_data;
2404         int rc;
2405         char *dn;
2406         LDAPMessage *result;
2407         LDAPMessage *entry;
2408         LDAPMod **mods;
2409
2410         if (!init_ldap_from_group(ldap_state, &mods, LDAP_MOD_REPLACE, map)) {
2411                 DEBUG(0, ("init_ldap_from_group failed\n"));
2412                 return NT_STATUS_UNSUCCESSFUL;
2413         }
2414
2415         if (mods == NULL) {
2416                 DEBUG(4, ("mods is empty: nothing to do\n"));
2417                 return NT_STATUS_UNSUCCESSFUL;
2418         }
2419
2420         rc = ldapsam_search_one_group_by_gid(ldap_state, map->gid, &result);
2421
2422         if (rc != LDAP_SUCCESS) {
2423                 ldap_mods_free(mods, 1);
2424                 return NT_STATUS_UNSUCCESSFUL;
2425         }
2426
2427         if (ldap_count_entries(ldap_state->ldap_struct, result) == 0) {
2428                 DEBUG(0, ("No group to modify!\n"));
2429                 ldap_msgfree(result);
2430                 ldap_mods_free(mods, 1);
2431                 return NT_STATUS_UNSUCCESSFUL;
2432         }
2433
2434         entry = ldap_first_entry(ldap_state->ldap_struct, result);
2435         dn = ldap_get_dn(ldap_state->ldap_struct, entry);
2436         ldap_msgfree(result);
2437
2438         rc = ldapsam_modify(ldap_state, dn, mods);
2439
2440         ldap_mods_free(mods, 1);
2441
2442         if (rc != LDAP_SUCCESS) {
2443                 DEBUG(0, ("failed to modify group %i\n", map->gid));
2444         }
2445
2446         DEBUG(2, ("successfully modified group %i in LDAP\n", map->gid));
2447         return NT_STATUS_OK;
2448 }
2449
2450 static NTSTATUS ldapsam_delete_group_mapping_entry(struct pdb_methods *methods,
2451                                                    DOM_SID sid)
2452 {
2453         struct ldapsam_privates *ldap_state =
2454                 (struct ldapsam_privates *)methods->private_data;
2455         pstring sidstring, filter;
2456         LDAPMessage *result;
2457         int rc;
2458         NTSTATUS ret;
2459
2460         const char *sam_group_attrs[] = { "ntSid", "ntGroupType",
2461                                           "description", "displayName",
2462                                           NULL };
2463         sid_to_string(sidstring, &sid);
2464         snprintf(filter, sizeof(filter)-1,
2465                  "(&(objectClass=sambaGroupMapping)(ntSid=%s))", sidstring);
2466
2467         rc = ldapsam_search_one_group(ldap_state, filter, &result);
2468
2469         if (rc != LDAP_SUCCESS) {
2470                 return NT_STATUS_NO_SUCH_GROUP;
2471         }
2472
2473         ret = ldapsam_delete_entry(ldap_state, result, "sambaGroupMapping",
2474                                    sam_group_attrs);
2475         ldap_msgfree(result);
2476         return ret;
2477 }
2478
2479 static NTSTATUS ldapsam_setsamgrent(struct pdb_methods *my_methods,
2480                                     BOOL update)
2481 {
2482         struct ldapsam_privates *ldap_state =
2483                 (struct ldapsam_privates *)my_methods->private_data;
2484         const char *filter = "(objectClass=sambaGroupMapping)";
2485         int rc;
2486
2487         rc = ldapsam_search(ldap_state, lp_ldap_suffix(),
2488                             LDAP_SCOPE_SUBTREE, filter,
2489                             group_attr, 0, &ldap_state->result);
2490
2491         if (rc != LDAP_SUCCESS) {
2492                 DEBUG(0, ("LDAP search failed: %s\n", ldap_err2string(rc)));
2493                 DEBUG(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
2494                 ldap_msgfree(ldap_state->result);
2495                 ldap_state->result = NULL;
2496                 return NT_STATUS_UNSUCCESSFUL;
2497         }
2498
2499         DEBUG(2, ("ldapsam_setsampwent: %d entries in the base!\n",
2500                   ldap_count_entries(ldap_state->ldap_struct,
2501                                      ldap_state->result)));
2502
2503         ldap_state->entry = ldap_first_entry(ldap_state->ldap_struct,
2504                                  ldap_state->result);
2505         ldap_state->index = 0;
2506
2507         return NT_STATUS_OK;
2508 }
2509
2510 static void ldapsam_endsamgrent(struct pdb_methods *my_methods)
2511 {
2512         ldapsam_endsampwent(my_methods);
2513 }
2514
2515 static NTSTATUS ldapsam_getsamgrent(struct pdb_methods *my_methods,
2516                                     GROUP_MAP *map)
2517 {
2518         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
2519         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2520         BOOL bret = False;
2521
2522         /* The rebind proc needs this *HACK*.  We are not multithreaded, so
2523            this will work, but it's not nice. */
2524         static_ldap_state = ldap_state;
2525
2526         while (!bret) {
2527                 if (!ldap_state->entry)
2528                         return ret;
2529                 
2530                 ldap_state->index++;
2531                 bret = init_group_from_ldap(ldap_state, map, ldap_state->entry);
2532                 
2533                 ldap_state->entry = ldap_next_entry(ldap_state->ldap_struct,
2534                                             ldap_state->entry); 
2535         }
2536
2537         return NT_STATUS_OK;
2538 }
2539
2540 static NTSTATUS ldapsam_enum_group_mapping(struct pdb_methods *methods,
2541                                            enum SID_NAME_USE sid_name_use,
2542                                            GROUP_MAP **rmap, int *num_entries,
2543                                            BOOL unix_only, BOOL with_priv)
2544 {
2545         GROUP_MAP map;
2546         GROUP_MAP *mapt;
2547         int entries = 0;
2548         NTSTATUS nt_status;
2549
2550         *num_entries = 0;
2551         *rmap = NULL;
2552
2553         if (!NT_STATUS_IS_OK(ldapsam_setsamgrent(methods, False))) {
2554                 DEBUG(0, ("Unable to open passdb\n"));
2555                 return NT_STATUS_ACCESS_DENIED;
2556         }
2557
2558         while (NT_STATUS_IS_OK(nt_status = ldapsam_getsamgrent(methods, &map))) {
2559                 if (sid_name_use != SID_NAME_UNKNOWN &&
2560                     sid_name_use != map.sid_name_use) {
2561                         DEBUG(11,("enum_group_mapping: group %s is not of the requested type\n", map.nt_name));
2562                         continue;
2563                 }
2564                 if (unix_only==ENUM_ONLY_MAPPED && map.gid==-1) {
2565                         DEBUG(11,("enum_group_mapping: group %s is non mapped\n", map.nt_name));
2566                         continue;
2567                 }
2568
2569                 mapt=(GROUP_MAP *)Realloc((*rmap), (entries+1)*sizeof(GROUP_MAP));
2570                 if (!mapt) {
2571                         DEBUG(0,("enum_group_mapping: Unable to enlarge group map!\n"));
2572                         SAFE_FREE(*rmap);
2573                         return NT_STATUS_UNSUCCESSFUL;
2574                 }
2575                 else
2576                         (*rmap) = mapt;
2577
2578                 mapt[entries] = map;
2579
2580                 entries += 1;
2581
2582         }
2583         ldapsam_endsamgrent(methods);
2584
2585         *num_entries = entries;
2586
2587         return NT_STATUS_OK;
2588 }
2589
2590 NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
2591 {
2592         NTSTATUS nt_status;
2593         struct ldapsam_privates *ldap_state;
2594
2595         if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
2596                 return nt_status;
2597         }
2598
2599         (*pdb_method)->name = "ldapsam";
2600
2601         (*pdb_method)->setsampwent = ldapsam_setsampwent;
2602         (*pdb_method)->endsampwent = ldapsam_endsampwent;
2603         (*pdb_method)->getsampwent = ldapsam_getsampwent;
2604         (*pdb_method)->getsampwnam = ldapsam_getsampwnam;
2605         (*pdb_method)->getsampwsid = ldapsam_getsampwsid;
2606         (*pdb_method)->add_sam_account = ldapsam_add_sam_account;
2607         (*pdb_method)->update_sam_account = ldapsam_update_sam_account;
2608         (*pdb_method)->delete_sam_account = ldapsam_delete_sam_account;
2609
2610         (*pdb_method)->getgrsid = ldapsam_getgrsid;
2611         (*pdb_method)->getgrgid = ldapsam_getgrgid;
2612         (*pdb_method)->getgrnam = ldapsam_getgrnam;
2613         (*pdb_method)->add_group_mapping_entry = ldapsam_add_group_mapping_entry;
2614         (*pdb_method)->update_group_mapping_entry = ldapsam_update_group_mapping_entry;
2615         (*pdb_method)->delete_group_mapping_entry = ldapsam_delete_group_mapping_entry;
2616         (*pdb_method)->enum_group_mapping = ldapsam_enum_group_mapping;
2617
2618         /* TODO: Setup private data and free */
2619
2620         ldap_state = talloc_zero(pdb_context->mem_ctx, sizeof(struct ldapsam_privates));
2621
2622         if (!ldap_state) {
2623                 DEBUG(0, ("talloc() failed for ldapsam private_data!\n"));
2624                 return NT_STATUS_NO_MEMORY;
2625         }
2626
2627         if (location) {
2628                 ldap_state->uri = talloc_strdup(pdb_context->mem_ctx, location);
2629 #ifdef WITH_LDAP_SAMCONFIG
2630         } else {
2631                 int ldap_port = lp_ldap_port();
2632                         
2633                 /* remap default port if not using SSL (ie clear or TLS) */
2634                 if ( (lp_ldap_ssl() != LDAP_SSL_ON) && (ldap_port == 636) ) {
2635                         ldap_port = 389;
2636                 }
2637
2638                 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);
2639                 if (!ldap_state->uri) {
2640                         return NT_STATUS_NO_MEMORY;
2641                 }
2642 #else
2643         } else {
2644                 ldap_state->uri = "ldap://localhost";
2645 #endif
2646         }
2647
2648         (*pdb_method)->private_data = ldap_state;
2649
2650         (*pdb_method)->free_private_data = free_private_data;
2651
2652         return NT_STATUS_OK;
2653 }
2654
2655 NTSTATUS pdb_init_ldapsam_nua(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
2656 {
2657         NTSTATUS nt_status;
2658         struct ldapsam_privates *ldap_state;
2659         uint32 low_nua_uid, high_nua_uid;
2660
2661         if (!NT_STATUS_IS_OK(nt_status = pdb_init_ldapsam(pdb_context, pdb_method, location))) {
2662                 return nt_status;
2663         }
2664
2665         (*pdb_method)->name = "ldapsam_nua";
2666
2667         ldap_state = (*pdb_method)->private_data;
2668         
2669         ldap_state->permit_non_unix_accounts = True;
2670
2671         if (!lp_non_unix_account_range(&low_nua_uid, &high_nua_uid)) {
2672                 DEBUG(0, ("cannot use ldapsam_nua without 'non unix account range' in smb.conf!\n"));
2673                 return NT_STATUS_UNSUCCESSFUL;
2674         }
2675
2676         ldap_state->low_nua_rid=fallback_pdb_uid_to_user_rid(low_nua_uid);
2677
2678         ldap_state->high_nua_rid=fallback_pdb_uid_to_user_rid(high_nua_uid);
2679
2680         return NT_STATUS_OK;
2681 }
2682
2683 int pdb_ldap_init(void)
2684 {
2685         smb_register_passdb("ldapsam", pdb_init_ldapsam, PASSDB_INTERFACE_VERSION);
2686         smb_register_passdb("ldapsam_nua", pdb_init_ldapsam_nua, PASSDB_INTERFACE_VERSION);
2687         return True;
2688 }