readding reverted changes during idmap merge (noticed by Andrew b.)
[ira/wip.git] / source3 / passdb / pdb_ldap.c
1 /* 
2    Unix SMB/CIFS mplementation.
3    LDAP protocol helper functions for SAMBA
4    Copyright (C) Jean François Micouleau        1998
5    Copyright (C) Gerald Carter                  2001-2003
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 /* TODO:
27 *  persistent connections: if using NSS LDAP, many connections are made
28 *      however, using only one within Samba would be nice
29 *  
30 *  Clean up SSL stuff, compile on OpenLDAP 1.x, 2.x, and Netscape SDK
31 *
32 *  Other LDAP based login attributes: accountExpires, etc.
33 *  (should be the domain of Samba proper, but the sam_password/SAM_ACCOUNT
34 *  structures don't have fields for some of these attributes)
35 *
36 *  SSL is done, but can't get the certificate based authentication to work
37 *  against on my test platform (Linux 2.4, OpenLDAP 2.x)
38 */
39
40 /* NOTE: this will NOT work against an Active Directory server
41 *  due to the fact that the two password fields cannot be retrieved
42 *  from a server; recommend using security = domain in this situation
43 *  and/or winbind
44 */
45
46 #include "includes.h"
47
48 #undef DBGC_CLASS
49 #define DBGC_CLASS DBGC_PASSDB
50
51 #include <lber.h>
52 #include <ldap.h>
53
54 #ifndef LDAP_OPT_SUCCESS
55 #define LDAP_OPT_SUCCESS 0
56 #endif
57
58 #ifndef SAM_ACCOUNT
59 #define SAM_ACCOUNT struct sam_passwd
60 #endif
61
62 struct ldapsam_privates {
63         /* Former statics */
64         LDAP *ldap_struct;
65         LDAPMessage *result;
66         LDAPMessage *entry;
67         int index;
68         
69         time_t last_ping;
70         /* retrive-once info */
71         const char *uri;
72         const char *domain_name;
73         DOM_SID domain_sid;
74         
75         /* configuration items */
76         int schema_ver;
77
78         BOOL permit_non_unix_accounts;
79         
80         uint32 low_allocated_user_rid; 
81         uint32 high_allocated_user_rid; 
82
83         uint32 low_allocated_group_rid; 
84         uint32 high_allocated_group_rid; 
85
86         char *bind_dn;
87         char *bind_secret;
88
89         unsigned int num_failures;
90 };
91
92 #define LDAPSAM_DONT_PING_TIME 10       /* ping only all 10 seconds */
93
94 static struct ldapsam_privates *static_ldap_state;
95
96 /* specify schema versions between 2.2. and 3.0 */
97
98 #define SCHEMAVER_SAMBAACCOUNT          1
99 #define SCHEMAVER_SAMBASAMACCOUNT       2
100
101 /* objectclass names */
102
103 #define LDAP_OBJ_SAMBASAMACCOUNT        "sambaSamAccount"
104 #define LDAP_OBJ_SAMBAACCOUNT           "sambaAccount"
105 #define LDAP_OBJ_GROUPMAP               "sambaGroupMapping"
106 #define LDAP_OBJ_DOMINFO                "sambaDomain"
107
108 #define LDAP_OBJ_ACCOUNT                "account"
109 #define LDAP_OBJ_POSIXACCOUNT           "posixAccount"
110 #define LDAP_OBJ_POSIXGROUP             "posixGroup"
111
112 /* some generic attributes that get reused a lot */
113
114 #define LDAP_ATTRIBUTE_SID              "sambaSID"
115
116 /* attribute map table indexes */
117
118 #define LDAP_ATTR_LIST_END              0
119 #define LDAP_ATTR_UID                   1
120 #define LDAP_ATTR_UIDNUMBER             2
121 #define LDAP_ATTR_GIDNUMBER             3
122 #define LDAP_ATTR_UNIX_HOME             4
123 #define LDAP_ATTR_PWD_LAST_SET          5
124 #define LDAP_ATTR_PWD_CAN_CHANGE        6
125 #define LDAP_ATTR_PWD_MUST_CHANGE       7
126 #define LDAP_ATTR_LOGON_TIME            8
127 #define LDAP_ATTR_LOGOFF_TIME           9
128 #define LDAP_ATTR_KICKOFF_TIME          10
129 #define LDAP_ATTR_CN                    11
130 #define LDAP_ATTR_DISPLAY_NAME          12
131 #define LDAP_ATTR_HOME_PATH             13
132 #define LDAP_ATTR_LOGON_SCRIPT          14
133 #define LDAP_ATTR_PROFILE_PATH          15
134 #define LDAP_ATTR_DESC                  16
135 #define LDAP_ATTR_USER_WKS              17
136 #define LDAP_ATTR_USER_SID              18
137 #define LDAP_ATTR_USER_RID              18
138 #define LDAP_ATTR_PRIMARY_GROUP_SID     19
139 #define LDAP_ATTR_PRIMARY_GROUP_RID     20
140 #define LDAP_ATTR_LMPW                  21
141 #define LDAP_ATTR_NTPW                  22
142 #define LDAP_ATTR_DOMAIN                23
143 #define LDAP_ATTR_OBJCLASS              24
144 #define LDAP_ATTR_ACB_INFO              25
145 #define LDAP_ATTR_NEXT_USERRID          26
146 #define LDAP_ATTR_NEXT_GROUPRID         27
147 #define LDAP_ATTR_DOM_SID               28
148 #define LDAP_ATTR_HOME_DRIVE            29
149 #define LDAP_ATTR_GROUP_SID             30
150 #define LDAP_ATTR_GROUP_TYPE            31
151
152
153 typedef struct _attrib_map_entry {
154         int             attrib;
155         const char      *name;
156 } ATTRIB_MAP_ENTRY;
157
158
159 /* attributes used by Samba 2.2 */
160
161 static ATTRIB_MAP_ENTRY attrib_map_v22[] = {
162         { LDAP_ATTR_UID,                "uid"           },
163         { LDAP_ATTR_UIDNUMBER,          "uidNumber"     },
164         { LDAP_ATTR_GIDNUMBER,          "gidNumber"     },
165         { LDAP_ATTR_UNIX_HOME,          "homeDirectory" },
166         { LDAP_ATTR_PWD_LAST_SET,       "pwdLastSet"    },
167         { LDAP_ATTR_PWD_CAN_CHANGE,     "pwdCanChange"  },
168         { LDAP_ATTR_PWD_MUST_CHANGE,    "pwdMustChange" },
169         { LDAP_ATTR_LOGON_TIME,         "logonTime"     },
170         { LDAP_ATTR_LOGOFF_TIME,        "logoffTime"    },
171         { LDAP_ATTR_KICKOFF_TIME,       "kickoffTime"   },
172         { LDAP_ATTR_CN,                 "cn"            },
173         { LDAP_ATTR_DISPLAY_NAME,       "displayName"   },
174         { LDAP_ATTR_HOME_PATH,          "smbHome"       },
175         { LDAP_ATTR_HOME_DRIVE,         "homeDrives"    },
176         { LDAP_ATTR_LOGON_SCRIPT,       "scriptPath"    },
177         { LDAP_ATTR_PROFILE_PATH,       "profilePath"   },
178         { LDAP_ATTR_DESC,               "description"   },
179         { LDAP_ATTR_USER_WKS,           "userWorkstations"},
180         { LDAP_ATTR_USER_RID,           "rid"           },
181         { LDAP_ATTR_PRIMARY_GROUP_RID,  "primaryGroupID"},
182         { LDAP_ATTR_LMPW,               "lmPassword"    },
183         { LDAP_ATTR_NTPW,               "ntPassword"    },
184         { LDAP_ATTR_DOMAIN,             "domain"        },
185         { LDAP_ATTR_OBJCLASS,           "objectClass"   },
186         { LDAP_ATTR_ACB_INFO,           "acctFlags"     },
187         { LDAP_ATTR_LIST_END,           NULL            }
188 };
189
190 /* attributes used by Samba 3.0's sambaSamAccount */
191
192 static ATTRIB_MAP_ENTRY attrib_map_v30[] = {
193         { LDAP_ATTR_UID,                "uid"                   },
194         { LDAP_ATTR_UIDNUMBER,          "uidNumber"             },
195         { LDAP_ATTR_GIDNUMBER,          "gidNumber"             },
196         { LDAP_ATTR_UNIX_HOME,          "homeDirectory"         },
197         { LDAP_ATTR_PWD_LAST_SET,       "sambaPwdLastSet"       },
198         { LDAP_ATTR_PWD_CAN_CHANGE,     "sambaPwdCanChange"     },
199         { LDAP_ATTR_PWD_MUST_CHANGE,    "sambaPwdMustChange"    },
200         { LDAP_ATTR_LOGON_TIME,         "sambaLogonTime"        },
201         { LDAP_ATTR_LOGOFF_TIME,        "sambaLogoffTime"       },
202         { LDAP_ATTR_KICKOFF_TIME,       "sambaKickoffTime"      },
203         { LDAP_ATTR_CN,                 "cn"                    },
204         { LDAP_ATTR_DISPLAY_NAME,       "displayName"           },
205         { LDAP_ATTR_HOME_DRIVE,         "sambaHoneDrive"        },
206         { LDAP_ATTR_HOME_PATH,          "sambaHomePath"         },
207         { LDAP_ATTR_LOGON_SCRIPT,       "sambaLogonScript"      },
208         { LDAP_ATTR_PROFILE_PATH,       "sambaProfilePath"      },
209         { LDAP_ATTR_DESC,               "description"           },
210         { LDAP_ATTR_USER_WKS,           "sambaUserWorkstations" },
211         { LDAP_ATTR_USER_SID,           "sambaSID"              },
212         { LDAP_ATTR_PRIMARY_GROUP_SID,  "sambaPrimaryGroupSID"  },
213         { LDAP_ATTR_LMPW,               "sambaLMPassword"       },
214         { LDAP_ATTR_NTPW,               "sambaNTPassword"       },
215         { LDAP_ATTR_DOMAIN,             "sambaDomainName"       },
216         { LDAP_ATTR_OBJCLASS,           "objectClass"           },
217         { LDAP_ATTR_ACB_INFO,           "sambaAcctFlags"        },
218         { LDAP_ATTR_LIST_END,           NULL                    }
219 };
220
221 /* attributes used for alalocating RIDs */
222
223 static ATTRIB_MAP_ENTRY dominfo_attr_list[] = {
224         { LDAP_ATTR_DOMAIN,             "sambaDomainName"       },
225         { LDAP_ATTR_NEXT_USERRID,       "sambaNextUserRid"      },
226         { LDAP_ATTR_NEXT_GROUPRID,      "sambaNextGroupRid"     },
227         { LDAP_ATTR_DOM_SID,            "sambaSID"              },
228         { LDAP_ATTR_LIST_END,           NULL                    },
229 };
230
231 /* Samba 3.0 group mapping attributes */
232
233 static ATTRIB_MAP_ENTRY groupmap_attr_list[] = {
234         { LDAP_ATTR_GIDNUMBER,          "gidNumber"             },
235         { LDAP_ATTR_GROUP_SID,          "sambaSID"              },
236         { LDAP_ATTR_GROUP_TYPE,         "sambaGroupType"        },
237         { LDAP_ATTR_DESC,               "description"           },
238         { LDAP_ATTR_DISPLAY_NAME,       "displayName"           },
239         { LDAP_ATTR_CN,                 "cn"                    },
240         { LDAP_ATTR_LIST_END,           NULL                    }       
241 };
242
243 static ATTRIB_MAP_ENTRY groupmap_attr_list_to_delete[] = {
244         { LDAP_ATTR_GROUP_SID,          "sambaSID"              },
245         { LDAP_ATTR_GROUP_TYPE,         "sambaGroupType"        },
246         { LDAP_ATTR_DESC,               "description"           },
247         { LDAP_ATTR_DISPLAY_NAME,       "displayName"           },
248         { LDAP_ATTR_LIST_END,           NULL                    }       
249 };
250
251 /**********************************************************************
252  perform a simple table lookup and return the attribute name 
253  **********************************************************************/
254  
255 static const char* get_attr_key2string( ATTRIB_MAP_ENTRY table[], int key )
256 {
257         int i = 0;
258         
259         while ( table[i].attrib != LDAP_ATTR_LIST_END ) {
260                 if ( table[i].attrib == key )
261                         return table[i].name;
262                 i++;
263         }
264         
265         return NULL;
266 }
267
268 /**********************************************************************
269  get the attribute name given a user schame version 
270  **********************************************************************/
271  
272 static const char* get_userattr_key2string( int schema_ver, int key )
273 {
274         switch ( schema_ver )
275         {
276                 case SCHEMAVER_SAMBAACCOUNT:
277                         return get_attr_key2string( attrib_map_v22, key );
278                         
279                 case SCHEMAVER_SAMBASAMACCOUNT:
280                         return get_attr_key2string( attrib_map_v30, key );
281                         
282                 default:
283                         DEBUG(0,("get_userattr_key2string: unknown schema version specified\n"));
284                         break;
285         }
286         return NULL;
287 }
288
289 /**********************************************************************
290  Return the list of attribute names from a mapping table
291  **********************************************************************/
292
293 static char** get_attr_list( ATTRIB_MAP_ENTRY table[] )
294 {
295         char **names;
296         int i = 0;
297         
298         while ( table[i].attrib != LDAP_ATTR_LIST_END )
299                 i++;
300         i++;
301
302         names = (char**)malloc( sizeof(char*)*i );
303         if ( !names ) {
304                 DEBUG(0,("get_attr_list: out of memory\n"));
305                 return NULL;
306         }
307
308         i = 0;
309         while ( table[i].attrib != LDAP_ATTR_LIST_END ) {
310                 names[i] = strdup( table[i].name );
311                 i++;
312         }
313         names[i] = NULL;
314         
315         return names;
316 }
317
318 /*********************************************************************
319  Cleanup 
320  ********************************************************************/
321
322 static void free_attr_list( char **list )
323 {
324         int i = 0;
325
326         if ( !list )
327                 return; 
328
329         while ( list[i] )
330                 SAFE_FREE( list[i] );
331
332         SAFE_FREE( list );
333 }
334
335 /**********************************************************************
336  return the list of attribute names given a user schema version 
337  **********************************************************************/
338
339 static char** get_userattr_list( int schema_ver )
340 {
341         switch ( schema_ver ) 
342         {
343                 case SCHEMAVER_SAMBAACCOUNT:
344                         return get_attr_list( attrib_map_v22 );
345                         
346                 case SCHEMAVER_SAMBASAMACCOUNT:
347                         return get_attr_list( attrib_map_v30 );
348                 default:
349                         DEBUG(0,("get_userattr_list: unknown schema version specified!\n"));
350                         break;
351         }
352         
353         return NULL;
354 }
355
356 /*******************************************************************
357  find the ldap password
358 ******************************************************************/
359 static BOOL fetch_ldapsam_pw(char **dn, char** pw)
360 {
361         char *key = NULL;
362         size_t size;
363         
364         *dn = smb_xstrdup(lp_ldap_admin_dn());
365         
366         if (asprintf(&key, "%s/%s", SECRETS_LDAP_BIND_PW, *dn) < 0) {
367                 SAFE_FREE(*dn);
368                 DEBUG(0, ("fetch_ldapsam_pw: asprintf failed!\n"));
369         }
370         
371         *pw=secrets_fetch(key, &size);
372         SAFE_FREE(key);
373
374         if (!size) {
375                 /* Upgrade 2.2 style entry */
376                 char *p;
377                 char* old_style_key = strdup(*dn);
378                 char *data;
379                 fstring old_style_pw;
380                 
381                 if (!old_style_key) {
382                         DEBUG(0, ("fetch_ldapsam_pw: strdup failed!\n"));
383                         return False;
384                 }
385
386                 for (p=old_style_key; *p; p++)
387                         if (*p == ',') *p = '/';
388         
389                 data=secrets_fetch(old_style_key, &size);
390                 if (!size && size < sizeof(old_style_pw)) {
391                         DEBUG(0,("fetch_ldap_pw: neither ldap secret retrieved!\n"));
392                         SAFE_FREE(old_style_key);
393                         SAFE_FREE(*dn);
394                         return False;
395                 }
396
397                 strncpy(old_style_pw, data, size);
398                 old_style_pw[size] = 0;
399
400                 SAFE_FREE(data);
401
402                 if (!secrets_store_ldap_pw(*dn, old_style_pw)) {
403                         DEBUG(0,("fetch_ldap_pw: ldap secret could not be upgraded!\n"));
404                         SAFE_FREE(old_style_key);
405                         SAFE_FREE(*dn);
406                         return False;                   
407                 }
408                 if (!secrets_delete(old_style_key)) {
409                         DEBUG(0,("fetch_ldap_pw: old ldap secret could not be deleted!\n"));
410                 }
411
412                 SAFE_FREE(old_style_key);
413
414                 *pw = smb_xstrdup(old_style_pw);                
415         }
416         
417         return True;
418 }
419                              
420 /*******************************************************************
421  open a connection to the ldap server.
422 ******************************************************************/
423 static int ldapsam_open_connection (struct ldapsam_privates *ldap_state, LDAP ** ldap_struct)
424 {
425         int rc = LDAP_SUCCESS;
426         int version;
427         BOOL ldap_v3 = False;
428
429 #ifdef HAVE_LDAP_INITIALIZE
430         DEBUG(10, ("ldapsam_open_connection: %s\n", ldap_state->uri));
431         
432         if ((rc = ldap_initialize(ldap_struct, ldap_state->uri)) != LDAP_SUCCESS) {
433                 DEBUG(0, ("ldap_initialize: %s\n", ldap_err2string(rc)));
434                 return rc;
435         }
436         
437 #else 
438
439         /* Parse the string manually */
440
441         {
442                 int port = 0;
443                 fstring protocol;
444                 fstring host;
445                 const char *p = ldap_state->uri; 
446                 SMB_ASSERT(sizeof(protocol)>10 && sizeof(host)>254);
447                 
448                 /* skip leading "URL:" (if any) */
449                 if ( strncasecmp( p, "URL:", 4 ) == 0 ) {
450                         p += 4;
451                 }
452                 
453                 sscanf(p, "%10[^:]://%254s[^:]:%d", protocol, host, &port);
454                 
455                 if (port == 0) {
456                         if (strequal(protocol, "ldap")) {
457                                 port = LDAP_PORT;
458                         } else if (strequal(protocol, "ldaps")) {
459                                 port = LDAPS_PORT;
460                         } else {
461                                 DEBUG(0, ("unrecognised protocol (%s)!\n", protocol));
462                         }
463                 }
464                 
465                 if ((*ldap_struct = ldap_init(host, port)) == NULL)     {
466                         DEBUG(0, ("ldap_init failed !\n"));
467                         return LDAP_OPERATIONS_ERROR;
468                 }
469                 
470                 if (strequal(protocol, "ldaps")) {
471 #ifdef LDAP_OPT_X_TLS
472                         int tls = LDAP_OPT_X_TLS_HARD;
473                         if (ldap_set_option (*ldap_struct, LDAP_OPT_X_TLS, &tls) != LDAP_SUCCESS)
474                         {
475                                 DEBUG(0, ("Failed to setup a TLS session\n"));
476                         }
477                         
478                         DEBUG(3,("LDAPS option set...!\n"));
479 #else
480                         DEBUG(0,("ldapsam_open_connection: Secure connection not supported by LDAP client libraries!\n"));
481                         return LDAP_OPERATIONS_ERROR;
482 #endif
483                 }
484         }
485 #endif
486
487         if (ldap_get_option(*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS)
488         {
489                 if (version != LDAP_VERSION3)
490                 {
491                         version = LDAP_VERSION3;
492                         if (ldap_set_option (*ldap_struct, LDAP_OPT_PROTOCOL_VERSION, &version) == LDAP_OPT_SUCCESS) {
493                                 ldap_v3 = True;
494                         }
495                 } else {
496                         ldap_v3 = True;
497                 }
498         }
499
500         if (lp_ldap_ssl() == LDAP_SSL_START_TLS) {
501 #ifdef LDAP_OPT_X_TLS
502                 if (ldap_v3) {
503                         if ((rc = ldap_start_tls_s (*ldap_struct, NULL, NULL)) != LDAP_SUCCESS)
504                         {
505                                 DEBUG(0,("Failed to issue the StartTLS instruction: %s\n",
506                                          ldap_err2string(rc)));
507                                 return rc;
508                         }
509                         DEBUG (3, ("StartTLS issued: using a TLS connection\n"));
510                 } else {
511                         
512                         DEBUG(0, ("Need LDAPv3 for Start TLS\n"));
513                         return LDAP_OPERATIONS_ERROR;
514                 }
515 #else
516                 DEBUG(0,("ldapsam_open_connection: StartTLS not supported by LDAP client libraries!\n"));
517                 return LDAP_OPERATIONS_ERROR;
518 #endif
519         }
520
521         DEBUG(2, ("ldapsam_open_connection: connection opened\n"));
522         return rc;
523 }
524
525
526 /*******************************************************************
527  a rebind function for authenticated referrals
528  This version takes a void* that we can shove useful stuff in :-)
529 ******************************************************************/
530 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
531 #else
532 static int rebindproc_with_state  (LDAP * ld, char **whop, char **credp, 
533                                    int *methodp, int freeit, void *arg)
534 {
535         struct ldapsam_privates *ldap_state = arg;
536         
537         /** @TODO Should we be doing something to check what servers we rebind to?
538             Could we get a referral to a machine that we don't want to give our
539             username and password to? */
540         
541         if (freeit) {
542                 SAFE_FREE(*whop);
543                 memset(*credp, '\0', strlen(*credp));
544                 SAFE_FREE(*credp);
545         } else {
546                 DEBUG(5,("rebind_proc_with_state: Rebinding as \"%s\"\n", 
547                           ldap_state->bind_dn));
548
549                 *whop = strdup(ldap_state->bind_dn);
550                 if (!*whop) {
551                         return LDAP_NO_MEMORY;
552                 }
553                 *credp = strdup(ldap_state->bind_secret);
554                 if (!*credp) {
555                         SAFE_FREE(*whop);
556                         return LDAP_NO_MEMORY;
557                 }
558                 *methodp = LDAP_AUTH_SIMPLE;
559         }
560         return 0;
561 }
562 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
563
564 /*******************************************************************
565  a rebind function for authenticated referrals
566  This version takes a void* that we can shove useful stuff in :-)
567  and actually does the connection.
568 ******************************************************************/
569 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
570 static int rebindproc_connect_with_state (LDAP *ldap_struct, 
571                                           LDAP_CONST char *url, 
572                                           ber_tag_t request,
573                                           ber_int_t msgid, void *arg)
574 {
575         struct ldapsam_privates *ldap_state = arg;
576         int rc;
577         DEBUG(5,("rebindproc_connect_with_state: Rebinding as \"%s\"\n", 
578                  ldap_state->bind_dn));
579         
580         /** @TODO Should we be doing something to check what servers we rebind to?
581             Could we get a referral to a machine that we don't want to give our
582             username and password to? */
583
584         rc = ldap_simple_bind_s(ldap_struct, ldap_state->bind_dn, ldap_state->bind_secret);
585         
586         return rc;
587 }
588 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
589
590 /*******************************************************************
591  Add a rebind function for authenticated referrals
592 ******************************************************************/
593 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
594 #else
595 # if LDAP_SET_REBIND_PROC_ARGS == 2
596 static int rebindproc (LDAP *ldap_struct, char **whop, char **credp,
597                        int *method, int freeit )
598 {
599         return rebindproc_with_state(ldap_struct, whop, credp,
600                                    method, freeit, static_ldap_state);
601         
602 }
603 # endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
604 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
605
606 /*******************************************************************
607  a rebind function for authenticated referrals
608  this also does the connection, but no void*.
609 ******************************************************************/
610 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
611 # if LDAP_SET_REBIND_PROC_ARGS == 2
612 static int rebindproc_connect (LDAP * ld, LDAP_CONST char *url, int request,
613                                ber_int_t msgid)
614 {
615         return rebindproc_connect_with_state(ld, url, (ber_tag_t)request, msgid, 
616                                              static_ldap_state);
617 }
618 # endif /*LDAP_SET_REBIND_PROC_ARGS == 2*/
619 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
620
621 /*******************************************************************
622  connect to the ldap server under system privilege.
623 ******************************************************************/
624 static int ldapsam_connect_system(struct ldapsam_privates *ldap_state, LDAP * ldap_struct)
625 {
626         int rc;
627         char *ldap_dn;
628         char *ldap_secret;
629
630         /* The rebind proc needs this *HACK*.  We are not multithreaded, so
631            this will work, but it's not nice. */
632         static_ldap_state = ldap_state;
633
634         /* get the password */
635         if (!fetch_ldapsam_pw(&ldap_dn, &ldap_secret))
636         {
637                 DEBUG(0, ("ldap_connect_system: Failed to retrieve password from secrets.tdb\n"));
638                 return LDAP_INVALID_CREDENTIALS;
639         }
640
641         ldap_state->bind_dn = ldap_dn;
642         ldap_state->bind_secret = ldap_secret;
643
644         /* removed the sasl_bind_s "EXTERNAL" stuff, as my testsuite 
645            (OpenLDAP) doesnt' seem to support it */
646            
647         DEBUG(10,("ldap_connect_system: Binding to ldap server %s as \"%s\"\n",
648                   ldap_state->uri, ldap_dn));
649
650 #if defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)
651 # if LDAP_SET_REBIND_PROC_ARGS == 2     
652         ldap_set_rebind_proc(ldap_struct, &rebindproc_connect); 
653 # endif
654 # if LDAP_SET_REBIND_PROC_ARGS == 3     
655         ldap_set_rebind_proc(ldap_struct, &rebindproc_connect_with_state, (void *)ldap_state);  
656 # endif
657 #else /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
658 # if LDAP_SET_REBIND_PROC_ARGS == 2     
659         ldap_set_rebind_proc(ldap_struct, &rebindproc); 
660 # endif
661 # if LDAP_SET_REBIND_PROC_ARGS == 3     
662         ldap_set_rebind_proc(ldap_struct, &rebindproc_with_state, (void *)ldap_state);  
663 # endif
664 #endif /*defined(LDAP_API_FEATURE_X_OPENLDAP) && (LDAP_API_VERSION > 2000)*/
665
666         rc = ldap_simple_bind_s(ldap_struct, ldap_dn, ldap_secret);
667
668         if (rc != LDAP_SUCCESS) {
669                 char *ld_error = NULL;
670                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
671                                 &ld_error);
672                 DEBUG(ldap_state->num_failures ? 2 : 0,
673                       ("failed to bind to server with dn= %s Error: %s\n\t%s\n",
674                                ldap_dn ? ld_error : "(unknown)", ldap_err2string(rc),
675                                ld_error));
676                 SAFE_FREE(ld_error);
677                 ldap_state->num_failures++;
678                 return rc;
679         }
680
681         ldap_state->num_failures = 0;
682
683         DEBUG(3, ("ldap_connect_system: succesful connection to the LDAP server\n"));
684         return rc;
685 }
686
687 /**********************************************************************
688 Connect to LDAP server 
689 *********************************************************************/
690 static int ldapsam_open(struct ldapsam_privates *ldap_state)
691 {
692         int rc;
693         SMB_ASSERT(ldap_state);
694                 
695 #ifndef NO_LDAP_SECURITY
696         if (geteuid() != 0) {
697                 DEBUG(0, ("ldapsam_open: cannot access LDAP when not root..\n"));
698                 return  LDAP_INSUFFICIENT_ACCESS;
699         }
700 #endif
701
702         if ((ldap_state->ldap_struct != NULL) && ((ldap_state->last_ping + LDAPSAM_DONT_PING_TIME) < time(NULL))) {
703                 struct sockaddr_un addr;
704                 socklen_t len = sizeof(addr);
705                 int sd;
706                 if (ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_DESC, &sd) == 0 &&
707                     getpeername(sd, (struct sockaddr *) &addr, &len) < 0) {
708                         /* the other end has died. reopen. */
709                         ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
710                         ldap_state->ldap_struct = NULL;
711                         ldap_state->last_ping = (time_t)0;
712                 } else {
713                         ldap_state->last_ping = time(NULL);
714                 } 
715         }
716
717         if (ldap_state->ldap_struct != NULL) {
718                 DEBUG(5,("ldapsam_open: already connected to the LDAP server\n"));
719                 return LDAP_SUCCESS;
720         }
721
722         if ((rc = ldapsam_open_connection(ldap_state, &ldap_state->ldap_struct))) {
723                 return rc;
724         }
725
726         if ((rc = ldapsam_connect_system(ldap_state, ldap_state->ldap_struct))) {
727                 ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
728                 ldap_state->ldap_struct = NULL;
729                 return rc;
730         }
731
732
733         ldap_state->last_ping = time(NULL);
734         DEBUG(4,("The LDAP server is succesful connected\n"));
735
736         return LDAP_SUCCESS;
737 }
738
739 /**********************************************************************
740 Disconnect from LDAP server 
741 *********************************************************************/
742 static NTSTATUS ldapsam_close(struct ldapsam_privates *ldap_state)
743 {
744         if (!ldap_state)
745                 return NT_STATUS_INVALID_PARAMETER;
746                 
747         if (ldap_state->ldap_struct != NULL) {
748                 ldap_unbind_ext(ldap_state->ldap_struct, NULL, NULL);
749                 ldap_state->ldap_struct = NULL;
750         }
751         
752         DEBUG(5,("The connection to the LDAP server was closed\n"));
753         /* maybe free the results here --metze */
754         
755         return NT_STATUS_OK;
756 }
757
758 static int ldapsam_retry_open(struct ldapsam_privates *ldap_state, int *attempts)
759 {
760         int rc;
761
762         SMB_ASSERT(ldap_state && attempts);
763                 
764         if (*attempts != 0) {
765                 unsigned int sleep_time;
766                 uint8 rand_byte;
767
768                 /* Sleep for a random timeout */
769                 rand_byte = (char)(sys_random());
770
771                 sleep_time = (((*attempts)*(*attempts))/2)*rand_byte*2; 
772                 /* we retry after (0.5, 1, 2, 3, 4.5, 6) seconds
773                    on average.  
774                  */
775                 DEBUG(3, ("Sleeping for %u milliseconds before reconnecting\n", 
776                           sleep_time));
777                 msleep(sleep_time);
778         }
779         (*attempts)++;
780
781         if ((rc = ldapsam_open(ldap_state))) {
782                 DEBUG(1,("Connection to LDAP Server failed for the %d try!\n",*attempts));
783                 return rc;
784         } 
785         
786         return LDAP_SUCCESS;            
787 }
788
789
790 /*********************************************************************
791  ********************************************************************/
792
793 static int ldapsam_search(struct ldapsam_privates *ldap_state, 
794                           const char *base, int scope, const char *filter, 
795                           char *attrs[], int attrsonly, 
796                           LDAPMessage **res)
797 {
798         int             rc = LDAP_SERVER_DOWN;
799         int             attempts = 0;
800         char           *utf8_filter;
801
802         SMB_ASSERT(ldap_state);
803
804         if (push_utf8_allocate(&utf8_filter, filter) == (size_t)-1) {
805                 return LDAP_NO_MEMORY;
806         }
807
808         while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
809                 
810                 if ((rc = ldapsam_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
811                         continue;
812                 
813                 rc = ldap_search_s(ldap_state->ldap_struct, base, scope, 
814                                    utf8_filter, attrs, attrsonly, res);
815         }
816         
817         if (rc == LDAP_SERVER_DOWN) {
818                 DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
819                 ldapsam_close(ldap_state);      
820         }
821
822         SAFE_FREE(utf8_filter);
823         return rc;
824 }
825
826 static int ldapsam_modify(struct ldapsam_privates *ldap_state, const char *dn, LDAPMod *attrs[])
827 {
828         int             rc = LDAP_SERVER_DOWN;
829         int             attempts = 0;
830         char           *utf8_dn;
831
832         SMB_ASSERT(ldap_state);
833
834         if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
835                 return LDAP_NO_MEMORY;
836         }
837
838         while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
839                 
840                 if ((rc = ldapsam_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
841                         continue;
842                 
843                 rc = ldap_modify_s(ldap_state->ldap_struct, utf8_dn, attrs);
844         }
845         
846         if (rc == LDAP_SERVER_DOWN) {
847                 DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
848                 ldapsam_close(ldap_state);      
849         }
850         
851         SAFE_FREE(utf8_dn);
852         return rc;
853 }
854
855 static int ldapsam_add(struct ldapsam_privates *ldap_state, const char *dn, LDAPMod *attrs[])
856 {
857         int             rc = LDAP_SERVER_DOWN;
858         int             attempts = 0;
859         char           *utf8_dn;
860         
861         SMB_ASSERT(ldap_state);
862
863         if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
864                 return LDAP_NO_MEMORY;
865         }
866
867         while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
868                 
869                 if ((rc = ldapsam_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
870                         continue;
871                 
872                 rc = ldap_add_s(ldap_state->ldap_struct, utf8_dn, attrs);
873         }
874         
875         if (rc == LDAP_SERVER_DOWN) {
876                 DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
877                 ldapsam_close(ldap_state);      
878         }
879                 
880         SAFE_FREE(utf8_dn);
881         return rc;
882 }
883
884 static int ldapsam_delete(struct ldapsam_privates *ldap_state, char *dn)
885 {
886         int             rc = LDAP_SERVER_DOWN;
887         int             attempts = 0;
888         char           *utf8_dn;
889         
890         SMB_ASSERT(ldap_state);
891
892         if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
893                 return LDAP_NO_MEMORY;
894         }
895
896         while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
897                 
898                 if ((rc = ldapsam_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
899                         continue;
900                 
901                 rc = ldap_delete_s(ldap_state->ldap_struct, utf8_dn);
902         }
903         
904         if (rc == LDAP_SERVER_DOWN) {
905                 DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
906                 ldapsam_close(ldap_state);      
907         }
908                 
909         SAFE_FREE(utf8_dn);
910         return rc;
911 }
912
913 #ifdef LDAP_EXOP_X_MODIFY_PASSWD
914 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)
915 {
916         int             rc = LDAP_SERVER_DOWN;
917         int             attempts = 0;
918         
919         if (!ldap_state)
920                 return (-1);
921
922         while ((rc == LDAP_SERVER_DOWN) && (attempts < 8)) {
923                 
924                 if ((rc = ldapsam_retry_open(ldap_state,&attempts)) != LDAP_SUCCESS)
925                         continue;
926                 
927                 rc = ldap_extended_operation_s(ldap_state->ldap_struct, reqoid, reqdata, serverctrls, clientctrls, retoidp, retdatap);
928         }
929         
930         if (rc == LDAP_SERVER_DOWN) {
931                 DEBUG(0,("%s: LDAP server is down!\n",FUNCTION_MACRO));
932                 ldapsam_close(ldap_state);      
933         }
934                 
935         return rc;
936 }
937 #endif
938
939 /*******************************************************************
940  run the search by name.
941 ******************************************************************/
942 static int ldapsam_search_suffix (struct ldapsam_privates *ldap_state, const char *filter, 
943                                 char **search_attr, LDAPMessage ** result)
944 {
945         int scope = LDAP_SCOPE_SUBTREE;
946         int rc;
947
948         DEBUG(2, ("ldapsam_search_suffix: searching for:[%s]\n", filter));
949
950         rc = ldapsam_search(ldap_state, lp_ldap_suffix(), scope, filter, search_attr, 0, result);
951
952         if (rc != LDAP_SUCCESS) {
953                 char *ld_error = NULL;
954                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
955                                 &ld_error);
956                 DEBUG(0,("ldapsam_search_suffix: Problem during the LDAP search: %s (%s)\n", 
957                         ld_error?ld_error:"(unknown)", ldap_err2string (rc)));
958                 DEBUG(3,("ldapsam_search_suffix: Query was: %s, %s\n", lp_ldap_suffix(), 
959                         filter));
960                 SAFE_FREE(ld_error);
961         }
962         
963         return rc;
964 }
965
966 /*******************************************************************
967  generate the LDAP search filter for the objectclass based on the 
968  version of the schema we are using 
969  ******************************************************************/
970
971 static const char* get_objclass_filter( int schema_ver )
972 {
973         static fstring objclass_filter;
974         
975         switch( schema_ver ) 
976         {
977                 case SCHEMAVER_SAMBAACCOUNT:
978                         snprintf( objclass_filter, sizeof(objclass_filter)-1, "(objectclass=%s)", LDAP_OBJ_SAMBAACCOUNT );
979                         break;
980                 case SCHEMAVER_SAMBASAMACCOUNT:
981                         snprintf( objclass_filter, sizeof(objclass_filter)-1, "(objectclass=%s)", LDAP_OBJ_SAMBASAMACCOUNT );
982                         break;
983                 default:
984                         DEBUG(0,("ldapsam_search_suffix_by_name(): Invalid schema version specified!\n"));
985                         break;
986         }
987         
988         return objclass_filter; 
989 }
990
991 /*******************************************************************
992  run the search by name.
993 ******************************************************************/
994 static int ldapsam_search_suffix_by_name (struct ldapsam_privates *ldap_state, const char *user,
995                              LDAPMessage ** result, char **attr)
996 {
997         pstring filter;
998         char *escape_user = escape_ldap_string_alloc(user);
999
1000         if (!escape_user) {
1001                 return LDAP_NO_MEMORY;
1002         }
1003
1004         /*
1005          * in the filter expression, replace %u with the real name
1006          * so in ldap filter, %u MUST exist :-)
1007          */
1008         snprintf(filter, sizeof(filter)-1, "(&%s%s)", lp_ldap_filter(), 
1009                 get_objclass_filter(ldap_state->schema_ver));
1010
1011         /* 
1012          * have to use this here because $ is filtered out
1013            * in pstring_sub
1014          */
1015         
1016
1017         all_string_sub(filter, "%u", escape_user, sizeof(pstring));
1018         SAFE_FREE(escape_user);
1019
1020         return ldapsam_search_suffix(ldap_state, filter, attr, result);
1021 }
1022
1023 /*******************************************************************
1024  run the search by rid.
1025 ******************************************************************/
1026 static int ldapsam_search_suffix_by_rid (struct ldapsam_privates *ldap_state, 
1027                                         uint32 rid, LDAPMessage ** result, 
1028                                         char **attr)
1029 {
1030         pstring filter;
1031         int rc;
1032
1033         /* check if the user rid exists, if not, try searching on the uid */
1034
1035         snprintf(filter, sizeof(filter)-1, "(&(rid=%i)%s)", rid, 
1036                 get_objclass_filter(ldap_state->schema_ver));
1037         
1038         rc = ldapsam_search_suffix(ldap_state, filter, attr, result);
1039         
1040         return rc;
1041 }
1042
1043 /*******************************************************************
1044  run the search by SID.
1045 ******************************************************************/
1046 static int ldapsam_search_suffix_by_sid (struct ldapsam_privates *ldap_state, 
1047                                         const DOM_SID *sid, LDAPMessage ** result, 
1048                                         char **attr)
1049 {
1050         pstring filter;
1051         int rc;
1052         fstring sid_string;
1053
1054         /* check if the user rid exsists, if not, try searching on the uid */
1055
1056         snprintf(filter, sizeof(filter)-1, "(&(%s=%s)%s)", 
1057                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_SID),
1058                 sid_to_string(sid_string, sid), 
1059                 get_objclass_filter(ldap_state->schema_ver));
1060                 
1061         rc = ldapsam_search_suffix(ldap_state, filter, attr, result);
1062         
1063         return rc;
1064 }
1065
1066 /*******************************************************************
1067 search an attribute and return the first value found.
1068 ******************************************************************/
1069 static BOOL get_single_attribute (LDAP * ldap_struct, LDAPMessage * entry,
1070                                   const char *attribute, pstring value)
1071 {
1072         char **values;
1073         
1074         if ( !attribute )
1075                 return False;
1076                 
1077         value[0] = '\0';
1078
1079         if ((values = ldap_get_values (ldap_struct, entry, attribute)) == NULL) {
1080                 DEBUG (10, ("get_single_attribute: [%s] = [<does not exist>]\n", attribute));
1081                 
1082                 return False;
1083         }
1084         
1085         if (convert_string(CH_UTF8, CH_UNIX,values[0], -1, value, sizeof(pstring)) == (size_t)-1)
1086         {
1087                 DEBUG(1, ("get_single_attribute: string conversion of [%s] = [%s] failed!\n", 
1088                           attribute, values[0]));
1089                 ldap_value_free(values);
1090                 return False;
1091         }
1092         
1093         ldap_value_free(values);
1094 #ifdef DEBUG_PASSWORDS
1095         DEBUG (100, ("get_single_attribute: [%s] = [%s]\n", attribute, value));
1096 #endif  
1097         return True;
1098 }
1099
1100 /************************************************************************
1101 Routine to manage the LDAPMod structure array
1102 manage memory used by the array, by each struct, and values
1103
1104 ************************************************************************/
1105 static void make_a_mod (LDAPMod *** modlist, int modop, const char *attribute, const char *value)
1106 {
1107         LDAPMod **mods;
1108         int i;
1109         int j;
1110
1111         mods = *modlist;
1112
1113         /* sanity checks on the mod values */
1114
1115         if (attribute == NULL || *attribute == '\0')
1116                 return; 
1117 #if 0   /* commented out after discussion with abartlet.  Do not reenable.
1118            left here so other so re-add similar code   --jerry */
1119         if (value == NULL || *value == '\0')
1120                 return;
1121 #endif
1122
1123         if (mods == NULL) 
1124         {
1125                 mods = (LDAPMod **) malloc(sizeof(LDAPMod *));
1126                 if (mods == NULL)
1127                 {
1128                         DEBUG(0, ("make_a_mod: out of memory!\n"));
1129                         return;
1130                 }
1131                 mods[0] = NULL;
1132         }
1133
1134         for (i = 0; mods[i] != NULL; ++i) {
1135                 if (mods[i]->mod_op == modop && !strcasecmp(mods[i]->mod_type, attribute))
1136                         break;
1137         }
1138
1139         if (mods[i] == NULL)
1140         {
1141                 mods = (LDAPMod **) Realloc (mods, (i + 2) * sizeof (LDAPMod *));
1142                 if (mods == NULL)
1143                 {
1144                         DEBUG(0, ("make_a_mod: out of memory!\n"));
1145                         return;
1146                 }
1147                 mods[i] = (LDAPMod *) malloc(sizeof(LDAPMod));
1148                 if (mods[i] == NULL)
1149                 {
1150                         DEBUG(0, ("make_a_mod: out of memory!\n"));
1151                         return;
1152                 }
1153                 mods[i]->mod_op = modop;
1154                 mods[i]->mod_values = NULL;
1155                 mods[i]->mod_type = strdup(attribute);
1156                 mods[i + 1] = NULL;
1157         }
1158
1159         if (value != NULL)
1160         {
1161                 char *utf8_value = NULL;
1162
1163                 j = 0;
1164                 if (mods[i]->mod_values != NULL) {
1165                         for (; mods[i]->mod_values[j] != NULL; j++);
1166                 }
1167                 mods[i]->mod_values = (char **)Realloc(mods[i]->mod_values,
1168                                                (j + 2) * sizeof (char *));
1169                                                
1170                 if (mods[i]->mod_values == NULL) {
1171                         DEBUG (0, ("make_a_mod: Memory allocation failure!\n"));
1172                         return;
1173                 }
1174
1175                 if (push_utf8_allocate(&utf8_value, value) == (size_t)-1) {
1176                         DEBUG (0, ("make_a_mod: String conversion failure!\n"));
1177                         return;
1178                 }
1179
1180                 mods[i]->mod_values[j] = utf8_value;
1181
1182                 mods[i]->mod_values[j + 1] = NULL;
1183         }
1184         *modlist = mods;
1185 }
1186
1187 /**********************************************************************
1188   Set attribute to newval in LDAP, regardless of what value the
1189   attribute had in LDAP before.
1190 *********************************************************************/
1191 static void make_ldap_mod(LDAP *ldap_struct, LDAPMessage *existing,
1192                           LDAPMod ***mods,
1193                           const char *attribute, const char *newval)
1194 {
1195         char **values = NULL;
1196
1197         if (existing != NULL) {
1198                 values = ldap_get_values(ldap_struct, existing, attribute);
1199         }
1200
1201         if ((values != NULL) && (values[0] != NULL) &&
1202             strcmp(values[0], newval) == 0) {
1203                 
1204                 /* Believe it or not, but LDAP will deny a delete and
1205                    an add at the same time if the values are the
1206                    same... */
1207
1208                 ldap_value_free(values);
1209                 return;
1210         }
1211
1212         /* Regardless of the real operation (add or modify)
1213            we add the new value here. We rely on deleting
1214            the old value, should it exist. */
1215
1216         if ((newval != NULL) && (strlen(newval) > 0)) {
1217                 make_a_mod(mods, LDAP_MOD_ADD, attribute, newval);
1218         }
1219
1220         if (values == NULL) {
1221                 /* There has been no value before, so don't delete it.
1222                    Here's a possible race: We might end up with
1223                    duplicate attributes */
1224                 return;
1225         }
1226
1227         /* By deleting exactly the value we found in the entry this
1228            should be race-free in the sense that the LDAP-Server will
1229            deny the complete operation if somebody changed the
1230            attribute behind our back. */
1231
1232         make_a_mod(mods, LDAP_MOD_DELETE, attribute, values[0]);
1233         ldap_value_free(values);
1234 }
1235
1236 /*******************************************************************
1237  Delete complete object or objectclass and attrs from
1238  object found in search_result depending on lp_ldap_delete_dn
1239 ******************************************************************/
1240 static NTSTATUS ldapsam_delete_entry(struct ldapsam_privates *ldap_state,
1241                                      LDAPMessage *result,
1242                                      const char *objectclass,
1243                                      char **attrs)
1244 {
1245         int rc;
1246         LDAPMessage *entry;
1247         LDAPMod **mods = NULL;
1248         char *name, *dn;
1249         BerElement *ptr = NULL;
1250
1251         rc = ldap_count_entries(ldap_state->ldap_struct, result);
1252
1253         if (rc != 1) {
1254                 DEBUG(0, ("Entry must exist exactly once!\n"));
1255                 return NT_STATUS_UNSUCCESSFUL;
1256         }
1257
1258         entry = ldap_first_entry(ldap_state->ldap_struct, result);
1259         dn    = ldap_get_dn(ldap_state->ldap_struct, entry);
1260
1261         if (lp_ldap_delete_dn()) {
1262                 NTSTATUS ret = NT_STATUS_OK;
1263                 rc = ldapsam_delete(ldap_state, dn);
1264
1265                 if (rc != LDAP_SUCCESS) {
1266                         DEBUG(0, ("Could not delete object %s\n", dn));
1267                         ret = NT_STATUS_UNSUCCESSFUL;
1268                 }
1269                 ldap_memfree(dn);
1270                 return ret;
1271         }
1272
1273         /* Ok, delete only the SAM attributes */
1274         
1275         for (name = ldap_first_attribute(ldap_state->ldap_struct, entry, &ptr);
1276              name != NULL;
1277              name = ldap_next_attribute(ldap_state->ldap_struct, entry, ptr)) 
1278         {
1279                 char **attrib;
1280
1281                 /* We are only allowed to delete the attributes that
1282                    really exist. */
1283
1284                 for (attrib = attrs; *attrib != NULL; attrib++) 
1285                 {
1286                         if (StrCaseCmp(*attrib, name) == 0) {
1287                                 DEBUG(10, ("deleting attribute %s\n", name));
1288                                 make_a_mod(&mods, LDAP_MOD_DELETE, name, NULL);
1289                         }
1290                 }
1291
1292                 ldap_memfree(name);
1293         }
1294         
1295         if (ptr != NULL) {
1296                 ber_free(ptr, 0);
1297         }
1298         
1299         make_a_mod(&mods, LDAP_MOD_DELETE, "objectClass", objectclass);
1300
1301         rc = ldapsam_modify(ldap_state, dn, mods);
1302         ldap_mods_free(mods, 1);
1303
1304         if (rc != LDAP_SUCCESS) {
1305                 char *ld_error = NULL;
1306                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
1307                                 &ld_error);
1308                 
1309                 DEBUG(0, ("could not delete attributes for %s, error: %s (%s)\n",
1310                           dn, ldap_err2string(rc), ld_error?ld_error:"unknown"));
1311                 SAFE_FREE(ld_error);
1312                 ldap_memfree(dn);
1313                 return NT_STATUS_UNSUCCESSFUL;
1314         }
1315
1316         ldap_memfree(dn);
1317         return NT_STATUS_OK;
1318 }
1319                                           
1320 /**********************************************************************
1321 Search for the domain info entry
1322 *********************************************************************/
1323 static int ldapsam_search_domain_info(struct ldapsam_privates *ldap_state,
1324                                       LDAPMessage ** result)
1325 {
1326         pstring filter;
1327         int rc;
1328         char **attr_list;
1329
1330         snprintf(filter, sizeof(filter)-1, "(&(objectClass=%s)(%s=%s))",
1331                 LDAP_OBJ_DOMINFO,
1332                 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), 
1333                 ldap_state->domain_name);
1334
1335         DEBUG(2, ("Searching for:[%s]\n", filter));
1336
1337
1338         attr_list = get_attr_list( dominfo_attr_list );
1339         rc = ldapsam_search_suffix(ldap_state, filter, attr_list , result);
1340         free_attr_list( attr_list );
1341
1342         if (rc != LDAP_SUCCESS) {
1343                 DEBUG(2,("Problem during LDAPsearch: %s\n", ldap_err2string (rc)));
1344                 DEBUG(2,("Query was: %s, %s\n", lp_ldap_suffix(), filter));
1345         }
1346         
1347         return rc;
1348 }
1349
1350 /**********************************************************************
1351  If this entry is is the 'allocated' range, extract the RID and return 
1352  it, so we can find the 'next' rid to allocate.
1353
1354  Do this, no matter what type of object holds the RID - be it a user,
1355  group or somthing else.
1356 *********************************************************************/
1357 static uint32 entry_to_rid(struct ldapsam_privates *ldap_state, LDAPMessage *entry, int rid_type) 
1358 {
1359         pstring sid_string;
1360         DOM_SID dom_sid;
1361         uint32 rid;
1362
1363         if (!get_single_attribute(ldap_state->ldap_struct, entry, 
1364                 LDAP_ATTRIBUTE_SID, sid_string)) 
1365         {
1366                 return 0;
1367         }
1368         
1369         if (!string_to_sid(&dom_sid, sid_string)) {
1370                 return 0;
1371         }
1372
1373         if (!sid_peek_check_rid(&dom_sid, get_global_sam_sid(), &rid)) {
1374                 /* not our domain, so we don't care */
1375                 return 0;
1376         }
1377
1378         switch (rid_type) {
1379         case USER_RID_TYPE:
1380                 if (rid >= ldap_state->low_allocated_user_rid && 
1381                     rid <= ldap_state->high_allocated_user_rid) {
1382                         return rid;
1383                 }
1384                 break;
1385         case GROUP_RID_TYPE:
1386                 if (rid >= ldap_state->low_allocated_group_rid && 
1387                     rid <= ldap_state->high_allocated_group_rid) {
1388                         return rid;
1389                 }
1390                 break;
1391         }
1392         return 0;
1393 }
1394
1395
1396 /**********************************************************************
1397 Connect to LDAP server and find the next available 'allocated' RID.
1398
1399 The search is done 'per type' as we allocate seperate pools for the
1400 EVEN and ODD (user and group) RIDs.  
1401
1402 This is only done once, so that we can fill out the sambaDomain.
1403 *********************************************************************/
1404 static uint32 search_next_allocated_rid(struct ldapsam_privates *ldap_state, int rid_type)
1405 {
1406         int rc;
1407         LDAPMessage *result;
1408         LDAPMessage *entry;
1409         uint32 top_rid = 0;
1410         uint32 next_rid;
1411         uint32 count;
1412         uint32 rid;
1413         char *sid_attr[] = {LDAP_ATTRIBUTE_SID, NULL};
1414         fstring filter;
1415         
1416         snprintf( filter, sizeof(filter)-1, "(%s=*)", LDAP_ATTRIBUTE_SID );
1417
1418         DEBUG(2, ("search_top_allocated_rid: searching for:[%s]\n", filter));
1419
1420         rc = ldapsam_search_suffix(ldap_state, filter, sid_attr, &result);
1421
1422         if (rc != LDAP_SUCCESS) {
1423                 DEBUG(3, ("LDAP search failed! cannot find base for NUA RIDs: %s\n", ldap_err2string(rc)));
1424                 DEBUGADD(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
1425
1426                 result = NULL;
1427                 return 0;
1428         }
1429         
1430         count = ldap_count_entries(ldap_state->ldap_struct, result);
1431         DEBUG(2, ("search_top_allocated_rid: %d entries in the base!\n", count));
1432         
1433         if (count == 0) {
1434                 DEBUG(3, ("LDAP search returned no records, assuming no allocated RIDs present!: %s\n", ldap_err2string(rc)));
1435                 DEBUGADD(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
1436         } else {
1437                 entry = ldap_first_entry(ldap_state->ldap_struct,result);
1438                 
1439                 top_rid = entry_to_rid(ldap_state, entry, rid_type);
1440                 
1441                 while ((entry = ldap_next_entry(ldap_state->ldap_struct, entry))) {
1442                         
1443                         rid = entry_to_rid(ldap_state, entry, rid_type);
1444                         if (((rid & ~RID_TYPE_MASK) == rid_type) && (rid > top_rid)) {
1445                                 top_rid = rid;
1446                         }
1447                 }
1448         }
1449
1450         switch (rid_type) {
1451         case USER_RID_TYPE:
1452                 if (top_rid < ldap_state->low_allocated_user_rid) {
1453                         return ldap_state->low_allocated_user_rid;
1454                 }
1455                 break;
1456         case GROUP_RID_TYPE:
1457                 if (top_rid < ldap_state->low_allocated_group_rid) 
1458                         return ldap_state->low_allocated_group_rid;
1459                 break;
1460         }
1461
1462         next_rid = (top_rid & ~RID_TYPE_MASK) + rid_type + RID_MULTIPLIER;
1463
1464         switch (rid_type) {
1465         case USER_RID_TYPE:
1466                 if (next_rid > ldap_state->high_allocated_user_rid) {
1467                         return 0;
1468                 }
1469                 break;
1470         case GROUP_RID_TYPE:
1471                 if (next_rid > ldap_state->high_allocated_group_rid) {
1472                         return 0;
1473                 }
1474                 break;
1475         }
1476         return next_rid;
1477 }
1478
1479 /**********************************************************************
1480  Add the sambaDomain to LDAP, so we don't have to search for this stuff
1481  again.  This is a once-add operation for now.
1482
1483  TODO:  Add other attributes, and allow modification.
1484 *********************************************************************/
1485 static NTSTATUS add_new_domain_info(struct ldapsam_privates *ldap_state) 
1486 {
1487         pstring tmp;
1488         pstring filter;
1489         LDAPMod **mods = NULL;
1490         int rc;
1491         int ldap_op;
1492         LDAPMessage *result = NULL;
1493         char *dn = NULL;
1494         int num_result;
1495         char **attr_list;
1496
1497         uint32 next_allocated_user_rid;
1498         uint32 next_allocated_group_rid;
1499
1500         next_allocated_user_rid = search_next_allocated_rid(ldap_state, USER_RID_TYPE);
1501         if (!next_allocated_user_rid) {
1502                 return NT_STATUS_UNSUCCESSFUL;
1503         }
1504
1505         next_allocated_group_rid = search_next_allocated_rid(ldap_state, GROUP_RID_TYPE);
1506         if (!next_allocated_group_rid) {
1507                 return NT_STATUS_UNSUCCESSFUL;
1508         }
1509
1510         slprintf (filter, sizeof (filter) - 1, "(&(%s=%s)(objectclass=%s))", 
1511                 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), 
1512                 ldap_state->domain_name, LDAP_OBJ_DOMINFO);
1513
1514         attr_list = get_attr_list( dominfo_attr_list );
1515         rc = ldapsam_search_suffix(ldap_state, filter, attr_list, &result);
1516         free_attr_list( attr_list );
1517
1518         if (rc != LDAP_SUCCESS) {
1519                 return NT_STATUS_UNSUCCESSFUL;
1520         }
1521
1522         num_result = ldap_count_entries(ldap_state->ldap_struct, result);
1523         
1524         if (num_result > 1) {
1525                 DEBUG (0, ("More than domain with that name exists: bailing out!\n"));
1526                 ldap_msgfree(result);
1527                 return NT_STATUS_UNSUCCESSFUL;
1528         }
1529         
1530         /* Check if we need to add an entry */
1531         DEBUG(3,("Adding new domain\n"));
1532         ldap_op = LDAP_MOD_ADD;
1533         asprintf (&dn, "%s=%s,%s", get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN),
1534                 ldap_state->domain_name, lp_ldap_suffix());
1535
1536         /* Free original search */
1537         ldap_msgfree(result);
1538
1539         if (!dn)
1540                 return NT_STATUS_NO_MEMORY;
1541
1542         /* make the changes - the entry *must* not already have samba attributes */
1543         make_a_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOMAIN), 
1544                 ldap_state->domain_name);
1545
1546         sid_to_string(tmp, &ldap_state->domain_sid);
1547         make_a_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID), tmp);
1548
1549         snprintf(tmp, sizeof(tmp)-1, "%i", next_allocated_user_rid);
1550         make_a_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID), tmp);
1551
1552         snprintf(tmp, sizeof(tmp)-1, "%i", next_allocated_group_rid);
1553         make_a_mod(&mods, LDAP_MOD_ADD, get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID), tmp);
1554
1555         make_a_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_DOMINFO);
1556
1557         switch(ldap_op)
1558         {
1559         case LDAP_MOD_ADD: 
1560                 rc = ldapsam_add(ldap_state, dn, mods);
1561                 break;
1562         case LDAP_MOD_REPLACE: 
1563                 rc = ldapsam_modify(ldap_state, dn, mods);
1564                 break;
1565         default:        
1566                 DEBUG(0,("Wrong LDAP operation type: %d!\n", ldap_op));
1567                 return NT_STATUS_INVALID_PARAMETER;
1568         }
1569         
1570         if (rc!=LDAP_SUCCESS) {
1571                 char *ld_error = NULL;
1572                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
1573                                 &ld_error);
1574                 DEBUG(1,
1575                       ("failed to %s domain dn= %s with: %s\n\t%s\n",
1576                        ldap_op == LDAP_MOD_ADD ? "add" : "modify",
1577                        dn, ldap_err2string(rc),
1578                        ld_error?ld_error:"unknown"));
1579                 SAFE_FREE(ld_error);
1580
1581                 ldap_mods_free(mods,1);
1582                 return NT_STATUS_UNSUCCESSFUL;
1583         }
1584
1585         DEBUG(2,("added: domain = %s in the LDAP database\n", ldap_state->domain_name));
1586         ldap_mods_free(mods, 1);
1587         return NT_STATUS_OK;
1588 }
1589
1590 /**********************************************************************
1591  Even if the sambaAccount attribute in LDAP tells us that this RID is 
1592  safe to use, always check before use.  
1593 *********************************************************************/
1594 static BOOL sid_in_use(struct ldapsam_privates *ldap_state, 
1595                        const DOM_SID *sid, int *error) 
1596 {
1597         fstring filter;
1598         fstring sid_string;
1599         LDAPMessage *result = NULL;
1600         int count;
1601         int rc;
1602         char *sid_attr[] = {LDAP_ATTRIBUTE_SID, NULL};
1603
1604         slprintf(filter, sizeof(filter)-1, "(%s=%s)", LDAP_ATTRIBUTE_SID, sid_to_string(sid_string, sid));
1605
1606         rc = ldapsam_search_suffix(ldap_state, filter, sid_attr, &result);
1607
1608         if (rc != LDAP_SUCCESS) {
1609                 char *ld_error = NULL;
1610                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
1611                 DEBUG(2, ("Failed to check if sid %s is alredy in use: %s\n", 
1612                           sid_string, ld_error));
1613                 SAFE_FREE(ld_error);
1614
1615                 *error = rc;
1616                 return True;
1617         }
1618         
1619         if ((count = ldap_count_entries(ldap_state->ldap_struct, result)) > 0) {
1620                 DEBUG(3, ("Sid %s already in use - trying next RID\n",
1621                           sid_string));
1622                 ldap_msgfree(result);
1623                 return True;
1624         }
1625
1626         ldap_msgfree(result);
1627
1628         /* good, sid is not in use */
1629         return False;
1630 }
1631
1632 /**********************************************************************
1633  Set the new nextRid attribute, and return one we can use.
1634
1635  This also checks that this RID is actually free - in case the admin
1636  manually stole it :-).
1637 *********************************************************************/
1638 static NTSTATUS ldapsam_next_rid(struct ldapsam_privates *ldap_state, uint32 *rid, int rid_type)
1639 {
1640         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
1641         int rc;
1642         LDAPMessage *result = NULL;
1643         LDAPMessage *entry  = NULL;
1644         char *dn;
1645         LDAPMod **mods = NULL;
1646         int count;
1647         fstring old_rid_string;
1648         fstring next_rid_string;
1649         uint32 next_rid;
1650         int attempts = 0;
1651
1652         if ( ldap_state->schema_ver != SCHEMAVER_SAMBASAMACCOUNT ) {
1653                 DEBUG(0, ("Allocated RIDs require the %s objectclass used by 'ldapsam'\n", 
1654                         LDAP_OBJ_SAMBASAMACCOUNT));
1655                 return NT_STATUS_UNSUCCESSFUL;
1656         }
1657         
1658         while (attempts < 10) 
1659         {
1660                 char *ld_error;
1661                 if (ldapsam_search_domain_info(ldap_state, &result)) {
1662                         return ret;
1663                 }
1664
1665                 if (ldap_count_entries(ldap_state->ldap_struct, result) < 1) {
1666                         DEBUG(3, ("Got no domain info entries for domain %s\n",
1667                                   ldap_state->domain_name));
1668                         ldap_msgfree(result);
1669                         if (NT_STATUS_IS_OK(ret = add_new_domain_info(ldap_state))) {
1670                                 continue;
1671                         } else {
1672                                 DEBUG(0, ("Adding domain info failed with %s\n", nt_errstr(ret)));
1673                                 return ret;
1674                         }
1675                 }
1676                 
1677                 if ((count = ldap_count_entries(ldap_state->ldap_struct, result)) > 1) {
1678                         DEBUG(0, ("Got too many (%d) domain info entries for domain %s\n",
1679                                   count, ldap_state->domain_name));
1680                         ldap_msgfree(result);
1681                         return ret;
1682                 }
1683
1684                 entry = ldap_first_entry(ldap_state->ldap_struct, result);
1685                 if (!entry) {
1686                         ldap_msgfree(result);
1687                         return ret;
1688                 }
1689
1690                 if ((dn = ldap_get_dn(ldap_state->ldap_struct, entry)) == NULL) {
1691                         DEBUG(0, ("Could not get domain info DN\n"));
1692                         ldap_msgfree(result);
1693                         return ret;
1694                 }
1695
1696                 /* yes, we keep 2 seperate counters, to avoid stomping on the two
1697                    different sets of algorithmic RIDs */
1698
1699                 switch (rid_type) {
1700                 case USER_RID_TYPE:
1701                         if (!get_single_attribute(ldap_state->ldap_struct, 
1702                                                   entry, "nextUserRid",
1703                                                   old_rid_string)) {
1704                                 ldap_memfree(dn);
1705                                 ldap_msgfree(result);
1706                                 return ret;
1707                         }
1708                         break;
1709                 case GROUP_RID_TYPE:
1710                         if (!get_single_attribute(ldap_state->ldap_struct, 
1711                                                   entry, "nextGroupRid",
1712                                                   old_rid_string)) {
1713                                 ldap_memfree(dn);
1714                                 ldap_msgfree(result);
1715                                 return ret;
1716                         }
1717                         break;
1718                 }
1719
1720                 /* This is the core of the whole routine. If we had
1721                    scheme-style closures, there would be a *lot* less code
1722                    duplication... */
1723                 *rid = (uint32)atol(old_rid_string);
1724                 next_rid = *rid+RID_MULTIPLIER;
1725
1726                 slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
1727
1728                 switch (rid_type) {
1729                 case USER_RID_TYPE:
1730                         if (next_rid > ldap_state->high_allocated_user_rid) {
1731                                 return NT_STATUS_UNSUCCESSFUL;
1732                         }
1733
1734                         /* Try to make the modification atomically by enforcing the
1735                            old value in the delete mod. */
1736                         make_ldap_mod(ldap_state->ldap_struct, entry, &mods, 
1737                                 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID), 
1738                                 next_rid_string);
1739                         break;
1740
1741                 case GROUP_RID_TYPE:
1742                         if (next_rid > ldap_state->high_allocated_group_rid) {
1743                                 return NT_STATUS_UNSUCCESSFUL;
1744                         }
1745
1746                         /* Try to make the modification atomically by enforcing the
1747                            old value in the delete mod. */
1748                         make_ldap_mod(ldap_state->ldap_struct, entry, &mods,
1749                                 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
1750                                 next_rid_string);
1751                         break;
1752                 }
1753
1754                 if ((rc = ldap_modify_s(ldap_state->ldap_struct, dn, mods)) == LDAP_SUCCESS) {
1755                         DOM_SID dom_sid;
1756                         DOM_SID sid;
1757                         pstring domain_sid_string;
1758                         int error = 0;
1759
1760                         if (!get_single_attribute(ldap_state->ldap_struct, result,
1761                                 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID),
1762                                 domain_sid_string)) 
1763                         {
1764                                 ldap_mods_free(mods, 1);
1765                                 ldap_memfree(dn);
1766                                 ldap_msgfree(result);
1767                                 return ret;
1768                         }
1769
1770                         if (!string_to_sid(&dom_sid, domain_sid_string)) { 
1771                                 ldap_mods_free(mods, 1);
1772                                 ldap_memfree(dn);
1773                                 ldap_msgfree(result);
1774                                 return ret;
1775                         }
1776
1777                         ldap_mods_free(mods, 1);
1778                         mods = NULL;
1779                         ldap_memfree(dn);
1780                         ldap_msgfree(result);
1781
1782                         sid_copy(&sid, &dom_sid);
1783                         sid_append_rid(&sid, *rid);
1784
1785                         /* check RID is not in use */
1786                         if (sid_in_use(ldap_state, &sid, &error)) {
1787                                 if (error) {
1788                                         return ret;
1789                                 }
1790                                 continue;
1791                         }
1792
1793                         return NT_STATUS_OK;
1794                 }
1795
1796                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
1797                 DEBUG(2, ("Failed to modify rid: %s\n", ld_error));
1798                 SAFE_FREE(ld_error);
1799
1800                 ldap_mods_free(mods, 1);
1801                 mods = NULL;
1802
1803                 ldap_memfree(dn);
1804                 dn = NULL;
1805
1806                 ldap_msgfree(result);
1807                 result = NULL;
1808
1809                 {
1810                         /* Sleep for a random timeout */
1811                         unsigned sleeptime = (sys_random()*sys_getpid()*attempts);
1812                         attempts += 1;
1813                         
1814                         sleeptime %= 100;
1815                         msleep(sleeptime);
1816                 }
1817         }
1818
1819         DEBUG(0, ("Failed to set new RID\n"));
1820         return ret;
1821 }
1822
1823 /* New Interface is being implemented here */
1824
1825 /**********************************************************************
1826 Initialize SAM_ACCOUNT from an LDAP query (unix attributes only)
1827 *********************************************************************/
1828 static BOOL get_unix_attributes (struct ldapsam_privates *ldap_state, 
1829                                 SAM_ACCOUNT * sampass,
1830                                 LDAPMessage * entry,
1831                                 gid_t *gid)
1832 {
1833         pstring  homedir;
1834         pstring  temp;
1835         char **ldap_values;
1836         char **values;
1837
1838         if ((ldap_values = ldap_get_values (ldap_state->ldap_struct, entry, "objectClass")) == NULL) {
1839                 DEBUG (1, ("get_unix_attributes: no objectClass! \n"));
1840                 return False;
1841         }
1842
1843         for (values=ldap_values;*values;values++) {
1844                 if (strcasecmp(*values, LDAP_OBJ_POSIXACCOUNT ) == 0) {
1845                         break;
1846                 }
1847         }
1848         
1849         if (!*values) { /*end of array, no posixAccount */
1850                 DEBUG(10, ("user does not have %s attributes\n", LDAP_OBJ_POSIXACCOUNT));
1851                 ldap_value_free(ldap_values);
1852                 return False;
1853         }
1854         ldap_value_free(ldap_values);
1855
1856         if ( !get_single_attribute(ldap_state->ldap_struct, entry, 
1857                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_UNIX_HOME), homedir) ) 
1858         {
1859                 return False;
1860         }
1861         
1862         if ( !get_single_attribute(ldap_state->ldap_struct, entry, 
1863                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_GIDNUMBER), temp) )
1864         {
1865                 return False;
1866         }
1867         
1868         *gid = (gid_t)atol(temp);
1869
1870         pdb_set_unix_homedir(sampass, homedir, PDB_SET);
1871         
1872         DEBUG(10, ("user has %s attributes\n", LDAP_OBJ_POSIXACCOUNT));
1873         
1874         return True;
1875 }
1876
1877
1878 /**********************************************************************
1879 Initialize SAM_ACCOUNT from an LDAP query
1880 (Based on init_sam_from_buffer in pdb_tdb.c)
1881 *********************************************************************/
1882 static BOOL init_sam_from_ldap (struct ldapsam_privates *ldap_state, 
1883                                 SAM_ACCOUNT * sampass,
1884                                 LDAPMessage * entry)
1885 {
1886         time_t  logon_time,
1887                         logoff_time,
1888                         kickoff_time,
1889                         pass_last_set_time, 
1890                         pass_can_change_time, 
1891                         pass_must_change_time;
1892         pstring         username, 
1893                         domain,
1894                         nt_username,
1895                         fullname,
1896                         homedir,
1897                         dir_drive,
1898                         logon_script,
1899                         profile_path,
1900                         acct_desc,
1901                         munged_dial,
1902                         workstations;
1903         uint32          user_rid; 
1904         uint8           smblmpwd[LM_HASH_LEN],
1905                         smbntpwd[NT_HASH_LEN];
1906         uint16          acct_ctrl = 0, 
1907                         logon_divs;
1908         uint32 hours_len;
1909         uint8           hours[MAX_HOURS_LEN];
1910         pstring temp;
1911         uid_t           uid = -1;
1912         gid_t           gid = getegid();
1913
1914         /*
1915          * do a little initialization
1916          */
1917         username[0]     = '\0';
1918         domain[0]       = '\0';
1919         nt_username[0]  = '\0';
1920         fullname[0]     = '\0';
1921         homedir[0]      = '\0';
1922         dir_drive[0]    = '\0';
1923         logon_script[0] = '\0';
1924         profile_path[0] = '\0';
1925         acct_desc[0]    = '\0';
1926         munged_dial[0]  = '\0';
1927         workstations[0] = '\0';
1928          
1929
1930         if (sampass == NULL || ldap_state == NULL || entry == NULL) {
1931                 DEBUG(0, ("init_sam_from_ldap: NULL parameters found!\n"));
1932                 return False;
1933         }
1934
1935         if (ldap_state->ldap_struct == NULL) {
1936                 DEBUG(0, ("init_sam_from_ldap: ldap_state->ldap_struct is NULL!\n"));
1937                 return False;
1938         }
1939         
1940         if (!get_single_attribute(ldap_state->ldap_struct, entry, "uid", username)) {
1941                 DEBUG(1, ("No uid attribute found for this user!\n"));
1942                 return False;
1943         }
1944
1945         DEBUG(2, ("Entry found for user: %s\n", username));
1946
1947         pstrcpy(nt_username, username);
1948
1949         pstrcpy(domain, ldap_state->domain_name);
1950         
1951         pdb_set_username(sampass, username, PDB_SET);
1952
1953         pdb_set_domain(sampass, domain, PDB_DEFAULT);
1954         pdb_set_nt_username(sampass, nt_username, PDB_SET);
1955         
1956         /* deal with different attributes between the schema first */
1957         
1958         if ( ldap_state->schema_ver == SCHEMAVER_SAMBASAMACCOUNT ) 
1959         {
1960                 if (get_single_attribute(ldap_state->ldap_struct, entry, 
1961                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_SID), temp)) 
1962                 {
1963                         pdb_set_user_sid_from_string(sampass, temp, PDB_SET);
1964                 }
1965                 
1966                 if (!get_single_attribute(ldap_state->ldap_struct, entry, 
1967                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PRIMARY_GROUP_SID), temp)) 
1968                 {
1969                         pdb_set_group_sid_from_string(sampass, temp, PDB_SET);                  
1970                 }
1971                 else 
1972                 {
1973                         pdb_set_group_sid_from_rid(sampass, DOMAIN_GROUP_RID_USERS, PDB_DEFAULT);
1974                 }
1975
1976
1977         } 
1978         else 
1979         {
1980                 if (get_single_attribute(ldap_state->ldap_struct, entry,
1981                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_RID), temp)) 
1982                 {
1983                         user_rid = (uint32)atol(temp);
1984                         pdb_set_user_sid_from_rid(sampass, user_rid, PDB_SET);
1985                 }
1986                 
1987                 if (!get_single_attribute(ldap_state->ldap_struct, entry, 
1988                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PRIMARY_GROUP_RID), temp)) 
1989                 {
1990                         pdb_set_group_sid_from_rid(sampass, DOMAIN_GROUP_RID_USERS, PDB_DEFAULT);
1991                 } else {
1992                         uint32 group_rid;
1993                         
1994                         group_rid = (uint32)atol(temp);
1995                         
1996                         /* for some reason, we often have 0 as a primary group RID.
1997                            Make sure that we treat this just as a 'default' value */
1998                            
1999                         if ( group_rid > 0 )
2000                                 pdb_set_group_sid_from_rid(sampass, group_rid, PDB_SET);
2001                         else
2002                                 pdb_set_group_sid_from_rid(sampass, DOMAIN_GROUP_RID_USERS, PDB_DEFAULT);
2003                 }
2004         }
2005
2006         if (pdb_get_init_flags(sampass,PDB_USERSID) == PDB_DEFAULT) {
2007                 DEBUG(1, ("no %s or %s attribute found for this user %s\n", 
2008                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_SID),
2009                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_RID),
2010                         username));
2011                 return False;
2012         }
2013
2014
2015         /* 
2016          * If so configured, try and get the values from LDAP 
2017          */
2018
2019         if (lp_ldap_trust_ids() && (get_unix_attributes(ldap_state, sampass, entry, &gid))) 
2020         {       
2021                 if (pdb_get_init_flags(sampass,PDB_GROUPSID) == PDB_DEFAULT) 
2022                 {
2023                         GROUP_MAP map;
2024                         /* call the mapping code here */
2025                         if(pdb_getgrgid(&map, gid, MAPPING_WITHOUT_PRIV)) {
2026                                 pdb_set_group_sid(sampass, &map.sid, PDB_SET);
2027                         } 
2028                         else {
2029                                 pdb_set_group_sid_from_rid(sampass, pdb_gid_to_group_rid(gid), PDB_SET);
2030                         }
2031                 }
2032         }
2033
2034         if (!get_single_attribute(ldap_state->ldap_struct, entry, 
2035                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_LAST_SET), temp)) 
2036         {
2037                 /* leave as default */
2038         } else {
2039                 pass_last_set_time = (time_t) atol(temp);
2040                 pdb_set_pass_last_set_time(sampass, pass_last_set_time, PDB_SET);
2041         }
2042
2043         if (!get_single_attribute(ldap_state->ldap_struct, entry, 
2044                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGON_TIME), temp)) 
2045         {
2046                 /* leave as default */
2047         } else {
2048                 logon_time = (time_t) atol(temp);
2049                 pdb_set_logon_time(sampass, logon_time, PDB_SET);
2050         }
2051
2052         if (!get_single_attribute(ldap_state->ldap_struct, entry, 
2053                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGOFF_TIME), temp)) 
2054         {
2055                 /* leave as default */
2056         } else {
2057                 logoff_time = (time_t) atol(temp);
2058                 pdb_set_logoff_time(sampass, logoff_time, PDB_SET);
2059         }
2060
2061         if (!get_single_attribute(ldap_state->ldap_struct, entry, 
2062                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_KICKOFF_TIME), temp)) 
2063         {
2064                 /* leave as default */
2065         } else {
2066                 kickoff_time = (time_t) atol(temp);
2067                 pdb_set_kickoff_time(sampass, kickoff_time, PDB_SET);
2068         }
2069
2070         if (!get_single_attribute(ldap_state->ldap_struct, entry, 
2071                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_CAN_CHANGE), temp)) 
2072         {
2073                 /* leave as default */
2074         } else {
2075                 pass_can_change_time = (time_t) atol(temp);
2076                 pdb_set_pass_can_change_time(sampass, pass_can_change_time, PDB_SET);
2077         }
2078
2079         if (!get_single_attribute(ldap_state->ldap_struct, entry, 
2080                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_MUST_CHANGE), temp)) 
2081         {       
2082                 /* leave as default */
2083         } else {
2084                 pass_must_change_time = (time_t) atol(temp);
2085                 pdb_set_pass_must_change_time(sampass, pass_must_change_time, PDB_SET);
2086         }
2087
2088         /* recommend that 'gecos' and 'displayName' should refer to the same
2089          * attribute OID.  userFullName depreciated, only used by Samba
2090          * primary rules of LDAP: don't make a new attribute when one is already defined
2091          * that fits your needs; using cn then displayName rather than 'userFullName'
2092          */
2093
2094         if (!get_single_attribute(ldap_state->ldap_struct, entry,
2095                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_DISPLAY_NAME), fullname)) 
2096         {
2097                 if (!get_single_attribute(ldap_state->ldap_struct, entry,
2098                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_CN), fullname)) 
2099                 {
2100                         /* leave as default */
2101                 } else {
2102                         pdb_set_fullname(sampass, fullname, PDB_SET);
2103                 }
2104         } else {
2105                 pdb_set_fullname(sampass, fullname, PDB_SET);
2106         }
2107
2108         if (!get_single_attribute(ldap_state->ldap_struct, entry, 
2109                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_HOME_DRIVE), dir_drive)) 
2110         {
2111                 pdb_set_dir_drive(sampass, talloc_sub_specified(sampass->mem_ctx, 
2112                                                                   lp_logon_drive(),
2113                                                                   username, domain, 
2114                                                                   uid, gid),
2115                                   PDB_DEFAULT);
2116         } else {
2117                 pdb_set_dir_drive(sampass, dir_drive, PDB_SET);
2118         }
2119
2120         if (!get_single_attribute(ldap_state->ldap_struct, entry,
2121                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_HOME_PATH), homedir)) 
2122         {
2123                 pdb_set_homedir(sampass, talloc_sub_specified(sampass->mem_ctx, 
2124                                                                   lp_logon_home(),
2125                                                                   username, domain, 
2126                                                                   uid, gid), 
2127                                   PDB_DEFAULT);
2128         } else {
2129                 pdb_set_homedir(sampass, homedir, PDB_SET);
2130         }
2131
2132         if (!get_single_attribute(ldap_state->ldap_struct, entry,
2133                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGON_SCRIPT), logon_script)) 
2134         {
2135                 pdb_set_logon_script(sampass, talloc_sub_specified(sampass->mem_ctx, 
2136                                                                      lp_logon_script(),
2137                                                                      username, domain, 
2138                                                                      uid, gid), 
2139                                      PDB_DEFAULT);
2140         } else {
2141                 pdb_set_logon_script(sampass, logon_script, PDB_SET);
2142         }
2143
2144         if (!get_single_attribute(ldap_state->ldap_struct, entry,
2145                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PROFILE_PATH), profile_path)) 
2146         {
2147                 pdb_set_profile_path(sampass, talloc_sub_specified(sampass->mem_ctx, 
2148                                                                      lp_logon_path(),
2149                                                                      username, domain, 
2150                                                                      uid, gid), 
2151                                      PDB_DEFAULT);
2152         } else {
2153                 pdb_set_profile_path(sampass, profile_path, PDB_SET);
2154         }
2155
2156         if (!get_single_attribute(ldap_state->ldap_struct, entry, 
2157                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_DESC), acct_desc)) 
2158         {
2159                 /* leave as default */
2160         } else {
2161                 pdb_set_acct_desc(sampass, acct_desc, PDB_SET);
2162         }
2163
2164         if (!get_single_attribute(ldap_state->ldap_struct, entry, 
2165                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_WKS), workstations)) 
2166         {
2167                 /* leave as default */;
2168         } else {
2169                 pdb_set_workstations(sampass, workstations, PDB_SET);
2170         }
2171
2172         /* FIXME: hours stuff should be cleaner */
2173         
2174         logon_divs = 168;
2175         hours_len = 21;
2176         memset(hours, 0xff, hours_len);
2177
2178         if (!get_single_attribute (ldap_state->ldap_struct, entry, 
2179                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LMPW), temp)) 
2180         {
2181                 /* leave as default */
2182         } else {
2183                 pdb_gethexpwd(temp, smblmpwd);
2184                 memset((char *)temp, '\0', strlen(temp)+1);
2185                 if (!pdb_set_lanman_passwd(sampass, smblmpwd, PDB_SET))
2186                         return False;
2187                 ZERO_STRUCT(smblmpwd);
2188         }
2189
2190         if (!get_single_attribute (ldap_state->ldap_struct, entry,
2191                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_NTPW), temp)) 
2192         {
2193                 /* leave as default */
2194         } else {
2195                 pdb_gethexpwd(temp, smbntpwd);
2196                 memset((char *)temp, '\0', strlen(temp)+1);
2197                 if (!pdb_set_nt_passwd(sampass, smbntpwd, PDB_SET))
2198                         return False;
2199                 ZERO_STRUCT(smbntpwd);
2200         }
2201
2202         if (!get_single_attribute (ldap_state->ldap_struct, entry,
2203                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_ACB_INFO), temp)) 
2204         {
2205                 acct_ctrl |= ACB_NORMAL;
2206         } else {
2207                 acct_ctrl = pdb_decode_acct_ctrl(temp);
2208
2209                 if (acct_ctrl == 0)
2210                         acct_ctrl |= ACB_NORMAL;
2211
2212                 pdb_set_acct_ctrl(sampass, acct_ctrl, PDB_SET);
2213         }
2214
2215         pdb_set_hours_len(sampass, hours_len, PDB_SET);
2216         pdb_set_logon_divs(sampass, logon_divs, PDB_SET);
2217
2218         pdb_set_munged_dial(sampass, munged_dial, PDB_SET);
2219         
2220         /* pdb_set_unknown_3(sampass, unknown3, PDB_SET); */
2221         /* pdb_set_unknown_5(sampass, unknown5, PDB_SET); */
2222         /* pdb_set_unknown_6(sampass, unknown6, PDB_SET); */
2223
2224         pdb_set_hours(sampass, hours, PDB_SET);
2225
2226         return True;
2227 }
2228
2229 /**********************************************************************
2230 Initialize SAM_ACCOUNT from an LDAP query
2231 (Based on init_buffer_from_sam in pdb_tdb.c)
2232 *********************************************************************/
2233 static BOOL init_ldap_from_sam (struct ldapsam_privates *ldap_state, 
2234                                 LDAPMessage *existing,
2235                                 LDAPMod *** mods, SAM_ACCOUNT * sampass,
2236                                 BOOL (*need_update)(const SAM_ACCOUNT *,
2237                                                     enum pdb_elements))
2238 {
2239         pstring temp;
2240         uint32 rid;
2241
2242         if (mods == NULL || sampass == NULL) {
2243                 DEBUG(0, ("init_ldap_from_sam: NULL parameters found!\n"));
2244                 return False;
2245         }
2246
2247         *mods = NULL;
2248
2249         /* 
2250          * took out adding "objectclass: sambaAccount"
2251          * do this on a per-mod basis
2252          */
2253         if (need_update(sampass, PDB_USERNAME))
2254                 make_ldap_mod(ldap_state->ldap_struct, existing, mods, 
2255                               "uid", pdb_get_username(sampass));
2256
2257         DEBUG(2, ("Setting entry for user: %s\n", pdb_get_username(sampass)));
2258
2259         if (pdb_get_init_flags(sampass, PDB_USERSID) == PDB_DEFAULT) {
2260                 if (ldap_state->permit_non_unix_accounts) {
2261                         if (!NT_STATUS_IS_OK(ldapsam_next_rid(ldap_state, &rid, USER_RID_TYPE))) {
2262                                 DEBUG(0, ("NO user RID specified on account %s, and "
2263                                           "finding next available NUA RID failed, "
2264                                           "cannot store!\n",
2265                                           pdb_get_username(sampass)));
2266                                 ldap_mods_free(*mods, 1);
2267                                 return False;
2268                         }
2269                 } else {
2270                         DEBUG(0, ("NO user RID specified on account %s, "
2271                                   "cannot store!\n", pdb_get_username(sampass)));
2272                         ldap_mods_free(*mods, 1);
2273                         return False;
2274                 }
2275
2276                 /* now that we have figured out the RID, always store it, as
2277                    the schema requires it (either as a SID or a RID) */
2278                    
2279                 if (!pdb_set_user_sid_from_rid(sampass, rid, PDB_CHANGED)) {
2280                         DEBUG(0, ("Could not store RID back onto SAM_ACCOUNT for user %s!\n", 
2281                                   pdb_get_username(sampass)));
2282                         ldap_mods_free(*mods, 1);
2283                         return False;
2284                 }
2285         }
2286
2287         /* only update the RID if we actually need to */
2288         if (need_update(sampass, PDB_USERSID)) 
2289         {
2290                 fstring sid_string;
2291                 fstring dom_sid_string;
2292                 const DOM_SID *user_sid = pdb_get_user_sid(sampass);
2293                 
2294                 switch ( ldap_state->schema_ver )
2295                 {
2296                         case SCHEMAVER_SAMBAACCOUNT:
2297                                 if (!sid_peek_check_rid(get_global_sam_sid(), user_sid, &rid)) {
2298                                         DEBUG(1, ("User's SID (%s) is not for this domain (%s), cannot add to LDAP!\n", 
2299                                                 sid_to_string(sid_string, user_sid), 
2300                                                 sid_to_string(dom_sid_string, get_global_sam_sid())));
2301                                         return False;
2302                                 }
2303                                 slprintf(temp, sizeof(temp) - 1, "%i", rid);
2304                                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2305                                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_RID), 
2306                                         temp);
2307                                 break;
2308                                 
2309                         case SCHEMAVER_SAMBASAMACCOUNT:
2310                                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2311                                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_SID), 
2312                                         sid_to_string(sid_string, user_sid));                                 
2313                                 break;
2314                                 
2315                         default:
2316                                 DEBUG(0,("init_ldap_from_sam: unknown schema version specified\n"));
2317                                 break;
2318                 }               
2319         }
2320
2321         /* we don't need to store the primary group RID - so leaving it
2322            'free' to hang off the unix primary group makes life easier */
2323
2324         if (need_update(sampass, PDB_GROUPSID)) 
2325         {
2326                 fstring sid_string;
2327                 fstring dom_sid_string;
2328                 const DOM_SID *group_sid = pdb_get_group_sid(sampass);
2329                 
2330                 switch ( ldap_state->schema_ver )
2331                 {
2332                         case SCHEMAVER_SAMBAACCOUNT:
2333                                 if (!sid_peek_check_rid(get_global_sam_sid(), group_sid, &rid)) {
2334                                         DEBUG(1, ("User's Primary Group SID (%s) is not for this domain (%s), cannot add to LDAP!\n",
2335                                                 sid_to_string(sid_string, group_sid),
2336                                                 sid_to_string(dom_sid_string, get_global_sam_sid())));
2337                                         return False;
2338                                 }
2339
2340                                 slprintf(temp, sizeof(temp) - 1, "%i", rid);
2341                                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2342                                         get_userattr_key2string(ldap_state->schema_ver, 
2343                                         LDAP_ATTR_PRIMARY_GROUP_RID), temp);
2344                                 break;
2345                                 
2346                         case SCHEMAVER_SAMBASAMACCOUNT:
2347                                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2348                                         get_userattr_key2string(ldap_state->schema_ver, 
2349                                         LDAP_ATTR_PRIMARY_GROUP_SID), sid_to_string(sid_string, group_sid));
2350                                 break;
2351                                 
2352                         default:
2353                                 DEBUG(0,("init_ldap_from_sam: unknown schema version specified\n"));
2354                                 break;
2355                 }
2356                 
2357         }
2358         
2359         /* displayName, cn, and gecos should all be the same
2360          *  most easily accomplished by giving them the same OID
2361          *  gecos isn't set here b/c it should be handled by the 
2362          *  add-user script
2363          *  We change displayName only and fall back to cn if
2364          *  it does not exist.
2365          */
2366
2367         if (need_update(sampass, PDB_FULLNAME))
2368                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2369                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_DISPLAY_NAME), 
2370                         pdb_get_fullname(sampass));
2371
2372         if (need_update(sampass, PDB_ACCTDESC))
2373                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2374                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_DESC), 
2375                         pdb_get_acct_desc(sampass));
2376
2377         if (need_update(sampass, PDB_WORKSTATIONS))
2378                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2379                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_USER_WKS), 
2380                         pdb_get_workstations(sampass));
2381
2382         if (need_update(sampass, PDB_SMBHOME))
2383                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2384                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_HOME_PATH), 
2385                         pdb_get_homedir(sampass));
2386                         
2387         if (need_update(sampass, PDB_DRIVE))
2388                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2389                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_HOME_DRIVE), 
2390                         pdb_get_dir_drive(sampass));
2391
2392         if (need_update(sampass, PDB_LOGONSCRIPT))
2393                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2394                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGON_SCRIPT), 
2395                         pdb_get_logon_script(sampass));
2396
2397         if (need_update(sampass, PDB_PROFILE))
2398                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2399                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PROFILE_PATH), 
2400                         pdb_get_profile_path(sampass));
2401
2402         slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logon_time(sampass));
2403         if (need_update(sampass, PDB_LOGONTIME))
2404                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2405                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGON_TIME), temp);
2406
2407         slprintf(temp, sizeof(temp) - 1, "%li", pdb_get_logoff_time(sampass));
2408         if (need_update(sampass, PDB_LOGOFFTIME))
2409                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2410                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LOGOFF_TIME), temp);
2411
2412         slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_kickoff_time(sampass));
2413         if (need_update(sampass, PDB_KICKOFFTIME))
2414                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2415                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_KICKOFF_TIME), temp);
2416
2417         slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_can_change_time(sampass));
2418         if (need_update(sampass, PDB_CANCHANGETIME))
2419                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2420                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_CAN_CHANGE), temp);
2421
2422         slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_must_change_time(sampass));
2423         if (need_update(sampass, PDB_MUSTCHANGETIME))
2424                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2425                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_MUST_CHANGE), temp);
2426
2427         if ((pdb_get_acct_ctrl(sampass)&(ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST))
2428                 || (lp_ldap_passwd_sync()!=LDAP_PASSWD_SYNC_ONLY)) 
2429         {
2430
2431                 pdb_sethexpwd(temp, pdb_get_lanman_passwd(sampass),
2432                                pdb_get_acct_ctrl(sampass));
2433
2434                 if (need_update(sampass, PDB_LMPASSWD))
2435                         make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2436                                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_LMPW), 
2437                                 temp);
2438
2439                 pdb_sethexpwd (temp, pdb_get_nt_passwd(sampass),
2440                                pdb_get_acct_ctrl(sampass));
2441
2442                 if (need_update(sampass, PDB_NTPASSWD))
2443                         make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2444                                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_NTPW), 
2445                                 temp);
2446
2447                 slprintf (temp, sizeof (temp) - 1, "%li", pdb_get_pass_last_set_time(sampass));
2448                 if (need_update(sampass, PDB_PASSLASTSET))
2449                         make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2450                                 get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_PWD_LAST_SET), 
2451                                 temp);
2452         }
2453
2454         /* FIXME: Hours stuff goes in LDAP  */
2455
2456         if (need_update(sampass, PDB_ACCTCTRL))
2457                 make_ldap_mod(ldap_state->ldap_struct, existing, mods,
2458                         get_userattr_key2string(ldap_state->schema_ver, LDAP_ATTR_ACB_INFO), 
2459                         pdb_encode_acct_ctrl (pdb_get_acct_ctrl(sampass), NEW_PW_FORMAT_SPACE_PADDED_LEN));
2460
2461         return True;
2462 }
2463
2464
2465
2466 /**********************************************************************
2467 Connect to LDAP server for password enumeration
2468 *********************************************************************/
2469 static NTSTATUS ldapsam_setsampwent(struct pdb_methods *my_methods, BOOL update)
2470 {
2471         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2472         int rc;
2473         pstring filter;
2474         char **attr_list;
2475
2476         snprintf( filter, sizeof(filter)-1, "(&%s%s)", lp_ldap_filter(), 
2477                 get_objclass_filter(ldap_state->schema_ver));
2478         all_string_sub(filter, "%u", "*", sizeof(pstring));
2479
2480         attr_list = get_userattr_list(ldap_state->schema_ver);
2481         rc = ldapsam_search_suffix(ldap_state, filter, attr_list, &ldap_state->result);
2482         free_attr_list( attr_list );
2483
2484         if (rc != LDAP_SUCCESS) {
2485                 DEBUG(0, ("LDAP search failed: %s\n", ldap_err2string(rc)));
2486                 DEBUG(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
2487                 ldap_msgfree(ldap_state->result);
2488                 ldap_state->result = NULL;
2489                 return NT_STATUS_UNSUCCESSFUL;
2490         }
2491
2492         DEBUG(2, ("ldapsam_setsampwent: %d entries in the base!\n",
2493                 ldap_count_entries(ldap_state->ldap_struct,
2494                 ldap_state->result)));
2495
2496         ldap_state->entry = ldap_first_entry(ldap_state->ldap_struct,
2497                                  ldap_state->result);
2498         ldap_state->index = 0;
2499
2500         return NT_STATUS_OK;
2501 }
2502
2503 /**********************************************************************
2504 End enumeration of the LDAP password list 
2505 *********************************************************************/
2506 static void ldapsam_endsampwent(struct pdb_methods *my_methods)
2507 {
2508         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2509         if (ldap_state->result) {
2510                 ldap_msgfree(ldap_state->result);
2511                 ldap_state->result = NULL;
2512         }
2513 }
2514
2515 /**********************************************************************
2516 Get the next entry in the LDAP password database 
2517 *********************************************************************/
2518 static NTSTATUS ldapsam_getsampwent(struct pdb_methods *my_methods, SAM_ACCOUNT *user)
2519 {
2520         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
2521         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2522         BOOL bret = False;
2523
2524         /* The rebind proc needs this *HACK*.  We are not multithreaded, so
2525            this will work, but it's not nice. */
2526         static_ldap_state = ldap_state;
2527
2528         while (!bret) {
2529                 if (!ldap_state->entry)
2530                         return ret;
2531                 
2532                 ldap_state->index++;
2533                 bret = init_sam_from_ldap(ldap_state, user, ldap_state->entry);
2534                 
2535                 ldap_state->entry = ldap_next_entry(ldap_state->ldap_struct,
2536                                             ldap_state->entry); 
2537         }
2538
2539         return NT_STATUS_OK;
2540 }
2541
2542 /**********************************************************************
2543 Get SAM_ACCOUNT entry from LDAP by username 
2544 *********************************************************************/
2545 static NTSTATUS ldapsam_getsampwnam(struct pdb_methods *my_methods, SAM_ACCOUNT *user, const char *sname)
2546 {
2547         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
2548         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2549         LDAPMessage *result;
2550         LDAPMessage *entry;
2551         int count;
2552         char ** attr_list;
2553         int rc;
2554         
2555         attr_list = get_userattr_list( ldap_state->schema_ver );
2556         rc = ldapsam_search_suffix_by_name(ldap_state, sname, &result, attr_list);
2557         free_attr_list( attr_list );
2558
2559         if ( rc != LDAP_SUCCESS ) 
2560                 return NT_STATUS_NO_SUCH_USER;
2561         
2562         count = ldap_count_entries(ldap_state->ldap_struct, result);
2563         
2564         if (count < 1) {
2565                 DEBUG(4,
2566                       ("Unable to locate user [%s] count=%d\n", sname,
2567                        count));
2568                 return NT_STATUS_NO_SUCH_USER;
2569         } else if (count > 1) {
2570                 DEBUG(1,
2571                       ("Duplicate entries for this user [%s] Failing. count=%d\n", sname,
2572                        count));
2573                 return NT_STATUS_NO_SUCH_USER;
2574         }
2575
2576         entry = ldap_first_entry(ldap_state->ldap_struct, result);
2577         if (entry) {
2578                 if (!init_sam_from_ldap(ldap_state, user, entry)) {
2579                         DEBUG(1,("ldapsam_getsampwnam: init_sam_from_ldap failed for user '%s'!\n", sname));
2580                         ldap_msgfree(result);
2581                         return NT_STATUS_NO_SUCH_USER;
2582                 }
2583                 ldap_msgfree(result);
2584                 ret = NT_STATUS_OK;
2585         } else {
2586                 ldap_msgfree(result);
2587         }
2588         return ret;
2589 }
2590
2591 /**********************************************************************
2592 Get SAM_ACCOUNT entry from LDAP by SID
2593 *********************************************************************/
2594 static NTSTATUS ldapsam_getsampwsid(struct pdb_methods *my_methods, SAM_ACCOUNT * user, const DOM_SID *sid)
2595 {
2596         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
2597         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2598         LDAPMessage *result;
2599         LDAPMessage *entry;
2600         fstring sid_string;
2601         int count;
2602         int rc;
2603         char ** attr_list;
2604         
2605         switch ( ldap_state->schema_ver )
2606         {
2607                 case SCHEMAVER_SAMBASAMACCOUNT:
2608                         attr_list = get_userattr_list(ldap_state->schema_ver);
2609                         rc = ldapsam_search_suffix_by_sid(ldap_state, sid, &result, attr_list);
2610                         free_attr_list( attr_list );
2611
2612                         if ( rc != LDAP_SUCCESS ) 
2613                                 return NT_STATUS_NO_SUCH_USER;
2614                         break;
2615                         
2616                 case SCHEMAVER_SAMBAACCOUNT:
2617                 {
2618                         uint32 rid;
2619                         if (!sid_peek_check_rid(get_global_sam_sid(), sid, &rid)) {
2620                                 return NT_STATUS_NO_SUCH_USER;
2621                         }
2622                 
2623                         attr_list = get_userattr_list(ldap_state->schema_ver);
2624                         rc = ldapsam_search_suffix_by_rid(ldap_state, rid, &result, attr_list );
2625                         free_attr_list( attr_list );
2626
2627                         if ( rc != LDAP_SUCCESS ) 
2628                                 return NT_STATUS_NO_SUCH_USER;
2629                 }
2630                 break;
2631         }
2632         
2633         count = ldap_count_entries(ldap_state->ldap_struct, result);
2634         
2635         if (count < 1) 
2636         {
2637                 DEBUG(4,
2638                       ("Unable to locate SID [%s] count=%d\n", sid_to_string(sid_string, sid),
2639                        count));
2640                 return NT_STATUS_NO_SUCH_USER;
2641         }  
2642         else if (count > 1) 
2643         {
2644                 DEBUG(1,
2645                       ("More than one user with SID [%s]. Failing. count=%d\n", sid_to_string(sid_string, sid),
2646                        count));
2647                 return NT_STATUS_NO_SUCH_USER;
2648         }
2649
2650         entry = ldap_first_entry(ldap_state->ldap_struct, result);
2651         if (entry) 
2652         {
2653                 if (!init_sam_from_ldap(ldap_state, user, entry)) {
2654                         DEBUG(1,("ldapsam_getsampwrid: init_sam_from_ldap failed!\n"));
2655                         ldap_msgfree(result);
2656                         return NT_STATUS_NO_SUCH_USER;
2657                 }
2658                 ldap_msgfree(result);
2659                 ret = NT_STATUS_OK;
2660         } else {
2661                 ldap_msgfree(result);
2662         }
2663         return ret;
2664 }       
2665
2666 /********************************************************************
2667 Do the actual modification - also change a plaittext passord if 
2668 it it set.
2669 **********************************************************************/
2670
2671 static NTSTATUS ldapsam_modify_entry(struct pdb_methods *my_methods, 
2672                                      SAM_ACCOUNT *newpwd, char *dn,
2673                                      LDAPMod **mods, int ldap_op, 
2674                                      BOOL (*need_update)(const SAM_ACCOUNT *,
2675                                                          enum pdb_elements))
2676 {
2677         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2678         int rc;
2679         
2680         if (!my_methods || !newpwd || !dn) {
2681                 return NT_STATUS_INVALID_PARAMETER;
2682         }
2683         
2684         if (!mods) {
2685                 DEBUG(5,("mods is empty: nothing to modify\n"));
2686                 /* may be password change below however */
2687         } else {
2688                 switch(ldap_op)
2689                 {
2690                         case LDAP_MOD_ADD: 
2691                                 make_a_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_ACCOUNT);
2692                                 rc = ldapsam_add(ldap_state, dn, mods);
2693                                 break;
2694                         case LDAP_MOD_REPLACE: 
2695                                 rc = ldapsam_modify(ldap_state, dn ,mods);
2696                                 break;
2697                         default:        
2698                                 DEBUG(0,("Wrong LDAP operation type: %d!\n", ldap_op));
2699                                 return NT_STATUS_INVALID_PARAMETER;
2700                 }
2701                 
2702                 if (rc!=LDAP_SUCCESS) {
2703                         char *ld_error = NULL;
2704                         ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
2705                                         &ld_error);
2706                         DEBUG(1,
2707                               ("failed to %s user dn= %s with: %s\n\t%s\n",
2708                                ldap_op == LDAP_MOD_ADD ? "add" : "modify",
2709                                dn, ldap_err2string(rc),
2710                                ld_error?ld_error:"unknown"));
2711                         SAFE_FREE(ld_error);
2712                         return NT_STATUS_UNSUCCESSFUL;
2713                 }  
2714         }
2715         
2716 #ifdef LDAP_EXOP_X_MODIFY_PASSWD
2717         if (!(pdb_get_acct_ctrl(newpwd)&(ACB_WSTRUST|ACB_SVRTRUST|ACB_DOMTRUST)) &&
2718                 (lp_ldap_passwd_sync() != LDAP_PASSWD_SYNC_OFF) &&
2719                 need_update(newpwd, PDB_PLAINTEXT_PW) &&
2720                 (pdb_get_plaintext_passwd(newpwd)!=NULL)) {
2721                 BerElement *ber;
2722                 struct berval *bv;
2723                 char *retoid;
2724                 struct berval *retdata;
2725                 char *utf8_password;
2726                 char *utf8_dn;
2727
2728                 if (push_utf8_allocate(&utf8_password, pdb_get_plaintext_passwd(newpwd)) == (size_t)-1) {
2729                         return NT_STATUS_NO_MEMORY;
2730                 }
2731
2732                 if (push_utf8_allocate(&utf8_dn, dn) == (size_t)-1) {
2733                         return NT_STATUS_NO_MEMORY;
2734                 }
2735
2736                 if ((ber = ber_alloc_t(LBER_USE_DER))==NULL) {
2737                         DEBUG(0,("ber_alloc_t returns NULL\n"));
2738                         SAFE_FREE(utf8_password);
2739                         return NT_STATUS_UNSUCCESSFUL;
2740                 }
2741
2742                 ber_printf (ber, "{");
2743                 ber_printf (ber, "ts", LDAP_TAG_EXOP_X_MODIFY_PASSWD_ID, utf8_dn);
2744                 ber_printf (ber, "ts", LDAP_TAG_EXOP_X_MODIFY_PASSWD_NEW, utf8_password);
2745                 ber_printf (ber, "N}");
2746
2747                 if ((rc = ber_flatten (ber, &bv))<0) {
2748                         DEBUG(0,("ber_flatten returns a value <0\n"));
2749                         ber_free(ber,1);
2750                         SAFE_FREE(utf8_dn);
2751                         SAFE_FREE(utf8_password);
2752                         return NT_STATUS_UNSUCCESSFUL;
2753                 }
2754                 
2755                 SAFE_FREE(utf8_dn);
2756                 SAFE_FREE(utf8_password);
2757                 ber_free(ber, 1);
2758
2759                 if ((rc = ldapsam_extended_operation(ldap_state, LDAP_EXOP_X_MODIFY_PASSWD,
2760                                                     bv, NULL, NULL, &retoid, &retdata))!=LDAP_SUCCESS) {
2761                         DEBUG(0,("LDAP Password could not be changed for user %s: %s\n",
2762                                 pdb_get_username(newpwd),ldap_err2string(rc)));
2763                 } else {
2764                         DEBUG(3,("LDAP Password changed for user %s\n",pdb_get_username(newpwd)));
2765 #ifdef DEBUG_PASSWORD
2766                         DEBUG(100,("LDAP Password changed to %s\n",pdb_get_plaintext_passwd(newpwd)));
2767 #endif    
2768                         ber_bvfree(retdata);
2769                         ber_memfree(retoid);
2770                 }
2771                 ber_bvfree(bv);
2772         }
2773 #else
2774         DEBUG(10,("LDAP PASSWORD SYNC is not supported!\n"));
2775 #endif /* LDAP_EXOP_X_MODIFY_PASSWD */
2776         return NT_STATUS_OK;
2777 }
2778
2779 /**********************************************************************
2780 Delete entry from LDAP for username 
2781 *********************************************************************/
2782 static NTSTATUS ldapsam_delete_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT * sam_acct)
2783 {
2784         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2785         const char *sname;
2786         int rc;
2787         LDAPMessage *result;
2788         NTSTATUS ret;
2789         char **attr_list;
2790         fstring objclass;
2791
2792         if (!sam_acct) {
2793                 DEBUG(0, ("sam_acct was NULL!\n"));
2794                 return NT_STATUS_INVALID_PARAMETER;
2795         }
2796
2797         sname = pdb_get_username(sam_acct);
2798
2799         DEBUG (3, ("Deleting user %s from LDAP.\n", sname));
2800
2801         attr_list= get_userattr_list( ldap_state->schema_ver );
2802         rc = ldapsam_search_suffix_by_name(ldap_state, sname, &result, attr_list);
2803
2804         if (rc != LDAP_SUCCESS)  {
2805                 free_attr_list( attr_list );
2806                 return NT_STATUS_NO_SUCH_USER;
2807         }
2808         
2809         switch ( ldap_state->schema_ver )
2810         {
2811                 case SCHEMAVER_SAMBASAMACCOUNT:
2812                         fstrcpy( objclass, LDAP_OBJ_SAMBASAMACCOUNT );
2813                         break;
2814                         
2815                 case SCHEMAVER_SAMBAACCOUNT:
2816                         fstrcpy( objclass, LDAP_OBJ_SAMBAACCOUNT );
2817                         break;
2818                 default:
2819                         fstrcpy( objclass, "UNKNOWN" );
2820                         DEBUG(0,("ldapsam_delete_sam_account: Unknown schema version specified!\n"));
2821                                 break;
2822         }
2823
2824         ret = ldapsam_delete_entry(ldap_state, result, objclass, attr_list );
2825         ldap_msgfree(result);
2826         free_attr_list( attr_list );
2827
2828         return ret;
2829 }
2830
2831 /**********************************************************************
2832   Helper function to determine for update_sam_account whether
2833   we need LDAP modification.
2834 *********************************************************************/
2835 static BOOL element_is_changed(const SAM_ACCOUNT *sampass,
2836                                enum pdb_elements element)
2837 {
2838         return IS_SAM_CHANGED(sampass, element);
2839 }
2840
2841 /**********************************************************************
2842 Update SAM_ACCOUNT 
2843 *********************************************************************/
2844 static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT * newpwd)
2845 {
2846         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
2847         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2848         int rc;
2849         char *dn;
2850         LDAPMessage *result;
2851         LDAPMessage *entry;
2852         LDAPMod **mods;
2853         char **attr_list;
2854
2855         attr_list = get_userattr_list(ldap_state->schema_ver);
2856         rc = ldapsam_search_suffix_by_name(ldap_state, pdb_get_username(newpwd), &result, attr_list );
2857         free_attr_list( attr_list );
2858         if (rc != LDAP_SUCCESS) 
2859                 return NT_STATUS_UNSUCCESSFUL;
2860
2861         if (ldap_count_entries(ldap_state->ldap_struct, result) == 0) {
2862                 DEBUG(0, ("No user to modify!\n"));
2863                 ldap_msgfree(result);
2864                 return NT_STATUS_UNSUCCESSFUL;
2865         }
2866
2867         entry = ldap_first_entry(ldap_state->ldap_struct, result);
2868         dn = ldap_get_dn(ldap_state->ldap_struct, entry);
2869
2870         if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd,
2871                                 element_is_changed)) {
2872                 DEBUG(0, ("ldapsam_update_sam_account: init_ldap_from_sam failed!\n"));
2873                 ldap_msgfree(result);
2874                 return NT_STATUS_UNSUCCESSFUL;
2875         }
2876         
2877         ldap_msgfree(result);
2878         
2879         if (mods == NULL) {
2880                 DEBUG(4,("mods is empty: nothing to update for user: %s\n",
2881                          pdb_get_username(newpwd)));
2882                 ldap_mods_free(mods, 1);
2883                 return NT_STATUS_OK;
2884         }
2885         
2886         ret = ldapsam_modify_entry(my_methods,newpwd,dn,mods,LDAP_MOD_REPLACE, element_is_changed);
2887         ldap_mods_free(mods,1);
2888
2889         if (!NT_STATUS_IS_OK(ret)) {
2890                 char *ld_error = NULL;
2891                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
2892                                 &ld_error);
2893                 DEBUG(0,("failed to modify user with uid = %s, error: %s (%s)\n",
2894                          pdb_get_username(newpwd), ld_error?ld_error:"(unknwon)", ldap_err2string(rc)));
2895                 SAFE_FREE(ld_error);
2896                 return ret;
2897         }
2898
2899         DEBUG(2, ("successfully modified uid = %s in the LDAP database\n",
2900                   pdb_get_username(newpwd)));
2901         return NT_STATUS_OK;
2902 }
2903
2904 /**********************************************************************
2905   Helper function to determine for update_sam_account whether
2906   we need LDAP modification.
2907  *********************************************************************/
2908 static BOOL element_is_set_or_changed(const SAM_ACCOUNT *sampass,
2909                                       enum pdb_elements element)
2910 {
2911         return (IS_SAM_SET(sampass, element) ||
2912                 IS_SAM_CHANGED(sampass, element));
2913 }
2914
2915 /**********************************************************************
2916 Add SAM_ACCOUNT to LDAP 
2917 *********************************************************************/
2918
2919 static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, SAM_ACCOUNT * newpwd)
2920 {
2921         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
2922         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
2923         int rc;
2924         LDAPMessage     *result = NULL;
2925         LDAPMessage     *entry  = NULL;
2926         pstring         dn;
2927         LDAPMod         **mods = NULL;
2928         int             ldap_op;
2929         uint32          num_result;
2930         char            **attr_list;
2931         char            *escape_user;
2932         const char      *username = pdb_get_username(newpwd);
2933         pstring         filter;
2934
2935         if (!username || !*username) {
2936                 DEBUG(0, ("Cannot add user without a username!\n"));
2937                 return NT_STATUS_INVALID_PARAMETER;
2938         }
2939
2940         /* free this list after the second search or in case we exit on failure */
2941         
2942         attr_list = get_userattr_list(ldap_state->schema_ver);
2943         rc = ldapsam_search_suffix_by_name (ldap_state, username, &result, attr_list);
2944
2945         if (rc != LDAP_SUCCESS) {
2946                 free_attr_list( attr_list );
2947                 return NT_STATUS_UNSUCCESSFUL;
2948         }
2949
2950         if (ldap_count_entries(ldap_state->ldap_struct, result) != 0) {
2951                 DEBUG(0,("User '%s' already in the base, with samba attributes\n", 
2952                          username));
2953                 ldap_msgfree(result);
2954                 free_attr_list( attr_list );
2955                 return NT_STATUS_UNSUCCESSFUL;
2956         }
2957         ldap_msgfree(result);
2958
2959         /* does the entry already exist but without a samba rttibutes?
2960            we don't really care what attributes are returned here */
2961            
2962         escape_user = escape_ldap_string_alloc( username );
2963         pstrcpy( filter, lp_ldap_filter() );
2964         all_string_sub( filter, "%u", escape_user, sizeof(filter) );
2965         SAFE_FREE( escape_user );
2966
2967         rc = ldapsam_search_suffix(ldap_state, filter, attr_list, &result);
2968         free_attr_list( attr_list );
2969
2970         if ( rc != LDAP_SUCCESS )
2971                 return NT_STATUS_UNSUCCESSFUL;
2972
2973         num_result = ldap_count_entries(ldap_state->ldap_struct, result);
2974         
2975         if (num_result > 1) {
2976                 DEBUG (0, ("More than one user with that uid exists: bailing out!\n"));
2977                 ldap_msgfree(result);
2978                 return NT_STATUS_UNSUCCESSFUL;
2979         }
2980         
2981         /* Check if we need to update an existing entry */
2982         if (num_result == 1) {
2983                 char *tmp;
2984                 
2985                 DEBUG(3,("User exists without samba attributes: adding them\n"));
2986                 ldap_op = LDAP_MOD_REPLACE;
2987                 entry = ldap_first_entry (ldap_state->ldap_struct, result);
2988                 tmp = ldap_get_dn (ldap_state->ldap_struct, entry);
2989                 slprintf (dn, sizeof (dn) - 1, "%s", tmp);
2990                 ldap_memfree (tmp);
2991         } else {
2992                 /* Check if we need to add an entry */
2993                 DEBUG(3,("Adding new user\n"));
2994                 ldap_op = LDAP_MOD_ADD;
2995                 if (username[strlen(username)-1] == '$') {
2996                         slprintf (dn, sizeof (dn) - 1, "uid=%s,%s", username, lp_ldap_machine_suffix ());
2997                 } else {
2998                         slprintf (dn, sizeof (dn) - 1, "uid=%s,%s", username, lp_ldap_user_suffix ());
2999                 }
3000         }
3001
3002         if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd,
3003                                 element_is_set_or_changed)) {
3004                 DEBUG(0, ("ldapsam_add_sam_account: init_ldap_from_sam failed!\n"));
3005                 ldap_msgfree(result);
3006                 return NT_STATUS_UNSUCCESSFUL;          
3007         }
3008         
3009         ldap_msgfree(result);
3010
3011         if (mods == NULL) {
3012                 DEBUG(0,("mods is empty: nothing to add for user: %s\n",pdb_get_username(newpwd)));
3013                 return NT_STATUS_UNSUCCESSFUL;
3014         }
3015         switch ( ldap_state->schema_ver )
3016         {
3017                 case SCHEMAVER_SAMBAACCOUNT:
3018                         make_a_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_SAMBAACCOUNT);
3019                         break;
3020                 case SCHEMAVER_SAMBASAMACCOUNT:
3021                         make_a_mod(&mods, LDAP_MOD_ADD, "objectclass", LDAP_OBJ_SAMBASAMACCOUNT);
3022                         break;
3023                 default:
3024                         DEBUG(0,("ldapsam_add_sam_account: invalid schema version specified\n"));
3025                         break;
3026         }
3027
3028         ret = ldapsam_modify_entry(my_methods,newpwd,dn,mods,ldap_op, element_is_set_or_changed);
3029         if (NT_STATUS_IS_ERR(ret)) {
3030                 DEBUG(0,("failed to modify/add user with uid = %s (dn = %s)\n",
3031                          pdb_get_username(newpwd),dn));
3032                 ldap_mods_free(mods,1);
3033                 return ret;
3034         }
3035
3036         DEBUG(2,("added: uid == %s in the LDAP database\n", pdb_get_username(newpwd)));
3037         ldap_mods_free(mods, 1);
3038         
3039         return NT_STATUS_OK;
3040 }
3041
3042 /**********************************************************************
3043  Housekeeping
3044  *********************************************************************/
3045
3046 static void free_private_data(void **vp) 
3047 {
3048         struct ldapsam_privates **ldap_state = (struct ldapsam_privates **)vp;
3049
3050         ldapsam_close(*ldap_state);
3051
3052         if ((*ldap_state)->bind_secret) {
3053                 memset((*ldap_state)->bind_secret, '\0', strlen((*ldap_state)->bind_secret));
3054         }
3055
3056         ldapsam_close(*ldap_state);
3057                 
3058         SAFE_FREE((*ldap_state)->bind_dn);
3059         SAFE_FREE((*ldap_state)->bind_secret);
3060
3061         *ldap_state = NULL;
3062
3063         /* No need to free any further, as it is talloc()ed */
3064 }
3065
3066 /**********************************************************************
3067  *********************************************************************/
3068
3069 static int ldapsam_search_one_group (struct ldapsam_privates *ldap_state,
3070                                      const char *filter,
3071                                      LDAPMessage ** result)
3072 {
3073         int scope = LDAP_SCOPE_SUBTREE;
3074         int rc;
3075         char **attr_list;
3076
3077         DEBUG(2, ("ldapsam_search_one_group: searching for:[%s]\n", filter));
3078
3079
3080         attr_list = get_attr_list(groupmap_attr_list);
3081         rc = ldapsam_search(ldap_state, lp_ldap_suffix (), scope,
3082                             filter, attr_list, 0, result);
3083         free_attr_list( attr_list );
3084
3085         if (rc != LDAP_SUCCESS) {
3086                 char *ld_error = NULL;
3087                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
3088                                 &ld_error);
3089                 DEBUG(0, ("ldapsam_search_one_group: "
3090                           "Problem during the LDAP search: LDAP error: %s (%s)",
3091                           ld_error?ld_error:"(unknown)", ldap_err2string(rc)));
3092                 DEBUG(3, ("ldapsam_search_one_group: Query was: %s, %s\n",
3093                           lp_ldap_suffix(), filter));
3094                 SAFE_FREE(ld_error);
3095         }
3096
3097         return rc;
3098 }
3099
3100 /**********************************************************************
3101  *********************************************************************/
3102
3103 static BOOL init_group_from_ldap(struct ldapsam_privates *ldap_state,
3104                                  GROUP_MAP *map, LDAPMessage *entry)
3105 {
3106         pstring temp;
3107
3108         if (ldap_state == NULL || map == NULL || entry == NULL ||
3109             ldap_state->ldap_struct == NULL) 
3110         {
3111                 DEBUG(0, ("init_group_from_ldap: NULL parameters found!\n"));
3112                 return False;
3113         }
3114
3115         if (!get_single_attribute(ldap_state->ldap_struct, entry, 
3116                 get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GIDNUMBER), temp)) 
3117         {
3118                 DEBUG(0, ("Mandatory attribute %s not found\n", 
3119                         get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GIDNUMBER)));
3120                 return False;
3121         }
3122         DEBUG(2, ("Entry found for group: %s\n", temp));
3123
3124         map->gid = (gid_t)atol(temp);
3125
3126         if (!get_single_attribute(ldap_state->ldap_struct, entry, 
3127                 get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GROUP_SID), temp)) 
3128         {
3129                 DEBUG(0, ("Mandatory attribute %s not found\n",
3130                         get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GROUP_SID)));
3131                 return False;
3132         }
3133         string_to_sid(&map->sid, temp);
3134
3135         if (!get_single_attribute(ldap_state->ldap_struct, entry, 
3136                 get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GROUP_TYPE), temp)) 
3137         {
3138                 DEBUG(0, ("Mandatory attribute %s not found\n",
3139                         get_attr_key2string( groupmap_attr_list, LDAP_ATTR_GROUP_TYPE)));
3140                 return False;
3141         }
3142         map->sid_name_use = (uint32)atol(temp);
3143
3144         if ((map->sid_name_use < SID_NAME_USER) ||
3145             (map->sid_name_use > SID_NAME_UNKNOWN)) {
3146                 DEBUG(0, ("Unknown Group type: %d\n", map->sid_name_use));
3147                 return False;
3148         }
3149
3150         if (!get_single_attribute(ldap_state->ldap_struct, entry, 
3151                 get_attr_key2string( groupmap_attr_list, LDAP_ATTR_DISPLAY_NAME), temp)) 
3152         {
3153                 temp[0] = '\0';
3154                 if (!get_single_attribute(ldap_state->ldap_struct, entry, 
3155                         get_attr_key2string( groupmap_attr_list, LDAP_ATTR_CN), temp)) 
3156                 {
3157                         DEBUG(0, ("Attributes cn not found either "
3158                                   "for gidNumber(%i)\n",map->gid));
3159                         return False;
3160                 }
3161         }
3162         fstrcpy(map->nt_name, temp);
3163
3164         if (!get_single_attribute(ldap_state->ldap_struct, entry, 
3165                 get_attr_key2string( groupmap_attr_list, LDAP_ATTR_DESC), temp)) 
3166         {
3167                 temp[0] = '\0';
3168         }
3169         fstrcpy(map->comment, temp);
3170
3171         map->systemaccount = 0;
3172         init_privilege(&map->priv_set);
3173
3174         return True;
3175 }
3176
3177 /**********************************************************************
3178  *********************************************************************/
3179
3180 static BOOL init_ldap_from_group(LDAP *ldap_struct,
3181                                  LDAPMessage *existing,
3182                                  LDAPMod ***mods,
3183                                  const GROUP_MAP *map)
3184 {
3185         pstring tmp;
3186
3187         if (mods == NULL || map == NULL) {
3188                 DEBUG(0, ("init_ldap_from_group: NULL parameters found!\n"));
3189                 return False;
3190         }
3191
3192         *mods = NULL;
3193
3194         sid_to_string(tmp, &map->sid);
3195         make_ldap_mod(ldap_struct, existing, mods, 
3196                 get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GROUP_SID), tmp);
3197         snprintf(tmp, sizeof(tmp)-1, "%i", map->sid_name_use);
3198         make_ldap_mod(ldap_struct, existing, mods, 
3199                 get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GROUP_TYPE), tmp);
3200
3201         make_ldap_mod(ldap_struct, existing, mods, 
3202                 get_attr_key2string( groupmap_attr_list, LDAP_ATTR_DISPLAY_NAME), map->nt_name);
3203         make_ldap_mod(ldap_struct, existing, mods, 
3204                 get_attr_key2string( groupmap_attr_list, LDAP_ATTR_DESC), map->comment);
3205
3206         return True;
3207 }
3208
3209 /**********************************************************************
3210  *********************************************************************/
3211
3212 static NTSTATUS ldapsam_getgroup(struct pdb_methods *methods,
3213                                  const char *filter,
3214                                  GROUP_MAP *map)
3215 {
3216         struct ldapsam_privates *ldap_state =
3217                 (struct ldapsam_privates *)methods->private_data;
3218         LDAPMessage *result;
3219         LDAPMessage *entry;
3220         int count;
3221
3222         if (ldapsam_search_one_group(ldap_state, filter, &result)
3223             != LDAP_SUCCESS) {
3224                 return NT_STATUS_NO_SUCH_GROUP;
3225         }
3226
3227         count = ldap_count_entries(ldap_state->ldap_struct, result);
3228
3229         if (count < 1) {
3230                 DEBUG(4, ("Did not find group for filter %s\n", filter));
3231                 return NT_STATUS_NO_SUCH_GROUP;
3232         }
3233
3234         if (count > 1) {
3235                 DEBUG(1, ("Duplicate entries for filter %s: count=%d\n",
3236                           filter, count));
3237                 return NT_STATUS_NO_SUCH_GROUP;
3238         }
3239
3240         entry = ldap_first_entry(ldap_state->ldap_struct, result);
3241
3242         if (!entry) {
3243                 ldap_msgfree(result);
3244                 return NT_STATUS_UNSUCCESSFUL;
3245         }
3246
3247         if (!init_group_from_ldap(ldap_state, map, entry)) {
3248                 DEBUG(1, ("init_group_from_ldap failed for group filter %s\n",
3249                           filter));
3250                 ldap_msgfree(result);
3251                 return NT_STATUS_NO_SUCH_GROUP;
3252         }
3253
3254         ldap_msgfree(result);
3255         return NT_STATUS_OK;
3256 }
3257
3258 /**********************************************************************
3259  *********************************************************************/
3260
3261 static NTSTATUS ldapsam_getgrsid(struct pdb_methods *methods, GROUP_MAP *map,
3262                                  DOM_SID sid, BOOL with_priv)
3263 {
3264         pstring filter;
3265
3266         snprintf(filter, sizeof(filter)-1, "(&(objectClass=%s)(%s=%s))",
3267                 LDAP_OBJ_GROUPMAP, 
3268                 get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GROUP_SID),
3269                 sid_string_static(&sid));
3270
3271         return ldapsam_getgroup(methods, filter, map);
3272 }
3273
3274 /**********************************************************************
3275  *********************************************************************/
3276
3277 static NTSTATUS ldapsam_getgrgid(struct pdb_methods *methods, GROUP_MAP *map,
3278                                  gid_t gid, BOOL with_priv)
3279 {
3280         pstring filter;
3281
3282         snprintf(filter, sizeof(filter)-1, "(&(objectClass=%s)(%s=%d))",
3283                 LDAP_OBJ_GROUPMAP,
3284                 get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GIDNUMBER),
3285                 gid);
3286
3287         return ldapsam_getgroup(methods, filter, map);
3288 }
3289
3290 /**********************************************************************
3291  *********************************************************************/
3292
3293 static NTSTATUS ldapsam_getgrnam(struct pdb_methods *methods, GROUP_MAP *map,
3294                                  char *name, BOOL with_priv)
3295 {
3296         pstring filter;
3297
3298         /* TODO: Escaping of name? */
3299
3300         snprintf(filter, sizeof(filter)-1, "(&(objectClass=%s)(|(%s=%s)(%s=%s)))",
3301                 LDAP_OBJ_GROUPMAP,
3302                 get_attr_key2string(groupmap_attr_list, LDAP_ATTR_DISPLAY_NAME), name,
3303                 get_attr_key2string(groupmap_attr_list, LDAP_ATTR_CN), name);
3304
3305         return ldapsam_getgroup(methods, filter, map);
3306 }
3307
3308 /**********************************************************************
3309  *********************************************************************/
3310
3311 static int ldapsam_search_one_group_by_gid(struct ldapsam_privates *ldap_state,
3312                                            gid_t gid,
3313                                            LDAPMessage **result)
3314 {
3315         pstring filter;
3316
3317         snprintf(filter, sizeof(filter)-1, "(&(objectClass=%s)(%s=%i))", 
3318                 LDAP_OBJ_POSIXGROUP,
3319                 get_attr_key2string(groupmap_attr_list, LDAP_ATTR_GIDNUMBER),
3320                 gid);
3321
3322         return ldapsam_search_one_group(ldap_state, filter, result);
3323 }
3324
3325 /**********************************************************************
3326  *********************************************************************/
3327
3328 static NTSTATUS ldapsam_add_group_mapping_entry(struct pdb_methods *methods,
3329                                                 GROUP_MAP *map)
3330 {
3331         struct ldapsam_privates *ldap_state =
3332                 (struct ldapsam_privates *)methods->private_data;
3333         LDAPMessage *result = NULL;
3334         LDAPMod **mods = NULL;
3335
3336         char *tmp;
3337         pstring dn;
3338         LDAPMessage *entry;
3339
3340         GROUP_MAP dummy;
3341
3342         int rc;
3343
3344         if (NT_STATUS_IS_OK(ldapsam_getgrgid(methods, &dummy,
3345                                              map->gid, False))) {
3346                 DEBUG(0, ("Group %i already exists in LDAP\n", map->gid));
3347                 return NT_STATUS_UNSUCCESSFUL;
3348         }
3349
3350         rc = ldapsam_search_one_group_by_gid(ldap_state, map->gid, &result);
3351         if (rc != LDAP_SUCCESS) {
3352                 return NT_STATUS_UNSUCCESSFUL;
3353         }
3354
3355         if (ldap_count_entries(ldap_state->ldap_struct, result) != 1) {
3356                 DEBUG(2, ("Group %i must exist exactly once in LDAP\n",
3357                           map->gid));
3358                 ldap_msgfree(result);
3359                 return NT_STATUS_UNSUCCESSFUL;
3360         }
3361
3362         entry = ldap_first_entry(ldap_state->ldap_struct, result);
3363         tmp = ldap_get_dn(ldap_state->ldap_struct, entry);
3364         pstrcpy(dn, tmp);
3365         ldap_memfree(tmp);
3366
3367         if (!init_ldap_from_group(ldap_state->ldap_struct,
3368                                   result, &mods, map)) {
3369                 DEBUG(0, ("init_ldap_from_group failed!\n"));
3370                 ldap_mods_free(mods, 1);
3371                 ldap_msgfree(result);
3372                 return NT_STATUS_UNSUCCESSFUL;
3373         }
3374
3375         ldap_msgfree(result);
3376
3377         if (mods == NULL) {
3378                 DEBUG(0, ("mods is empty\n"));
3379                 return NT_STATUS_UNSUCCESSFUL;
3380         }
3381
3382         make_a_mod(&mods, LDAP_MOD_ADD, "objectClass",
3383                    "sambaGroupMapping");
3384
3385         rc = ldapsam_modify(ldap_state, dn, mods);
3386         ldap_mods_free(mods, 1);
3387
3388         if (rc != LDAP_SUCCESS) {
3389                 char *ld_error = NULL;
3390                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
3391                                 &ld_error);
3392                 DEBUG(0, ("failed to add group %i error: %s (%s)\n", map->gid, 
3393                           ld_error ? ld_error : "(unknown)", ldap_err2string(rc)));
3394                 SAFE_FREE(ld_error);
3395                 return NT_STATUS_UNSUCCESSFUL;
3396         }
3397
3398         DEBUG(2, ("successfully modified group %i in LDAP\n", map->gid));
3399         return NT_STATUS_OK;
3400 }
3401
3402 /**********************************************************************
3403  *********************************************************************/
3404
3405 static NTSTATUS ldapsam_update_group_mapping_entry(struct pdb_methods *methods,
3406                                                    GROUP_MAP *map)
3407 {
3408         struct ldapsam_privates *ldap_state =
3409                 (struct ldapsam_privates *)methods->private_data;
3410         int rc;
3411         char *dn;
3412         LDAPMessage *result;
3413         LDAPMessage *entry;
3414         LDAPMod **mods;
3415
3416         rc = ldapsam_search_one_group_by_gid(ldap_state, map->gid, &result);
3417
3418         if (rc != LDAP_SUCCESS) {
3419                 return NT_STATUS_UNSUCCESSFUL;
3420         }
3421
3422         if (ldap_count_entries(ldap_state->ldap_struct, result) == 0) {
3423                 DEBUG(0, ("No group to modify!\n"));
3424                 ldap_msgfree(result);
3425                 return NT_STATUS_UNSUCCESSFUL;
3426         }
3427
3428         entry = ldap_first_entry(ldap_state->ldap_struct, result);
3429         dn = ldap_get_dn(ldap_state->ldap_struct, entry);
3430
3431         if (!init_ldap_from_group(ldap_state->ldap_struct,
3432                                   result, &mods, map)) {
3433                 DEBUG(0, ("init_ldap_from_group failed\n"));
3434                 ldap_msgfree(result);
3435                 return NT_STATUS_UNSUCCESSFUL;
3436         }
3437
3438         ldap_msgfree(result);
3439
3440         if (mods == NULL) {
3441                 DEBUG(4, ("mods is empty: nothing to do\n"));
3442                 return NT_STATUS_UNSUCCESSFUL;
3443         }
3444
3445         rc = ldapsam_modify(ldap_state, dn, mods);
3446
3447         ldap_mods_free(mods, 1);
3448
3449         if (rc != LDAP_SUCCESS) {
3450                 char *ld_error = NULL;
3451                 ldap_get_option(ldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
3452                                 &ld_error);
3453                 DEBUG(0, ("failed to modify group %i error: %s (%s)\n", map->gid, 
3454                           ld_error ? ld_error : "(unknown)", ldap_err2string(rc)));
3455                 SAFE_FREE(ld_error);
3456         }
3457
3458         DEBUG(2, ("successfully modified group %i in LDAP\n", map->gid));
3459         return NT_STATUS_OK;
3460 }
3461
3462 /**********************************************************************
3463  *********************************************************************/
3464
3465 static NTSTATUS ldapsam_delete_group_mapping_entry(struct pdb_methods *methods,
3466                                                    DOM_SID sid)
3467 {
3468         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)methods->private_data;
3469         pstring sidstring, filter;
3470         LDAPMessage *result;
3471         int rc;
3472         NTSTATUS ret;
3473         char **attr_list;
3474
3475         sid_to_string(sidstring, &sid);
3476         
3477         snprintf(filter, sizeof(filter)-1, "(&(objectClass=%s)(%s=%s))", 
3478                 LDAP_OBJ_GROUPMAP, LDAP_ATTRIBUTE_SID, sidstring);
3479
3480         rc = ldapsam_search_one_group(ldap_state, filter, &result);
3481
3482         if (rc != LDAP_SUCCESS) {
3483                 return NT_STATUS_NO_SUCH_GROUP;
3484         }
3485
3486         attr_list = get_attr_list( groupmap_attr_list_to_delete );
3487         ret = ldapsam_delete_entry(ldap_state, result, LDAP_OBJ_GROUPMAP, attr_list);
3488         free_attr_list ( attr_list );
3489
3490         ldap_msgfree(result);
3491
3492         return ret;
3493 }
3494
3495 /**********************************************************************
3496  *********************************************************************/
3497
3498 static NTSTATUS ldapsam_setsamgrent(struct pdb_methods *my_methods, BOOL update)
3499 {
3500         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
3501         fstring filter;
3502         int rc;
3503         char **attr_list;
3504
3505         snprintf( filter, sizeof(filter)-1, "(objectclass=%s)", LDAP_OBJ_GROUPMAP);
3506         attr_list = get_attr_list( groupmap_attr_list );
3507         rc = ldapsam_search(ldap_state, lp_ldap_suffix(),
3508                             LDAP_SCOPE_SUBTREE, filter,
3509                             attr_list, 0, &ldap_state->result);
3510         free_attr_list( attr_list );
3511
3512         if (rc != LDAP_SUCCESS) {
3513                 DEBUG(0, ("LDAP search failed: %s\n", ldap_err2string(rc)));
3514                 DEBUG(3, ("Query was: %s, %s\n", lp_ldap_suffix(), filter));
3515                 ldap_msgfree(ldap_state->result);
3516                 ldap_state->result = NULL;
3517                 return NT_STATUS_UNSUCCESSFUL;
3518         }
3519
3520         DEBUG(2, ("ldapsam_setsampwent: %d entries in the base!\n",
3521                   ldap_count_entries(ldap_state->ldap_struct,
3522                                      ldap_state->result)));
3523
3524         ldap_state->entry = ldap_first_entry(ldap_state->ldap_struct, ldap_state->result);
3525         ldap_state->index = 0;
3526
3527         return NT_STATUS_OK;
3528 }
3529
3530 /**********************************************************************
3531  *********************************************************************/
3532
3533 static void ldapsam_endsamgrent(struct pdb_methods *my_methods)
3534 {
3535         ldapsam_endsampwent(my_methods);
3536 }
3537
3538 /**********************************************************************
3539  *********************************************************************/
3540
3541 static NTSTATUS ldapsam_getsamgrent(struct pdb_methods *my_methods,
3542                                     GROUP_MAP *map)
3543 {
3544         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
3545         struct ldapsam_privates *ldap_state = (struct ldapsam_privates *)my_methods->private_data;
3546         BOOL bret = False;
3547
3548         /* The rebind proc needs this *HACK*.  We are not multithreaded, so
3549            this will work, but it's not nice. */
3550         static_ldap_state = ldap_state;
3551
3552         while (!bret) {
3553                 if (!ldap_state->entry)
3554                         return ret;
3555                 
3556                 ldap_state->index++;
3557                 bret = init_group_from_ldap(ldap_state, map, ldap_state->entry);
3558                 
3559                 ldap_state->entry = ldap_next_entry(ldap_state->ldap_struct,
3560                                             ldap_state->entry); 
3561         }
3562
3563         return NT_STATUS_OK;
3564 }
3565
3566 /**********************************************************************
3567  *********************************************************************/
3568
3569 static NTSTATUS ldapsam_enum_group_mapping(struct pdb_methods *methods,
3570                                            enum SID_NAME_USE sid_name_use,
3571                                            GROUP_MAP **rmap, int *num_entries,
3572                                            BOOL unix_only, BOOL with_priv)
3573 {
3574         GROUP_MAP map;
3575         GROUP_MAP *mapt;
3576         int entries = 0;
3577         NTSTATUS nt_status;
3578
3579         *num_entries = 0;
3580         *rmap = NULL;
3581
3582         if (!NT_STATUS_IS_OK(ldapsam_setsamgrent(methods, False))) {
3583                 DEBUG(0, ("Unable to open passdb\n"));
3584                 return NT_STATUS_ACCESS_DENIED;
3585         }
3586
3587         while (NT_STATUS_IS_OK(nt_status = ldapsam_getsamgrent(methods, &map))) {
3588                 if (sid_name_use != SID_NAME_UNKNOWN &&
3589                     sid_name_use != map.sid_name_use) {
3590                         DEBUG(11,("enum_group_mapping: group %s is not of the requested type\n", map.nt_name));
3591                         continue;
3592                 }
3593                 if (unix_only==ENUM_ONLY_MAPPED && map.gid==-1) {
3594                         DEBUG(11,("enum_group_mapping: group %s is non mapped\n", map.nt_name));
3595                         continue;
3596                 }
3597
3598                 mapt=(GROUP_MAP *)Realloc((*rmap), (entries+1)*sizeof(GROUP_MAP));
3599                 if (!mapt) {
3600                         DEBUG(0,("enum_group_mapping: Unable to enlarge group map!\n"));
3601                         SAFE_FREE(*rmap);
3602                         return NT_STATUS_UNSUCCESSFUL;
3603                 }
3604                 else
3605                         (*rmap) = mapt;
3606
3607                 mapt[entries] = map;
3608
3609                 entries += 1;
3610
3611         }
3612         ldapsam_endsamgrent(methods);
3613
3614         *num_entries = entries;
3615
3616         return NT_STATUS_OK;
3617 }
3618
3619 /**********************************************************************
3620  *********************************************************************/
3621
3622 static NTSTATUS pdb_init_ldapsam_common(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, 
3623                                         const char *location)
3624 {
3625         NTSTATUS nt_status;
3626         struct ldapsam_privates *ldap_state;
3627
3628         if (!NT_STATUS_IS_OK(nt_status = make_pdb_methods(pdb_context->mem_ctx, pdb_method))) {
3629                 return nt_status;
3630         }
3631
3632         (*pdb_method)->name = "ldapsam";
3633
3634         (*pdb_method)->setsampwent = ldapsam_setsampwent;
3635         (*pdb_method)->endsampwent = ldapsam_endsampwent;
3636         (*pdb_method)->getsampwent = ldapsam_getsampwent;
3637         (*pdb_method)->getsampwnam = ldapsam_getsampwnam;
3638         (*pdb_method)->getsampwsid = ldapsam_getsampwsid;
3639         (*pdb_method)->add_sam_account = ldapsam_add_sam_account;
3640         (*pdb_method)->update_sam_account = ldapsam_update_sam_account;
3641         (*pdb_method)->delete_sam_account = ldapsam_delete_sam_account;
3642
3643         (*pdb_method)->getgrsid = ldapsam_getgrsid;
3644         (*pdb_method)->getgrgid = ldapsam_getgrgid;
3645         (*pdb_method)->getgrnam = ldapsam_getgrnam;
3646         (*pdb_method)->add_group_mapping_entry = ldapsam_add_group_mapping_entry;
3647         (*pdb_method)->update_group_mapping_entry = ldapsam_update_group_mapping_entry;
3648         (*pdb_method)->delete_group_mapping_entry = ldapsam_delete_group_mapping_entry;
3649         (*pdb_method)->enum_group_mapping = ldapsam_enum_group_mapping;
3650
3651         /* TODO: Setup private data and free */
3652
3653         ldap_state = talloc_zero(pdb_context->mem_ctx, sizeof(struct ldapsam_privates));
3654
3655         if (!ldap_state) {
3656                 DEBUG(0, ("talloc() failed for ldapsam private_data!\n"));
3657                 return NT_STATUS_NO_MEMORY;
3658         }
3659
3660         if (location) {
3661                 ldap_state->uri = talloc_strdup(pdb_context->mem_ctx, location);
3662         } else {
3663                 ldap_state->uri = "ldap://localhost";
3664         }
3665
3666         ldap_state->domain_name = talloc_strdup(pdb_context->mem_ctx, get_global_sam_name());
3667         if (!ldap_state->domain_name) {
3668                 return NT_STATUS_NO_MEMORY;
3669         }
3670
3671         sid_copy(&ldap_state->domain_sid, get_global_sam_sid());
3672
3673         (*pdb_method)->private_data = ldap_state;
3674
3675         (*pdb_method)->free_private_data = free_private_data;
3676
3677         return NT_STATUS_OK;
3678 }
3679
3680 /**********************************************************************
3681  *********************************************************************/
3682
3683 static NTSTATUS pdb_init_ldapsam_compat(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
3684 {
3685         NTSTATUS nt_status;
3686         struct ldapsam_privates *ldap_state;
3687
3688         if (!NT_STATUS_IS_OK(nt_status = pdb_init_ldapsam_common(pdb_context, pdb_method, location))) {
3689                 return nt_status;
3690         }
3691
3692         (*pdb_method)->name = "ldapsam_compat";
3693
3694         ldap_state = (*pdb_method)->private_data;
3695         ldap_state->schema_ver = SCHEMAVER_SAMBAACCOUNT;
3696
3697         if (location) {
3698                 ldap_state->uri = talloc_strdup(pdb_context->mem_ctx, location);
3699         } else {
3700 #ifndef WITH_LDAP_SAMCONFIG
3701                 ldap_state->uri = "ldap://localhost";
3702 #else
3703                 int ldap_port = lp_ldap_port();
3704                         
3705                 /* remap default port if not using SSL (ie clear or TLS) */
3706                 if ( (lp_ldap_ssl() != LDAP_SSL_ON) && (ldap_port == 636) ) {
3707                         ldap_port = 389;
3708                 }
3709
3710                 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);
3711                 if (!ldap_state->uri) {
3712                         return NT_STATUS_NO_MEMORY;
3713                 }
3714 #endif
3715         }
3716
3717         return NT_STATUS_OK;
3718 }
3719
3720 /**********************************************************************
3721  *********************************************************************/
3722
3723 static NTSTATUS pdb_init_ldapsam(PDB_CONTEXT *pdb_context, PDB_METHODS **pdb_method, const char *location)
3724 {
3725         NTSTATUS nt_status;
3726         struct ldapsam_privates *ldap_state;
3727         uint32 low_idmap_uid, high_idmap_uid;
3728         uint32 low_idmap_gid, high_idmap_gid;
3729
3730         if (!NT_STATUS_IS_OK(nt_status = pdb_init_ldapsam_common(pdb_context, pdb_method, location))) {
3731                 return nt_status;
3732         }
3733
3734         (*pdb_method)->name = "ldapsam";
3735
3736         ldap_state = (*pdb_method)->private_data;
3737         ldap_state->schema_ver = SCHEMAVER_SAMBASAMACCOUNT;     
3738         ldap_state->permit_non_unix_accounts = False;
3739
3740         /* check for non-unix account ranges */
3741
3742         if (lp_idmap_uid(&low_idmap_uid, &high_idmap_uid) 
3743                 &&  lp_idmap_gid(&low_idmap_gid, &high_idmap_gid)) 
3744         {
3745                 DEBUG(2, ("Enabling non-unix account ranges\n"));
3746
3747                 ldap_state->permit_non_unix_accounts = True;
3748
3749                 ldap_state->low_allocated_user_rid   = fallback_pdb_uid_to_user_rid(low_idmap_uid);
3750                 ldap_state->high_allocated_user_rid  = fallback_pdb_uid_to_user_rid(high_idmap_uid);
3751                 ldap_state->low_allocated_group_rid  = pdb_gid_to_group_rid(low_idmap_gid);
3752                 ldap_state->high_allocated_group_rid = pdb_gid_to_group_rid(high_idmap_gid);
3753         }
3754
3755         return NT_STATUS_OK;
3756 }
3757
3758 NTSTATUS pdb_ldap_init(void)
3759 {
3760         NTSTATUS nt_status;
3761         if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "ldapsam", pdb_init_ldapsam)))
3762                 return nt_status;
3763
3764         if (!NT_STATUS_IS_OK(nt_status = smb_register_passdb(PASSDB_INTERFACE_VERSION, "ldapsam_compat", pdb_init_ldapsam_compat)))
3765                 return nt_status;
3766
3767         return NT_STATUS_OK;
3768 }
3769
3770