/* * Unix SMB/CIFS implementation. * MS-RPC client library implementation (SAMR pipe) * Copyright (C) Chris Nicholls 2005. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "libmsrpc.h" #include "libmsrpc_internal.h" /*used by cac_SamGetNamesFromRids*/ #define SAMR_RID_UNKNOWN 8 #define SAMR_ENUM_MAX_SIZE 0xffff /*not sure what this is.. taken from rpcclient/cmd_samr.c*/ #define SAMR_LOOKUP_FLAGS 0x000003e8 DOM_SID *cac_get_domain_sid( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, uint32 des_access ); int cac_SamConnect( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamConnect *op ) { SMBCSRV *srv = NULL; struct rpc_pipe_client *pipe_hnd = NULL; POLICY_HND *sam_out = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || op->in.access == 0 || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } srv = cac_GetServer( hnd ); if ( !srv ) { hnd->status = NT_STATUS_INVALID_CONNECTION; return CAC_FAILURE; } /*initialize for samr pipe if we have to */ if ( !hnd->_internal.pipes[PI_SAMR] ) { if ( ! ( pipe_hnd = cli_rpc_pipe_open_noauth( srv->cli, PI_SAMR, &hnd->status ) ) ) { return CAC_FAILURE; } hnd->_internal.pipes[PI_SAMR] = True; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } sam_out = talloc( mem_ctx, POLICY_HND ); if ( !sam_out ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } if ( hnd->_internal.srv_level >= SRV_WIN_2K_SP3 ) { hnd->status = rpccli_samr_connect4( pipe_hnd, mem_ctx, op->in.access, sam_out ); } if ( hnd->_internal.srv_level < SRV_WIN_2K_SP3 || !NT_STATUS_IS_OK( hnd->status ) ) { /*if sam_connect4 failed, the use sam_connect and lower srv_level */ hnd->status = rpccli_samr_connect( pipe_hnd, mem_ctx, op->in.access, sam_out ); if ( NT_STATUS_IS_OK( hnd->status ) && hnd->_internal.srv_level > SRV_WIN_2K ) { hnd->_internal.srv_level = SRV_WIN_2K; } } if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; op->out.sam = sam_out; return CAC_SUCCESS; } int cac_SamClose( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, POLICY_HND * sam ) { struct rpc_pipe_client *pipe_hnd = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !sam || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_close( pipe_hnd, mem_ctx, sam ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; return CAC_SUCCESS; } /*this is an internal function. Due to a circular dependency, it must be prototyped in libmsrpc.h (which I don't want to do) * cac_SamOpenDomain() is the only function that calls it, so I just put the definition here */ /*attempts to find the sid of the domain we are connected to*/ DOM_SID *cac_get_domain_sid( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, uint32 des_access ) { struct LsaOpenPolicy lop; struct LsaFetchSid fs; DOM_SID *sid; ZERO_STRUCT( lop ); ZERO_STRUCT( fs ); lop.in.access = des_access; lop.in.security_qos = True; if ( !cac_LsaOpenPolicy( hnd, mem_ctx, &lop ) ) return NULL; fs.in.pol = lop.out.pol; fs.in.info_class = CAC_DOMAIN_INFO; if ( !cac_LsaFetchSid( hnd, mem_ctx, &fs ) ) return NULL; cac_LsaClosePolicy( hnd, mem_ctx, lop.out.pol ); if ( !fs.out.domain_sid ) return NULL; sid = ( DOM_SID * ) TALLOC_MEMDUP( mem_ctx, &( fs.out.domain_sid->sid ), sizeof( DOM_SID ) ); if ( !sid ) { hnd->status = NT_STATUS_NO_MEMORY; } return sid; } int cac_SamOpenDomain( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamOpenDomain *op ) { struct rpc_pipe_client *pipe_hnd = NULL; DOM_SID *sid_buf; POLICY_HND *sam_out; POLICY_HND *pol_out; struct SamLookupDomain sld; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || op->in.access == 0 || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } if ( !op->in.sam ) { /*use cac_SamConnect() since it does the session setup */ struct SamConnect sc; ZERO_STRUCT( sc ); sc.in.access = op->in.access; if ( !cac_SamConnect( hnd, mem_ctx, &sc ) ) { return CAC_FAILURE; } sam_out = sc.out.sam; } else { sam_out = op->in.sam; } if ( !op->in.sid ) { /*find the sid for the SAM's domain */ /*try using cac_SamLookupDomain() first */ ZERO_STRUCT( sld ); sld.in.sam = sam_out; sld.in.name = hnd->domain; if ( cac_SamLookupDomain( hnd, mem_ctx, &sld ) ) { /*then we got the sid */ sid_buf = sld.out.sid; } else { /*try to get it from the LSA */ sid_buf = cac_get_domain_sid( hnd, mem_ctx, op->in.access ); } } else { /*we already have the sid for the domain we want */ sid_buf = op->in.sid; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } pol_out = talloc( mem_ctx, POLICY_HND ); if ( !pol_out ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } /*now open the domain */ hnd->status = rpccli_samr_open_domain( pipe_hnd, mem_ctx, sam_out, op->in.access, sid_buf, pol_out ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; op->out.sam = sam_out; op->out.dom_hnd = pol_out; return CAC_SUCCESS; } int cac_SamOpenUser( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamOpenUser *op ) { struct rpc_pipe_client *pipe_hnd = NULL; uint32 *rid_buf = NULL; uint32 num_rids = 0; uint32 *rid_types = NULL; POLICY_HND *user_out = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || !op->in.dom_hnd || op->in.access == 0 || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } if ( op->in.rid == 0 && op->in.name == NULL ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( op->in.rid == 0 && op->in.name ) { /*lookup the name and then set rid_buf */ hnd->status = rpccli_samr_lookup_names( pipe_hnd, mem_ctx, op->in.dom_hnd, SAMR_LOOKUP_FLAGS, 1, ( const char ** ) &op->in. name, &num_rids, &rid_buf, &rid_types ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; if ( num_rids == 0 || rid_buf == NULL || rid_types[0] == SAMR_RID_UNKNOWN ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } TALLOC_FREE( rid_types ); } else { rid_buf = &op->in.rid; } user_out = talloc( mem_ctx, POLICY_HND ); if ( !user_out ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } hnd->status = rpccli_samr_open_user( pipe_hnd, mem_ctx, op->in.dom_hnd, op->in.access, *rid_buf, user_out ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; op->out.user_hnd = user_out; return CAC_SUCCESS; } int cac_SamCreateUser( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamCreateUser *op ) { struct rpc_pipe_client *pipe_hnd = NULL; POLICY_HND *user_out = NULL; uint32 rid_out; uint32 acct_flags=0; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || !op->in.dom_hnd || !op->in.name || op->in.acb_mask == 0 || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } user_out = talloc( mem_ctx, POLICY_HND ); if ( !user_out ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } acct_flags = SAMR_GENERIC_READ | SAMR_GENERIC_WRITE | SAMR_GENERIC_EXECUTE | SAMR_STANDARD_WRITEDAC | SAMR_STANDARD_DELETE | SAMR_USER_SETPASS | SAMR_USER_GETATTR | SAMR_USER_SETATTR; DEBUG(10, ("Creating account with flags: %d\n",acct_flags)); hnd->status = rpccli_samr_create_dom_user( pipe_hnd, mem_ctx, op->in.dom_hnd, op->in.name, op->in.acb_mask, acct_flags, user_out, &rid_out ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; op->out.user_hnd = user_out; op->out.rid = rid_out; return CAC_SUCCESS; } int cac_SamDeleteUser( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, POLICY_HND * user_hnd ) { struct rpc_pipe_client *pipe_hnd = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !user_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_delete_dom_user( pipe_hnd, mem_ctx, user_hnd ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; return CAC_SUCCESS; } int cac_SamEnumUsers( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamEnumUsers *op ) { struct rpc_pipe_client *pipe_hnd = NULL; uint32 resume_idx_out = 0; char **names_out = NULL; uint32 *rids_out = NULL; uint32 num_users_out = 0; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || !op->in.dom_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } /*this is a hack.. but is the only reliable way to know if everything has been enumerated */ if ( op->out.done == True ) return CAC_FAILURE; pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } resume_idx_out = op->out.resume_idx; hnd->status = rpccli_samr_enum_dom_users( pipe_hnd, mem_ctx, op->in.dom_hnd, &resume_idx_out, op->in.acb_mask, SAMR_ENUM_MAX_SIZE, &names_out, &rids_out, &num_users_out ); if ( NT_STATUS_IS_OK( hnd->status ) ) op->out.done = True; /*if there are no more entries, the operation will return NT_STATUS_OK. * We want to return failure if no results were returned*/ if ( !NT_STATUS_IS_OK( hnd->status ) && NT_STATUS_V( hnd->status ) != NT_STATUS_V( STATUS_MORE_ENTRIES ) ) return CAC_FAILURE; op->out.resume_idx = resume_idx_out; op->out.num_users = num_users_out; op->out.rids = rids_out; op->out.names = names_out; return CAC_SUCCESS; } int cac_SamGetNamesFromRids( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamGetNamesFromRids *op ) { struct rpc_pipe_client *pipe_hnd = NULL; uint32 num_names_out; char **names_out; uint32 *name_types_out; uint32 i = 0; CacLookupRidsRecord *map_out; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || !op->in.dom_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } if ( !op->in.rids && op->in.num_rids != 0 ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } if ( op->in.num_rids == 0 ) { /*nothing to do */ op->out.num_names = 0; return CAC_SUCCESS; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_lookup_rids( pipe_hnd, mem_ctx, op->in.dom_hnd, op->in.num_rids, op->in.rids, &num_names_out, &names_out, &name_types_out ); if ( !NT_STATUS_IS_OK( hnd->status ) && !NT_STATUS_EQUAL( hnd->status, STATUS_SOME_UNMAPPED ) ) return CAC_FAILURE; if (num_names_out) { map_out = TALLOC_ARRAY( mem_ctx, CacLookupRidsRecord, num_names_out ); if ( !map_out ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } } else { map_out = NULL; } for ( i = 0; i < num_names_out; i++ ) { if ( name_types_out[i] == SAMR_RID_UNKNOWN ) { map_out[i].found = False; map_out[i].name = NULL; map_out[i].type = 0; } else { map_out[i].found = True; map_out[i].name = talloc_strdup( mem_ctx, names_out[i] ); map_out[i].type = name_types_out[i]; } map_out[i].rid = op->in.rids[i]; } TALLOC_FREE( names_out ); TALLOC_FREE( name_types_out ); op->out.num_names = num_names_out; op->out.map = map_out; if ( NT_STATUS_EQUAL( hnd->status, STATUS_SOME_UNMAPPED ) ) return CAC_PARTIAL_SUCCESS; return CAC_SUCCESS; } int cac_SamGetRidsFromNames( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamGetRidsFromNames *op ) { struct rpc_pipe_client *pipe_hnd = NULL; uint32 num_rids_out; uint32 *rids_out; uint32 *rid_types_out; uint32 i = 0; CacLookupRidsRecord *map_out; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || !op->in.dom_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } if ( !op->in.names && op->in.num_names != 0 ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } if ( op->in.num_names == 0 ) { /*then we don't have to do anything */ op->out.num_rids = 0; return CAC_SUCCESS; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_lookup_names( pipe_hnd, mem_ctx, op->in.dom_hnd, SAMR_LOOKUP_FLAGS, op->in.num_names, ( const char ** ) op->in.names, &num_rids_out, &rids_out, &rid_types_out ); if ( !NT_STATUS_IS_OK( hnd->status ) && !NT_STATUS_EQUAL( hnd->status, STATUS_SOME_UNMAPPED ) ) return CAC_FAILURE; if (num_rids_out) { map_out = TALLOC_ARRAY( mem_ctx, CacLookupRidsRecord, num_rids_out ); if ( !map_out ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } } else { map_out = NULL; } for ( i = 0; i < num_rids_out; i++ ) { if ( rid_types_out[i] == SAMR_RID_UNKNOWN ) { map_out[i].found = False; map_out[i].rid = 0; map_out[i].type = 0; } else { map_out[i].found = True; map_out[i].rid = rids_out[i]; map_out[i].type = rid_types_out[i]; } map_out[i].name = talloc_strdup( mem_ctx, op->in.names[i] ); } op->out.num_rids = num_rids_out; op->out.map = map_out; TALLOC_FREE( rids_out ); TALLOC_FREE( rid_types_out ); if ( NT_STATUS_EQUAL( hnd->status, STATUS_SOME_UNMAPPED ) ) return CAC_PARTIAL_SUCCESS; return CAC_SUCCESS; } int cac_SamGetGroupsForUser( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamGetGroupsForUser *op ) { struct rpc_pipe_client *pipe_hnd = NULL; DOM_GID *groups = NULL; uint32 num_groups_out = 0; uint32 *rids_out = NULL; uint32 *attr_out = NULL; uint32 i; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || !op->in.user_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_query_usergroups( pipe_hnd, mem_ctx, op->in.user_hnd, &num_groups_out, &groups ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; if (num_groups_out) { rids_out = TALLOC_ARRAY( mem_ctx, uint32, num_groups_out ); if ( !rids_out ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } attr_out = TALLOC_ARRAY( mem_ctx, uint32, num_groups_out ); if ( !attr_out ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } } else { rids_out = NULL; attr_out = NULL; } for ( i = 0; i < num_groups_out; i++ ) { rids_out[i] = groups[i].g_rid; attr_out[i] = groups[i].attr; } TALLOC_FREE( groups ); op->out.num_groups = num_groups_out; op->out.rids = rids_out; op->out.attributes = attr_out; return CAC_SUCCESS; } int cac_SamOpenGroup( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamOpenGroup *op ) { struct rpc_pipe_client *pipe_hnd = NULL; POLICY_HND *group_hnd_out = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || op->in.access == 0 || op->in.rid == 0 || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } group_hnd_out = talloc( mem_ctx, POLICY_HND ); if ( !group_hnd_out ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } hnd->status = rpccli_samr_open_group( pipe_hnd, mem_ctx, op->in.dom_hnd, op->in.access, op->in.rid, group_hnd_out ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; op->out.group_hnd = group_hnd_out; return CAC_SUCCESS; } int cac_SamCreateGroup( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamCreateGroup *op ) { struct rpc_pipe_client *pipe_hnd = NULL; POLICY_HND *group_hnd_out = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || !op->in.name || op->in.name[0] == '\0' || op->in.access == 0 || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } group_hnd_out = talloc( mem_ctx, POLICY_HND ); if ( !group_hnd_out ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } hnd->status = rpccli_samr_create_dom_group( pipe_hnd, mem_ctx, op->in.dom_hnd, op->in.name, op->in.access, group_hnd_out ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; op->out.group_hnd = group_hnd_out; return CAC_SUCCESS; } int cac_SamDeleteGroup( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, POLICY_HND * group_hnd ) { struct rpc_pipe_client *pipe_hnd = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !group_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_delete_dom_group( pipe_hnd, mem_ctx, group_hnd ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; return CAC_SUCCESS; } int cac_SamGetGroupMembers( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamGetGroupMembers *op ) { struct rpc_pipe_client *pipe_hnd = NULL; uint32 num_mem_out; uint32 *rids_out; uint32 *attr_out; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || !op->in.group_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_query_groupmem( pipe_hnd, mem_ctx, op->in.group_hnd, &num_mem_out, &rids_out, &attr_out ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; op->out.num_members = num_mem_out; op->out.rids = rids_out; op->out.attributes = attr_out; return CAC_SUCCESS; } int cac_SamAddGroupMember( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamAddGroupMember *op ) { struct rpc_pipe_client *pipe_hnd = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || !op->in.group_hnd || op->in.rid == 0 || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_add_groupmem( pipe_hnd, mem_ctx, op->in.group_hnd, op->in.rid ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; return CAC_SUCCESS; } int cac_SamRemoveGroupMember( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamRemoveGroupMember *op ) { struct rpc_pipe_client *pipe_hnd = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || !op->in.group_hnd || op->in.rid == 0 || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_del_groupmem( pipe_hnd, mem_ctx, op->in.group_hnd, op->in.rid ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; return CAC_SUCCESS; } int cac_SamClearGroupMembers( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, POLICY_HND * group_hnd ) { struct rpc_pipe_client *pipe_hnd = NULL; int result = CAC_SUCCESS; int i = 0; uint32 num_mem = 0; uint32 *rid = NULL; uint32 *attr = NULL; NTSTATUS status; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !group_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_query_groupmem( pipe_hnd, mem_ctx, group_hnd, &num_mem, &rid, &attr ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; /*try to delete the users one by one */ for ( i = 0; i < num_mem && NT_STATUS_IS_OK( hnd->status ); i++ ) { hnd->status = rpccli_samr_del_groupmem( pipe_hnd, mem_ctx, group_hnd, rid[i] ); } /*if not all members could be removed, then try to re-add the members that were already deleted */ if ( !NT_STATUS_IS_OK( hnd->status ) ) { status = NT_STATUS_OK; for ( i -= 1; i >= 0 && NT_STATUS_IS_OK( status ); i-- ) { status = rpccli_samr_add_groupmem( pipe_hnd, mem_ctx, group_hnd, rid[i] ); } /*we return with the NTSTATUS error that we got when trying to delete users */ if ( !NT_STATUS_IS_OK( status ) ) result = CAC_FAILURE; } TALLOC_FREE( attr ); return result; } int cac_SamSetGroupMembers( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamSetGroupMembers *op ) { struct rpc_pipe_client *pipe_hnd = NULL; uint32 i = 0; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || !op->in.group_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } /*use cac_SamClearGroupMembers() to clear them */ if ( !cac_SamClearGroupMembers( hnd, mem_ctx, op->in.group_hnd ) ) return CAC_FAILURE; /*hnd->status is already set */ for ( i = 0; i < op->in.num_members && NT_STATUS_IS_OK( hnd->status ); i++ ) { hnd->status = rpccli_samr_add_groupmem( pipe_hnd, mem_ctx, op->in.group_hnd, op->in.rids[i] ); } if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; return CAC_SUCCESS; } int cac_SamEnumGroups( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamEnumGroups *op ) { struct rpc_pipe_client *pipe_hnd = NULL; uint32 i = 0; uint32 resume_idx_out = 0; char **names_out = NULL; char **desc_out = NULL; uint32 *rids_out = NULL; uint32 num_groups_out = 0; struct acct_info *acct_buf = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || !op->in.dom_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } /*using this BOOL is the only reliable way to know that we are done */ if ( op->out.done == True ) /*we return failure so the call will break out of a loop */ return CAC_FAILURE; pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } resume_idx_out = op->out.resume_idx; hnd->status = rpccli_samr_enum_dom_groups( pipe_hnd, mem_ctx, op->in.dom_hnd, &resume_idx_out, SAMR_ENUM_MAX_SIZE, &acct_buf, &num_groups_out ); if ( NT_STATUS_IS_OK( hnd->status ) ) { op->out.done = True; } else if ( NT_STATUS_V( hnd->status ) != NT_STATUS_V( STATUS_MORE_ENTRIES ) ) { /*if there are no more entries, the operation will return NT_STATUS_OK. * We want to return failure if no results were returned*/ return CAC_FAILURE; } if (num_groups_out) { names_out = TALLOC_ARRAY( mem_ctx, char *, num_groups_out ); if ( !names_out ) { hnd->status = NT_STATUS_NO_MEMORY; TALLOC_FREE( acct_buf ); return CAC_FAILURE; } desc_out = TALLOC_ARRAY( mem_ctx, char *, num_groups_out ); if ( !desc_out ) { hnd->status = NT_STATUS_NO_MEMORY; TALLOC_FREE( acct_buf ); TALLOC_FREE( names_out ); return CAC_FAILURE; } rids_out = TALLOC_ARRAY( mem_ctx, uint32, num_groups_out ); if ( !rids_out ) { hnd->status = NT_STATUS_NO_MEMORY; TALLOC_FREE( acct_buf ); TALLOC_FREE( names_out ); TALLOC_FREE( desc_out ); return CAC_FAILURE; } } else { names_out = NULL; desc_out = NULL; rids_out = NULL; } for ( i = 0; i < num_groups_out; i++ ) { names_out[i] = talloc_strdup( mem_ctx, acct_buf[i].acct_name ); desc_out[i] = talloc_strdup( mem_ctx, acct_buf[i].acct_desc ); rids_out[i] = acct_buf[i].rid; if ( !names_out[i] || !desc_out[i] ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } } op->out.resume_idx = resume_idx_out; op->out.num_groups = num_groups_out; op->out.rids = rids_out; op->out.names = names_out; op->out.descriptions = desc_out; return CAC_SUCCESS; } int cac_SamEnumAliases( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamEnumAliases *op ) { struct rpc_pipe_client *pipe_hnd = NULL; uint32 i = 0; uint32 resume_idx_out = 0; char **names_out = NULL; char **desc_out = NULL; uint32 *rids_out = NULL; uint32 num_als_out = 0; struct acct_info *acct_buf = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || !op->in.dom_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } /*this is a hack.. but is the only reliable way to know if everything has been enumerated */ if ( op->out.done == True ) { return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } resume_idx_out = op->out.resume_idx; hnd->status = rpccli_samr_enum_als_groups( pipe_hnd, mem_ctx, op->in.dom_hnd, &resume_idx_out, SAMR_ENUM_MAX_SIZE, &acct_buf, &num_als_out ); if ( NT_STATUS_IS_OK( hnd->status ) ) op->out.done = True; /*if there are no more entries, the operation will return NT_STATUS_OK. * We want to return failure if no results were returned*/ if ( !NT_STATUS_IS_OK( hnd->status ) && NT_STATUS_V( hnd->status ) != NT_STATUS_V( STATUS_MORE_ENTRIES ) ) return CAC_FAILURE; if (num_als_out) { names_out = TALLOC_ARRAY( mem_ctx, char *, num_als_out ); if ( !names_out ) { hnd->status = NT_STATUS_NO_MEMORY; TALLOC_FREE( acct_buf ); return CAC_FAILURE; } desc_out = TALLOC_ARRAY( mem_ctx, char *, num_als_out ); if ( !desc_out ) { hnd->status = NT_STATUS_NO_MEMORY; TALLOC_FREE( acct_buf ); TALLOC_FREE( names_out ); return CAC_FAILURE; } rids_out = TALLOC_ARRAY( mem_ctx, uint32, num_als_out ); if ( !rids_out ) { hnd->status = NT_STATUS_NO_MEMORY; TALLOC_FREE( acct_buf ); TALLOC_FREE( names_out ); TALLOC_FREE( desc_out ); return CAC_FAILURE; } } else { names_out = NULL; desc_out = NULL; rids_out = NULL; } for ( i = 0; i < num_als_out; i++ ) { names_out[i] = talloc_strdup( mem_ctx, acct_buf[i].acct_name ); desc_out[i] = talloc_strdup( mem_ctx, acct_buf[i].acct_desc ); rids_out[i] = acct_buf[i].rid; if ( !names_out[i] || !desc_out[i] ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } } op->out.resume_idx = resume_idx_out; op->out.num_aliases = num_als_out; op->out.rids = rids_out; op->out.names = names_out; op->out.descriptions = desc_out; return CAC_SUCCESS; } int cac_SamCreateAlias( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamCreateAlias *op ) { struct rpc_pipe_client *pipe_hnd = NULL; POLICY_HND *als_hnd_out = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || !op->in.name || op->in.name[0] == '\0' || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } als_hnd_out = talloc( mem_ctx, POLICY_HND ); if ( !als_hnd_out ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } hnd->status = rpccli_samr_create_dom_alias( pipe_hnd, mem_ctx, op->in.dom_hnd, op->in.name, als_hnd_out ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; op->out.alias_hnd = als_hnd_out; return CAC_SUCCESS; } int cac_SamOpenAlias( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamOpenAlias *op ) { struct rpc_pipe_client *pipe_hnd = NULL; POLICY_HND *als_hnd_out = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || op->in.access == 0 || op->in.rid == 0 || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } als_hnd_out = talloc( mem_ctx, POLICY_HND ); if ( !als_hnd_out ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } hnd->status = rpccli_samr_open_alias( pipe_hnd, mem_ctx, op->in.dom_hnd, op->in.access, op->in.rid, als_hnd_out ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; op->out.alias_hnd = als_hnd_out; return CAC_SUCCESS; } int cac_SamDeleteAlias( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, POLICY_HND * alias_hnd ) { struct rpc_pipe_client *pipe_hnd = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !alias_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_delete_dom_alias( pipe_hnd, mem_ctx, alias_hnd ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; return CAC_SUCCESS; } int cac_SamAddAliasMember( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamAddAliasMember *op ) { struct rpc_pipe_client *pipe_hnd = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || !op->in.alias_hnd || !op->in.sid || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_add_aliasmem( pipe_hnd, mem_ctx, op->in.alias_hnd, op->in.sid ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; return CAC_SUCCESS; } int cac_SamRemoveAliasMember( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamRemoveAliasMember *op ) { struct rpc_pipe_client *pipe_hnd = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || !op->in.alias_hnd || !op->in.sid || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_del_aliasmem( pipe_hnd, mem_ctx, op->in.alias_hnd, op->in.sid ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; return CAC_SUCCESS; } int cac_SamGetAliasMembers( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamGetAliasMembers *op ) { struct rpc_pipe_client *pipe_hnd = NULL; uint32 num_mem_out; DOM_SID *sids_out; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || !op->in.alias_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_query_aliasmem( pipe_hnd, mem_ctx, op->in.alias_hnd, &num_mem_out, &sids_out ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; op->out.num_members = num_mem_out; op->out.sids = sids_out; return CAC_SUCCESS; } int cac_SamClearAliasMembers( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, POLICY_HND * alias_hnd ) { struct rpc_pipe_client *pipe_hnd = NULL; int result = CAC_SUCCESS; int i = 0; uint32 num_mem = 0; DOM_SID *sid = NULL; NTSTATUS status; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !alias_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_query_aliasmem( pipe_hnd, mem_ctx, alias_hnd, &num_mem, &sid ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; /*try to delete the users one by one */ for ( i = 0; i < num_mem && NT_STATUS_IS_OK( hnd->status ); i++ ) { hnd->status = rpccli_samr_del_aliasmem( pipe_hnd, mem_ctx, alias_hnd, &sid[i] ); } /*if not all members could be removed, then try to re-add the members that were already deleted */ if ( !NT_STATUS_IS_OK( hnd->status ) ) { status = NT_STATUS_OK; for ( i -= 1; i >= 0 && NT_STATUS_IS_OK( status ); i-- ) { status = rpccli_samr_add_aliasmem( pipe_hnd, mem_ctx, alias_hnd, &sid[i] ); } /*we return with the NTSTATUS error that we got when trying to delete users */ if ( !NT_STATUS_IS_OK( status ) ) result = CAC_FAILURE; } TALLOC_FREE( sid ); return result; } int cac_SamSetAliasMembers( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamSetAliasMembers *op ) { struct rpc_pipe_client *pipe_hnd = NULL; uint32 i = 0; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || !op->in.alias_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } /*use cac_SamClearAliasMembers() to clear them */ if ( !cac_SamClearAliasMembers( hnd, mem_ctx, op->in.alias_hnd ) ) return CAC_FAILURE; /*hnd->status is already set */ for ( i = 0; i < op->in.num_members && NT_STATUS_IS_OK( hnd->status ); i++ ) { hnd->status = rpccli_samr_add_aliasmem( pipe_hnd, mem_ctx, op->in.alias_hnd, &( op->in.sids[i] ) ); } if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; return CAC_SUCCESS; } int cac_SamUserChangePasswd( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamUserChangePasswd *op ) { SMBCSRV *srv = NULL; struct rpc_pipe_client *pipe_hnd = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || !op->in.username || !op->in.password || !op->in.new_password || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } srv = cac_GetServer( hnd ); if ( !srv ) { hnd->status = NT_STATUS_INVALID_CONNECTION; return CAC_FAILURE; } /*open a session on SAMR if we don't have one */ if ( !hnd->_internal.pipes[PI_SAMR] ) { if ( ! ( pipe_hnd = cli_rpc_pipe_open_noauth( srv->cli, PI_SAMR, &hnd->status ) ) ) { return CAC_FAILURE; } hnd->_internal.pipes[PI_SAMR] = True; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_chgpasswd_user( pipe_hnd, mem_ctx, op->in.username, op->in.new_password, op->in.password ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; return CAC_SUCCESS; } int cac_SamEnableUser( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, POLICY_HND * user_hnd ) { SMBCSRV *srv = NULL; struct rpc_pipe_client *pipe_hnd = NULL; SAM_USERINFO_CTR *ctr; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !user_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } srv = cac_GetServer( hnd ); if ( !srv ) { hnd->status = NT_STATUS_INVALID_CONNECTION; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } /*info_level = 21 is the only level that I have found to work reliably. It would be nice if user_level = 10 worked. */ hnd->status = rpccli_samr_query_userinfo( pipe_hnd, mem_ctx, user_hnd, 0x10, &ctr ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; /**check the ACB mask*/ if ( ( ctr->info.id16->acb_info & ACB_DISABLED ) == ACB_DISABLED ) { /*toggle the disabled bit */ ctr->info.id16->acb_info ^= ACB_DISABLED; } else { /*the user is already enabled so just return success */ return CAC_SUCCESS; } /*now set the userinfo */ hnd->status = rpccli_samr_set_userinfo2( pipe_hnd, mem_ctx, user_hnd, 0x10, &srv->cli->user_session_key, ctr ); /*this will only work properly if we use set_userinfo2 - fail if it is not supported */ if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; return CAC_SUCCESS; } int cac_SamDisableUser( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, POLICY_HND * user_hnd ) { SMBCSRV *srv = NULL; struct rpc_pipe_client *pipe_hnd = NULL; SAM_USERINFO_CTR *ctr; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !user_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } srv = cac_GetServer( hnd ); if ( !srv ) { hnd->status = NT_STATUS_INVALID_CONNECTION; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_query_userinfo( pipe_hnd, mem_ctx, user_hnd, 0x10, &ctr ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; if ( ( ctr->info.id16->acb_info & ACB_DISABLED ) == ACB_DISABLED ) { /*then the user is already disabled */ return CAC_SUCCESS; } /*toggle the disabled bit */ ctr->info.id16->acb_info ^= ACB_DISABLED; /*this will only work properly if we use set_userinfo2 */ hnd->status = rpccli_samr_set_userinfo2( pipe_hnd, mem_ctx, user_hnd, 0x10, &srv->cli->user_session_key, ctr ); /*this will only work properly if we use set_userinfo2 fail if it is not supported */ if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; return CAC_SUCCESS; } int cac_SamSetPassword( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamSetPassword *op ) { SMBCSRV *srv = NULL; struct rpc_pipe_client *pipe_hnd = NULL; SAM_USERINFO_CTR ctr; SAM_USER_INFO_24 info24; uint8 pw[516]; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op->in.user_hnd || !op->in.password || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } srv = cac_GetServer( hnd ); if ( !srv ) { hnd->status = NT_STATUS_INVALID_CONNECTION; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } ZERO_STRUCT( ctr ); ZERO_STRUCT( info24 ); encode_pw_buffer( pw, op->in.password, STR_UNICODE ); init_sam_user_info24( &info24, ( char * ) pw, 24 ); ctr.switch_value = 24; ctr.info.id24 = &info24; hnd->status = rpccli_samr_set_userinfo( pipe_hnd, mem_ctx, op->in.user_hnd, 24, &srv->cli->user_session_key, &ctr ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; return CAC_SUCCESS; } int cac_SamGetUserInfo( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamGetUserInfo *op ) { struct rpc_pipe_client *pipe_hnd = NULL; SAM_USERINFO_CTR *ctr; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op->in.user_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_query_userinfo( pipe_hnd, mem_ctx, op->in.user_hnd, 21, &ctr ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; op->out.info = cac_MakeUserInfo( mem_ctx, ctr ); if ( !op->out.info ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } return CAC_SUCCESS; } int cac_SamSetUserInfo( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamSetUserInfo *op ) { SMBCSRV *srv = NULL; struct rpc_pipe_client *pipe_hnd = NULL; SAM_USERINFO_CTR *ctr; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op->in.user_hnd || !op->in.info || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } ctr = cac_MakeUserInfoCtr( mem_ctx, op->in.info ); if ( !ctr ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } srv = cac_GetServer( hnd ); if ( !srv ) { hnd->status = NT_STATUS_INVALID_CONNECTION; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( hnd->_internal.srv_level >= SRV_WIN_NT4 ) { hnd->status = rpccli_samr_set_userinfo2( pipe_hnd, mem_ctx, op->in.user_hnd, 21, &srv->cli-> user_session_key, ctr ); } if ( hnd->_internal.srv_level < SRV_WIN_NT4 || !NT_STATUS_IS_OK( hnd->status ) ) { hnd->status = rpccli_samr_set_userinfo( pipe_hnd, mem_ctx, op->in.user_hnd, 21, &srv->cli->user_session_key, ctr ); if ( NT_STATUS_IS_OK( hnd->status ) && hnd->_internal.srv_level > SRV_WIN_NT4 ) { hnd->_internal.srv_level = SRV_WIN_NT4; } } if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; return CAC_SUCCESS; } int cac_SamGetUserInfoCtr( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamGetUserInfoCtr *op ) { struct rpc_pipe_client *pipe_hnd = NULL; SAM_USERINFO_CTR *ctr_out; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op->in.user_hnd || op->in.info_class == 0 || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_query_userinfo( pipe_hnd, mem_ctx, op->in.user_hnd, op->in.info_class, &ctr_out ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; op->out.ctr = ctr_out; return CAC_SUCCESS; } int cac_SamSetUserInfoCtr( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamSetUserInfoCtr *op ) { SMBCSRV *srv = NULL; struct rpc_pipe_client *pipe_hnd = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op->in.user_hnd || !op->in.ctr || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } srv = cac_GetServer( hnd ); if ( !srv ) { hnd->status = NT_STATUS_INVALID_CONNECTION; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_set_userinfo( pipe_hnd, mem_ctx, op->in.user_hnd, op->in.ctr->switch_value, &srv->cli->user_session_key, op->in.ctr ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; return CAC_SUCCESS; } int cac_SamRenameUser( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamRenameUser *op ) { SMBCSRV *srv = NULL; struct rpc_pipe_client *pipe_hnd = NULL; SAM_USERINFO_CTR ctr; SAM_USER_INFO_7 info7; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op->in.user_hnd || !op->in.new_name || op->in.new_name[0] == '\0' || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } srv = cac_GetServer( hnd ); if ( !srv ) { hnd->status = NT_STATUS_INVALID_CONNECTION; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } ZERO_STRUCT( ctr ); ZERO_STRUCT( info7 ); init_sam_user_info7( &info7, op->in.new_name ); ctr.switch_value = 7; ctr.info.id7 = &info7; hnd->status = rpccli_samr_set_userinfo( pipe_hnd, mem_ctx, op->in.user_hnd, 7, &srv->cli->user_session_key, &ctr ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; return CAC_SUCCESS; } int cac_SamGetGroupInfo( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamGetGroupInfo *op ) { struct rpc_pipe_client *pipe_hnd = NULL; GROUP_INFO_CTR *ctr; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op->in.group_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } /*get a GROUP_INFO_1 structure */ hnd->status = rpccli_samr_query_groupinfo( pipe_hnd, mem_ctx, op->in.group_hnd, 1, &ctr ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; op->out.info = cac_MakeGroupInfo( mem_ctx, ctr ); if ( !op->out.info ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } return CAC_SUCCESS; } int cac_SamSetGroupInfo( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamSetGroupInfo *op ) { struct rpc_pipe_client *pipe_hnd = NULL; GROUP_INFO_CTR *ctr = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op->in.group_hnd || !op->in.info || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } ctr = cac_MakeGroupInfoCtr( mem_ctx, op->in.info ); if ( !ctr ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_set_groupinfo( pipe_hnd, mem_ctx, op->in.group_hnd, ctr ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; return CAC_SUCCESS; } int cac_SamRenameGroup( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamRenameGroup *op ) { struct rpc_pipe_client *pipe_hnd = NULL; GROUP_INFO_CTR ctr; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op->in.group_hnd || !op->in.new_name || op->in.new_name[0] == '\0' || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } ZERO_STRUCT( ctr ); init_samr_group_info2( &ctr.group.info2, op->in.new_name ); ctr.switch_value1 = 2; hnd->status = rpccli_samr_set_groupinfo( pipe_hnd, mem_ctx, op->in.group_hnd, &ctr ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; return CAC_SUCCESS; } int cac_SamGetAliasInfo( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamGetAliasInfo *op ) { struct rpc_pipe_client *pipe_hnd = NULL; ALIAS_INFO_CTR ctr; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op->in.alias_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } /*get a GROUP_INFO_1 structure */ hnd->status = rpccli_samr_query_alias_info( pipe_hnd, mem_ctx, op->in.alias_hnd, 1, &ctr ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; op->out.info = cac_MakeAliasInfo( mem_ctx, ctr ); if ( !op->out.info ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } return CAC_SUCCESS; } int cac_SamSetAliasInfo( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamSetAliasInfo *op ) { struct rpc_pipe_client *pipe_hnd = NULL; ALIAS_INFO_CTR *ctr = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op->in.alias_hnd || !op->in.info || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } ctr = cac_MakeAliasInfoCtr( mem_ctx, op->in.info ); if ( !ctr ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_set_aliasinfo( pipe_hnd, mem_ctx, op->in.alias_hnd, ctr ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; return CAC_SUCCESS; } int cac_SamGetDomainInfo( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamGetDomainInfo *op ) { struct rpc_pipe_client *pipe_hnd = NULL; SAM_UNK_CTR ctr; SAM_UNK_INFO_1 info1; SAM_UNK_INFO_2 info2; SAM_UNK_INFO_12 info12; /*use this to keep track of a failed call */ NTSTATUS status_buf = NT_STATUS_OK; uint16 fail_count = 0; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op->in.dom_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } /*first try with info 1 */ hnd->status = rpccli_samr_query_dom_info( pipe_hnd, mem_ctx, op->in.dom_hnd, 1, &ctr ); if ( NT_STATUS_IS_OK( hnd->status ) ) { /*then we buffer the SAM_UNK_INFO_1 structure */ info1 = ctr.info.inf1; } else { /*then the call failed, store the status and ZERO out the info structure */ ZERO_STRUCT( info1 ); status_buf = hnd->status; fail_count++; } /*try again for the next one */ hnd->status = rpccli_samr_query_dom_info( pipe_hnd, mem_ctx, op->in.dom_hnd, 2, &ctr ); if ( NT_STATUS_IS_OK( hnd->status ) ) { /*store the info */ info2 = ctr.info.inf2; } else { /*ZERO out the structure and store the bad status */ ZERO_STRUCT( info2 ); status_buf = hnd->status; fail_count++; } /*once more */ hnd->status = rpccli_samr_query_dom_info( pipe_hnd, mem_ctx, op->in.dom_hnd, 12, &ctr ); if ( NT_STATUS_IS_OK( hnd->status ) ) { info12 = ctr.info.inf12; } else { ZERO_STRUCT( info12 ); status_buf = hnd->status; fail_count++; } /*return failure if all 3 calls failed */ if ( fail_count == 3 ) return CAC_FAILURE; op->out.info = cac_MakeDomainInfo( mem_ctx, &info1, &info2, &info12 ); if ( !op->out.info ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } if ( fail_count > 0 ) { hnd->status = status_buf; return CAC_PARTIAL_SUCCESS; } return CAC_SUCCESS; } int cac_SamGetDomainInfoCtr( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamGetDomainInfoCtr *op ) { struct rpc_pipe_client *pipe_hnd = NULL; SAM_UNK_CTR *ctr_out; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op->in.dom_hnd || op->in.info_class == 0 || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } ctr_out = talloc( mem_ctx, SAM_UNK_CTR ); if ( !ctr_out ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } hnd->status = rpccli_samr_query_dom_info( pipe_hnd, mem_ctx, op->in.dom_hnd, op->in.info_class, ctr_out ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; op->out.info = ctr_out; return CAC_SUCCESS; } int cac_SamGetDisplayInfo( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamGetDisplayInfo *op ) { struct rpc_pipe_client *pipe_hnd = NULL; SAM_DISPINFO_CTR ctr_out; uint32 max_entries_buf = 0; uint32 max_size_buf = 0; uint32 resume_idx_out; uint32 num_entries_out; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op->in.dom_hnd || op->in.info_class == 0 || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } if ( op->out.done == True ) /*this is done so we can use the function as a loop condition */ return CAC_FAILURE; pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( op->in.max_entries == 0 || op->in.max_size == 0 ) { get_query_dispinfo_params( op->out.loop_count, &max_entries_buf, &max_size_buf ); } else { max_entries_buf = op->in.max_entries; max_size_buf = op->in.max_size; } resume_idx_out = op->out.resume_idx; hnd->status = rpccli_samr_query_dispinfo( pipe_hnd, mem_ctx, op->in.dom_hnd, &resume_idx_out, op->in.info_class, &num_entries_out, max_entries_buf, max_size_buf, &ctr_out ); if ( !NT_STATUS_IS_OK( hnd->status ) && !NT_STATUS_EQUAL( hnd->status, STATUS_MORE_ENTRIES ) ) { /*be defensive, maybe they'll call again without zeroing the struct */ op->out.loop_count = 0; op->out.resume_idx = 0; return CAC_FAILURE; } if ( NT_STATUS_IS_OK( hnd->status ) ) { /*we want to quit once the function is called next. so it can be used in a loop */ op->out.done = True; } op->out.resume_idx = resume_idx_out; op->out.num_entries = num_entries_out; op->out.ctr = ctr_out; op->out.loop_count++; return CAC_SUCCESS; } int cac_SamLookupDomain( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamLookupDomain *op ) { struct rpc_pipe_client *pipe_hnd = NULL; DOM_SID *sid_out = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op->in.sam || !op->in.name || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } sid_out = talloc( mem_ctx, DOM_SID ); if ( !sid_out ) { hnd->status = NT_STATUS_NO_MEMORY; return CAC_FAILURE; } hnd->status = rpccli_samr_lookup_domain( pipe_hnd, mem_ctx, op->in.sam, op->in.name, sid_out ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; op->out.sid = sid_out; return CAC_SUCCESS; } int cac_SamGetSecurityObject( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamGetSecurityObject *op ) { struct rpc_pipe_client *pipe_hnd = NULL; /*this number taken from rpcclient/cmd_samr.c, I think it is the only supported level */ uint32 sec_info = DACL_SECURITY_INFORMATION; SEC_DESC_BUF *sec_out = NULL; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op->in.pol || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } pipe_hnd = cac_GetPipe( hnd, PI_SAMR ); if ( !pipe_hnd ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } hnd->status = rpccli_samr_query_sec_obj( pipe_hnd, mem_ctx, op->in.pol, sec_info, mem_ctx, &sec_out ); if ( !NT_STATUS_IS_OK( hnd->status ) ) return CAC_FAILURE; op->out.sec = sec_out; return CAC_SUCCESS; } int cac_SamFlush( CacServerHandle * hnd, TALLOC_CTX * mem_ctx, struct SamFlush *op ) { struct SamOpenDomain od; if ( !hnd ) return CAC_FAILURE; if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) { hnd->status = NT_STATUS_INVALID_HANDLE; return CAC_FAILURE; } if ( !op || !op->in.dom_hnd || !mem_ctx ) { hnd->status = NT_STATUS_INVALID_PARAMETER; return CAC_FAILURE; } if ( !cac_SamClose( hnd, mem_ctx, op->in.dom_hnd ) ) return CAC_FAILURE; ZERO_STRUCT( od ); od.in.access = ( op->in.access ) ? op->in.access : MAXIMUM_ALLOWED_ACCESS; od.in.sid = op->in.sid; if ( !cac_SamOpenDomain( hnd, mem_ctx, &od ) ) return CAC_FAILURE; /*this function does not use an output parameter to make it as convenient as possible to use */ *op->in.dom_hnd = *od.out.dom_hnd; TALLOC_FREE( od.out.dom_hnd ); return CAC_SUCCESS; }