2 Unix SMB/CIFS implementation.
4 Copyright (C) James Myers 2003
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 BOOL smbcli_client_initialize(struct smbcli_client* context,
25 char* username, char* password, char* workgroup,
29 for (i=0; i < DFS_MAX_CLUSTER_SIZE ; i++) {
30 context->cli[i] = smbcli_raw_initialise();
32 context->sockops = sockops;
33 context->username = username;
34 context->password = password;
35 context->workgroup = workgroup;
36 context->connection_flags = flags;
37 if (flags & SMBCLI_FULL_CONNECTION_USE_DFS)
38 context->use_dfs = True;
39 context->number_members = DFS_MAX_CLUSTER_SIZE;
43 /****************************************************************************
44 Interpret a Dfs referral structure.
45 The length of the structure is returned
46 The structure of a Dfs referral depends on the info level.
47 ****************************************************************************/
49 static int interpret_referral(struct smbcli_state *cli,
50 int level,char *p,referral_info *rinfo)
57 rinfo->server_type = SVAL(p,4);
58 rinfo->referral_flags = SVAL(p,6);
59 rinfo->proximity = SVAL(p,8);
60 rinfo->ttl = SVAL(p,10);
61 rinfo->pathOffset = SVAL(p,12);
62 rinfo->altPathOffset = SVAL(p,14);
63 rinfo->nodeOffset = SVAL(p,16);
64 DEBUG(3,("referral version=%d, size=%d, server_type=%d, flags=0x%x, proximity=%d, ttl=%d, pathOffset=%d, altPathOffset=%d, nodeOffset=%d\n",
65 version, size, rinfo->server_type, rinfo->referral_flags,
66 rinfo->proximity, rinfo->ttl, rinfo->pathOffset,
67 rinfo->altPathOffset, rinfo->nodeOffset));
69 q = (char*)(p + (rinfo->pathOffset));
70 //printf("p=%p, q=%p, offset=%d\n", p, q, rinfo->pathOffset);
71 //printf("hex=0x%x, string=%s\n", q, q);
72 clistr_pull(cli, rinfo->path, q,
75 DEBUG(4,("referral path=%s\n", rinfo->path));
76 q = (char*)(p + (rinfo->altPathOffset)/sizeof(char));
77 if (rinfo->altPathOffset > 0)
78 clistr_pull(cli, rinfo->altPath, q,
79 sizeof(rinfo->altPath),
81 DEBUG(4,("referral alt path=%s\n", rinfo->altPath));
82 q = (char*)(p + (rinfo->nodeOffset)/sizeof(char));
83 if (rinfo->nodeOffset > 0)
84 clistr_pull(cli, rinfo->node, q,
87 DEBUG(4,("referral node=%s\n", rinfo->node));
88 fstrcpy(rinfo->host, &rinfo->node[1]);
89 p = strchr_m(&rinfo->host[1],'\\');
91 printf("invalid referral node %s\n", rinfo->node);
95 rinfo->share = talloc_strdup(cli->mem_ctx, p+1);
96 DEBUG(3,("referral host=%s share=%s\n",
97 rinfo->host, rinfo->share));
102 int smbcli_select_dfs_referral(struct smbcli_state *cli, dfs_info* dinfo)
104 return (int)sys_random()%dinfo->number_referrals;
107 int smbcli_get_dfs_referral(struct smbcli_state *cli,const char *Fname, dfs_info* dinfo)
109 struct smb_trans2 parms;
114 char *rparam=NULL, *rdata=NULL;
115 int param_len, data_len;
118 DATA_BLOB trans_param, trans_data;
120 /* NT uses 260, OS/2 uses 2. Both accept 1. */
121 info_level = (cli->capabilities&CAP_NT_SMBS)?260:1;
123 pstrcpy(fname,Fname);
125 setup = TRANSACT2_GET_DFS_REFERRAL ;
126 SSVAL(param,0,SMBCLI_DFS_MAX_REFERRAL_LEVEL); /* attribute */
128 p += clistr_push(cli, param+2, fname, -1,
131 param_len = PTR_DIFF(p, param);
132 DEBUG(3,("smbcli_get_dfs_referral: sending request\n"));
134 trans_param.length = param_len;
135 trans_param.data = param;
136 trans_data.length = 0;
137 trans_data.data = NULL;
139 if (!smbcli_send_trans(cli, SMBtrans2,
141 -1, 0, /* fid, flags */
142 &setup, 1, 0, /* setup, length, max */
143 &trans_param, 10, /* param, length, max */
145 cli->max_xmit /* data, length, max */
150 if (!smbcli_receive_trans(cli, SMBtrans2,
152 &rdata, &data_len) &&
153 smbcli_is_dos_error(cli)) {
156 //printf("smbcli_get_dfs_referral: received response, rdata=%p, rparam=%p\n",
159 if (smbcli_is_error(cli) || !rdata)
162 /* parse out some important return info */
163 //printf("smbcli_get_dfs_referral: valid response\n");
165 dinfo->path_consumed = SVAL(p,0);
166 dinfo->number_referrals = SVAL(p,2);
167 dinfo->referral_flags = SVAL(p,4);
168 DEBUG(3,("smbcli_get_dfs_referral: path_consumed=%d, # referrals=%d, flags=0x%x\n",
169 dinfo->path_consumed, dinfo->number_referrals,
170 dinfo->referral_flags));
172 /* point to the referral bytes */
174 for (i=0; i < dinfo->number_referrals; i++) {
175 p += interpret_referral(cli,info_level,p,&dinfo->referrals[i]);
181 DEBUG(3,("received %d Dfs referrals\n",
182 dinfo->number_referrals));
184 dinfo->selected_referral = smbcli_select_dfs_referral(cli, dinfo);
185 DEBUG(3, ("selected Dfs referral %d %s\n",
186 dinfo->selected_referral, dinfo->referrals[dinfo->selected_referral].node));
188 return(dinfo->number_referrals);
192 /* check if the server produced Dfs redirect */
193 BOOL smbcli_check_dfs_redirect(struct smbcli_state* c, char* fname,
196 //printf("check_dfs_redirect: error %s\n",
197 // smbcli_errstr(c));
198 if (smbcli_is_dos_error(c)) {
199 printf("got dos error\n");
207 status = smbcli_nt_error(c);
208 //printf("got nt error 0x%x\n", status);
210 if (NT_STATUS_V(NT_STATUS_PATH_NOT_COVERED) != NT_STATUS_V(status)) {
214 /* execute trans2 getdfsreferral */
215 //printf("check_dfs_redirect: process referral\n");
216 //smbcli_get_dfs_referral(c, fname, dinfo);
220 int smbcli_dfs_open_connection(struct smbcli_client* cluster,
221 char* host, char* share, int flags)
225 struct smbcli_state* c;
227 // check if already connected
228 for (i=0; i < DFS_MAX_CLUSTER_SIZE; i++) {
229 if (cluster->cli[i]->in_use && strequal(host, smbcli_state_get_host(cluster->cli[i]))
230 && strequal(share, smbcli_state_get_share(cluster->cli[i]))) {
231 DEBUG(3,("smbcli_dfs_open_connection: already connected to \\\\%s\\%s\n", host, share));
236 DEBUG(3,("smbcli_dfs_open_connection: opening \\\\%s\\%s %s@%s\n",
237 host, share, cluster->username, cluster->workgroup));
238 for (i=0; i < DFS_MAX_CLUSTER_SIZE; i++) {
239 if (!cluster->cli[i]->in_use) {
243 if (i >= DFS_MAX_CLUSTER_SIZE)
247 if (NT_STATUS_IS_ERR(smbcli_full_connection(&c,
250 cluster->username, cluster->workgroup,
251 cluster->password, flags,
254 smbcli_state_set_sockopt(cluster->cli[i], cluster->sockops);
255 smbcli_state_set_host(cluster->cli[i], host);
256 smbcli_state_set_share(cluster->cli[i], share);
257 cluster->cli[i]->in_use = True;
258 DEBUG(3,("smbcli_dfs_open_connection: connected \\\\%s\\%s (%d) %s@%s\n",
259 smbcli_state_get_host(cluster->cli[i]), smbcli_state_get_share(cluster->cli[i]), i,
260 cluster->username, cluster->workgroup));
265 /**********************************************************************
266 Parse the pathname of the form \hostname\service\reqpath
267 into the dfs_path structure
268 **********************************************************************/
270 BOOL smbcli_parse_dfs_path(char* pathname, struct dfs_path* pdp)
272 pstring pathname_local;
275 pstrcpy(pathname_local,pathname);
276 p = temp = pathname_local;
280 trim_string(temp,"\\","\\");
281 DEBUG(10,("temp in smbcli_parse_dfs_path: .%s. after trimming \\'s\n",temp));
284 /* parse out hostname */
285 p = strchr(temp,'\\');
289 pstrcpy(pdp->hostname,temp);
290 DEBUG(10,("hostname: %s\n",pdp->hostname));
292 /* parse out servicename */
294 p = strchr(temp,'\\');
296 pstrcpy(pdp->servicename,temp);
297 pdp->reqpath[0] = '\0';
301 pstrcpy(pdp->servicename,temp);
302 DEBUG(10,("servicename: %s\n",pdp->servicename));
304 /* rest is reqpath */
305 pstrcpy(pdp->reqpath, p+1);
307 DEBUG(10,("rest of the path: %s\n",pdp->reqpath));
311 char* rebuild_filename(char *referral_fname, struct smbcli_state* c,
312 char* fname, int path_consumed)
314 const char *template = "\\\\%s\\%s\\%s";
317 // TODO: handle consumed length
318 DEBUG(3,("rebuild_filename: %s, %d consumed of %d\n",
319 fname, path_consumed, strlen(fname)));
320 if (smbcli_parse_dfs_path(fname, &dp)) {
321 DEBUG(3,("rebuild_filename: reqpath=%s\n",
323 asprintf(&referral_fname,
324 template, smbcli_state_get_host(c),
325 smbcli_state_get_share(c), dp.reqpath);
329 DEBUG(3,("rebuild_filename: %s -> %s\n", fname, referral_fname));
330 return referral_fname;
333 /****************************************************************************
334 Open a file (allowing for Dfs referral).
335 ****************************************************************************/
337 int smbcli_dfs_open(struct smbcli_client* cluster, int *server,
338 char *fname_src, int flags, int share_mode)
342 char *referral_fname;
345 DEBUG(3,("smbcli_dfs_open: open %s on server %s(%d)\n",
346 fname_src, smbcli_state_get_host(cluster->cli[*server]), *server));
347 cluster->cli[*server]->dfs_referral = *server;
348 if ((fnum = smbcli_open(cluster->cli[*server], fname_src, flags, share_mode)) < 0) {
349 if (smbcli_check_dfs_redirect(cluster->cli[*server], fname_src, &dinfo)) {
350 // choose referral, check if already connected, open if not
351 referral_number = dinfo.selected_referral;
352 DEBUG(3,("smbcli_dfs_open: redirecting to %s\n", dinfo.referrals[referral_number].node));
353 cluster->cli[*server]->dfs_referral = smbcli_dfs_open_connection(cluster,
354 dinfo.referrals[referral_number].host,
355 dinfo.referrals[referral_number].share,
356 cluster->connection_flags);
357 *server = cluster->cli[*server]->dfs_referral;
360 // rebuild file name and retry operation.
361 if (rebuild_filename(referral_fname, cluster->cli[*server], fname_src, dinfo.path_consumed) == NULL)
363 fname_src = referral_fname;
364 DEBUG(3,("smbcli_dfs_open: Dfs open %s on server %s(%d)\n",
365 fname_src, smbcli_state_get_host(cluster->cli[*server]), *server));
366 fnum = smbcli_open(cluster->cli[*server], fname_src, flags, share_mode);
368 if (smbcli_is_error(cluster->cli[*server])) {
369 printf("smbcli_dfs_open: open of %s failed (%s)\n",
370 fname_src, smbcli_errstr(cluster->cli[*server]));
374 DEBUG(3,("smbcli_dfs_open: open %s fnum=%d\n",
379 /****************************************************************************
380 Delete a file (allowing for Dfs referral).
381 ****************************************************************************/
383 NTSTATUS smbcli_nt_unlink(struct smbcli_client* cluster, int *server,
384 char *fname_src, uint16_t FileAttributes)
388 char *referral_fname;
389 struct smb_unlink parms;
391 DEBUG(3,("smbcli_nt_unlink: delete %s on server %s(%d), attributes=0x%x\n",
392 fname_src, smbcli_state_get_host(cluster->cli[*server]), *server,
394 cluster->cli[*server]->dfs_referral = *server;
395 parms.in.pattern = fname_src;
396 parms.in.dirtype = FileAttributes;
397 if (NT_STATUS_IS_ERR(smbcli_raw_unlink(cluster->cli[*server], &parms))) {
398 printf("smbcli_nt_unlink: delete of %s failed (%s)\n",
399 fname_src, smbcli_errstr(cluster->cli[*server]));
400 if (smbcli_check_dfs_redirect(cluster->cli[*server], fname_src, &dinfo)) {
401 // choose referral, check if already connected, open if not
402 referral_number = dinfo.selected_referral;
403 DEBUG(3,("smbcli_nt_unlink: redirecting to %s\n", dinfo.referrals[referral_number].node));
404 cluster->cli[*server]->dfs_referral = smbcli_dfs_open_connection(cluster,
405 dinfo.referrals[referral_number].host,
406 dinfo.referrals[referral_number].share,
407 cluster->connection_flags);
408 *server = cluster->cli[*server]->dfs_referral;
410 return NT_STATUS_INTERNAL_ERROR;
411 // rebuild file name and retry operation.
412 if (rebuild_filename(referral_fname, cluster->cli[*server], fname_src, dinfo.path_consumed) == NULL)
413 return NT_STATUS_INTERNAL_ERROR;
414 fname_src = referral_fname;
415 DEBUG(3,("smbcli_nt_unlink: Dfs delete %s on server %s(%d)\n",
416 fname_src, smbcli_state_get_host(cluster->cli[*server]), *server));
417 smbcli_raw_unlink(cluster->cli[*server], &parms);
419 if (smbcli_is_error(cluster->cli[*server])) {
420 printf("smbcli_nt_unlink: delete of %s failed (%s)\n",
421 fname_src, smbcli_errstr(cluster->cli[*server]));
424 return smbcli_nt_error(cluster->cli[*server]);
427 /****************************************************************************
428 Rename a file (allowing for Dfs referral).
429 ****************************************************************************/
431 BOOL smbcli_dfs_rename(struct smbcli_client* cluster, int *server,
432 char *fname_src, char *fname_dst)
436 char *referral_fname;
438 DEBUG(3,("smbcli_dfs_rename: rename %s to %s on server %s(%d)\n",
439 fname_src, fname_dst, smbcli_state_get_host(cluster->cli[*server]), *server));
440 cluster->cli[*server]->dfs_referral = *server;
441 if (!smbcli_rename(cluster->cli[*server], fname_src, fname_dst)) {
442 if (smbcli_check_dfs_redirect(cluster->cli[*server], fname_src, &dinfo)) {
443 // choose referral, check if already connected, open if not
444 referral_number = dinfo.selected_referral;
445 DEBUG(3,("smbcli_dfs_rename: redirecting to %s\n", dinfo.referrals[referral_number].node));
446 cluster->cli[*server]->dfs_referral = smbcli_dfs_open_connection(cluster,
447 dinfo.referrals[referral_number].host,
448 dinfo.referrals[referral_number].share,
449 cluster->connection_flags);
450 *server = cluster->cli[*server]->dfs_referral;
453 // rebuild file name and retry operation.
454 if (rebuild_filename(referral_fname, cluster->cli[*server], fname_src, dinfo.path_consumed) == NULL)
456 fname_src = referral_fname;
457 DEBUG(3,("smbcli_dfs_rename: Dfs rename %s to %s on server %s(%d)\n",
458 fname_src, fname_dst, smbcli_state_get_host(cluster->cli[*server]), *server));
459 smbcli_rename(cluster->cli[*server], fname_src, fname_dst);
461 if (smbcli_is_error(cluster->cli[*server])) {
462 printf("smbcli_dfs_rename: rename of %s to %s failed (%s)\n",
463 fname_src, fname_dst, smbcli_errstr(cluster->cli[*server]));
470 /****************************************************************************
471 Make directory (allowing for Dfs referral).
472 ****************************************************************************/
474 BOOL smbcli_dfs_mkdir(struct smbcli_client* cluster, int *server,
479 char *referral_fname;
481 DEBUG(3,("smbcli_dfs_mkdir: mkdir %s on server %s(%d)\n",
482 fname_src, smbcli_state_get_host(cluster->cli[*server]), *server));
483 cluster->cli[*server]->dfs_referral = *server;
484 if (!smbcli_mkdir(cluster->cli[*server], fname_src)) {
485 printf("smbcli_dfs_mkdir: mkdir of %s failed (%s)\n",
486 fname_src, smbcli_errstr(cluster->cli[*server]));
487 if (smbcli_check_dfs_redirect(cluster->cli[*server], fname_src, &dinfo)) {
488 // choose referral, check if already connected, open if not
489 referral_number = dinfo.selected_referral;
490 DEBUG(3,("smbcli_dfs_mkdir: redirecting to %s\n", dinfo.referrals[referral_number].node));
491 cluster->cli[*server]->dfs_referral = smbcli_dfs_open_connection(cluster,
492 dinfo.referrals[referral_number].host,
493 dinfo.referrals[referral_number].share,
494 cluster->connection_flags);
495 *server = cluster->cli[*server]->dfs_referral;
498 // rebuild file name and retry operation.
499 if (rebuild_filename(referral_fname, cluster->cli[*server], fname_src, dinfo.path_consumed) == NULL)
501 fname_src = referral_fname;
502 DEBUG(3,("smbcli_dfs_mkdir: Dfs mkdir %s on server %s(%d)\n",
503 fname_src, smbcli_state_get_host(cluster->cli[*server]), *server));
504 smbcli_mkdir(cluster->cli[*server], fname_src);
506 if (smbcli_is_error(cluster->cli[*server])) {
507 printf("smbcli_dfs_mkdir: mkdir of %s failed (%s)\n",
508 fname_src, smbcli_errstr(cluster->cli[*server]));
515 /****************************************************************************
516 Remove directory (allowing for Dfs referral).
517 ****************************************************************************/
519 BOOL smbcli_dfs_rmdir(struct smbcli_client* cluster, int *server,
524 char *referral_fname;
526 DEBUG(3,("smbcli_dfs_rmdir: rmdir %s on server %s(%d)\n",
527 fname_src, smbcli_state_get_host(cluster->cli[*server]), *server));
528 cluster->cli[*server]->dfs_referral = *server;
529 if (!smbcli_rmdir(cluster->cli[*server], fname_src)) {
530 printf("smbcli_dfs_rmdir: rmdir of %s failed (%s)\n",
531 fname_src, smbcli_errstr(cluster->cli[*server]));
532 if (smbcli_check_dfs_redirect(cluster->cli[*server], fname_src, &dinfo)) {
533 // choose referral, check if already connected, open if not
534 referral_number = dinfo.selected_referral;
535 DEBUG(3,("smbcli_dfs_rmdir: redirecting to %s\n", dinfo.referrals[referral_number].node));
536 cluster->cli[*server]->dfs_referral = smbcli_dfs_open_connection(cluster,
537 dinfo.referrals[referral_number].host,
538 dinfo.referrals[referral_number].share,
539 cluster->connection_flags);
540 *server = cluster->cli[*server]->dfs_referral;
543 // rebuild file name and retry operation.
544 if (rebuild_filename(referral_fname, cluster->cli[*server], fname_src, dinfo.path_consumed) == NULL)
546 fname_src = referral_fname;
547 DEBUG(3,("smbcli_dfs_rmdir: Dfs rmdir %s on server %s(%d)\n",
548 fname_src, smbcli_state_get_host(cluster->cli[*server]), *server));
549 smbcli_rmdir(cluster->cli[*server], fname_src);
551 if (smbcli_is_error(cluster->cli[*server])) {
552 printf("smbcli_dfs_rmdir: rmdir of %s failed (%s)\n",
553 fname_src, smbcli_errstr(cluster->cli[*server]));