Fix C++ warnings
[Samba/gbeck.git] / source3 / libsmb / clidfs.c
blobe0c40b52ed269bf95dd24a89923ab4ba5dc95641
1 /*
2 Unix SMB/CIFS implementation.
3 client connect/disconnect routines
4 Copyright (C) Andrew Tridgell 1994-1998
5 Copyright (C) Gerald (Jerry) Carter 2004
6 Copyright (C) Jeremy Allison 2007
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
24 /********************************************************************
25 Important point.
27 DFS paths are *always* of the form \server\share\<pathname> (the \ characters
28 are not C escaped here).
30 - but if we're using POSIX paths then <pathname> may contain
31 '/' separators, not '\\' separators. So cope with '\\' or '/'
32 as a separator when looking at the pathname part.... JRA.
33 ********************************************************************/
35 struct client_connection {
36 struct client_connection *prev, *next;
37 struct cli_state *cli;
38 char *mount;
41 /* global state....globals reek! */
42 int max_protocol = PROTOCOL_NT1;
44 static struct cm_cred_struct {
45 char *username;
46 char *password;
47 bool got_pass;
48 bool use_kerberos;
49 int signing_state;
50 } cm_creds;
52 static void cm_set_password(const char *newpass);
54 static int port;
55 static int name_type = 0x20;
56 static bool have_ip;
57 static struct sockaddr_storage dest_ss;
59 static struct client_connection *connections;
61 /********************************************************************
62 Return a connection to a server.
63 ********************************************************************/
65 static struct cli_state *do_connect(TALLOC_CTX *ctx,
66 const char *server,
67 const char *share,
68 bool show_sessetup)
70 struct cli_state *c = NULL;
71 struct nmb_name called, calling;
72 const char *server_n;
73 struct sockaddr_storage ss;
74 char *servicename;
75 char *sharename;
76 char *newserver, *newshare;
77 const char *username;
78 const char *password;
79 NTSTATUS status;
81 /* make a copy so we don't modify the global string 'service' */
82 servicename = talloc_strdup(ctx,share);
83 if (!servicename) {
84 return NULL;
86 sharename = servicename;
87 if (*sharename == '\\') {
88 server = sharename+2;
89 sharename = strchr_m(server,'\\');
90 if (!sharename) {
91 return NULL;
93 *sharename = 0;
94 sharename++;
97 server_n = server;
99 zero_addr(&ss);
101 make_nmb_name(&calling, global_myname(), 0x0);
102 make_nmb_name(&called , server, name_type);
104 again:
105 zero_addr(&ss);
106 if (have_ip)
107 ss = dest_ss;
109 /* have to open a new connection */
110 if (!(c=cli_initialise()) || (cli_set_port(c, port) != port)) {
111 d_printf("Connection to %s failed\n", server_n);
112 return NULL;
114 status = cli_connect(c, server_n, &ss);
115 if (!NT_STATUS_IS_OK(status)) {
116 d_printf("Connection to %s failed (Error %s)\n",
117 server_n,
118 nt_errstr(status));
119 return NULL;
122 c->protocol = max_protocol;
123 c->use_kerberos = cm_creds.use_kerberos;
124 cli_setup_signing_state(c, cm_creds.signing_state);
126 if (!cli_session_request(c, &calling, &called)) {
127 char *p;
128 d_printf("session request to %s failed (%s)\n",
129 called.name, cli_errstr(c));
130 cli_shutdown(c);
131 c = NULL;
132 if ((p=strchr_m(called.name, '.'))) {
133 *p = 0;
134 goto again;
136 if (strcmp(called.name, "*SMBSERVER")) {
137 make_nmb_name(&called , "*SMBSERVER", 0x20);
138 goto again;
140 return NULL;
143 DEBUG(4,(" session request ok\n"));
145 if (!cli_negprot(c)) {
146 d_printf("protocol negotiation failed\n");
147 cli_shutdown(c);
148 return NULL;
151 if (!cm_creds.got_pass) {
152 char *pass = getpass("Password: ");
153 if (pass) {
154 cm_set_password(pass);
158 username = cm_creds.username ? cm_creds.username : "";
159 password = cm_creds.password ? cm_creds.password : "";
161 if (!NT_STATUS_IS_OK(cli_session_setup(c, username,
162 password, strlen(password),
163 password, strlen(password),
164 lp_workgroup()))) {
165 /* If a password was not supplied then
166 * try again with a null username. */
167 if (password[0] || !username[0] || cm_creds.use_kerberos ||
168 !NT_STATUS_IS_OK(cli_session_setup(c, "",
169 "", 0,
170 "", 0,
171 lp_workgroup()))) {
172 d_printf("session setup failed: %s\n", cli_errstr(c));
173 if (NT_STATUS_V(cli_nt_error(c)) ==
174 NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED))
175 d_printf("did you forget to run kinit?\n");
176 cli_shutdown(c);
177 return NULL;
179 d_printf("Anonymous login successful\n");
182 if ( show_sessetup ) {
183 if (*c->server_domain) {
184 DEBUG(0,("Domain=[%s] OS=[%s] Server=[%s]\n",
185 c->server_domain,c->server_os,c->server_type));
186 } else if (*c->server_os || *c->server_type) {
187 DEBUG(0,("OS=[%s] Server=[%s]\n",
188 c->server_os,c->server_type));
191 DEBUG(4,(" session setup ok\n"));
193 /* here's the fun part....to support 'msdfs proxy' shares
194 (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL
195 here before trying to connect to the original share.
196 check_dfs_proxy() will fail if it is a normal share. */
198 if ((c->capabilities & CAP_DFS) &&
199 cli_check_msdfs_proxy(ctx, c, sharename,
200 &newserver, &newshare)) {
201 cli_shutdown(c);
202 return do_connect(ctx, newserver, newshare, false);
205 /* must be a normal share */
207 if (!cli_send_tconX(c, sharename, "?????",
208 password, strlen(password)+1)) {
209 d_printf("tree connect failed: %s\n", cli_errstr(c));
210 cli_shutdown(c);
211 return NULL;
214 DEBUG(4,(" tconx ok\n"));
215 return c;
218 /****************************************************************************
219 ****************************************************************************/
221 static void cli_cm_set_mntpoint(struct cli_state *c, const char *mnt)
223 struct client_connection *p;
224 int i;
226 for (p=connections,i=0; p; p=p->next,i++) {
227 if (strequal(p->cli->desthost, c->desthost) &&
228 strequal(p->cli->share, c->share)) {
229 break;
233 if (p) {
234 char *name = clean_name(NULL, p->mount);
235 if (!name) {
236 return;
238 p->mount = talloc_strdup(p, name);
239 TALLOC_FREE(name);
243 /****************************************************************************
244 ****************************************************************************/
246 const char *cli_cm_get_mntpoint(struct cli_state *c)
248 struct client_connection *p;
249 int i;
251 for (p=connections,i=0; p; p=p->next,i++) {
252 if (strequal(p->cli->desthost, c->desthost) &&
253 strequal(p->cli->share, c->share)) {
254 break;
258 if (p) {
259 return p->mount;
261 return NULL;
264 /********************************************************************
265 Add a new connection to the list
266 ********************************************************************/
268 static struct cli_state *cli_cm_connect(TALLOC_CTX *ctx,
269 struct cli_state *referring_cli,
270 const char *server,
271 const char *share,
272 bool show_hdr)
274 struct client_connection *node;
276 /* NB This must be the null context here... JRA. */
277 node = TALLOC_ZERO_ARRAY(NULL, struct client_connection, 1);
278 if (!node) {
279 return NULL;
282 node->cli = do_connect(ctx, server, share, show_hdr);
284 if ( !node->cli ) {
285 TALLOC_FREE( node );
286 return NULL;
289 DLIST_ADD( connections, node );
291 cli_cm_set_mntpoint(node->cli, "");
293 if (referring_cli && referring_cli->posix_capabilities) {
294 uint16 major, minor;
295 uint32 caplow, caphigh;
296 if (cli_unix_extensions_version(node->cli, &major,
297 &minor, &caplow, &caphigh)) {
298 cli_set_unix_extensions_capabilities(node->cli,
299 major, minor,
300 caplow, caphigh);
304 return node->cli;
307 /********************************************************************
308 Return a connection to a server.
309 ********************************************************************/
311 static struct cli_state *cli_cm_find(const char *server, const char *share)
313 struct client_connection *p;
315 for (p=connections; p; p=p->next) {
316 if ( strequal(server, p->cli->desthost) &&
317 strequal(share,p->cli->share)) {
318 return p->cli;
322 return NULL;
325 /****************************************************************************
326 Open a client connection to a \\server\share. Set's the current *cli
327 global variable as a side-effect (but only if the connection is successful).
328 ****************************************************************************/
330 struct cli_state *cli_cm_open(TALLOC_CTX *ctx,
331 struct cli_state *referring_cli,
332 const char *server,
333 const char *share,
334 bool show_hdr)
336 struct cli_state *c;
338 /* try to reuse an existing connection */
340 c = cli_cm_find(server, share);
341 if (!c) {
342 c = cli_cm_connect(ctx, referring_cli, server, share, show_hdr);
345 return c;
348 /****************************************************************************
349 ****************************************************************************/
351 void cli_cm_shutdown(void)
353 struct client_connection *p, *x;
355 for (p=connections; p;) {
356 cli_shutdown(p->cli);
357 x = p;
358 p = p->next;
360 TALLOC_FREE(x);
363 connections = NULL;
364 return;
367 /****************************************************************************
368 ****************************************************************************/
370 void cli_cm_display(void)
372 struct client_connection *p;
373 int i;
375 for ( p=connections,i=0; p; p=p->next,i++ ) {
376 d_printf("%d:\tserver=%s, share=%s\n",
377 i, p->cli->desthost, p->cli->share );
381 /****************************************************************************
382 ****************************************************************************/
384 static void cm_set_password(const char *newpass)
386 SAFE_FREE(cm_creds.password);
387 cm_creds.password = SMB_STRDUP(newpass);
388 if (cm_creds.password) {
389 cm_creds.got_pass = true;
393 void cli_cm_set_credentials(void)
395 SAFE_FREE(cm_creds.username);
396 cm_creds.username = SMB_STRDUP(get_cmdline_auth_info_username());
398 if (get_cmdline_auth_info_got_pass()) {
399 cm_set_password(get_cmdline_auth_info_password());
402 cm_creds.use_kerberos = get_cmdline_auth_info_use_kerberos();
403 cm_creds.signing_state = get_cmdline_auth_info_signing_state();
406 /****************************************************************************
407 ****************************************************************************/
409 void cli_cm_set_port(int port_number)
411 port = port_number;
414 /****************************************************************************
415 ****************************************************************************/
417 void cli_cm_set_dest_name_type(int type)
419 name_type = type;
422 /****************************************************************************
423 ****************************************************************************/
425 void cli_cm_set_dest_ss(struct sockaddr_storage *pss)
427 dest_ss = *pss;
428 have_ip = true;
431 /**********************************************************************
432 split a dfs path into the server, share name, and extrapath components
433 **********************************************************************/
435 static void split_dfs_path(TALLOC_CTX *ctx,
436 const char *nodepath,
437 char **pp_server,
438 char **pp_share,
439 char **pp_extrapath)
441 char *p, *q;
442 char *path;
444 *pp_server = NULL;
445 *pp_share = NULL;
446 *pp_extrapath = NULL;
448 path = talloc_strdup(ctx, nodepath);
449 if (!path) {
450 return;
453 if ( path[0] != '\\' ) {
454 return;
457 p = strchr_m( path + 1, '\\' );
458 if ( !p ) {
459 return;
462 *p = '\0';
463 p++;
465 /* Look for any extra/deep path */
466 q = strchr_m(p, '\\');
467 if (q != NULL) {
468 *q = '\0';
469 q++;
470 *pp_extrapath = talloc_strdup(ctx, q);
471 } else {
472 *pp_extrapath = talloc_strdup(ctx, "");
475 *pp_share = talloc_strdup(ctx, p);
476 *pp_server = talloc_strdup(ctx, &path[1]);
479 /****************************************************************************
480 Return the original path truncated at the directory component before
481 the first wildcard character. Trust the caller to provide a NULL
482 terminated string
483 ****************************************************************************/
485 static char *clean_path(TALLOC_CTX *ctx, const char *path)
487 size_t len;
488 char *p1, *p2, *p;
489 char *path_out;
491 /* No absolute paths. */
492 while (IS_DIRECTORY_SEP(*path)) {
493 path++;
496 path_out = talloc_strdup(ctx, path);
497 if (!path_out) {
498 return NULL;
501 p1 = strchr_m(path_out, '*');
502 p2 = strchr_m(path_out, '?');
504 if (p1 || p2) {
505 if (p1 && p2) {
506 p = MIN(p1,p2);
507 } else if (!p1) {
508 p = p2;
509 } else {
510 p = p1;
512 *p = '\0';
514 /* Now go back to the start of this component. */
515 p1 = strrchr_m(path_out, '/');
516 p2 = strrchr_m(path_out, '\\');
517 p = MAX(p1,p2);
518 if (p) {
519 *p = '\0';
523 /* Strip any trailing separator */
525 len = strlen(path_out);
526 if ( (len > 0) && IS_DIRECTORY_SEP(path_out[len-1])) {
527 path_out[len-1] = '\0';
530 return path_out;
533 /****************************************************************************
534 ****************************************************************************/
536 static char *cli_dfs_make_full_path(TALLOC_CTX *ctx,
537 struct cli_state *cli,
538 const char *dir)
540 /* Ensure the extrapath doesn't start with a separator. */
541 while (IS_DIRECTORY_SEP(*dir)) {
542 dir++;
545 return talloc_asprintf(ctx, "\\%s\\%s\\%s",
546 cli->desthost, cli->share, dir);
549 /********************************************************************
550 check for dfs referral
551 ********************************************************************/
553 static bool cli_dfs_check_error( struct cli_state *cli, NTSTATUS status )
555 uint32 flgs2 = SVAL(cli->inbuf,smb_flg2);
557 /* only deal with DS when we negotiated NT_STATUS codes and UNICODE */
559 if (!((flgs2&FLAGS2_32_BIT_ERROR_CODES) &&
560 (flgs2&FLAGS2_UNICODE_STRINGS)))
561 return false;
563 if (NT_STATUS_EQUAL(status, NT_STATUS(IVAL(cli->inbuf,smb_rcls))))
564 return true;
566 return false;
569 /********************************************************************
570 Get the dfs referral link.
571 ********************************************************************/
573 bool cli_dfs_get_referral(TALLOC_CTX *ctx,
574 struct cli_state *cli,
575 const char *path,
576 CLIENT_DFS_REFERRAL**refs,
577 size_t *num_refs,
578 uint16 *consumed)
580 unsigned int data_len = 0;
581 unsigned int param_len = 0;
582 uint16 setup = TRANSACT2_GET_DFS_REFERRAL;
583 char *param;
584 char *rparam=NULL, *rdata=NULL;
585 char *p;
586 char *endp;
587 size_t pathlen = 2*(strlen(path)+1);
588 uint16 num_referrals;
589 CLIENT_DFS_REFERRAL *referrals = NULL;
590 bool ret = false;
592 *num_refs = 0;
593 *refs = NULL;
595 param = SMB_MALLOC_ARRAY(char, 2+pathlen+2);
596 if (!param) {
597 return false;
599 SSVAL(param, 0, 0x03); /* max referral level */
600 p = &param[2];
602 p += clistr_push(cli, p, path, pathlen, STR_TERMINATE);
603 param_len = PTR_DIFF(p, param);
605 if (!cli_send_trans(cli, SMBtrans2,
606 NULL, /* name */
607 -1, 0, /* fid, flags */
608 &setup, 1, 0, /* setup, length, max */
609 param, param_len, 2, /* param, length, max */
610 NULL, 0, cli->max_xmit /* data, length, max */
611 )) {
612 SAFE_FREE(param);
613 return false;
616 SAFE_FREE(param);
618 if (!cli_receive_trans(cli, SMBtrans2,
619 &rparam, &param_len,
620 &rdata, &data_len)) {
621 return false;
624 if (data_len < 4) {
625 goto out;
628 endp = rdata + data_len;
630 *consumed = SVAL(rdata, 0);
631 num_referrals = SVAL(rdata, 2);
633 if (num_referrals != 0) {
634 uint16 ref_version;
635 uint16 ref_size;
636 int i;
637 uint16 node_offset;
639 referrals = TALLOC_ARRAY(ctx, CLIENT_DFS_REFERRAL,
640 num_referrals);
642 if (!referrals) {
643 goto out;
645 /* start at the referrals array */
647 p = rdata+8;
648 for (i=0; i<num_referrals && p < endp; i++) {
649 if (p + 18 > endp) {
650 goto out;
652 ref_version = SVAL(p, 0);
653 ref_size = SVAL(p, 2);
654 node_offset = SVAL(p, 16);
656 if (ref_version != 3) {
657 p += ref_size;
658 continue;
661 referrals[i].proximity = SVAL(p, 8);
662 referrals[i].ttl = SVAL(p, 10);
664 if (p + node_offset > endp) {
665 goto out;
667 clistr_pull_talloc(ctx, cli, &referrals[i].dfspath,
668 p+node_offset, -1,
669 STR_TERMINATE|STR_UNICODE );
671 if (!referrals[i].dfspath) {
672 goto out;
674 p += ref_size;
676 if (i < num_referrals) {
677 goto out;
681 ret = true;
683 *num_refs = num_referrals;
684 *refs = referrals;
686 out:
688 SAFE_FREE(rdata);
689 SAFE_FREE(rparam);
690 return ret;
693 /********************************************************************
694 ********************************************************************/
696 bool cli_resolve_path(TALLOC_CTX *ctx,
697 const char *mountpt,
698 struct cli_state *rootcli,
699 const char *path,
700 struct cli_state **targetcli,
701 char **pp_targetpath)
703 CLIENT_DFS_REFERRAL *refs = NULL;
704 size_t num_refs = 0;
705 uint16 consumed;
706 struct cli_state *cli_ipc = NULL;
707 char *dfs_path = NULL;
708 char *cleanpath = NULL;
709 char *extrapath = NULL;
710 int pathlen;
711 char *server = NULL;
712 char *share = NULL;
713 struct cli_state *newcli = NULL;
714 char *newpath = NULL;
715 char *newmount = NULL;
716 char *ppath = NULL;
717 SMB_STRUCT_STAT sbuf;
718 uint32 attributes;
720 if ( !rootcli || !path || !targetcli ) {
721 return false;
724 /* Don't do anything if this is not a DFS root. */
726 if ( !rootcli->dfsroot) {
727 *targetcli = rootcli;
728 *pp_targetpath = talloc_strdup(ctx, path);
729 if (!*pp_targetpath) {
730 return false;
732 return true;
735 *targetcli = NULL;
737 /* Send a trans2_query_path_info to check for a referral. */
739 cleanpath = clean_path(ctx, path);
740 if (!cleanpath) {
741 return false;
744 dfs_path = cli_dfs_make_full_path(ctx, rootcli, cleanpath);
745 if (!dfs_path) {
746 return false;
749 if (cli_qpathinfo_basic( rootcli, dfs_path, &sbuf, &attributes)) {
750 /* This is an ordinary path, just return it. */
751 *targetcli = rootcli;
752 *pp_targetpath = talloc_strdup(ctx, path);
753 if (!*pp_targetpath) {
754 return false;
756 goto done;
759 /* Special case where client asked for a path that does not exist */
761 if (cli_dfs_check_error(rootcli, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
762 *targetcli = rootcli;
763 *pp_targetpath = talloc_strdup(ctx, path);
764 if (!*pp_targetpath) {
765 return false;
767 goto done;
770 /* We got an error, check for DFS referral. */
772 if (!cli_dfs_check_error(rootcli, NT_STATUS_PATH_NOT_COVERED)) {
773 return false;
776 /* Check for the referral. */
778 if (!(cli_ipc = cli_cm_open(ctx, rootcli,
779 rootcli->desthost, "IPC$", false))) {
780 return false;
783 if (!cli_dfs_get_referral(ctx, cli_ipc, dfs_path, &refs,
784 &num_refs, &consumed) || !num_refs) {
785 return false;
788 /* Just store the first referral for now. */
790 if (!refs[0].dfspath) {
791 return false;
793 split_dfs_path(ctx, refs[0].dfspath, &server, &share, &extrapath );
795 if (!server || !share) {
796 return false;
799 /* Make sure to recreate the original string including any wildcards. */
801 dfs_path = cli_dfs_make_full_path(ctx, rootcli, path);
802 if (!dfs_path) {
803 return false;
805 pathlen = strlen(dfs_path)*2;
806 consumed = MIN(pathlen, consumed);
807 *pp_targetpath = talloc_strdup(ctx, &dfs_path[consumed/2]);
808 if (!*pp_targetpath) {
809 return false;
811 dfs_path[consumed/2] = '\0';
814 * *pp_targetpath is now the unconsumed part of the path.
815 * dfs_path is now the consumed part of the path
816 * (in \server\share\path format).
819 /* Open the connection to the target server & share */
820 if ((*targetcli = cli_cm_open(ctx, rootcli,
821 server, share, false)) == NULL) {
822 d_printf("Unable to follow dfs referral [\\%s\\%s]\n",
823 server, share );
824 return false;
827 if (extrapath && strlen(extrapath) > 0) {
828 *pp_targetpath = talloc_asprintf(ctx,
829 "%s%s",
830 extrapath,
831 *pp_targetpath);
832 if (!*pp_targetpath) {
833 return false;
837 /* parse out the consumed mount path */
838 /* trim off the \server\share\ */
840 ppath = dfs_path;
842 if (*ppath != '\\') {
843 d_printf("cli_resolve_path: "
844 "dfs_path (%s) not in correct format.\n",
845 dfs_path );
846 return false;
849 ppath++; /* Now pointing at start of server name. */
851 if ((ppath = strchr_m( dfs_path, '\\' )) == NULL) {
852 return false;
855 ppath++; /* Now pointing at start of share name. */
857 if ((ppath = strchr_m( ppath+1, '\\' )) == NULL) {
858 return false;
861 ppath++; /* Now pointing at path component. */
863 newmount = talloc_asprintf(ctx, "%s\\%s", mountpt, ppath );
864 if (!newmount) {
865 return false;
868 cli_cm_set_mntpoint(*targetcli, newmount);
870 /* Check for another dfs referral, note that we are not
871 checking for loops here. */
873 if (!strequal(*pp_targetpath, "\\") && !strequal(*pp_targetpath, "/")) {
874 if (cli_resolve_path(ctx,
875 newmount,
876 *targetcli,
877 *pp_targetpath,
878 &newcli,
879 &newpath)) {
881 * When cli_resolve_path returns true here it's always
882 * returning the complete path in newpath, so we're done
883 * here.
885 *targetcli = newcli;
886 *pp_targetpath = newpath;
887 return true;
891 done:
893 /* If returning true ensure we return a dfs root full path. */
894 if ((*targetcli)->dfsroot) {
895 dfs_path = talloc_strdup(ctx, *pp_targetpath);
896 if (!dfs_path) {
897 return false;
899 *pp_targetpath = cli_dfs_make_full_path(ctx, *targetcli, dfs_path);
902 return true;
905 /********************************************************************
906 ********************************************************************/
908 bool cli_check_msdfs_proxy(TALLOC_CTX *ctx,
909 struct cli_state *cli,
910 const char *sharename,
911 char **pp_newserver,
912 char **pp_newshare )
914 CLIENT_DFS_REFERRAL *refs = NULL;
915 size_t num_refs = 0;
916 uint16 consumed;
917 char *fullpath = NULL;
918 bool res;
919 uint16 cnum;
920 char *newextrapath = NULL;
922 if (!cli || !sharename) {
923 return false;
926 cnum = cli->cnum;
928 /* special case. never check for a referral on the IPC$ share */
930 if (strequal(sharename, "IPC$")) {
931 return false;
934 /* send a trans2_query_path_info to check for a referral */
936 fullpath = talloc_asprintf(ctx, "\\%s\\%s", cli->desthost, sharename );
937 if (!fullpath) {
938 return false;
941 /* check for the referral */
943 if (!cli_send_tconX(cli, "IPC$", "IPC", NULL, 0)) {
944 return false;
947 res = cli_dfs_get_referral(ctx, cli, fullpath, &refs, &num_refs, &consumed);
949 if (!cli_tdis(cli)) {
950 return false;
953 cli->cnum = cnum;
955 if (!res || !num_refs) {
956 return false;
959 if (!refs[0].dfspath) {
960 return false;
963 split_dfs_path(ctx, refs[0].dfspath, pp_newserver,
964 pp_newshare, &newextrapath );
966 if (!pp_newserver || !pp_newshare) {
967 return false;
970 /* check that this is not a self-referral */
972 if (strequal(cli->desthost, *pp_newserver) &&
973 strequal(sharename, *pp_newshare)) {
974 return false;
977 return true;