1996-05-04 11:50:46 +04:00
/*
2001-06-29 12:04:12 +04:00
* Unix SMB / Netbios implementation .
* Version 1.9 .
* smbpasswd module .
* Copyright ( C ) Jeremy Allison 1995 - 1998
* Copyright ( C ) Tim Potter 2001
1996-05-04 11:50:46 +04:00
*
2001-06-29 12:04:12 +04:00
* 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 .
1996-05-04 11:50:46 +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 .
*
* 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
2001-06-29 12:04:12 +04:00
* Mass Ave , Cambridge , MA 0213 9 , USA . */
1996-05-04 11:50:46 +04:00
# include "includes.h"
1998-04-25 05:12:08 +04:00
extern pstring global_myname ;
1998-04-30 02:27:26 +04:00
1998-11-19 01:04:24 +03:00
/*
* Next two lines needed for SunOS and don ' t
* hurt anything else . . .
*/
extern char * optarg ;
extern int optind ;
1998-04-25 05:12:08 +04:00
2001-06-25 05:15:17 +04:00
/* forced running in root-mode */
static BOOL local_mode ;
1998-11-12 09:12:19 +03:00
/*********************************************************
Print command usage on stderr and die .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void usage ( void )
1996-05-04 11:50:46 +04:00
{
1998-11-12 09:12:19 +03:00
if ( getuid ( ) = = 0 ) {
printf ( " smbpasswd [options] [username] [password] \n " ) ;
} else {
printf ( " smbpasswd [options] [password] \n " ) ;
}
printf ( " options: \n " ) ;
printf ( " -s use stdin for password prompt \n " ) ;
printf ( " -D LEVEL debug level \n " ) ;
printf ( " -U USER remote username \n " ) ;
printf ( " -r MACHINE remote machine \n " ) ;
2001-06-25 05:15:17 +04:00
if ( getuid ( ) = = 0 | | local_mode ) {
printf ( " -L local mode (must be first option) \n " ) ;
1998-11-12 09:12:19 +03:00
printf ( " -R ORDER name resolve order \n " ) ;
printf ( " -j DOMAIN join domain name \n " ) ;
printf ( " -a add user \n " ) ;
2000-02-26 01:25:25 +03:00
printf ( " -x delete user \n " ) ;
1998-11-12 23:22:11 +03:00
printf ( " -d disable user \n " ) ;
1998-11-12 09:12:19 +03:00
printf ( " -e enable user \n " ) ;
printf ( " -n set no password \n " ) ;
1999-12-13 16:27:58 +03:00
printf ( " -m machine trust account \n " ) ;
1998-11-12 09:12:19 +03:00
}
1996-05-04 11:50:46 +04:00
exit ( 1 ) ;
}
1999-11-21 00:59:16 +03:00
/*********************************************************
Join a domain .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
static int join_domain ( char * domain , char * remote )
1999-11-21 00:59:16 +03:00
{
1999-12-13 16:27:58 +03:00
pstring remote_machine ;
1999-11-21 00:59:16 +03:00
fstring trust_passwd ;
1999-12-13 16:27:58 +03:00
unsigned char orig_trust_passwd_hash [ 16 ] ;
BOOL ret ;
pstrcpy ( remote_machine , remote ? remote : " " ) ;
fstrcpy ( trust_passwd , global_myname ) ;
strlower ( trust_passwd ) ;
E_md4hash ( ( uchar * ) trust_passwd , orig_trust_passwd_hash ) ;
1999-11-21 00:59:16 +03:00
1999-12-13 16:27:58 +03:00
/* Ensure that we are not trying to join a
domain if we are locally set up as a domain
controller . */
1999-11-21 00:59:16 +03:00
1999-12-13 16:27:58 +03:00
if ( strequal ( remote , global_myname ) ) {
fprintf ( stderr , " Cannot join domain %s as the domain controller name is our own. We cannot be a domain controller for a domain and also be a domain member. \n " , domain ) ;
1999-11-21 00:59:16 +03:00
return 1 ;
}
1999-12-13 16:27:58 +03:00
/*
* Write the old machine account password .
*/
1999-11-21 00:59:16 +03:00
2000-06-03 10:34:40 +04:00
if ( ! secrets_store_trust_account_password ( domain , orig_trust_passwd_hash ) ) {
1999-12-13 16:27:58 +03:00
fprintf ( stderr , " Unable to write the machine account password for \
machine % s in domain % s . \ n " , global_myname, domain);
1999-11-21 00:59:16 +03:00
return 1 ;
}
1999-12-13 16:27:58 +03:00
/*
* If we are given a remote machine assume this is the PDC .
*/
if ( remote = = NULL ) {
pstrcpy ( remote_machine , lp_passwordserver ( ) ) ;
1998-11-12 09:12:19 +03:00
}
1999-12-13 16:27:58 +03:00
if ( ! * remote_machine ) {
fprintf ( stderr , " No password server list given in smb.conf - \
unable to join domain . \ n " );
1999-07-22 14:55:41 +04:00
return 1 ;
}
1999-12-13 16:27:58 +03:00
ret = change_trust_account_password ( domain , remote_machine ) ;
1998-11-12 09:12:19 +03:00
1999-12-13 16:27:58 +03:00
if ( ! ret ) {
2000-05-08 14:42:21 +04:00
trust_password_delete ( domain ) ;
1998-11-12 09:12:19 +03:00
fprintf ( stderr , " Unable to join domain %s. \n " , domain ) ;
1999-12-13 16:27:58 +03:00
} else {
printf ( " Joined domain %s. \n " , domain ) ;
1998-11-12 09:12:19 +03:00
}
1999-12-13 16:27:58 +03:00
return ( int ) ret ;
1998-11-12 09:12:19 +03:00
}
2001-06-29 12:04:12 +04:00
/* Initialise client credentials for authenticated pipe access */
void init_rpcclient_creds ( struct ntuser_creds * creds , char * username ,
char * domain , char * password )
{
ZERO_STRUCTP ( creds ) ;
if ( lp_encrypted_passwords ( ) ) {
pwd_make_lm_nt_16 ( & creds - > pwd , password ) ;
} else {
pwd_set_cleartext ( & creds - > pwd , password ) ;
}
fstrcpy ( creds - > user_name , username ) ;
fstrcpy ( creds - > domain , domain ) ;
}
/*********************************************************
Join a domain using the administrator username and password
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Macro for checking RPC error codes to make things more readable */
# define CHECK_RPC_ERR(rpc, msg) \
2001-09-04 11:13:01 +04:00
if ( ! NT_STATUS_IS_OK ( result = rpc ) ) { \
2001-06-29 12:04:12 +04:00
DEBUG ( 0 , ( msg " : %s \n " , get_nt_error_msg ( result ) ) ) ; \
goto done ; \
}
# define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \
2001-09-04 11:13:01 +04:00
if ( ! NT_STATUS_IS_OK ( result = rpc ) ) { \
2001-06-29 12:04:12 +04:00
DEBUG ( 0 , debug_args ) ; \
goto done ; \
}
static int join_domain_byuser ( char * domain , char * remote_machine ,
char * username , char * password )
{
/* libsmb variables */
struct nmb_name calling , called ;
struct ntuser_creds creds ;
struct cli_state cli ;
fstring dest_host , acct_name ;
struct in_addr dest_ip ;
TALLOC_CTX * mem_ctx ;
2001-08-31 09:48:37 +04:00
uint32 acb_info ;
2001-06-29 12:04:12 +04:00
/* rpc variables */
POLICY_HND lsa_pol , sam_pol , domain_pol , user_pol ;
DOM_SID domain_sid ;
uint32 user_rid ;
/* Password stuff */
char * machine_pwd ;
int plen = 0 ;
uchar pwbuf [ 516 ] , ntpw [ 16 ] , sess_key [ 16 ] ;
SAM_USERINFO_CTR ctr ;
SAM_USER_INFO_24 p24 ;
SAM_USER_INFO_10 p10 ;
/* Misc */
2001-09-04 11:13:01 +04:00
NTSTATUS result ;
2001-06-29 12:04:12 +04:00
int retval = 1 ;
/* Connect to remote machine */
ZERO_STRUCT ( cli ) ;
ZERO_STRUCT ( creds ) ;
if ( ! ( mem_ctx = talloc_init ( ) ) ) {
DEBUG ( 0 , ( " Could not initialise talloc context \n " ) ) ;
goto done ;
}
if ( ! cli_initialise ( & cli ) ) {
DEBUG ( 0 , ( " Could not initialise client structure \n " ) ) ;
goto done ;
}
init_rpcclient_creds ( & creds , username , domain , password ) ;
cli_init_creds ( & cli , & creds ) ;
if ( ! resolve_srv_name ( remote_machine , dest_host , & dest_ip ) ) {
DEBUG ( 0 , ( " Could not resolve name %s \n " , remote_machine ) ) ;
goto done ;
}
make_nmb_name ( & called , dns_to_netbios_name ( dest_host ) , 0x20 ) ;
make_nmb_name ( & calling , dns_to_netbios_name ( global_myname ) , 0 ) ;
if ( ! cli_establish_connection ( & cli , dest_host , & dest_ip , & calling ,
& called , " IPC$ " , " IPC " , False , True ) ) {
DEBUG ( 0 , ( " Error connecting to %s \n " , dest_host ) ) ;
goto done ;
}
/* Fetch domain sid */
if ( ! cli_nt_session_open ( & cli , PIPE_LSARPC ) ) {
DEBUG ( 0 , ( " Error connecting to SAM pipe \n " ) ) ;
goto done ;
}
CHECK_RPC_ERR ( cli_lsa_open_policy ( & cli , mem_ctx , True ,
SEC_RIGHTS_MAXIMUM_ALLOWED ,
& lsa_pol ) ,
" error opening lsa policy handle " ) ;
CHECK_RPC_ERR ( cli_lsa_query_info_policy ( & cli , mem_ctx , & lsa_pol ,
5 , domain , & domain_sid ) ,
" error querying info policy " ) ;
cli_lsa_close ( & cli , mem_ctx , & lsa_pol ) ;
cli_nt_session_close ( & cli ) ; /* Done with this pipe */
/* Create domain user */
if ( ! cli_nt_session_open ( & cli , PIPE_SAMR ) ) {
DEBUG ( 0 , ( " Error connecting to SAM pipe \n " ) ) ;
goto done ;
}
CHECK_RPC_ERR ( cli_samr_connect ( & cli , mem_ctx ,
SEC_RIGHTS_MAXIMUM_ALLOWED ,
& sam_pol ) ,
" could not connect to SAM database " ) ;
CHECK_RPC_ERR ( cli_samr_open_domain ( & cli , mem_ctx , & sam_pol ,
SEC_RIGHTS_MAXIMUM_ALLOWED ,
& domain_sid , & domain_pol ) ,
" could not open domain " ) ;
/* Create domain user */
fstrcpy ( acct_name , global_myname ) ;
fstrcat ( acct_name , " $ " ) ;
strlower ( acct_name ) ;
2001-08-31 09:48:37 +04:00
acb_info = ( lp_server_role ( ) = = ROLE_DOMAIN_BDC ) ? ACB_SVRTRUST :
ACB_WSTRUST ;
2001-06-29 12:04:12 +04:00
{
uint32 unknown = 0xe005000b ;
result = cli_samr_create_dom_user ( & cli , mem_ctx , & domain_pol ,
2001-08-31 09:48:37 +04:00
acct_name , acb_info ,
2001-06-29 12:04:12 +04:00
unknown , & user_pol ,
& user_rid ) ;
2001-08-03 03:48:51 +04:00
/* We *must* do this.... don't ask... */
CHECK_RPC_ERR_DEBUG ( cli_samr_close ( & cli , mem_ctx , & user_pol ) , ( " error closing user policy " ) ) ;
result = NT_STATUS_USER_EXISTS ;
}
2001-06-29 12:04:12 +04:00
2001-09-04 11:13:01 +04:00
if ( NT_STATUS_V ( result ) = = NT_STATUS_V ( NT_STATUS_USER_EXISTS ) ) {
2001-06-29 12:04:12 +04:00
uint32 num_rids , * name_types , * user_rids ;
uint32 flags = 0x3e8 ;
char * names ;
/* Look up existing rid */
names = ( char * ) & acct_name [ 0 ] ;
CHECK_RPC_ERR_DEBUG (
cli_samr_lookup_names ( & cli , mem_ctx ,
& domain_pol , flags ,
1 , & names , & num_rids ,
& user_rids , & name_types ) ,
( " error looking up rid for user %s: %s \n " ,
acct_name , get_nt_error_msg ( result ) ) ) ;
if ( name_types [ 0 ] ! = SID_NAME_USER ) {
DEBUG ( 0 , ( " %s is not a user account \n " , acct_name ) ) ;
goto done ;
}
user_rid = user_rids [ 0 ] ;
/* Open handle on user */
CHECK_RPC_ERR_DEBUG (
cli_samr_open_user ( & cli , mem_ctx , & domain_pol ,
SEC_RIGHTS_MAXIMUM_ALLOWED ,
user_rid , & user_pol ) ,
( " could not re-open existing user %s: %s \n " ,
acct_name , get_nt_error_msg ( result ) ) ) ;
2001-09-04 11:13:01 +04:00
} else if ( ! NT_STATUS_IS_OK ( result ) ) {
2001-06-29 12:04:12 +04:00
DEBUG ( 0 , ( " error creating domain user: %s \n " ,
get_nt_error_msg ( result ) ) ) ;
goto done ;
}
/* Create a random machine account password */
{
UNISTR2 upw ; /* Unicode password */
upw . buffer = ( uint16 * ) talloc_zero ( mem_ctx , 0xc *
sizeof ( uint16 ) ) ;
upw . uni_str_len = 0xc ;
upw . uni_max_len = 0xc ;
machine_pwd = ( char * ) upw . buffer ;
plen = upw . uni_str_len * 2 ;
2001-08-25 00:32:01 +04:00
generate_random_buffer ( ( unsigned char * ) machine_pwd , plen , True ) ;
2001-06-29 12:04:12 +04:00
2001-08-25 00:32:01 +04:00
encode_pw_buffer ( ( char * ) pwbuf , machine_pwd , plen , False ) ;
2001-06-29 12:04:12 +04:00
nt_owf_genW ( & upw , ntpw ) ;
}
/* Set password on machine account */
ZERO_STRUCT ( ctr ) ;
ZERO_STRUCT ( p24 ) ;
2001-08-25 00:32:01 +04:00
init_sam_user_info24 ( & p24 , ( char * ) pwbuf , 24 ) ;
2001-06-29 12:04:12 +04:00
ctr . switch_value = 24 ;
ctr . info . id24 = & p24 ;
/* I don't think this is quite the right place for this
calculation . It should be moved somewhere where the credentials
are calculated . ) - : */
mdfour ( sess_key , cli . pwd . smb_nt_pwd , 16 ) ;
CHECK_RPC_ERR ( cli_samr_set_userinfo ( & cli , mem_ctx , & user_pol , 24 ,
sess_key , & ctr ) ,
" error setting trust account password " ) ;
/* Why do we have to try to (re-)set the ACB to be the same as what
we passed in the samr_create_dom_user ( ) call ? When a NT
workstation is joined to a domain by an administrator the
acb_info is set to 0x80 . For a normal user with " Add
workstations to the domain " rights the acb_info is 0x84. I'm
not sure whether it is supposed to make a difference or not . NT
seems to cope with either value so don ' t bomb out if the set
userinfo2 level 0x10 fails . - tpot */
2001-08-03 03:48:51 +04:00
ZERO_STRUCT ( ctr ) ;
2001-06-29 12:04:12 +04:00
ctr . switch_value = 0x10 ;
ctr . info . id10 = & p10 ;
2001-08-31 09:48:37 +04:00
init_sam_user_info10 ( & p10 , acb_info ) ;
2001-06-29 12:04:12 +04:00
/* Ignoring the return value is necessary for joining a domain
as a normal user with " Add workstation to domain " privilege . */
result = cli_samr_set_userinfo2 ( & cli , mem_ctx , & user_pol , 0x10 ,
sess_key , & ctr ) ;
/* Now store the secret in the secrets database */
strupper ( domain ) ;
if ( ! secrets_store_domain_sid ( domain , & domain_sid ) | |
! secrets_store_trust_account_password ( domain , ntpw ) ) {
DEBUG ( 0 , ( " error storing domain secrets \n " ) ) ;
goto done ;
}
retval = 0 ; /* Success! */
done :
/* Close down pipe - this will clean up open policy handles */
if ( cli . nt_pipe_fnum )
cli_nt_session_close ( & cli ) ;
/* Display success or failure */
if ( retval ! = 0 ) {
trust_password_delete ( domain ) ;
fprintf ( stderr , " Unable to join domain %s. \n " , domain ) ;
} else {
printf ( " Joined domain %s. \n " , domain ) ;
}
return retval ;
}
1998-04-30 02:27:26 +04:00
1998-11-12 09:12:19 +03:00
static void set_line_buffering ( FILE * f )
1998-04-30 02:27:26 +04:00
{
1998-11-12 09:12:19 +03:00
setvbuf ( f , NULL , _IOLBF , 0 ) ;
1998-04-30 02:27:26 +04:00
}
1998-11-04 03:57:00 +03:00
/*************************************************************
Utility function to prompt for passwords from stdin . Each
password entered must end with a newline .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static char * stdin_new_passwd ( void )
{
1998-11-12 09:12:19 +03:00
static fstring new_passwd ;
size_t len ;
1998-11-13 06:37:01 +03:00
ZERO_ARRAY ( new_passwd ) ;
1998-11-12 09:12:19 +03:00
/*
* if no error is reported from fgets ( ) and string at least contains
* the newline that ends the password , then replace the newline with
* a null terminator .
*/
if ( fgets ( new_passwd , sizeof ( new_passwd ) , stdin ) ! = NULL ) {
if ( ( len = strlen ( new_passwd ) ) > 0 ) {
if ( new_passwd [ len - 1 ] = = ' \n ' )
new_passwd [ len - 1 ] = 0 ;
}
}
return ( new_passwd ) ;
1998-11-04 03:57:00 +03:00
}
1998-11-12 09:12:19 +03:00
1998-11-04 03:57:00 +03:00
/*************************************************************
Utility function to get passwords via tty or stdin
Used if the ' - s ' option is set to silently get passwords
to enable scripting .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static char * get_pass ( char * prompt , BOOL stdin_get )
{
1998-11-12 09:12:19 +03:00
char * p ;
if ( stdin_get ) {
p = stdin_new_passwd ( ) ;
} else {
p = getpass ( prompt ) ;
}
return xstrdup ( p ) ;
1998-11-04 03:57:00 +03:00
}
1998-09-25 02:33:13 +04:00
/*************************************************************
Utility function to prompt for new password .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-11-12 09:12:19 +03:00
static char * prompt_for_new_password ( BOOL stdin_get )
1998-09-25 02:33:13 +04:00
{
1998-11-12 09:12:19 +03:00
char * p ;
fstring new_passwd ;
1998-09-25 02:33:13 +04:00
1998-11-13 06:37:01 +03:00
ZERO_ARRAY ( new_passwd ) ;
1998-11-04 03:57:00 +03:00
1998-11-12 09:12:19 +03:00
p = get_pass ( " New SMB password: " , stdin_get ) ;
1998-09-25 02:33:13 +04:00
1998-11-12 09:12:19 +03:00
fstrcpy ( new_passwd , p ) ;
2001-09-17 15:48:29 +04:00
SAFE_FREE ( p ) ;
1998-09-25 02:33:13 +04:00
1998-11-12 09:12:19 +03:00
p = get_pass ( " Retype new SMB password: " , stdin_get ) ;
1998-09-25 02:33:13 +04:00
1998-11-12 09:12:19 +03:00
if ( strcmp ( p , new_passwd ) ) {
fprintf ( stderr , " Mismatch - password unchanged. \n " ) ;
1999-12-13 16:27:58 +03:00
ZERO_ARRAY ( new_passwd ) ;
2001-09-17 15:48:29 +04:00
SAFE_FREE ( p ) ;
1998-11-12 09:12:19 +03:00
return NULL ;
}
1998-09-25 02:33:13 +04:00
2000-07-26 07:55:17 +04:00
return p ;
1998-09-25 02:33:13 +04:00
}
1998-03-25 00:04:36 +03:00
1998-11-12 09:12:19 +03:00
/*************************************************************
2000-02-26 01:25:25 +03:00
Change a password either locally or remotely .
1998-11-12 09:12:19 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-02-26 01:25:25 +03:00
1998-11-12 09:12:19 +03:00
static BOOL password_change ( const char * remote_machine , char * user_name ,
2000-02-26 01:25:25 +03:00
char * old_passwd , char * new_passwd , int local_flags )
1998-11-12 09:12:19 +03:00
{
1998-11-13 02:49:32 +03:00
BOOL ret ;
pstring err_str ;
pstring msg_str ;
1999-12-13 16:27:58 +03:00
if ( remote_machine ! = NULL ) {
2000-02-26 01:25:25 +03:00
if ( local_flags & ( LOCAL_ADD_USER | LOCAL_DELETE_USER | LOCAL_DISABLE_USER | LOCAL_ENABLE_USER |
2001-03-11 03:32:10 +03:00
LOCAL_TRUST_ACCOUNT | LOCAL_SET_NO_PASSWORD ) ) {
1998-11-12 09:12:19 +03:00
/* these things can't be done remotely yet */
return False ;
}
2001-03-11 03:32:10 +03:00
ret = remote_password_change ( remote_machine , user_name ,
2001-09-29 17:08:26 +04:00
old_passwd , new_passwd , err_str , sizeof ( err_str ) ) ;
1999-12-13 16:27:58 +03:00
if ( * err_str )
1998-11-13 02:49:32 +03:00
fprintf ( stderr , err_str ) ;
return ret ;
1998-11-12 09:12:19 +03:00
}
2000-02-26 01:25:25 +03:00
ret = local_password_change ( user_name , local_flags , new_passwd ,
1999-12-13 16:27:58 +03:00
err_str , sizeof ( err_str ) , msg_str , sizeof ( msg_str ) ) ;
1998-11-13 02:49:32 +03:00
1999-12-13 16:27:58 +03:00
if ( * msg_str )
1998-11-13 02:49:32 +03:00
printf ( msg_str ) ;
1999-12-13 16:27:58 +03:00
if ( * err_str )
1998-11-13 02:49:32 +03:00
fprintf ( stderr , err_str ) ;
return ret ;
1998-11-12 09:12:19 +03:00
}
/*************************************************************
2000-02-26 01:25:25 +03:00
Handle password changing for root .
1998-11-12 09:12:19 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-02-26 01:25:25 +03:00
1998-11-12 09:12:19 +03:00
static int process_root ( int argc , char * argv [ ] )
{
struct passwd * pwd ;
2000-07-26 07:55:17 +04:00
int result = 0 , ch ;
2001-09-13 00:00:42 +04:00
BOOL joining_domain = False , got_pass = False , got_username = False ;
2001-10-30 08:21:16 +03:00
int local_flags = LOCAL_SET_PASSWORD ;
1998-11-12 09:12:19 +03:00
BOOL stdin_passwd_get = False ;
2001-06-29 12:04:12 +04:00
fstring user_name , user_password ;
1998-11-12 09:12:19 +03:00
char * new_domain = NULL ;
char * new_passwd = NULL ;
char * old_passwd = NULL ;
char * remote_machine = NULL ;
1999-12-13 16:27:58 +03:00
2001-09-13 00:00:42 +04:00
ZERO_STRUCT ( user_name ) ;
ZERO_STRUCT ( user_password ) ;
2001-08-30 02:47:59 +04:00
2001-08-30 09:54:41 +04:00
user_name [ 0 ] = ' \0 ' ;
2001-09-13 00:00:42 +04:00
while ( ( ch = getopt ( argc , argv , " axdehmnj:r:sR:D:U:L " ) ) ! = EOF ) {
1999-12-13 16:27:58 +03:00
switch ( ch ) {
2001-06-25 05:15:17 +04:00
case ' L ' :
local_mode = True ;
break ;
1999-12-13 16:27:58 +03:00
case ' a ' :
2000-02-26 01:25:25 +03:00
local_flags | = LOCAL_ADD_USER ;
break ;
case ' x ' :
local_flags | = LOCAL_DELETE_USER ;
2001-10-30 08:21:16 +03:00
local_flags & = ~ LOCAL_SET_PASSWORD ;
1999-12-13 16:27:58 +03:00
break ;
case ' d ' :
2000-02-26 01:25:25 +03:00
local_flags | = LOCAL_DISABLE_USER ;
2001-10-30 08:21:16 +03:00
local_flags & = ~ LOCAL_SET_PASSWORD ;
1999-12-13 16:27:58 +03:00
break ;
case ' e ' :
2000-02-26 01:25:25 +03:00
local_flags | = LOCAL_ENABLE_USER ;
2001-10-30 08:21:16 +03:00
local_flags & = ~ LOCAL_SET_PASSWORD ;
1999-12-13 16:27:58 +03:00
break ;
2000-02-26 01:25:25 +03:00
case ' m ' :
local_flags | = LOCAL_TRUST_ACCOUNT ;
1999-12-13 16:27:58 +03:00
break ;
case ' n ' :
2000-02-26 01:25:25 +03:00
local_flags | = LOCAL_SET_NO_PASSWORD ;
2001-10-30 08:21:16 +03:00
local_flags & = ~ LOCAL_SET_PASSWORD ;
2000-03-01 21:58:50 +03:00
break ;
2000-02-26 01:25:25 +03:00
case ' j ' :
new_domain = optarg ;
strupper ( new_domain ) ;
joining_domain = True ;
break ;
1999-12-13 16:27:58 +03:00
case ' r ' :
remote_machine = optarg ;
break ;
case ' s ' :
set_line_buffering ( stdin ) ;
set_line_buffering ( stdout ) ;
set_line_buffering ( stderr ) ;
stdin_passwd_get = True ;
break ;
case ' R ' :
lp_set_name_resolve_order ( optarg ) ;
break ;
2000-02-26 01:25:25 +03:00
case ' D ' :
DEBUGLEVEL = atoi ( optarg ) ;
1999-12-13 16:27:58 +03:00
break ;
2001-06-29 12:04:12 +04:00
case ' U ' : {
char * lp ;
2001-09-13 00:00:42 +04:00
got_username = True ;
2001-06-29 12:04:12 +04:00
fstrcpy ( user_name , optarg ) ;
2001-07-04 11:36:09 +04:00
if ( ( lp = strchr_m ( user_name , ' % ' ) ) ) {
2001-06-29 12:04:12 +04:00
* lp = 0 ;
fstrcpy ( user_password , lp + 1 ) ;
got_pass = True ;
2001-07-04 11:36:09 +04:00
memset ( strchr_m ( optarg , ' % ' ) + 1 , ' X ' ,
2001-06-29 12:04:12 +04:00
strlen ( user_password ) ) ;
}
1999-12-13 16:27:58 +03:00
break ;
2001-06-29 12:04:12 +04:00
}
2001-08-03 03:48:51 +04:00
case ' h ' :
1999-12-13 16:27:58 +03:00
default :
usage ( ) ;
1998-11-12 09:12:19 +03:00
}
}
argc - = optind ;
argv + = optind ;
/*
2001-04-24 20:44:28 +04:00
* Ensure both add / delete user are not set
2000-02-26 01:25:25 +03:00
* Ensure add / delete user and either remote machine or join domain are
1998-11-12 09:12:19 +03:00
* not both set .
*/
2001-04-24 22:53:15 +04:00
if ( ( ( local_flags & ( LOCAL_ADD_USER | LOCAL_DELETE_USER ) ) = = ( LOCAL_ADD_USER | LOCAL_DELETE_USER ) ) | |
2001-04-24 20:44:28 +04:00
( ( local_flags & ( LOCAL_ADD_USER | LOCAL_DELETE_USER ) ) & &
( ( remote_machine ! = NULL ) | | joining_domain ) ) ) {
1998-11-12 09:12:19 +03:00
usage ( ) ;
}
2001-01-12 02:21:17 +03:00
/* Only load interfaces if we are doing network operations. */
if ( joining_domain | | remote_machine ) {
load_interfaces ( ) ;
}
2001-06-29 12:04:12 +04:00
/* Join a domain */
if ( joining_domain ) {
2000-02-26 01:25:25 +03:00
if ( argc ! = 0 )
usage ( ) ;
2001-06-29 12:04:12 +04:00
/* Are we joining by specifing an admin username and
password ? */
if ( user_name [ 0 ] ) {
/* Get administrator password if not specified */
if ( ! got_pass ) {
char * pass = getpass ( " Password: " ) ;
if ( pass )
pstrcpy ( user_password , pass ) ;
}
return join_domain_byuser ( new_domain , remote_machine ,
user_name , user_password ) ;
} else {
/* Or just with the server manager? */
return join_domain ( new_domain , remote_machine ) ;
}
1998-11-12 09:12:19 +03:00
}
/*
* Deal with root - can add a user , but only locally .
*/
switch ( argc ) {
case 0 :
2001-09-13 00:00:42 +04:00
if ( ! got_username )
fstrcpy ( user_name , " " ) ;
1998-11-12 09:12:19 +03:00
break ;
case 1 :
2001-09-13 00:00:42 +04:00
if ( got_username )
usage ( ) ;
2001-06-29 12:04:12 +04:00
fstrcpy ( user_name , argv [ 0 ] ) ;
1998-11-12 09:12:19 +03:00
break ;
case 2 :
2001-09-13 00:00:42 +04:00
if ( got_username | | got_pass )
usage ( ) ;
2001-06-29 12:04:12 +04:00
fstrcpy ( user_name , argv [ 0 ] ) ;
2000-08-21 23:30:19 +04:00
new_passwd = xstrdup ( argv [ 1 ] ) ;
1998-11-12 09:12:19 +03:00
break ;
default :
usage ( ) ;
}
2001-09-29 17:08:26 +04:00
if ( ! user_name [ 0 ] & & ( pwd = sys_getpwuid ( geteuid ( ) ) ) ) {
2001-06-29 12:04:12 +04:00
fstrcpy ( user_name , pwd - > pw_name ) ;
1998-11-12 09:12:19 +03:00
}
2001-06-29 12:04:12 +04:00
if ( ! user_name [ 0 ] ) {
1998-11-12 09:12:19 +03:00
fprintf ( stderr , " You must specify a username \n " ) ;
exit ( 1 ) ;
}
2000-02-26 01:25:25 +03:00
if ( local_flags & LOCAL_TRUST_ACCOUNT ) {
1998-11-12 09:12:19 +03:00
/* add the $ automatically */
static fstring buf ;
1998-11-16 23:19:57 +03:00
/*
* Remove any trailing ' $ ' before we
* generate the initial machine password .
*/
if ( user_name [ strlen ( user_name ) - 1 ] = = ' $ ' ) {
user_name [ strlen ( user_name ) - 1 ] = 0 ;
}
2000-02-26 01:25:25 +03:00
if ( local_flags & LOCAL_ADD_USER ) {
2001-09-17 15:48:29 +04:00
SAFE_FREE ( new_passwd ) ;
1998-11-12 09:12:19 +03:00
new_passwd = xstrdup ( user_name ) ;
strlower ( new_passwd ) ;
}
1998-11-16 23:19:57 +03:00
/*
* Now ensure the username ends in ' $ ' for
* the machine add .
*/
1998-11-12 09:12:19 +03:00
slprintf ( buf , sizeof ( buf ) - 1 , " %s$ " , user_name ) ;
2001-06-29 12:04:12 +04:00
fstrcpy ( user_name , buf ) ;
1998-11-12 09:12:19 +03:00
}
if ( remote_machine ! = NULL ) {
old_passwd = get_pass ( " Old SMB password: " , stdin_passwd_get ) ;
}
2001-10-30 08:21:16 +03:00
if ( ! ( local_flags & LOCAL_SET_PASSWORD ) ) {
1999-12-13 16:27:58 +03:00
1998-11-12 23:22:11 +03:00
/*
* If we are trying to enable a user , first we need to find out
* if they are using a modern version of the smbpasswd file that
* disables a user by just writing a flag into the file . If so
* then we can re - enable a user without prompting for a new
* password . If not ( ie . they have a no stored password in the
* smbpasswd file ) then we need to prompt for a new password .
*/
2001-03-11 03:32:10 +03:00
if ( local_flags & LOCAL_ENABLE_USER ) {
2001-05-04 19:44:27 +04:00
SAM_ACCOUNT * sampass = NULL ;
BOOL ret ;
pdb_init_sam ( & sampass ) ;
ret = pdb_getsampwnam ( sampass , user_name ) ;
2001-10-30 08:21:16 +03:00
if ( ( sampass ! = False ) & & ( pdb_get_lanman_passwd ( sampass ) = = NULL ) ) {
local_flags | = LOCAL_SET_PASSWORD ;
1998-11-12 23:22:11 +03:00
}
2001-09-29 17:08:26 +04:00
pdb_free_sam ( & sampass ) ;
1998-11-12 23:22:11 +03:00
}
2001-10-30 08:21:16 +03:00
}
1998-11-12 23:22:11 +03:00
2001-10-30 08:21:16 +03:00
if ( local_flags & LOCAL_SET_PASSWORD ) {
new_passwd = prompt_for_new_password ( stdin_passwd_get ) ;
1999-12-13 16:27:58 +03:00
if ( ! new_passwd ) {
fprintf ( stderr , " Unable to get new password. \n " ) ;
exit ( 1 ) ;
}
1999-03-19 08:00:39 +03:00
}
2001-03-11 03:32:10 +03:00
if ( ! password_change ( remote_machine , user_name , old_passwd , new_passwd , local_flags ) ) {
2000-02-26 01:25:25 +03:00
fprintf ( stderr , " Failed to modify password entry for user %s \n " , user_name ) ;
2000-07-26 07:55:17 +04:00
result = 1 ;
goto done ;
1998-11-12 09:12:19 +03:00
}
2001-10-30 08:21:16 +03:00
if ( ! ( local_flags & ( LOCAL_ADD_USER | LOCAL_DISABLE_USER | LOCAL_ENABLE_USER | LOCAL_DELETE_USER | LOCAL_SET_NO_PASSWORD | LOCAL_SET_PASSWORD ) ) ) {
2001-05-04 19:44:27 +04:00
SAM_ACCOUNT * sampass = NULL ;
BOOL ret ;
pdb_init_sam ( & sampass ) ;
ret = pdb_getsampwnam ( sampass , user_name ) ;
1999-12-13 16:27:58 +03:00
printf ( " Password changed for user %s. " , user_name ) ;
2001-05-04 19:44:27 +04:00
if ( ( ret ! = False ) & & ( pdb_get_acct_ctrl ( sampass ) & ACB_DISABLED ) )
1999-12-13 16:27:58 +03:00
printf ( " User has disabled flag set. " ) ;
2001-05-04 19:44:27 +04:00
if ( ( ret ! = False ) & & ( pdb_get_acct_ctrl ( sampass ) & ACB_PWNOTREQ ) )
1999-12-13 16:27:58 +03:00
printf ( " User has no password flag set. " ) ;
printf ( " \n " ) ;
2001-09-29 17:08:26 +04:00
pdb_free_sam ( & sampass ) ;
1998-11-12 09:12:19 +03:00
}
2000-07-26 07:55:17 +04:00
done :
2001-09-17 15:48:29 +04:00
SAFE_FREE ( new_passwd ) ;
2000-07-26 07:55:17 +04:00
return result ;
1998-11-12 09:12:19 +03:00
}
/*************************************************************
handle password changing for non - root
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int process_nonroot ( int argc , char * argv [ ] )
{
struct passwd * pwd = NULL ;
2000-07-26 07:55:17 +04:00
int result = 0 , ch ;
1998-11-12 09:12:19 +03:00
BOOL stdin_passwd_get = False ;
char * old_passwd = NULL ;
char * remote_machine = NULL ;
char * user_name = NULL ;
char * new_passwd = NULL ;
1999-12-13 16:27:58 +03:00
while ( ( ch = getopt ( argc , argv , " hD:r:sU: " ) ) ! = EOF ) {
switch ( ch ) {
1998-11-12 09:12:19 +03:00
case ' D ' :
DEBUGLEVEL = atoi ( optarg ) ;
break ;
case ' r ' :
remote_machine = optarg ;
break ;
case ' s ' :
set_line_buffering ( stdin ) ;
set_line_buffering ( stdout ) ;
set_line_buffering ( stderr ) ;
stdin_passwd_get = True ;
break ;
case ' U ' :
user_name = optarg ;
break ;
default :
usage ( ) ;
}
}
argc - = optind ;
argv + = optind ;
if ( argc > 1 ) {
usage ( ) ;
}
if ( argc = = 1 ) {
new_passwd = argv [ 0 ] ;
}
if ( ! user_name ) {
1999-12-13 16:27:58 +03:00
pwd = sys_getpwuid ( getuid ( ) ) ;
1998-11-12 09:12:19 +03:00
if ( pwd ) {
user_name = xstrdup ( pwd - > pw_name ) ;
} else {
fprintf ( stderr , " you don't exist - go away \n " ) ;
exit ( 1 ) ;
}
}
/*
* A non - root user is always setting a password
* via a remote machine ( even if that machine is
* localhost ) .
*/
2001-01-12 02:21:17 +03:00
load_interfaces ( ) ; /* Delayed from main() */
1998-11-12 09:12:19 +03:00
if ( remote_machine = = NULL ) {
remote_machine = " 127.0.0.1 " ;
}
if ( remote_machine ! = NULL ) {
old_passwd = get_pass ( " Old SMB password: " , stdin_passwd_get ) ;
}
if ( ! new_passwd ) {
new_passwd = prompt_for_new_password ( stdin_passwd_get ) ;
}
if ( ! new_passwd ) {
1999-12-13 16:27:58 +03:00
fprintf ( stderr , " Unable to get new password. \n " ) ;
exit ( 1 ) ;
1998-11-12 09:12:19 +03:00
}
2000-02-26 01:25:25 +03:00
if ( ! password_change ( remote_machine , user_name , old_passwd , new_passwd , 0 ) ) {
1998-11-12 09:12:19 +03:00
fprintf ( stderr , " Failed to change password for %s \n " , user_name ) ;
2000-07-26 07:55:17 +04:00
result = 1 ;
goto done ;
1998-11-12 09:12:19 +03:00
}
printf ( " Password changed for user %s \n " , user_name ) ;
2000-07-26 07:55:17 +04:00
done :
2001-09-17 15:48:29 +04:00
SAFE_FREE ( old_passwd ) ;
SAFE_FREE ( new_passwd ) ;
2000-07-26 07:55:17 +04:00
return result ;
1998-11-12 09:12:19 +03:00
}
/*********************************************************
Start here .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int main ( int argc , char * * argv )
{
static pstring servicesf = CONFIGFILE ;
1999-12-13 16:27:58 +03:00
# if defined(HAVE_SET_AUTH_PARAMETERS)
set_auth_parameters ( argc , argv ) ;
# endif /* HAVE_SET_AUTH_PARAMETERS */
1998-11-12 09:12:19 +03:00
TimeInit ( ) ;
setup_logging ( " smbpasswd " , True ) ;
2000-11-14 02:03:34 +03:00
if ( ! initialize_password_db ( True ) ) {
1999-12-13 16:27:58 +03:00
fprintf ( stderr , " Can't setup password database vectors. \n " ) ;
1998-11-12 09:12:19 +03:00
exit ( 1 ) ;
}
1999-12-13 16:27:58 +03:00
if ( ! lp_load ( servicesf , True , False , False ) ) {
fprintf ( stderr , " Can't load %s - run testparm to debug it \n " ,
servicesf ) ;
1998-11-12 09:12:19 +03:00
exit ( 1 ) ;
}
/*
* Set the machine NETBIOS name if not already
* set from the config file .
*/
if ( ! * global_myname ) {
char * p ;
1999-12-13 16:27:58 +03:00
fstrcpy ( global_myname , myhostname ( ) ) ;
2001-07-04 11:36:09 +04:00
p = strchr_m ( global_myname , ' . ' ) ;
1998-11-12 09:12:19 +03:00
if ( p ) * p = 0 ;
}
strupper ( global_myname ) ;
/* Check the effective uid - make sure we are not setuid */
if ( ( geteuid ( ) = = ( uid_t ) 0 ) & & ( getuid ( ) ! = ( uid_t ) 0 ) ) {
fprintf ( stderr , " smbpasswd must *NOT* be setuid root. \n " ) ;
exit ( 1 ) ;
}
2001-06-25 05:15:17 +04:00
/* pre-check for local mode option as first option. We can't
do this via normal getopt as getopt can ' t be called
twice . */
if ( argc > 1 & & strcmp ( argv [ 1 ] , " -L " ) = = 0 ) {
local_mode = True ;
}
if ( local_mode | | getuid ( ) = = 0 ) {
2001-07-07 01:53:32 +04:00
secrets_init ( ) ;
1998-11-12 09:12:19 +03:00
return process_root ( argc , argv ) ;
}
return process_nonroot ( argc , argv ) ;
1996-05-04 11:50:46 +04:00
}