2003-05-12 05:20:17 +04:00
/*
Unix SMB / CIFS implementation .
NT QUOTA suppport
Copyright ( C ) Stefan ( metze ) Metzmacher 2003
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
2003-05-12 05:20:17 +04:00
( 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
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2003-05-12 05:20:17 +04:00
*/
# include "includes.h"
2011-03-22 18:57:01 +03:00
# include "smbd/smbd.h"
2011-03-02 18:06:32 +03:00
# include "../lib/util/util_pw.h"
2011-02-25 19:14:22 +03:00
# include "system/passwd.h"
2011-03-22 18:50:02 +03:00
# include "passdb/lookup_sid.h"
2011-05-06 13:47:43 +04:00
# include "libsmb/libsmb.h"
2003-05-12 05:20:17 +04:00
2004-01-15 11:49:30 +03:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_QUOTA
2008-10-14 03:59:36 +04:00
static uint64_t limit_nt2unix ( uint64_t in , uint64_t bsize )
2003-05-12 05:20:17 +04:00
{
2008-10-14 03:59:36 +04:00
uint64_t ret = ( uint64_t ) 0 ;
2003-05-12 05:20:17 +04:00
2008-10-14 03:59:36 +04:00
ret = ( uint64_t ) ( in / bsize ) ;
2003-05-12 05:20:17 +04:00
if ( in > 0 & & ret = = 0 ) {
/* we have to make sure that a overflow didn't set NO_LIMIT */
2008-10-14 03:59:36 +04:00
ret = ( uint64_t ) 1 ;
2003-05-12 05:20:17 +04:00
}
if ( in = = SMB_NTQUOTAS_NO_LIMIT )
ret = SMB_QUOTAS_NO_LIMIT ;
else if ( in = = SMB_NTQUOTAS_NO_SPACE )
ret = SMB_QUOTAS_NO_SPACE ;
else if ( in = = SMB_NTQUOTAS_NO_ENTRY )
ret = SMB_QUOTAS_NO_LIMIT ;
return ret ;
}
2008-10-14 03:59:36 +04:00
static uint64_t limit_unix2nt ( uint64_t in , uint64_t bsize )
2003-05-12 05:20:17 +04:00
{
2008-10-14 03:59:36 +04:00
uint64_t ret = ( uint64_t ) 0 ;
2003-05-12 05:20:17 +04:00
2008-10-14 03:59:36 +04:00
ret = ( uint64_t ) ( in * bsize ) ;
2003-05-12 05:20:17 +04:00
return ret ;
}
2008-10-14 03:59:36 +04:00
static uint64_t limit_blk2inodes ( uint64_t in )
2003-05-12 05:20:17 +04:00
{
2008-10-14 03:59:36 +04:00
uint64_t ret = ( uint64_t ) 0 ;
2003-05-12 05:20:17 +04:00
2008-10-14 03:59:36 +04:00
ret = ( uint64_t ) ( in / 2 ) ;
2003-05-12 05:20:17 +04:00
if ( ret = = 0 & & in ! = 0 )
2008-10-14 03:59:36 +04:00
ret = ( uint64_t ) 1 ;
2003-05-12 05:20:17 +04:00
return ret ;
}
2016-03-29 23:30:23 +03:00
NTSTATUS vfs_get_ntquota ( files_struct * fsp , enum SMB_QUOTA_TYPE qtype ,
struct dom_sid * psid , SMB_NTQUOTA_STRUCT * qt )
2003-05-12 05:20:17 +04:00
{
int ret ;
SMB_DISK_QUOTA D ;
unid_t id ;
2017-06-01 21:45:25 +03:00
struct smb_filename * smb_fname_cwd = NULL ;
int saved_errno = 0 ;
2003-05-12 05:20:17 +04:00
ZERO_STRUCT ( D ) ;
2016-03-29 23:30:23 +03:00
if ( ! fsp | | ! fsp - > conn | | ! qt ) {
return NT_STATUS_INTERNAL_ERROR ;
}
2003-05-12 05:20:17 +04:00
ZERO_STRUCT ( * qt ) ;
id . uid = - 1 ;
2006-02-04 01:19:41 +03:00
if ( psid & & ! sid_to_uid ( psid , & id . uid ) ) {
2003-05-12 05:20:17 +04:00
DEBUG ( 0 , ( " sid_to_uid: failed, SID[%s] \n " ,
2007-12-15 23:11:36 +03:00
sid_string_dbg ( psid ) ) ) ;
2016-03-29 23:30:23 +03:00
return NT_STATUS_NO_SUCH_USER ;
2003-05-12 05:20:17 +04:00
}
2017-06-01 21:45:25 +03:00
smb_fname_cwd = synthetic_smb_fname ( talloc_tos ( ) ,
" . " ,
NULL ,
NULL ,
0 ) ;
if ( smb_fname_cwd = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
ret = SMB_VFS_GET_QUOTA ( fsp - > conn , smb_fname_cwd , qtype , id , & D ) ;
if ( ret = = - 1 ) {
saved_errno = errno ;
}
TALLOC_FREE ( smb_fname_cwd ) ;
if ( saved_errno ! = 0 ) {
errno = saved_errno ;
}
2003-05-12 05:20:17 +04:00
if ( psid )
qt - > sid = * psid ;
if ( ret ! = 0 ) {
2016-03-29 23:30:23 +03:00
return map_nt_error_from_unix ( errno ) ;
2003-05-12 05:20:17 +04:00
}
2008-10-14 03:59:36 +04:00
qt - > usedspace = ( uint64_t ) D . curblocks * D . bsize ;
2003-05-12 05:20:17 +04:00
qt - > softlim = limit_unix2nt ( D . softlimit , D . bsize ) ;
qt - > hardlim = limit_unix2nt ( D . hardlimit , D . bsize ) ;
qt - > qflags = D . qflags ;
2016-03-29 23:30:23 +03:00
return NT_STATUS_OK ;
2003-05-12 05:20:17 +04:00
}
2010-05-21 05:25:01 +04:00
int vfs_set_ntquota ( files_struct * fsp , enum SMB_QUOTA_TYPE qtype , struct dom_sid * psid , SMB_NTQUOTA_STRUCT * qt )
2003-05-12 05:20:17 +04:00
{
int ret ;
SMB_DISK_QUOTA D ;
unid_t id ;
ZERO_STRUCT ( D ) ;
if ( ! fsp | | ! fsp - > conn | | ! qt )
return ( - 1 ) ;
id . uid = - 1 ;
2008-10-14 03:59:36 +04:00
D . bsize = ( uint64_t ) QUOTABLOCK_SIZE ;
2003-05-14 18:38:11 +04:00
2003-05-12 05:20:17 +04:00
D . softlimit = limit_nt2unix ( qt - > softlim , D . bsize ) ;
D . hardlimit = limit_nt2unix ( qt - > hardlim , D . bsize ) ;
D . qflags = qt - > qflags ;
D . isoftlimit = limit_blk2inodes ( D . softlimit ) ;
D . ihardlimit = limit_blk2inodes ( D . hardlimit ) ;
2006-02-04 01:19:41 +03:00
if ( psid & & ! sid_to_uid ( psid , & id . uid ) ) {
2003-05-12 05:20:17 +04:00
DEBUG ( 0 , ( " sid_to_uid: failed, SID[%s] \n " ,
2007-12-15 23:11:36 +03:00
sid_string_dbg ( psid ) ) ) ;
2003-05-12 05:20:17 +04:00
}
2003-05-14 14:59:01 +04:00
ret = SMB_VFS_SET_QUOTA ( fsp - > conn , qtype , id , & D ) ;
2003-05-12 05:20:17 +04:00
return ret ;
}
2017-02-17 23:02:09 +03:00
static bool already_in_quota_list ( SMB_NTQUOTA_LIST * qt_list , uid_t uid )
2003-05-12 05:20:17 +04:00
{
SMB_NTQUOTA_LIST * tmp_list = NULL ;
if ( ! qt_list )
return False ;
for ( tmp_list = qt_list ; tmp_list ! = NULL ; tmp_list = tmp_list - > next ) {
if ( tmp_list - > uid = = uid ) {
return True ;
}
}
return False ;
}
int vfs_get_user_ntquota_list ( files_struct * fsp , SMB_NTQUOTA_LIST * * qt_list )
{
struct passwd * usr ;
TALLOC_CTX * mem_ctx = NULL ;
if ( ! fsp | | ! fsp - > conn | | ! qt_list )
return ( - 1 ) ;
* qt_list = NULL ;
if ( ( mem_ctx = talloc_init ( " SMB_USER_QUOTA_LIST " ) ) = = NULL ) {
DEBUG ( 0 , ( " talloc_init() failed \n " ) ) ;
return ( - 1 ) ;
}
2012-03-24 18:23:02 +04:00
setpwent ( ) ;
while ( ( usr = getpwent ( ) ) ! = NULL ) {
2003-05-12 05:20:17 +04:00
SMB_NTQUOTA_STRUCT tmp_qt ;
SMB_NTQUOTA_LIST * tmp_list_ent ;
2010-05-21 05:25:01 +04:00
struct dom_sid sid ;
2016-03-29 23:30:23 +03:00
NTSTATUS status ;
2003-05-12 05:20:17 +04:00
ZERO_STRUCT ( tmp_qt ) ;
2017-02-17 23:02:09 +03:00
if ( already_in_quota_list ( ( * qt_list ) , usr - > pw_uid ) ) {
DEBUG ( 5 , ( " record for uid[%ld] already in the list \n " , ( long ) usr - > pw_uid ) ) ;
2003-05-12 05:20:17 +04:00
continue ;
}
2006-02-04 01:19:41 +03:00
uid_to_sid ( & sid , usr - > pw_uid ) ;
2003-05-12 05:20:17 +04:00
2016-03-29 23:30:23 +03:00
status =
vfs_get_ntquota ( fsp , SMB_USER_QUOTA_TYPE , & sid , & tmp_qt ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2016-03-30 13:59:39 +03:00
DEBUG ( 5 , ( " failed getting quota for uid[%ld] - %s \n " ,
( long ) usr - > pw_uid , nt_errstr ( status ) ) ) ;
continue ;
}
if ( tmp_qt . softlim = = 0 & & tmp_qt . hardlim = = 0 ) {
2003-07-24 15:37:11 +04:00
DEBUG ( 5 , ( " no quota entry for sid[%s] path[%s] \n " ,
2007-12-15 23:11:36 +03:00
sid_string_dbg ( & sid ) ,
fsp - > conn - > connectpath ) ) ;
2003-05-12 05:20:17 +04:00
continue ;
}
DEBUG ( 15 , ( " quota entry for id[%s] path[%s] \n " ,
2007-12-15 23:11:36 +03:00
sid_string_dbg ( & sid ) , fsp - > conn - > connectpath ) ) ;
2003-05-12 05:20:17 +04:00
2011-06-07 05:44:43 +04:00
if ( ( tmp_list_ent = talloc_zero ( mem_ctx , SMB_NTQUOTA_LIST ) ) = = NULL ) {
2007-04-28 03:18:41 +04:00
DEBUG ( 0 , ( " TALLOC_ZERO() failed \n " ) ) ;
2003-05-12 05:20:17 +04:00
* qt_list = NULL ;
talloc_destroy ( mem_ctx ) ;
return ( - 1 ) ;
}
2011-06-07 05:44:43 +04:00
if ( ( tmp_list_ent - > quotas = talloc_zero ( mem_ctx , SMB_NTQUOTA_STRUCT ) ) = = NULL ) {
2007-04-28 03:18:41 +04:00
DEBUG ( 0 , ( " TALLOC_ZERO() failed \n " ) ) ;
2003-05-12 05:20:17 +04:00
* qt_list = NULL ;
talloc_destroy ( mem_ctx ) ;
return ( - 1 ) ;
}
tmp_list_ent - > uid = usr - > pw_uid ;
memcpy ( tmp_list_ent - > quotas , & tmp_qt , sizeof ( tmp_qt ) ) ;
tmp_list_ent - > mem_ctx = mem_ctx ;
DLIST_ADD ( ( * qt_list ) , tmp_list_ent ) ;
}
2012-03-24 18:23:02 +04:00
endpwent ( ) ;
2003-05-12 05:20:17 +04:00
2016-09-18 11:05:23 +03:00
if ( * qt_list = = NULL ) {
TALLOC_FREE ( mem_ctx ) ;
}
2003-05-12 05:20:17 +04:00
return 0 ;
}
2008-03-29 20:19:31 +03:00
static int quota_handle_destructor ( SMB_NTQUOTA_HANDLE * handle )
{
2016-09-18 11:09:54 +03:00
free_ntquota_list ( & handle - > quota_list ) ;
2008-03-29 20:19:31 +03:00
return 0 ;
}
2003-05-12 05:20:17 +04:00
void * init_quota_handle ( TALLOC_CTX * mem_ctx )
{
SMB_NTQUOTA_HANDLE * qt_handle ;
if ( ! mem_ctx )
2011-12-20 13:25:05 +04:00
return NULL ;
2003-05-12 05:20:17 +04:00
2011-06-07 05:44:43 +04:00
qt_handle = talloc_zero ( mem_ctx , SMB_NTQUOTA_HANDLE ) ;
2003-05-12 05:20:17 +04:00
if ( qt_handle = = NULL ) {
2007-04-28 03:18:41 +04:00
DEBUG ( 0 , ( " TALLOC_ZERO() failed \n " ) ) ;
2003-05-12 05:20:17 +04:00
return NULL ;
}
2008-03-29 20:19:31 +03:00
talloc_set_destructor ( qt_handle , quota_handle_destructor ) ;
return ( void * ) qt_handle ;
2003-05-12 05:20:17 +04:00
}