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