1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-28 07:21:54 +03:00
samba-mirror/source3/utils/smbpasswd.c

949 lines
23 KiB
C
Raw Normal View History

/*
* Unix SMB/Netbios implementation.
* Copyright (C) Jeremy Allison 1995-1998
* Copyright (C) Tim Potter 2001
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 675
* Mass Ave, Cambridge, MA 02139, USA. */
#include "includes.h"
extern pstring global_myname;
/*
* Next two lines needed for SunOS and don't
* hurt anything else...
*/
extern char *optarg;
extern int optind;
/** forced running in root-mode **/
static BOOL local_mode;
/**
* Print command usage on stderr and die.
**/
static void usage(void)
{
printf("When run by root:\n");
printf(" smbpasswd [options] [username] [password]\n");
printf("otherwise:\n");
printf(" smbpasswd [options] [password]\n\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");
printf("extra options when run by root or in local mode:\n");
printf(" -L local mode (must be first option)\n");
printf(" -R ORDER name resolve order\n");
printf(" -j DOMAIN join domain name\n");
printf(" -a add user\n");
printf(" -x delete user\n");
printf(" -d disable user\n");
printf(" -e enable user\n");
printf(" -n set no password\n");
printf(" -m machine trust account\n");
exit(1);
}
/*********************************************************
Join a domain.
**********************************************************/
static int join_domain(char *domain, char *remote)
{
pstring remote_machine;
fstring trust_passwd;
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);
/* Ensure that we are not trying to join a
domain if we are locally set up as a domain
controller. */
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);
return 1;
}
/*
* Write the old machine account password.
*/
if(!secrets_store_trust_account_password(domain, orig_trust_passwd_hash)) {
fprintf(stderr, "Unable to write the machine account password for \
machine %s in domain %s.\n", global_myname, domain);
return 1;
}
/*
* If we are given a remote machine assume this is the PDC.
*/
if(remote == NULL) {
pstrcpy(remote_machine, lp_passwordserver());
}
if(!*remote_machine) {
fprintf(stderr, "No password server list given in smb.conf - \
unable to join domain.\n");
return 1;
}
ret = change_trust_account_password( domain, remote_machine);
if(!ret) {
trust_password_delete(domain);
fprintf(stderr,"Unable to join domain %s.\n",domain);
} else {
printf("Joined domain %s.\n",domain);
}
return (int)ret;
}
/* 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) \
if (!NT_STATUS_IS_OK(result = rpc)) { \
DEBUG(0, (msg ": %s\n", get_nt_error_msg(result))); \
goto done; \
}
#define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \
if (!NT_STATUS_IS_OK(result = rpc)) { \
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;
uint32 acb_info;
/* 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 */
NTSTATUS result;
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);
acb_info = (lp_server_role() == ROLE_DOMAIN_BDC) ? ACB_SVRTRUST :
ACB_WSTRUST;
{
uint32 unknown = 0xe005000b;
result = cli_samr_create_dom_user(&cli, mem_ctx, &domain_pol,
acct_name, acb_info,
unknown, &user_pol,
&user_rid);
/* 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;
}
if (NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_USER_EXISTS)) {
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)));
} else if (!NT_STATUS_IS_OK(result)) {
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;
generate_random_buffer((unsigned char *)machine_pwd, plen, True);
encode_pw_buffer((char *)pwbuf, machine_pwd, plen, False);
nt_owf_genW(&upw, ntpw);
}
/* Set password on machine account */
ZERO_STRUCT(ctr);
ZERO_STRUCT(p24);
init_sam_user_info24(&p24, (char *)pwbuf,24);
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 */
ZERO_STRUCT(ctr);
ctr.switch_value = 0x10;
ctr.info.id10 = &p10;
init_sam_user_info10(&p10, acb_info);
/* 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;
}
static void set_line_buffering(FILE *f)
{
setvbuf(f, NULL, _IOLBF, 0);
}
/*************************************************************
Utility function to prompt for passwords from stdin. Each
password entered must end with a newline.
*************************************************************/
static char *stdin_new_passwd(void)
{
static fstring new_passwd;
size_t len;
ZERO_ARRAY(new_passwd);
/*
* 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);
}
/*************************************************************
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)
{
char *p;
if (stdin_get) {
p = stdin_new_passwd();
} else {
p = getpass(prompt);
}
return smb_xstrdup(p);
}
/*************************************************************
Utility function to prompt for new password.
*************************************************************/
static char *prompt_for_new_password(BOOL stdin_get)
{
char *p;
fstring new_passwd;
ZERO_ARRAY(new_passwd);
p = get_pass("New SMB password:", stdin_get);
fstrcpy(new_passwd, p);
SAFE_FREE(p);
p = get_pass("Retype new SMB password:", stdin_get);
if (strcmp(p, new_passwd)) {
fprintf(stderr, "Mismatch - password unchanged.\n");
ZERO_ARRAY(new_passwd);
SAFE_FREE(p);
return NULL;
}
return p;
}
/*************************************************************
Change a password either locally or remotely.
*************************************************************/
static BOOL password_change(const char *remote_machine, char *user_name,
char *old_passwd, char *new_passwd, int local_flags)
{
BOOL ret;
pstring err_str;
pstring msg_str;
if (remote_machine != NULL) {
if (local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER|
LOCAL_TRUST_ACCOUNT|LOCAL_SET_NO_PASSWORD)) {
/* these things can't be done remotely yet */
return False;
}
ret = remote_password_change(remote_machine, user_name,
Fix up a number of intertwined issues: The big one is a global change to allow us to NULLify the free'ed pointer to a former passdb object. This was done to allow idra's SAFE_FREE() macro to do its magic, and to satisfy the input test in pdb_init_sam() for a NULL pointer to start with. This NULL pointer test was what was breaking the adding of accounts up until now, and this code has been reworked to avoid duplicating work - I hope this will avoid a similar mess-up in future. Finally, I fixed a few nasty bugs where the pdb_ fuctions's return codes were being ignored. Some of these functions malloc() and are permitted to fail. Also, this caught a nasty bug where pdb_set_lanman_password(sam, NULL) acheived precisely didilly-squat, just returning False. Now that we check the returns this bug was spotted. This could allow different LM and NT passwords. - the pdbedit code needs to start checking these too, but I havn't had a chance to fix it. I have also fixed up where some of the password changing code was using the pdb_set functions to store *internal* data. I assume this is from a previous lot of mass conversion work... Most likally (and going on past experience) I have missed somthing, probably in the LanMan password change code which I havn't yet been able to test, but this lot is in much better shape than it was before. If all this is too much to swallow (particularly for 2.2.2) then just adding a sam_pass = NULL to the particular line of passdb.c should do the trick for the ovbious bug. Andrew Bartlett (This used to be commit 762c8758a7869809d89b4da9c2a5249678942930)
2001-09-29 17:08:26 +04:00
old_passwd, new_passwd, err_str, sizeof(err_str));
if(*err_str)
fprintf(stderr, err_str);
return ret;
}
ret = local_password_change(user_name, local_flags, new_passwd,
err_str, sizeof(err_str), msg_str, sizeof(msg_str));
if(*msg_str)
printf(msg_str);
if(*err_str)
fprintf(stderr, err_str);
return ret;
}
/*************************************************************
Handle password changing for root.
*************************************************************/
static int process_root(int argc, char *argv[])
{
struct passwd *pwd;
int result = 0, ch;
BOOL joining_domain = False, got_pass = False, got_username = False;
int local_flags = LOCAL_SET_PASSWORD;
BOOL stdin_passwd_get = False;
fstring user_name, user_password;
char *new_domain = NULL;
char *new_passwd = NULL;
char *old_passwd = NULL;
char *remote_machine = NULL;
ZERO_STRUCT(user_name);
ZERO_STRUCT(user_password);
user_name[0] = '\0';
while ((ch = getopt(argc, argv, "axdehmnj:r:sR:D:U:L")) != EOF) {
switch(ch) {
case 'L':
local_mode = True;
break;
case 'a':
local_flags |= LOCAL_ADD_USER;
break;
case 'x':
local_flags |= LOCAL_DELETE_USER;
local_flags &= ~LOCAL_SET_PASSWORD;
break;
case 'd':
local_flags |= LOCAL_DISABLE_USER;
local_flags &= ~LOCAL_SET_PASSWORD;
break;
case 'e':
local_flags |= LOCAL_ENABLE_USER;
local_flags &= ~LOCAL_SET_PASSWORD;
break;
case 'm':
local_flags |= LOCAL_TRUST_ACCOUNT;
break;
case 'n':
local_flags |= LOCAL_SET_NO_PASSWORD;
local_flags &= ~LOCAL_SET_PASSWORD;
break;
case 'j':
new_domain = optarg;
strupper(new_domain);
joining_domain = True;
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 'R':
lp_set_name_resolve_order(optarg);
break;
case 'D':
DEBUGLEVEL = atoi(optarg);
break;
case 'U': {
char *lp;
got_username = True;
fstrcpy(user_name, optarg);
if ((lp = strchr_m(user_name, '%'))) {
*lp = 0;
fstrcpy(user_password, lp + 1);
got_pass = True;
memset(strchr_m(optarg, '%') + 1, 'X',
strlen(user_password));
}
break;
}
case 'h':
default:
usage();
}
}
argc -= optind;
argv += optind;
/*
* Ensure both add/delete user are not set
* Ensure add/delete user and either remote machine or join domain are
* not both set.
*/
if(((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) == (LOCAL_ADD_USER|LOCAL_DELETE_USER)) ||
((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) &&
((remote_machine != NULL) || joining_domain))) {
usage();
}
/* Only load interfaces if we are doing network operations. */
if (joining_domain || remote_machine) {
load_interfaces();
}
/* Join a domain */
if (joining_domain) {
if (argc != 0)
usage();
/* 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);
}
}
/*
* Deal with root - can add a user, but only locally.
*/
switch(argc) {
case 0:
if (!got_username)
fstrcpy(user_name, "");
break;
case 1:
if (got_username)
usage();
fstrcpy(user_name, argv[0]);
break;
case 2:
if (got_username || got_pass)
usage();
fstrcpy(user_name, argv[0]);
new_passwd = smb_xstrdup(argv[1]);
break;
default:
usage();
}
Fix up a number of intertwined issues: The big one is a global change to allow us to NULLify the free'ed pointer to a former passdb object. This was done to allow idra's SAFE_FREE() macro to do its magic, and to satisfy the input test in pdb_init_sam() for a NULL pointer to start with. This NULL pointer test was what was breaking the adding of accounts up until now, and this code has been reworked to avoid duplicating work - I hope this will avoid a similar mess-up in future. Finally, I fixed a few nasty bugs where the pdb_ fuctions's return codes were being ignored. Some of these functions malloc() and are permitted to fail. Also, this caught a nasty bug where pdb_set_lanman_password(sam, NULL) acheived precisely didilly-squat, just returning False. Now that we check the returns this bug was spotted. This could allow different LM and NT passwords. - the pdbedit code needs to start checking these too, but I havn't had a chance to fix it. I have also fixed up where some of the password changing code was using the pdb_set functions to store *internal* data. I assume this is from a previous lot of mass conversion work... Most likally (and going on past experience) I have missed somthing, probably in the LanMan password change code which I havn't yet been able to test, but this lot is in much better shape than it was before. If all this is too much to swallow (particularly for 2.2.2) then just adding a sam_pass = NULL to the particular line of passdb.c should do the trick for the ovbious bug. Andrew Bartlett (This used to be commit 762c8758a7869809d89b4da9c2a5249678942930)
2001-09-29 17:08:26 +04:00
if (!user_name[0] && (pwd = sys_getpwuid(geteuid()))) {
fstrcpy(user_name, pwd->pw_name);
}
if (!user_name[0]) {
fprintf(stderr,"You must specify a username\n");
exit(1);
}
if (local_flags & LOCAL_TRUST_ACCOUNT) {
/* add the $ automatically */
static fstring buf;
/*
* Remove any trailing '$' before we
* generate the initial machine password.
*/
if (user_name[strlen(user_name)-1] == '$') {
user_name[strlen(user_name)-1] = 0;
}
if (local_flags & LOCAL_ADD_USER) {
SAFE_FREE(new_passwd);
new_passwd = smb_xstrdup(user_name);
strlower(new_passwd);
}
/*
* Now ensure the username ends in '$' for
* the machine add.
*/
slprintf(buf, sizeof(buf)-1, "%s$", user_name);
fstrcpy(user_name, buf);
}
if (remote_machine != NULL) {
old_passwd = get_pass("Old SMB password:",stdin_passwd_get);
}
if (!(local_flags & LOCAL_SET_PASSWORD)) {
/*
* 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.
*/
if(local_flags & LOCAL_ENABLE_USER) {
SAM_ACCOUNT *sampass = NULL;
BOOL ret;
pdb_init_sam(&sampass);
ret = pdb_getsampwnam(sampass, user_name);
if((sampass != False) && (pdb_get_lanman_passwd(sampass) == NULL)) {
local_flags |= LOCAL_SET_PASSWORD;
}
Fix up a number of intertwined issues: The big one is a global change to allow us to NULLify the free'ed pointer to a former passdb object. This was done to allow idra's SAFE_FREE() macro to do its magic, and to satisfy the input test in pdb_init_sam() for a NULL pointer to start with. This NULL pointer test was what was breaking the adding of accounts up until now, and this code has been reworked to avoid duplicating work - I hope this will avoid a similar mess-up in future. Finally, I fixed a few nasty bugs where the pdb_ fuctions's return codes were being ignored. Some of these functions malloc() and are permitted to fail. Also, this caught a nasty bug where pdb_set_lanman_password(sam, NULL) acheived precisely didilly-squat, just returning False. Now that we check the returns this bug was spotted. This could allow different LM and NT passwords. - the pdbedit code needs to start checking these too, but I havn't had a chance to fix it. I have also fixed up where some of the password changing code was using the pdb_set functions to store *internal* data. I assume this is from a previous lot of mass conversion work... Most likally (and going on past experience) I have missed somthing, probably in the LanMan password change code which I havn't yet been able to test, but this lot is in much better shape than it was before. If all this is too much to swallow (particularly for 2.2.2) then just adding a sam_pass = NULL to the particular line of passdb.c should do the trick for the ovbious bug. Andrew Bartlett (This used to be commit 762c8758a7869809d89b4da9c2a5249678942930)
2001-09-29 17:08:26 +04:00
pdb_free_sam(&sampass);
}
}
if(local_flags & LOCAL_SET_PASSWORD) {
new_passwd = prompt_for_new_password(stdin_passwd_get);
if(!new_passwd) {
fprintf(stderr, "Unable to get new password.\n");
exit(1);
}
}
if (!password_change(remote_machine, user_name, old_passwd, new_passwd, local_flags)) {
fprintf(stderr,"Failed to modify password entry for user %s\n", user_name);
result = 1;
goto done;
}
if(!(local_flags & (LOCAL_ADD_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER|LOCAL_DELETE_USER|LOCAL_SET_NO_PASSWORD|LOCAL_SET_PASSWORD))) {
SAM_ACCOUNT *sampass = NULL;
BOOL ret;
pdb_init_sam(&sampass);
ret = pdb_getsampwnam(sampass, user_name);
printf("Password changed for user %s.", user_name );
if( (ret != False) && (pdb_get_acct_ctrl(sampass)&ACB_DISABLED) )
printf(" User has disabled flag set.");
if((ret != False) && (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ) )
printf(" User has no password flag set.");
printf("\n");
Fix up a number of intertwined issues: The big one is a global change to allow us to NULLify the free'ed pointer to a former passdb object. This was done to allow idra's SAFE_FREE() macro to do its magic, and to satisfy the input test in pdb_init_sam() for a NULL pointer to start with. This NULL pointer test was what was breaking the adding of accounts up until now, and this code has been reworked to avoid duplicating work - I hope this will avoid a similar mess-up in future. Finally, I fixed a few nasty bugs where the pdb_ fuctions's return codes were being ignored. Some of these functions malloc() and are permitted to fail. Also, this caught a nasty bug where pdb_set_lanman_password(sam, NULL) acheived precisely didilly-squat, just returning False. Now that we check the returns this bug was spotted. This could allow different LM and NT passwords. - the pdbedit code needs to start checking these too, but I havn't had a chance to fix it. I have also fixed up where some of the password changing code was using the pdb_set functions to store *internal* data. I assume this is from a previous lot of mass conversion work... Most likally (and going on past experience) I have missed somthing, probably in the LanMan password change code which I havn't yet been able to test, but this lot is in much better shape than it was before. If all this is too much to swallow (particularly for 2.2.2) then just adding a sam_pass = NULL to the particular line of passdb.c should do the trick for the ovbious bug. Andrew Bartlett (This used to be commit 762c8758a7869809d89b4da9c2a5249678942930)
2001-09-29 17:08:26 +04:00
pdb_free_sam(&sampass);
}
done:
SAFE_FREE(new_passwd);
return result;
}
/**
handle password changing for non-root
**/
static int process_nonroot(int argc, char *argv[])
{
struct passwd *pwd = NULL;
int result = 0, ch;
BOOL stdin_passwd_get = False;
char *old_passwd = NULL;
char *remote_machine = NULL;
char *user_name = NULL;
char *new_passwd = NULL;
while ((ch = getopt(argc, argv, "hD:r:sU:")) != EOF) {
switch(ch) {
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) {
pwd = sys_getpwuid(getuid());
if (pwd) {
user_name = smb_xstrdup(pwd->pw_name);
} else {
fprintf(stderr, "smbpasswd: 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).
*/
load_interfaces(); /* Delayed from main() */
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) {
fprintf(stderr, "Unable to get new password.\n");
exit(1);
}
if (!password_change(remote_machine, user_name, old_passwd, new_passwd, 0)) {
fprintf(stderr,"Failed to change password for %s\n", user_name);
result = 1;
goto done;
}
printf("Password changed for user %s\n", user_name);
done:
SAFE_FREE(old_passwd);
SAFE_FREE(new_passwd);
return result;
}
/*********************************************************
Start here.
**********************************************************/
int main(int argc, char **argv)
{
#if defined(HAVE_SET_AUTH_PARAMETERS)
set_auth_parameters(argc, argv);
#endif /* HAVE_SET_AUTH_PARAMETERS */
setup_logging("smbpasswd", True);
Large commit which restructures the local password storage API. Currently the only backend which works is smbpasswd (tdb, LDAP, and NIS+) are broken, but they were somewhat broken before. :) The following functions implement the storage manipulation interface /*The following definitions come from passdb/pdb_smbpasswd.c */ BOOL pdb_setsampwent (BOOL update); void pdb_endsampwent (void); SAM_ACCOUNT* pdb_getsampwent (void); SAM_ACCOUNT* pdb_getsampwnam (char *username); SAM_ACCOUNT* pdb_getsampwuid (uid_t uid); SAM_ACCOUNT* pdb_getsampwrid (uint32 rid); BOOL pdb_add_sam_account (SAM_ACCOUNT *sampass); BOOL pdb_update_sam_account (SAM_ACCOUNT *sampass, BOOL override); BOOL pdb_delete_sam_account (char* username); There is also a host of pdb_set..() and pdb_get..() functions for manipulating SAM_ACCOUNT struct members. Note that the struct passdb_ops {} has gone away. Also notice that struct smb_passwd (formally in smb.h) has been moved to passdb/pdb_smbpasswd.c and is not accessed outisde of static internal functions in this file. All local password searches should make use of the the SAM_ACCOUNT struct and the previously mentioned functions. I'll write some documentation for this later. The next step is to fix the TDB passdb backend, then work on spliting the backends out into share libraries, and finally get the LDAP backend going. What works and may not: o domain logons from Win9x works o domain logons from WinNT 4 works o user and group enumeration as implemented by Tim works o file and print access works o changing password from Win9x & NT ummm...i'll fix this tonight :) If I broke anything else, just yell and I'll fix it. I think it should be fairly quite. -- jerry (This used to be commit 0b92d0838ebdbe24f34f17e313ecbf61a0301389)
2000-11-14 02:03:34 +03:00
if(!initialize_password_db(True)) {
fprintf(stderr, "Can't setup password database vectors.\n");
exit(1);
}
if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
fprintf(stderr, "Can't load %s - run testparm to debug it\n",
dyn_CONFIGFILE);
exit(1);
}
/*
* Set the machine NETBIOS name if not already
* set from the config file.
*/
if (!*global_myname) {
char *p;
fstrcpy(global_myname, myhostname());
p = strchr_m(global_myname, '.' );
if (p) *p = 0;
}
strupper(global_myname);
/* Check the effective uid - make sure we are not setuid */
if (is_setuid_root()) {
fprintf(stderr, "smbpasswd must *NOT* be setuid root.\n");
exit(1);
}
/* 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) {
secrets_init();
return process_root(argc, argv);
}
return process_nonroot(argc, argv);
}