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