BOOL cli_check_msdfs_proxy( struct cli_state *cli, const char *sharename, fstring newserver, fstring newshare ) { CLIENT_DFS_REFERRAL *refs = NULL; size_t num_refs; uint16 consumed; pstring fullpath; BOOL res; uint16 cnum; pstring newextrapath; if ( !cli || !sharename ) return False; cnum = cli->cnum; /* special case. never check for a referral on the IPC$ share */ if ( strequal( sharename, "IPC$" ) ) { return False; } /* send a trans2_query_path_info to check for a referral */ pstr_sprintf( fullpath, "\\%s\\%s", cli->desthost, sharename ); /* check for the referral */ if (!cli_send_tconX(cli, "IPC$", "IPC", NULL, 0)) { return False; } res = cli_dfs_get_referral(cli, fullpath, &refs, &num_refs, &consumed); if (!cli_tdis(cli)) { SAFE_FREE( refs ); return False; } cli->cnum = cnum; if (!res || !num_refs ) { SAFE_FREE( refs ); return False; } split_dfs_path( refs[0].dfspath, newserver, newshare, newextrapath ); /* check that this is not a self-referral */ if ( strequal( cli->desthost, newserver ) && strequal( sharename, newshare ) ) { SAFE_FREE( refs ); return False; } SAFE_FREE( refs ); return True; }
/************************************************************* 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 struct cli_state *smb_complete_connection(const char *myname, const char *server, int port, const char *username, const char *password, const char *workgroup, const char *share, int flags) { struct cli_state *cli; /* New connection */ NTSTATUS nt_status; /* Start the SMB connection */ nt_status = cli_start_connection( &cli, myname, server, NULL, port, Undefined, flags, NULL); if (!NT_STATUS_IS_OK(nt_status)) { return NULL; } /* We pretty much guarentee password must be valid or a pointer to a 0 char. */ if (!password) { return NULL; } if ( (username) && (*username) && (strlen(password) == 0 ) && (cli->use_kerberos) ) { /* Use kerberos authentication */ struct passwd *pw; char *cache_file; if ( !(pw = sys_getpwnam(username)) ) { fprintf(stderr,"ERROR Can not get %s uid\n", username); cli_shutdown(cli); return NULL; } /* * Get the ticket cache of the user to set KRB5CCNAME env * variable */ cache_file = get_ticket_cache( pw->pw_uid ); if ( cache_file == NULL ) { fprintf(stderr, "ERROR: Can not get the ticket cache for %s\n", username); cli_shutdown(cli); return NULL; } if ( setenv(KRB5CCNAME, cache_file, OVERWRITE) < 0 ) { fprintf(stderr, "ERROR: Can not add KRB5CCNAME to the environment"); cli_shutdown(cli); free(cache_file); return NULL; } free(cache_file); /* * Change the UID of the process to be able to read the kerberos * ticket cache */ setuid(pw->pw_uid); } if (!NT_STATUS_IS_OK(cli_session_setup(cli, username, password, strlen(password)+1, password, strlen(password)+1, workgroup))) { fprintf(stderr,"ERROR: Session setup failed: %s\n", cli_errstr(cli)); if (NT_STATUS_V(cli_nt_error(cli)) == NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED)) { fprintf(stderr, "did you forget to run kinit?\n"); } cli_shutdown(cli); return NULL; } if (!cli_send_tconX(cli, share, "?????", password, strlen(password)+1)) { fprintf(stderr, "ERROR: Tree connect failed (%s)\n", cli_errstr(cli)); cli_shutdown(cli); return NULL; } 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; } if (!cli_set_port(cli, 139)) { cli_shutdown(cli); return; } 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; } if (!cli_negprot(cli)) { cli_shutdown(cli); return; } if (!NT_STATUS_IS_OK(cli_session_setup(cli, "", "", 1, "", 0, workgroup))) { cli_shutdown(cli); return; } if (!cli_send_tconX(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); }
/**************************************************************************** establishes a connection right up to doing tconX, reading in a password. ****************************************************************************/ BOOL cli_establish_connection(struct cli_state *cli, char *dest_host, struct in_addr *dest_ip, struct nmb_name *calling, struct nmb_name *called, char *service, char *service_type, BOOL do_shutdown, BOOL do_tcon) { cli->dbg(5, "cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n", nmb_namestr(calling), nmb_namestr(called), inet_ntoa(*dest_ip), cli->user_name, cli->domain); /* establish connection */ if ((!cli->initialised)) { return False; } if (!cli_connect(cli, dest_host, dest_ip)) { cli->dbg(1, "cli_establish_connection: failed to connect to %s (%s)\n", nmb_namestr(calling), inet_ntoa(*dest_ip)); return False; } if (!cli_session_request(cli, calling, called)) { cli->dbg(1, "failed session request\n"); if (do_shutdown) cli_shutdown(cli); return False; } if (!cli_negprot(cli)) { cli->dbg(1, "failed negprot\n"); if (do_shutdown) cli_shutdown(cli); return False; } if (cli->pwd.cleartext || cli->pwd.null_pwd) { fstring passwd; int pass_len; if (cli->pwd.null_pwd) { /* attempt null session */ passwd[0] = 0; pass_len = 1; } else { /* attempt clear-text session */ pwd_get_cleartext(&(cli->pwd), passwd); pass_len = strlen(passwd); } /* attempt clear-text session */ if (!cli_session_setup(cli, cli->user_name, passwd, pass_len, NULL, 0, cli->domain)) { cli->dbg(1, "failed session setup\n"); if (do_shutdown) { cli_shutdown(cli); } return False; } if (do_tcon) { if (!cli_send_tconX(cli, service, service_type, (char *)passwd, strlen(passwd))) { cli->dbg(1, "failed tcon_X\n"); if (do_shutdown) { cli_shutdown(cli); } return False; } } } else { /* attempt encrypted session */ unsigned char nt_sess_pwd[24]; unsigned char lm_sess_pwd[24]; /* creates (storing a copy of) and then obtains a 24 byte password OWF */ pwd_make_lm_nt_owf(&(cli->pwd), cli->cryptkey); pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd); /* attempt encrypted session */ if (!cli_session_setup(cli, cli->user_name, (char *)lm_sess_pwd, sizeof(lm_sess_pwd), (char *)nt_sess_pwd, sizeof(nt_sess_pwd), cli->domain)) { cli->dbg(1, "failed session setup\n"); if (do_shutdown) cli_shutdown(cli); return False; } if (do_tcon) { if (!cli_send_tconX(cli, service, service_type, (char *)nt_sess_pwd, sizeof(nt_sess_pwd))) { cli->dbg(1, "failed tcon_X\n"); if (do_shutdown) cli_shutdown(cli); return False; } } } if (do_shutdown) cli_shutdown(cli); return True; }
/***************************************************** 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; }
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; }
SMBCSRV * SMBC_server(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) { 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; zero_sockaddr(&ss); ZERO_STRUCT(c); 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. */ if (srv->cli->cnum == (uint16) -1) { /* Ensure we have accurate auth info */ SMBC_call_auth_fn(ctx, context, server, 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. */ if (!cli_send_tconX(srv->cli, share, "?????", *pp_password, strlen(*pp_password)+1)) { errno = SMBC_errno(context, srv->cli); 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(server) ^ str_checksum(share)); } } } /* If we have a connection... */ if (srv) { /* ... then we're done here. Give 'em what they came for. */ 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; } 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")); if (!cli_negprot(c)) { 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))) { /* 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; } } cli_init_creds(c, username_used, *pp_workgroup, *pp_password); DEBUG(4,(" session setup ok\n")); if (!cli_send_tconX(c, share, "?????", *pp_password, strlen(*pp_password)+1)) { errno = SMBC_errno(context, c); 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) { errno = ENOMEM; goto failed; } 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; /* now add it to the cache (internal or external) */ /* Let the cache function set errno if it wants to */ errno = 0; if (smbc_getFunctionAddCachedServer(context)(context, srv, server, share, *pp_workgroup, *pp_username)) { int saved_errno = errno; DEBUG(3, (" Failed to add server to cache\n")); errno = saved_errno; if (errno == 0) { errno = ENOMEM; } goto failed; } DEBUG(2, ("Server connect ok: //%s/%s: %p\n", server, share, srv)); DLIST_ADD(context->internal->servers, srv); 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; failed: cli_shutdown(c); if (!srv) { return NULL; } SAFE_FREE(srv); return NULL; }
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; }
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 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; }
/***************************************************** 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; }