2019-07-29 09:09:09 +02:00
#![ deny(warnings) ]
2020-08-04 04:58:11 +02:00
#![ warn(unused_extern_crates) ]
#![ deny(clippy::unwrap_used) ]
#![ deny(clippy::expect_used) ]
#![ deny(clippy::panic) ]
#![ deny(clippy::unreachable) ]
#![ deny(clippy::await_holding_lock) ]
#![ deny(clippy::needless_pass_by_value) ]
#![ deny(clippy::trivially_copy_pass_by_ref) ]
2019-07-29 09:09:09 +02:00
2020-07-28 08:55:58 +02:00
use users ::{ get_current_gid , get_current_uid , get_effective_gid , get_effective_uid } ;
2020-06-18 02:30:42 +02:00
use serde_derive ::Deserialize ;
2020-07-28 08:55:58 +02:00
use std ::fs ::{ metadata , File , Metadata } ;
2020-06-18 02:30:42 +02:00
use std ::io ::Read ;
2020-07-28 08:55:58 +02:00
use std ::os ::unix ::fs ::MetadataExt ;
2020-06-18 02:30:42 +02:00
use std ::path ::Path ;
2020-01-08 11:49:26 +01:00
use std ::path ::PathBuf ;
2020-06-18 02:30:42 +02:00
use std ::str ::FromStr ;
2019-05-08 02:39:46 +02:00
2020-06-18 02:30:42 +02:00
use kanidm ::audit ::LogLevel ;
2019-09-14 15:44:08 +02:00
use kanidm ::config ::Configuration ;
use kanidm ::core ::{
2019-11-29 01:48:22 +01:00
backup_server_core , create_server_core , domain_rename_core , recover_account_core ,
2020-06-07 01:53:10 +02:00
reindex_server_core , restore_server_core , verify_server_core ,
2019-07-29 09:09:18 +02:00
} ;
2019-07-15 01:15:25 +02:00
use structopt ::StructOpt ;
2021-02-13 04:46:22 +01:00
include! ( " ./opt.rs " ) ;
2020-06-18 02:30:42 +02:00
#[ derive(Debug, Deserialize) ]
struct ServerConfig {
pub bindaddress : Option < String > ,
pub ldapbindaddress : Option < String > ,
// pub threads: Option<usize>,
pub db_path : String ,
2020-08-04 08:52:57 +02:00
pub db_fs_type : Option < String > ,
2020-06-18 02:30:42 +02:00
pub tls_ca : Option < String > ,
pub tls_cert : Option < String > ,
pub tls_key : Option < String > ,
pub log_level : Option < String > ,
2020-12-02 02:12:07 +01:00
pub origin : String ,
2020-06-18 02:30:42 +02:00
}
impl ServerConfig {
pub fn new < P : AsRef < Path > > ( config_path : P ) -> Result < Self , ( ) > {
let mut f = File ::open ( config_path ) . map_err ( | e | {
eprintln! ( " Unable to open config file [ {:?} ] 🥺 " , e ) ;
} ) ? ;
let mut contents = String ::new ( ) ;
f . read_to_string ( & mut contents )
. map_err ( | e | eprintln! ( " unable to read contents {:?} " , e ) ) ? ;
toml ::from_str ( contents . as_str ( ) ) . map_err ( | e | eprintln! ( " unable to parse config {:?} " , e ) )
}
2019-07-15 01:15:25 +02:00
}
2021-02-13 04:46:22 +01:00
impl KanidmdOpt {
2020-06-18 02:30:42 +02:00
fn commonopt ( & self ) -> & CommonOpt {
2019-09-06 05:05:27 +02:00
match self {
2021-02-13 04:46:22 +01:00
KanidmdOpt ::Server ( sopt ) | KanidmdOpt ::Verify ( sopt ) | KanidmdOpt ::Reindex ( sopt ) = > {
& sopt
}
KanidmdOpt ::Backup ( bopt ) = > & bopt . commonopts ,
KanidmdOpt ::Restore ( ropt ) = > & ropt . commonopts ,
KanidmdOpt ::RecoverAccount ( ropt ) = > & ropt . commonopts ,
KanidmdOpt ::DomainChange ( dopt ) = > & dopt . commonopts ,
2019-09-06 05:05:27 +02:00
}
}
}
2020-07-28 08:55:58 +02:00
fn read_file_metadata ( path : & PathBuf ) -> Metadata {
match metadata ( path ) {
Ok ( m ) = > m ,
Err ( e ) = > {
eprintln! (
" Unable to read metadata for {} - {:?} " ,
2020-08-04 04:58:11 +02:00
path . to_str ( ) . unwrap_or ( " invalid file path " ) ,
2020-07-28 08:55:58 +02:00
e
) ;
std ::process ::exit ( 1 ) ;
}
}
}
2020-09-06 00:44:35 +02:00
#[ tokio::main ]
2020-06-05 06:01:20 +02:00
async fn main ( ) {
2020-07-28 08:55:58 +02:00
// Get info about who we are.
let cuid = get_current_uid ( ) ;
let ceuid = get_effective_uid ( ) ;
let cgid = get_current_gid ( ) ;
let cegid = get_effective_gid ( ) ;
if cuid = = 0 | | ceuid = = 0 | | cgid = = 0 | | cegid = = 0 {
2020-10-30 02:12:06 +01:00
eprintln! ( " WARNING: This is running as uid == 0 (root) which may be a security risk. " ) ;
// eprintln!("ERROR: Refusing to run - this process must not operate as root.");
// std::process::exit(1);
2020-07-28 08:55:58 +02:00
}
if cuid ! = ceuid | | cgid ! = cegid {
eprintln! ( " {} != {} || {} != {} " , cuid , ceuid , cgid , cegid ) ;
eprintln! ( " ERROR: Refusing to run - uid and euid OR gid and egid must be consistent. " ) ;
std ::process ::exit ( 1 ) ;
}
2019-07-15 01:15:25 +02:00
// Read cli args, determine if we should backup/restore
2021-02-13 04:46:22 +01:00
let opt = KanidmdOpt ::from_args ( ) ;
2019-07-15 01:15:25 +02:00
let mut config = Configuration ::new ( ) ;
2020-07-28 08:55:58 +02:00
// Check the permissions are sane.
let cfg_meta = read_file_metadata ( & ( opt . commonopt ( ) . config_path ) ) ;
if ! cfg_meta . permissions ( ) . readonly ( ) {
eprintln! ( " WARNING: permissions on {} may not be secure. Should be readonly to running uid. This could be a security risk ... " ,
2020-08-04 04:58:11 +02:00
opt . commonopt ( ) . config_path . to_str ( ) . unwrap_or ( " invalid file path " ) ) ;
2020-07-28 08:55:58 +02:00
}
if cfg_meta . mode ( ) & 0o007 ! = 0 {
eprintln! ( " WARNING: {} has 'everyone' permission bits in the mode. This could be a security risk ... " ,
2020-08-04 04:58:11 +02:00
opt . commonopt ( ) . config_path . to_str ( ) . unwrap_or ( " invalid file path " )
2020-07-28 08:55:58 +02:00
) ;
}
if cfg_meta . uid ( ) = = cuid | | cfg_meta . uid ( ) = = ceuid {
eprintln! ( " WARNING: {} owned by the current uid, which may allow file permission changes. This could be a security risk ... " ,
2020-08-04 04:58:11 +02:00
opt . commonopt ( ) . config_path . to_str ( ) . unwrap_or ( " invalid file path " )
2020-07-28 08:55:58 +02:00
) ;
}
// Read our config
2020-06-18 02:30:42 +02:00
let sconfig = match ServerConfig ::new ( & ( opt . commonopt ( ) . config_path ) ) {
Ok ( c ) = > c ,
Err ( e ) = > {
eprintln! ( " Config Parse failure {:?} " , e ) ;
std ::process ::exit ( 1 ) ;
}
} ;
// Apply the file requirements
let ll = sconfig
. log_level
. map ( | ll | match LogLevel ::from_str ( ll . as_str ( ) ) {
Ok ( v ) = > v as u32 ,
Err ( e ) = > {
eprintln! ( " {:?} " , e ) ;
std ::process ::exit ( 1 ) ;
}
} ) ;
2020-07-28 08:55:58 +02:00
// Check the permissions of the files from the configuration.
if let Some ( i_str ) = & ( sconfig . tls_ca ) {
let i_path = PathBuf ::from ( i_str . as_str ( ) ) ;
let i_meta = read_file_metadata ( & i_path ) ;
if ! i_meta . permissions ( ) . readonly ( ) {
eprintln! ( " WARNING: permissions on {} may not be secure. Should be readonly to running uid. This could be a security risk ... " , i_str ) ;
}
}
if let Some ( i_str ) = & ( sconfig . tls_cert ) {
let i_path = PathBuf ::from ( i_str . as_str ( ) ) ;
let i_meta = read_file_metadata ( & i_path ) ;
if ! i_meta . permissions ( ) . readonly ( ) {
eprintln! ( " WARNING: permissions on {} may not be secure. Should be readonly to running uid. This could be a security risk ... " , i_str ) ;
}
}
if let Some ( i_str ) = & ( sconfig . tls_key ) {
let i_path = PathBuf ::from ( i_str . as_str ( ) ) ;
let i_meta = read_file_metadata ( & i_path ) ;
if ! i_meta . permissions ( ) . readonly ( ) {
eprintln! ( " WARNING: permissions on {} may not be secure. Should be readonly to running uid. This could be a security risk ... " , i_str ) ;
}
if i_meta . mode ( ) & 0o007 ! = 0 {
eprintln! ( " WARNING: {} has 'everyone' permission bits in the mode. This could be a security risk ... " , i_str ) ;
}
}
let db_path = PathBuf ::from ( sconfig . db_path . as_str ( ) ) ;
// We can't check the db_path permissions because it may note exist yet!
if let Some ( db_parent_path ) = db_path . parent ( ) {
if ! db_parent_path . exists ( ) {
eprintln! (
" DB folder {} may not exist, server startup may FAIL! " ,
2020-08-04 04:58:11 +02:00
db_parent_path . to_str ( ) . unwrap_or ( " invalid file path " )
2020-07-28 08:55:58 +02:00
) ;
}
let db_par_path_buf = db_parent_path . to_path_buf ( ) ;
let i_meta = read_file_metadata ( & db_par_path_buf ) ;
if ! i_meta . is_dir ( ) {
eprintln! (
" ERROR: Refusing to run - DB folder {} may not be a directory " ,
2020-08-04 04:58:11 +02:00
db_par_path_buf . to_str ( ) . unwrap_or ( " invalid file path " )
2020-07-28 08:55:58 +02:00
) ;
std ::process ::exit ( 1 ) ;
}
if i_meta . permissions ( ) . readonly ( ) {
2020-08-04 04:58:11 +02:00
eprintln! ( " WARNING: DB folder permissions on {} indicate it may not be RW. This could cause the server start up to fail! " , db_par_path_buf . to_str ( ) . unwrap_or ( " invalid file path " ) ) ;
2020-07-28 08:55:58 +02:00
}
if i_meta . mode ( ) & 0o007 ! = 0 {
2020-08-04 04:58:11 +02:00
eprintln! ( " WARNING: DB folder {} has 'everyone' permission bits in the mode. This could be a security risk ... " , db_par_path_buf . to_str ( ) . unwrap_or ( " invalid file path " ) ) ;
2020-07-28 08:55:58 +02:00
}
}
2020-06-18 02:30:42 +02:00
config . update_log_level ( ll ) ;
config . update_db_path ( & sconfig . db_path . as_str ( ) ) ;
2020-08-04 08:52:57 +02:00
config . update_db_fs_type ( & sconfig . db_fs_type ) ;
2020-06-18 02:30:42 +02:00
config . update_tls ( & sconfig . tls_ca , & sconfig . tls_cert , & sconfig . tls_key ) ;
config . update_bind ( & sconfig . bindaddress ) ;
config . update_ldapbind ( & sconfig . ldapbindaddress ) ;
2020-12-02 02:12:07 +01:00
config . update_origin ( & sconfig . origin . as_str ( ) ) ;
2020-06-18 02:30:42 +02:00
// Apply any cli overrides, normally debug level.
2020-06-21 13:57:48 +02:00
if let Some ( dll ) = opt . commonopt ( ) . debug . as_ref ( ) {
config . update_log_level ( Some ( dll . clone ( ) as u32 ) ) ;
}
2020-12-02 02:12:07 +01:00
::std ::env ::set_var ( " RUST_LOG " , " tide=info,kanidm=info,webauthn=debug " ) ;
2020-06-05 06:01:20 +02:00
env_logger ::builder ( )
. format_timestamp ( None )
. format_level ( false )
. init ( ) ;
2019-07-12 07:28:46 +02:00
2019-07-15 01:15:25 +02:00
match opt {
2021-02-13 04:46:22 +01:00
KanidmdOpt ::Server ( _sopt ) = > {
2020-06-18 02:30:42 +02:00
eprintln! ( " Running in server mode ... " ) ;
2019-07-15 01:15:25 +02:00
2020-09-06 00:44:35 +02:00
/*
let mut rt = tokio ::runtime ::Builder ::new ( )
. threaded_scheduler ( )
. build ( )
. unwrap ( ) ;
* /
2020-06-10 04:07:43 +02:00
let sctx = create_server_core ( config ) . await ;
2020-06-05 06:01:20 +02:00
match sctx {
2020-09-06 00:44:35 +02:00
Ok ( _sctx ) = > match tokio ::signal ::ctrl_c ( ) . await {
2020-08-04 04:58:11 +02:00
Ok ( _ ) = > {
eprintln! ( " Ctrl-C received, shutting down " ) ;
2020-09-06 00:44:35 +02:00
// sctx.stop(true).await;
2020-08-04 04:58:11 +02:00
}
Err ( _ ) = > {
eprintln! ( " Invalid signal received, shutting down as a precaution ... " ) ;
2020-09-06 00:44:35 +02:00
// sctx.stop(true).await;
2020-08-04 04:58:11 +02:00
}
} ,
2020-06-05 06:01:20 +02:00
Err ( _ ) = > {
2020-06-18 02:30:42 +02:00
eprintln! ( " Failed to start server core! " ) ;
2020-06-05 06:01:20 +02:00
return ;
}
}
2019-07-15 01:15:25 +02:00
}
2021-02-13 04:46:22 +01:00
KanidmdOpt ::Backup ( bopt ) = > {
2020-06-18 02:30:42 +02:00
eprintln! ( " Running in backup mode ... " ) ;
2019-07-15 01:15:25 +02:00
2020-06-18 02:30:42 +02:00
// config.update_db_path(&bopt.commonopts.db_path);
2019-07-15 01:15:25 +02:00
let p = match bopt . path . to_str ( ) {
Some ( p ) = > p ,
None = > {
2020-06-18 02:30:42 +02:00
eprintln! ( " Invalid backup path " ) ;
2019-07-15 01:15:25 +02:00
std ::process ::exit ( 1 ) ;
}
} ;
2020-08-04 04:58:11 +02:00
backup_server_core ( & config , p ) ;
2019-07-15 01:15:25 +02:00
}
2021-02-13 04:46:22 +01:00
KanidmdOpt ::Restore ( ropt ) = > {
2020-06-18 02:30:42 +02:00
eprintln! ( " Running in restore mode ... " ) ;
2019-07-15 01:15:25 +02:00
2020-06-18 02:30:42 +02:00
// config.update_db_path(&ropt.commonopts.db_path);
2018-09-29 09:54:16 +02:00
2019-07-15 01:15:25 +02:00
let p = match ropt . path . to_str ( ) {
Some ( p ) = > p ,
None = > {
2020-06-18 02:30:42 +02:00
eprintln! ( " Invalid restore path " ) ;
2019-07-15 01:15:25 +02:00
std ::process ::exit ( 1 ) ;
}
} ;
2020-08-04 04:58:11 +02:00
restore_server_core ( & config , p ) ;
2019-07-15 01:15:25 +02:00
}
2021-02-13 04:46:22 +01:00
KanidmdOpt ::Verify ( _vopt ) = > {
2020-06-18 02:30:42 +02:00
eprintln! ( " Running in db verification mode ... " ) ;
2019-07-29 09:09:09 +02:00
2020-06-18 02:30:42 +02:00
// config.update_db_path(&vopt.db_path);
2020-08-04 04:58:11 +02:00
verify_server_core ( & config ) ;
2019-07-29 09:09:09 +02:00
}
2021-02-13 04:46:22 +01:00
KanidmdOpt ::RecoverAccount ( raopt ) = > {
2020-06-18 02:30:42 +02:00
eprintln! ( " Running account recovery ... " ) ;
2019-09-04 03:06:37 +02:00
2020-08-04 04:58:11 +02:00
let password = match rpassword ::prompt_password_stderr ( " new password: " ) {
Ok ( pw ) = > pw ,
Err ( e ) = > {
eprintln! ( " Failed to get password from prompt {:?} " , e ) ;
std ::process ::exit ( 1 ) ;
}
} ;
2020-06-18 02:30:42 +02:00
// config.update_db_path(&raopt.commonopts.db_path);
2019-09-04 03:06:37 +02:00
2020-08-04 04:58:11 +02:00
recover_account_core ( & config , & raopt . name , & password ) ;
2019-09-04 03:06:37 +02:00
}
2020-06-07 01:53:10 +02:00
/*
2021-02-13 04:46:22 +01:00
KanidmdOpt ::ResetServerId ( vopt ) = > {
2020-06-18 02:30:42 +02:00
eprintln! ( " Resetting server id. THIS WILL BREAK REPLICATION " ) ;
2019-09-14 10:21:41 +02:00
config . update_db_path ( & vopt . db_path ) ;
reset_sid_core ( config ) ;
}
2020-06-07 01:53:10 +02:00
* /
2021-02-13 04:46:22 +01:00
KanidmdOpt ::Reindex ( _copt ) = > {
2020-06-18 02:30:42 +02:00
eprintln! ( " Running in reindex mode ... " ) ;
2019-11-17 03:36:32 +01:00
2020-06-18 02:30:42 +02:00
// config.update_db_path(&copt.db_path);
2020-08-04 04:58:11 +02:00
reindex_server_core ( & config ) ;
2019-11-17 03:36:32 +01:00
}
2021-02-13 04:46:22 +01:00
KanidmdOpt ::DomainChange ( dopt ) = > {
2020-06-18 02:30:42 +02:00
eprintln! ( " Running in domain name change mode ... this may take a long time ... " ) ;
2019-11-29 01:48:22 +01:00
2020-06-18 02:30:42 +02:00
// config.update_db_path(&dopt.commonopts.db_path);
2020-08-04 04:58:11 +02:00
domain_rename_core ( & config , & dopt . new_domain_name ) ;
2019-11-29 01:48:22 +01:00
}
2019-07-15 01:15:25 +02:00
}
2018-09-29 09:54:16 +02:00
}