#include "includes.h"
#define LOCK_TIMEOUT 15
static TDB_CONTEXT *tdb;
BOOL privilege_init(void)
{
tdb = tdb_open_log(lock_path("privilege.tdb"), 0, TDB_DEFAULT,
O_RDWR|O_CREAT, 0600);
if (!tdb) {
DEBUG(0,("Failed to open privilege database\n"));
return False;
}
return True;
}
static NTSTATUS privilege_lock_right(const char *right)
{
if (tdb_lock_bystring(tdb, right, LOCK_TIMEOUT) != 0) {
return NT_STATUS_INTERNAL_ERROR;
}
return NT_STATUS_OK;
}
static void privilege_unlock_right(const char *right)
{
tdb_unlock_bystring(tdb, right);
}
NTSTATUS privilege_enum_account_with_right(const char *right,
uint32 *count,
DOM_SID **sids)
{
TDB_DATA data;
char *p;
int i;
if (!tdb) {
return NT_STATUS_INTERNAL_ERROR;
}
data = tdb_fetch_bystring(tdb, right);
if (!data.dptr) {
*count = 0;
*sids = NULL;
return NT_STATUS_OK;
}
for (i=0, p=data.dptr; p<data.dptr+data.dsize; i++) {
p += strlen(p) + 1;
}
*count = i;
*sids = SMB_MALLOC_ARRAY(DOM_SID, *count);
if (! *sids) {
return NT_STATUS_NO_MEMORY;
}
for (i=0, p=data.dptr; p<data.dptr+data.dsize; i++) {
if (!string_to_sid(&(*sids)[i], p)) {
free(data.dptr);
return NT_STATUS_INTERNAL_DB_CORRUPTION;
}
p += strlen(p) + 1;
}
free(data.dptr);
return NT_STATUS_OK;
}
static NTSTATUS privilege_set_accounts_with_right(const char *right,
uint32 count,
DOM_SID *sids)
{
TDB_DATA data;
char *p;
int i;
if (!tdb) {
return NT_STATUS_INTERNAL_ERROR;
}
data.dptr = SMB_MALLOC(count * ((MAXSUBAUTHS*11) + 30));
if (!data.dptr) {
return NT_STATUS_NO_MEMORY;
}
p = data.dptr;
for (i=0;i<count;i++) {
sid_to_string(p, &sids[i]);
p += strlen(p) + 1;
}
data.dsize = PTR_DIFF(p, data.dptr);
if (tdb_store_bystring(tdb, right, data, TDB_REPLACE) != 0) {
free(data.dptr);
return NT_STATUS_INTERNAL_ERROR;
}
free(data.dptr);
return NT_STATUS_OK;
}
NTSTATUS privilege_add_account_right(const char *right,
DOM_SID *sid)
{
NTSTATUS status;
DOM_SID *current_sids;
uint32 current_count;
int i;
status = privilege_lock_right(right);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
status = privilege_enum_account_with_right(right, ¤t_count, ¤t_sids);
if (!NT_STATUS_IS_OK(status)) {
privilege_unlock_right(right);
return status;
}
for (i=0;i<current_count;i++) {
if (sid_equal(¤t_sids[i], sid)) {
privilege_unlock_right(right);
free(current_sids);
return NT_STATUS_OK;
}
}
current_sids = SMB_REALLOC_ARRAY(current_sids, DOM_SID, current_count+1);
if (!current_sids) {
privilege_unlock_right(right);
return NT_STATUS_NO_MEMORY;
}
sid_copy(¤t_sids[current_count], sid);
current_count++;
status = privilege_set_accounts_with_right(right, current_count, current_sids);
free(current_sids);
privilege_unlock_right(right);
return status;
}
NTSTATUS privilege_remove_account_right(const char *right,
DOM_SID *sid)
{
NTSTATUS status;
DOM_SID *current_sids;
uint32 current_count;
int i;
status = privilege_lock_right(right);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
status = privilege_enum_account_with_right(right, ¤t_count, ¤t_sids);
if (!NT_STATUS_IS_OK(status)) {
privilege_unlock_right(right);
return status;
}
for (i=0;i<current_count;i++) {
if (sid_equal(¤t_sids[i], sid)) {
if (current_count-i > 1) {
memmove(¤t_sids[i], ¤t_sids[i+1],
sizeof(current_sids[0]) * ((current_count-i)-1));
}
current_count--;
status = privilege_set_accounts_with_right(right,
current_count,
current_sids);
free(current_sids);
privilege_unlock_right(right);
return status;
}
}
safe_free(current_sids);
privilege_unlock_right(right);
return NT_STATUS_OK;
}
static BOOL privilege_sid_has_right(DOM_SID *sid, const char *right)
{
NTSTATUS status;
uint32 count;
DOM_SID *sids;
int i;
status = privilege_enum_account_with_right(right, &count, &sids);
if (!NT_STATUS_IS_OK(status)) {
return False;
}
for (i=0;i<count;i++) {
if (sid_equal(sid, &sids[i])) {
free(sids);
return True;
}
}
safe_free(sids);
return False;
}
NTSTATUS privilege_enum_account_rights(DOM_SID *sid,
uint32 *count,
char ***rights)
{
TDB_DATA key, nextkey;
char *right;
if (!tdb) {
return NT_STATUS_INTERNAL_ERROR;
}
*rights = NULL;
*count = 0;
for (key = tdb_firstkey(tdb); key.dptr; key = nextkey) {
nextkey = tdb_nextkey(tdb, key);
right = key.dptr;
if (privilege_sid_has_right(sid, right)) {
(*rights) = SMB_REALLOC_ARRAY(*rights,char *, (*count)+1);
if (! *rights) {
safe_free(nextkey.dptr);
free(key.dptr);
return NT_STATUS_NO_MEMORY;
}
(*rights)[*count] = SMB_STRDUP(right);
(*count)++;
}
free(key.dptr);
}
return NT_STATUS_OK;
}