00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "includes.h"
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 struct client_connection {
00037 struct client_connection *prev, *next;
00038 struct cli_state *cli;
00039 pstring mount;
00040 };
00041
00042
00043
00044 static pstring username;
00045 static pstring password;
00046 static BOOL use_kerberos;
00047 static BOOL got_pass;
00048 static int signing_state;
00049 int max_protocol = PROTOCOL_NT1;
00050
00051 static int port;
00052 static int name_type = 0x20;
00053 static BOOL have_ip;
00054 static struct in_addr dest_ip;
00055
00056 static struct client_connection *connections;
00057
00058
00059
00060
00061
00062 static struct cli_state *do_connect( const char *server, const char *share,
00063 BOOL show_sessetup )
00064 {
00065 struct cli_state *c = NULL;
00066 struct nmb_name called, calling;
00067 const char *server_n;
00068 struct in_addr ip;
00069 pstring servicename;
00070 char *sharename;
00071 fstring newserver, newshare;
00072 NTSTATUS status;
00073
00074
00075 pstrcpy(servicename, share);
00076 sharename = servicename;
00077 if (*sharename == '\\') {
00078 server = sharename+2;
00079 sharename = strchr_m(server,'\\');
00080 if (!sharename) return NULL;
00081 *sharename = 0;
00082 sharename++;
00083 }
00084
00085 server_n = server;
00086
00087 zero_ip(&ip);
00088
00089 make_nmb_name(&calling, global_myname(), 0x0);
00090 make_nmb_name(&called , server, name_type);
00091
00092 again:
00093 zero_ip(&ip);
00094 if (have_ip)
00095 ip = dest_ip;
00096
00097
00098 if (!(c=cli_initialise()) || (cli_set_port(c, port) != port)) {
00099 d_printf("Connection to %s failed\n", server_n);
00100 return NULL;
00101 }
00102 status = cli_connect(c, server_n, &ip);
00103 if (!NT_STATUS_IS_OK(status)) {
00104 d_printf("Connection to %s failed (Error %s)\n", server_n, nt_errstr(status));
00105 return NULL;
00106 }
00107
00108 c->protocol = max_protocol;
00109 c->use_kerberos = use_kerberos;
00110 cli_setup_signing_state(c, signing_state);
00111
00112
00113 if (!cli_session_request(c, &calling, &called)) {
00114 char *p;
00115 d_printf("session request to %s failed (%s)\n",
00116 called.name, cli_errstr(c));
00117 cli_shutdown(c);
00118 c = NULL;
00119 if ((p=strchr_m(called.name, '.'))) {
00120 *p = 0;
00121 goto again;
00122 }
00123 if (strcmp(called.name, "*SMBSERVER")) {
00124 make_nmb_name(&called , "*SMBSERVER", 0x20);
00125 goto again;
00126 }
00127 return NULL;
00128 }
00129
00130 DEBUG(4,(" session request ok\n"));
00131
00132 if (!cli_negprot(c)) {
00133 d_printf("protocol negotiation failed\n");
00134 cli_shutdown(c);
00135 return NULL;
00136 }
00137
00138 if (!got_pass) {
00139 char *pass = getpass("Password: ");
00140 if (pass) {
00141 pstrcpy(password, pass);
00142 got_pass = 1;
00143 }
00144 }
00145
00146 if (!NT_STATUS_IS_OK(cli_session_setup(c, username,
00147 password, strlen(password),
00148 password, strlen(password),
00149 lp_workgroup()))) {
00150
00151 if (password[0] || !username[0] || use_kerberos ||
00152 !NT_STATUS_IS_OK(cli_session_setup(c, "", "", 0, "", 0,
00153 lp_workgroup()))) {
00154 d_printf("session setup failed: %s\n", cli_errstr(c));
00155 if (NT_STATUS_V(cli_nt_error(c)) ==
00156 NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED))
00157 d_printf("did you forget to run kinit?\n");
00158 cli_shutdown(c);
00159 return NULL;
00160 }
00161 d_printf("Anonymous login successful\n");
00162 }
00163
00164 if ( show_sessetup ) {
00165 if (*c->server_domain) {
00166 DEBUG(0,("Domain=[%s] OS=[%s] Server=[%s]\n",
00167 c->server_domain,c->server_os,c->server_type));
00168 } else if (*c->server_os || *c->server_type){
00169 DEBUG(0,("OS=[%s] Server=[%s]\n",
00170 c->server_os,c->server_type));
00171 }
00172 }
00173 DEBUG(4,(" session setup ok\n"));
00174
00175
00176
00177
00178
00179
00180 if ( (c->capabilities & CAP_DFS) && cli_check_msdfs_proxy( c, sharename, newserver, newshare ) ) {
00181 cli_shutdown(c);
00182 return do_connect( newserver, newshare, False );
00183 }
00184
00185
00186
00187 if (!cli_send_tconX(c, sharename, "?????", password, strlen(password)+1)) {
00188 d_printf("tree connect failed: %s\n", cli_errstr(c));
00189 cli_shutdown(c);
00190 return NULL;
00191 }
00192
00193 DEBUG(4,(" tconx ok\n"));
00194
00195 return c;
00196 }
00197
00198
00199
00200
00201 static void cli_cm_set_mntpoint( struct cli_state *c, const char *mnt )
00202 {
00203 struct client_connection *p;
00204 int i;
00205
00206 for ( p=connections,i=0; p; p=p->next,i++ ) {
00207 if ( strequal(p->cli->desthost, c->desthost) && strequal(p->cli->share, c->share) )
00208 break;
00209 }
00210
00211 if ( p ) {
00212 pstrcpy( p->mount, mnt );
00213 clean_name(p->mount);
00214 }
00215 }
00216
00217
00218
00219
00220 const char *cli_cm_get_mntpoint( struct cli_state *c )
00221 {
00222 struct client_connection *p;
00223 int i;
00224
00225 for ( p=connections,i=0; p; p=p->next,i++ ) {
00226 if ( strequal(p->cli->desthost, c->desthost) && strequal(p->cli->share, c->share) )
00227 break;
00228 }
00229
00230 if ( p )
00231 return p->mount;
00232
00233 return NULL;
00234 }
00235
00236
00237
00238
00239
00240 static struct cli_state *cli_cm_connect( const char *server,
00241 const char *share,
00242 BOOL show_hdr)
00243 {
00244 struct client_connection *node;
00245
00246 node = SMB_XMALLOC_P( struct client_connection );
00247
00248 node->cli = do_connect( server, share, show_hdr );
00249
00250 if ( !node->cli ) {
00251 SAFE_FREE( node );
00252 return NULL;
00253 }
00254
00255 DLIST_ADD( connections, node );
00256
00257 cli_cm_set_mntpoint( node->cli, "" );
00258
00259 return node->cli;
00260
00261 }
00262
00263
00264
00265
00266
00267 static struct cli_state *cli_cm_find( const char *server, const char *share )
00268 {
00269 struct client_connection *p;
00270
00271 for ( p=connections; p; p=p->next ) {
00272 if ( strequal(server, p->cli->desthost) && strequal(share,p->cli->share) )
00273 return p->cli;
00274 }
00275
00276 return NULL;
00277 }
00278
00279
00280
00281
00282
00283
00284 struct cli_state *cli_cm_open(const char *server,
00285 const char *share,
00286 BOOL show_hdr)
00287 {
00288 struct cli_state *c;
00289
00290
00291
00292 c = cli_cm_find( server, share );
00293
00294 if ( !c ) {
00295 c = cli_cm_connect(server, share, show_hdr);
00296 }
00297
00298 return c;
00299 }
00300
00301
00302
00303
00304 void cli_cm_shutdown( void )
00305 {
00306
00307 struct client_connection *p, *x;
00308
00309 for ( p=connections; p; ) {
00310 cli_shutdown( p->cli );
00311 x = p;
00312 p = p->next;
00313
00314 SAFE_FREE( x );
00315 }
00316
00317 connections = NULL;
00318 return;
00319 }
00320
00321
00322
00323
00324 void cli_cm_display(void)
00325 {
00326 struct client_connection *p;
00327 int i;
00328
00329 for ( p=connections,i=0; p; p=p->next,i++ ) {
00330 d_printf("%d:\tserver=%s, share=%s\n",
00331 i, p->cli->desthost, p->cli->share );
00332 }
00333 }
00334
00335
00336
00337
00338 void cli_cm_set_credentials( struct user_auth_info *user )
00339 {
00340 pstrcpy( username, user->username );
00341
00342 if ( user->got_pass ) {
00343 pstrcpy( password, user->password );
00344 got_pass = True;
00345 }
00346
00347 use_kerberos = user->use_kerberos;
00348 signing_state = user->signing_state;
00349 }
00350
00351
00352
00353
00354 void cli_cm_set_port( int port_number )
00355 {
00356 port = port_number;
00357 }
00358
00359
00360
00361
00362 void cli_cm_set_dest_name_type( int type )
00363 {
00364 name_type = type;
00365 }
00366
00367
00368
00369
00370 void cli_cm_set_dest_ip(struct in_addr ip )
00371 {
00372 dest_ip = ip;
00373 have_ip = True;
00374 }
00375
00376
00377
00378
00379
00380 static void split_dfs_path( const char *nodepath, fstring server, fstring share, pstring extrapath )
00381 {
00382 char *p, *q;
00383 pstring path;
00384
00385 pstrcpy( path, nodepath );
00386
00387 if ( path[0] != '\\' ) {
00388 return;
00389 }
00390
00391 p = strchr_m( path + 1, '\\' );
00392 if ( !p ) {
00393 return;
00394 }
00395
00396 *p = '\0';
00397 p++;
00398
00399
00400 q = strchr_m(p, '\\');
00401 if (q != NULL) {
00402 *q = '\0';
00403 q++;
00404 pstrcpy( extrapath, q );
00405 } else {
00406 pstrcpy( extrapath, '\0' );
00407 }
00408
00409 fstrcpy( share, p );
00410 fstrcpy( server, &path[1] );
00411 }
00412
00413
00414
00415
00416
00417
00418
00419 static void clean_path(const char *path, pstring path_out)
00420 {
00421 size_t len;
00422 char *p1, *p2, *p;
00423
00424
00425 while (IS_DIRECTORY_SEP(*path)) {
00426 path++;
00427 }
00428
00429 pstrcpy(path_out, path);
00430
00431 p1 = strchr_m(path_out, '*');
00432 p2 = strchr_m(path_out, '?');
00433
00434 if (p1 || p2) {
00435 if (p1 && p2) {
00436 p = MIN(p1,p2);
00437 } else if (!p1) {
00438 p = p2;
00439 } else {
00440 p = p1;
00441 }
00442 *p = '\0';
00443
00444
00445 p1 = strrchr_m(path_out, '/');
00446 p2 = strrchr_m(path_out, '\\');
00447 p = MAX(p1,p2);
00448 if (p) {
00449 *p = '\0';
00450 }
00451 }
00452
00453
00454
00455 len = strlen(path_out);
00456 if ( (len > 0) && IS_DIRECTORY_SEP(path_out[len-1])) {
00457 path_out[len-1] = '\0';
00458 }
00459 }
00460
00461
00462
00463
00464 static void cli_dfs_make_full_path( struct cli_state *cli,
00465 const char *dir,
00466 pstring path_out)
00467 {
00468
00469 while (IS_DIRECTORY_SEP(*dir)) {
00470 dir++;
00471 }
00472
00473 pstr_sprintf( path_out, "\\%s\\%s\\%s", cli->desthost, cli->share, dir);
00474 }
00475
00476
00477
00478
00479
00480 static BOOL cli_dfs_check_error( struct cli_state *cli, NTSTATUS status )
00481 {
00482 uint32 flgs2 = SVAL(cli->inbuf,smb_flg2);
00483
00484
00485
00486 if ( !( (flgs2&FLAGS2_32_BIT_ERROR_CODES) && (flgs2&FLAGS2_UNICODE_STRINGS) ) )
00487 return False;
00488
00489 if ( NT_STATUS_EQUAL( status, NT_STATUS(IVAL(cli->inbuf,smb_rcls)) ) )
00490 return True;
00491
00492 return False;
00493 }
00494
00495
00496
00497
00498
00499 BOOL cli_dfs_get_referral( struct cli_state *cli,
00500 const char *path,
00501 CLIENT_DFS_REFERRAL**refs,
00502 size_t *num_refs,
00503 uint16 *consumed)
00504 {
00505 unsigned int data_len = 0;
00506 unsigned int param_len = 0;
00507 uint16 setup = TRANSACT2_GET_DFS_REFERRAL;
00508 char param[sizeof(pstring)+2];
00509 pstring data;
00510 char *rparam=NULL, *rdata=NULL;
00511 char *p;
00512 size_t pathlen = 2*(strlen(path)+1);
00513 uint16 num_referrals;
00514 CLIENT_DFS_REFERRAL *referrals = NULL;
00515
00516 memset(param, 0, sizeof(param));
00517 SSVAL(param, 0, 0x03);
00518 p = ¶m[2];
00519
00520 p += clistr_push(cli, p, path, MIN(pathlen, sizeof(param)-2), STR_TERMINATE);
00521 param_len = PTR_DIFF(p, param);
00522
00523 if (!cli_send_trans(cli, SMBtrans2,
00524 NULL,
00525 -1, 0,
00526 &setup, 1, 0,
00527 param, param_len, 2,
00528 (char *)&data, data_len, cli->max_xmit
00529 )) {
00530 return False;
00531 }
00532
00533 if (!cli_receive_trans(cli, SMBtrans2,
00534 &rparam, ¶m_len,
00535 &rdata, &data_len)) {
00536 return False;
00537 }
00538
00539 *consumed = SVAL( rdata, 0 );
00540 num_referrals = SVAL( rdata, 2 );
00541
00542 if ( num_referrals != 0 ) {
00543 uint16 ref_version;
00544 uint16 ref_size;
00545 int i;
00546 uint16 node_offset;
00547
00548 referrals = SMB_XMALLOC_ARRAY( CLIENT_DFS_REFERRAL, num_referrals );
00549
00550
00551
00552 p = rdata+8;
00553 for ( i=0; i<num_referrals; i++ ) {
00554 ref_version = SVAL( p, 0 );
00555 ref_size = SVAL( p, 2 );
00556 node_offset = SVAL( p, 16 );
00557
00558 if ( ref_version != 3 ) {
00559 p += ref_size;
00560 continue;
00561 }
00562
00563 referrals[i].proximity = SVAL( p, 8 );
00564 referrals[i].ttl = SVAL( p, 10 );
00565
00566 clistr_pull( cli, referrals[i].dfspath, p+node_offset,
00567 sizeof(referrals[i].dfspath), -1, STR_TERMINATE|STR_UNICODE );
00568
00569 p += ref_size;
00570 }
00571 }
00572
00573 *num_refs = num_referrals;
00574 *refs = referrals;
00575
00576 SAFE_FREE(rdata);
00577 SAFE_FREE(rparam);
00578
00579 return True;
00580 }
00581
00582
00583
00584
00585
00586 BOOL cli_resolve_path( const char *mountpt,
00587 struct cli_state *rootcli,
00588 const char *path,
00589 struct cli_state **targetcli,
00590 pstring targetpath)
00591 {
00592 CLIENT_DFS_REFERRAL *refs = NULL;
00593 size_t num_refs;
00594 uint16 consumed;
00595 struct cli_state *cli_ipc;
00596 pstring dfs_path, cleanpath, extrapath;
00597 int pathlen;
00598 fstring server, share;
00599 struct cli_state *newcli;
00600 pstring newpath;
00601 pstring newmount;
00602 char *ppath, *temppath = NULL;
00603
00604 SMB_STRUCT_STAT sbuf;
00605 uint32 attributes;
00606
00607 if ( !rootcli || !path || !targetcli ) {
00608 return False;
00609 }
00610
00611
00612
00613 if ( !rootcli->dfsroot) {
00614 *targetcli = rootcli;
00615 pstrcpy( targetpath, path );
00616 return True;
00617 }
00618
00619 *targetcli = NULL;
00620
00621
00622
00623 clean_path(path, cleanpath);
00624 cli_dfs_make_full_path(rootcli, cleanpath, dfs_path );
00625
00626 if (cli_qpathinfo_basic( rootcli, dfs_path, &sbuf, &attributes ) ) {
00627
00628 *targetcli = rootcli;
00629 pstrcpy( targetpath, path );
00630 goto done;
00631 }
00632
00633
00634
00635 if ( cli_dfs_check_error(rootcli, NT_STATUS_OBJECT_NAME_NOT_FOUND) ) {
00636 *targetcli = rootcli;
00637 pstrcpy( targetpath, path );
00638 goto done;
00639 }
00640
00641
00642
00643 if ( !cli_dfs_check_error(rootcli, NT_STATUS_PATH_NOT_COVERED)) {
00644 return False;
00645 }
00646
00647
00648
00649 if ( !(cli_ipc = cli_cm_open( rootcli->desthost, "IPC$", False )) ) {
00650 return False;
00651 }
00652
00653 if ( !cli_dfs_get_referral(cli_ipc, dfs_path, &refs, &num_refs, &consumed)
00654 || !num_refs ) {
00655 return False;
00656 }
00657
00658
00659
00660 split_dfs_path( refs[0].dfspath, server, share, extrapath );
00661 SAFE_FREE(refs);
00662
00663
00664
00665 cli_dfs_make_full_path( rootcli, path, dfs_path);
00666 pathlen = strlen( dfs_path )*2;
00667 consumed = MIN(pathlen, consumed );
00668 pstrcpy( targetpath, &dfs_path[consumed/2] );
00669 dfs_path[consumed/2] = '\0';
00670
00671
00672
00673
00674
00675
00676
00677
00678 if ( (*targetcli = cli_cm_open(server, share, False)) == NULL ) {
00679 d_printf("Unable to follow dfs referral [\\%s\\%s]\n",
00680 server, share );
00681 return False;
00682 }
00683
00684 if (strlen(extrapath) > 0) {
00685 string_append(&temppath, extrapath);
00686 string_append(&temppath, targetpath);
00687 pstrcpy( targetpath, temppath );
00688 }
00689
00690
00691
00692
00693 ppath = dfs_path;
00694
00695 if (*ppath != '\\') {
00696 d_printf("cli_resolve_path: dfs_path (%s) not in correct format.\n",
00697 dfs_path );
00698 return False;
00699 }
00700
00701 ppath++;
00702
00703 if ((ppath = strchr_m( dfs_path, '\\' )) == NULL) {
00704 return False;
00705 }
00706
00707 ppath++;
00708
00709 if ((ppath = strchr_m( ppath+1, '\\' )) == NULL) {
00710 return False;
00711 }
00712
00713 ppath++;
00714
00715 pstr_sprintf( newmount, "%s\\%s", mountpt, ppath );
00716
00717 cli_cm_set_mntpoint( *targetcli, newmount );
00718
00719
00720
00721
00722 if ( !strequal( targetpath, "\\" ) && !strequal( targetpath, "/")) {
00723 if ( cli_resolve_path( newmount, *targetcli, targetpath, &newcli, newpath ) ) {
00724
00725
00726
00727
00728
00729 *targetcli = newcli;
00730 pstrcpy( targetpath, newpath );
00731 return True;
00732 }
00733 }
00734
00735 done:
00736
00737
00738 if ( (*targetcli)->dfsroot ) {
00739 pstrcpy(dfs_path, targetpath );
00740 cli_dfs_make_full_path( *targetcli, dfs_path, targetpath);
00741 }
00742
00743 return True;
00744 }
00745
00746
00747
00748
00749 BOOL cli_check_msdfs_proxy( struct cli_state *cli, const char *sharename,
00750 fstring newserver, fstring newshare )
00751 {
00752 CLIENT_DFS_REFERRAL *refs = NULL;
00753 size_t num_refs;
00754 uint16 consumed;
00755 pstring fullpath;
00756 BOOL res;
00757 uint16 cnum;
00758 pstring newextrapath;
00759
00760 if ( !cli || !sharename )
00761 return False;
00762
00763 cnum = cli->cnum;
00764
00765
00766
00767 if ( strequal( sharename, "IPC$" ) ) {
00768 return False;
00769 }
00770
00771
00772
00773 pstr_sprintf( fullpath, "\\%s\\%s", cli->desthost, sharename );
00774
00775
00776
00777 if (!cli_send_tconX(cli, "IPC$", "IPC", NULL, 0)) {
00778 return False;
00779 }
00780
00781 res = cli_dfs_get_referral(cli, fullpath, &refs, &num_refs, &consumed);
00782
00783 if (!cli_tdis(cli)) {
00784 SAFE_FREE( refs );
00785 return False;
00786 }
00787
00788 cli->cnum = cnum;
00789
00790 if (!res || !num_refs ) {
00791 SAFE_FREE( refs );
00792 return False;
00793 }
00794
00795 split_dfs_path( refs[0].dfspath, newserver, newshare, newextrapath );
00796
00797
00798
00799 if ( strequal( cli->desthost, newserver ) && strequal( sharename, newshare ) ) {
00800 SAFE_FREE( refs );
00801 return False;
00802 }
00803
00804 SAFE_FREE( refs );
00805
00806 return True;
00807 }