import HEAD into svn+ssh://svn.samba.org/home/svn/samba/trunk
[metze/old/v3-2-winbind-ndr.git] / source / sam / idmap_ldap.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    idmap LDAP backend
5
6    Copyright (C) Tim Potter             2000
7    Copyright (C) Jim McDonough <jmcd@us.ibm.com>        2003
8    Copyright (C) Simo Sorce             2003
9    Copyright (C) Gerald Carter          2003
10
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 2 of the License, or
14    (at your option) any later version.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */
25
26 #include "includes.h"
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_IDMAP
30
31
32 #include <lber.h>
33 #include <ldap.h>
34
35 #include "smbldap.h"
36
37 struct ldap_idmap_state {
38         struct smbldap_state *smbldap_state;
39         TALLOC_CTX *mem_ctx;
40 };
41
42 static struct ldap_idmap_state ldap_state;
43
44 /* number tries while allocating new id */
45 #define LDAP_MAX_ALLOC_ID 128
46
47
48 /***********************************************************************
49  This function cannot be called to modify a mapping, only set a new one
50 ***********************************************************************/
51
52 static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type)
53 {
54         pstring dn;
55         pstring id_str;
56         fstring type;
57         LDAPMod **mods = NULL;
58         int rc = -1;
59         int ldap_op;
60         fstring sid_string;
61         LDAPMessage *entry = NULL;
62
63         sid_to_string( sid_string, sid );
64
65         ldap_op = LDAP_MOD_ADD;
66         pstr_sprintf(dn, "%s=%s,%s", get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID),
67                  sid_string, lp_ldap_idmap_suffix());
68
69         if ( id_type & ID_USERID )
70                 fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER ) );
71         else
72                 fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER ) );
73
74         pstr_sprintf(id_str, "%lu", ((id_type & ID_USERID) ? (unsigned long)id.uid :
75                                                  (unsigned long)id.gid));       
76         
77         smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDMAP_ENTRY );
78
79         smbldap_make_mod( ldap_state.smbldap_state->ldap_struct, 
80                           entry, &mods, type, id_str );
81
82         smbldap_make_mod( ldap_state.smbldap_state->ldap_struct,
83                           entry, &mods,  
84                           get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID), 
85                           sid_string );
86
87         /* There may well be nothing at all to do */
88
89         if (mods) {
90                 smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SID_ENTRY );
91                 rc = smbldap_add(ldap_state.smbldap_state, dn, mods);
92                 ldap_mods_free( mods, True );   
93         } else {
94                 rc = LDAP_SUCCESS;
95         }
96
97         if (rc != LDAP_SUCCESS) {
98                 char *ld_error = NULL;
99                 ldap_get_option(ldap_state.smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
100                                 &ld_error);
101                 DEBUG(0,("ldap_set_mapping_internals: Failed to %s mapping from %s to %lu [%s]\n",
102                          (ldap_op == LDAP_MOD_ADD) ? "add" : "replace",
103                          sid_string, (unsigned long)((id_type & ID_USERID) ? id.uid : id.gid), type));
104                 DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n", 
105                         ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
106                 return NT_STATUS_UNSUCCESSFUL;
107         }
108                 
109         DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to %lu [%s]\n",
110                 sid_string, ((id_type & ID_USERID) ? (unsigned long)id.uid : 
111                              (unsigned long)id.gid), type));
112
113         return NT_STATUS_OK;
114 }
115
116 /**********************************************************************
117  Even if the sambaDomain attribute in LDAP tells us that this RID is 
118  safe to use, always check before use.  
119 *********************************************************************/
120
121 static BOOL sid_in_use(struct ldap_idmap_state *state, 
122                        const DOM_SID *sid, int *error) 
123 {
124         fstring filter;
125         fstring sid_string;
126         LDAPMessage *result = NULL;
127         int count;
128         int rc;
129         char *sid_attr[] = {LDAP_ATTRIBUTE_SID, NULL};
130
131         slprintf(filter, sizeof(filter)-1, "(%s=%s)", LDAP_ATTRIBUTE_SID, sid_to_string(sid_string, sid));
132
133         rc = smbldap_search_suffix(state->smbldap_state, 
134                                    filter, sid_attr, &result);
135
136         if (rc != LDAP_SUCCESS) {
137                 char *ld_error = NULL;
138                 ldap_get_option(state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
139                 DEBUG(2, ("Failed to check if sid %s is alredy in use: %s\n",
140                           sid_string, ld_error));
141                 SAFE_FREE(ld_error);
142
143                 *error = rc;
144                 return True;
145         }
146         
147         if ((count = ldap_count_entries(state->smbldap_state->ldap_struct, result)) > 0) {
148                 DEBUG(3, ("Sid %s already in use - trying next RID\n",
149                           sid_string));
150                 ldap_msgfree(result);
151                 return True;
152         }
153
154         ldap_msgfree(result);
155
156         /* good, sid is not in use */
157         return False;
158 }
159
160 /**********************************************************************
161  Set the new nextRid attribute, and return one we can use.
162
163  This also checks that this RID is actually free - in case the admin
164  manually stole it :-).
165 *********************************************************************/
166
167 static NTSTATUS ldap_next_rid(struct ldap_idmap_state *state, uint32 *rid, 
168                               int rid_type)
169 {
170         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
171         int rc;
172         LDAPMessage *domain_result = NULL;
173         LDAPMessage *entry  = NULL;
174         char *dn;
175         LDAPMod **mods = NULL;
176         fstring old_rid_string;
177         fstring next_rid_string;
178         fstring algorithmic_rid_base_string;
179         uint32 next_rid;
180         uint32 alg_rid_base;
181         int attempts = 0;
182         char *ld_error = NULL;
183
184         while (attempts < 10) {
185                 if (!NT_STATUS_IS_OK(ret = smbldap_search_domain_info(state->smbldap_state, 
186                                 &domain_result, get_global_sam_name(), True))) {
187                         return ret;
188                 }
189         
190                 entry = ldap_first_entry(state->smbldap_state->ldap_struct, domain_result);
191                 if (!entry) {
192                         DEBUG(0, ("Could not get domain info entry\n"));
193                         ldap_msgfree(domain_result);
194                         return ret;
195                 }
196
197                 if ((dn = smbldap_get_dn(state->smbldap_state->ldap_struct, entry)) == NULL) {
198                         DEBUG(0, ("Could not get domain info DN\n"));
199                         ldap_msgfree(domain_result);
200                         return ret;
201                 }
202
203                 /* yes, we keep 3 seperate counters, one for rids between 1000 (BASE_RID) and 
204                    algorithmic_rid_base.  The other two are to avoid stomping on the
205                    different sets of algorithmic RIDs */
206                 
207                 if (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry,
208                                          get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE),
209                                          algorithmic_rid_base_string)) {
210                         
211                         alg_rid_base = (uint32)atol(algorithmic_rid_base_string);
212                 } else {
213                         alg_rid_base = algorithmic_rid_base();
214                         /* Try to make the modification atomically by enforcing the
215                            old value in the delete mod. */
216                         slprintf(algorithmic_rid_base_string, sizeof(algorithmic_rid_base_string)-1, "%d", alg_rid_base);
217                         smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods, 
218                                          get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE), 
219                                          algorithmic_rid_base_string);
220                 }
221
222                 next_rid = 0;
223
224                 if (alg_rid_base > BASE_RID) {
225                         /* we have a non-default 'algorithmic rid base', so we have 'low' rids that we 
226                            can allocate to new users */
227                         if (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry,
228                                                  get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID),
229                                                  old_rid_string)) {
230                                 *rid = (uint32)atol(old_rid_string);
231                         } else {
232                                 *rid = BASE_RID;
233                         }
234
235                         next_rid = *rid+1;
236                         if (next_rid >= alg_rid_base) {
237                                 ldap_msgfree(domain_result);
238                                 return NT_STATUS_UNSUCCESSFUL;
239                         }
240                         
241                         slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
242                                 
243                         /* Try to make the modification atomically by enforcing the
244                            old value in the delete mod. */
245                         smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods, 
246                                          get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID), 
247                                          next_rid_string);
248                 }
249
250                 if (!next_rid) { /* not got one already */
251                         switch (rid_type) {
252                         case USER_RID_TYPE:
253                                 if (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry,
254                                                          get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID),
255                                                          old_rid_string)) {
256                                         *rid = (uint32)atol(old_rid_string);                                    
257                                 }
258                                 break;
259                         case GROUP_RID_TYPE:
260                                 if (smbldap_get_single_pstring(state->smbldap_state->ldap_struct, entry, 
261                                                          get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
262                                                          old_rid_string)) {
263                                         *rid = (uint32)atol(old_rid_string);
264                                 }
265                                 break;
266                         }
267                         
268                         /* This is the core of the whole routine. If we had
269                            scheme-style closures, there would be a *lot* less code
270                            duplication... */
271
272                         next_rid = *rid+RID_MULTIPLIER;
273                         slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
274                         
275                         switch (rid_type) {
276                         case USER_RID_TYPE:
277                                 /* Try to make the modification atomically by enforcing the
278                                    old value in the delete mod. */
279                                 smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods, 
280                                                  get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID), 
281                                                  next_rid_string);
282                                 break;
283                                 
284                         case GROUP_RID_TYPE:
285                                 /* Try to make the modification atomically by enforcing the
286                                    old value in the delete mod. */
287                                 smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
288                                                  get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
289                                                  next_rid_string);
290                                 break;
291                         }
292                 }
293
294                 if ((rc = smbldap_modify(state->smbldap_state, dn, mods)) == LDAP_SUCCESS) {
295                         DOM_SID dom_sid;
296                         DOM_SID sid;
297                         pstring domain_sid_string;
298                         int error = 0;
299
300                         if (!smbldap_get_single_pstring(state->smbldap_state->ldap_struct, domain_result,
301                                         get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID),
302                                         domain_sid_string)) {
303                                 ldap_mods_free(mods, True);
304                                 SAFE_FREE(dn);
305                                 ldap_msgfree(domain_result);
306                                 return ret;
307                         }
308
309                         if (!string_to_sid(&dom_sid, domain_sid_string)) { 
310                                 ldap_mods_free(mods, True);
311                                 SAFE_FREE(dn);
312                                 ldap_msgfree(domain_result);
313                                 return ret;
314                         }
315
316                         ldap_mods_free(mods, True);
317                         mods = NULL;
318                         SAFE_FREE(dn);
319                         ldap_msgfree(domain_result);
320
321                         sid_copy(&sid, &dom_sid);
322                         sid_append_rid(&sid, *rid);
323
324                         /* check RID is not in use */
325                         if (sid_in_use(state, &sid, &error)) {
326                                 if (error) {
327                                         return ret;
328                                 }
329                                 continue;
330                         }
331
332                         return NT_STATUS_OK;
333                 }
334
335                 ld_error = NULL;
336                 ldap_get_option(state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
337                 DEBUG(2, ("Failed to modify rid: %s\n", ld_error ? ld_error : "(NULL"));
338                 SAFE_FREE(ld_error);
339
340                 ldap_mods_free(mods, True);
341                 mods = NULL;
342
343                 SAFE_FREE(dn);
344
345                 ldap_msgfree(domain_result);
346                 domain_result = NULL;
347
348                 {
349                         /* Sleep for a random timeout */
350                         unsigned sleeptime = (sys_random()*sys_getpid()*attempts);
351                         attempts += 1;
352                         
353                         sleeptime %= 100;
354                         smb_msleep(sleeptime);
355                 }
356         }
357
358         DEBUG(0, ("Failed to set new RID\n"));
359         return ret;
360 }
361
362
363 /*****************************************************************************
364  Allocate a new RID
365 *****************************************************************************/
366
367 static NTSTATUS ldap_allocate_rid(uint32 *rid, int rid_type)
368 {
369         return ldap_next_rid( &ldap_state, rid, rid_type );
370 }
371
372 /*****************************************************************************
373  Allocate a new uid or gid
374 *****************************************************************************/
375
376 static NTSTATUS ldap_allocate_id(unid_t *id, int id_type)
377 {
378         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
379         int rc = LDAP_SERVER_DOWN;
380         int count = 0;
381         LDAPMessage *result = NULL;
382         LDAPMessage *entry = NULL;
383         pstring id_str, new_id_str;
384         LDAPMod **mods = NULL;
385         const char *type;
386         char *dn = NULL;
387         char **attr_list;
388         pstring filter;
389         uid_t   luid, huid;
390         gid_t   lgid, hgid;
391
392
393         type = (id_type & ID_USERID) ?
394                 get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER ) : 
395                 get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
396
397         pstr_sprintf(filter, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
398
399         attr_list = get_attr_list( idpool_attr_list );
400
401         rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
402                                LDAP_SCOPE_SUBTREE, filter,
403                                attr_list, 0, &result);
404         free_attr_list( attr_list );
405          
406         if (rc != LDAP_SUCCESS) {
407                 DEBUG(0,("ldap_allocate_id: %s object not found\n", LDAP_OBJ_IDPOOL));
408                 goto out;
409         }
410         
411         count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
412         if (count != 1) {
413                 DEBUG(0,("ldap_allocate_id: single %s object not found\n", LDAP_OBJ_IDPOOL));
414                 goto out;
415         }
416
417         dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
418         if (!dn) {
419                 goto out;
420         }
421         entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
422
423         if (!smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, type, id_str)) {
424                 DEBUG(0,("ldap_allocate_id: %s attribute not found\n",
425                          type));
426                 goto out;
427         }
428
429         /* this must succeed or else we wouldn't have initialized */
430                 
431         lp_idmap_uid( &luid, &huid);
432         lp_idmap_gid( &lgid, &hgid);
433         
434         /* make sure we still have room to grow */
435         
436         if (id_type & ID_USERID) {
437                 id->uid = strtoul(id_str, NULL, 10);
438                 if (id->uid > huid ) {
439                         DEBUG(0,("ldap_allocate_id: Cannot allocate uid above %lu!\n", 
440                                  (unsigned long)huid));
441                         goto out;
442                 }
443         }
444         else { 
445                 id->gid = strtoul(id_str, NULL, 10);
446                 if (id->gid > hgid ) {
447                         DEBUG(0,("ldap_allocate_id: Cannot allocate gid above %lu!\n", 
448                                  (unsigned long)hgid));
449                         goto out;
450                 }
451         }
452         
453         pstr_sprintf(new_id_str, "%lu", 
454                  ((id_type & ID_USERID) ? (unsigned long)id->uid : 
455                   (unsigned long)id->gid) + 1);
456                  
457         smbldap_set_mod( &mods, LDAP_MOD_DELETE, type, id_str );                 
458         smbldap_set_mod( &mods, LDAP_MOD_ADD, type, new_id_str );
459
460         if (mods == NULL) {
461                 DEBUG(0,("ldap_allocate_id: smbldap_set_mod() failed.\n"));
462                 goto out;               
463         }
464
465         rc = smbldap_modify(ldap_state.smbldap_state, dn, mods);
466
467         ldap_mods_free( mods, True );
468         if (rc != LDAP_SUCCESS) {
469                 DEBUG(0,("ldap_allocate_id: Failed to allocate new %s.  ldap_modify() failed.\n",
470                         type));
471                 goto out;
472         }
473         
474         ret = NT_STATUS_OK;
475 out:
476         SAFE_FREE(dn);
477         if (result != NULL)
478                 ldap_msgfree(result);
479
480         return ret;
481 }
482
483 /*****************************************************************************
484  get a sid from an id
485 *****************************************************************************/
486
487 static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
488 {
489         LDAPMessage *result = NULL;
490         LDAPMessage *entry = NULL;
491         pstring sid_str;
492         pstring filter;
493         pstring suffix;
494         const char *type;
495         int rc;
496         int count;
497         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
498         char **attr_list;
499
500         if ( id_type & ID_USERID ) 
501                 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER );
502         else 
503                 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
504
505         pstrcpy( suffix, lp_ldap_idmap_suffix() );
506         pstr_sprintf(filter, "(&(objectClass=%s)(%s=%lu))",
507                 LDAP_OBJ_IDMAP_ENTRY, type,  
508                 ((id_type & ID_USERID) ? (unsigned long)id.uid : (unsigned long)id.gid));
509                 
510         attr_list = get_attr_list( sidmap_attr_list );
511         rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE, 
512                 filter, attr_list, 0, &result);
513
514         if (rc != LDAP_SUCCESS) {
515                 DEBUG(3,("ldap_get_isd_from_id: Failure looking up entry (%s)\n",
516                         ldap_err2string(rc) ));
517                 goto out;
518         }
519                            
520         count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
521
522         if (count != 1) {
523                 DEBUG(0,("ldap_get_sid_from_id: mapping not found for %s: %lu\n", 
524                         type, ((id_type & ID_USERID) ? (unsigned long)id.uid : 
525                                (unsigned long)id.gid)));
526                 goto out;
527         }
528         
529         entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
530         
531         if ( !smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, LDAP_ATTRIBUTE_SID, sid_str) )
532                 goto out;
533            
534         if (!string_to_sid(sid, sid_str))
535                 goto out;
536
537         ret = NT_STATUS_OK;
538 out:
539         free_attr_list( attr_list );     
540
541         if (result)
542                 ldap_msgfree(result);
543
544         return ret;
545 }
546
547 /***********************************************************************
548  Get an id from a sid 
549 ***********************************************************************/
550
551 static NTSTATUS ldap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
552 {
553         LDAPMessage *result = NULL;
554         LDAPMessage *entry = NULL;
555         pstring sid_str;
556         pstring filter;
557         pstring id_str;
558         const char *suffix;     
559         const char *type;
560         int rc;
561         int count;
562         char **attr_list;
563         char *dn = NULL;
564         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
565
566         sid_to_string(sid_str, sid);
567
568         DEBUG(8,("ldap_get_id_from_sid: %s (%s)\n", sid_str,
569                 (*id_type & ID_GROUPID ? "group" : "user") ));
570
571         suffix = lp_ldap_idmap_suffix();
572         pstr_sprintf(filter, "(&(objectClass=%s)(%s=%s))", 
573                 LDAP_OBJ_IDMAP_ENTRY, LDAP_ATTRIBUTE_SID, sid_str);
574                         
575         if ( *id_type & ID_GROUPID ) 
576                 type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER );
577         else 
578                 type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER );
579
580         /* do the search and check for errors */
581
582         attr_list = get_attr_list( sidmap_attr_list );
583         rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE, 
584                 filter, attr_list, 0, &result);
585                         
586         if (rc != LDAP_SUCCESS) {
587                 DEBUG(3,("ldap_get_id_from_sid: Failure looking up idmap entry (%s)\n",
588                         ldap_err2string(rc) ));
589                 goto out;
590         }
591                         
592         /* check for the number of entries returned */
593
594         count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
595            
596         if ( count > 1 ) {
597                 DEBUG(0, ("ldap_get_id_from_sid: (2nd) search %s returned [%d] entries!\n",
598                         filter, count));
599                 goto out;
600         }
601         
602         /* try to allocate a new id if we still haven't found one */
603
604         if ( !count ) {
605                 int i;
606
607                 if (*id_type & ID_QUERY_ONLY) {
608                         DEBUG(5,("ldap_get_id_from_sid: No matching entry found and QUERY_ONLY flag set\n"));
609                         goto out;
610                 }
611
612                 DEBUG(8,("ldap_get_id_from_sid: Allocating new id\n"));
613                 
614                 for (i = 0; i < LDAP_MAX_ALLOC_ID; i++) {
615                         ret = ldap_allocate_id(id, *id_type);
616                         if ( NT_STATUS_IS_OK(ret) )
617                                 break;
618                 }
619                 
620                 if ( !NT_STATUS_IS_OK(ret) ) {
621                         DEBUG(0,("ldap_allocate_id: cannot acquire id lock!\n"));
622                         goto out;
623                 }
624
625                 DEBUG(10,("ldap_get_id_from_sid: Allocated new %cid [%ul]\n",
626                         (*id_type & ID_GROUPID ? 'g' : 'u'), (uint32)id->uid ));
627         
628                 ret = ldap_set_mapping(sid, *id, *id_type);
629
630                 /* all done */
631
632                 goto out;
633         }
634
635         DEBUG(10,("ldap_get_id_from_sid: success\n"));
636
637         entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
638         
639         dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
640         if (!dn)
641                 goto out;
642
643         DEBUG(10, ("Found mapping entry at dn=%s, looking for %s\n", dn, type));
644                 
645         if ( smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, type, id_str) ) {
646                 if ( (*id_type & ID_USERID) )
647                         id->uid = strtoul(id_str, NULL, 10);
648                 else
649                         id->gid = strtoul(id_str, NULL, 10);
650                 
651                 ret = NT_STATUS_OK;
652                 goto out;
653         }
654         
655 out:
656         free_attr_list( attr_list );
657         if (result)
658                 ldap_msgfree(result);
659         SAFE_FREE(dn);
660         
661         return ret;
662 }
663
664 /**********************************************************************
665  Verify the sambaUnixIdPool entry in the directiry.  
666 **********************************************************************/
667
668 static NTSTATUS verify_idpool( void )
669 {
670         fstring filter;
671         int rc;
672         char **attr_list;
673         LDAPMessage *result = NULL;
674         LDAPMod **mods = NULL;
675         int count;
676         
677         fstr_sprintf( filter, "(objectclass=%s)", LDAP_OBJ_IDPOOL );
678         
679         attr_list = get_attr_list( idpool_attr_list );
680         rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), 
681                 LDAP_SCOPE_SUBTREE, filter, attr_list, 0, &result);
682         free_attr_list ( attr_list );
683
684         if (rc != LDAP_SUCCESS)
685                 return NT_STATUS_UNSUCCESSFUL;
686
687         count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
688
689         ldap_msgfree(result);
690
691         if ( count > 1 ) {
692                 DEBUG(0,("ldap_idmap_init: multiple entries returned from %s (base == %s)\n",
693                         filter, lp_ldap_idmap_suffix() ));
694                 return NT_STATUS_UNSUCCESSFUL;
695         }
696         else if (count == 0) {
697                 uid_t   luid, huid;
698                 gid_t   lgid, hgid;
699                 fstring uid_str, gid_str;
700                 
701                 if ( !lp_idmap_uid(&luid, &huid) || !lp_idmap_gid( &lgid, &hgid ) ) {
702                         DEBUG(0,("ldap_idmap_init: idmap uid/gid parameters not specified\n"));
703                         return NT_STATUS_UNSUCCESSFUL;
704                 }
705                 
706                 fstr_sprintf( uid_str, "%lu", (unsigned long)luid );
707                 fstr_sprintf( gid_str, "%lu", (unsigned long)lgid );
708
709                 smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDPOOL );
710                 smbldap_set_mod( &mods, LDAP_MOD_ADD, 
711                         get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER), uid_str );
712                 smbldap_set_mod( &mods, LDAP_MOD_ADD,
713                         get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER), gid_str );
714                 
715                 rc = smbldap_modify(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), mods);
716         }
717
718         return ( rc==LDAP_SUCCESS ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
719 }
720
721 /*****************************************************************************
722  Initialise idmap database. 
723 *****************************************************************************/
724
725 static NTSTATUS ldap_idmap_init( char *params )
726 {
727         NTSTATUS nt_status;
728
729         ldap_state.mem_ctx = talloc_init("idmap_ldap");
730         if (!ldap_state.mem_ctx) {
731                 return NT_STATUS_NO_MEMORY;
732         }
733
734         /* assume location is the only parameter */
735         if (!NT_STATUS_IS_OK(nt_status = 
736                              smbldap_init(ldap_state.mem_ctx, params, 
737                                           &ldap_state.smbldap_state))) {
738                 talloc_destroy(ldap_state.mem_ctx);
739                 return nt_status;
740         }
741
742         /* see if the idmap suffix and sub entries exists */
743         
744         nt_status = verify_idpool();    
745         if ( !NT_STATUS_IS_OK(nt_status) )
746                 return nt_status;
747                 
748         return NT_STATUS_OK;
749 }
750
751 /*****************************************************************************
752  End the LDAP session
753 *****************************************************************************/
754
755 static NTSTATUS ldap_idmap_close(void)
756 {
757
758         smbldap_free_struct(&(ldap_state).smbldap_state);
759         talloc_destroy(ldap_state.mem_ctx);
760         
761         DEBUG(5,("The connection to the LDAP server was closed\n"));
762         /* maybe free the results here --metze */
763         
764         return NT_STATUS_OK;
765 }
766
767
768 /* This function doesn't make as much sense in an LDAP world since the calling
769    node doesn't really control the ID ranges */
770 static void ldap_idmap_status(void)
771 {
772         DEBUG(0, ("LDAP IDMAP Status not available\n"));
773 }
774
775 static struct idmap_methods ldap_methods = {
776         ldap_idmap_init,
777         ldap_allocate_rid,
778         ldap_allocate_id,
779         ldap_get_sid_from_id,
780         ldap_get_id_from_sid,
781         ldap_set_mapping,
782         ldap_idmap_close,
783         ldap_idmap_status
784
785 };
786
787 NTSTATUS idmap_ldap_init(void)
788 {
789         return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap", &ldap_methods);
790 }