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