~ubuntu-branches/ubuntu/maverick/samba/maverick-proposed

« back to all changes in this revision

Viewing changes to source/passdb/lookup_sid.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2004-10-15 12:31:58 UTC
  • Revision ID: james.westby@ubuntu.com-20041015123158-aokykzdqkdgy6dfx
Tags: upstream-3.0.7
ImportĀ upstreamĀ versionĀ 3.0.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Unix SMB/CIFS implementation.
 
3
   uid/user handling
 
4
   Copyright (C) Andrew Tridgell         1992-1998
 
5
   Copyright (C) Gerald (Jerry) Carter   2003
 
6
   
 
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.
 
11
   
 
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.
 
16
   
 
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.
 
20
*/
 
21
 
 
22
#include "includes.h"
 
23
 
 
24
/*****************************************************************
 
25
 *THE CANONICAL* convert name to SID function.
 
26
 Tries local lookup first - for local domains - then uses winbind.
 
27
*****************************************************************/  
 
28
 
 
29
BOOL lookup_name(const char *domain, const char *name, DOM_SID *psid, enum SID_NAME_USE *name_type)
 
30
{
 
31
        fstring sid;
 
32
        BOOL local_lookup = False;
 
33
        
 
34
        *name_type = SID_NAME_UNKNOWN;
 
35
 
 
36
        /* If we are looking up a domain user, make sure it is
 
37
           for the local machine only */
 
38
        
 
39
        if (strequal(domain, get_global_sam_name())) {
 
40
                if (local_lookup_name(name, psid, name_type)) {
 
41
                        DEBUG(10,
 
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));
 
45
                        return True;
 
46
                }
 
47
        } else {
 
48
                /* Remote */
 
49
                if (winbind_lookup_name(domain, name, psid, name_type)) {
 
50
                        
 
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));
 
54
                        return True;
 
55
                }
 
56
        }
 
57
        
 
58
        DEBUG(10, ("lookup_name: %s lookup for [%s]\\[%s] failed\n", 
 
59
                   local_lookup ? "local" : "winbind", domain, name));
 
60
 
 
61
        return False;
 
62
}
 
63
 
 
64
/*****************************************************************
 
65
 *THE CANONICAL* convert SID to name function.
 
66
 Tries local lookup first - for local sids, then tries winbind.
 
67
*****************************************************************/  
 
68
 
 
69
BOOL lookup_sid(const DOM_SID *sid, fstring dom_name, fstring name, enum SID_NAME_USE *name_type)
 
70
{
 
71
        if (!name_type)
 
72
                return False;
 
73
 
 
74
        *name_type = SID_NAME_UNKNOWN;
 
75
 
 
76
        /* Check if this is our own sid.  This should perhaps be done by
 
77
           winbind?  For the moment handle it here. */
 
78
 
 
79
        if (sid->num_auths == 5) {
 
80
                DOM_SID tmp_sid;
 
81
                uint32 rid;
 
82
 
 
83
                sid_copy(&tmp_sid, sid);
 
84
                sid_split_rid(&tmp_sid, &rid);
 
85
 
 
86
                if (sid_equal(get_global_sam_sid(), &tmp_sid)) {
 
87
 
 
88
                        return map_domain_sid_to_name(&tmp_sid, dom_name) &&
 
89
                                local_lookup_sid(sid, name, name_type);
 
90
                }
 
91
        }
 
92
 
 
93
        if (!winbind_lookup_sid(sid, dom_name, name, name_type)) {
 
94
                fstring sid_str;
 
95
                DOM_SID tmp_sid;
 
96
                uint32 rid;
 
97
 
 
98
                DEBUG(10,("lookup_sid: winbind lookup for SID %s failed - trying local.\n", sid_to_string(sid_str, sid) ));
 
99
 
 
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);
 
104
        }
 
105
        return True;
 
106
}
 
107
 
 
108
 
 
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
*****************************************************************/  
 
116
 
 
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
 
121
 
 
122
static size_t n_uid_sid_cache = 0;
 
123
static size_t n_gid_sid_cache = 0;
 
124
 
 
125
static struct uid_sid_cache {
 
126
        struct uid_sid_cache *next, *prev;
 
127
        uid_t uid;
 
128
        DOM_SID sid;
 
129
        enum SID_NAME_USE sidtype;
 
130
} *uid_sid_cache_head;
 
131
 
 
132
static struct gid_sid_cache {
 
133
        struct gid_sid_cache *next, *prev;
 
134
        gid_t gid;
 
135
        DOM_SID sid;
 
136
        enum SID_NAME_USE sidtype;
 
137
} *gid_sid_cache_head;
 
138
 
 
139
/*****************************************************************
 
140
  Find a SID given a uid.
 
141
*****************************************************************/  
 
142
 
 
143
static BOOL fetch_sid_from_uid_cache(DOM_SID *psid, uid_t uid)
 
144
{
 
145
        struct uid_sid_cache *pc;
 
146
 
 
147
        for (pc = uid_sid_cache_head; pc; pc = pc->next) {
 
148
                if (pc->uid == uid) {
 
149
                        fstring sid;
 
150
                        *psid = pc->sid;
 
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);
 
154
                        return True;
 
155
                }
 
156
        }
 
157
        return False;
 
158
}
 
159
 
 
160
/*****************************************************************
 
161
  Find a uid given a SID.
 
162
*****************************************************************/  
 
163
 
 
164
static BOOL fetch_uid_from_cache( uid_t *puid, const DOM_SID *psid )
 
165
{
 
166
        struct uid_sid_cache *pc;
 
167
 
 
168
        for (pc = uid_sid_cache_head; pc; pc = pc->next) {
 
169
                if (sid_compare(&pc->sid, psid) == 0) {
 
170
                        fstring sid;
 
171
                        *puid = pc->uid;
 
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);
 
175
                        return True;
 
176
                }
 
177
        }
 
178
        return False;
 
179
}
 
180
 
 
181
/*****************************************************************
 
182
 Store uid to SID mapping in cache.
 
183
*****************************************************************/  
 
184
 
 
185
static void store_uid_sid_cache(const DOM_SID *psid, uid_t uid)
 
186
{
 
187
        struct uid_sid_cache *pc;
 
188
 
 
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;
 
192
                size_t i;
 
193
 
 
194
                for (i = 0, pc = uid_sid_cache_head; i < (n_uid_sid_cache - TURNOVER_UID_SID_CACHE_SIZE); i++, pc = pc->next)
 
195
                        ;
 
196
                for(; pc; pc = pc_next) {
 
197
                        pc_next = pc->next;
 
198
                        DLIST_REMOVE(uid_sid_cache_head,pc);
 
199
                        SAFE_FREE(pc);
 
200
                        n_uid_sid_cache--;
 
201
                }
 
202
        }
 
203
 
 
204
        pc = (struct uid_sid_cache *)malloc(sizeof(struct uid_sid_cache));
 
205
        if (!pc)
 
206
                return;
 
207
        pc->uid = uid;
 
208
        sid_copy(&pc->sid, psid);
 
209
        DLIST_ADD(uid_sid_cache_head, pc);
 
210
        n_uid_sid_cache++;
 
211
}
 
212
 
 
213
/*****************************************************************
 
214
  Find a SID given a gid.
 
215
*****************************************************************/  
 
216
 
 
217
static BOOL fetch_sid_from_gid_cache(DOM_SID *psid, gid_t gid)
 
218
{
 
219
        struct gid_sid_cache *pc;
 
220
 
 
221
        for (pc = gid_sid_cache_head; pc; pc = pc->next) {
 
222
                if (pc->gid == gid) {
 
223
                        fstring sid;
 
224
                        *psid = pc->sid;
 
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);
 
228
                        return True;
 
229
                }
 
230
        }
 
231
        return False;
 
232
}
 
233
 
 
234
/*****************************************************************
 
235
  Find a gid given a SID.
 
236
*****************************************************************/  
 
237
 
 
238
static BOOL fetch_gid_from_cache(gid_t *pgid, const DOM_SID *psid)
 
239
{
 
240
        struct gid_sid_cache *pc;
 
241
 
 
242
        for (pc = gid_sid_cache_head; pc; pc = pc->next) {
 
243
                if (sid_compare(&pc->sid, psid) == 0) {
 
244
                        fstring sid;
 
245
                        *pgid = pc->gid;
 
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);
 
249
                        return True;
 
250
                }
 
251
        }
 
252
        return False;
 
253
}
 
254
 
 
255
/*****************************************************************
 
256
 Store gid to SID mapping in cache.
 
257
*****************************************************************/  
 
258
 
 
259
static void store_gid_sid_cache(const DOM_SID *psid, gid_t gid)
 
260
{
 
261
        struct gid_sid_cache *pc;
 
262
 
 
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;
 
266
                size_t i;
 
267
 
 
268
                for (i = 0, pc = gid_sid_cache_head; i < (n_gid_sid_cache - TURNOVER_GID_SID_CACHE_SIZE); i++, pc = pc->next)
 
269
                        ;
 
270
                for(; pc; pc = pc_next) {
 
271
                        pc_next = pc->next;
 
272
                        DLIST_REMOVE(gid_sid_cache_head,pc);
 
273
                        SAFE_FREE(pc);
 
274
                        n_gid_sid_cache--;
 
275
                }
 
276
        }
 
277
 
 
278
        pc = (struct gid_sid_cache *)malloc(sizeof(struct gid_sid_cache));
 
279
        if (!pc)
 
280
                return;
 
281
        pc->gid = gid;
 
282
        sid_copy(&pc->sid, psid);
 
283
        DLIST_ADD(gid_sid_cache_head, pc);
 
284
        n_gid_sid_cache++;
 
285
}
 
286
 
 
287
/*****************************************************************
 
288
 *THE CANONICAL* convert uid_t to SID function.
 
289
*****************************************************************/  
 
290
 
 
291
NTSTATUS uid_to_sid(DOM_SID *psid, uid_t uid)
 
292
{
 
293
        fstring sid;
 
294
        uid_t low, high;
 
295
 
 
296
        ZERO_STRUCTP(psid);
 
297
 
 
298
        if (fetch_sid_from_uid_cache(psid, uid))
 
299
                return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
 
300
 
 
301
        /* DC's never use winbindd to resolve users outside the 
 
302
           defined idmap range */
 
303
 
 
304
        if ( lp_server_role()==ROLE_DOMAIN_MEMBER 
 
305
                || (lp_idmap_uid(&low, &high) && uid >= low && uid <= high) ) 
 
306
        {
 
307
                if (winbind_uid_to_sid(psid, uid)) {
 
308
 
 
309
                        DEBUG(10,("uid_to_sid: winbindd %u -> %s\n",
 
310
                                (unsigned int)uid, sid_to_string(sid, psid)));
 
311
 
 
312
                        if (psid)
 
313
                                store_uid_sid_cache(psid, uid);
 
314
                        return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
 
315
                }
 
316
        }
 
317
 
 
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;
 
321
        }
 
322
        
 
323
        DEBUG(10,("uid_to_sid: local %u -> %s\n", (unsigned int)uid, sid_to_string(sid, psid)));
 
324
 
 
325
        store_uid_sid_cache(psid, uid);
 
326
        return NT_STATUS_OK;
 
327
}
 
328
 
 
329
/*****************************************************************
 
330
 *THE CANONICAL* convert gid_t to SID function.
 
331
*****************************************************************/  
 
332
 
 
333
NTSTATUS gid_to_sid(DOM_SID *psid, gid_t gid)
 
334
{
 
335
        fstring sid;
 
336
        gid_t low, high;
 
337
 
 
338
        ZERO_STRUCTP(psid);
 
339
 
 
340
        if (fetch_sid_from_gid_cache(psid, gid))
 
341
                return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
 
342
 
 
343
        /* DC's never use winbindd to resolve groups outside the
 
344
           defined idmap range */
 
345
 
 
346
        if ( lp_server_role()==ROLE_DOMAIN_MEMBER
 
347
                || (lp_idmap_gid(&low, &high) && gid >= low && gid <= high) )
 
348
        {
 
349
                if (winbind_gid_to_sid(psid, gid)) {
 
350
 
 
351
                        DEBUG(10,("gid_to_sid: winbindd %u -> %s\n",
 
352
                                (unsigned int)gid, sid_to_string(sid, psid)));
 
353
                        
 
354
                        if (psid)
 
355
                                store_gid_sid_cache(psid, gid);
 
356
                        return ( psid ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL );
 
357
                }
 
358
        }
 
359
 
 
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;
 
363
        }
 
364
        
 
365
        DEBUG(10,("gid_to_sid: local %u -> %s\n", (unsigned int)gid, sid_to_string(sid, psid)));
 
366
 
 
367
        store_gid_sid_cache(psid, gid);
 
368
        return NT_STATUS_OK;
 
369
}
 
370
 
 
371
/*****************************************************************
 
372
 *THE CANONICAL* convert SID to uid function.
 
373
*****************************************************************/  
 
374
 
 
375
NTSTATUS sid_to_uid(const DOM_SID *psid, uid_t *puid)
 
376
{
 
377
        fstring dom_name, name, sid_str;
 
378
        enum SID_NAME_USE name_type;
 
379
 
 
380
        if (fetch_uid_from_cache(puid, psid))
 
381
                return NT_STATUS_OK;
 
382
 
 
383
        /* if this is our SID then go straight to a local lookup */
 
384
        
 
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) ));
 
388
                
 
389
                if ( local_sid_to_uid(puid, psid, &name_type) )
 
390
                        goto success;
 
391
                        
 
392
                DEBUG(10,("sid_to_uid: local lookup failed\n"));
 
393
                
 
394
                return NT_STATUS_UNSUCCESSFUL;
 
395
        }
 
396
        
 
397
        /* If it is not our local domain, only hope is winbindd */
 
398
 
 
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) ));
 
402
                        
 
403
                return NT_STATUS_UNSUCCESSFUL;
 
404
        }
 
405
 
 
406
        /* If winbindd does know the SID, ensure this is a user */
 
407
 
 
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;
 
412
        }
 
413
 
 
414
        /* get the uid.  Has to work or else we are dead in the water */
 
415
 
 
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;
 
420
        }
 
421
 
 
422
success:
 
423
        DEBUG(10,("sid_to_uid: %s -> %u\n", sid_to_string(sid_str, psid),
 
424
                (unsigned int)*puid ));
 
425
 
 
426
        store_uid_sid_cache(psid, *puid);
 
427
        
 
428
        return NT_STATUS_OK;
 
429
}
 
430
/*****************************************************************
 
431
 *THE CANONICAL* convert SID to gid function.
 
432
 Group mapping is used for gids that maps to Wellknown SIDs
 
433
*****************************************************************/  
 
434
 
 
435
NTSTATUS sid_to_gid(const DOM_SID *psid, gid_t *pgid)
 
436
{
 
437
        fstring dom_name, name, sid_str;
 
438
        enum SID_NAME_USE name_type;
 
439
 
 
440
        if (fetch_gid_from_cache(pgid, psid))
 
441
                return NT_STATUS_OK;
 
442
 
 
443
        /*
 
444
         * First we must look up the name and decide if this is a group sid.
 
445
         * Group mapping can deal with foreign SIDs
 
446
         */
 
447
 
 
448
        if ( local_sid_to_gid(pgid, psid, &name_type) )
 
449
                goto success;
 
450
        
 
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)));
 
453
                
 
454
                return NT_STATUS_UNSUCCESSFUL;
 
455
        }
 
456
 
 
457
        /* winbindd knows it; Ensure this is a group sid */
 
458
 
 
459
        if ((name_type != SID_NAME_DOM_GRP) && (name_type != SID_NAME_ALIAS) 
 
460
                && (name_type != SID_NAME_WKN_GRP)) 
 
461
        {
 
462
                DEBUG(10,("sid_to_gid: winbind lookup succeeded but SID is not a known group (%u)\n",
 
463
                        (unsigned int)name_type ));
 
464
 
 
465
                /* winbindd is running and knows about this SID.  Just the wrong type.
 
466
                   Don't fallback to a local lookup here */
 
467
                   
 
468
                return NT_STATUS_INVALID_PARAMETER;
 
469
        }
 
470
        
 
471
        /* winbindd knows it and it is a type of group; sid_to_gid must succeed
 
472
           or we are dead in the water */
 
473
 
 
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;
 
478
        }
 
479
 
 
480
success:
 
481
        DEBUG(10,("sid_to_gid: %s -> %u\n", sid_to_string(sid_str, psid),
 
482
                (unsigned int)*pgid ));
 
483
 
 
484
        store_gid_sid_cache(psid, *pgid);
 
485
        
 
486
        return NT_STATUS_OK;
 
487
}
 
488