2
Unix SMB/CIFS implementation.
4
Copyright (C) Andrew Tridgell 1992-1998
5
Copyright (C) Gerald (Jerry) Carter 2003
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24
/*****************************************************************
25
*THE CANONICAL* convert name to SID function.
26
Tries local lookup first - for local domains - then uses winbind.
27
*****************************************************************/
29
BOOL lookup_name(const char *domain, const char *name, DOM_SID *psid, enum SID_NAME_USE *name_type)
32
BOOL local_lookup = False;
34
*name_type = SID_NAME_UNKNOWN;
36
/* If we are looking up a domain user, make sure it is
37
for the local machine only */
39
if (strequal(domain, get_global_sam_name())) {
40
if (local_lookup_name(name, psid, name_type)) {
42
("lookup_name: (local) [%s]\\[%s] -> SID %s (type %s: %u)\n",
43
domain, name, sid_to_string(sid,psid),
44
sid_type_lookup(*name_type), (unsigned int)*name_type));
49
if (winbind_lookup_name(domain, name, psid, name_type)) {
51
DEBUG(10,("lookup_name (winbindd): [%s]\\[%s] -> SID %s (type %u)\n",
52
domain, name, sid_to_string(sid, psid),
53
(unsigned int)*name_type));
58
DEBUG(10, ("lookup_name: %s lookup for [%s]\\[%s] failed\n",
59
local_lookup ? "local" : "winbind", domain, name));
64
/*****************************************************************
65
*THE CANONICAL* convert SID to name function.
66
Tries local lookup first - for local sids, then tries winbind.
67
*****************************************************************/
69
BOOL lookup_sid(const DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE *name_type)
74
*name_type = SID_NAME_UNKNOWN;
76
/* Check if this is our own sid. This should perhaps be done by
77
winbind? For the moment handle it here. */
79
if (sid->num_auths == 5) {
83
sid_copy(&tmp_sid, sid);
84
sid_split_rid(&tmp_sid, &rid);
86
if (sid_equal(get_global_sam_sid(), &tmp_sid)) {
88
return map_domain_sid_to_name(&tmp_sid, dom_name) &&
89
local_lookup_sid(sid, name, name_type);
93
if (!winbind_lookup_sid(sid, dom_name, name, name_type)) {
98
DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying local.\n", sid_to_string(sid_str, sid) ));
100
sid_copy(&tmp_sid, sid);
101
sid_split_rid(&tmp_sid, &rid);
102
return map_domain_sid_to_name(&tmp_sid, dom_name) &&
103
lookup_known_rid(&tmp_sid, rid, name, name_type);
109
/*****************************************************************
110
Id mapping cache. This is to avoid Winbind mappings already
111
seen by smbd to be queried too frequently, keeping winbindd
112
busy, and blocking smbd while winbindd is busy with other
113
stuff. Written by Michael Steffens <michael.steffens@hp.com>,
114
modified to use linked lists by jra.
115
*****************************************************************/
117
#define MAX_UID_SID_CACHE_SIZE 100
118
#define TURNOVER_UID_SID_CACHE_SIZE 10
119
#define MAX_GID_SID_CACHE_SIZE 100
120
#define TURNOVER_GID_SID_CACHE_SIZE 10
122
static size_t n_uid_sid_cache = 0;
123
static size_t n_gid_sid_cache = 0;
125
static struct uid_sid_cache {
126
struct uid_sid_cache *next, *prev;
129
enum SID_NAME_USE sidtype;
130
} *uid_sid_cache_head;
132
static struct gid_sid_cache {
133
struct gid_sid_cache *next, *prev;
136
enum SID_NAME_USE sidtype;
137
} *gid_sid_cache_head;
139
/*****************************************************************
140
Find a SID given a uid.
141
*****************************************************************/
143
static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
145
struct uid_sid_cache *pc;
147
for (pc = uid_sid_cache_head; pc; pc = pc->next) {
148
if (pc->uid == uid) {
151
DEBUG(3,("fetch sid from uid cache %u -> %s\n",
152
(unsigned int)uid, sid_to_string(sid, psid)));
153
DLIST_PROMOTE(uid_sid_cache_head, pc);
160
/*****************************************************************
161
Find a uid given a SID.
162
*****************************************************************/
164
static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
166
struct uid_sid_cache *pc;
168
for (pc = uid_sid_cache_head; pc; pc = pc->next) {
169
if (sid_compare(&pc->sid, psid) == 0) {
172
DEBUG(3,("fetch uid from cache %u -> %s\n",
173
(unsigned int)*puid, sid_to_string(sid, psid)));
174
DLIST_PROMOTE(uid_sid_cache_head, pc);
181
/*****************************************************************
182
Store uid to SID mapping in cache.
183
*****************************************************************/
185
static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
187
struct uid_sid_cache *pc;
189
if (n_uid_sid_cache >= MAX_UID_SID_CACHE_SIZE && n_uid_sid_cache > TURNOVER_UID_SID_CACHE_SIZE) {
190
/* Delete the last TURNOVER_UID_SID_CACHE_SIZE entries. */
191
struct uid_sid_cache *pc_next;
194
for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
196
for(; pc; pc = pc_next) {
198
DLIST_REMOVE(uid_sid_cache_head,pc);
204
pc = (struct uid_sid_cache *)malloc(sizeof(struct uid_sid_cache));
208
sid_copy(&pc->sid, psid);
209
DLIST_ADD(uid_sid_cache_head, pc);
213
/*****************************************************************
214
Find a SID given a gid.
215
*****************************************************************/
217
static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
219
struct gid_sid_cache *pc;
221
for (pc = gid_sid_cache_head; pc; pc = pc->next) {
222
if (pc->gid == gid) {
225
DEBUG(3,("fetch sid from gid cache %u -> %s\n",
226
(unsigned int)gid, sid_to_string(sid, psid)));
227
DLIST_PROMOTE(gid_sid_cache_head, pc);
234
/*****************************************************************
235
Find a gid given a SID.
236
*****************************************************************/
238
static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
240
struct gid_sid_cache *pc;
242
for (pc = gid_sid_cache_head; pc; pc = pc->next) {
243
if (sid_compare(&pc->sid, psid) == 0) {
246
DEBUG(3,("fetch uid from cache %u -> %s\n",
247
(unsigned int)*pgid, sid_to_string(sid, psid)));
248
DLIST_PROMOTE(gid_sid_cache_head, pc);
255
/*****************************************************************
256
Store gid to SID mapping in cache.
257
*****************************************************************/
259
static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
261
struct gid_sid_cache *pc;
263
if (n_gid_sid_cache >= MAX_GID_SID_CACHE_SIZE && n_gid_sid_cache > TURNOVER_GID_SID_CACHE_SIZE) {
264
/* Delete the last TURNOVER_GID_SID_CACHE_SIZE entries. */
265
struct gid_sid_cache *pc_next;
268
for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
270
for(; pc; pc = pc_next) {
272
DLIST_REMOVE(gid_sid_cache_head,pc);
278
pc = (struct gid_sid_cache *)malloc(sizeof(struct gid_sid_cache));
282
sid_copy(&pc->sid, psid);
283
DLIST_ADD(gid_sid_cache_head, pc);
287
/*****************************************************************
288
*THE CANONICAL* convert uid_t to SID function.
289
*****************************************************************/
291
NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid)
298
if (fetch_sid_from_uid_cache(psid, uid))
299
return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
301
/* DC's never use winbindd to resolve users outside the
302
defined idmap range */
304
if ( lp_server_role()==ROLE_DOMAIN_MEMBER
305
|| (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) )
307
if (winbind_uid_to_sid(psid, uid)) {
309
DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
310
(unsigned int)uid, sid_to_string(sid, psid)));
313
store_uid_sid_cache(psid, uid);
314
return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
318
if (!local_uid_to_sid(psid, uid)) {
319
DEBUG(10,("uid_to_sid: local %u failed to map to sid\n", (unsigned int)uid ));
320
return NT_STATUS_UNSUCCESSFUL;
323
DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
325
store_uid_sid_cache(psid, uid);
329
/*****************************************************************
330
*THE CANONICAL* convert gid_t to SID function.
331
*****************************************************************/
333
NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid)
340
if (fetch_sid_from_gid_cache(psid, gid))
341
return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
343
/* DC's never use winbindd to resolve groups outside the
344
defined idmap range */
346
if ( lp_server_role()==ROLE_DOMAIN_MEMBER
347
|| (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) )
349
if (winbind_gid_to_sid(psid, gid)) {
351
DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
352
(unsigned int)gid, sid_to_string(sid, psid)));
355
store_gid_sid_cache(psid, gid);
356
return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
360
if (!local_gid_to_sid(psid, gid)) {
361
DEBUG(10,("gid_to_sid: local %u failed to map to sid\n", (unsigned int)gid ));
362
return NT_STATUS_UNSUCCESSFUL;
365
DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
367
store_gid_sid_cache(psid, gid);
371
/*****************************************************************
372
*THE CANONICAL* convert SID to uid function.
373
*****************************************************************/
375
NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid)
377
fstring dom_name, name, sid_str;
378
enum SID_NAME_USE name_type;
380
if (fetch_uid_from_cache(puid, psid))
383
/* if this is our SID then go straight to a local lookup */
385
if ( sid_compare_domain(get_global_sam_sid(), psid) == 0 ) {
386
DEBUG(10,("sid_to_uid: my domain (%s) - trying local.\n",
387
sid_string_static(psid) ));
389
if ( local_sid_to_uid(puid, psid, &name_type) )
392
DEBUG(10,("sid_to_uid: local lookup failed\n"));
394
return NT_STATUS_UNSUCCESSFUL;
397
/* If it is not our local domain, only hope is winbindd */
399
if ( !winbind_lookup_sid(psid, dom_name, name, &name_type) ) {
400
DEBUG(10,("sid_to_uid: winbind lookup for non-local sid %s failed\n",
401
sid_string_static(psid) ));
403
return NT_STATUS_UNSUCCESSFUL;
406
/* If winbindd does know the SID, ensure this is a user */
408
if (name_type != SID_NAME_USER) {
409
DEBUG(10,("sid_to_uid: winbind lookup succeeded but SID is not a user (%u)\n",
410
(unsigned int)name_type ));
411
return NT_STATUS_INVALID_PARAMETER;
414
/* get the uid. Has to work or else we are dead in the water */
416
if ( !winbind_sid_to_uid(puid, psid) ) {
417
DEBUG(10,("sid_to_uid: winbind failed to allocate a new uid for sid %s\n",
418
sid_to_string(sid_str, psid) ));
419
return NT_STATUS_UNSUCCESSFUL;
423
DEBUG(10,("sid_to_uid: %s -> %u\n", sid_to_string(sid_str, psid),
424
(unsigned int)*puid ));
426
store_uid_sid_cache(psid, *puid);
430
/*****************************************************************
431
*THE CANONICAL* convert SID to gid function.
432
Group mapping is used for gids that maps to Wellknown SIDs
433
*****************************************************************/
435
NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid)
437
fstring dom_name, name, sid_str;
438
enum SID_NAME_USE name_type;
440
if (fetch_gid_from_cache(pgid, psid))
444
* First we must look up the name and decide if this is a group sid.
445
* Group mapping can deal with foreign SIDs
448
if ( local_sid_to_gid(pgid, psid, &name_type) )
451
if (!winbind_lookup_sid(psid, dom_name, name, &name_type)) {
452
DEBUG(10,("sid_to_gid: no one knows the SID %s (tried local, then winbind)\n", sid_to_string(sid_str, psid)));
454
return NT_STATUS_UNSUCCESSFUL;
457
/* winbindd knows it; Ensure this is a group sid */
459
if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS)
460
&& (name_type != SID_NAME_WKN_GRP))
462
DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
463
(unsigned int)name_type ));
465
/* winbindd is running and knows about this SID. Just the wrong type.
466
Don't fallback to a local lookup here */
468
return NT_STATUS_INVALID_PARAMETER;
471
/* winbindd knows it and it is a type of group; sid_to_gid must succeed
472
or we are dead in the water */
474
if ( !winbind_sid_to_gid(pgid, psid) ) {
475
DEBUG(10,("sid_to_uid: winbind failed to allocate a new gid for sid %s\n",
476
sid_to_string(sid_str, psid) ));
477
return NT_STATUS_UNSUCCESSFUL;
481
DEBUG(10,("sid_to_gid: %s -> %u\n", sid_to_string(sid_str, psid),
482
(unsigned int)*pgid ));
484
store_gid_sid_cache(psid, *pgid);