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