From 6a7164233e3bf9d6bb57c44a53204068e454ae5c Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 29 Apr 1998 22:27:26 +0000 Subject: Makefile: Added files to smbpasswd.c. loadparm.c: Patch from tim@quiknet.com for static string problems. server.c: Setup global_myname. smbpass.c: Fix up locking. Add machine_password_delete() call. smbpasswd.c: Added provisional code to add to a domain. lib/rpc/client/cli_login.c: Fixed incorrect cred_hash3 call when setting machine password. lib/rpc/server/srv_netlog.c: Fixed incorrect cred_hash3 call when setting machine password. Jeremy. --- source/include/proto.h | 1 + source/param/loadparm.c | 6 +- source/passdb/smbpass.c | 81 ++++++++---- source/rpc_client/cli_login.c | 2 +- source/rpc_server/srv_netlog.c | 2 +- source/smbd/server.c | 16 +++ source/utils/smbpasswd.c | 282 ++++++++++++++++++++++++++++++++++++++--- 7 files changed, 343 insertions(+), 47 deletions(-) (limited to 'source') diff --git a/source/include/proto.h b/source/include/proto.h index 15c25b01e70..76fb11c12e9 100644 --- a/source/include/proto.h +++ b/source/include/proto.h @@ -1773,6 +1773,7 @@ BOOL add_smbpwd_entry(struct smb_passwd *newpwd); BOOL mod_smbpwd_entry(struct smb_passwd* pwd); void *machine_password_lock( char *domain, char *name, BOOL update); BOOL machine_password_unlock( void *token ); +BOOL machine_password_delete( char *domain, char *name ); BOOL get_machine_account_password( void *mach_tok, unsigned char *ret_pwd, time_t *last_change_time); BOOL set_machine_account_password( void *mach_tok, unsigned char *md4_new_pwd); diff --git a/source/param/loadparm.c b/source/param/loadparm.c index 2249c8b473f..dda31f3efe1 100644 --- a/source/param/loadparm.c +++ b/source/param/loadparm.c @@ -2144,8 +2144,7 @@ static void lp_add_auto_services(char *str) { char *s; char *p; - int homes = lp_servicenumber(HOMES_NAME); - int printers = lp_servicenumber(PRINTERS_NAME); + int homes, printers; if (!str) return; @@ -2153,6 +2152,9 @@ static void lp_add_auto_services(char *str) s = strdup(str); if (!s) return; + homes = lp_servicenumber(HOMES_NAME); + printers = lp_servicenumber(PRINTERS_NAME); + for (p=strtok(s,LIST_SEP);p;p=strtok(NULL,LIST_SEP)) { char *home = get_home_dir(p); diff --git a/source/passdb/smbpass.c b/source/passdb/smbpass.c index aa3a694567c..2ab21f78ef7 100644 --- a/source/passdb/smbpass.c +++ b/source/passdb/smbpass.c @@ -80,7 +80,7 @@ static BOOL pw_file_lock(int fd, int type, int secs, int *plock_depth) (*plock_depth)++; if(pw_file_lock_depth == 0) { - if (do_pw_lock(fd, secs, type)) { + if (!do_pw_lock(fd, secs, type)) { DEBUG(10,("pw_file_lock: locking file failed, error = %s.\n", strerror(errno))); return False; @@ -135,7 +135,7 @@ void *startsmbpwent(BOOL update) /* Set a 16k buffer to do more efficient reads */ setvbuf(fp, s_readbuf, _IOFBF, sizeof(s_readbuf)); - if (!pw_file_lock(fileno(fp), F_RDLCK | (update ? F_WRLCK : 0), 5, &pw_file_lock_depth)) + if (!pw_file_lock(fileno(fp), (update ? F_WRLCK : F_RDLCK), 5, &pw_file_lock_depth)) { DEBUG(0, ("startsmbpwent: unable to lock file %s\n", pfile)); fclose(fp); @@ -774,7 +774,7 @@ BOOL mod_smbpwd_entry(struct smb_passwd* pwd) lockfd = fileno(fp); - if (!pw_file_lock(lockfd, F_RDLCK | F_WRLCK, 5, &pw_file_lock_depth)) { + if (!pw_file_lock(lockfd, F_WRLCK, 5, &pw_file_lock_depth)) { DEBUG(0, ("mod_smbpwd_entry: unable to lock file %s\n", pfile)); fclose(fp); return False; @@ -1076,48 +1076,63 @@ BOOL mod_smbpwd_entry(struct smb_passwd* pwd) static int mach_passwd_lock_depth; /************************************************************************ - Routine to lock the machine account password file for a domain. + Routine to get the name for a machine account file. ************************************************************************/ -void *machine_password_lock( char *domain, char *name, BOOL update) +static void get_machine_account_file_name( char *domain, char *name, char *mac_file) { - FILE *fp; - pstring mac_file; unsigned int mac_file_len; char *p; - if(mach_passwd_lock_depth == 0) { + pstrcpy(mac_file, lp_smb_passwd_file()); + p = strrchr(mac_file, '/'); + if(p != NULL) + *++p = '\0'; - pstrcpy(mac_file, lp_smb_passwd_file()); - p = strrchr(mac_file, '/'); + mac_file_len = strlen(mac_file); - if(p != NULL) - *++p = '\0'; + if (sizeof(pstring) - mac_file_len - strlen(domain) - strlen(name) - 6 < 0) + { + DEBUG(0,("machine_password_lock: path %s too long to add machine details.\n", + mac_file)); + return; + } - mac_file_len = strlen(mac_file); + strcat(mac_file, domain); + strcat(mac_file, "."); + strcat(mac_file, name); + strcat(mac_file, ".mac"); +} + +/************************************************************************ + Routine to lock the machine account password file for a domain. +************************************************************************/ - if (sizeof(pstring) - mac_file_len - strlen(domain) - strlen(name) - 6 < 0) - { - DEBUG(0,("machine_password_lock: path %s too long to add machine details.\n", - mac_file)); - return NULL; - } +void *machine_password_lock( char *domain, char *name, BOOL update) +{ + FILE *fp; + pstring mac_file; + + if(mach_passwd_lock_depth == 0) { - strcat(mac_file, domain); - strcat(mac_file, "."); - strcat(mac_file, name); - strcat(mac_file, ".mac"); + get_machine_account_file_name( domain, name, mac_file); if((fp = fopen(mac_file, "r+b")) == NULL) { - DEBUG(0,("machine_password_lock: cannot open file %s - Error was %s.\n", - mac_file, strerror(errno) )); - return NULL; + if(errno == ENOENT && update) { + fp = fopen(mac_file, "w+b"); + } + + if(fp == NULL) { + DEBUG(0,("machine_password_lock: cannot open file %s - Error was %s.\n", + mac_file, strerror(errno) )); + return NULL; + } } chmod(mac_file, 0600); } - if(!pw_file_lock(fileno(fp), F_RDLCK | (update ? F_WRLCK : 0), + if(!pw_file_lock(fileno(fp), (update ? F_WRLCK : F_RDLCK), 60, &mach_passwd_lock_depth)) { DEBUG(0,("machine_password_lock: cannot lock file %s\n", mac_file)); @@ -1141,6 +1156,18 @@ BOOL machine_password_unlock( void *token ) return ret; } +/************************************************************************ + Routine to delete the machine account password file for a domain. +************************************************************************/ + +BOOL machine_password_delete( char *domain, char *name ) +{ + pstring mac_file; + + get_machine_account_file_name( domain, name, mac_file); + return (unlink( mac_file ) == 0); +} + /************************************************************************ Routine to get the machine account password for a domain. The user of this function must have locked the machine password file. diff --git a/source/rpc_client/cli_login.c b/source/rpc_client/cli_login.c index 80dca21149a..b4cdf3ae50a 100644 --- a/source/rpc_client/cli_login.c +++ b/source/rpc_client/cli_login.c @@ -90,7 +90,7 @@ BOOL cli_nt_srv_pwset(struct cli_state *cli, unsigned char *new_hashof_mach_pwd) #endif /* Process the new password. */ - cred_hash3( processed_new_pwd, new_hashof_mach_pwd, cli->sess_key, 0); + cred_hash3( processed_new_pwd, new_hashof_mach_pwd, cli->sess_key, 1); /* send client srv_pwset challenge */ return cli_net_srv_pwset(cli, processed_new_pwd); diff --git a/source/rpc_server/srv_netlog.c b/source/rpc_server/srv_netlog.c index 1f76d545f69..743e4477a6f 100644 --- a/source/rpc_server/srv_netlog.c +++ b/source/rpc_server/srv_netlog.c @@ -402,7 +402,7 @@ static void api_net_srv_pwset( int uid, DEBUG(100,("%02X ", q_a.pwd[i])); DEBUG(100,("\n")); - cred_hash3( pwd, q_a.pwd, vuser->dc.sess_key, 1); + cred_hash3( pwd, q_a.pwd, vuser->dc.sess_key, 0); /* lies! nt and lm passwords are _not_ the same: don't care */ smb_pass->smb_passwd = pwd; diff --git a/source/smbd/server.c b/source/smbd/server.c index ac18bb40388..83293a57876 100644 --- a/source/smbd/server.c +++ b/source/smbd/server.c @@ -26,6 +26,7 @@ pstring servicesf = CONFIGFILE; extern pstring debugf; extern pstring sesssetup_user; extern fstring global_myworkgroup; +extern pstring global_myname; char *InBuffer = NULL; char *OutBuffer = NULL; @@ -4942,6 +4943,21 @@ static void init_structs(void ) int i; get_myname(myhostname,NULL); + /* + * Set the machine NETBIOS name if not already + * set from the config file. + */ + + if (!*global_myname) + { + char *p; + fstrcpy( global_myname, myhostname ); + p = strchr( global_myname, '.' ); + if (p) + *p = 0; + } + strupper( global_myname ); + for (i=0;i] [-D DEBUGLEVEL] [-r machine] [username] [password]\n%s: [-h]\n", name, name, name); +%s: [-R ] [-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 ); -- cgit