sync 3.0 into HEAD for the last time
[vlendec/samba-autobuild/.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 #define IDMAP_GROUP_SUFFIX      "ou=idmap group"
38 #define IDMAP_USER_SUFFIX       "ou=idmap people"
39
40
41 struct ldap_idmap_state {
42         struct smbldap_state *smbldap_state;
43         TALLOC_CTX *mem_ctx;
44 };
45
46 #define LDAP_MAX_ALLOC_ID 128              /* number tries while allocating
47                                               new id */
48
49 static struct ldap_idmap_state ldap_state;
50
51 static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type);
52 static NTSTATUS ldap_set_mapping_internals(const DOM_SID *sid, unid_t id, int id_type, 
53                                            const char *ldap_dn, LDAPMessage *entry);
54 static NTSTATUS ldap_idmap_close(void);
55
56
57 /**********************************************************************
58  Even if the sambaDomain attribute in LDAP tells us that this RID is 
59  safe to use, always check before use.  
60 *********************************************************************/
61
62 static BOOL sid_in_use(struct ldap_idmap_state *state, 
63                        const DOM_SID *sid, int *error) 
64 {
65         fstring filter;
66         fstring sid_string;
67         LDAPMessage *result = NULL;
68         int count;
69         int rc;
70         char *sid_attr[] = {LDAP_ATTRIBUTE_SID, NULL};
71
72         slprintf(filter, sizeof(filter)-1, "(%s=%s)", LDAP_ATTRIBUTE_SID, sid_to_string(sid_string, sid));
73
74         rc = smbldap_search_suffix(state->smbldap_state, 
75                                    filter, sid_attr, &result);
76
77         if (rc != LDAP_SUCCESS) {
78                 char *ld_error = NULL;
79                 ldap_get_option(state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
80                 DEBUG(2, ("Failed to check if sid %s is alredy in use: %s\n", 
81                           sid_string, ld_error));
82                 SAFE_FREE(ld_error);
83
84                 *error = rc;
85                 return True;
86         }
87         
88         if ((count = ldap_count_entries(state->smbldap_state->ldap_struct, result)) > 0) {
89                 DEBUG(3, ("Sid %s already in use - trying next RID\n",
90                           sid_string));
91                 ldap_msgfree(result);
92                 return True;
93         }
94
95         ldap_msgfree(result);
96
97         /* good, sid is not in use */
98         return False;
99 }
100
101 /**********************************************************************
102  Set the new nextRid attribute, and return one we can use.
103
104  This also checks that this RID is actually free - in case the admin
105  manually stole it :-).
106 *********************************************************************/
107 static NTSTATUS ldap_next_rid(struct ldap_idmap_state *state, uint32 *rid, 
108                               int rid_type)
109 {
110         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
111         int rc;
112         LDAPMessage *domain_result = NULL;
113         LDAPMessage *entry  = NULL;
114         char *dn;
115         LDAPMod **mods = NULL;
116         fstring old_rid_string;
117         fstring next_rid_string;
118         fstring algorithmic_rid_base_string;
119         uint32 next_rid;
120         uint32 alg_rid_base;
121         int attempts = 0;
122         char *ld_error = NULL;
123
124         while (attempts < 10) 
125         {
126                 if (!NT_STATUS_IS_OK(ret = smbldap_search_domain_info(state->smbldap_state, 
127                         &domain_result, get_global_sam_name(), True))) 
128                 {
129                         return ret;
130                 }
131         
132                 entry = ldap_first_entry(state->smbldap_state->ldap_struct, domain_result);
133                 if (!entry) {
134                         DEBUG(0, ("Could not get domain info entry\n"));
135                         ldap_msgfree(domain_result);
136                         return ret;
137                 }
138
139                 if ((dn = ldap_get_dn(state->smbldap_state->ldap_struct, entry)) == NULL) {
140                         DEBUG(0, ("Could not get domain info DN\n"));
141                         ldap_msgfree(domain_result);
142                         return ret;
143                 }
144
145                 /* yes, we keep 3 seperate counters, one for rids between 1000 (BASE_RID) and 
146                    algorithmic_rid_base.  The other two are to avoid stomping on the 
147                    different sets of algorithmic RIDs */
148                 
149                 if (smbldap_get_single_attribute(state->smbldap_state->ldap_struct, entry,
150                                          get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE),
151                                          algorithmic_rid_base_string)) 
152                 {
153                         
154                         alg_rid_base = (uint32)atol(algorithmic_rid_base_string);
155                 } else {
156                         alg_rid_base = algorithmic_rid_base();
157                         /* Try to make the modification atomically by enforcing the
158                            old value in the delete mod. */
159                         slprintf(algorithmic_rid_base_string, sizeof(algorithmic_rid_base_string)-1, "%d", alg_rid_base);
160                         smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods, 
161                                          get_attr_key2string(dominfo_attr_list, LDAP_ATTR_ALGORITHMIC_RID_BASE), 
162                                          algorithmic_rid_base_string);
163                 }
164
165                 next_rid = 0;
166
167                 if (alg_rid_base > BASE_RID) {
168                         /* we have a non-default 'algorithmic rid base', so we have 'low' rids that we 
169                            can allocate to new users */
170                         if (smbldap_get_single_attribute(state->smbldap_state->ldap_struct, entry,
171                                                  get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID),
172                                                  old_rid_string)) 
173                         {
174                                 *rid = (uint32)atol(old_rid_string);
175                         } else {
176                                 *rid = BASE_RID;
177                         }
178
179                         next_rid = *rid+1;
180                         if (next_rid >= alg_rid_base) {
181                                 return NT_STATUS_UNSUCCESSFUL;
182                         }
183                         
184                         slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
185                                 
186                         /* Try to make the modification atomically by enforcing the
187                            old value in the delete mod. */
188                         smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods, 
189                                          get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_RID), 
190                                          next_rid_string);
191                 }
192
193                 if (!next_rid) { /* not got one already */
194                         switch (rid_type) {
195                         case USER_RID_TYPE:
196                                 if (smbldap_get_single_attribute(state->smbldap_state->ldap_struct, entry,
197                                                          get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID),
198                                                          old_rid_string)) 
199                                 {
200                                         *rid = (uint32)atol(old_rid_string);                                    
201                                 }
202                                 break;
203                         case GROUP_RID_TYPE:
204                                 if (smbldap_get_single_attribute(state->smbldap_state->ldap_struct, entry, 
205                                                          get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
206                                                          old_rid_string)) 
207                                 {
208                                         *rid = (uint32)atol(old_rid_string);
209                                 }
210                                 break;
211                         }
212                         
213                         /* This is the core of the whole routine. If we had
214                            scheme-style closures, there would be a *lot* less code
215                            duplication... */
216
217                         next_rid = *rid+RID_MULTIPLIER;
218                         slprintf(next_rid_string, sizeof(next_rid_string)-1, "%d", next_rid);
219                         
220                         switch (rid_type) {
221                         case USER_RID_TYPE:
222                                 /* Try to make the modification atomically by enforcing the
223                                    old value in the delete mod. */
224                                 smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods, 
225                                                  get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_USERRID), 
226                                                  next_rid_string);
227                                 break;
228                                 
229                         case GROUP_RID_TYPE:
230                                 /* Try to make the modification atomically by enforcing the
231                                    old value in the delete mod. */
232                                 smbldap_make_mod(state->smbldap_state->ldap_struct, entry, &mods,
233                                                  get_attr_key2string(dominfo_attr_list, LDAP_ATTR_NEXT_GROUPRID),
234                                                  next_rid_string);
235                                 break;
236                         }
237                 }
238
239                 if ((rc = ldap_modify_s(state->smbldap_state->ldap_struct, dn, mods)) == LDAP_SUCCESS) {
240                         DOM_SID dom_sid;
241                         DOM_SID sid;
242                         pstring domain_sid_string;
243                         int error = 0;
244
245                         if (!smbldap_get_single_attribute(state->smbldap_state->ldap_struct, domain_result,
246                                 get_attr_key2string(dominfo_attr_list, LDAP_ATTR_DOM_SID),
247                                 domain_sid_string)) 
248                         {
249                                 ldap_mods_free(mods, True);
250                                 ldap_memfree(dn);
251                                 ldap_msgfree(domain_result);
252                                 return ret;
253                         }
254
255                         if (!string_to_sid(&dom_sid, domain_sid_string)) { 
256                                 ldap_mods_free(mods, True);
257                                 ldap_memfree(dn);
258                                 ldap_msgfree(domain_result);
259                                 return ret;
260                         }
261
262                         ldap_mods_free(mods, True);
263                         mods = NULL;
264                         ldap_memfree(dn);
265                         ldap_msgfree(domain_result);
266
267                         sid_copy(&sid, &dom_sid);
268                         sid_append_rid(&sid, *rid);
269
270                         /* check RID is not in use */
271                         if (sid_in_use(state, &sid, &error)) {
272                                 if (error) {
273                                         return ret;
274                                 }
275                                 continue;
276                         }
277
278                         return NT_STATUS_OK;
279                 }
280
281                 ld_error = NULL;
282                 ldap_get_option(state->smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING, &ld_error);
283                 DEBUG(2, ("Failed to modify rid: %s\n", ld_error ? ld_error : "(NULL"));
284                 SAFE_FREE(ld_error);
285
286                 ldap_mods_free(mods, True);
287                 mods = NULL;
288
289                 ldap_memfree(dn);
290                 dn = NULL;
291
292                 ldap_msgfree(domain_result);
293                 domain_result = NULL;
294
295                 {
296                         /* Sleep for a random timeout */
297                         unsigned sleeptime = (sys_random()*sys_getpid()*attempts);
298                         attempts += 1;
299                         
300                         sleeptime %= 100;
301                         msleep(sleeptime);
302                 }
303         }
304
305         DEBUG(0, ("Failed to set new RID\n"));
306         return ret;
307 }
308
309
310 /*****************************************************************************
311  Allocate a new RID
312 *****************************************************************************/
313
314 static NTSTATUS ldap_allocate_rid(uint32 *rid, int rid_type)
315 {
316         return ldap_next_rid( &ldap_state, rid, rid_type );
317 }
318
319 /*****************************************************************************
320  Allocate a new uid or gid
321 *****************************************************************************/
322
323 static NTSTATUS ldap_allocate_id(unid_t *id, int id_type)
324 {
325         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
326         int rc = LDAP_SERVER_DOWN;
327         int count = 0;
328         LDAPMessage *result = NULL;
329         LDAPMessage *entry = NULL;
330         pstring id_str, new_id_str;
331         LDAPMod **mods = NULL;
332         const char *type;
333         char *dn;
334         char **attr_list;
335         pstring filter;
336         uid_t   luid, huid;
337         gid_t   lgid, hgid;
338
339
340         type = (id_type & ID_USERID) ?
341                 get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER ) : 
342                 get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
343
344         pstr_sprintf(filter, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
345
346         attr_list = get_attr_list( idpool_attr_list );
347         
348         rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
349                                LDAP_SCOPE_SUBTREE, filter,
350                                attr_list, 0, &result);
351         free_attr_list( attr_list );
352          
353         if (rc != LDAP_SUCCESS) {
354                 DEBUG(0,("ldap_allocate_id: %s object not found\n", LDAP_OBJ_IDPOOL));
355                 goto out;
356         }
357         
358         count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
359         if (count != 1) {
360                 DEBUG(0,("ldap_allocate_id: single %s object not found\n", LDAP_OBJ_IDPOOL));
361                 goto out;
362         }
363
364         dn = ldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
365         entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
366
367         if (!smbldap_get_single_attribute(ldap_state.smbldap_state->ldap_struct, entry, type, id_str)) {
368                 DEBUG(0,("ldap_allocate_id: %s attribute not found\n",
369                          type));
370                 goto out;
371         }
372
373         /* this must succeed or else we wouldn't have initialized */
374                 
375         lp_idmap_uid( &luid, &huid);
376         lp_idmap_gid( &lgid, &hgid);
377         
378         /* make sure we still have room to grow */
379         
380         if (id_type & ID_USERID) {
381                 id->uid = strtoul(id_str, NULL, 10);
382                 if (id->uid > huid ) {
383                         DEBUG(0,("ldap_allocate_id: Cannot allocate uid above %lu!\n", 
384                                  (unsigned long)huid));
385                         goto out;
386                 }
387         }
388         else { 
389                 id->gid = strtoul(id_str, NULL, 10);
390                 if (id->gid > hgid ) {
391                         DEBUG(0,("ldap_allocate_id: Cannot allocate gid above %lu!\n", 
392                                  (unsigned long)hgid));
393                         goto out;
394                 }
395         }
396         
397         pstr_sprintf(new_id_str, "%lu", 
398                  ((id_type & ID_USERID) ? (unsigned long)id->uid : 
399                   (unsigned long)id->gid) + 1);
400                  
401         smbldap_set_mod( &mods, LDAP_MOD_DELETE, type, id_str );                 
402         smbldap_set_mod( &mods, LDAP_MOD_ADD, type, new_id_str );
403         
404         rc = ldap_modify_s(ldap_state.smbldap_state->ldap_struct, dn, mods);
405
406         ldap_memfree(dn);
407         ldap_mods_free( mods, True );
408         
409         if (rc != LDAP_SUCCESS) {
410                 DEBUG(0,("ldap_allocate_id: Failed to allocate new %s.  ldap_modify() failed.\n",
411                         type));
412                 goto out;
413         }
414         
415         ret = NT_STATUS_OK;
416 out:
417         return ret;
418 }
419
420 /*****************************************************************************
421  get a sid from an id
422 *****************************************************************************/
423
424 static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, int id_type)
425 {
426         LDAPMessage *result = NULL;
427         LDAPMessage *entry = NULL;
428         fstring id_str;
429         pstring sid_str;
430         pstring filter;
431         pstring suffix;
432         const char *type;
433         const char *obj_class;
434         int rc;
435         int count;
436         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
437         char **attr_list;
438
439         /* first we try for a samba user or group mapping */
440         
441         if ( id_type & ID_USERID ) {
442                 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER );
443                 obj_class = LDAP_OBJ_SAMBASAMACCOUNT;
444                 fstr_sprintf(id_str, "%lu", (unsigned long)id.uid );    
445                 pstrcpy( suffix, lp_ldap_suffix());
446         }
447         else {
448                 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
449                 obj_class = LDAP_OBJ_GROUPMAP;
450                 fstr_sprintf(id_str, "%lu", (unsigned long)id.gid );    
451                 pstrcpy( suffix, lp_ldap_group_suffix() );
452         }
453
454         DEBUG(5,("ldap_get_sid_from_id: Searching \"%s\"\n", filter ));
455                  
456         attr_list = get_attr_list( sidmap_attr_list );
457         pstr_sprintf(filter, "(&(|(objectClass=%s)(objectClass=%s))(%s=%s))", 
458                  LDAP_OBJ_IDMAP_ENTRY, obj_class, type, id_str);
459
460         rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE, 
461                             filter, attr_list, 0, &result);
462         
463         if (rc != LDAP_SUCCESS) {
464                 DEBUG(3,("ldap_get_isd_from_id: Failure looking up entry (%s)\n",
465                         ldap_err2string(rc) ));
466                 goto out;
467         }
468
469         count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
470         
471         if (count > 1) {
472                 DEBUG(0,("ldap_get_sid_from_id: mapping returned [%d] entries!\n",
473                         count));
474                 goto out;
475         }
476
477         /* fall back to looking up an idmap entry if we didn't find and 
478            actual user or group */
479         
480         if (count == 0) {
481                 ldap_msgfree(result);
482                 result = NULL;
483                 
484                 pstr_sprintf(filter, "(&(objectClass=%s)(%s=%lu))",
485                         LDAP_OBJ_IDMAP_ENTRY, type,  
486                          ((id_type & ID_USERID) ? (unsigned long)id.uid : 
487                           (unsigned long)id.gid));
488
489                 pstrcpy( suffix, lp_ldap_idmap_suffix() );
490
491                 rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE, 
492                         filter, attr_list, 0, &result);
493
494                 if (rc != LDAP_SUCCESS) {
495                         DEBUG(3,("ldap_get_isd_from_id: Failure looking up entry (%s)\n",
496                                 ldap_err2string(rc) ));
497                         goto out;
498                 }
499                            
500                 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
501
502                 if (count != 1) {
503                         DEBUG(0,("ldap_get_sid_from_id: mapping not found for %s: %lu\n", 
504                                 type, ((id_type & ID_USERID) ? (unsigned long)id.uid : 
505                                        (unsigned long)id.gid)));
506                         goto out;
507                 }
508         }
509         
510         entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
511         
512         if ( !smbldap_get_single_attribute(ldap_state.smbldap_state->ldap_struct, entry, LDAP_ATTRIBUTE_SID, sid_str) )
513                 goto out;
514            
515         if (!string_to_sid(sid, sid_str)) 
516                 goto out;
517
518         ret = NT_STATUS_OK;
519 out:
520         free_attr_list( attr_list );     
521
522         if (result)
523                 ldap_msgfree(result);
524
525         return ret;
526 }
527
528 /***********************************************************************
529  Get an id from a sid 
530 ***********************************************************************/
531
532 static NTSTATUS ldap_get_id_from_sid(unid_t *id, int *id_type, const DOM_SID *sid)
533 {
534         LDAPMessage *result = NULL;
535         LDAPMessage *entry = NULL;
536         pstring sid_str;
537         pstring filter;
538         pstring id_str;
539         const char *suffix;     
540         const char *type;
541         int rc;
542         int count;
543         char **attr_list;
544         char *dn = NULL;
545         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
546
547         sid_to_string(sid_str, sid);
548
549         DEBUG(8,("ldap_get_id_from_sid: %s (%s)\n", sid_str,
550                 (*id_type & ID_GROUPID ? "group" : "user") ));
551
552         /* ahhh....  ok.  We have to check users and groups in places other
553            than idmap (hint: we're a domain member of a Samba domain) */
554
555         if ( *id_type & ID_GROUPID ) {
556
557                 type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER );
558                 suffix = lp_ldap_group_suffix();
559                 pstr_sprintf(filter, "(&(|(objectClass=%s)(objectClass=%s))(%s=%s))", 
560                         LDAP_OBJ_GROUPMAP, LDAP_OBJ_IDMAP_ENTRY, 
561                         get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID ), 
562                         sid_str);
563
564         }
565         else {
566
567                 type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER );
568                 suffix = lp_ldap_suffix();
569                 pstr_sprintf(filter, "(&(|(&(objectClass=%s)(objectClass=%s))(objectClass=%s))(%s=%s))", 
570                          LDAP_OBJ_SAMBASAMACCOUNT, LDAP_OBJ_POSIXACCOUNT, LDAP_OBJ_IDMAP_ENTRY, 
571                          get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID ), 
572                          sid_str);
573
574         }
575
576         DEBUG(10,("ldap_get_id_from_sid: Searching for \"%s\"\n", filter));
577
578         /* do the search and check for errors */
579
580         attr_list = get_attr_list( sidmap_attr_list );
581         rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE, 
582                 filter, attr_list, 0, &result); 
583
584         if ( rc != LDAP_SUCCESS ) {
585                 DEBUG(3,("ldap_get_id_from_sid: Failure looking up group mapping (%s)\n",
586                         ldap_err2string(rc) ));
587                 goto out;
588         }
589
590         count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
591
592         if ( count > 1 ) {
593                 DEBUG(3,("ldap_get_id_from_sid: search \"%s\" returned [%d] entries.  Bailing...\n",
594                         filter, count));
595                 goto out;
596         }
597
598         /* see if we need to do a search here */
599
600         if ( count == 0 ) {
601
602                 if ( result ) {
603                         ldap_msgfree(result);
604                         result = NULL;
605                 }
606
607                 /* look in idmap suffix */
608
609                 suffix = lp_ldap_idmap_suffix();
610                 pstr_sprintf(filter, "(&(objectClass=%s)(%s=%s))", 
611                         LDAP_OBJ_IDMAP_ENTRY, LDAP_ATTRIBUTE_SID, sid_str);
612
613                 rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE, 
614                         filter, attr_list, 0, &result);
615                         
616                 if (rc != LDAP_SUCCESS) {
617                         DEBUG(3,("ldap_get_id_from_sid: Failure looking up idmap entry (%s)\n",
618                                 ldap_err2string(rc) ));
619                         goto out;
620                 }
621                         
622                 /* check for the number of entries returned */
623
624                 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
625            
626                 if ( count > 1 ) {
627                         DEBUG(0, ("ldap_get_id_from_sid: (2nd) search %s returned [%d] entries!\n",
628                                 filter, count));
629                         goto out;
630                 }
631         
632
633                 /* try to allocate a new id if we still haven't found one */
634
635                 if ( (count==0) && !(*id_type & ID_QUERY_ONLY) ) {
636                         int i;
637
638                         DEBUG(8,("ldap_get_id_from_sid: Allocating new id\n"));
639                 
640                         for (i = 0; i < LDAP_MAX_ALLOC_ID; i++) {
641                                 ret = ldap_allocate_id(id, *id_type);
642                                 if ( NT_STATUS_IS_OK(ret) )
643                                         break;
644                         }
645                 
646                         if ( !NT_STATUS_IS_OK(ret) ) {
647                                 DEBUG(0,("ldap_allocate_id: cannot acquire id lock!\n"));
648                                 goto out;
649                         }
650
651                         DEBUG(10,("ldap_get_id_from_sid: Allocated new %cid [%ul]\n",
652                                 (*id_type & ID_GROUPID ? 'g' : 'u'), (uint32)id->uid ));
653         
654                         ret = ldap_set_mapping(sid, *id, *id_type);
655
656                         /* all done */
657
658                         goto out;
659                 }
660         }
661
662         DEBUG(10,("ldap_get_id_from_sid: success\n"));
663
664         entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
665         
666         dn = ldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
667
668         DEBUG(10, ("Found mapping entry at dn=%s, looking for %s\n", dn, type));
669                 
670         if ( smbldap_get_single_attribute(ldap_state.smbldap_state->ldap_struct, entry, type, id_str) ) 
671         {
672                 if ( (*id_type & ID_USERID) )
673                         id->uid = strtoul(id_str, NULL, 10);
674                 else
675                         id->gid = strtoul(id_str, NULL, 10);
676                 
677                 ret = NT_STATUS_OK;
678                 goto out;
679         }
680         
681 out:
682         free_attr_list( attr_list );
683         if (result)
684                 ldap_msgfree(result);
685         if (dn)
686                 ldap_memfree(dn);
687         
688         return ret;
689 }
690
691 /***********************************************************************
692  This function cannot be called to modify a mapping, only set a new one 
693
694  This takes a possible pointer to the existing entry for the UID or SID
695  involved.
696 ***********************************************************************/
697
698 static NTSTATUS ldap_set_mapping_internals(const DOM_SID *sid, unid_t id, 
699                                            int id_type, const char *ldap_dn, 
700                                            LDAPMessage *entry)
701 {
702         pstring dn; 
703         pstring id_str;
704         fstring type;
705         LDAPMod **mods = NULL;
706         int rc = -1;
707         int ldap_op;
708         fstring sid_string;
709         char **values = NULL;
710         int i;
711
712         sid_to_string( sid_string, sid );
713
714         if (ldap_dn) {
715                 DEBUG(10, ("Adding new IDMAP mapping on DN: %s", ldap_dn));
716                 ldap_op = LDAP_MOD_REPLACE;
717                 pstrcpy( dn, ldap_dn );
718         } else {
719                 ldap_op = LDAP_MOD_ADD;
720                 pstr_sprintf(dn, "%s=%s,%s", get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID), 
721                          sid_string, lp_ldap_idmap_suffix());
722         }
723         
724         if ( id_type & ID_USERID ) 
725                 fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER ) );
726         else
727                 fstrcpy( type, get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER ) );
728
729         pstr_sprintf(id_str, "%lu", ((id_type & ID_USERID) ? (unsigned long)id.uid : 
730                                                  (unsigned long)id.gid));       
731         
732         if (entry) 
733                 values = ldap_get_values(ldap_state.smbldap_state->ldap_struct, entry, "objectClass");
734
735         if (values) {
736                 BOOL found_idmap = False;
737                 for (i=0; values[i]; i++) {
738                         if (StrCaseCmp(values[i], LDAP_OBJ_IDMAP_ENTRY) == 0) {
739                                 found_idmap = True;
740                                 break;
741                         }
742                 }
743                 if (!found_idmap)
744                         smbldap_set_mod( &mods, LDAP_MOD_ADD, 
745                                          "objectClass", LDAP_OBJ_IDMAP_ENTRY );
746         } else {
747                 smbldap_set_mod( &mods, LDAP_MOD_ADD, 
748                                  "objectClass", LDAP_OBJ_IDMAP_ENTRY );
749         }
750
751         smbldap_make_mod( ldap_state.smbldap_state->ldap_struct, 
752                           entry, &mods, type, id_str );
753
754         smbldap_make_mod( ldap_state.smbldap_state->ldap_struct, 
755                           entry, &mods,  
756                           get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID), 
757                           sid_string );
758
759         /* There may well be nothing at all to do */
760         if (mods) {
761                 switch(ldap_op)
762                 {
763                 case LDAP_MOD_ADD: 
764                         smbldap_set_mod( &mods, LDAP_MOD_ADD, 
765                                          "objectClass", LDAP_OBJ_SID_ENTRY );
766                         rc = smbldap_add(ldap_state.smbldap_state, dn, mods);
767                         break;
768                 case LDAP_MOD_REPLACE: 
769                         rc = smbldap_modify(ldap_state.smbldap_state, dn, mods);
770                         break;
771                 }
772                 
773                 ldap_mods_free( mods, True );   
774         } else {
775                 rc = LDAP_SUCCESS;
776         }
777
778         if (rc != LDAP_SUCCESS) {
779                 char *ld_error = NULL;
780                 ldap_get_option(ldap_state.smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
781                                 &ld_error);
782                 DEBUG(0,("ldap_set_mapping_internals: Failed to %s mapping from %s to %lu [%s]\n",
783                          (ldap_op == LDAP_MOD_ADD) ? "add" : "replace",
784                          sid_string, (unsigned long)((id_type & ID_USERID) ? id.uid : id.gid), type));
785                 DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n", ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
786                 return NT_STATUS_UNSUCCESSFUL;
787         }
788                 
789         DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to %lu [%s]\n",
790                 sid_string, ((id_type & ID_USERID) ? (unsigned long)id.uid : 
791                              (unsigned long)id.gid), type));
792
793         return NT_STATUS_OK;
794 }
795
796 /***********************************************************************
797  This function cannot be called to modify a mapping, only set a new one 
798 ***********************************************************************/
799
800 static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, int id_type) 
801 {
802         NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
803         char *dn = NULL;
804         LDAPMessage *result = NULL;
805         LDAPMessage *entry = NULL;
806         const char *type;
807         const char *obj_class;
808         const char *posix_obj_class;
809         const char *suffix;
810         fstring sid_str;
811         fstring id_str;
812         pstring filter;
813         char **attr_list;
814         int rc;
815         int count;
816
817         /* try for a samba user or group mapping (looking for an entry with a SID) */
818         if ( id_type & ID_USERID ) {
819                 obj_class = LDAP_OBJ_SAMBASAMACCOUNT;
820                 suffix = lp_ldap_suffix();
821                 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER );
822                 posix_obj_class = LDAP_OBJ_POSIXACCOUNT;
823                 fstr_sprintf(id_str, "%lu", (unsigned long)id.uid );    
824         }
825         else {
826                 obj_class = LDAP_OBJ_GROUPMAP;
827                 suffix = lp_ldap_group_suffix();
828                 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
829                 posix_obj_class = LDAP_OBJ_POSIXGROUP;
830                 fstr_sprintf(id_str, "%lu", (unsigned long)id.gid );    
831         }
832         
833         sid_to_string(sid_str, sid);
834         pstr_sprintf(filter, 
835                  "(|"
836                  "(&(|(objectClass=%s)(|(objectClass=%s)(objectClass=%s)))(%s=%s))"
837                  "(&(objectClass=%s)(%s=%s))"
838                  ")", 
839                  /* objectClasses that might contain a SID */
840                  LDAP_OBJ_SID_ENTRY, LDAP_OBJ_IDMAP_ENTRY, obj_class, 
841                  get_attr_key2string( sidmap_attr_list, LDAP_ATTR_SID ), 
842                  sid_str, 
843
844                  /* objectClasses that might contain a Unix UID/GID */
845                  posix_obj_class, 
846                  /* Unix UID/GID specifier*/
847                  type, 
848                  /* actual ID */
849                  id_str);
850
851         attr_list = get_attr_list( sidmap_attr_list );
852         rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE, 
853                             filter, attr_list, 0, &result);
854         free_attr_list( attr_list );
855         
856         if (rc != LDAP_SUCCESS)
857                 goto out;
858
859         count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
860         
861         /* fall back to looking up an idmap entry if we didn't find anything under the idmap
862            user or group suffix */
863
864         if (count == 1) {
865                 entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
866         
867                 dn = ldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
868                 DEBUG(10, ("Found partial mapping entry at dn=%s, looking for %s\n", dn, type));
869
870                 ret = ldap_set_mapping_internals(sid, id, id_type, dn, entry);
871
872                 goto out;
873         } else if (count > 1) {
874                 DEBUG(0, ("Too many entries trying to find DN to attach ldap \n"));
875                 goto out;
876         }
877
878         ret = ldap_set_mapping_internals(sid, id, id_type, NULL, NULL);
879
880 out:
881         if (result)
882                 ldap_msgfree(result);
883         if (dn)
884                 ldap_memfree(dn);
885         
886         return ret;
887 }
888
889
890 /**********************************************************************
891  Verify the sambaUnixIdPool entry in the directiry.  
892 **********************************************************************/
893
894 static NTSTATUS verify_idpool( void )
895 {
896         fstring filter;
897         int rc;
898         char **attr_list;
899         LDAPMessage *result = NULL;
900         LDAPMod **mods = NULL;
901         int count;
902         
903         fstr_sprintf( filter, "(objectclass=%s)", LDAP_OBJ_IDPOOL );
904         
905         attr_list = get_attr_list( idpool_attr_list );
906         rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), 
907                 LDAP_SCOPE_SUBTREE, filter, attr_list, 0, &result);
908         free_attr_list ( attr_list );
909
910         if (rc != LDAP_SUCCESS)
911                 return NT_STATUS_UNSUCCESSFUL;
912
913         count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
914
915         if ( count > 1 ) {
916                 DEBUG(0,("ldap_idmap_init: multiple entries returned from %s (base == %s)\n",
917                         filter, lp_ldap_idmap_suffix() ));
918                 return NT_STATUS_UNSUCCESSFUL;
919         }
920         else if (count == 0) {
921                 uid_t   luid, huid;
922                 gid_t   lgid, hgid;
923                 fstring uid_str, gid_str;
924                 
925                 if ( !lp_idmap_uid(&luid, &huid) || !lp_idmap_gid( &lgid, &hgid ) ) {
926                         DEBUG(0,("ldap_idmap_init: idmap uid/gid parameters not specified\n"));
927                         return NT_STATUS_UNSUCCESSFUL;
928                 }
929                 
930                 fstr_sprintf( uid_str, "%lu", (unsigned long)luid );
931                 fstr_sprintf( gid_str, "%lu", (unsigned long)lgid );
932
933                 smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDPOOL );
934                 smbldap_set_mod( &mods, LDAP_MOD_ADD, 
935                         get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER), uid_str );
936                 smbldap_set_mod( &mods, LDAP_MOD_ADD,
937                         get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER), gid_str );
938                 
939                 rc = smbldap_modify(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), mods);
940         }
941
942         return ( rc==LDAP_SUCCESS ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
943 }
944
945 /*****************************************************************************
946  Initialise idmap database. 
947 *****************************************************************************/
948 static NTSTATUS ldap_idmap_init( char *params )
949 {
950         NTSTATUS nt_status;
951
952         ldap_state.mem_ctx = talloc_init("idmap_ldap");
953         if (!ldap_state.mem_ctx) {
954                 return NT_STATUS_NO_MEMORY;
955         }
956
957         /* assume location is the only parameter */
958         if (!NT_STATUS_IS_OK(nt_status = 
959                              smbldap_init(ldap_state.mem_ctx, params, 
960                                           &ldap_state.smbldap_state))) {
961                 talloc_destroy(ldap_state.mem_ctx);
962                 return nt_status;
963         }
964
965         /* see if the idmap suffix and sub entries exists */
966         
967         nt_status = verify_idpool();    
968         if ( !NT_STATUS_IS_OK(nt_status) )
969                 return nt_status;
970                 
971         return NT_STATUS_OK;
972 }
973
974 /*****************************************************************************
975  End the LDAP session
976 *****************************************************************************/
977
978 static NTSTATUS ldap_idmap_close(void)
979 {
980
981         smbldap_free_struct(&(ldap_state).smbldap_state);
982         talloc_destroy(ldap_state.mem_ctx);
983         
984         DEBUG(5,("The connection to the LDAP server was closed\n"));
985         /* maybe free the results here --metze */
986         
987         return NT_STATUS_OK;
988 }
989
990
991 /* This function doesn't make as much sense in an LDAP world since the calling
992    node doesn't really control the ID ranges */
993 static void ldap_idmap_status(void)
994 {
995         DEBUG(0, ("LDAP IDMAP Status not available\n"));
996 }
997
998 static struct idmap_methods ldap_methods = {
999         ldap_idmap_init,
1000         ldap_allocate_rid,
1001         ldap_allocate_id,
1002         ldap_get_sid_from_id,
1003         ldap_get_id_from_sid,
1004         ldap_set_mapping,
1005         ldap_idmap_close,
1006         ldap_idmap_status
1007
1008 };
1009
1010 NTSTATUS idmap_ldap_init(void)
1011 {
1012         return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap", &ldap_methods);
1013 }