/**************************************************************************** Try and find an interface that matches an ip. If we cannot, return NULL **************************************************************************/ static struct interface *iface_find(struct in_addr ip, BOOL CheckMask) { struct interface *i; if (is_zero_ip(ip)) return local_interfaces; for (i=local_interfaces; i; i=i->next) if (CheckMask) { if (same_net(i->ip,ip,i->nmask)) return i; } else if ((i->ip).s_addr == ip.s_addr) return i; return NULL; }
static BOOL rpc_dc_name(const char *domain, fstring srv_name, struct in_addr *ip_out) { struct ip_service *ip_list = NULL; struct in_addr dc_ip, exclude_ip; int count, i; NTSTATUS result; zero_ip(&exclude_ip); /* get a list of all domain controllers */ if (!NT_STATUS_IS_OK(get_sorted_dc_list(domain, NULL, &ip_list, &count, False))) { DEBUG(3, ("Could not look up dc's for domain %s\n", domain)); return False; } /* Remove the entry we've already failed with (should be the PDC). */ for (i = 0; i < count; i++) { if (is_zero_ip(ip_list[i].ip)) continue; if (name_status_find(domain, 0x1c, 0x20, ip_list[i].ip, srv_name)) { result = check_negative_conn_cache( domain, srv_name ); if ( NT_STATUS_IS_OK(result) ) { dc_ip = ip_list[i].ip; goto done; } } } SAFE_FREE(ip_list); /* No-one to talk to )-: */ return False; /* Boo-hoo */ done: /* We have the netbios name and IP address of a domain controller. Ideally we should sent a SAMLOGON request to determine whether the DC is alive and kicking. If we can catch a dead DC before performing a cli_connect() we can avoid a 30-second timeout. */ DEBUG(3, ("rpc_dc_name: Returning DC %s (%s) for domain %s\n", srv_name, inet_ntoa(dc_ip), domain)); *ip_out = dc_ip; SAFE_FREE(ip_list); return True; }
BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip) { extern pstring user_socket_options; int name_type = 0x20; char *p; /* reasonable default hostname */ if (!host) host = "*SMBSERVER"; fstrcpy(cli->desthost, host); /* allow hostnames of the form NAME#xx and do a netbios lookup */ if ((p = strchr(cli->desthost, '#'))) { name_type = strtol(p+1, NULL, 16); *p = 0; } if (!ip || is_zero_ip(*ip)) { if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) { return False; } if (ip) *ip = cli->dest_ip; } else { cli->dest_ip = *ip; } if (getenv("LIBSMB_PROG")) { cli->fd = sock_exec(getenv("LIBSMB_PROG")); } else { /* try 445 first, then 139 */ int port = cli->port?cli->port:445; cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, cli->timeout); if (cli->fd == -1 && cli->port == 0) { port = 139; cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, cli->timeout); } if (cli->fd != -1) cli->port = port; } if (cli->fd == -1) { DEBUG(1,("Error connecting to %s (%s)\n", inet_ntoa(*ip),strerror(errno))); return False; } set_socket_options(cli->fd,user_socket_options); return True; }
BOOL net_find_pdc(struct in_addr *server_ip, fstring server_name, const char *domain_name) { if (get_pdc_ip(domain_name, server_ip)) { if (is_zero_ip(*server_ip)) return False; if (!name_status_find(domain_name, 0x1b, 0x20, *server_ip, server_name)) return False; return True; } else return False; }
static int get_ldap_sequence_number( const char* domain, uint32 *seq) { int ret = -1; int i, port = LDAP_PORT; struct ip_service *ip_list = NULL; int count; if ( !get_sorted_dc_list(domain, &ip_list, &count, False) ) { DEBUG(3, ("Could not look up dc's for domain %s\n", domain)); return False; } /* Finally return first DC that we can contact */ for (i = 0; i < count; i++) { fstring ipstr; /* since the is an LDAP lookup, default to the LDAP_PORT is not set */ port = (ip_list[i].port!= PORT_NONE) ? ip_list[i].port : LDAP_PORT; fstrcpy( ipstr, inet_ntoa(ip_list[i].ip) ); if (is_zero_ip(ip_list[i].ip)) continue; if ( (ret = get_ldap_seq( ipstr, port, seq)) == 0 ) goto done; /* add to failed connection cache */ add_failed_connection_entry( domain, ipstr, NT_STATUS_UNSUCCESSFUL ); } done: if ( ret == 0 ) { DEBUG(3, ("get_ldap_sequence_number: Retrieved sequence number for Domain (%s) from DC (%s:%d)\n", domain, inet_ntoa(ip_list[i].ip), port)); } SAFE_FREE(ip_list); return ret; }
static struct in_addr *lookup_byname_backend(const char *name, int *count) { int fd; struct in_addr *ret = NULL; struct in_addr p; int j, flags; *count = 0; fd = wins_lookup_open_socket_in(); if (fd == -1) return NULL; p = wins_srv_ip(); if( !is_zero_ip(p) ) { ret = name_query(fd,name,0x20,False,True, p, count, &flags); goto out; } if (lp_wins_support()) { /* we are our own WINS server */ ret = name_query(fd,name,0x20,False,True, *interpret_addr2("127.0.0.1"), count, &flags); goto out; } /* uggh, we have to broadcast to each interface in turn */ for (j=iface_count() - 1; j >= 0; j--) { struct in_addr *bcast = iface_n_bcast(j); ret = name_query(fd,name,0x20,True,True,*bcast,count, &flags); if (ret) break; } out: close(fd); return ret; }
static void find_domain_master_name_query_success(struct subnet_record *subrec, struct userdata_struct *userdata_in, struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec) { /* * Unfortunately, finding the IP address of the Domain Master Browser, * as we have here, is not enough. We need to now do a sync to the * SERVERNAME<0x20> NetBIOS name, as only recent NT servers will * respond to the SMBSERVER name. To get this name from IP * address we do a Node status request, and look for the first * NAME<0x20> in the response, and take that as the server name. * We also keep a cache of the Domain Master Browser name for this * workgroup in the Workgroup struct, so that if the same IP addess * is returned every time, we don't need to do the node status * request. */ struct work_record *work; struct nmb_name nmbname; struct userdata_struct *userdata; int size = sizeof(struct userdata_struct) + sizeof(fstring)+1; if( !(work = find_workgroup_on_subnet(subrec, q_name->name)) ) { if( DEBUGLVL( 0 ) ) { dbgtext( "find_domain_master_name_query_success:\n" ); dbgtext( "Failed to find workgroup %s\n", q_name->name ); } return; } /* First check if we already have a dmb for this workgroup. */ if(!is_zero_ip(work->dmb_addr) && ip_equal(work->dmb_addr, answer_ip)) { /* Do the local master browser announcement to the domain master browser name and IP. */ announce_local_master_browser_to_domain_master_browser( work ); /* Now synchronise lists with the domain master browser. */ sync_with_dmb(work); return; } else zero_ip(&work->dmb_addr); /* Now initiate the node status request. */ make_nmb_name(&nmbname,"*",0x0); /* Put the workgroup name into the userdata so we know what workgroup we're talking to when the reply comes back. */ /* Setup the userdata_struct - this is copied so we can use a stack variable for this. */ if((userdata = (struct userdata_struct *)malloc(size)) == NULL) { DEBUG(0, ("find_domain_master_name_query_success: malloc fail.\n")); return; } userdata->copy_fn = NULL; userdata->free_fn = NULL; userdata->userdata_len = strlen(work->work_group)+1; pstrcpy(userdata->data, work->work_group); node_status( subrec, &nmbname, answer_ip, domain_master_node_status_success, domain_master_node_status_fail, userdata); zero_free(userdata, size); }
/**************************************************************************** main program ****************************************************************************/ int main(int argc, const char **argv) { int opt,i; char *p; int rc = 0; int argc_new = 0; const char ** argv_new; poptContext pc; struct poptOption long_options[] = { {"help", 'h', POPT_ARG_NONE, 0, 'h'}, {"workgroup", 'w', POPT_ARG_STRING, &opt_target_workgroup}, {"user", 'U', POPT_ARG_STRING, &opt_user_name, 'U'}, {"ipaddress", 'I', POPT_ARG_STRING, 0,'I'}, {"port", 'p', POPT_ARG_INT, &opt_port}, {"myname", 'n', POPT_ARG_STRING, &opt_requester_name}, {"server", 'S', POPT_ARG_STRING, &opt_host}, {"container", 'c', POPT_ARG_STRING, &opt_container}, {"comment", 'C', POPT_ARG_STRING, &opt_comment}, {"maxusers", 'M', POPT_ARG_INT, &opt_maxusers}, {"flags", 'F', POPT_ARG_INT, &opt_flags}, {"long", 'l', POPT_ARG_NONE, &opt_long_list_entries}, {"reboot", 'r', POPT_ARG_NONE, &opt_reboot}, {"force", 'f', POPT_ARG_NONE, &opt_force}, {"stdin", 'i', POPT_ARG_NONE, &opt_stdin}, {"timeout", 't', POPT_ARG_INT, &opt_timeout}, {"machine-pass",'P', POPT_ARG_NONE, &opt_machine_pass}, {"myworkgroup", 'W', POPT_ARG_STRING, &opt_workgroup}, {"verbose", 'v', POPT_ARG_NONE, &opt_verbose}, /* Options for 'net groupmap set' */ {"local", 'L', POPT_ARG_NONE, &opt_localgroup}, {"domain", 'D', POPT_ARG_NONE, &opt_domaingroup}, {"ntname", 'N', POPT_ARG_STRING, &opt_newntname}, {"rid", 'R', POPT_ARG_INT, &opt_rid}, /* Options for 'net rpc share migrate' */ {"acls", 0, POPT_ARG_NONE, &opt_acls}, {"attrs", 0, POPT_ARG_NONE, &opt_attrs}, {"timestamps", 0, POPT_ARG_NONE, &opt_timestamps}, {"exclude", 'e', POPT_ARG_STRING, &opt_exclude}, {"destination", 0, POPT_ARG_STRING, &opt_destination}, {"tallocreport", 0, POPT_ARG_NONE, &do_talloc_report}, POPT_COMMON_SAMBA { 0, 0, 0, 0} }; zero_ip(&opt_dest_ip); load_case_tables(); /* set default debug level to 0 regardless of what smb.conf sets */ DEBUGLEVEL_CLASS[DBGC_ALL] = 0; dbf = x_stderr; pc = poptGetContext(NULL, argc, (const char **) argv, long_options, POPT_CONTEXT_KEEP_FIRST); while((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { case 'h': net_help(argc, argv); exit(0); break; case 'I': opt_dest_ip = *interpret_addr2(poptGetOptArg(pc)); if (is_zero_ip(opt_dest_ip)) d_fprintf(stderr, "\nInvalid ip address specified\n"); else opt_have_ip = True; break; case 'U': opt_user_specified = True; opt_user_name = SMB_STRDUP(opt_user_name); p = strchr(opt_user_name,'%'); if (p) { *p = 0; opt_password = p+1; } break; default: d_fprintf(stderr, "\nInvalid option %s: %s\n", poptBadOption(pc, 0), poptStrerror(opt)); net_help(argc, argv); exit(1); } } /* * Don't load debug level from smb.conf. It should be * set by cmdline arg or remain default (0) */ AllowDebugChange = False; lp_load(dyn_CONFIGFILE,True,False,False,True); argv_new = (const char **)poptGetArgs(pc); argc_new = argc; for (i=0; i<argc; i++) { if (argv_new[i] == NULL) { argc_new = i; break; } } if (do_talloc_report) { talloc_enable_leak_report(); } if (opt_requester_name) { set_global_myname(opt_requester_name); } if (!opt_user_name && getenv("LOGNAME")) { opt_user_name = getenv("LOGNAME"); } if (!opt_user_name) { opt_user_name = ""; } if (!opt_workgroup) { opt_workgroup = smb_xstrdup(lp_workgroup()); } if (!opt_target_workgroup) { opt_target_workgroup = smb_xstrdup(lp_workgroup()); } if (!init_names()) exit(1); load_interfaces(); /* this makes sure that when we do things like call scripts, that it won't assert becouse we are not root */ sec_init(); if (opt_machine_pass) { /* it is very useful to be able to make ads queries as the machine account for testing purposes and for domain leave */ net_use_krb_machine_account(); } if (!opt_password) { opt_password = getenv("PASSWD"); } rc = net_run_function(argc_new-1, argv_new+1, net_func, net_help); DEBUG(2,("return code = %d\n", rc)); return rc; }
BOOL net_find_server(const char *domain, unsigned flags, struct in_addr *server_ip, char **server_name) { const char *d = domain ? domain : opt_target_workgroup; if (opt_host) { *server_name = SMB_STRDUP(opt_host); } if (opt_have_ip) { *server_ip = opt_dest_ip; if (!*server_name) { *server_name = SMB_STRDUP(inet_ntoa(opt_dest_ip)); } } else if (*server_name) { /* resolve the IP address */ if (!resolve_name(*server_name, server_ip, 0x20)) { DEBUG(1,("Unable to resolve server name\n")); return False; } } else if (flags & NET_FLAGS_PDC) { struct in_addr pdc_ip; if (get_pdc_ip(d, &pdc_ip)) { fstring dc_name; if (is_zero_ip(pdc_ip)) return False; if ( !name_status_find(d, 0x1b, 0x20, pdc_ip, dc_name) ) return False; *server_name = SMB_STRDUP(dc_name); *server_ip = pdc_ip; } } else if (flags & NET_FLAGS_DMB) { struct in_addr msbrow_ip; /* if (!resolve_name(MSBROWSE, &msbrow_ip, 1)) */ if (!resolve_name(d, &msbrow_ip, 0x1B)) { DEBUG(1,("Unable to resolve domain browser via name lookup\n")); return False; } else { *server_ip = msbrow_ip; } *server_name = SMB_STRDUP(inet_ntoa(opt_dest_ip)); } else if (flags & NET_FLAGS_MASTER) { struct in_addr brow_ips; if (!resolve_name(d, &brow_ips, 0x1D)) { /* go looking for workgroups */ DEBUG(1,("Unable to resolve master browser via name lookup\n")); return False; } else { *server_ip = brow_ips; } *server_name = SMB_STRDUP(inet_ntoa(opt_dest_ip)); } else if (!(flags & NET_FLAGS_LOCALHOST_DEFAULT_INSANE)) { *server_ip = loopback_ip; *server_name = SMB_STRDUP("127.0.0.1"); } if (!server_name || !*server_name) { DEBUG(1,("no server to connect to\n")); return False; } return True; }
static int join_domain_byuser(char *domain, const char *remote, char *username, char *password) { /* libsmb variables */ pstring pdc_name; struct nmb_name calling, called; struct ntuser_creds creds; struct cli_state cli; fstring acct_name; struct in_addr dest_ip; TALLOC_CTX *mem_ctx; /* 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; pstrcpy(pdc_name, remote ? remote : ""); /* Connect to remote machine */ ZERO_STRUCT(cli); ZERO_STRUCT(creds); ZERO_STRUCT(dest_ip); /* Make sure no nasty surprises */ 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 we are given a remote machine assume this is the PDC. */ if(remote == NULL || !strcmp(remote, "*")) { struct in_addr *ip_list; int addr_count; if (!get_dc_list(True /* PDC only*/, domain, &ip_list, &addr_count)) { fprintf(stderr, "Unable to find the domain controller for domain %s.\n", domain); return 1; } if ((addr_count < 1) || (is_zero_ip(ip_list[0]))) { fprintf(stderr, "Incorrect entries returned when finding the domain controller for domain %s.\n", domain); return 1; } if (!lookup_dc_name(global_myname, domain, &ip_list[0], pdc_name)) { fprintf(stderr, "Unable to lookup the name for the domain controller for domain %s.\n", domain); return 1; } dest_ip = ip_list[0]; } make_nmb_name(&called, pdc_name, 0x20); make_nmb_name(&calling, dns_to_netbios_name(global_myname), 0); if (!cli_establish_connection(&cli, pdc_name, &dest_ip, &calling, &called, "IPC$", "IPC", False, True)) { if (!NT_STATUS_IS_OK(cli_nt_error(&cli))) { DEBUG(0, ("Error connecting to %s - %s\n", pdc_name,cli_errstr(&cli))); } else { DEBUG(0, ("Error connecting to %s\n", pdc_name)); } 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); { uint32 unknown = 0xe005000b; result = cli_samr_create_dom_user(&cli, mem_ctx, &domain_pol, acct_name, ACB_WSTRUST, unknown, &user_pol, &user_rid); } if (NT_STATUS_IS_OK(result)) { /* 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; const 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); mdfour( ntpw, (unsigned char *)upw.buffer, plen); } /* 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_WSTRUST); /* 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; }