2 Unix SMB/CIFS implementation.
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.
29 #define DBGC_CLASS DBGC_IDMAP
37 struct ldap_idmap_state
{
38 struct smbldap_state
*smbldap_state
;
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
)
57 LDAPMod
**mods
= NULL
;
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
) );
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
,
85 get_attr_key2string(sidmap_attr_list
, LDAP_ATTR_SID
),
88 /* There may well be nothing at all to do */
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
);
98 if (rc
!= LDAP_SUCCESS
) {
99 char *ld_error
= NULL
;
100 ldap_get_option(ldap_state
.smbldap_state
->ldap_struct
, LDAP_OPT_ERROR_STRING
,
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
));
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
;
126 LDAPMessage
*result
= NULL
;
127 LDAPMessage
*entry
= NULL
;
128 pstring id_str
, new_id_str
;
129 LDAPMod
**mods
= NULL
;
132 const char **attr_list
;
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
));
159 count
= ldap_count_entries(ldap_state
.smbldap_state
->ldap_struct
, result
);
161 DEBUG(0,("ldap_allocate_id: single %s object not found\n", LDAP_OBJ_IDPOOL
));
165 dn
= smbldap_get_dn(ldap_state
.smbldap_state
->ldap_struct
, result
);
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",
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
));
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
));
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
);
208 DEBUG(0,("ldap_allocate_id: smbldap_set_mod() failed.\n"));
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",
225 ldap_msgfree(result
);
230 /*****************************************************************************
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
;
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
);
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
) ));
267 count
= ldap_count_entries(ldap_state
.smbldap_state
->ldap_struct
, result
);
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
)));
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
) )
281 if (!string_to_sid(sid
, sid_str
))
286 TALLOC_FREE( attr_list
);
289 ldap_msgfree(result
);
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
;
311 const char **attr_list
;
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
);
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
) ));
341 /* check for the number of entries returned */
343 count
= ldap_count_entries(ldap_state
.smbldap_state
->ldap_struct
, result
);
346 DEBUG(0, ("ldap_get_id_from_sid: (2nd) search %s returned [%d] entries!\n",
351 /* try to allocate a new id if we still haven't found one */
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"));
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
) )
369 if ( !NT_STATUS_IS_OK(ret
) ) {
370 DEBUG(0,("ldap_allocate_id: cannot acquire id lock!\n"));
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
);
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
);
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);
398 id
->gid
= strtoul(id_str
, NULL
, 10);
405 TALLOC_FREE( attr_list
);
407 ldap_msgfree(result
);
413 /**********************************************************************
414 Verify the sambaUnixIdPool entry in the directiry.
415 **********************************************************************/
417 static NTSTATUS
verify_idpool( void )
421 const char **attr_list
;
422 LDAPMessage
*result
= NULL
;
423 LDAPMod
**mods
= NULL
;
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
);
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) {
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
);
464 rc
= smbldap_modify(ldap_state
.smbldap_state
, lp_ldap_idmap_suffix(), mods
);
465 ldap_mods_free( mods
, True
);
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
)
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
);
495 /* see if the idmap suffix and sub entries exists */
497 nt_status
= verify_idpool();
498 if ( !NT_STATUS_IS_OK(nt_status
) )
504 /*****************************************************************************
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 */
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
= {
531 ldap_get_sid_from_id
,
532 ldap_get_id_from_sid
,
539 NTSTATUS
idmap_ldap_init(void)
541 return smb_register_idmap(SMB_IDMAP_INTERFACE_VERSION
, "ldap", &ldap_methods
);