2007-12-17 12:34:29 +03:00
/*
2007-04-09 14:38:55 +04:00
* Unix SMB / CIFS implementation .
* Authentication utility functions
* Copyright ( C ) Andrew Tridgell 1992 - 1998
* Copyright ( C ) Andrew Bartlett 2001
* Copyright ( C ) Jeremy Allison 2000 - 2001
* Copyright ( C ) Rafal Szczesniak 2002
* Copyright ( C ) Volker Lendecke 2006
* Copyright ( C ) Michael Adam 2007
*
* 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
2007-07-09 23:25:36 +04:00
* the Free Software Foundation ; either version 3 of the License , or
2007-04-09 14:38:55 +04:00
* ( at your option ) any later version .
2007-12-17 12:34:29 +03:00
*
2007-04-09 14:38:55 +04:00
* 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 .
2007-12-17 12:34:29 +03:00
*
2007-04-09 14:38:55 +04:00
* You should have received a copy of the GNU General Public License
2007-07-10 09:23:25 +04:00
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
2007-04-09 14:38:55 +04:00
*/
/* functions moved from auth/auth_util.c to minimize linker deps */
# include "includes.h"
2016-12-27 15:52:00 +03:00
# include "lib/util_unixsids.h"
2011-10-13 16:56:03 +04:00
# include "system/passwd.h"
2011-03-25 04:28:05 +03:00
# include "auth.h"
2010-08-05 04:25:37 +04:00
# include "secrets.h"
2014-07-17 14:58:34 +04:00
# include "../lib/util/memcache.h"
2010-08-05 17:14:04 +04:00
# include "../librpc/gen_ndr/netlogon.h"
2010-10-12 08:27:50 +04:00
# include "../libcli/security/security.h"
2011-03-02 18:06:32 +03:00
# include "../lib/util/util_pw.h"
2011-03-22 18:50:02 +03:00
# include "passdb.h"
2011-03-25 13:56:52 +03:00
# include "lib/privileges.h"
2010-08-05 17:14:04 +04:00
2007-04-09 14:38:55 +04:00
/****************************************************************************
2010-08-26 16:08:22 +04:00
Check for a SID in an struct security_token
2007-04-09 14:38:55 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-08-26 16:08:22 +04:00
bool nt_token_check_sid ( const struct dom_sid * sid , const struct security_token * token )
2007-04-09 14:38:55 +04:00
{
if ( ! sid | | ! token )
return False ;
2007-12-17 12:34:29 +03:00
2010-09-17 08:55:56 +04:00
return security_token_has_sid ( token , sid ) ;
2007-04-09 14:38:55 +04:00
}
2015-05-14 03:26:01 +03:00
bool nt_token_check_domain_rid ( struct security_token * token , uint32_t rid )
2007-04-09 14:38:55 +04:00
{
2010-05-21 05:25:01 +04:00
struct dom_sid domain_sid ;
2007-04-09 14:38:55 +04:00
2007-12-17 12:34:29 +03:00
/* if we are a domain member, the get the domain SID, else for
2007-04-09 14:38:55 +04:00
a DC or standalone server , use our own SID */
if ( lp_server_role ( ) = = ROLE_DOMAIN_MEMBER ) {
if ( ! secrets_fetch_domain_sid ( lp_workgroup ( ) ,
& domain_sid ) ) {
DEBUG ( 1 , ( " nt_token_check_domain_rid: Cannot lookup "
" SID for domain [%s] \n " , lp_workgroup ( ) ) ) ;
return False ;
}
2007-12-17 12:34:29 +03:00
}
2007-04-09 14:38:55 +04:00
else
sid_copy ( & domain_sid , get_global_sam_sid ( ) ) ;
sid_append_rid ( & domain_sid , rid ) ;
2007-12-17 12:34:29 +03:00
2007-04-09 14:38:55 +04:00
return nt_token_check_sid ( & domain_sid , token ) ; \
}
/******************************************************************************
Create a token for the root user to be used internally by smbd .
This is similar to running under the context of the LOCAL_SYSTEM account
in Windows . This is a read - only token . Do not modify it or free ( ) it .
2010-09-26 02:44:55 +04:00
Create a copy if you need to change it .
2007-04-09 14:38:55 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-03-12 12:33:15 +03:00
NTSTATUS get_root_nt_token ( struct security_token * * token )
2007-04-09 14:38:55 +04:00
{
2019-03-12 12:33:15 +03:00
struct security_token * for_cache ;
2010-05-21 05:25:01 +04:00
struct dom_sid u_sid , g_sid ;
2007-04-09 14:38:55 +04:00
struct passwd * pw ;
2007-12-28 19:24:39 +03:00
void * cache_data ;
2019-03-12 12:33:15 +03:00
NTSTATUS status = NT_STATUS_OK ;
2007-12-17 12:34:29 +03:00
2007-12-28 19:24:39 +03:00
cache_data = memcache_lookup_talloc (
NULL , SINGLETON_CACHE_TALLOC ,
2008-10-13 07:20:26 +04:00
data_blob_string_const_null ( " root_nt_token " ) ) ;
2007-12-28 19:24:39 +03:00
if ( cache_data ! = NULL ) {
2019-03-12 12:33:15 +03:00
* token = talloc_get_type_abort (
2010-08-26 14:04:11 +04:00
cache_data , struct security_token ) ;
2019-03-12 12:33:15 +03:00
return NT_STATUS_OK ;
2007-12-28 19:24:39 +03:00
}
2007-04-09 14:38:55 +04:00
2012-03-24 18:25:05 +04:00
if ( ! ( pw = getpwuid ( 0 ) ) ) {
2012-03-24 18:24:15 +04:00
if ( ! ( pw = getpwnam ( " root " ) ) ) {
2019-03-12 12:33:15 +03:00
DBG_ERR ( " get_root_nt_token: both getpwuid(0) "
" and getpwnam( \" root \" ) failed! \n " ) ;
return NT_STATUS_NO_SUCH_USER ;
2009-08-22 20:40:58 +04:00
}
2007-04-09 14:38:55 +04:00
}
2007-12-17 12:34:29 +03:00
/* get the user and primary group SIDs; although the
2007-04-09 14:38:55 +04:00
BUILTIN \ Administrators SId is really the one that matters here */
2007-12-17 12:34:29 +03:00
2007-04-09 14:38:55 +04:00
uid_to_sid ( & u_sid , pw - > pw_uid ) ;
gid_to_sid ( & g_sid , pw - > pw_gid ) ;
2019-03-12 12:33:15 +03:00
status = create_local_nt_token ( talloc_tos ( ) , & u_sid , False ,
1 , & global_sid_Builtin_Administrators , token ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2007-12-28 19:24:39 +03:00
2019-03-12 12:33:15 +03:00
security_token_set_privilege ( * token , SEC_PRIV_DISK_OPERATOR ) ;
2008-04-15 22:41:14 +04:00
2019-03-12 12:33:15 +03:00
for_cache = * token ;
2008-11-14 15:42:54 +03:00
2007-12-28 19:24:39 +03:00
memcache_add_talloc (
NULL , SINGLETON_CACHE_TALLOC ,
2008-11-14 15:42:54 +03:00
data_blob_string_const_null ( " root_nt_token " ) , & for_cache ) ;
2007-12-28 19:24:39 +03:00
2019-03-12 12:33:15 +03:00
return status ;
2007-04-09 14:38:55 +04:00
}
/*
* Add alias SIDs from memberships within the partially created token SID list
*/
2010-05-21 05:25:01 +04:00
NTSTATUS add_aliases ( const struct dom_sid * domain_sid ,
2010-08-26 14:04:11 +04:00
struct security_token * token )
2007-04-09 14:38:55 +04:00
{
2015-05-14 03:26:01 +03:00
uint32_t * aliases ;
2007-04-09 14:38:55 +04:00
size_t i , num_aliases ;
NTSTATUS status ;
TALLOC_CTX * tmp_ctx ;
if ( ! ( tmp_ctx = talloc_init ( " add_aliases " ) ) ) {
return NT_STATUS_NO_MEMORY ;
}
aliases = NULL ;
num_aliases = 0 ;
status = pdb_enum_alias_memberships ( tmp_ctx , domain_sid ,
2010-08-31 03:32:52 +04:00
token - > sids ,
2007-04-09 14:38:55 +04:00
token - > num_sids ,
& aliases , & num_aliases ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " pdb_enum_alias_memberships failed: %s \n " ,
nt_errstr ( status ) ) ) ;
2008-01-09 02:11:31 +03:00
goto done ;
2007-04-09 14:38:55 +04:00
}
for ( i = 0 ; i < num_aliases ; i + + ) {
2010-05-21 05:25:01 +04:00
struct dom_sid alias_sid ;
2007-04-09 14:38:55 +04:00
sid_compose ( & alias_sid , domain_sid , aliases [ i ] ) ;
2008-01-09 02:11:31 +03:00
status = add_sid_to_array_unique ( token , & alias_sid ,
2010-08-31 03:32:52 +04:00
& token - > sids ,
2008-01-09 02:11:31 +03:00
& token - > num_sids ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2007-04-09 14:38:55 +04:00
DEBUG ( 0 , ( " add_sid_to_array failed \n " ) ) ;
2008-01-09 02:11:31 +03:00
goto done ;
2007-04-09 14:38:55 +04:00
}
}
2008-01-09 02:11:31 +03:00
done :
2007-04-09 14:38:55 +04:00
TALLOC_FREE ( tmp_ctx ) ;
return NT_STATUS_OK ;
}
/*******************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-08-26 14:04:11 +04:00
static NTSTATUS add_builtin_administrators ( struct security_token * token ,
2010-05-21 05:25:01 +04:00
const struct dom_sid * dom_sid )
2007-04-09 14:38:55 +04:00
{
2010-05-21 05:25:01 +04:00
struct dom_sid domadm ;
2008-01-09 02:11:31 +03:00
NTSTATUS status ;
2007-04-09 14:38:55 +04:00
/* nothing to do if we aren't in a domain */
2007-12-17 12:34:29 +03:00
2007-04-09 14:38:55 +04:00
if ( ! ( IS_DC | | lp_server_role ( ) = = ROLE_DOMAIN_MEMBER ) ) {
return NT_STATUS_OK ;
}
2007-12-17 12:34:29 +03:00
2007-04-09 14:38:55 +04:00
/* Find the Domain Admins SID */
2007-12-17 12:34:29 +03:00
2007-04-09 14:38:55 +04:00
if ( IS_DC ) {
sid_copy ( & domadm , get_global_sam_sid ( ) ) ;
} else {
2018-03-13 23:38:27 +03:00
if ( dom_sid = = NULL ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
2008-07-24 07:42:32 +04:00
sid_copy ( & domadm , dom_sid ) ;
2007-04-09 14:38:55 +04:00
}
2010-05-18 00:04:24 +04:00
sid_append_rid ( & domadm , DOMAIN_RID_ADMINS ) ;
2007-12-17 12:34:29 +03:00
2007-04-09 14:38:55 +04:00
/* Add Administrators if the user beloongs to Domain Admins */
2007-12-17 12:34:29 +03:00
2007-04-09 14:38:55 +04:00
if ( nt_token_check_sid ( & domadm , token ) ) {
2008-01-09 02:11:31 +03:00
status = add_sid_to_array ( token ,
& global_sid_Builtin_Administrators ,
2010-08-31 03:32:52 +04:00
& token - > sids , & token - > num_sids ) ;
2008-01-09 02:11:31 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2007-04-09 14:38:55 +04:00
}
}
2007-12-17 12:34:29 +03:00
2007-04-09 14:38:55 +04:00
return NT_STATUS_OK ;
}
2018-03-07 01:26:28 +03:00
static NTSTATUS add_builtin_guests ( struct security_token * token ,
const struct dom_sid * dom_sid )
{
struct dom_sid tmp_sid ;
NTSTATUS status ;
/*
* First check the local GUEST account .
*/
2018-10-05 13:12:39 +03:00
sid_compose ( & tmp_sid , get_global_sam_sid ( ) , DOMAIN_RID_GUEST ) ;
2018-03-07 01:26:28 +03:00
if ( nt_token_check_sid ( & tmp_sid , token ) ) {
status = add_sid_to_array_unique ( token ,
& global_sid_Builtin_Guests ,
& token - > sids , & token - > num_sids ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
return NT_STATUS_OK ;
}
/*
* First check the local GUESTS group .
*/
2018-10-05 13:12:39 +03:00
sid_compose ( & tmp_sid , get_global_sam_sid ( ) , DOMAIN_RID_GUESTS ) ;
2018-03-07 01:26:28 +03:00
if ( nt_token_check_sid ( & tmp_sid , token ) ) {
status = add_sid_to_array_unique ( token ,
& global_sid_Builtin_Guests ,
& token - > sids , & token - > num_sids ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
return NT_STATUS_OK ;
}
if ( lp_server_role ( ) ! = ROLE_DOMAIN_MEMBER ) {
return NT_STATUS_OK ;
}
if ( dom_sid = = NULL ) {
return NT_STATUS_INVALID_PARAMETER_MIX ;
}
/*
* First check the domain GUESTS group .
*/
sid_copy ( & tmp_sid , dom_sid ) ;
sid_append_rid ( & tmp_sid , DOMAIN_RID_GUESTS ) ;
if ( nt_token_check_sid ( & tmp_sid , token ) ) {
status = add_sid_to_array_unique ( token ,
& global_sid_Builtin_Guests ,
& token - > sids , & token - > num_sids ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
return NT_STATUS_OK ;
}
return NT_STATUS_OK ;
}
2018-03-06 19:14:34 +03:00
static NTSTATUS add_local_groups ( struct security_token * result ,
bool is_guest ) ;
2010-05-29 00:16:53 +04:00
2017-03-01 01:22:43 +03:00
NTSTATUS get_user_sid_info3_and_extra ( const struct netr_SamInfo3 * info3 ,
const struct extra_auth_info * extra ,
struct dom_sid * sid )
{
/* USER SID */
if ( info3 - > base . rid = = ( uint32_t ) ( - 1 ) ) {
/* this is a signal the user was fake and generated,
* the actual SID we want to use is stored in the extra
* sids */
if ( is_null_sid ( & extra - > user_sid ) ) {
/* we couldn't find the user sid, bail out */
DEBUG ( 3 , ( " Invalid user SID \n " ) ) ;
return NT_STATUS_UNSUCCESSFUL ;
}
sid_copy ( sid , & extra - > user_sid ) ;
} else {
sid_copy ( sid , info3 - > base . domain_sid ) ;
sid_append_rid ( sid , info3 - > base . rid ) ;
}
return NT_STATUS_OK ;
}
2010-05-29 00:16:53 +04:00
NTSTATUS create_local_nt_token_from_info3 ( TALLOC_CTX * mem_ctx ,
bool is_guest ,
2011-07-18 04:19:27 +04:00
const struct netr_SamInfo3 * info3 ,
const struct extra_auth_info * extra ,
2010-08-26 14:04:11 +04:00
struct security_token * * ntok )
2010-05-29 00:16:53 +04:00
{
2010-08-26 14:04:11 +04:00
struct security_token * usrtok = NULL ;
2018-03-07 01:40:10 +03:00
uint32_t session_info_flags = 0 ;
2010-05-29 00:16:53 +04:00
NTSTATUS status ;
2021-03-04 13:42:25 +03:00
uint32_t i ;
2010-05-29 00:16:53 +04:00
DEBUG ( 10 , ( " Create local NT token for %s \n " ,
info3 - > base . account_name . string ) ) ;
2010-08-26 14:04:11 +04:00
usrtok = talloc_zero ( mem_ctx , struct security_token ) ;
2010-05-29 00:16:53 +04:00
if ( ! usrtok ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
return NT_STATUS_NO_MEMORY ;
}
/* Add the user and primary group sid FIRST */
/* check if the user rid is the special "Domain Guests" rid.
* If so pick the first sid for the extra sids instead as it
* is a local fake account */
2010-08-31 03:32:52 +04:00
usrtok - > sids = talloc_array ( usrtok , struct dom_sid , 2 ) ;
if ( ! usrtok - > sids ) {
2010-05-29 00:16:53 +04:00
TALLOC_FREE ( usrtok ) ;
return NT_STATUS_NO_MEMORY ;
}
usrtok - > num_sids = 2 ;
2017-03-01 01:22:43 +03:00
status = get_user_sid_info3_and_extra ( info3 , extra , & usrtok - > sids [ 0 ] ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( usrtok ) ;
return status ;
2010-05-29 00:16:53 +04:00
}
/* GROUP SID */
if ( info3 - > base . primary_gid = = ( uint32_t ) ( - 1 ) ) {
/* this is a signal the user was fake and generated,
* the actual SID we want to use is stored in the extra
* sids */
if ( is_null_sid ( & extra - > pgid_sid ) ) {
/* we couldn't find the user sid, bail out */
DEBUG ( 3 , ( " Invalid group SID \n " ) ) ;
TALLOC_FREE ( usrtok ) ;
return NT_STATUS_UNSUCCESSFUL ;
}
2010-08-31 03:32:52 +04:00
sid_copy ( & usrtok - > sids [ 1 ] , & extra - > pgid_sid ) ;
2010-05-29 00:16:53 +04:00
} else {
2010-08-31 03:32:52 +04:00
sid_copy ( & usrtok - > sids [ 1 ] , info3 - > base . domain_sid ) ;
sid_append_rid ( & usrtok - > sids [ 1 ] ,
2010-05-29 00:16:53 +04:00
info3 - > base . primary_gid ) ;
}
/* Now the SIDs we got from authentication. These are the ones from
* the info3 struct or from the pdb_enum_group_memberships , depending
* on who authenticated the user .
* Note that we start the for loop at " 1 " here , we already added the
* first group sid as primary above . */
for ( i = 0 ; i < info3 - > base . groups . count ; i + + ) {
struct dom_sid tmp_sid ;
sid_copy ( & tmp_sid , info3 - > base . domain_sid ) ;
sid_append_rid ( & tmp_sid , info3 - > base . groups . rids [ i ] . rid ) ;
status = add_sid_to_array_unique ( usrtok , & tmp_sid ,
2010-08-31 03:32:52 +04:00
& usrtok - > sids ,
2010-05-29 00:16:53 +04:00
& usrtok - > num_sids ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( " Failed to add SID to nt token \n " ) ) ;
TALLOC_FREE ( usrtok ) ;
return status ;
}
}
/* now also add extra sids if they are not the special user/group
* sids */
for ( i = 0 ; i < info3 - > sidcount ; i + + ) {
status = add_sid_to_array_unique ( usrtok ,
info3 - > sids [ i ] . sid ,
2010-08-31 03:32:52 +04:00
& usrtok - > sids ,
2010-05-29 00:16:53 +04:00
& usrtok - > num_sids ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( " Failed to add SID to nt token \n " ) ) ;
TALLOC_FREE ( usrtok ) ;
return status ;
}
}
2018-03-06 19:14:34 +03:00
status = add_local_groups ( usrtok , is_guest ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( " Failed to add local groups \n " ) ) ;
TALLOC_FREE ( usrtok ) ;
return status ;
}
2018-03-07 01:40:10 +03:00
session_info_flags | = AUTH_SESSION_INFO_DEFAULT_GROUPS ;
if ( ! is_guest ) {
session_info_flags | = AUTH_SESSION_INFO_AUTHENTICATED ;
}
status = finalize_local_nt_token ( usrtok , session_info_flags ) ;
2010-05-29 00:16:53 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( " Failed to finalize nt token \n " ) ) ;
TALLOC_FREE ( usrtok ) ;
return status ;
}
* ntok = usrtok ;
return NT_STATUS_OK ;
}
2007-04-09 14:38:55 +04:00
/*******************************************************************
Create a NT token for the user , expanding local aliases
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-03-12 12:33:15 +03:00
NTSTATUS create_local_nt_token ( TALLOC_CTX * mem_ctx ,
2010-05-21 05:25:01 +04:00
const struct dom_sid * user_sid ,
2007-10-19 04:40:25 +04:00
bool is_guest ,
2007-04-09 14:38:55 +04:00
int num_groupsids ,
2019-03-12 12:33:15 +03:00
const struct dom_sid * groupsids ,
struct security_token * * token )
2007-04-09 14:38:55 +04:00
{
2010-08-26 14:04:11 +04:00
struct security_token * result = NULL ;
2007-04-09 14:38:55 +04:00
int i ;
NTSTATUS status ;
2018-03-07 01:40:10 +03:00
uint32_t session_info_flags = 0 ;
2018-12-13 23:01:00 +03:00
struct dom_sid_buf buf ;
2007-04-09 14:38:55 +04:00
2007-12-15 23:11:36 +03:00
DEBUG ( 10 , ( " Create local NT token for %s \n " ,
2018-12-13 23:01:00 +03:00
dom_sid_str_buf ( user_sid , & buf ) ) ) ;
2007-04-09 14:38:55 +04:00
2011-06-07 05:44:43 +04:00
if ( ! ( result = talloc_zero ( mem_ctx , struct security_token ) ) ) {
2007-04-09 14:38:55 +04:00
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
2019-03-12 12:33:15 +03:00
status = NT_STATUS_NO_MEMORY ;
goto err ;
2007-04-09 14:38:55 +04:00
}
/* Add the user and primary group sid */
2008-01-09 02:11:31 +03:00
status = add_sid_to_array ( result , user_sid ,
2010-08-31 03:32:52 +04:00
& result - > sids , & result - > num_sids ) ;
2008-01-09 02:11:31 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2019-03-12 12:33:15 +03:00
goto err ;
2007-04-09 14:38:55 +04:00
}
/* For guest, num_groupsids may be zero. */
if ( num_groupsids ) {
2008-01-09 02:11:31 +03:00
status = add_sid_to_array ( result , & groupsids [ 0 ] ,
2010-08-31 03:32:52 +04:00
& result - > sids ,
2008-01-09 02:11:31 +03:00
& result - > num_sids ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2019-03-12 12:33:15 +03:00
goto err ;
2007-04-09 14:38:55 +04:00
}
}
2007-12-17 12:34:29 +03:00
2010-05-29 00:16:53 +04:00
/* Now the SIDs we got from authentication. These are the ones from
* the info3 struct or from the pdb_enum_group_memberships , depending
* on who authenticated the user .
* Note that we start the for loop at " 1 " here , we already added the
* first group sid as primary above . */
for ( i = 1 ; i < num_groupsids ; i + + ) {
status = add_sid_to_array_unique ( result , & groupsids [ i ] ,
2010-08-31 03:32:52 +04:00
& result - > sids ,
2010-05-29 00:16:53 +04:00
& result - > num_sids ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2019-03-12 12:33:15 +03:00
goto err ;
2010-05-29 00:16:53 +04:00
}
}
2018-03-06 19:14:34 +03:00
status = add_local_groups ( result , is_guest ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2019-03-12 12:33:15 +03:00
goto err ;
2018-03-06 19:14:34 +03:00
}
2018-03-07 01:40:10 +03:00
session_info_flags | = AUTH_SESSION_INFO_DEFAULT_GROUPS ;
if ( ! is_guest ) {
session_info_flags | = AUTH_SESSION_INFO_AUTHENTICATED ;
}
status = finalize_local_nt_token ( result , session_info_flags ) ;
2010-05-29 00:16:53 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2019-03-12 12:33:15 +03:00
goto err ;
2010-05-29 00:16:53 +04:00
}
2018-03-07 01:26:28 +03:00
if ( is_guest ) {
/*
* It ' s ugly , but for now it ' s
* needed to add Builtin_Guests
* here , the " local " token only
* consist of S - 1 - 22 - * SIDs
* and finalize_local_nt_token ( )
* doesn ' t have the chance to
* to detect it need to
* add Builtin_Guests via
* add_builtin_guests ( ) .
*/
status = add_sid_to_array_unique ( result ,
& global_sid_Builtin_Guests ,
& result - > sids ,
& result - > num_sids ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( " Failed to add SID to nt token \n " ) ) ;
2019-03-12 12:33:15 +03:00
goto err ;
2018-03-07 01:26:28 +03:00
}
}
2019-03-12 12:33:15 +03:00
* token = result ;
return NT_STATUS_SUCCESS ;
err :
TALLOC_FREE ( result ) ;
return status ;
2010-05-29 00:16:53 +04:00
}
2014-03-23 08:23:48 +04:00
/***************************************************
Merge in any groups from / etc / group .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static NTSTATUS add_local_groups ( struct security_token * result ,
bool is_guest )
2010-05-29 00:16:53 +04:00
{
2014-03-23 08:23:48 +04:00
gid_t * gids = NULL ;
uint32_t getgroups_num_group_sids = 0 ;
struct passwd * pass = NULL ;
TALLOC_CTX * tmp_ctx = talloc_stackframe ( ) ;
2021-03-04 13:42:25 +03:00
uint32_t i ;
2010-05-29 00:16:53 +04:00
2014-03-23 08:23:48 +04:00
if ( is_guest ) {
2014-03-20 23:39:10 +04:00
/*
2014-03-23 08:23:48 +04:00
* Guest is a special case . It ' s always
* a user that can be looked up , but
* result - > sids [ 0 ] is set to DOMAIN \ Guest .
* Lookup by account name instead .
2014-03-20 23:39:10 +04:00
*/
2014-03-23 08:23:48 +04:00
pass = Get_Pwnam_alloc ( tmp_ctx , lp_guest_account ( ) ) ;
} else {
uid_t uid ;
/* For non-guest result->sids[0] is always the user sid. */
if ( ! sid_to_uid ( & result - > sids [ 0 ] , & uid ) ) {
/*
* Non - mappable SID like SYSTEM .
* Can ' t be in any / etc / group groups .
*/
TALLOC_FREE ( tmp_ctx ) ;
return NT_STATUS_OK ;
}
2014-03-20 23:39:10 +04:00
pass = getpwuid_alloc ( tmp_ctx , uid ) ;
if ( pass = = NULL ) {
2018-12-13 23:01:00 +03:00
struct dom_sid_buf buf ;
2019-03-12 12:33:15 +03:00
DBG_ERR ( " SID %s -> getpwuid(%u) failed, is nsswitch configured? \n " ,
2018-12-13 23:01:00 +03:00
dom_sid_str_buf ( & result - > sids [ 0 ] , & buf ) ,
2019-03-12 12:33:15 +03:00
( unsigned int ) uid ) ;
TALLOC_FREE ( tmp_ctx ) ;
return NT_STATUS_NO_SUCH_USER ;
2014-03-20 23:39:10 +04:00
}
2014-03-23 08:23:48 +04:00
}
if ( ! pass ) {
TALLOC_FREE ( tmp_ctx ) ;
return NT_STATUS_UNSUCCESSFUL ;
}
/*
* Now we must get any groups this user has been
* added to in / etc / group and merge them in .
* This has to be done in every code path
* that creates an NT token , as remote users
* may have been added to the local / etc / group
* database . Tokens created merely from the
* info3 structs ( via the DC or via the krb5 PAC )
* won ' t have these local groups . Note the
* groups added here will only be UNIX groups
* ( S - 1 - 22 - 2 - XXXX groups ) as getgroups_unix_user ( )
* turns off winbindd before calling getgroups ( ) .
*
* NB . This is duplicating work already
* done in the ' unix_user : ' case of
* create_token_from_sid ( ) but won ' t
* do anything other than be inefficient
* in that case .
*/
if ( ! getgroups_unix_user ( tmp_ctx , pass - > pw_name , pass - > pw_gid ,
& gids , & getgroups_num_group_sids ) ) {
DEBUG ( 1 , ( " getgroups_unix_user for user %s failed \n " ,
pass - > pw_name ) ) ;
TALLOC_FREE ( tmp_ctx ) ;
return NT_STATUS_UNSUCCESSFUL ;
}
for ( i = 0 ; i < getgroups_num_group_sids ; i + + ) {
NTSTATUS status ;
struct dom_sid grp_sid ;
gid_to_sid ( & grp_sid , gids [ i ] ) ;
2014-03-20 23:39:10 +04:00
2014-03-23 08:23:48 +04:00
status = add_sid_to_array_unique ( result ,
& grp_sid ,
& result - > sids ,
& result - > num_sids ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( " Failed to add UNIX SID to nt token \n " ) ) ;
2014-03-20 23:39:10 +04:00
TALLOC_FREE ( tmp_ctx ) ;
2014-03-23 08:23:48 +04:00
return status ;
2014-03-20 23:39:10 +04:00
}
2014-03-23 08:23:48 +04:00
}
TALLOC_FREE ( tmp_ctx ) ;
return NT_STATUS_OK ;
}
2018-03-07 01:45:30 +03:00
NTSTATUS finalize_local_nt_token ( struct security_token * result ,
uint32_t session_info_flags )
2014-03-23 08:23:48 +04:00
{
2018-03-13 23:38:27 +03:00
struct dom_sid _dom_sid = { 0 , } ;
struct dom_sid * domain_sid = NULL ;
2014-03-23 08:23:48 +04:00
NTSTATUS status ;
2014-05-03 04:59:37 +04:00
struct acct_info * info ;
2018-03-13 23:38:27 +03:00
bool ok ;
2014-03-20 23:39:10 +04:00
2018-03-07 01:36:03 +03:00
result - > privilege_mask = 0 ;
result - > rights_mask = 0 ;
if ( result - > num_sids = = 0 ) {
return NT_STATUS_INVALID_TOKEN ;
}
2018-03-07 01:40:10 +03:00
if ( session_info_flags & AUTH_SESSION_INFO_DEFAULT_GROUPS ) {
status = add_sid_to_array ( result , & global_sid_World ,
& result - > sids , & result - > num_sids ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
status = add_sid_to_array ( result , & global_sid_Network ,
& result - > sids , & result - > num_sids ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2007-04-09 14:38:55 +04:00
}
2018-03-07 01:36:03 +03:00
/*
* Don ' t expand nested groups of system , anonymous etc
*
* Note that they still get SID_WORLD and SID_NETWORK
* for now in order let existing tests pass .
*
* But SYSTEM doesn ' t get AUTHENTICATED_USERS
* and ANONYMOUS doesn ' t get BUILTIN GUESTS anymore .
*/
if ( security_token_is_anonymous ( result ) ) {
return NT_STATUS_OK ;
}
if ( security_token_is_system ( result ) ) {
result - > privilege_mask = ~ 0 ;
return NT_STATUS_OK ;
}
2018-03-07 01:40:10 +03:00
if ( session_info_flags & AUTH_SESSION_INFO_AUTHENTICATED ) {
2008-01-09 02:11:31 +03:00
status = add_sid_to_array ( result ,
& global_sid_Authenticated_Users ,
2010-08-31 03:32:52 +04:00
& result - > sids ,
2008-01-09 02:11:31 +03:00
& result - > num_sids ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-05-29 00:16:53 +04:00
return status ;
2007-04-09 14:38:55 +04:00
}
}
2007-12-17 12:34:29 +03:00
2018-03-07 01:40:10 +03:00
/* Add in BUILTIN sids */
2018-03-13 23:38:27 +03:00
become_root ( ) ;
ok = secrets_fetch_domain_sid ( lp_workgroup ( ) , & _dom_sid ) ;
if ( ok ) {
domain_sid = & _dom_sid ;
} else {
DEBUG ( 3 , ( " Failed to fetch domain sid for %s \n " ,
lp_workgroup ( ) ) ) ;
}
unbecome_root ( ) ;
2014-05-03 04:59:37 +04:00
info = talloc_zero ( talloc_tos ( ) , struct acct_info ) ;
if ( info = = NULL ) {
DEBUG ( 0 , ( " talloc failed! \n " ) ) ;
return NT_STATUS_NO_MEMORY ;
}
2007-04-09 14:38:55 +04:00
/* Deal with the BUILTIN\Administrators group. If the SID can
2007-12-17 12:34:29 +03:00
be resolved then assume that the add_aliasmem ( S - 1 - 5 - 32 )
2007-04-09 14:38:55 +04:00
handled it . */
2014-05-03 04:59:37 +04:00
status = pdb_get_aliasinfo ( & global_sid_Builtin_Administrators , info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2007-12-17 12:34:29 +03:00
2008-07-24 07:42:32 +04:00
become_root ( ) ;
2018-03-13 23:38:27 +03:00
status = create_builtin_administrators ( domain_sid ) ;
2008-07-24 07:42:32 +04:00
unbecome_root ( ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_PROTOCOL_UNREACHABLE ) ) {
/* Add BUILTIN\Administrators directly to token. */
2018-03-13 23:38:27 +03:00
status = add_builtin_administrators ( result , domain_sid ) ;
2007-04-09 14:38:55 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-07-24 07:42:32 +04:00
DEBUG ( 3 , ( " Failed to check for local "
" Administrators membership (%s) \n " ,
nt_errstr ( status ) ) ) ;
2007-12-17 12:34:29 +03:00
}
2008-07-24 07:42:32 +04:00
} else if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 2 , ( " WARNING: Failed to create "
" BUILTIN \\ Administrators group! Can "
" Winbind allocate gids? \n " ) ) ;
2007-12-17 12:34:29 +03:00
}
2007-04-09 14:38:55 +04:00
}
/* Deal with the BUILTIN\Users group. If the SID can
2007-12-17 12:34:29 +03:00
be resolved then assume that the add_aliasmem ( S - 1 - 5 - 32 )
2007-04-09 14:38:55 +04:00
handled it . */
2014-05-03 04:59:37 +04:00
status = pdb_get_aliasinfo ( & global_sid_Builtin_Users , info ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2007-12-17 12:34:29 +03:00
2008-07-24 07:33:15 +04:00
become_root ( ) ;
2018-03-13 23:38:27 +03:00
status = create_builtin_users ( domain_sid ) ;
2008-07-24 07:33:15 +04:00
unbecome_root ( ) ;
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_PROTOCOL_UNREACHABLE ) & &
! NT_STATUS_IS_OK ( status ) )
{
DEBUG ( 2 , ( " WARNING: Failed to create BUILTIN \\ Users group! "
" Can Winbind allocate gids? \n " ) ) ;
2007-04-09 14:38:55 +04:00
}
}
2018-03-07 01:26:28 +03:00
/*
2018-03-07 01:26:28 +03:00
* Deal with the BUILTIN \ Guests group . If the SID can
* be resolved then assume that the add_aliasmem ( S - 1 - 5 - 32 )
* handled it .
2018-03-07 01:26:28 +03:00
*/
2018-03-07 01:26:28 +03:00
status = pdb_get_aliasinfo ( & global_sid_Builtin_Guests , info ) ;
2018-03-07 01:26:28 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2018-03-07 01:26:28 +03:00
become_root ( ) ;
status = create_builtin_guests ( domain_sid ) ;
unbecome_root ( ) ;
2018-12-19 11:38:33 +03:00
/*
* NT_STATUS_PROTOCOL_UNREACHABLE :
* = > winbindd is not running .
*
* NT_STATUS_ACCESS_DENIED :
* = > no idmap config at all
* and wbint_AllocateGid ( ) / winbind_allocate_gid ( )
* failed .
*
* NT_STATUS_NO_SUCH_GROUP :
* = > no idmap config at all and
* " tdbsam:map builtin = no " means
* wbint_Sids2UnixIDs ( ) fails .
*/
if ( NT_STATUS_EQUAL ( status , NT_STATUS_PROTOCOL_UNREACHABLE ) | |
NT_STATUS_EQUAL ( status , NT_STATUS_ACCESS_DENIED ) | |
NT_STATUS_EQUAL ( status , NT_STATUS_NO_SUCH_GROUP ) ) {
2018-03-07 01:26:28 +03:00
/*
* Add BUILTIN \ Guests directly to token .
* But only if the token already indicates
* real guest access by :
* - local GUEST account
* - local GUESTS group
* - domain GUESTS group
*
* Even if a user was authenticated , it
* can be member of a guest related group .
*/
status = add_builtin_guests ( result , domain_sid ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 3 , ( " Failed to check for local "
" Guests membership (%s) \n " ,
nt_errstr ( status ) ) ) ;
/*
* This is a hard error .
*/
return status ;
}
} else if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 2 , ( " Failed to create "
" BUILTIN \\ Guests group %s! Can "
" Winbind allocate gids? \n " ,
nt_errstr ( status ) ) ) ;
/*
* This is a hard error .
*/
return status ;
}
2018-03-07 01:26:28 +03:00
}
2014-05-03 04:59:37 +04:00
TALLOC_FREE ( info ) ;
2007-04-09 14:38:55 +04:00
/* Deal with local groups */
2007-12-17 12:34:29 +03:00
2007-04-09 14:38:55 +04:00
if ( lp_winbind_nested_groups ( ) ) {
2007-10-10 12:27:56 +04:00
become_root ( ) ;
2007-04-09 14:38:55 +04:00
/* Now add the aliases. First the one from our local SAM */
status = add_aliases ( get_global_sam_sid ( ) , result ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2007-12-10 13:47:17 +03:00
unbecome_root ( ) ;
2010-05-29 00:16:53 +04:00
return status ;
2007-04-09 14:38:55 +04:00
}
/* Finally the builtin ones */
status = add_aliases ( & global_sid_Builtin , result ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2007-12-10 13:47:17 +03:00
unbecome_root ( ) ;
2010-05-29 00:16:53 +04:00
return status ;
2007-04-09 14:38:55 +04:00
}
2007-10-10 12:27:56 +04:00
unbecome_root ( ) ;
2007-12-17 12:34:29 +03:00
}
2007-04-09 14:38:55 +04:00
2018-03-07 01:42:54 +03:00
if ( session_info_flags & AUTH_SESSION_INFO_NTLM ) {
struct dom_sid tmp_sid = { 0 , } ;
ok = dom_sid_parse ( SID_NT_NTLM_AUTHENTICATION , & tmp_sid ) ;
if ( ! ok ) {
return NT_STATUS_NO_MEMORY ;
}
status = add_sid_to_array ( result ,
& tmp_sid ,
& result - > sids ,
& result - > num_sids ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
}
2007-04-09 14:38:55 +04:00
2018-03-07 01:40:10 +03:00
if ( session_info_flags & AUTH_SESSION_INFO_SIMPLE_PRIVILEGES ) {
if ( security_token_has_builtin_administrators ( result ) ) {
result - > privilege_mask = ~ 0 ;
}
} else {
/* Add privileges based on current user sids */
get_privileges_for_sids ( & result - > privilege_mask , result - > sids ,
result - > num_sids ) ;
}
2010-05-29 00:16:53 +04:00
return NT_STATUS_OK ;
2007-04-09 14:38:55 +04:00
}
2007-05-07 16:15:11 +04:00
/****************************************************************************
prints a UNIX ' token ' to debug output .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void debug_unix_user_token ( int dbg_class , int dbg_lev , uid_t uid , gid_t gid ,
int n_groups , gid_t * groups )
{
int i ;
DEBUGC ( dbg_class , dbg_lev ,
( " UNIX token of user %ld \n " , ( long int ) uid ) ) ;
DEBUGADDC ( dbg_class , dbg_lev ,
( " Primary group is %ld and contains %i supplementary "
" groups \n " , ( long int ) gid , n_groups ) ) ;
for ( i = 0 ; i < n_groups ; i + + )
2007-12-17 12:34:29 +03:00
DEBUGADDC ( dbg_class , dbg_lev , ( " Group[%3i]: %ld \n " , i ,
2007-05-07 16:15:11 +04:00
( long int ) groups [ i ] ) ) ;
}
2010-04-11 15:48:55 +04:00
/*
2012-05-10 03:19:46 +04:00
* Create an artificial NT token given just a domain SID .
2010-04-11 15:48:55 +04:00
*
* We have 3 cases :
*
* unmapped unix users : Go directly to nss to find the user ' s group .
*
* A passdb user : The list of groups is provided by pdb_enum_group_memberships .
*
* If the user is provided by winbind , the primary gid is set to " domain
* users " of the user's domain. For an explanation why this is necessary, see
* the thread starting at
* http : //lists.samba.org/archive/samba-technical/2006-January/044803.html.
*/
2012-05-10 03:19:46 +04:00
static NTSTATUS create_token_from_sid ( TALLOC_CTX * mem_ctx ,
const struct dom_sid * user_sid ,
bool is_guest ,
uid_t * uid , gid_t * gid ,
char * * found_username ,
struct security_token * * token )
2010-04-11 15:48:55 +04:00
{
NTSTATUS result = NT_STATUS_NO_SUCH_USER ;
TALLOC_CTX * tmp_ctx = talloc_stackframe ( ) ;
gid_t * gids ;
2010-05-21 05:25:01 +04:00
struct dom_sid * group_sids ;
2016-05-27 02:31:55 +03:00
struct dom_sid tmp_sid ;
2010-08-26 14:54:13 +04:00
uint32_t num_group_sids ;
2011-02-21 12:30:28 +03:00
uint32_t num_gids ;
uint32_t i ;
2013-01-29 20:19:17 +04:00
uint32_t high , low ;
bool range_ok ;
2018-12-13 23:01:00 +03:00
struct dom_sid_buf buf ;
2010-04-11 15:48:55 +04:00
2012-05-10 03:19:46 +04:00
if ( sid_check_is_in_our_sam ( user_sid ) ) {
2010-04-11 15:48:55 +04:00
bool ret ;
2011-02-21 12:30:28 +03:00
uint32_t pdb_num_group_sids ;
2010-04-11 15:48:55 +04:00
/* This is a passdb user, so ask passdb */
struct samu * sam_acct = NULL ;
if ( ! ( sam_acct = samu_new ( tmp_ctx ) ) ) {
result = NT_STATUS_NO_MEMORY ;
goto done ;
}
become_root ( ) ;
2012-05-10 03:19:46 +04:00
ret = pdb_getsampwsid ( sam_acct , user_sid ) ;
2010-04-11 15:48:55 +04:00
unbecome_root ( ) ;
if ( ! ret ) {
2012-05-10 03:19:46 +04:00
DEBUG ( 1 , ( " pdb_getsampwsid(%s) failed \n " ,
2018-12-13 23:01:00 +03:00
dom_sid_str_buf ( user_sid , & buf ) ) ) ;
2012-05-10 03:19:46 +04:00
DEBUGADD ( 1 , ( " Fall back to unix user \n " ) ) ;
2010-04-11 15:48:55 +04:00
goto unix_user ;
}
result = pdb_enum_group_memberships ( tmp_ctx , sam_acct ,
& group_sids , & gids ,
2010-08-26 14:54:13 +04:00
& pdb_num_group_sids ) ;
2010-04-11 15:48:55 +04:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2012-05-10 03:19:46 +04:00
DEBUG ( 1 , ( " enum_group_memberships failed for %s: "
2018-12-13 23:01:00 +03:00
" %s \n " ,
dom_sid_str_buf ( user_sid , & buf ) ,
2010-04-11 15:48:55 +04:00
nt_errstr ( result ) ) ) ;
2012-05-10 03:19:46 +04:00
DEBUGADD ( 1 , ( " Fall back to unix uid lookup \n " ) ) ;
2010-04-11 15:48:55 +04:00
goto unix_user ;
}
2010-08-26 14:54:13 +04:00
num_group_sids = pdb_num_group_sids ;
2010-04-11 15:48:55 +04:00
/* see the smb_panic() in pdb_default_enum_group_memberships */
SMB_ASSERT ( num_group_sids > 0 ) ;
/* Ensure we're returning the found_username on the right context. */
* found_username = talloc_strdup ( mem_ctx ,
pdb_get_username ( sam_acct ) ) ;
2012-12-11 21:05:31 +04:00
if ( * found_username = = NULL ) {
2012-12-10 18:06:27 +04:00
result = NT_STATUS_NO_MEMORY ;
goto done ;
}
2010-04-11 15:48:55 +04:00
/*
* If the SID from lookup_name ( ) was the guest sid , passdb knows
2014-02-03 06:22:13 +04:00
* about the mapping of guest sid to lp_guest_account ( )
2010-04-11 15:48:55 +04:00
* username and will return the unix_pw info for a guest
* user . Use it if it ' s there , else lookup the * uid details
2010-10-20 19:16:23 +04:00
* using Get_Pwnam_alloc ( ) . See bug # 6291 for details . JRA .
2010-04-11 15:48:55 +04:00
*/
/* We must always assign the *uid. */
if ( sam_acct - > unix_pw = = NULL ) {
2010-10-20 19:16:23 +04:00
struct passwd * pwd = Get_Pwnam_alloc ( sam_acct , * found_username ) ;
2010-04-11 15:48:55 +04:00
if ( ! pwd ) {
2010-10-20 19:16:23 +04:00
DEBUG ( 10 , ( " Get_Pwnam_alloc failed for %s \n " ,
2010-04-11 15:48:55 +04:00
* found_username ) ) ;
result = NT_STATUS_NO_SUCH_USER ;
goto done ;
}
result = samu_set_unix ( sam_acct , pwd ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
DEBUG ( 10 , ( " samu_set_unix failed for %s \n " ,
* found_username ) ) ;
result = NT_STATUS_NO_SUCH_USER ;
goto done ;
}
}
* uid = sam_acct - > unix_pw - > pw_uid ;
2012-05-10 03:19:46 +04:00
} else if ( sid_check_is_in_unix_users ( user_sid ) ) {
2011-02-21 12:30:28 +03:00
uint32_t getgroups_num_group_sids ;
2010-04-11 15:48:55 +04:00
/* This is a unix user not in passdb. We need to ask nss
* directly , without consulting passdb */
struct passwd * pass ;
/*
* This goto target is used as a fallback for the passdb
* case . The concrete bug report is when passdb gave us an
* unmapped gid .
*/
unix_user :
2012-05-10 03:19:46 +04:00
if ( ! sid_to_uid ( user_sid , uid ) ) {
DEBUG ( 1 , ( " unix_user case, sid_to_uid for %s failed \n " ,
2018-12-13 23:01:00 +03:00
dom_sid_str_buf ( user_sid , & buf ) ) ) ;
2010-04-11 15:48:55 +04:00
result = NT_STATUS_NO_SUCH_USER ;
goto done ;
}
2012-05-10 03:19:46 +04:00
uid_to_unix_users_sid ( * uid , & tmp_sid ) ;
user_sid = & tmp_sid ;
2010-04-11 15:48:55 +04:00
pass = getpwuid_alloc ( tmp_ctx , * uid ) ;
if ( pass = = NULL ) {
2012-05-10 03:19:46 +04:00
DEBUG ( 1 , ( " getpwuid(%u) failed \n " ,
( unsigned int ) * uid ) ) ;
2010-04-11 15:48:55 +04:00
goto done ;
}
2012-05-10 03:19:46 +04:00
if ( ! getgroups_unix_user ( tmp_ctx , pass - > pw_name , pass - > pw_gid ,
2010-08-26 14:54:13 +04:00
& gids , & getgroups_num_group_sids ) ) {
2010-04-11 15:48:55 +04:00
DEBUG ( 1 , ( " getgroups_unix_user for user %s failed \n " ,
2012-05-10 03:19:46 +04:00
pass - > pw_name ) ) ;
2010-04-11 15:48:55 +04:00
goto done ;
}
2010-08-26 14:54:13 +04:00
num_group_sids = getgroups_num_group_sids ;
2010-04-11 15:48:55 +04:00
2015-03-10 23:13:56 +03:00
group_sids = talloc_array ( tmp_ctx , struct dom_sid , num_group_sids ) ;
if ( group_sids = = NULL ) {
DEBUG ( 1 , ( " talloc_array failed \n " ) ) ;
result = NT_STATUS_NO_MEMORY ;
goto done ;
2010-04-11 15:48:55 +04:00
}
for ( i = 0 ; i < num_group_sids ; i + + ) {
gid_to_sid ( & group_sids [ i ] , gids [ i ] ) ;
}
/* In getgroups_unix_user we always set the primary gid */
SMB_ASSERT ( num_group_sids > 0 ) ;
/* Ensure we're returning the found_username on the right context. */
* found_username = talloc_strdup ( mem_ctx , pass - > pw_name ) ;
2012-12-11 21:05:31 +04:00
if ( * found_username = = NULL ) {
2012-12-10 18:06:27 +04:00
result = NT_STATUS_NO_MEMORY ;
goto done ;
}
2010-04-11 15:48:55 +04:00
} else {
/* This user is from winbind, force the primary gid to the
* user ' s " domain users " group . Under certain circumstances
* ( user comes from NT4 ) , this might be a loss of
* information . But we can not rely on winbind getting the
* correct info . AD might prohibit winbind looking up that
* information . */
/* We must always assign the *uid. */
2012-05-10 03:19:46 +04:00
if ( ! sid_to_uid ( user_sid , uid ) ) {
DEBUG ( 1 , ( " winbindd case, sid_to_uid for %s failed \n " ,
2018-12-13 23:01:00 +03:00
dom_sid_str_buf ( user_sid , & buf ) ) ) ;
2010-04-11 15:48:55 +04:00
result = NT_STATUS_NO_SUCH_USER ;
goto done ;
}
num_group_sids = 1 ;
2011-06-07 05:30:12 +04:00
group_sids = talloc_array ( tmp_ctx , struct dom_sid , num_group_sids ) ;
2010-04-11 15:48:55 +04:00
if ( group_sids = = NULL ) {
2011-06-07 05:30:12 +04:00
DEBUG ( 1 , ( " talloc_array failed \n " ) ) ;
2010-04-11 15:48:55 +04:00
result = NT_STATUS_NO_MEMORY ;
goto done ;
}
2015-03-10 23:03:15 +03:00
gids = talloc_array ( tmp_ctx , gid_t , num_group_sids ) ;
if ( gids = = NULL ) {
result = NT_STATUS_NO_MEMORY ;
goto done ;
}
2012-05-10 03:19:46 +04:00
sid_copy ( & group_sids [ 0 ] , user_sid ) ;
2011-03-10 18:19:17 +03:00
sid_split_rid ( & group_sids [ 0 ] , NULL ) ;
2010-05-18 00:04:24 +04:00
sid_append_rid ( & group_sids [ 0 ] , DOMAIN_RID_USERS ) ;
2010-04-11 15:48:55 +04:00
2015-03-10 23:03:15 +03:00
if ( ! sid_to_gid ( & group_sids [ 0 ] , & gids [ 0 ] ) ) {
2010-04-11 15:48:55 +04:00
DEBUG ( 1 , ( " sid_to_gid(%s) failed \n " ,
2018-12-13 23:01:00 +03:00
dom_sid_str_buf ( & group_sids [ 0 ] , & buf ) ) ) ;
2010-04-11 15:48:55 +04:00
goto done ;
}
2012-05-10 03:19:46 +04:00
* found_username = NULL ;
2010-04-11 15:48:55 +04:00
}
2015-03-10 23:09:53 +03:00
* gid = gids [ 0 ] ;
2010-04-11 15:48:55 +04:00
/* Add the "Unix Group" SID for each gid to catch mapped groups
and their Unix equivalent . This is to solve the backwards
compatibility problem of ' valid users = + ntadmin ' where
ntadmin has been paired with " Domain Admins " in the group
mapping table . Otherwise smb . conf would need to be changed
to ' valid user = " Domain Admins " ' . - - jerry */
num_gids = num_group_sids ;
2013-01-29 20:19:17 +04:00
range_ok = lp_idmap_default_range ( & low , & high ) ;
2010-04-11 15:48:55 +04:00
for ( i = 0 ; i < num_gids ; i + + ) {
2015-03-10 22:55:22 +03:00
struct dom_sid unix_group_sid ;
2010-04-11 15:48:55 +04:00
/* don't pickup anything managed by Winbind */
2013-01-29 20:19:17 +04:00
if ( range_ok & & ( gids [ i ] > = low ) & & ( gids [ i ] < = high ) ) {
2010-04-11 15:48:55 +04:00
continue ;
2013-01-29 20:19:17 +04:00
}
2010-04-11 15:48:55 +04:00
2010-07-11 19:30:53 +04:00
gid_to_unix_groups_sid ( gids [ i ] , & unix_group_sid ) ;
2010-04-11 15:48:55 +04:00
result = add_sid_to_array_unique ( tmp_ctx , & unix_group_sid ,
& group_sids , & num_group_sids ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
goto done ;
}
}
/* Ensure we're creating the nt_token on the right context. */
2019-03-12 12:33:15 +03:00
result = create_local_nt_token ( mem_ctx , user_sid ,
is_guest , num_group_sids , group_sids , token ) ;
2010-04-11 15:48:55 +04:00
2019-03-12 12:33:15 +03:00
if ( ! NT_STATUS_IS_OK ( result ) ) {
2010-04-11 15:48:55 +04:00
goto done ;
}
result = NT_STATUS_OK ;
done :
TALLOC_FREE ( tmp_ctx ) ;
return result ;
}
2012-05-10 03:19:46 +04:00
/*
* Create an artificial NT token given just a username . ( Initially intended
* for force user )
*
* We go through lookup_name ( ) to avoid problems we had with ' winbind use
* default domain ' .
*
* We have 3 cases :
*
* unmapped unix users : Go directly to nss to find the user ' s group .
*
* A passdb user : The list of groups is provided by pdb_enum_group_memberships .
*
* If the user is provided by winbind , the primary gid is set to " domain
* users " of the user's domain. For an explanation why this is necessary, see
* the thread starting at
* http : //lists.samba.org/archive/samba-technical/2006-January/044803.html.
*/
NTSTATUS create_token_from_username ( TALLOC_CTX * mem_ctx , const char * username ,
bool is_guest ,
uid_t * uid , gid_t * gid ,
char * * found_username ,
struct security_token * * token )
{
NTSTATUS result = NT_STATUS_NO_SUCH_USER ;
TALLOC_CTX * tmp_ctx = talloc_stackframe ( ) ;
struct dom_sid user_sid ;
enum lsa_SidType type ;
if ( ! lookup_name_smbconf ( tmp_ctx , username , LOOKUP_NAME_ALL ,
NULL , NULL , & user_sid , & type ) ) {
DEBUG ( 1 , ( " lookup_name_smbconf for %s failed \n " , username ) ) ;
goto done ;
}
if ( type ! = SID_NAME_USER ) {
DEBUG ( 1 , ( " %s is a %s, not a user \n " , username ,
sid_type_lookup ( type ) ) ) ;
goto done ;
}
result = create_token_from_sid ( mem_ctx , & user_sid , is_guest , uid , gid , found_username , token ) ;
if ( ! NT_STATUS_IS_OK ( result ) ) {
goto done ;
}
2012-12-11 01:22:10 +04:00
/*
* If result = = NT_STATUS_OK then
* we know we have a valid token . Ensure
* we also have a valid username to match .
*/
2012-05-10 03:19:46 +04:00
if ( * found_username = = NULL ) {
* found_username = talloc_strdup ( mem_ctx , username ) ;
2012-12-11 01:22:10 +04:00
if ( * found_username = = NULL ) {
result = NT_STATUS_NO_MEMORY ;
}
2012-05-10 03:19:46 +04:00
}
done :
TALLOC_FREE ( tmp_ctx ) ;
return result ;
}
/***************************************************************************
2012-12-11 00:56:42 +04:00
Build upon create_token_from_sid :
2012-05-10 03:19:46 +04:00
2012-12-10 17:48:43 +04:00
Expensive helper function to figure out whether a user given its sid is
2012-05-10 03:19:46 +04:00
member of a particular group .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool user_sid_in_group_sid ( const struct dom_sid * sid , const struct dom_sid * group_sid )
{
NTSTATUS status ;
uid_t uid ;
gid_t gid ;
char * found_username ;
struct security_token * token ;
2012-09-16 00:47:06 +04:00
bool result = false ;
2012-05-10 03:19:46 +04:00
enum lsa_SidType type ;
TALLOC_CTX * mem_ctx = talloc_stackframe ( ) ;
2018-12-20 23:53:17 +03:00
struct dom_sid_buf buf ;
2012-05-10 03:19:46 +04:00
if ( ! lookup_sid ( mem_ctx , sid ,
NULL , NULL , & type ) ) {
2018-12-20 23:53:17 +03:00
DEBUG ( 1 , ( " lookup_sid for %s failed \n " ,
dom_sid_str_buf ( sid , & buf ) ) ) ;
2012-05-10 03:19:46 +04:00
goto done ;
}
if ( type ! = SID_NAME_USER ) {
2018-12-20 23:53:17 +03:00
DEBUG ( 5 , ( " %s is a %s, not a user \n " ,
dom_sid_str_buf ( sid , & buf ) ,
2012-05-10 03:19:46 +04:00
sid_type_lookup ( type ) ) ) ;
goto done ;
}
status = create_token_from_sid ( mem_ctx , sid , False ,
& uid , & gid , & found_username ,
& token ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2018-12-20 23:53:17 +03:00
DEBUG ( 10 , ( " could not create token for %s \n " ,
dom_sid_str_buf ( sid , & buf ) ) ) ;
2012-09-16 00:47:06 +04:00
goto done ;
2012-05-10 03:19:46 +04:00
}
result = security_token_has_sid ( token , group_sid ) ;
done :
TALLOC_FREE ( mem_ctx ) ;
return result ;
}
2010-04-11 15:48:55 +04:00
/***************************************************************************
Build upon create_token_from_username :
Expensive helper function to figure out whether a user given its name is
member of a particular group .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-05-21 05:25:01 +04:00
bool user_in_group_sid ( const char * username , const struct dom_sid * group_sid )
2010-04-11 15:48:55 +04:00
{
NTSTATUS status ;
uid_t uid ;
gid_t gid ;
char * found_username ;
2010-08-26 14:04:11 +04:00
struct security_token * token ;
2010-04-11 15:48:55 +04:00
bool result ;
TALLOC_CTX * mem_ctx = talloc_stackframe ( ) ;
status = create_token_from_username ( mem_ctx , username , False ,
& uid , & gid , & found_username ,
& token ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " could not create token for %s \n " , username ) ) ;
TALLOC_FREE ( mem_ctx ) ;
return False ;
}
2010-09-17 08:55:56 +04:00
result = security_token_has_sid ( token , group_sid ) ;
2010-04-11 15:48:55 +04:00
TALLOC_FREE ( mem_ctx ) ;
return result ;
}
bool user_in_group ( const char * username , const char * groupname )
{
TALLOC_CTX * mem_ctx = talloc_stackframe ( ) ;
2010-05-21 05:25:01 +04:00
struct dom_sid group_sid ;
2010-04-11 15:48:55 +04:00
bool ret ;
ret = lookup_name ( mem_ctx , groupname , LOOKUP_NAME_ALL ,
NULL , NULL , & group_sid , NULL ) ;
TALLOC_FREE ( mem_ctx ) ;
if ( ! ret ) {
DEBUG ( 10 , ( " lookup_name for (%s) failed. \n " , groupname ) ) ;
return False ;
}
return user_in_group_sid ( username , & group_sid ) ;
}
2007-04-09 14:38:55 +04:00
/* END */