diff options
Diffstat (limited to 'source3/utils')
-rw-r--r-- | source3/utils/smbpasswd.c | 282 |
1 files changed, 266 insertions, 16 deletions
diff --git a/source3/utils/smbpasswd.c b/source3/utils/smbpasswd.c index 8086253349..338c0d5650 100644 --- a/source3/utils/smbpasswd.c +++ b/source3/utils/smbpasswd.c @@ -19,7 +19,11 @@ #include "includes.h" +extern pstring myhostname; extern pstring global_myname; +extern fstring global_myworkgroup; + +static char *prog_name; /********************************************************* Print command usage on stderr and die. @@ -29,13 +33,225 @@ static void usage(char *name, BOOL is_root) { if(is_root) fprintf(stderr, "Usage is : %s [-D DEBUGLEVEL] [-a] [-d] [-m] [-n] [username] [password]\n\ -%s: [-R <name resolve order>] [-D DEBUGLEVEL] [-r machine] [username] [password]\n%s: [-h]\n", name, name, name); +%s: [-R <name resolve order>] [-D DEBUGLEVEL] [-j DOMAINNAME] [-r machine] [username] [password]\n%s: [-h]\n", name, name, name); else fprintf(stderr, "Usage is : %s [-h] [-D DEBUGLEVEL] [-r machine] [password]\n", name); exit(1); } /********************************************************* +Join a domain. +**********************************************************/ + +static int setup_account( char *domain, char *remote_machine, + unsigned char orig_machine_passwd_hash[16], + unsigned char new_machine_passwd_hash[16]) +{ + struct in_addr dest_ip; + struct cli_state cli; + + memset(&cli, '\0', sizeof(struct cli_state)); + if(cli_initialise(&cli) == False) { + fprintf(stderr, "%s: unable to initialize client connection.\n", prog_name); + return 1; + } + + if(!resolve_name( remote_machine, &dest_ip)) { + fprintf(stderr, "%s: Can't resolve address for %s\n", prog_name, remote_machine); + return 1; + } + + if (ismyip(dest_ip)) { + fprintf(stderr,"%s: Machine %s is one of our addresses. Cannot add to ourselves.\n", prog_name, + remote_machine); + return 1; + } + + if (!cli_connect(&cli, remote_machine, &dest_ip)) { + fprintf(stderr, "%s: unable to connect to SMB server on \ +machine %s. Error was : %s.\n", prog_name, remote_machine, cli_errstr(&cli) ); + return 1; + } + + if (!cli_session_request(&cli, remote_machine, 0x20, global_myname)) { + fprintf(stderr, "%s: machine %s rejected the session setup. \ +Error was : %s.\n", prog_name, remote_machine, cli_errstr(&cli) ); + cli_shutdown(&cli); + return 1; + } + + cli.protocol = PROTOCOL_NT1; + + if (!cli_negprot(&cli)) { + fprintf(stderr, "%s: machine %s rejected the negotiate protocol. \ +Error was : %s.\n", prog_name, remote_machine, cli_errstr(&cli) ); + cli_shutdown(&cli); + return 1; + } + if (cli.protocol != PROTOCOL_NT1) { + fprintf(stderr, "%s: machine %s didn't negotiate NT protocol.\n", prog_name, remote_machine); + cli_shutdown(&cli); + return 1; + } + + /* + * Do an anonymous session setup. + */ + + if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) { + fprintf(stderr, "%s: machine %s rejected the session setup. \ +Error was : %s.\n", prog_name, remote_machine, cli_errstr(&cli) ); + cli_shutdown(&cli); + return 1; + } + + if (!(cli.sec_mode & 1)) { + fprintf(stderr, "%s: machine %s isn't in user level security mode\n", prog_name, remote_machine); + cli_shutdown(&cli); + return 1; + } + + if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) { + fprintf(stderr, "%s: machine %s rejected the tconX on the IPC$ share. \ +Error was : %s.\n", prog_name, remote_machine, cli_errstr(&cli) ); + cli_shutdown(&cli); + return 1; + } + + /* + * Ok - we have an anonymous connection to the IPC$ share. + * Now start the NT Domain stuff :-). + */ + + if(cli_nt_session_open(&cli, PIPE_NETLOGON, False) == False) { + fprintf(stderr, "%s: unable to open the domain client session to \ +machine %s. Error was : %s.\n", prog_name, remote_machine, cli_errstr(&cli)); + cli_nt_session_close(&cli); + cli_ulogoff(&cli); + cli_shutdown(&cli); + return 1; + } + + if(cli_nt_setup_creds(&cli, orig_machine_passwd_hash) == False) { + fprintf(stderr, "%s: unable to setup the PDC credentials to machine \ +%s. Error was : %s.\n", prog_name, remote_machine, cli_errstr(&cli)); + cli_nt_session_close(&cli); + cli_ulogoff(&cli); + cli_shutdown(&cli); + return 1; + } + + if( cli_nt_srv_pwset( &cli,new_machine_passwd_hash ) == False) { + fprintf(stderr, "%s: unable to change password for machine %s in domain \ +%s to Domain controller %s. Error was %s.\n", prog_name, global_myname, domain, remote_machine, + cli_errstr(&cli)); + cli_close(&cli, cli.nt_pipe_fnum); + cli_ulogoff(&cli); + cli_shutdown(&cli); + return 1; + } + + cli_nt_session_close(&cli); + cli_ulogoff(&cli); + cli_shutdown(&cli); + + return 0; +} + +/********************************************************* +Join a domain. +**********************************************************/ + +static int join_domain( char *domain, char *remote) +{ + fstring remote_machine; + char *p; + fstring machine_passwd; + unsigned char machine_passwd_hash[16]; + unsigned char new_machine_passwd_hash[16]; + void *vp; + int ret = 1; + + fstrcpy(remote_machine, remote ? remote : ""); + fstrcpy(machine_passwd, global_myname); + strlower(machine_passwd); + E_md4hash( machine_passwd, machine_passwd_hash); + + generate_random_buffer( new_machine_passwd_hash, 16, True); + + /* Ensure that we are not trying to join a + domain if we are locally set up as a domain + controller. */ + + if(lp_domain_controller() && strequal(lp_workgroup(), domain)) { + fprintf(stderr, "%s: Cannot join domain %s as we already configured as domain controller \ +for that domain.\n", prog_name, domain); + return 1; + } + + /* + * Write the new machine password. + */ + + /* + * Get the machine account password. + */ + if((vp = machine_password_lock( domain, global_myname, True)) == NULL) { + fprintf(stderr, "%s: unable to open the machine account password file for \ +machine %s in domain %s.\n", prog_name, global_myname, domain); + return 1; + } + + if(!set_machine_account_password( vp, new_machine_passwd_hash)) { + fprintf(stderr, "%s: unable to read the machine account password for \ +machine %s in domain %s.\n", prog_name, global_myname, domain); + machine_password_unlock(vp); + return 1; + } + + machine_password_unlock(vp); + + /* + * If we are given a remote machine assume this is the PDC. + */ + + if(remote != NULL) { + strupper(remote_machine); + ret = setup_account( domain, remote_machine, machine_passwd_hash, new_machine_passwd_hash); + if(ret == 0) + printf("%s: Joined domain %s.\n", prog_name, domain); + } else { + /* + * Treat each name in the 'password server =' line as a potential + * PDC/BDC. Contact each in turn and try and authenticate and + * change the machine account password. + */ + + p = lp_passwordserver(); + + if(!*p) + fprintf(stderr, "%s: No password server list given in smb.conf - \ +unable to join domain.\n", prog_name); + + while(p && next_token( &p, remote_machine, LIST_SEP)) { + + strupper(remote_machine); + if(setup_account( domain, remote_machine, machine_passwd_hash, new_machine_passwd_hash) == 0) { + printf("%s: Joined domain %s.\n", prog_name, domain); + return 0; + } + } + } + + if(ret) { + machine_password_delete( domain, global_myname); + fprintf(stderr,"%s: Unable to join domain %s.\n", prog_name, domain); + } + + return ret; +} + +/********************************************************* Start here. **********************************************************/ @@ -44,7 +260,6 @@ int main(int argc, char **argv) extern char *optarg; extern int optind; extern int DEBUGLEVEL; - char *prog_name; int real_uid; struct passwd *pwd; fstring old_passwd; @@ -59,11 +274,13 @@ int main(int argc, char **argv) BOOL is_root = False; pstring user_name; char *remote_machine = NULL; - BOOL add_user = False; - BOOL got_new_pass = False; - BOOL machine_account = False; - BOOL disable_user = False; - BOOL set_no_password = False; + BOOL add_user = False; + BOOL got_new_pass = False; + BOOL machine_account = False; + BOOL disable_user = False; + BOOL set_no_password = False; + BOOL joining_domain = False; + char *new_domain = NULL; pstring servicesf = CONFIGFILE; void *vp; @@ -84,7 +301,26 @@ int main(int argc, char **argv) if (!lp_load(servicesf,True,False,False)) { fprintf(stderr, "%s: Can't load %s - run testparm to debug it\n", prog_name, servicesf); } + + if(!get_myname(myhostname,NULL)) { + fprintf(stderr, "%s: unable to get my hostname.\n", prog_name ); + exit(1); + } + + /* + * Set the machine NETBIOS name if not already + * set from the config file. + */ + if (!*global_myname) + { + fstrcpy( global_myname, myhostname ); + p = strchr( global_myname, '.' ); + if (p) + *p = 0; + } + strupper( global_myname ); + codepage_initialise(lp_client_code_page()); /* Get the real uid */ @@ -98,7 +334,7 @@ int main(int argc, char **argv) is_root = (real_uid == 0); - while ((ch = getopt(argc, argv, "adhmnr:R:D:")) != EOF) { + while ((ch = getopt(argc, argv, "adhmnj:r:R:D:")) != EOF) { switch(ch) { case 'a': if(is_root) @@ -139,6 +375,14 @@ int main(int argc, char **argv) } else usage(prog_name, is_root); break; + case 'j': + if(is_root) { + new_domain = optarg; + strupper(new_domain); + joining_domain = True; + } else + usage(prog_name, is_root); + break; case 'h': default: usage(prog_name, is_root); @@ -149,13 +393,24 @@ int main(int argc, char **argv) argv += optind; /* - * Ensure add_user and remote machine are + * Ensure add_user and either remote machine or join domain are * not both set. */ - if(add_user && (remote_machine != NULL)) + + if(add_user && ((remote_machine != NULL) || joining_domain)) + usage(prog_name, True); + + /* + * Deal with joining a domain. + */ + if(joining_domain && argc != 0) usage(prog_name, True); - if( is_root ) { + if(joining_domain) { + return join_domain( new_domain, remote_machine); + } + + if(is_root) { /* * Deal with root - can add a user, but only locally. @@ -297,11 +552,6 @@ int main(int argc, char **argv) struct cli_state cli; struct in_addr ip; - if(get_myname(global_myname,NULL) == False) { - fprintf(stderr, "%s: unable to get my hostname.\n", prog_name ); - exit(1); - } - if(!resolve_name( remote_machine, &ip)) { fprintf(stderr, "%s: unable to find an IP address for machine %s.\n", prog_name, remote_machine ); |