~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/lib/privileges.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   Unix SMB/CIFS implementation.
 
3
   Privileges handling functions
 
4
   Copyright (C) Jean François Micouleau        1998-2001
 
5
   Copyright (C) Simo Sorce                     2002-2003
 
6
   Copyright (C) Gerald (Jerry) Carter          2005
 
7
   Copyright (C) Michael Adam                   2007
 
8
 
 
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 3 of the License, or
 
12
   (at your option) any later version.
 
13
 
 
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.
 
18
 
 
19
   You should have received a copy of the GNU General Public License
 
20
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
21
*/
 
22
 
 
23
 
 
24
#include "includes.h"
 
25
 
 
26
#define PRIVPREFIX              "PRIV_"
 
27
 
 
28
typedef struct {
 
29
        size_t count;
 
30
        DOM_SID *list;
 
31
} SID_LIST;
 
32
 
 
33
typedef struct {
 
34
        TALLOC_CTX *mem_ctx;
 
35
        SE_PRIV privilege;
 
36
        SID_LIST sids;
 
37
} PRIV_SID_LIST;
 
38
 
 
39
 
 
40
static bool get_privileges( const DOM_SID *sid, SE_PRIV *mask )
 
41
{
 
42
        struct db_context *db = get_account_pol_db();
 
43
        fstring tmp, keystr;
 
44
        TDB_DATA data;
 
45
 
 
46
        /* Fail if the admin has not enable privileges */
 
47
 
 
48
        if ( !lp_enable_privileges() ) {
 
49
                return False;
 
50
        }
 
51
 
 
52
        if ( db == NULL )
 
53
                return False;
 
54
 
 
55
        /* PRIV_<SID> (NULL terminated) as the key */
 
56
 
 
57
        fstr_sprintf(keystr, "%s%s", PRIVPREFIX, sid_to_fstring(tmp, sid));
 
58
 
 
59
        data = dbwrap_fetch_bystring( db, talloc_tos(), keystr );
 
60
 
 
61
        if ( !data.dptr ) {
 
62
                DEBUG(3, ("get_privileges: No privileges assigned to SID "
 
63
                          "[%s]\n", sid_string_dbg(sid)));
 
64
                return False;
 
65
        }
 
66
 
 
67
        SMB_ASSERT( data.dsize == sizeof( SE_PRIV ) );
 
68
 
 
69
        se_priv_copy( mask, (SE_PRIV*)data.dptr );
 
70
        TALLOC_FREE(data.dptr);
 
71
 
 
72
        return True;
 
73
}
 
74
 
 
75
/***************************************************************************
 
76
 Store the privilege mask (set) for a given SID
 
77
****************************************************************************/
 
78
 
 
79
static bool set_privileges( const DOM_SID *sid, SE_PRIV *mask )
 
80
{
 
81
        struct db_context *db = get_account_pol_db();
 
82
        fstring tmp, keystr;
 
83
        TDB_DATA data;
 
84
 
 
85
        if ( !lp_enable_privileges() )
 
86
                return False;
 
87
 
 
88
        if ( db == NULL )
 
89
                return False;
 
90
 
 
91
        if ( !sid || (sid->num_auths == 0) ) {
 
92
                DEBUG(0,("set_privileges: Refusing to store empty SID!\n"));
 
93
                return False;
 
94
        }
 
95
 
 
96
        /* PRIV_<SID> (NULL terminated) as the key */
 
97
 
 
98
        fstr_sprintf(keystr, "%s%s", PRIVPREFIX, sid_to_fstring(tmp, sid));
 
99
 
 
100
        /* no packing.  static size structure, just write it out */
 
101
 
 
102
        data.dptr  = (uint8 *)mask;
 
103
        data.dsize = sizeof(SE_PRIV);
 
104
 
 
105
        return NT_STATUS_IS_OK(dbwrap_store_bystring(db, keystr, data,
 
106
                                                     TDB_REPLACE));
 
107
}
 
108
 
 
109
/*********************************************************************
 
110
 get a list of all privileges for all sids in the list
 
111
*********************************************************************/
 
112
 
 
113
bool get_privileges_for_sids(SE_PRIV *privileges, DOM_SID *slist, int scount)
 
114
{
 
115
        SE_PRIV mask;
 
116
        int i;
 
117
        bool found = False;
 
118
 
 
119
        se_priv_copy( privileges, &se_priv_none );
 
120
 
 
121
        for ( i=0; i<scount; i++ ) {
 
122
                /* don't add unless we actually have a privilege assigned */
 
123
 
 
124
                if ( !get_privileges( &slist[i], &mask ) )
 
125
                        continue;
 
126
 
 
127
                DEBUG(5,("get_privileges_for_sids: sid = %s\nPrivilege "
 
128
                         "set:\n", sid_string_dbg(&slist[i])));
 
129
                dump_se_priv( DBGC_ALL, 5, &mask );
 
130
 
 
131
                se_priv_add( privileges, &mask );
 
132
                found = True;
 
133
        }
 
134
 
 
135
        return found;
 
136
}
 
137
 
 
138
 
 
139
/*********************************************************************
 
140
 traversal functions for privilege_enumerate_accounts
 
141
*********************************************************************/
 
142
 
 
143
static int priv_traverse_fn(struct db_record *rec, void *state)
 
144
{
 
145
        PRIV_SID_LIST *priv = (PRIV_SID_LIST *)state;
 
146
        int  prefixlen = strlen(PRIVPREFIX);
 
147
        DOM_SID sid;
 
148
        fstring sid_string;
 
149
 
 
150
        /* easy check first */
 
151
 
 
152
        if (rec->value.dsize != sizeof(SE_PRIV) )
 
153
                return 0;
 
154
 
 
155
        /* check we have a PRIV_+SID entry */
 
156
 
 
157
        if ( strncmp((char *)rec->key.dptr, PRIVPREFIX, prefixlen) != 0)
 
158
                return 0;
 
159
 
 
160
        /* check to see if we are looking for a particular privilege */
 
161
 
 
162
        if ( !se_priv_equal(&priv->privilege, &se_priv_none) ) {
 
163
                SE_PRIV mask;
 
164
 
 
165
                se_priv_copy( &mask, (SE_PRIV*)rec->value.dptr );
 
166
 
 
167
                /* if the SID does not have the specified privilege
 
168
                   then just return */
 
169
 
 
170
                if ( !is_privilege_assigned( &mask, &priv->privilege) )
 
171
                        return 0;
 
172
        }
 
173
 
 
174
        fstrcpy( sid_string, (char *)&(rec->key.dptr[strlen(PRIVPREFIX)]) );
 
175
 
 
176
        /* this is a last ditch safety check to preventing returning
 
177
           and invalid SID (i've somehow run into this on development branches) */
 
178
 
 
179
        if ( strcmp( "S-0-0", sid_string ) == 0 )
 
180
                return 0;
 
181
 
 
182
        if ( !string_to_sid(&sid, sid_string) ) {
 
183
                DEBUG(0,("travsersal_fn_enum__acct: Could not convert SID [%s]\n",
 
184
                        sid_string));
 
185
                return 0;
 
186
        }
 
187
 
 
188
        if (!NT_STATUS_IS_OK(add_sid_to_array(priv->mem_ctx, &sid,
 
189
                                              &priv->sids.list,
 
190
                                              &priv->sids.count)))
 
191
        {
 
192
                return 0;
 
193
        }
 
194
 
 
195
        return 0;
 
196
}
 
197
 
 
198
/*********************************************************************
 
199
 Retreive list of privileged SIDs (for _lsa_enumerate_accounts()
 
200
*********************************************************************/
 
201
 
 
202
NTSTATUS privilege_enumerate_accounts(DOM_SID **sids, int *num_sids)
 
203
{
 
204
        struct db_context *db = get_account_pol_db();
 
205
        PRIV_SID_LIST priv;
 
206
 
 
207
        if (db == NULL) {
 
208
                return NT_STATUS_ACCESS_DENIED;
 
209
        }
 
210
 
 
211
        ZERO_STRUCT(priv);
 
212
 
 
213
        se_priv_copy( &priv.privilege, &se_priv_none );
 
214
 
 
215
        db->traverse_read(db, priv_traverse_fn, &priv);
 
216
 
 
217
        /* give the memory away; caller will free */
 
218
 
 
219
        *sids      = priv.sids.list;
 
220
        *num_sids  = priv.sids.count;
 
221
 
 
222
        return NT_STATUS_OK;
 
223
}
 
224
 
 
225
/*********************************************************************
 
226
 Retrieve list of SIDs granted a particular privilege
 
227
*********************************************************************/
 
228
 
 
229
NTSTATUS privilege_enum_sids(const SE_PRIV *mask, TALLOC_CTX *mem_ctx,
 
230
                             DOM_SID **sids, int *num_sids)
 
231
{
 
232
        struct db_context *db = get_account_pol_db();
 
233
        PRIV_SID_LIST priv;
 
234
 
 
235
        if (db == NULL) {
 
236
                return NT_STATUS_ACCESS_DENIED;
 
237
        }
 
238
 
 
239
        ZERO_STRUCT(priv);
 
240
 
 
241
        se_priv_copy(&priv.privilege, mask);
 
242
        priv.mem_ctx = mem_ctx;
 
243
 
 
244
        db->traverse_read(db, priv_traverse_fn, &priv);
 
245
 
 
246
        /* give the memory away; caller will free */
 
247
 
 
248
        *sids      = priv.sids.list;
 
249
        *num_sids  = priv.sids.count;
 
250
 
 
251
        return NT_STATUS_OK;
 
252
}
 
253
 
 
254
/***************************************************************************
 
255
 Add privilege to sid
 
256
****************************************************************************/
 
257
 
 
258
bool grant_privilege(const DOM_SID *sid, const SE_PRIV *priv_mask)
 
259
{
 
260
        SE_PRIV old_mask, new_mask;
 
261
 
 
262
        ZERO_STRUCT( old_mask );
 
263
        ZERO_STRUCT( new_mask );
 
264
 
 
265
        if ( get_privileges( sid, &old_mask ) )
 
266
                se_priv_copy( &new_mask, &old_mask );
 
267
        else
 
268
                se_priv_copy( &new_mask, &se_priv_none );
 
269
 
 
270
        se_priv_add( &new_mask, priv_mask );
 
271
 
 
272
        DEBUG(10,("grant_privilege: %s\n", sid_string_dbg(sid)));
 
273
 
 
274
        DEBUGADD( 10, ("original privilege mask:\n"));
 
275
        dump_se_priv( DBGC_ALL, 10, &old_mask );
 
276
 
 
277
        DEBUGADD( 10, ("new privilege mask:\n"));
 
278
        dump_se_priv( DBGC_ALL, 10, &new_mask );
 
279
 
 
280
        return set_privileges( sid, &new_mask );
 
281
}
 
282
 
 
283
/*********************************************************************
 
284
 Add a privilege based on its name
 
285
*********************************************************************/
 
286
 
 
287
bool grant_privilege_by_name(DOM_SID *sid, const char *name)
 
288
{
 
289
        SE_PRIV mask;
 
290
 
 
291
        if (! se_priv_from_name(name, &mask)) {
 
292
                DEBUG(3, ("grant_privilege_by_name: "
 
293
                          "No Such Privilege Found (%s)\n", name));
 
294
                return False;
 
295
        }
 
296
 
 
297
        return grant_privilege( sid, &mask );
 
298
}
 
299
 
 
300
/***************************************************************************
 
301
 Remove privilege from sid
 
302
****************************************************************************/
 
303
 
 
304
bool revoke_privilege(const DOM_SID *sid, const SE_PRIV *priv_mask)
 
305
{
 
306
        SE_PRIV mask;
 
307
 
 
308
        /* if the user has no privileges, then we can't revoke any */
 
309
 
 
310
        if ( !get_privileges( sid, &mask ) )
 
311
                return True;
 
312
 
 
313
        DEBUG(10,("revoke_privilege: %s\n", sid_string_dbg(sid)));
 
314
 
 
315
        DEBUGADD( 10, ("original privilege mask:\n"));
 
316
        dump_se_priv( DBGC_ALL, 10, &mask );
 
317
 
 
318
        se_priv_remove( &mask, priv_mask );
 
319
 
 
320
        DEBUGADD( 10, ("new privilege mask:\n"));
 
321
        dump_se_priv( DBGC_ALL, 10, &mask );
 
322
 
 
323
        return set_privileges( sid, &mask );
 
324
}
 
325
 
 
326
/*********************************************************************
 
327
 Revoke all privileges
 
328
*********************************************************************/
 
329
 
 
330
bool revoke_all_privileges( DOM_SID *sid )
 
331
{
 
332
        return revoke_privilege( sid, &se_priv_all );
 
333
}
 
334
 
 
335
/*********************************************************************
 
336
 Add a privilege based on its name
 
337
*********************************************************************/
 
338
 
 
339
bool revoke_privilege_by_name(DOM_SID *sid, const char *name)
 
340
{
 
341
        SE_PRIV mask;
 
342
 
 
343
        if (! se_priv_from_name(name, &mask)) {
 
344
                DEBUG(3, ("revoke_privilege_by_name: "
 
345
                          "No Such Privilege Found (%s)\n", name));
 
346
                return False;
 
347
        }
 
348
 
 
349
        return revoke_privilege(sid, &mask);
 
350
 
 
351
}
 
352
 
 
353
/***************************************************************************
 
354
 Retrieve the SIDs assigned to a given privilege
 
355
****************************************************************************/
 
356
 
 
357
NTSTATUS privilege_create_account(const DOM_SID *sid )
 
358
{
 
359
        return ( grant_privilege(sid, &se_priv_none) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL);
 
360
}
 
361
 
 
362
/***************************************************************************
 
363
 Delete a privileged account
 
364
****************************************************************************/
 
365
 
 
366
NTSTATUS privilege_delete_account(const struct dom_sid *sid)
 
367
{
 
368
        struct db_context *db = get_account_pol_db();
 
369
        fstring tmp, keystr;
 
370
 
 
371
        if (!lp_enable_privileges()) {
 
372
                return NT_STATUS_OK;
 
373
        }
 
374
 
 
375
        if (!db) {
 
376
                return NT_STATUS_INVALID_HANDLE;
 
377
        }
 
378
 
 
379
        if (!sid || (sid->num_auths == 0)) {
 
380
                return NT_STATUS_INVALID_SID;
 
381
        }
 
382
 
 
383
        /* PRIV_<SID> (NULL terminated) as the key */
 
384
 
 
385
        fstr_sprintf(keystr, "%s%s", PRIVPREFIX, sid_to_fstring(tmp, sid));
 
386
 
 
387
        return dbwrap_delete_bystring(db, keystr);
 
388
}
 
389
 
 
390
/****************************************************************************
 
391
 initialise a privilege list and set the talloc context
 
392
 ****************************************************************************/
 
393
 
 
394
NTSTATUS privilege_set_init(PRIVILEGE_SET *priv_set)
 
395
{
 
396
        TALLOC_CTX *mem_ctx;
 
397
 
 
398
        ZERO_STRUCTP( priv_set );
 
399
 
 
400
        mem_ctx = talloc_init("privilege set");
 
401
        if ( !mem_ctx ) {
 
402
                DEBUG(0,("privilege_set_init: failed to initialize talloc ctx!\n"));
 
403
                return NT_STATUS_NO_MEMORY;
 
404
        }
 
405
 
 
406
        priv_set->mem_ctx = mem_ctx;
 
407
 
 
408
        return NT_STATUS_OK;
 
409
}
 
410
 
 
411
/****************************************************************************
 
412
  initialise a privilege list and with someone else's talloc context
 
413
****************************************************************************/
 
414
 
 
415
NTSTATUS privilege_set_init_by_ctx(TALLOC_CTX *mem_ctx, PRIVILEGE_SET *priv_set)
 
416
{
 
417
        ZERO_STRUCTP( priv_set );
 
418
 
 
419
        priv_set->mem_ctx = mem_ctx;
 
420
        priv_set->ext_ctx = True;
 
421
 
 
422
        return NT_STATUS_OK;
 
423
}
 
424
 
 
425
/****************************************************************************
 
426
 Free all memory used by a PRIVILEGE_SET
 
427
****************************************************************************/
 
428
 
 
429
void privilege_set_free(PRIVILEGE_SET *priv_set)
 
430
{
 
431
        if ( !priv_set )
 
432
                return;
 
433
 
 
434
        if ( !( priv_set->ext_ctx ) )
 
435
                talloc_destroy( priv_set->mem_ctx );
 
436
 
 
437
        ZERO_STRUCTP( priv_set );
 
438
}
 
439
 
 
440
/****************************************************************************
 
441
 duplicate alloc luid_attr
 
442
 ****************************************************************************/
 
443
 
 
444
NTSTATUS dup_luid_attr(TALLOC_CTX *mem_ctx, LUID_ATTR **new_la, LUID_ATTR *old_la, int count)
 
445
{
 
446
        int i;
 
447
 
 
448
        if ( !old_la )
 
449
                return NT_STATUS_OK;
 
450
 
 
451
        if (count) {
 
452
                *new_la = TALLOC_ARRAY(mem_ctx, LUID_ATTR, count);
 
453
                if ( !*new_la ) {
 
454
                        DEBUG(0,("dup_luid_attr: failed to alloc new LUID_ATTR array [%d]\n", count));
 
455
                        return NT_STATUS_NO_MEMORY;
 
456
                }
 
457
        } else {
 
458
                *new_la = NULL;
 
459
        }
 
460
 
 
461
        for (i=0; i<count; i++) {
 
462
                (*new_la)[i].luid.high = old_la[i].luid.high;
 
463
                (*new_la)[i].luid.low = old_la[i].luid.low;
 
464
                (*new_la)[i].attr = old_la[i].attr;
 
465
        }
 
466
 
 
467
        return NT_STATUS_OK;
 
468
}
 
469
 
 
470
/*******************************************************************
 
471
*******************************************************************/
 
472
 
 
473
bool is_privileged_sid( const DOM_SID *sid )
 
474
{
 
475
        SE_PRIV mask;
 
476
 
 
477
        return get_privileges( sid, &mask );
 
478
}
 
479
 
 
480
/*******************************************************************
 
481
*******************************************************************/
 
482
 
 
483
bool grant_all_privileges( const DOM_SID *sid )
 
484
{
 
485
        SE_PRIV mask;
 
486
 
 
487
        if (!se_priv_put_all_privileges(&mask)) {
 
488
                return False;
 
489
        }
 
490
 
 
491
        return grant_privilege( sid, &mask );
 
492
}