r20110: Fix interaction between paranoid malloc checker
[Samba.git] / source / sam / idmap_ldap.c
blob3fec3a142be71b0c4d65bb62ce6e5eb5821cdbaa
1 /*
2 Unix SMB/CIFS implementation.
4 idmap LDAP backend
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
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.
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.
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.
26 #include "includes.h"
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_IDMAP
32 #include <lber.h>
33 #include <ldap.h>
35 #include "smbldap.h"
37 struct ldap_idmap_state {
38 struct smbldap_state *smbldap_state;
39 TALLOC_CTX *mem_ctx;
42 static struct ldap_idmap_state ldap_state;
44 /* number tries while allocating new id */
45 #define LDAP_MAX_ALLOC_ID 128
48 /***********************************************************************
49 This function cannot be called to modify a mapping, only set a new one
50 ***********************************************************************/
52 static NTSTATUS ldap_set_mapping(const DOM_SID *sid, unid_t id, enum idmap_type id_type)
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;
63 sid_to_string( sid_string, sid );
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());
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 ) );
75 pstr_sprintf(id_str, "%lu", ((id_type == ID_USERID) ? (unsigned long)id.uid :
76 (unsigned long)id.gid));
78 smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDMAP_ENTRY );
80 smbldap_make_mod( ldap_state.smbldap_state->ldap_struct,
81 entry, &mods, type, id_str );
83 smbldap_make_mod( ldap_state.smbldap_state->ldap_struct,
84 entry, &mods,
85 get_attr_key2string(sidmap_attr_list, LDAP_ATTR_SID),
86 sid_string );
88 /* There may well be nothing at all to do */
90 if (mods) {
91 smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_SID_ENTRY );
92 rc = smbldap_add(ldap_state.smbldap_state, dn, mods);
93 ldap_mods_free( mods, True );
94 } else {
95 rc = LDAP_SUCCESS;
98 if (rc != LDAP_SUCCESS) {
99 char *ld_error = NULL;
100 ldap_get_option(ldap_state.smbldap_state->ldap_struct, LDAP_OPT_ERROR_STRING,
101 &ld_error);
102 DEBUG(0,("ldap_set_mapping_internals: Failed to %s mapping from %s to %lu [%s]\n",
103 (ldap_op == LDAP_MOD_ADD) ? "add" : "replace",
104 sid_string, (unsigned long)((id_type & ID_USERID) ? id.uid : id.gid), type));
105 DEBUG(0, ("ldap_set_mapping_internals: Error was: %s (%s)\n",
106 ld_error ? ld_error : "(NULL)", ldap_err2string (rc)));
107 return NT_STATUS_UNSUCCESSFUL;
110 DEBUG(10,("ldap_set_mapping: Successfully created mapping from %s to %lu [%s]\n",
111 sid_string, ((id_type & ID_USERID) ? (unsigned long)id.uid :
112 (unsigned long)id.gid), type));
114 return NT_STATUS_OK;
117 /*****************************************************************************
118 Allocate a new uid or gid
119 *****************************************************************************/
121 static NTSTATUS ldap_allocate_id(unid_t *id, enum idmap_type id_type)
123 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
124 int rc = LDAP_SERVER_DOWN;
125 int count = 0;
126 LDAPMessage *result = NULL;
127 LDAPMessage *entry = NULL;
128 pstring id_str, new_id_str;
129 LDAPMod **mods = NULL;
130 const char *type;
131 char *dn = NULL;
132 const char **attr_list;
133 pstring filter;
134 uid_t luid, huid;
135 gid_t lgid, hgid;
137 if (id_type != ID_USERID && id_type != ID_GROUPID) {
138 return NT_STATUS_INVALID_PARAMETER;
141 type = (id_type == ID_USERID) ?
142 get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER ) :
143 get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
145 pstr_sprintf(filter, "(objectClass=%s)", LDAP_OBJ_IDPOOL);
147 attr_list = get_attr_list( NULL, idpool_attr_list );
149 rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
150 LDAP_SCOPE_SUBTREE, filter,
151 attr_list, 0, &result);
152 TALLOC_FREE( attr_list );
154 if (rc != LDAP_SUCCESS) {
155 DEBUG(0,("ldap_allocate_id: %s object not found\n", LDAP_OBJ_IDPOOL));
156 goto out;
159 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
160 if (count != 1) {
161 DEBUG(0,("ldap_allocate_id: single %s object not found\n", LDAP_OBJ_IDPOOL));
162 goto out;
165 dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
166 if (!dn) {
167 goto out;
169 entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
171 if (!smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, type, id_str)) {
172 DEBUG(0,("ldap_allocate_id: %s attribute not found\n",
173 type));
174 goto out;
177 /* this must succeed or else we wouldn't have initialized */
179 lp_idmap_uid( &luid, &huid);
180 lp_idmap_gid( &lgid, &hgid);
182 /* make sure we still have room to grow */
184 if (id_type == ID_USERID) {
185 id->uid = strtoul(id_str, NULL, 10);
186 if (id->uid > huid ) {
187 DEBUG(0,("ldap_allocate_id: Cannot allocate uid above %lu!\n",
188 (unsigned long)huid));
189 goto out;
191 } else {
192 id->gid = strtoul(id_str, NULL, 10);
193 if (id->gid > hgid ) {
194 DEBUG(0,("ldap_allocate_id: Cannot allocate gid above %lu!\n",
195 (unsigned long)hgid));
196 goto out;
200 pstr_sprintf(new_id_str, "%lu",
201 ((id_type == ID_USERID) ? (unsigned long)id->uid :
202 (unsigned long)id->gid) + 1);
204 smbldap_set_mod( &mods, LDAP_MOD_DELETE, type, id_str );
205 smbldap_set_mod( &mods, LDAP_MOD_ADD, type, new_id_str );
207 if (mods == NULL) {
208 DEBUG(0,("ldap_allocate_id: smbldap_set_mod() failed.\n"));
209 goto out;
212 rc = smbldap_modify(ldap_state.smbldap_state, dn, mods);
214 ldap_mods_free( mods, True );
215 if (rc != LDAP_SUCCESS) {
216 DEBUG(1,("ldap_allocate_id: Failed to allocate new %s. ldap_modify() failed.\n",
217 type));
218 goto out;
221 ret = NT_STATUS_OK;
222 out:
223 SAFE_FREE(dn);
224 if (result != NULL)
225 ldap_msgfree(result);
227 return ret;
230 /*****************************************************************************
231 get a sid from an id
232 *****************************************************************************/
234 static NTSTATUS ldap_get_sid_from_id(DOM_SID *sid, unid_t id, enum idmap_type id_type, int flags)
236 LDAPMessage *result = NULL;
237 LDAPMessage *entry = NULL;
238 pstring sid_str;
239 pstring filter;
240 pstring suffix;
241 const char *type;
242 int rc;
243 int count;
244 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
245 const char **attr_list;
247 if ( id_type == ID_USERID )
248 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_UIDNUMBER );
249 else
250 type = get_attr_key2string( idpool_attr_list, LDAP_ATTR_GIDNUMBER );
252 pstrcpy( suffix, lp_ldap_idmap_suffix() );
253 pstr_sprintf(filter, "(&(objectClass=%s)(%s=%lu))",
254 LDAP_OBJ_IDMAP_ENTRY, type,
255 ((id_type & ID_USERID) ? (unsigned long)id.uid : (unsigned long)id.gid));
257 attr_list = get_attr_list( NULL, sidmap_attr_list );
258 rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
259 filter, attr_list, 0, &result);
261 if (rc != LDAP_SUCCESS) {
262 DEBUG(3,("ldap_get_isd_from_id: Failure looking up entry (%s)\n",
263 ldap_err2string(rc) ));
264 goto out;
267 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
269 if (count != 1) {
270 DEBUG(0,("ldap_get_sid_from_id: mapping not found for %s: %lu\n",
271 type, ((id_type & ID_USERID) ? (unsigned long)id.uid :
272 (unsigned long)id.gid)));
273 goto out;
276 entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
278 if ( !smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, LDAP_ATTRIBUTE_SID, sid_str) )
279 goto out;
281 if (!string_to_sid(sid, sid_str))
282 goto out;
284 ret = NT_STATUS_OK;
285 out:
286 TALLOC_FREE( attr_list );
288 if (result)
289 ldap_msgfree(result);
291 return ret;
294 /***********************************************************************
295 Get an id from a sid - urg. This is assuming the *output* parameter id_type
296 has been initialized with the correct needed type - ID_USERID or ID_GROUPID.
297 This *sucks* and is bad design and needs fixing. JRA.
298 ***********************************************************************/
300 static NTSTATUS ldap_get_id_from_sid(unid_t *id, enum idmap_type *id_type, const DOM_SID *sid, int flags)
302 LDAPMessage *result = NULL;
303 LDAPMessage *entry = NULL;
304 pstring sid_str;
305 pstring filter;
306 pstring id_str;
307 const char *suffix;
308 const char *type;
309 int rc;
310 int count;
311 const char **attr_list;
312 char *dn = NULL;
313 NTSTATUS ret = NT_STATUS_UNSUCCESSFUL;
315 sid_to_string(sid_str, sid);
317 DEBUG(8,("ldap_get_id_from_sid: %s (%s)\n", sid_str,
318 (*id_type & ID_GROUPID ? "group" : "user") ));
320 suffix = lp_ldap_idmap_suffix();
321 pstr_sprintf(filter, "(&(objectClass=%s)(%s=%s))",
322 LDAP_OBJ_IDMAP_ENTRY, LDAP_ATTRIBUTE_SID, sid_str);
324 if ( *id_type == ID_GROUPID )
325 type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_GIDNUMBER );
326 else
327 type = get_attr_key2string( sidmap_attr_list, LDAP_ATTR_UIDNUMBER );
329 /* do the search and check for errors */
331 attr_list = get_attr_list( NULL, sidmap_attr_list );
332 rc = smbldap_search(ldap_state.smbldap_state, suffix, LDAP_SCOPE_SUBTREE,
333 filter, attr_list, 0, &result);
335 if (rc != LDAP_SUCCESS) {
336 DEBUG(3,("ldap_get_id_from_sid: Failure looking up idmap entry (%s)\n",
337 ldap_err2string(rc) ));
338 goto out;
341 /* check for the number of entries returned */
343 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
345 if ( count > 1 ) {
346 DEBUG(0, ("ldap_get_id_from_sid: (2nd) search %s returned [%d] entries!\n",
347 filter, count));
348 goto out;
351 /* try to allocate a new id if we still haven't found one */
353 if ( !count ) {
354 int i;
356 if (flags & IDMAP_FLAG_QUERY_ONLY) {
357 DEBUG(5,("ldap_get_id_from_sid: No matching entry found and QUERY_ONLY flag set\n"));
358 goto out;
361 DEBUG(8,("ldap_get_id_from_sid: Allocating new id\n"));
363 for (i = 0; i < LDAP_MAX_ALLOC_ID; i++) {
364 ret = ldap_allocate_id(id, *id_type);
365 if ( NT_STATUS_IS_OK(ret) )
366 break;
369 if ( !NT_STATUS_IS_OK(ret) ) {
370 DEBUG(0,("ldap_allocate_id: cannot acquire id lock!\n"));
371 goto out;
374 DEBUG(10,("ldap_get_id_from_sid: Allocated new %cid [%ul]\n",
375 (*id_type & ID_GROUPID ? 'g' : 'u'), (uint32)id->uid ));
377 ret = ldap_set_mapping(sid, *id, *id_type);
379 /* all done */
381 goto out;
384 DEBUG(10,("ldap_get_id_from_sid: success\n"));
386 entry = ldap_first_entry(ldap_state.smbldap_state->ldap_struct, result);
388 dn = smbldap_get_dn(ldap_state.smbldap_state->ldap_struct, result);
389 if (!dn)
390 goto out;
392 DEBUG(10, ("Found mapping entry at dn=%s, looking for %s\n", dn, type));
394 if ( smbldap_get_single_pstring(ldap_state.smbldap_state->ldap_struct, entry, type, id_str) ) {
395 if ( (*id_type == ID_USERID) )
396 id->uid = strtoul(id_str, NULL, 10);
397 else
398 id->gid = strtoul(id_str, NULL, 10);
400 ret = NT_STATUS_OK;
401 goto out;
404 out:
405 TALLOC_FREE( attr_list );
406 if (result)
407 ldap_msgfree(result);
408 SAFE_FREE(dn);
410 return ret;
413 /**********************************************************************
414 Verify the sambaUnixIdPool entry in the directiry.
415 **********************************************************************/
417 static NTSTATUS verify_idpool( void )
419 fstring filter;
420 int rc;
421 const char **attr_list;
422 LDAPMessage *result = NULL;
423 LDAPMod **mods = NULL;
424 int count;
426 fstr_sprintf( filter, "(objectclass=%s)", LDAP_OBJ_IDPOOL );
428 attr_list = get_attr_list( NULL, idpool_attr_list );
429 rc = smbldap_search(ldap_state.smbldap_state, lp_ldap_idmap_suffix(),
430 LDAP_SCOPE_SUBTREE, filter, attr_list, 0, &result);
431 TALLOC_FREE( attr_list );
433 if (rc != LDAP_SUCCESS)
434 return NT_STATUS_UNSUCCESSFUL;
436 count = ldap_count_entries(ldap_state.smbldap_state->ldap_struct, result);
438 ldap_msgfree(result);
440 if ( count > 1 ) {
441 DEBUG(0,("ldap_idmap_init: multiple entries returned from %s (base == %s)\n",
442 filter, lp_ldap_idmap_suffix() ));
443 return NT_STATUS_UNSUCCESSFUL;
445 else if (count == 0) {
446 uid_t luid, huid;
447 gid_t lgid, hgid;
448 fstring uid_str, gid_str;
450 if ( !lp_idmap_uid(&luid, &huid) || !lp_idmap_gid( &lgid, &hgid ) ) {
451 DEBUG(0,("ldap_idmap_init: idmap uid/gid parameters not specified\n"));
452 return NT_STATUS_UNSUCCESSFUL;
455 fstr_sprintf( uid_str, "%lu", (unsigned long)luid );
456 fstr_sprintf( gid_str, "%lu", (unsigned long)lgid );
458 smbldap_set_mod( &mods, LDAP_MOD_ADD, "objectClass", LDAP_OBJ_IDPOOL );
459 smbldap_set_mod( &mods, LDAP_MOD_ADD,
460 get_attr_key2string(idpool_attr_list, LDAP_ATTR_UIDNUMBER), uid_str );
461 smbldap_set_mod( &mods, LDAP_MOD_ADD,
462 get_attr_key2string(idpool_attr_list, LDAP_ATTR_GIDNUMBER), gid_str );
463 if (mods) {
464 rc = smbldap_modify(ldap_state.smbldap_state, lp_ldap_idmap_suffix(), mods);
465 ldap_mods_free( mods, True );
466 } else {
467 return NT_STATUS_UNSUCCESSFUL;
471 return ( rc==LDAP_SUCCESS ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
474 /*****************************************************************************
475 Initialise idmap database.
476 *****************************************************************************/
478 static NTSTATUS ldap_idmap_init( const char *params )
480 NTSTATUS nt_status;
482 ldap_state.mem_ctx = talloc_init("idmap_ldap");
483 if (!ldap_state.mem_ctx) {
484 return NT_STATUS_NO_MEMORY;
487 /* assume location is the only parameter */
488 if (!NT_STATUS_IS_OK(nt_status =
489 smbldap_init(ldap_state.mem_ctx, params,
490 &ldap_state.smbldap_state))) {
491 talloc_destroy(ldap_state.mem_ctx);
492 return nt_status;
495 /* see if the idmap suffix and sub entries exists */
497 nt_status = verify_idpool();
498 if ( !NT_STATUS_IS_OK(nt_status) )
499 return nt_status;
501 return NT_STATUS_OK;
504 /*****************************************************************************
505 End the LDAP session
506 *****************************************************************************/
508 static NTSTATUS ldap_idmap_close(void)
511 smbldap_free_struct(&(ldap_state).smbldap_state);
512 talloc_destroy(ldap_state.mem_ctx);
514 DEBUG(5,("The connection to the LDAP server was closed\n"));
515 /* maybe free the results here --metze */
517 return NT_STATUS_OK;
521 /* This function doesn't make as much sense in an LDAP world since the calling
522 node doesn't really control the ID ranges */
523 static void ldap_idmap_status(void)
525 DEBUG(0, ("LDAP IDMAP Status not available\n"));
528 static struct idmap_methods ldap_methods = {
529 ldap_idmap_init,
530 ldap_allocate_id,
531 ldap_get_sid_from_id,
532 ldap_get_id_from_sid,
533 ldap_set_mapping,
534 ldap_idmap_close,
535 ldap_idmap_status
539 NTSTATUS idmap_ldap_init(void)
541 return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION, "ldap", &ldap_methods);