static int do_message_op(void) { struct in_addr ip; struct nmb_name called, calling; fstring server_name; char name_type_hex[10]; make_nmb_name(&calling, global_myname(), 0x0); make_nmb_name(&called , desthost, name_type); fstrcpy(server_name, desthost); snprintf(name_type_hex, sizeof(name_type_hex), "#%X", name_type); fstrcat(server_name, name_type_hex); zero_ip(&ip); if (!(cli=cli_initialise(NULL)) || (cli_set_port(cli, port) != port) || !cli_connect(cli, server_name, &ip)) { d_printf("Connection to %s failed\n", desthost); return 1; } if (!cli_session_request(cli, &calling, &called)) { d_printf("session request failed\n"); cli_shutdown(cli); return 1; } send_message(); cli_shutdown(cli); return 0; }
BOOL attempt_netbios_session_request(struct cli_state *cli, const char *srchost, const char *desthost, struct in_addr *pdest_ip) { struct nmb_name calling, called; make_nmb_name(&calling, srchost, 0x0); /* * If the called name is an IP address * then use *SMBSERVER immediately. */ if(is_ipaddress(desthost)) make_nmb_name(&called, "*SMBSERVER", 0x20); else make_nmb_name(&called, desthost, 0x20); if (!cli_session_request(cli, &calling, &called)) { struct nmb_name smbservername; make_nmb_name(&smbservername , "*SMBSERVER", 0x20); /* * If the name wasn't *SMBSERVER then * try with *SMBSERVER if the first name fails. */ if (nmb_name_equal(&called, &smbservername)) { /* * The name used was *SMBSERVER, don't bother with another name. */ DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER with error %s.\n", desthost, cli_errstr(cli) )); return False; } /* * We need to close the connection here but can't call cli_shutdown as * will free an allocated cli struct. cli_close_connection was invented * for this purpose. JRA. Based on work by "Kim R. Pedersen" <*****@*****.**>. */ cli_close_connection(cli); if (!cli_initialise(cli) || !cli_connect(cli, desthost, pdest_ip) || !cli_session_request(cli, &calling, &smbservername)) { DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) )); return False; } } return True; }
/* check to see if smbd is running on localhost by trying to open a connection then closing it */ BOOL smbd_running(void) { struct cli_state *cli; if ((cli = cli_initialise()) == NULL) return False; if (!cli_connect(cli, global_myname(), &loopback_ip)) { cli_shutdown(cli); return False; } cli_shutdown(cli); return True; }
/* check to see if smbd is running on localhost by trying to open a connection then closing it */ BOOL smbd_running(void) { static struct cli_state cli; extern struct in_addr loopback_ip; if (!cli_initialise(&cli)) return False; if (!cli_connect(&cli, "localhost", &loopback_ip)) { cli_shutdown(&cli); return False; } cli_shutdown(&cli); return True; }
/**************************************************************************** support for server level security ****************************************************************************/ struct cli_state *server_cryptkey(void) { fstring desthost; struct in_addr dest_ip; extern fstring local_machine; char *p; if (!cli_initialise(&cli)) return NULL; for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) { fstrcpy(desthost,p); standard_sub_basic(desthost); strupper(desthost); if(!resolve_name( desthost, &dest_ip)) { DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",p)); continue; } if (ismyip(dest_ip)) { DEBUG(1,("Password server loop - disabling password server %s\n",p)); continue; } if (cli_connect(&cli, desthost, &dest_ip)) { DEBUG(3,("connected to password server %s\n",p)); break; } } if (!p) { DEBUG(1,("password server not available\n")); cli_shutdown(&cli); return NULL; } if (!cli_session_request(&cli, desthost, 0x20, local_machine)) { DEBUG(1,("%s rejected the session\n",desthost)); cli_shutdown(&cli); return NULL; } DEBUG(3,("got session\n")); if (!cli_negprot(&cli)) { DEBUG(1,("%s rejected the negprot\n",desthost)); cli_shutdown(&cli); return NULL; } if (cli.protocol < PROTOCOL_LANMAN2 || !(cli.sec_mode & 1)) { DEBUG(1,("%s isn't in user level security mode\n",desthost)); cli_shutdown(&cli); return NULL; } DEBUG(3,("password server OK\n")); return &cli; }
static struct cli_state *do_connect( const char *server, const char *share, BOOL show_sessetup ) { struct cli_state *c = NULL; struct nmb_name called, calling; const char *server_n; struct in_addr ip; pstring servicename; char *sharename; fstring newserver, newshare; NTSTATUS status; /* make a copy so we don't modify the global string 'service' */ pstrcpy(servicename, share); sharename = servicename; if (*sharename == '\\') { server = sharename+2; sharename = strchr_m(server,'\\'); if (!sharename) return NULL; *sharename = 0; sharename++; } server_n = server; zero_ip(&ip); make_nmb_name(&calling, global_myname(), 0x0); make_nmb_name(&called , server, name_type); again: zero_ip(&ip); if (have_ip) ip = dest_ip; /* have to open a new connection */ if (!(c=cli_initialise()) || (cli_set_port(c, port) != port)) { d_printf("Connection to %s failed\n", server_n); return NULL; } status = cli_connect(c, server_n, &ip); if (!NT_STATUS_IS_OK(status)) { d_printf("Connection to %s failed (Error %s)\n", server_n, nt_errstr(status)); return NULL; } c->protocol = max_protocol; c->use_kerberos = use_kerberos; cli_setup_signing_state(c, signing_state); if (!cli_session_request(c, &calling, &called, NULL)) { char *p; d_printf("session request to %s failed (%s)\n", called.name, cli_errstr(c)); cli_shutdown(c); c = NULL; if ((p=strchr_m(called.name, '.'))) { *p = 0; goto again; } if (strcmp(called.name, "*SMBSERVER")) { make_nmb_name(&called , "*SMBSERVER", 0x20); goto again; } return NULL; } DEBUG(4,(" session request ok\n")); if (!cli_negprot(c)) { d_printf("protocol negotiation failed\n"); cli_shutdown(c); return NULL; } if (!got_pass) { char *pass = getpass("Password: "******"", "", 0, "", 0, lp_workgroup()))) { d_printf("session setup failed: %s\n", cli_errstr(c)); if (NT_STATUS_V(cli_nt_error(c)) == NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED)) d_printf("did you forget to run kinit?\n"); cli_shutdown(c); return NULL; } d_printf("Anonymous login successful\n"); } if ( show_sessetup ) { if (*c->server_domain) { DEBUG(0,("Domain=[%s] OS=[%s] Server=[%s]\n", c->server_domain,c->server_os,c->server_type)); } else if (*c->server_os || *c->server_type){ DEBUG(0,("OS=[%s] Server=[%s]\n", c->server_os,c->server_type)); } } DEBUG(4,(" session setup ok\n")); /* here's the fun part....to support 'msdfs proxy' shares (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL here before trying to connect to the original share. check_dfs_proxy() will fail if it is a normal share. */ if ( (c->capabilities & CAP_DFS) && cli_check_msdfs_proxy( c, sharename, newserver, newshare ) ) { cli_shutdown(c); return do_connect( newserver, newshare, False ); } /* must be a normal share */ if (!cli_send_tconX(c, sharename, "?????", password, strlen(password)+1)) { d_printf("tree connect failed: %s\n", cli_errstr(c)); cli_shutdown(c); return NULL; } DEBUG(4,(" tconx ok\n")); return c; }
static void sync_child(char *name, int nm_type, char *workgroup, struct in_addr ip, bool local, bool servers, char *fname) { fstring unix_workgroup; struct cli_state *cli; uint32 local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0; struct nmb_name called, calling; struct sockaddr_storage ss; NTSTATUS status; /* W2K DMB's return empty browse lists on port 445. Use 139. * Patch from Andy Levine [email protected]. */ cli = cli_initialise(); if (!cli) { return; } cli_set_port(cli, 139); in_addr_to_sockaddr_storage(&ss, ip); status = cli_connect(cli, name, &ss); if (!NT_STATUS_IS_OK(status)) { cli_shutdown(cli); return; } make_nmb_name(&calling, get_local_machine_name(), 0x0); make_nmb_name(&called , name, nm_type); if (!cli_session_request(cli, &calling, &called)) { cli_shutdown(cli); return; } status = cli_negprot(cli); if (!NT_STATUS_IS_OK(status)) { cli_shutdown(cli); return; } if (!NT_STATUS_IS_OK(cli_session_setup(cli, "", "", 1, "", 0, workgroup))) { cli_shutdown(cli); return; } if (!NT_STATUS_IS_OK(cli_tcon_andx(cli, "IPC$", "IPC", "", 1))) { cli_shutdown(cli); return; } /* All the cli_XX functions take UNIX character set. */ fstrcpy(unix_workgroup, cli->server_domain ? cli->server_domain : workgroup); /* Fetch a workgroup list. */ cli_NetServerEnum(cli, unix_workgroup, local_type|SV_TYPE_DOMAIN_ENUM, callback, NULL); /* Now fetch a server list. */ if (servers) { fstrcpy(unix_workgroup, workgroup); cli_NetServerEnum(cli, unix_workgroup, local?SV_TYPE_LOCAL_LIST_ONLY:SV_TYPE_ALL, callback, NULL); } cli_shutdown(cli); }
static SMBCSRV * SMBC_server_internal(TALLOC_CTX *ctx, SMBCCTX *context, bool connect_if_not_found, const char *server, const char *share, char **pp_workgroup, char **pp_username, char **pp_password, bool *in_cache) { SMBCSRV *srv=NULL; char *workgroup = NULL; struct cli_state *c; struct nmb_name called, calling; const char *server_n = server; struct sockaddr_storage ss; int tried_reverse = 0; int port_try_first; int port_try_next; int is_ipc = (share != NULL && strcmp(share, "IPC$") == 0); uint32 fs_attrs = 0; const char *username_used; NTSTATUS status; char *newserver, *newshare; zero_sockaddr(&ss); ZERO_STRUCT(c); *in_cache = false; if (server[0] == 0) { errno = EPERM; return NULL; } /* Look for a cached connection */ srv = SMBC_find_server(ctx, context, server, share, pp_workgroup, pp_username, pp_password); /* * If we found a connection and we're only allowed one share per * server... */ if (srv && *share != '\0' && smbc_getOptionOneSharePerServer(context)) { /* * ... then if there's no current connection to the share, * connect to it. SMBC_find_server(), or rather the function * pointed to by context->get_cached_srv_fn which * was called by SMBC_find_server(), will have issued a tree * disconnect if the requested share is not the same as the * one that was already connected. */ /* * Use srv->cli->desthost and srv->cli->share instead of * server and share below to connect to the actual share, * i.e., a normal share or a referred share from * 'msdfs proxy' share. */ if (srv->cli->cnum == (uint16) -1) { /* Ensure we have accurate auth info */ SMBC_call_auth_fn(ctx, context, srv->cli->desthost, srv->cli->share, pp_workgroup, pp_username, pp_password); if (!*pp_workgroup || !*pp_username || !*pp_password) { errno = ENOMEM; cli_shutdown(srv->cli); srv->cli = NULL; smbc_getFunctionRemoveCachedServer(context)(context, srv); return NULL; } /* * We don't need to renegotiate encryption * here as the encryption context is not per * tid. */ status = cli_tcon_andx(srv->cli, srv->cli->share, "?????", *pp_password, strlen(*pp_password)+1); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); cli_shutdown(srv->cli); srv->cli = NULL; smbc_getFunctionRemoveCachedServer(context)(context, srv); srv = NULL; } /* Determine if this share supports case sensitivity */ if (is_ipc) { DEBUG(4, ("IPC$ so ignore case sensitivity\n")); } else if (!cli_get_fs_attr_info(c, &fs_attrs)) { DEBUG(4, ("Could not retrieve " "case sensitivity flag: %s.\n", cli_errstr(c))); /* * We can't determine the case sensitivity of * the share. We have no choice but to use the * user-specified case sensitivity setting. */ if (smbc_getOptionCaseSensitive(context)) { cli_set_case_sensitive(c, True); } else { cli_set_case_sensitive(c, False); } } else { DEBUG(4, ("Case sensitive: %s\n", (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? "True" : "False"))); cli_set_case_sensitive( c, (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? True : False)); } /* * Regenerate the dev value since it's based on both * server and share */ if (srv) { srv->dev = (dev_t)(str_checksum(srv->cli->desthost) ^ str_checksum(srv->cli->share)); } } } /* If we have a connection... */ if (srv) { /* ... then we're done here. Give 'em what they came for. */ *in_cache = true; goto done; } /* If we're not asked to connect when a connection doesn't exist... */ if (! connect_if_not_found) { /* ... then we're done here. */ return NULL; } if (!*pp_workgroup || !*pp_username || !*pp_password) { errno = ENOMEM; return NULL; } make_nmb_name(&calling, smbc_getNetbiosName(context), 0x0); make_nmb_name(&called , server, 0x20); DEBUG(4,("SMBC_server: server_n=[%s] server=[%s]\n", server_n, server)); DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server)); again: zero_sockaddr(&ss); /* have to open a new connection */ if ((c = cli_initialise()) == NULL) { errno = ENOMEM; return NULL; } if (smbc_getOptionUseKerberos(context)) { c->use_kerberos = True; } if (smbc_getOptionFallbackAfterKerberos(context)) { c->fallback_after_kerberos = True; } if (smbc_getOptionUseCCache(context)) { c->use_ccache = True; } c->timeout = smbc_getTimeout(context); /* * Force use of port 139 for first try if share is $IPC, empty, or * null, so browse lists can work */ if (share == NULL || *share == '\0' || is_ipc) { port_try_first = 139; port_try_next = 445; } else { port_try_first = 445; port_try_next = 139; } c->port = port_try_first; status = cli_connect(c, server_n, &ss); if (!NT_STATUS_IS_OK(status)) { /* First connection attempt failed. Try alternate port. */ c->port = port_try_next; status = cli_connect(c, server_n, &ss); if (!NT_STATUS_IS_OK(status)) { cli_shutdown(c); errno = ETIMEDOUT; return NULL; } } if (!cli_session_request(c, &calling, &called)) { cli_shutdown(c); if (strcmp(called.name, "*SMBSERVER")) { make_nmb_name(&called , "*SMBSERVER", 0x20); goto again; } else { /* Try one more time, but ensure we don't loop */ /* Only try this if server is an IP address ... */ if (is_ipaddress(server) && !tried_reverse) { fstring remote_name; struct sockaddr_storage rem_ss; if (!interpret_string_addr(&rem_ss, server, NI_NUMERICHOST)) { DEBUG(4, ("Could not convert IP address " "%s to struct sockaddr_storage\n", server)); errno = ETIMEDOUT; return NULL; } tried_reverse++; /* Yuck */ if (name_status_find("*", 0, 0, &rem_ss, remote_name)) { make_nmb_name(&called, remote_name, 0x20); goto again; } } } errno = ETIMEDOUT; return NULL; } DEBUG(4,(" session request ok\n")); status = cli_negprot(c); if (!NT_STATUS_IS_OK(status)) { cli_shutdown(c); errno = ETIMEDOUT; return NULL; } username_used = *pp_username; if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used, *pp_password, strlen(*pp_password), *pp_password, strlen(*pp_password), *pp_workgroup))) { fprintf(stderr, "JerryLin: Libsmb_server.c->SMBC_server_internal: cli_session_setup fail with username=[%s], password=[%s]\n", username_used, *pp_password); /* Failed. Try an anonymous login, if allowed by flags. */ username_used = ""; if (smbc_getOptionNoAutoAnonymousLogin(context) || !NT_STATUS_IS_OK(cli_session_setup(c, username_used, *pp_password, 1, *pp_password, 0, *pp_workgroup))) { cli_shutdown(c); errno = EPERM; return NULL; } } status = cli_init_creds(c, username_used, *pp_workgroup, *pp_password); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); cli_shutdown(c); return NULL; } DEBUG(4,(" session setup ok\n")); /* here's the fun part....to support 'msdfs proxy' shares (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL here before trying to connect to the original share. cli_check_msdfs_proxy() will fail if it is a normal share. */ if ((c->capabilities & CAP_DFS) && cli_check_msdfs_proxy(ctx, c, share, &newserver, &newshare, /* FIXME: cli_check_msdfs_proxy() does not support smbc_smb_encrypt_level type */ context->internal->smb_encryption_level ? true : false, *pp_username, *pp_password, *pp_workgroup)) { cli_shutdown(c); srv = SMBC_server_internal(ctx, context, connect_if_not_found, newserver, newshare, pp_workgroup, pp_username, pp_password, in_cache); TALLOC_FREE(newserver); TALLOC_FREE(newshare); return srv; } /* must be a normal share */ status = cli_tcon_andx(c, share, "?????", *pp_password, strlen(*pp_password)+1); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); fprintf(stderr, "JerryLin: Libsmb_server.c->SMBC_server_internal: cli_tcon_andx return %08X, errno=[%d]\n", NT_STATUS_V(status), errno); cli_shutdown(c); return NULL; } DEBUG(4,(" tconx ok\n")); /* Determine if this share supports case sensitivity */ if (is_ipc) { DEBUG(4, ("IPC$ so ignore case sensitivity\n")); } else if (!cli_get_fs_attr_info(c, &fs_attrs)) { DEBUG(4, ("Could not retrieve case sensitivity flag: %s.\n", cli_errstr(c))); /* * We can't determine the case sensitivity of the share. We * have no choice but to use the user-specified case * sensitivity setting. */ if (smbc_getOptionCaseSensitive(context)) { cli_set_case_sensitive(c, True); } else { cli_set_case_sensitive(c, False); } } else { DEBUG(4, ("Case sensitive: %s\n", (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? "True" : "False"))); cli_set_case_sensitive(c, (fs_attrs & FILE_CASE_SENSITIVE_SEARCH ? True : False)); } if (context->internal->smb_encryption_level) { /* Attempt UNIX smb encryption. */ if (!NT_STATUS_IS_OK(cli_force_encryption(c, username_used, *pp_password, *pp_workgroup))) { /* * context->smb_encryption_level == 1 * means don't fail if encryption can't be negotiated, * == 2 means fail if encryption can't be negotiated. */ DEBUG(4,(" SMB encrypt failed\n")); if (context->internal->smb_encryption_level == 2) { cli_shutdown(c); errno = EPERM; return NULL; } } DEBUG(4,(" SMB encrypt ok\n")); } /* * Ok, we have got a nice connection * Let's allocate a server structure. */ srv = SMB_MALLOC_P(SMBCSRV); if (!srv) { cli_shutdown(c); errno = ENOMEM; return NULL; } ZERO_STRUCTP(srv); srv->cli = c; srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); srv->no_pathinfo = False; srv->no_pathinfo2 = False; srv->no_nt_session = False; done: if (!pp_workgroup || !*pp_workgroup || !**pp_workgroup) { workgroup = talloc_strdup(ctx, smbc_getWorkgroup(context)); } else { workgroup = *pp_workgroup; } if(!workgroup) { return NULL; } /* set the credentials to make DFS work */ smbc_set_credentials_with_fallback(context, workgroup, *pp_username, *pp_password); return srv; }
static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, const int sockfd, const int pipe_index, const char *controller, struct cli_state **cli, BOOL *retry) { char *machine_password, *machine_krb5_principal; char *ipc_username, *ipc_domain, *ipc_password; BOOL got_mutex; BOOL add_failed_connection = True; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; struct sockaddr peeraddr; socklen_t peeraddr_len; struct sockaddr_in *peeraddr_in = (struct sockaddr_in *)&peeraddr; machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(), lp_realm()) == -1) { SAFE_FREE(machine_password); return NT_STATUS_NO_MEMORY; } cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password); *retry = True; got_mutex = secrets_named_mutex(controller, WINBIND_SERVER_MUTEX_WAIT_TIME); if (!got_mutex) { DEBUG(0,("cm_open_connection: mutex grab failed for %s\n", controller)); result = NT_STATUS_POSSIBLE_DEADLOCK; goto done; } if ((*cli = cli_initialise(NULL)) == NULL) { DEBUG(1, ("Could not cli_initialize\n")); result = NT_STATUS_NO_MEMORY; goto done; } (*cli)->timeout = 10000; /* 10 seconds */ (*cli)->fd = sockfd; fstrcpy((*cli)->desthost, controller); (*cli)->use_kerberos = True; peeraddr_len = sizeof(peeraddr); if ((getpeername((*cli)->fd, &peeraddr, &peeraddr_len) != 0) || (peeraddr_len != sizeof(struct sockaddr_in)) || (peeraddr_in->sin_family != PF_INET)) { DEBUG(0,("cm_prepare_connection: %s\n", strerror(errno))); goto done; } if (ntohs(peeraddr_in->sin_port) == 139) { struct nmb_name calling; struct nmb_name called; make_nmb_name(&calling, global_myname(), 0x0); make_nmb_name(&called, "*SMBSERVER", 0x20); if (!cli_session_request(*cli, &calling, &called)) { DEBUG(8, ("cli_session_request failed for %s\n", controller)); goto done; } } cli_setup_signing_state(*cli, Undefined); if (!cli_negprot(*cli)) { DEBUG(1, ("cli_negprot failed\n")); cli_shutdown(*cli); goto done; } /* Krb5 session */ if ((lp_security() == SEC_ADS) && ((*cli)->protocol >= PROTOCOL_NT1 && (*cli)->capabilities & CAP_EXTENDED_SECURITY)) { ADS_STATUS ads_status; (*cli)->use_kerberos = True; DEBUG(5, ("connecting to %s from %s with kerberos principal " "[%s]\n", controller, global_myname(), machine_krb5_principal)); ads_status = cli_session_setup_spnego(*cli, machine_krb5_principal, machine_password, lp_workgroup()); if (!ADS_ERR_OK(ads_status)) DEBUG(4,("failed kerberos session setup with %s\n", ads_errstr(ads_status))); result = ads_ntstatus(ads_status); } if (NT_STATUS_IS_OK(result)) goto session_setup_done; /* Fall back to non-kerberos session setup */ (*cli)->use_kerberos = False; if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) && (strlen(ipc_username) > 0)) { /* Only try authenticated if we have a username */ DEBUG(5, ("connecting to %s from %s with username " "[%s]\\[%s]\n", controller, global_myname(), ipc_domain, ipc_username)); if (cli_session_setup(*cli, ipc_username, ipc_password, strlen(ipc_password)+1, ipc_password, strlen(ipc_password)+1, ipc_domain)) { DEBUG(5, ("authenticated session setup failed\n")); goto session_setup_done; } } /* Fall back to anonymous connection, this might fail later */ if (cli_session_setup(*cli, "", NULL, 0, NULL, 0, "")) { DEBUG(5, ("Connected anonymously\n")); goto session_setup_done; } result = cli_nt_error(*cli); if (NT_STATUS_IS_OK(result)) result = NT_STATUS_UNSUCCESSFUL; /* We can't session setup */ goto done; session_setup_done: if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) { result = cli_nt_error(*cli); DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result))); if (NT_STATUS_IS_OK(result)) result = NT_STATUS_UNSUCCESSFUL; cli_shutdown(*cli); goto done; } secrets_named_mutex_release(controller); got_mutex = False; *retry = False; /* Windows 2003 SP1 does not lie LsaOpenPolicy() over schannel. Returns RPC_NT_CANNOT_SUPPPORT (0xc0020041) for that call. So just drop it on the lsarpc pipe */ if ( (domain->primary || IS_DC) && (pipe_index!=PI_LSARPC) ) { NTSTATUS status = setup_schannel( *cli, domain->name ); if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("schannel refused - continuing without " "schannel (%s)\n", nt_errstr(status))); } } /* set the domain if empty; needed for schannel connections */ if ( !*(*cli)->domain ) fstrcpy( (*cli)->domain, domain->name ); if ( !cli_nt_session_open (*cli, pipe_index) ) { result = NT_STATUS_PIPE_NOT_AVAILABLE; /* This might be a NT4 DC */ if ( is_win2k_pipe(pipe_index) ) add_failed_connection = False; cli_shutdown(*cli); goto done; } result = NT_STATUS_OK; add_failed_connection = False; done: if (got_mutex) secrets_named_mutex_release(controller); SAFE_FREE(machine_password); SAFE_FREE(machine_krb5_principal); SAFE_FREE(ipc_username); SAFE_FREE(ipc_domain); SAFE_FREE(ipc_password); if (add_failed_connection) add_failed_connection_entry(domain->name, controller, result); return result; }
int vscan_send_warning_message(const char *filename, const char *virname, const char *ipaddr) { struct in_addr ip; struct sockaddr_storage ss; struct nmb_name called, calling; pstring myname; pstring message; pstring shortfilename; char* lastslash; static pstring lastfile; static pstring lastip; #if SAMBA_VERSION_MAJOR==3 fstrcpy(remote_machine, get_remote_machine_name()); DEBUG(5, ("remote machine is: %s\n", remote_machine)); #endif /* Only notify once for a given virus/ip combo - otherwise the * scanner will go crazy reaccessing the file and sending * messages once the user hits the "okay" button */ if (strncmp(lastfile,filename,sizeof(pstring)) == 0) { if (strncmp(lastip,ipaddr,sizeof(pstring)) == 0) { DEBUG(5,("Both IP and Filename are the same, not notifying\n")); return 0; } } ZERO_ARRAY(lastfile); ZERO_ARRAY(lastip); pstrcpy(lastfile,filename); pstrcpy(lastip,ipaddr); ZERO_ARRAY(myname); pstrcpy(myname,myhostname()); ZERO_ARRAY(username); /* could make this configurable */ snprintf(username,sizeof(pstring)-1,"%s VIRUS SCANNER",myname); /* We need to get the real ip structure from the ip string * is this info already available somewhere else in samba? */ zero_ip_v4(&ip); if (inet_aton(ipaddr,&ip) == 0) { DEBUG(5,("Cannot resolve ip address %s\n", ipaddr)); return 1; } in_addr_to_sockaddr_storage(&ss, ip); make_nmb_name(&calling, myname, 0x0); make_nmb_name(&called , remote_machine, name_type); if (!(cli=cli_initialise())) { DEBUG(5,("Connection to %s failed\n", remote_machine)); return 1; } cli_set_port(cli, port); if (!NT_STATUS_IS_OK(cli_connect(cli, remote_machine, &ss))) { DEBUG(5,("Connection to %s failed\n", remote_machine)); return 1; } if (!cli_session_request(cli, &calling, &called)) { DEBUG(5,("session request failed\n")); cli_shutdown(cli); return 1; } ZERO_ARRAY(shortfilename); /* we don't want the entire filename, otherwise the message service may choke * so we chop off the path up to the very last forward-slash * assumption: unix-style pathnames in filename (don't know if there's a * portable file-separator variable... */ lastslash = strrchr(filename,'/'); if (lastslash != NULL && lastslash != filename) { pstrcpy(shortfilename,lastslash+1); } else { pstrcpy(shortfilename,filename); } ZERO_ARRAY(message); /* could make the message configurable and language specific? */ snprintf(message,sizeof(pstring)-1, "%s IS INFECTED WITH VIRUS %s.\r\n\r\nAccess will be denied.\r\nPlease contact your system administrator", shortfilename, virname); /* actually send the message... */ send_message(message); cli_shutdown(cli); return 0; }
/***************************************************** return a connection to a server *******************************************************/ static struct cli_state *connect_one(char *share, int snum) { struct cli_state *c; struct nmb_name called, calling; char *server_n; fstring server; struct in_addr ip; fstring myname; static int count; fstrcpy(server,share+2); share = strchr_m(server,'\\'); if (!share) return NULL; *share = 0; share++; server_n = server; zero_ip(&ip); slprintf(myname,sizeof(myname), "lock-%lu-%u", (unsigned long)getpid(), count++); make_nmb_name(&calling, myname, 0x0); make_nmb_name(&called , server, 0x20); again: zero_ip(&ip); /* have to open a new connection */ if (!(c=cli_initialise(NULL)) || !cli_connect(c, server_n, &ip)) { DEBUG(0,("Connection to %s failed\n", server_n)); return NULL; } c->use_kerberos = use_kerberos; if (!cli_session_request(c, &calling, &called)) { DEBUG(0,("session request to %s failed\n", called.name)); cli_shutdown(c); if (strcmp(called.name, "*SMBSERVER")) { make_nmb_name(&called , "*SMBSERVER", 0x20); goto again; } return NULL; } DEBUG(4,(" session request ok\n")); if (!cli_negprot(c)) { DEBUG(0,("protocol negotiation failed\n")); cli_shutdown(c); return NULL; } if (!got_pass) { char *pass = getpass("Password: "******"session setup failed: %s\n", cli_errstr(c))); return NULL; } /* * These next two lines are needed to emulate * old client behaviour for people who have * scripts based on client output. * QUESTION ? Do we want to have a 'client compatibility * mode to turn these on/off ? JRA. */ if (*c->server_domain || *c->server_os || *c->server_type) DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n", c->server_domain,c->server_os,c->server_type)); DEBUG(4,(" session setup ok\n")); if (!cli_send_tconX(c, share, "?????", password[snum], strlen(password[snum])+1)) { DEBUG(0,("tree connect failed: %s\n", cli_errstr(c))); cli_shutdown(c); return NULL; } DEBUG(4,(" tconx ok\n")); c->use_oplocks = use_oplocks; return c; }
NTSTATUS cli_full_connection(struct cli_state **output_cli, const char *my_name, const char *dest_host, struct in_addr *dest_ip, int port, const char *service, const char *service_type, const char *user, const char *domain, const char *password, int pass_len) { struct ntuser_creds creds; NTSTATUS nt_status; struct nmb_name calling; struct nmb_name called; struct cli_state *cli; struct in_addr ip; if (!output_cli) DEBUG(0, ("output_cli is NULL!?!")); *output_cli = NULL; make_nmb_name(&calling, my_name, 0x0); make_nmb_name(&called , dest_host, 0x20); again: if (!(cli = cli_initialise(NULL))) return NT_STATUS_NO_MEMORY; if (cli_set_port(cli, port) != port) { cli_shutdown(cli); return NT_STATUS_UNSUCCESSFUL; } ip = *dest_ip; DEBUG(3,("Connecting to host=%s share=%s\n", dest_host, service)); if (!cli_connect(cli, dest_host, &ip)) { DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n", nmb_namestr(&called), inet_ntoa(*dest_ip))); cli_shutdown(cli); return NT_STATUS_UNSUCCESSFUL; } if (!cli_session_request(cli, &calling, &called)) { char *p; DEBUG(1,("session request to %s failed (%s)\n", called.name, cli_errstr(cli))); cli_shutdown(cli); if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) { *p = 0; goto again; } if (strcmp(called.name, "*SMBSERVER")) { make_nmb_name(&called , "*SMBSERVER", 0x20); goto again; } return NT_STATUS_UNSUCCESSFUL; } if (!cli_negprot(cli)) { DEBUG(1,("failed negprot\n")); nt_status = NT_STATUS_UNSUCCESSFUL; cli_shutdown(cli); return nt_status; } if (!cli_session_setup(cli, user, password, pass_len, password, pass_len, domain)) { DEBUG(1,("failed session setup\n")); nt_status = cli_nt_error(cli); cli_shutdown(cli); if (NT_STATUS_IS_OK(nt_status)) nt_status = NT_STATUS_UNSUCCESSFUL; return nt_status; } if (service) { if (!cli_send_tconX(cli, service, service_type, password, pass_len)) { DEBUG(1,("failed tcon_X\n")); nt_status = cli_nt_error(cli); cli_shutdown(cli); if (NT_STATUS_IS_OK(nt_status)) nt_status = NT_STATUS_UNSUCCESSFUL; return nt_status; } } init_creds(&creds, user, domain, password, pass_len); cli_init_creds(cli, &creds); *output_cli = cli; return NT_STATUS_OK; }
static struct cli_state *do_connect( const char *server, const char *share, BOOL show_sessetup ) { struct cli_state *c; struct nmb_name called, calling; const char *server_n; struct in_addr ip; pstring servicename; char *sharename; /* make a copy so we don't modify the global string 'service' */ pstrcpy(servicename, share); sharename = servicename; if (*sharename == '\\') { server = sharename+2; sharename = strchr_m(server,'\\'); if (!sharename) return NULL; *sharename = 0; sharename++; } server_n = server; zero_ip(&ip); make_nmb_name(&calling, global_myname(), 0x0); make_nmb_name(&called , server, name_type); again: zero_ip(&ip); if (have_ip) ip = dest_ip; /* have to open a new connection */ if (!(c=cli_initialise(NULL)) || (cli_set_port(c, port) != port) || !cli_connect(c, server_n, &ip)) { d_printf("Connection to %s failed\n", server_n); return NULL; } c->protocol = max_protocol; c->use_kerberos = use_kerberos; cli_setup_signing_state(c, signing_state); if (!cli_session_request(c, &calling, &called)) { char *p; d_printf("session request to %s failed (%s)\n", called.name, cli_errstr(c)); cli_shutdown(c); if ((p=strchr_m(called.name, '.'))) { *p = 0; goto again; } if (strcmp(called.name, "*SMBSERVER")) { make_nmb_name(&called , "*SMBSERVER", 0x20); goto again; } return NULL; } DEBUG(4,(" session request ok\n")); if (!cli_negprot(c)) { d_printf("protocol negotiation failed\n"); cli_shutdown(c); return NULL; } if (!got_pass) { char *pass = getpass("Password: "******"", "", 0, "", 0, lp_workgroup())) { d_printf("session setup failed: %s\n", cli_errstr(c)); if (NT_STATUS_V(cli_nt_error(c)) == NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED)) d_printf("did you forget to run kinit?\n"); cli_shutdown(c); return NULL; } d_printf("Anonymous login successful\n"); } if ( show_sessetup ) { if (*c->server_domain) { DEBUG(0,("Domain=[%s] OS=[%s] Server=[%s]\n", c->server_domain,c->server_os,c->server_type)); } else if (*c->server_os || *c->server_type){ DEBUG(0,("OS=[%s] Server=[%s]\n", c->server_os,c->server_type)); } } DEBUG(4,(" session setup ok\n")); if (!cli_send_tconX(c, sharename, "?????", password, strlen(password)+1)) { d_printf("tree connect failed: %s\n", cli_errstr(c)); cli_shutdown(c); return NULL; } DEBUG(4,(" tconx ok\n")); return c; }
/**************************************************************************** initialise smb client structure ****************************************************************************/ void rpcclient_init(void) { memset((char *)smb_cli, '\0', sizeof(smb_cli)); cli_initialise(smb_cli); smb_cli->capabilities |= CAP_NT_SMBS; }
static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx) { struct cli_state *cli = NULL; char *desthost = NULL; struct sockaddr_storage dest_ss; const char *p; char *pserver = NULL; bool connected_ok = False; struct named_mutex *mutex = NULL; NTSTATUS status; if (!(cli = cli_initialise())) return NULL; /* security = server just can't function with spnego */ cli->use_spnego = False; pserver = talloc_strdup(mem_ctx, lp_passwordserver()); p = pserver; while(next_token_talloc(mem_ctx, &p, &desthost, LIST_SEP)) { desthost = talloc_sub_basic(mem_ctx, current_user_info.smb_name, current_user_info.domain, desthost); if (!desthost) { return NULL; } strupper_m(desthost); if(!resolve_name( desthost, &dest_ss, 0x20, false)) { DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost)); continue; } if (ismyaddr((struct sockaddr *)&dest_ss)) { DEBUG(1,("Password server loop - disabling password server %s\n",desthost)); continue; } /* we use a mutex to prevent two connections at once - when a Win2k PDC get two connections where one hasn't completed a session setup yet it will send a TCP reset to the first connection (tridge) */ mutex = grab_named_mutex(talloc_tos(), desthost, 10); if (mutex == NULL) { cli_shutdown(cli); return NULL; } status = cli_connect(cli, desthost, &dest_ss); if (NT_STATUS_IS_OK(status)) { DEBUG(3,("connected to password server %s\n",desthost)); connected_ok = True; break; } DEBUG(10,("server_cryptkey: failed to connect to server %s. Error %s\n", desthost, nt_errstr(status) )); TALLOC_FREE(mutex); } if (!connected_ok) { DEBUG(0,("password server not available\n")); cli_shutdown(cli); return NULL; } if (!attempt_netbios_session_request(&cli, global_myname(), desthost, &dest_ss)) { TALLOC_FREE(mutex); DEBUG(1,("password server fails session request\n")); cli_shutdown(cli); return NULL; } if (strequal(desthost,myhostname())) { exit_server_cleanly("Password server loop!"); } DEBUG(3,("got session\n")); status = cli_negprot(cli); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(mutex); DEBUG(1, ("%s rejected the negprot: %s\n", desthost, nt_errstr(status))); cli_shutdown(cli); return NULL; } if (cli->protocol < PROTOCOL_LANMAN2 || !(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) { TALLOC_FREE(mutex); DEBUG(1,("%s isn't in user level security mode\n",desthost)); cli_shutdown(cli); return NULL; } /* Get the first session setup done quickly, to avoid silly Win2k bugs. (The next connection to the server will kill this one... */ status = cli_session_setup(cli, "", "", 0, "", 0, ""); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(mutex); DEBUG(0,("%s rejected the initial session setup (%s)\n", desthost, nt_errstr(status))); cli_shutdown(cli); return NULL; } TALLOC_FREE(mutex); DEBUG(3,("password server OK\n")); return cli; }
NTSTATUS remote_password_change(const char *remote_machine, const char *user_name, const char *old_passwd, const char *new_passwd, char **err_str) { struct nmb_name calling, called; struct cli_state *cli; struct rpc_pipe_client *pipe_hnd; struct sockaddr_storage ss; NTSTATUS result; bool pass_must_change = False; *err_str = NULL; if(!resolve_name( remote_machine, &ss, 0x20)) { asprintf(err_str, "Unable to find an IP address for machine " "%s.\n", remote_machine); return NT_STATUS_UNSUCCESSFUL; } cli = cli_initialise(); if (!cli) { return NT_STATUS_NO_MEMORY; } result = cli_connect(cli, remote_machine, &ss); if (!NT_STATUS_IS_OK(result)) { asprintf(err_str, "Unable to connect to SMB server on " "machine %s. Error was : %s.\n", remote_machine, nt_errstr(result)); cli_shutdown(cli); return result; } make_nmb_name(&calling, global_myname() , 0x0); make_nmb_name(&called , remote_machine, 0x20); if (!cli_session_request(cli, &calling, &called)) { asprintf(err_str, "machine %s rejected the session setup. " "Error was : %s.\n", remote_machine, cli_errstr(cli) ); result = cli_nt_error(cli); cli_shutdown(cli); return result; } cli->protocol = PROTOCOL_NT1; if (!cli_negprot(cli)) { asprintf(err_str, "machine %s rejected the negotiate " "protocol. Error was : %s.\n", remote_machine, cli_errstr(cli) ); result = cli_nt_error(cli); cli_shutdown(cli); return result; } /* Given things like SMB signing, restrict anonymous and the like, try an authenticated connection first */ result = cli_session_setup(cli, user_name, old_passwd, strlen(old_passwd)+1, old_passwd, strlen(old_passwd)+1, ""); if (!NT_STATUS_IS_OK(result)) { /* Password must change or Password expired are the only valid * error conditions here from where we can proceed, the rest like * account locked out or logon failure will lead to errors later * anyway */ if (!NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) && !NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED)) { asprintf(err_str, "Could not connect to machine %s: " "%s\n", remote_machine, cli_errstr(cli)); cli_shutdown(cli); return result; } pass_must_change = True; /* * We should connect as the anonymous user here, in case * the server has "must change password" checked... * Thanks to <*****@*****.**> for this fix. */ result = cli_session_setup(cli, "", "", 0, "", 0, ""); if (!NT_STATUS_IS_OK(result)) { asprintf(err_str, "machine %s rejected the session " "setup. Error was : %s.\n", remote_machine, cli_errstr(cli) ); cli_shutdown(cli); return result; } cli_init_creds(cli, "", "", NULL); } else { cli_init_creds(cli, user_name, "", old_passwd); } if (!cli_send_tconX(cli, "IPC$", "IPC", "", 1)) { asprintf(err_str, "machine %s rejected the tconX on the IPC$ " "share. Error was : %s.\n", remote_machine, cli_errstr(cli) ); result = cli_nt_error(cli); cli_shutdown(cli); return result; } /* Try not to give the password away too easily */ if (!pass_must_change) { pipe_hnd = cli_rpc_pipe_open_ntlmssp(cli, PI_SAMR, PIPE_AUTH_LEVEL_PRIVACY, "", /* what domain... ? */ user_name, old_passwd, &result); } else { /* * If the user password must be changed the ntlmssp bind will * fail the same way as the session setup above did. The * difference ist that with a pipe bind we don't get a good * error message, the result will be that the rpc call below * will just fail. So we do it anonymously, there's no other * way. */ pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &result); } if (!pipe_hnd) { if (lp_client_lanman_auth()) { /* Use the old RAP method. */ if (!cli_oem_change_password(cli, user_name, new_passwd, old_passwd)) { asprintf(err_str, "machine %s rejected the " "password change: Error was : %s.\n", remote_machine, cli_errstr(cli) ); result = cli_nt_error(cli); cli_shutdown(cli); return result; } } else { asprintf(err_str, "SAMR connection to machine %s " "failed. Error was %s, but LANMAN password " "changed are disabled\n", nt_errstr(result), remote_machine); result = cli_nt_error(cli); cli_shutdown(cli); return result; } } if (NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user(pipe_hnd, pipe_hnd->mem_ctx, user_name, new_passwd, old_passwd))) { /* Great - it all worked! */ cli_shutdown(cli); return NT_STATUS_OK; } else if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) { /* it failed, but for reasons such as wrong password, too short etc ... */ asprintf(err_str, "machine %s rejected the password change: " "Error was : %s.\n", remote_machine, get_friendly_nt_error_msg(result)); cli_shutdown(cli); return result; } /* OK, that failed, so try again... */ cli_rpc_pipe_close(pipe_hnd); /* Try anonymous NTLMSSP... */ cli_init_creds(cli, "", "", NULL); result = NT_STATUS_UNSUCCESSFUL; /* OK, this is ugly, but... try an anonymous pipe. */ pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &result); if ( pipe_hnd && (NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user(pipe_hnd, pipe_hnd->mem_ctx, user_name, new_passwd, old_passwd)))) { /* Great - it all worked! */ cli_shutdown(cli); return NT_STATUS_OK; } else { if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) { /* it failed, but again it was due to things like new password too short */ asprintf(err_str, "machine %s rejected the " "(anonymous) password change: Error was : " "%s.\n", remote_machine, get_friendly_nt_error_msg(result)); cli_shutdown(cli); return result; } /* We have failed to change the user's password, and we think the server just might not support SAMR password changes, so fall back */ if (lp_client_lanman_auth()) { /* Use the old RAP method. */ if (cli_oem_change_password(cli, user_name, new_passwd, old_passwd)) { /* SAMR failed, but the old LanMan protocol worked! */ cli_shutdown(cli); return NT_STATUS_OK; } asprintf(err_str, "machine %s rejected the password " "change: Error was : %s.\n", remote_machine, cli_errstr(cli) ); result = cli_nt_error(cli); cli_shutdown(cli); return result; } else { asprintf(err_str, "SAMR connection to machine %s " "failed. Error was %s, but LANMAN password " "changed are disabled\n", nt_errstr(result), remote_machine); cli_shutdown(cli); return NT_STATUS_UNSUCCESSFUL; } } }
/***************************************************** return a connection to a server *******************************************************/ struct cli_state *connect_one(char *share) { struct cli_state *c; struct nmb_name called, calling; char *server_n; char *server; struct in_addr ip; extern struct in_addr ipzero; server = share+2; share = strchr(server,'\\'); if (!share) return NULL; *share = 0; share++; server_n = server; ip = ipzero; make_nmb_name(&calling, "masktest", 0x0, ""); make_nmb_name(&called , server, 0x20, ""); again: ip = ipzero; /* have to open a new connection */ if (!(c=cli_initialise(NULL)) || (cli_set_port(c, 139) == 0) || !cli_connect(c, server_n, &ip)) { DEBUG(0,("Connection to %s failed\n", server_n)); return NULL; } if (!cli_session_request(c, &calling, &called)) { DEBUG(0,("session request to %s failed\n", called.name)); cli_shutdown(c); if (strcmp(called.name, "*SMBSERVER")) { make_nmb_name(&called , "*SMBSERVER", 0x20, ""); goto again; } return NULL; } DEBUG(4,(" session request ok\n")); if (!cli_negprot(c)) { DEBUG(0,("protocol negotiation failed\n")); cli_shutdown(c); return NULL; } if (!got_pass) { char *pass = getpass("Password: "******"session setup failed: %s\n", cli_errstr(c))); return NULL; } /* * These next two lines are needed to emulate * old client behaviour for people who have * scripts based on client output. * QUESTION ? Do we want to have a 'client compatibility * mode to turn these on/off ? JRA. */ if (*c->server_domain || *c->server_os || *c->server_type) DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n", c->server_domain,c->server_os,c->server_type)); DEBUG(4,(" session setup ok\n")); if (!cli_send_tconX(c, share, "?????", password, strlen(password)+1)) { DEBUG(0,("tree connect failed: %s\n", cli_errstr(c))); cli_shutdown(c); return NULL; } DEBUG(4,(" tconx ok\n")); return c; }
static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx) { struct cli_state *cli = NULL; fstring desthost; struct in_addr dest_ip; const char *p; char *pserver; BOOL connected_ok = False; if (!(cli = cli_initialise())) return NULL; /* security = server just can't function with spnego */ cli->use_spnego = False; pserver = talloc_strdup(mem_ctx, lp_passwordserver()); p = pserver; while(next_token( &p, desthost, LIST_SEP, sizeof(desthost))) { standard_sub_basic(current_user_info.smb_name, current_user_info.domain, desthost, sizeof(desthost)); strupper_m(desthost); if(!resolve_name( desthost, &dest_ip, 0x20)) { DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost)); continue; } if (ismyip(dest_ip)) { DEBUG(1,("Password server loop - disabling password server %s\n",desthost)); continue; } /* we use a mutex to prevent two connections at once - when a Win2k PDC get two connections where one hasn't completed a session setup yet it will send a TCP reset to the first connection (tridge) */ if (!grab_server_mutex(desthost)) { return NULL; } if (cli_connect(cli, desthost, &dest_ip)) { DEBUG(3,("connected to password server %s\n",desthost)); connected_ok = True; break; } } if (!connected_ok) { release_server_mutex(); DEBUG(0,("password server not available\n")); cli_shutdown(cli); return NULL; } if (!attempt_netbios_session_request(&cli, global_myname(), desthost, &dest_ip)) { release_server_mutex(); DEBUG(1,("password server fails session request\n")); cli_shutdown(cli); return NULL; } if (strequal(desthost,myhostname())) { exit_server_cleanly("Password server loop!"); } DEBUG(3,("got session\n")); if (!cli_negprot(cli)) { DEBUG(1,("%s rejected the negprot\n",desthost)); release_server_mutex(); cli_shutdown(cli); return NULL; } if (cli->protocol < PROTOCOL_LANMAN2 || !(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) { DEBUG(1,("%s isn't in user level security mode\n",desthost)); release_server_mutex(); cli_shutdown(cli); return NULL; } /* Get the first session setup done quickly, to avoid silly Win2k bugs. (The next connection to the server will kill this one... */ if (!NT_STATUS_IS_OK(cli_session_setup(cli, "", "", 0, "", 0, ""))) { DEBUG(0,("%s rejected the initial session setup (%s)\n", desthost, cli_errstr(cli))); release_server_mutex(); cli_shutdown(cli); return NULL; } release_server_mutex(); DEBUG(3,("password server OK\n")); return cli; }
/***************************************************** return a connection to a server (existing or new) *******************************************************/ struct smbw_server *smbw_server(char *server, char *share) { struct smbw_server *srv=NULL; struct cli_state c; char *username; char *password; char *workgroup; struct nmb_name called, calling; char *p, *server_n = server; fstring group; pstring ipenv; struct in_addr ip; zero_ip(&ip); ZERO_STRUCT(c); get_auth_data_fn(server, share, &workgroup, &username, &password); /* try to use an existing connection */ for (srv=smbw_srvs;srv;srv=srv->next) { if (strcmp(server,srv->server_name)==0 && strcmp(share,srv->share_name)==0 && strcmp(workgroup,srv->workgroup)==0 && strcmp(username, srv->username) == 0) return srv; } if (server[0] == 0) { errno = EPERM; return NULL; } make_nmb_name(&calling, global_myname, 0x0); make_nmb_name(&called , server, 0x20); DEBUG(4,("server_n=[%s] server=[%s]\n", server_n, server)); if ((p=strchr(server_n,'#')) && (strcmp(p+1,"1D")==0 || strcmp(p+1,"01")==0)) { struct in_addr sip; pstring s; fstrcpy(group, server_n); p = strchr(group,'#'); *p = 0; /* cache the workgroup master lookup */ slprintf(s,sizeof(s)-1,"MASTER_%s", group); if (!(server_n = smbw_getshared(s))) { if (!find_master_ip(group, &sip)) { errno = ENOENT; return NULL; } fstrcpy(group, inet_ntoa(sip)); server_n = group; smbw_setshared(s,server_n); } } DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server)); again: slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n); zero_ip(&ip); if ((p=smbw_getshared(ipenv))) { ip = *(interpret_addr2(p)); } /* have to open a new connection */ if (!cli_initialise(&c) || !cli_connect(&c, server_n, &ip)) { errno = ENOENT; return NULL; } if (!cli_session_request(&c, &calling, &called)) { cli_shutdown(&c); if (strcmp(called.name, "*SMBSERVER")) { make_nmb_name(&called , "*SMBSERVER", 0x20); goto again; } errno = ENOENT; return NULL; } DEBUG(4,(" session request ok\n")); if (!cli_negprot(&c)) { cli_shutdown(&c); errno = ENOENT; return NULL; } if (!cli_session_setup(&c, username, password, strlen(password), password, strlen(password), workgroup) && /* try an anonymous login if it failed */ !cli_session_setup(&c, "", "", 1,"", 0, workgroup)) { cli_shutdown(&c); errno = EPERM; return NULL; } DEBUG(4,(" session setup ok\n")); if (!cli_send_tconX(&c, share, "?????", password, strlen(password)+1)) { errno = smbw_errno(&c); cli_shutdown(&c); return NULL; } smbw_setshared(ipenv,inet_ntoa(ip)); DEBUG(4,(" tconx ok\n")); srv = (struct smbw_server *)malloc(sizeof(*srv)); if (!srv) { errno = ENOMEM; goto failed; } ZERO_STRUCTP(srv); srv->cli = c; srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share)); srv->server_name = strdup(server); if (!srv->server_name) { errno = ENOMEM; goto failed; } srv->share_name = strdup(share); if (!srv->share_name) { errno = ENOMEM; goto failed; } srv->workgroup = strdup(workgroup); if (!srv->workgroup) { errno = ENOMEM; goto failed; } srv->username = strdup(username); if (!srv->username) { errno = ENOMEM; goto failed; } /* some programs play with file descriptors fairly intimately. We try to get out of the way by duping to a high fd number */ if (fcntl(SMBW_CLI_FD + srv->cli.fd, F_GETFD) && errno == EBADF) { if (dup2(srv->cli.fd,SMBW_CLI_FD+srv->cli.fd) == srv->cli.fd+SMBW_CLI_FD) { close(srv->cli.fd); srv->cli.fd += SMBW_CLI_FD; } } DLIST_ADD(smbw_srvs, srv); return srv; failed: cli_shutdown(&c); if (!srv) return NULL; SAFE_FREE(srv->server_name); SAFE_FREE(srv->share_name); SAFE_FREE(srv); return NULL; }
/************************************************************* change a password on a remote machine using IPC calls *************************************************************/ BOOL remote_password_change(const char *remote_machine, const char *user_name, const char *old_passwd, const char *new_passwd, char *err_str, size_t err_str_len) { struct nmb_name calling, called; struct cli_state cli; struct in_addr ip; *err_str = '\0'; if(!resolve_name( remote_machine, &ip, 0x20)) { slprintf(err_str, err_str_len-1, "unable to find an IP address for machine %s.\n", remote_machine ); return False; } ZERO_STRUCT(cli); if (!cli_initialise(&cli) || !cli_connect(&cli, remote_machine, &ip)) { slprintf(err_str, err_str_len-1, "unable to connect to SMB server on machine %s. Error was : %s.\n", remote_machine, cli_errstr(&cli) ); return False; } make_nmb_name(&calling, global_myname() , 0x0); make_nmb_name(&called , remote_machine, 0x20); if (!cli_session_request(&cli, &calling, &called)) { slprintf(err_str, err_str_len-1, "machine %s rejected the session setup. Error was : %s.\n", remote_machine, cli_errstr(&cli) ); cli_shutdown(&cli); return False; } cli.protocol = PROTOCOL_NT1; if (!cli_negprot(&cli)) { slprintf(err_str, err_str_len-1, "machine %s rejected the negotiate protocol. Error was : %s.\n", remote_machine, cli_errstr(&cli) ); cli_shutdown(&cli); return False; } /* * We should connect as the anonymous user here, in case * the server has "must change password" checked... * Thanks to <*****@*****.**> for this fix. */ if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) { slprintf(err_str, err_str_len-1, "machine %s rejected the session setup. Error was : %s.\n", remote_machine, cli_errstr(&cli) ); cli_shutdown(&cli); return False; } if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) { slprintf(err_str, err_str_len-1, "machine %s rejected the tconX on the IPC$ share. Error was : %s.\n", remote_machine, cli_errstr(&cli) ); cli_shutdown(&cli); return False; } if(!cli_oem_change_password(&cli, user_name, new_passwd, old_passwd)) { slprintf(err_str, err_str_len-1, "machine %s rejected the password change: Error was : %s.\n", remote_machine, cli_errstr(&cli) ); cli_shutdown(&cli); return False; } cli_shutdown(&cli); 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; }