2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-2006,
5 * Copyright (C) Jean François Micouleau 1998-2001.
6 * Copyright (C) Volker Lendecke 2006.
7 * Copyright (C) Gerald Carter 2006.
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "groupdb/mapping.h"
27 static TDB_CONTEXT
*tdb
; /* used for driver files */
29 /****************************************************************************
30 Open the group mapping tdb.
31 ****************************************************************************/
32 BOOL
init_group_mapping(void)
34 const char *vstring
= "INFO/version";
36 GROUP_MAP
*map_table
= NULL
;
37 size_t num_entries
= 0;
42 tdb
= tdb_open_log(lock_path("group_mapping.tdb"), 0, TDB_DEFAULT
, O_RDWR
|O_CREAT
, 0600);
44 DEBUG(0,("Failed to open group mapping database\n"));
48 /* handle a Samba upgrade */
49 tdb_lock_bystring(tdb
, vstring
);
51 /* Cope with byte-reversed older versions of the db. */
52 vers_id
= tdb_fetch_int32(tdb
, vstring
);
53 if ((vers_id
== DATABASE_VERSION_V1
) || (IREV(vers_id
) == DATABASE_VERSION_V1
)) {
54 /* Written on a bigendian machine with old fetch_int code. Save as le. */
55 tdb_store_int32(tdb
, vstring
, DATABASE_VERSION_V2
);
56 vers_id
= DATABASE_VERSION_V2
;
59 /* if its an unknown version we remove everthing in the db */
61 if (vers_id
!= DATABASE_VERSION_V2
) {
62 tdb_traverse(tdb
, tdb_traverse_delete_fn
, NULL
);
63 tdb_store_int32(tdb
, vstring
, DATABASE_VERSION_V2
);
66 tdb_unlock_bystring(tdb
, vstring
);
68 /* cleanup any map entries with a gid == -1 */
70 if ( enum_group_mapping( NULL
, SID_NAME_UNKNOWN
, &map_table
, &num_entries
, False
) ) {
73 for ( i
=0; i
<num_entries
; i
++ ) {
74 if ( map_table
[i
].gid
== -1 ) {
75 group_map_remove( &map_table
[i
].sid
);
79 SAFE_FREE( map_table
);
86 /****************************************************************************
87 ****************************************************************************/
88 BOOL
add_mapping_entry(GROUP_MAP
*map
, int flag
)
92 fstring string_sid
="";
95 if(!init_group_mapping()) {
96 DEBUG(0,("failed to initialize group mapping\n"));
100 sid_to_string(string_sid
, &map
->sid
);
102 len
= tdb_pack(buf
, sizeof(buf
), "ddff",
103 map
->gid
, map
->sid_name_use
, map
->nt_name
, map
->comment
);
105 if (len
> sizeof(buf
))
108 slprintf(key
, sizeof(key
), "%s%s", GROUP_PREFIX
, string_sid
);
110 kbuf
.dsize
= strlen(key
)+1;
114 if (tdb_store(tdb
, kbuf
, dbuf
, flag
) != 0) return False
;
120 /****************************************************************************
121 Return the sid and the type of the unix group.
122 ****************************************************************************/
124 BOOL
get_group_map_from_sid(DOM_SID sid
, GROUP_MAP
*map
)
131 if(!init_group_mapping()) {
132 DEBUG(0,("failed to initialize group mapping\n"));
136 /* the key is the SID, retrieving is direct */
138 sid_to_string(string_sid
, &sid
);
139 slprintf(key
, sizeof(key
), "%s%s", GROUP_PREFIX
, string_sid
);
142 kbuf
.dsize
= strlen(key
)+1;
144 dbuf
= tdb_fetch(tdb
, kbuf
);
148 ret
= tdb_unpack(dbuf
.dptr
, dbuf
.dsize
, "ddff",
149 &map
->gid
, &map
->sid_name_use
, &map
->nt_name
, &map
->comment
);
151 SAFE_FREE(dbuf
.dptr
);
154 DEBUG(3,("get_group_map_from_sid: tdb_unpack failure\n"));
158 sid_copy(&map
->sid
, &sid
);
163 /****************************************************************************
164 Return the sid and the type of the unix group.
165 ****************************************************************************/
167 BOOL
get_group_map_from_gid(gid_t gid
, GROUP_MAP
*map
)
169 TDB_DATA kbuf
, dbuf
, newkey
;
173 if(!init_group_mapping()) {
174 DEBUG(0,("failed to initialize group mapping\n"));
178 /* we need to enumerate the TDB to find the GID */
180 for (kbuf
= tdb_firstkey(tdb
);
182 newkey
= tdb_nextkey(tdb
, kbuf
), safe_free(kbuf
.dptr
), kbuf
=newkey
) {
184 if (strncmp(kbuf
.dptr
, GROUP_PREFIX
, strlen(GROUP_PREFIX
)) != 0) continue;
186 dbuf
= tdb_fetch(tdb
, kbuf
);
190 fstrcpy(string_sid
, kbuf
.dptr
+strlen(GROUP_PREFIX
));
192 string_to_sid(&map
->sid
, string_sid
);
194 ret
= tdb_unpack(dbuf
.dptr
, dbuf
.dsize
, "ddff",
195 &map
->gid
, &map
->sid_name_use
, &map
->nt_name
, &map
->comment
);
197 SAFE_FREE(dbuf
.dptr
);
200 DEBUG(3,("get_group_map_from_gid: tdb_unpack failure\n"));
205 SAFE_FREE(kbuf
.dptr
);
213 /****************************************************************************
214 Return the sid and the type of the unix group.
215 ****************************************************************************/
217 BOOL
get_group_map_from_ntname(const char *name
, GROUP_MAP
*map
)
219 TDB_DATA kbuf
, dbuf
, newkey
;
223 if(!init_group_mapping()) {
224 DEBUG(0,("get_group_map_from_ntname:failed to initialize group mapping\n"));
228 /* we need to enumerate the TDB to find the name */
230 for (kbuf
= tdb_firstkey(tdb
);
232 newkey
= tdb_nextkey(tdb
, kbuf
), safe_free(kbuf
.dptr
), kbuf
=newkey
) {
234 if (strncmp(kbuf
.dptr
, GROUP_PREFIX
, strlen(GROUP_PREFIX
)) != 0) continue;
236 dbuf
= tdb_fetch(tdb
, kbuf
);
240 fstrcpy(string_sid
, kbuf
.dptr
+strlen(GROUP_PREFIX
));
242 string_to_sid(&map
->sid
, string_sid
);
244 ret
= tdb_unpack(dbuf
.dptr
, dbuf
.dsize
, "ddff",
245 &map
->gid
, &map
->sid_name_use
, &map
->nt_name
, &map
->comment
);
247 SAFE_FREE(dbuf
.dptr
);
250 DEBUG(3,("get_group_map_from_ntname: tdb_unpack failure\n"));
254 if ( strequal(name
, map
->nt_name
) ) {
255 SAFE_FREE(kbuf
.dptr
);
263 /****************************************************************************
264 Remove a group mapping entry.
265 ****************************************************************************/
267 BOOL
group_map_remove(const DOM_SID
*sid
)
273 if(!init_group_mapping()) {
274 DEBUG(0,("failed to initialize group mapping\n"));
278 /* the key is the SID, retrieving is direct */
280 sid_to_string(string_sid
, sid
);
281 slprintf(key
, sizeof(key
), "%s%s", GROUP_PREFIX
, string_sid
);
284 kbuf
.dsize
= strlen(key
)+1;
286 dbuf
= tdb_fetch(tdb
, kbuf
);
290 SAFE_FREE(dbuf
.dptr
);
292 if(tdb_delete(tdb
, kbuf
) != TDB_SUCCESS
)
298 /****************************************************************************
299 Enumerate the group mapping.
300 ****************************************************************************/
302 BOOL
enum_group_mapping(const DOM_SID
*domsid
, enum SID_NAME_USE sid_name_use
, GROUP_MAP
**pp_rmap
,
303 size_t *p_num_entries
, BOOL unix_only
)
305 TDB_DATA kbuf
, dbuf
, newkey
;
314 if(!init_group_mapping()) {
315 DEBUG(0,("failed to initialize group mapping\n"));
322 for (kbuf
= tdb_firstkey(tdb
);
324 newkey
= tdb_nextkey(tdb
, kbuf
), safe_free(kbuf
.dptr
), kbuf
=newkey
) {
326 if (strncmp(kbuf
.dptr
, GROUP_PREFIX
, strlen(GROUP_PREFIX
)) != 0)
329 dbuf
= tdb_fetch(tdb
, kbuf
);
333 fstrcpy(string_sid
, kbuf
.dptr
+strlen(GROUP_PREFIX
));
335 ret
= tdb_unpack(dbuf
.dptr
, dbuf
.dsize
, "ddff",
336 &map
.gid
, &map
.sid_name_use
, &map
.nt_name
, &map
.comment
);
338 SAFE_FREE(dbuf
.dptr
);
341 DEBUG(3,("enum_group_mapping: tdb_unpack failure\n"));
345 /* list only the type or everything if UNKNOWN */
346 if (sid_name_use
!=SID_NAME_UNKNOWN
&& sid_name_use
!=map
.sid_name_use
) {
347 DEBUG(11,("enum_group_mapping: group %s is not of the requested type\n", map
.nt_name
));
351 if (unix_only
==ENUM_ONLY_MAPPED
&& map
.gid
==-1) {
352 DEBUG(11,("enum_group_mapping: group %s is non mapped\n", map
.nt_name
));
356 string_to_sid(&grpsid
, string_sid
);
357 sid_copy( &map
.sid
, &grpsid
);
359 sid_split_rid( &grpsid
, &rid
);
361 /* Only check the domain if we were given one */
363 if ( domsid
&& !sid_equal( domsid
, &grpsid
) ) {
364 DEBUG(11,("enum_group_mapping: group %s is not in domain %s\n",
365 string_sid
, sid_string_static(domsid
)));
369 DEBUG(11,("enum_group_mapping: returning group %s of "
370 "type %s\n", map
.nt_name
,
371 sid_type_lookup(map
.sid_name_use
)));
373 (*pp_rmap
) = SMB_REALLOC_ARRAY((*pp_rmap
), GROUP_MAP
, entries
+1);
375 DEBUG(0,("enum_group_mapping: Unable to enlarge group map!\n"));
381 mapt
[entries
].gid
= map
.gid
;
382 sid_copy( &mapt
[entries
].sid
, &map
.sid
);
383 mapt
[entries
].sid_name_use
= map
.sid_name_use
;
384 fstrcpy(mapt
[entries
].nt_name
, map
.nt_name
);
385 fstrcpy(mapt
[entries
].comment
, map
.comment
);
391 *p_num_entries
=entries
;
396 /* This operation happens on session setup, so it should better be fast. We
397 * store a list of aliases a SID is member of hanging off MEMBEROF/SID. */
399 NTSTATUS
one_alias_membership(const DOM_SID
*member
,
400 DOM_SID
**sids
, size_t *num
)
402 fstring key
, string_sid
;
406 if (!init_group_mapping()) {
407 DEBUG(0,("failed to initialize group mapping\n"));
408 return NT_STATUS_ACCESS_DENIED
;
411 sid_to_string(string_sid
, member
);
412 slprintf(key
, sizeof(key
), "%s%s", MEMBEROF_PREFIX
, string_sid
);
414 kbuf
.dsize
= strlen(key
)+1;
417 dbuf
= tdb_fetch(tdb
, kbuf
);
419 if (dbuf
.dptr
== NULL
) {
425 while (next_token(&p
, string_sid
, " ", sizeof(string_sid
))) {
429 if (!string_to_sid(&alias
, string_sid
))
432 add_sid_to_array_unique(NULL
, &alias
, sids
, num
);
435 return NT_STATUS_NO_MEMORY
;
438 SAFE_FREE(dbuf
.dptr
);
442 static NTSTATUS
alias_memberships(const DOM_SID
*members
, size_t num_members
,
443 DOM_SID
**sids
, size_t *num
)
450 for (i
=0; i
<num_members
; i
++) {
451 NTSTATUS status
= one_alias_membership(&members
[i
], sids
, num
);
452 if (!NT_STATUS_IS_OK(status
))
458 static BOOL
is_aliasmem(const DOM_SID
*alias
, const DOM_SID
*member
)
463 /* This feels the wrong way round, but the on-disk data structure
464 * dictates it this way. */
465 if (!NT_STATUS_IS_OK(alias_memberships(member
, 1, &sids
, &num
)))
468 for (i
=0; i
<num
; i
++) {
469 if (sid_compare(alias
, &sids
[i
]) == 0) {
479 NTSTATUS
add_aliasmem(const DOM_SID
*alias
, const DOM_SID
*member
)
485 char *new_memberstring
;
488 if(!init_group_mapping()) {
489 DEBUG(0,("failed to initialize group mapping\n"));
490 return NT_STATUS_ACCESS_DENIED
;
493 if (!get_group_map_from_sid(*alias
, &map
))
494 return NT_STATUS_NO_SUCH_ALIAS
;
496 if ( (map
.sid_name_use
!= SID_NAME_ALIAS
) &&
497 (map
.sid_name_use
!= SID_NAME_WKN_GRP
) )
498 return NT_STATUS_NO_SUCH_ALIAS
;
500 if (is_aliasmem(alias
, member
))
501 return NT_STATUS_MEMBER_IN_ALIAS
;
503 sid_to_string(string_sid
, member
);
504 slprintf(key
, sizeof(key
), "%s%s", MEMBEROF_PREFIX
, string_sid
);
506 kbuf
.dsize
= strlen(key
)+1;
509 dbuf
= tdb_fetch(tdb
, kbuf
);
511 sid_to_string(string_sid
, alias
);
513 if (dbuf
.dptr
!= NULL
) {
514 asprintf(&new_memberstring
, "%s %s", (char *)(dbuf
.dptr
),
517 new_memberstring
= SMB_STRDUP(string_sid
);
520 if (new_memberstring
== NULL
)
521 return NT_STATUS_NO_MEMORY
;
523 SAFE_FREE(dbuf
.dptr
);
524 dbuf
.dsize
= strlen(new_memberstring
)+1;
525 dbuf
.dptr
= new_memberstring
;
527 result
= tdb_store(tdb
, kbuf
, dbuf
, 0);
529 SAFE_FREE(new_memberstring
);
531 return (result
== 0 ? NT_STATUS_OK
: NT_STATUS_ACCESS_DENIED
);
534 struct aliasmem_closure
{
535 const DOM_SID
*alias
;
540 static int collect_aliasmem(TDB_CONTEXT
*tdb_ctx
, TDB_DATA key
, TDB_DATA data
,
543 struct aliasmem_closure
*closure
= (struct aliasmem_closure
*)state
;
545 fstring alias_string
;
547 if (strncmp(key
.dptr
, MEMBEROF_PREFIX
,
548 strlen(MEMBEROF_PREFIX
)) != 0)
553 while (next_token(&p
, alias_string
, " ", sizeof(alias_string
))) {
555 DOM_SID alias
, member
;
556 const char *member_string
;
559 if (!string_to_sid(&alias
, alias_string
))
562 if (sid_compare(closure
->alias
, &alias
) != 0)
565 /* Ok, we found the alias we're looking for in the membership
566 * list currently scanned. The key represents the alias
567 * member. Add that. */
569 member_string
= strchr(key
.dptr
, '/');
571 /* Above we tested for MEMBEROF_PREFIX which includes the
574 SMB_ASSERT(member_string
!= NULL
);
577 if (!string_to_sid(&member
, member_string
))
580 add_sid_to_array(NULL
, &member
, closure
->sids
, closure
->num
);
586 NTSTATUS
enum_aliasmem(const DOM_SID
*alias
, DOM_SID
**sids
, size_t *num
)
589 struct aliasmem_closure closure
;
591 if(!init_group_mapping()) {
592 DEBUG(0,("failed to initialize group mapping\n"));
593 return NT_STATUS_ACCESS_DENIED
;
596 if (!get_group_map_from_sid(*alias
, &map
))
597 return NT_STATUS_NO_SUCH_ALIAS
;
599 if ( (map
.sid_name_use
!= SID_NAME_ALIAS
) &&
600 (map
.sid_name_use
!= SID_NAME_WKN_GRP
) )
601 return NT_STATUS_NO_SUCH_ALIAS
;
606 closure
.alias
= alias
;
610 tdb_traverse(tdb
, collect_aliasmem
, &closure
);
614 NTSTATUS
del_aliasmem(const DOM_SID
*alias
, const DOM_SID
*member
)
625 result
= alias_memberships(member
, 1, &sids
, &num
);
627 if (!NT_STATUS_IS_OK(result
))
630 for (i
=0; i
<num
; i
++) {
631 if (sid_compare(&sids
[i
], alias
) == 0) {
639 return NT_STATUS_MEMBER_NOT_IN_ALIAS
;
643 sids
[i
] = sids
[num
-1];
647 sid_to_string(sid_string
, member
);
648 slprintf(key
, sizeof(key
), "%s%s", MEMBEROF_PREFIX
, sid_string
);
650 kbuf
.dsize
= strlen(key
)+1;
654 return tdb_delete(tdb
, kbuf
) == 0 ?
655 NT_STATUS_OK
: NT_STATUS_UNSUCCESSFUL
;
657 member_string
= SMB_STRDUP("");
659 if (member_string
== NULL
) {
661 return NT_STATUS_NO_MEMORY
;
664 for (i
=0; i
<num
; i
++) {
665 char *s
= member_string
;
667 sid_to_string(sid_string
, &sids
[i
]);
668 asprintf(&member_string
, "%s %s", s
, sid_string
);
671 if (member_string
== NULL
) {
673 return NT_STATUS_NO_MEMORY
;
677 dbuf
.dsize
= strlen(member_string
)+1;
678 dbuf
.dptr
= member_string
;
680 result
= tdb_store(tdb
, kbuf
, dbuf
, 0) == 0 ?
681 NT_STATUS_OK
: NT_STATUS_ACCESS_DENIED
;
684 SAFE_FREE(member_string
);