00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "includes.h"
00025
00026 #define PRIVPREFIX "PRIV_"
00027
00028 static const SE_PRIV se_priv_all = SE_ALL_PRIVS;
00029 static const SE_PRIV se_priv_end = SE_END;
00030
00031
00032
00033
00034 const SE_PRIV se_priv_none = SE_NONE;
00035 const SE_PRIV se_machine_account = SE_MACHINE_ACCOUNT;
00036 const SE_PRIV se_print_operator = SE_PRINT_OPERATOR;
00037 const SE_PRIV se_add_users = SE_ADD_USERS;
00038 const SE_PRIV se_disk_operators = SE_DISK_OPERATOR;
00039 const SE_PRIV se_remote_shutdown = SE_REMOTE_SHUTDOWN;
00040 const SE_PRIV se_restore = SE_RESTORE;
00041 const SE_PRIV se_take_ownership = SE_TAKE_OWNERSHIP;
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 PRIVS privs[] = {
00085 #if 0
00086
00087
00088 {SE_NETWORK_LOGON, "SeNetworkLogonRight", "Access this computer from network", { 0x0, 0x0 }},
00089 {SE_INTERACTIVE_LOGON, "SeInteractiveLogonRight", "Log on locally", { 0x0, 0x0 }},
00090 {SE_BATCH_LOGON, "SeBatchLogonRight", "Log on as a batch job", { 0x0, 0x0 }},
00091 {SE_SERVICE_LOGON, "SeServiceLogonRight", "Log on as a service", { 0x0, 0x0 }},
00092 #endif
00093 {SE_MACHINE_ACCOUNT, "SeMachineAccountPrivilege", "Add machines to domain", { 0x0, 0x0006 }},
00094 {SE_TAKE_OWNERSHIP, "SeTakeOwnershipPrivilege", "Take ownership of files or other objects",{ 0x0, 0x0009 }},
00095 {SE_BACKUP, "SeBackupPrivilege", "Back up files and directories", { 0x0, 0x0011 }},
00096 {SE_RESTORE, "SeRestorePrivilege", "Restore files and directories", { 0x0, 0x0012 }},
00097 {SE_REMOTE_SHUTDOWN, "SeRemoteShutdownPrivilege", "Force shutdown from a remote system", { 0x0, 0x0018 }},
00098
00099 {SE_PRINT_OPERATOR, "SePrintOperatorPrivilege", "Manage printers", { 0x0, 0x1001 }},
00100 {SE_ADD_USERS, "SeAddUsersPrivilege", "Add users and groups to the domain", { 0x0, 0x1002 }},
00101 {SE_DISK_OPERATOR, "SeDiskOperatorPrivilege", "Manage disk shares", { 0x0, 0x1003 }},
00102
00103 {SE_END, "", "", { 0x0, 0x0 }}
00104 };
00105
00106 typedef struct {
00107 size_t count;
00108 DOM_SID *list;
00109 } SID_LIST;
00110
00111 typedef struct {
00112 SE_PRIV privilege;
00113 SID_LIST sids;
00114 } PRIV_SID_LIST;
00115
00116
00117
00118
00119
00120 BOOL se_priv_copy( SE_PRIV *dst, const SE_PRIV *src )
00121 {
00122 if ( !dst || !src )
00123 return False;
00124
00125 memcpy( dst, src, sizeof(SE_PRIV) );
00126
00127 return True;
00128 }
00129
00130
00131
00132
00133
00134 void se_priv_add( SE_PRIV *mask, const SE_PRIV *addpriv )
00135 {
00136 int i;
00137
00138 for ( i=0; i<SE_PRIV_MASKSIZE; i++ ) {
00139 mask->mask[i] |= addpriv->mask[i];
00140 }
00141 }
00142
00143
00144
00145
00146
00147
00148 void se_priv_remove( SE_PRIV *mask, const SE_PRIV *removepriv )
00149 {
00150 int i;
00151
00152 for ( i=0; i<SE_PRIV_MASKSIZE; i++ ) {
00153 mask->mask[i] &= ~removepriv->mask[i];
00154 }
00155 }
00156
00157
00158
00159
00160
00161 static void se_priv_invert( SE_PRIV *new_mask, const SE_PRIV *mask )
00162 {
00163 SE_PRIV allprivs;
00164
00165 se_priv_copy( &allprivs, &se_priv_all );
00166 se_priv_remove( &allprivs, mask );
00167 se_priv_copy( new_mask, &allprivs );
00168 }
00169
00170
00171
00172
00173
00174 static BOOL se_priv_equal( const SE_PRIV *mask1, const SE_PRIV *mask2 )
00175 {
00176 return ( memcmp(mask1, mask2, sizeof(SE_PRIV)) == 0 );
00177 }
00178
00179
00180
00181
00182
00183 static BOOL se_priv_empty( const SE_PRIV *mask )
00184 {
00185 SE_PRIV p1;
00186 int i;
00187
00188 se_priv_copy( &p1, mask );
00189
00190 for ( i=0; i<SE_PRIV_MASKSIZE; i++ ) {
00191 p1.mask[i] &= se_priv_all.mask[i];
00192 }
00193
00194 return se_priv_equal( &p1, &se_priv_none );
00195 }
00196
00197
00198
00199
00200
00201 BOOL se_priv_from_name( const char *name, SE_PRIV *mask )
00202 {
00203 int i;
00204
00205 for ( i=0; !se_priv_equal(&privs[i].se_priv, &se_priv_end); i++ ) {
00206 if ( strequal( privs[i].name, name ) ) {
00207 se_priv_copy( mask, &privs[i].se_priv );
00208 return True;
00209 }
00210 }
00211
00212 return False;
00213 }
00214
00215
00216
00217
00218
00219 void dump_se_priv( int dbg_cl, int dbg_lvl, const SE_PRIV *mask )
00220 {
00221 int i;
00222
00223 DEBUGADDC( dbg_cl, dbg_lvl,("SE_PRIV "));
00224
00225 for ( i=0; i<SE_PRIV_MASKSIZE; i++ ) {
00226 DEBUGADDC( dbg_cl, dbg_lvl,(" 0x%x", mask->mask[i] ));
00227 }
00228
00229 DEBUGADDC( dbg_cl, dbg_lvl, ("\n"));
00230 }
00231
00232
00233
00234
00235
00236 static BOOL get_privileges( const DOM_SID *sid, SE_PRIV *mask )
00237 {
00238 TDB_CONTEXT *tdb = get_account_pol_tdb();
00239 fstring keystr;
00240 TDB_DATA key, data;
00241
00242
00243
00244 if ( !lp_enable_privileges() ) {
00245 return False;
00246 }
00247
00248 if ( !tdb )
00249 return False;
00250
00251
00252
00253 fstr_sprintf( keystr, "%s%s", PRIVPREFIX, sid_string_static(sid) );
00254 key.dptr = keystr;
00255 key.dsize = strlen(keystr) + 1;
00256
00257 data = tdb_fetch( tdb, key );
00258
00259 if ( !data.dptr ) {
00260 DEBUG(3,("get_privileges: No privileges assigned to SID [%s]\n",
00261 sid_string_static(sid)));
00262 return False;
00263 }
00264
00265 SMB_ASSERT( data.dsize == sizeof( SE_PRIV ) );
00266
00267 se_priv_copy( mask, (SE_PRIV*)data.dptr );
00268 SAFE_FREE(data.dptr);
00269
00270 return True;
00271 }
00272
00273
00274
00275
00276
00277 static BOOL set_privileges( const DOM_SID *sid, SE_PRIV *mask )
00278 {
00279 TDB_CONTEXT *tdb = get_account_pol_tdb();
00280 fstring keystr;
00281 TDB_DATA key, data;
00282
00283 if ( !lp_enable_privileges() )
00284 return False;
00285
00286 if ( !tdb )
00287 return False;
00288
00289 if ( !sid || (sid->num_auths == 0) ) {
00290 DEBUG(0,("set_privileges: Refusing to store empty SID!\n"));
00291 return False;
00292 }
00293
00294
00295
00296 fstr_sprintf( keystr, "%s%s", PRIVPREFIX, sid_string_static(sid) );
00297 key.dptr = keystr;
00298 key.dsize = strlen(keystr) + 1;
00299
00300
00301
00302 data.dptr = (char*)mask;
00303 data.dsize = sizeof(SE_PRIV);
00304
00305 return ( tdb_store(tdb, key, data, TDB_REPLACE) != -1 );
00306 }
00307
00308
00309
00310
00311
00312 static BOOL is_privilege_assigned( const SE_PRIV *privileges,
00313 const SE_PRIV *check )
00314 {
00315 SE_PRIV p1, p2;
00316
00317 if ( !privileges || !check )
00318 return False;
00319
00320
00321
00322 if ( se_priv_empty( check ) ) {
00323 DEBUG(1,("is_privilege_assigned: no privileges in check_mask!\n"));
00324 return True;
00325 }
00326
00327 se_priv_copy( &p1, check );
00328
00329
00330
00331
00332
00333 se_priv_invert( &p1, check );
00334 se_priv_copy( &p2, privileges );
00335 se_priv_remove( &p2, &p1 );
00336
00337 return se_priv_equal( &p2, check );
00338 }
00339
00340
00341
00342
00343
00344 static BOOL is_any_privilege_assigned( SE_PRIV *privileges, const SE_PRIV *check )
00345 {
00346 SE_PRIV p1, p2;
00347
00348 if ( !privileges || !check )
00349 return False;
00350
00351
00352
00353 if ( se_priv_empty( check ) ) {
00354 DEBUG(1,("is_any_privilege_assigned: no privileges in check_mask!\n"));
00355 return True;
00356 }
00357
00358 se_priv_copy( &p1, check );
00359
00360
00361
00362
00363
00364 se_priv_invert( &p1, check );
00365 se_priv_copy( &p2, privileges );
00366 se_priv_remove( &p2, &p1 );
00367
00368
00369
00370 return !se_priv_empty( &p2 );
00371 }
00372
00373
00374
00375
00376
00377 static BOOL privilege_set_add(PRIVILEGE_SET *priv_set, LUID_ATTR set)
00378 {
00379 LUID_ATTR *new_set;
00380
00381
00382
00383 new_set = TALLOC_REALLOC_ARRAY(priv_set->mem_ctx, priv_set->set, LUID_ATTR, priv_set->count + 1);
00384 if ( !new_set ) {
00385 DEBUG(0,("privilege_set_add: failed to allocate memory!\n"));
00386 return False;
00387 }
00388
00389 new_set[priv_set->count].luid.high = set.luid.high;
00390 new_set[priv_set->count].luid.low = set.luid.low;
00391 new_set[priv_set->count].attr = set.attr;
00392
00393 priv_set->count++;
00394 priv_set->set = new_set;
00395
00396 return True;
00397 }
00398
00399
00400
00401
00402
00403
00404
00405 LUID_ATTR get_privilege_luid( SE_PRIV *mask )
00406 {
00407 LUID_ATTR priv_luid;
00408 int i;
00409
00410 ZERO_STRUCT( priv_luid );
00411
00412 for ( i=0; !se_priv_equal(&privs[i].se_priv, &se_priv_end); i++ ) {
00413
00414 if ( se_priv_equal( &privs[i].se_priv, mask ) ) {
00415 priv_luid.luid = privs[i].luid;
00416 break;
00417 }
00418 }
00419
00420 return priv_luid;
00421 }
00422
00423
00424
00425
00426
00427 const char* get_privilege_dispname( const char *name )
00428 {
00429 int i;
00430
00431 for ( i=0; !se_priv_equal(&privs[i].se_priv, &se_priv_end); i++ ) {
00432
00433 if ( strequal( privs[i].name, name ) ) {
00434 return privs[i].description;
00435 }
00436 }
00437
00438 return NULL;
00439 }
00440
00441
00442
00443
00444
00445 BOOL get_privileges_for_sids(SE_PRIV *privileges, DOM_SID *slist, int scount)
00446 {
00447 SE_PRIV mask;
00448 int i;
00449 BOOL found = False;
00450
00451 se_priv_copy( privileges, &se_priv_none );
00452
00453 for ( i=0; i<scount; i++ ) {
00454
00455
00456 if ( !get_privileges( &slist[i], &mask ) )
00457 continue;
00458
00459 DEBUG(5,("get_privileges_for_sids: sid = %s\nPrivilege set:\n",
00460 sid_string_static(&slist[i])));
00461 dump_se_priv( DBGC_ALL, 5, &mask );
00462
00463 se_priv_add( privileges, &mask );
00464 found = True;
00465 }
00466
00467 return found;
00468 }
00469
00470
00471
00472
00473
00474
00475 static int priv_traverse_fn(TDB_CONTEXT *t, TDB_DATA key, TDB_DATA data, void *state)
00476 {
00477 PRIV_SID_LIST *priv = (PRIV_SID_LIST *)state;
00478 int prefixlen = strlen(PRIVPREFIX);
00479 DOM_SID sid;
00480 fstring sid_string;
00481
00482
00483
00484 if ( data.dsize != sizeof(SE_PRIV) )
00485 return 0;
00486
00487
00488
00489 if ( strncmp(key.dptr, PRIVPREFIX, prefixlen) != 0)
00490 return 0;
00491
00492
00493
00494 if ( !se_priv_equal(&priv->privilege, &se_priv_none) ) {
00495 SE_PRIV mask;
00496
00497 se_priv_copy( &mask, (SE_PRIV*)data.dptr );
00498
00499
00500
00501
00502 if ( !is_privilege_assigned( &mask, &priv->privilege) )
00503 return 0;
00504 }
00505
00506 fstrcpy( sid_string, &key.dptr[strlen(PRIVPREFIX)] );
00507
00508
00509
00510
00511 if ( strcmp( "S-0-0", sid_string ) == 0 )
00512 return 0;
00513
00514 if ( !string_to_sid(&sid, sid_string) ) {
00515 DEBUG(0,("travsersal_fn_enum__acct: Could not convert SID [%s]\n",
00516 sid_string));
00517 return 0;
00518 }
00519
00520 if (!add_sid_to_array( NULL, &sid, &priv->sids.list, &priv->sids.count )) {
00521 return 0;
00522 }
00523
00524 return 0;
00525 }
00526
00527
00528
00529
00530
00531 NTSTATUS privilege_enumerate_accounts(DOM_SID **sids, int *num_sids)
00532 {
00533 TDB_CONTEXT *tdb = get_account_pol_tdb();
00534 PRIV_SID_LIST priv;
00535
00536 if (!tdb) {
00537 return NT_STATUS_ACCESS_DENIED;
00538 }
00539
00540 ZERO_STRUCT(priv);
00541
00542 se_priv_copy( &priv.privilege, &se_priv_none );
00543
00544 tdb_traverse( tdb, priv_traverse_fn, &priv);
00545
00546
00547
00548 *sids = priv.sids.list;
00549 *num_sids = priv.sids.count;
00550
00551 return NT_STATUS_OK;
00552 }
00553
00554
00555
00556
00557
00558 BOOL grant_privilege(const DOM_SID *sid, const SE_PRIV *priv_mask)
00559 {
00560 SE_PRIV old_mask, new_mask;
00561
00562 ZERO_STRUCT( old_mask );
00563 ZERO_STRUCT( new_mask );
00564
00565 if ( get_privileges( sid, &old_mask ) )
00566 se_priv_copy( &new_mask, &old_mask );
00567 else
00568 se_priv_copy( &new_mask, &se_priv_none );
00569
00570 se_priv_add( &new_mask, priv_mask );
00571
00572 DEBUG(10,("grant_privilege: %s\n", sid_string_static(sid)));
00573
00574 DEBUGADD( 10, ("original privilege mask:\n"));
00575 dump_se_priv( DBGC_ALL, 10, &old_mask );
00576
00577 DEBUGADD( 10, ("new privilege mask:\n"));
00578 dump_se_priv( DBGC_ALL, 10, &new_mask );
00579
00580 return set_privileges( sid, &new_mask );
00581 }
00582
00583
00584
00585
00586
00587 BOOL grant_privilege_by_name(DOM_SID *sid, const char *name)
00588 {
00589 int i;
00590
00591 for ( i=0; !se_priv_equal(&privs[i].se_priv, &se_priv_end); i++ ) {
00592 if ( strequal(privs[i].name, name) ) {
00593 return grant_privilege( sid, &privs[i].se_priv );
00594 }
00595 }
00596
00597 DEBUG(3, ("grant_privilege_by_name: No Such Privilege Found (%s)\n", name));
00598
00599 return False;
00600 }
00601
00602
00603
00604
00605
00606 BOOL revoke_privilege(const DOM_SID *sid, const SE_PRIV *priv_mask)
00607 {
00608 SE_PRIV mask;
00609
00610
00611
00612 if ( !get_privileges( sid, &mask ) )
00613 return True;
00614
00615 DEBUG(10,("revoke_privilege: %s\n", sid_string_static(sid)));
00616
00617 DEBUGADD( 10, ("original privilege mask:\n"));
00618 dump_se_priv( DBGC_ALL, 10, &mask );
00619
00620 se_priv_remove( &mask, priv_mask );
00621
00622 DEBUGADD( 10, ("new privilege mask:\n"));
00623 dump_se_priv( DBGC_ALL, 10, &mask );
00624
00625 return set_privileges( sid, &mask );
00626 }
00627
00628
00629
00630
00631
00632 BOOL revoke_all_privileges( DOM_SID *sid )
00633 {
00634 return revoke_privilege( sid, &se_priv_all );
00635 }
00636
00637
00638
00639
00640
00641 BOOL revoke_privilege_by_name(DOM_SID *sid, const char *name)
00642 {
00643 int i;
00644
00645 for ( i=0; !se_priv_equal(&privs[i].se_priv, &se_priv_end); i++ ) {
00646 if ( strequal(privs[i].name, name) ) {
00647 return revoke_privilege( sid, &privs[i].se_priv );
00648 }
00649 }
00650
00651 DEBUG(3, ("revoke_privilege_by_name: No Such Privilege Found (%s)\n", name));
00652
00653 return False;
00654 }
00655
00656
00657
00658
00659
00660 NTSTATUS privilege_create_account(const DOM_SID *sid )
00661 {
00662 return ( grant_privilege(sid, &se_priv_none) ? NT_STATUS_OK : NT_STATUS_UNSUCCESSFUL);
00663 }
00664
00665
00666
00667
00668
00669 NTSTATUS privilege_set_init(PRIVILEGE_SET *priv_set)
00670 {
00671 TALLOC_CTX *mem_ctx;
00672
00673 ZERO_STRUCTP( priv_set );
00674
00675 mem_ctx = talloc_init("privilege set");
00676 if ( !mem_ctx ) {
00677 DEBUG(0,("privilege_set_init: failed to initialize talloc ctx!\n"));
00678 return NT_STATUS_NO_MEMORY;
00679 }
00680
00681 priv_set->mem_ctx = mem_ctx;
00682
00683 return NT_STATUS_OK;
00684 }
00685
00686
00687
00688
00689
00690 NTSTATUS privilege_set_init_by_ctx(TALLOC_CTX *mem_ctx, PRIVILEGE_SET *priv_set)
00691 {
00692 ZERO_STRUCTP( priv_set );
00693
00694 priv_set->mem_ctx = mem_ctx;
00695 priv_set->ext_ctx = True;
00696
00697 return NT_STATUS_OK;
00698 }
00699
00700
00701
00702
00703
00704 void privilege_set_free(PRIVILEGE_SET *priv_set)
00705 {
00706 if ( !priv_set )
00707 return;
00708
00709 if ( !( priv_set->ext_ctx ) )
00710 talloc_destroy( priv_set->mem_ctx );
00711
00712 ZERO_STRUCTP( priv_set );
00713 }
00714
00715
00716
00717
00718
00719 NTSTATUS dup_luid_attr(TALLOC_CTX *mem_ctx, LUID_ATTR **new_la, LUID_ATTR *old_la, int count)
00720 {
00721 int i;
00722
00723 if ( !old_la )
00724 return NT_STATUS_OK;
00725
00726 if (count) {
00727 *new_la = TALLOC_ARRAY(mem_ctx, LUID_ATTR, count);
00728 if ( !*new_la ) {
00729 DEBUG(0,("dup_luid_attr: failed to alloc new LUID_ATTR array [%d]\n", count));
00730 return NT_STATUS_NO_MEMORY;
00731 }
00732 } else {
00733 *new_la = NULL;
00734 }
00735
00736 for (i=0; i<count; i++) {
00737 (*new_la)[i].luid.high = old_la[i].luid.high;
00738 (*new_la)[i].luid.low = old_la[i].luid.low;
00739 (*new_la)[i].attr = old_la[i].attr;
00740 }
00741
00742 return NT_STATUS_OK;
00743 }
00744
00745
00746
00747
00748
00749
00750 BOOL user_has_privileges(const NT_USER_TOKEN *token, const SE_PRIV *privilege)
00751 {
00752 if ( !token )
00753 return False;
00754
00755 return is_privilege_assigned( &token->privileges, privilege );
00756 }
00757
00758
00759
00760
00761
00762
00763 BOOL user_has_any_privilege(NT_USER_TOKEN *token, const SE_PRIV *privilege)
00764 {
00765 if ( !token )
00766 return False;
00767
00768 return is_any_privilege_assigned( &token->privileges, privilege );
00769 }
00770
00771
00772
00773
00774
00775 char* luid_to_privilege_name(const LUID *set)
00776 {
00777 static fstring name;
00778 int i;
00779
00780 if (set->high != 0)
00781 return NULL;
00782
00783 for ( i=0; !se_priv_equal(&privs[i].se_priv, &se_priv_end); i++ ) {
00784 if ( set->low == privs[i].luid.low ) {
00785 fstrcpy( name, privs[i].name );
00786 return name;
00787 }
00788 }
00789
00790 return NULL;
00791 }
00792
00793
00794
00795
00796
00797 int count_all_privileges( void )
00798 {
00799 static int count;
00800
00801 if ( count )
00802 return count;
00803
00804
00805 for ( count=0; !se_priv_equal(&privs[count].se_priv, &se_priv_end); count++ ) ;
00806
00807 return count;
00808 }
00809
00810
00811
00812
00813 BOOL se_priv_to_privilege_set( PRIVILEGE_SET *set, SE_PRIV *mask )
00814 {
00815 int i;
00816 uint32 num_privs = count_all_privileges();
00817 LUID_ATTR luid;
00818
00819 luid.attr = 0;
00820 luid.luid.high = 0;
00821
00822 for ( i=0; i<num_privs; i++ ) {
00823 if ( !is_privilege_assigned(mask, &privs[i].se_priv) )
00824 continue;
00825
00826 luid.luid = privs[i].luid;
00827
00828 if ( !privilege_set_add( set, luid ) )
00829 return False;
00830 }
00831
00832 return True;
00833 }
00834
00835
00836
00837
00838 static BOOL luid_to_se_priv( LUID *luid, SE_PRIV *mask )
00839 {
00840 int i;
00841 uint32 num_privs = count_all_privileges();
00842
00843 for ( i=0; i<num_privs; i++ ) {
00844 if ( luid->low == privs[i].luid.low ) {
00845 se_priv_copy( mask, &privs[i].se_priv );
00846 return True;
00847 }
00848 }
00849
00850 return False;
00851 }
00852
00853
00854
00855
00856 BOOL privilege_set_to_se_priv( SE_PRIV *mask, PRIVILEGE_SET *privset )
00857 {
00858 int i;
00859
00860 ZERO_STRUCTP( mask );
00861
00862 for ( i=0; i<privset->count; i++ ) {
00863 SE_PRIV r;
00864
00865
00866
00867
00868 if ( privset->set[i].luid.high != 0 )
00869 return False;
00870
00871 if ( luid_to_se_priv( &privset->set[i].luid, &r ) )
00872 se_priv_add( mask, &r );
00873 }
00874
00875 return True;
00876 }
00877
00878
00879
00880
00881 BOOL is_privileged_sid( const DOM_SID *sid )
00882 {
00883 SE_PRIV mask;
00884
00885 return get_privileges( sid, &mask );
00886 }
00887
00888
00889
00890
00891 BOOL grant_all_privileges( const DOM_SID *sid )
00892 {
00893 int i;
00894 SE_PRIV mask;
00895 uint32 num_privs = count_all_privileges();
00896
00897 se_priv_copy( &mask, &se_priv_none );
00898
00899 for ( i=0; i<num_privs; i++ ) {
00900 se_priv_add(&mask, &privs[i].se_priv);
00901 }
00902
00903 return grant_privilege( sid, &mask );
00904 }