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