Пример #1
0
BOOL cli_resolve_path( const char *mountpt,
			struct cli_state *rootcli,
			const char *path,
			struct cli_state **targetcli,
			pstring targetpath)
{
	CLIENT_DFS_REFERRAL *refs = NULL;
	size_t num_refs;
	uint16 consumed;
	struct cli_state *cli_ipc;
	pstring dfs_path, cleanpath, extrapath;
	int pathlen;
	fstring server, share;
	struct cli_state *newcli;
	pstring newpath;
	pstring newmount;
	char *ppath, *temppath = NULL;
	
	SMB_STRUCT_STAT sbuf;
	uint32 attributes;
	
	if ( !rootcli || !path || !targetcli ) {
		return False;
	}
		
	/* Don't do anything if this is not a DFS root. */

	if ( !rootcli->dfsroot) {
		*targetcli = rootcli;
		pstrcpy( targetpath, path );
		return True;
	}

	*targetcli = NULL;

	/* Send a trans2_query_path_info to check for a referral. */

	clean_path(path, cleanpath);
	cli_dfs_make_full_path(rootcli, cleanpath, dfs_path );

	if (cli_qpathinfo_basic( rootcli, dfs_path, &sbuf, &attributes ) ) {
		/* This is an ordinary path, just return it. */
		*targetcli = rootcli;
		pstrcpy( targetpath, path );
		goto done;
	}

	/* Special case where client asked for a path that does not exist */

	if ( cli_dfs_check_error(rootcli, NT_STATUS_OBJECT_NAME_NOT_FOUND) ) {
		*targetcli = rootcli;
		pstrcpy( targetpath, path );
		goto done;
	}

	/* We got an error, check for DFS referral. */

	if ( !cli_dfs_check_error(rootcli, NT_STATUS_PATH_NOT_COVERED))  {
		return False;
	}

	/* Check for the referral. */

	if ( !(cli_ipc = cli_cm_open( rootcli->desthost, "IPC$", False )) ) {
		return False;
	}
	
	if ( !cli_dfs_get_referral(cli_ipc, dfs_path, &refs, &num_refs, &consumed) 
			|| !num_refs ) {
		return False;
	}
	
	/* Just store the first referral for now. */

	split_dfs_path( refs[0].dfspath, server, share, extrapath );
	SAFE_FREE(refs);

	/* Make sure to recreate the original string including any wildcards. */
	
	cli_dfs_make_full_path( rootcli, path, dfs_path);
	pathlen = strlen( dfs_path )*2;
	consumed = MIN(pathlen, consumed );
	pstrcpy( targetpath, &dfs_path[consumed/2] );
	dfs_path[consumed/2] = '\0';

	/*
 	 * targetpath is now the unconsumed part of the path.
 	 * dfs_path is now the consumed part of the path (in \server\share\path format).
 	 */

	/* Open the connection to the target server & share */
	
	if ( (*targetcli = cli_cm_open(server, share, False)) == NULL ) {
		d_printf("Unable to follow dfs referral [\\%s\\%s]\n",
			server, share );
		return False;
	}
	
	if (strlen(extrapath) > 0) {
		string_append(&temppath, extrapath);
		string_append(&temppath, targetpath);
		pstrcpy( targetpath, temppath );
	}
	
	/* parse out the consumed mount path */
	/* trim off the \server\share\ */

	ppath = dfs_path;

	if (*ppath != '\\') {
		d_printf("cli_resolve_path: dfs_path (%s) not in correct format.\n",
			dfs_path );
		return False;
	}

	ppath++; /* Now pointing at start of server name. */
	
	if ((ppath = strchr_m( dfs_path, '\\' )) == NULL) {
		return False;
	}

	ppath++; /* Now pointing at start of share name. */

	if ((ppath = strchr_m( ppath+1, '\\' )) == NULL) {
		return False;
	}

	ppath++; /* Now pointing at path component. */

	pstr_sprintf( newmount, "%s\\%s", mountpt, ppath );

	cli_cm_set_mntpoint( *targetcli, newmount );

	/* Check for another dfs referral, note that we are not 
	   checking for loops here. */

	if ( !strequal( targetpath, "\\" ) &&  !strequal( targetpath, "/")) {
		if ( cli_resolve_path( newmount, *targetcli, targetpath, &newcli, newpath ) ) {
			/*
			 * When cli_resolve_path returns true here it's always
 			 * returning the complete path in newpath, so we're done
 			 * here.
 			 */
			*targetcli = newcli;
			pstrcpy( targetpath, newpath );
			return True;
		}
	}

  done:

	/* If returning True ensure we return a dfs root full path. */
	if ( (*targetcli)->dfsroot ) {
		pstrcpy(dfs_path, targetpath );
		cli_dfs_make_full_path( *targetcli, dfs_path, targetpath); 
	}

	return True;
}
Пример #2
0
SMBCFILE *
SMBC_open_ctx(SMBCCTX *context,
              const char *fname,
              int flags,
              mode_t mode)
{
	char *server = NULL;
        char *share = NULL;
        char *user = NULL;
        char *password = NULL;
        char *workgroup = NULL;
	char *path = NULL;
	char *targetpath = NULL;
	struct cli_state *targetcli = NULL;
	SMBCSRV *srv   = NULL;
	SMBCFILE *file = NULL;
	uint16_t fd;
	uint16_t port = 0;
	NTSTATUS status = NT_STATUS_OBJECT_PATH_INVALID;
	TALLOC_CTX *frame = talloc_stackframe();

	if (!context || !context->internal->initialized) {
		errno = EINVAL;  /* Best I can think of ... */
		TALLOC_FREE(frame);
		return NULL;
	}

	if (!fname) {
		errno = EINVAL;
		TALLOC_FREE(frame);
		return NULL;
	}

	if (SMBC_parse_path(frame,
                            context,
                            fname,
                            &workgroup,
                            &server,
                            &port,
                            &share,
                            &path,
                            &user,
                            &password,
                            NULL)) {
		errno = EINVAL;
		TALLOC_FREE(frame);
		return NULL;
        }

	if (!user || user[0] == (char)0) {
		user = talloc_strdup(frame, smbc_getUser(context));
		if (!user) {
                	errno = ENOMEM;
			TALLOC_FREE(frame);
			return NULL;
		}
	}

	srv = SMBC_server(frame, context, True,
                          server, port, share, &workgroup, &user, &password);
	if (!srv) {
		if (errno == EPERM) errno = EACCES;
		TALLOC_FREE(frame);
		return NULL;  /* SMBC_server sets errno */
	}

	/* Hmmm, the test for a directory is suspect here ... FIXME */

	if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') {
		status = NT_STATUS_OBJECT_PATH_INVALID;
	} else {
		file = SMB_MALLOC_P(SMBCFILE);
		if (!file) {
			errno = ENOMEM;
			TALLOC_FREE(frame);
			return NULL;
		}

		ZERO_STRUCTP(file);

		/*d_printf(">>>open: resolving %s\n", path);*/
		status = cli_resolve_path(
			frame, "", context->internal->auth_info,
			srv->cli, path, &targetcli, &targetpath);
		if (!NT_STATUS_IS_OK(status)) {
			d_printf("Could not resolve %s\n", path);
                        errno = ENOENT;
			SAFE_FREE(file);
			TALLOC_FREE(frame);
			return NULL;
		}
		/*d_printf(">>>open: resolved %s as %s\n", path, targetpath);*/

		status = cli_open(targetcli, targetpath, flags,
                                   context->internal->share_mode, &fd);
		if (!NT_STATUS_IS_OK(status)) {

			/* Handle the error ... */

			SAFE_FREE(file);
			errno = SMBC_errno(context, targetcli);
			TALLOC_FREE(frame);
			return NULL;
		}

		/* Fill in file struct */

		file->cli_fd  = fd;
		file->fname   = SMB_STRDUP(fname);
		file->srv     = srv;
		file->offset  = 0;
		file->file    = True;
		/*
		 * targetcli is either equal to srv->cli or
		 * is a subsidiary DFS connection. Either way
		 * file->cli_fd belongs to it so we must cache
		 * it for read/write/close, not re-resolve each time.
		 * Re-resolving is both slow and incorrect.
		 */
		file->targetcli = targetcli;

		DLIST_ADD(context->internal->files, file);

                /*
                 * If the file was opened in O_APPEND mode, all write
                 * operations should be appended to the file.  To do that,
                 * though, using this protocol, would require a getattrE()
                 * call for each and every write, to determine where the end
                 * of the file is. (There does not appear to be an append flag
                 * in the protocol.)  Rather than add all of that overhead of
                 * retrieving the current end-of-file offset prior to each
                 * write operation, we'll assume that most append operations
                 * will continuously write, so we'll just set the offset to
                 * the end of the file now and hope that's adequate.
                 *
                 * Note to self: If this proves inadequate, and O_APPEND
                 * should, in some cases, be forced for each write, add a
                 * field in the context options structure, for
                 * "strict_append_mode" which would select between the current
                 * behavior (if FALSE) or issuing a getattrE() prior to each
                 * write and forcing the write to the end of the file (if
                 * TRUE).  Adding that capability will likely require adding
                 * an "append" flag into the _SMBCFILE structure to track
                 * whether a file was opened in O_APPEND mode.  -- djl
                 */
                if (flags & O_APPEND) {
                        if (SMBC_lseek_ctx(context, file, 0, SEEK_END) < 0) {
                                (void) SMBC_close_ctx(context, file);
                                errno = ENXIO;
				TALLOC_FREE(frame);
                                return NULL;
                        }
                }

		TALLOC_FREE(frame);
		return file;
	}

	/* Check if opendir needed ... */

	if (!NT_STATUS_IS_OK(status)) {
		int eno = 0;

		eno = SMBC_errno(context, srv->cli);
		file = smbc_getFunctionOpendir(context)(context, fname);
		if (!file) errno = eno;
		TALLOC_FREE(frame);
		return file;
	}

	errno = EINVAL; /* FIXME, correct errno ? */
	TALLOC_FREE(frame);
	return NULL;
}
Пример #3
0
/*
 * Get info from an SMB server on a file. Use a qpathinfo call first
 * and if that fails, use getatr, as Win95 sometimes refuses qpathinfo
 */
bool
SMBC_getatr(SMBCCTX * context,
            SMBCSRV *srv,
            const char *path,
            uint16_t *mode,
            off_t *size,
            struct timespec *create_time_ts,
            struct timespec *access_time_ts,
            struct timespec *write_time_ts,
            struct timespec *change_time_ts,
            SMB_INO_T *ino)
{
	char *fixedpath = NULL;
	char *targetpath = NULL;
	struct cli_state *targetcli = NULL;
	time_t write_time;
	TALLOC_CTX *frame = talloc_stackframe();
	NTSTATUS status;

	if (!context || !context->internal->initialized) {
		errno = EINVAL;
		TALLOC_FREE(frame);
 		return False;
 	}

	/* path fixup for . and .. */
	if (strequal(path, ".") || strequal(path, "..")) {
		fixedpath = talloc_strdup(frame, "\\");
		if (!fixedpath) {
			errno = ENOMEM;
			TALLOC_FREE(frame);
			return False;
		}
	} else {
		fixedpath = talloc_strdup(frame, path);
		if (!fixedpath) {
			errno = ENOMEM;
			TALLOC_FREE(frame);
			return False;
		}
		trim_string(fixedpath, NULL, "\\..");
		trim_string(fixedpath, NULL, "\\.");
	}
	DEBUG(4,("SMBC_getatr: sending qpathinfo\n"));

	status = cli_resolve_path(frame, "", context->internal->auth_info,
				  srv->cli, fixedpath,
				  &targetcli, &targetpath);
	if (!NT_STATUS_IS_OK(status)) {
		d_printf("Couldn't resolve %s\n", path);
                errno = ENOENT;
		TALLOC_FREE(frame);
		return False;
	}

	if (!srv->no_pathinfo2 &&
            NT_STATUS_IS_OK(cli_qpathinfo2(targetcli, targetpath,
                           create_time_ts,
                           access_time_ts,
                           write_time_ts,
                           change_time_ts,
			   size, mode, ino))) {
		TALLOC_FREE(frame);
		return True;
        }

	srv->no_pathinfo2 = True;

	if (!srv->no_pathinfo3 &&
            NT_STATUS_IS_OK(cli_qpathinfo3(targetcli, targetpath,
                           create_time_ts,
                           access_time_ts,
                           write_time_ts,
                           change_time_ts,
			   size, mode, ino))) {
		TALLOC_FREE(frame);
		return True;
        }

	srv->no_pathinfo3 = True;

	/* if this is NT then don't bother with the getatr */
	if (smb1cli_conn_capabilities(targetcli->conn) & CAP_NT_SMBS) {
		goto all_failed;
        }

	if (NT_STATUS_IS_OK(cli_getatr(targetcli, targetpath, mode, size, &write_time))) {
                struct timespec w_time_ts;

                w_time_ts = convert_time_t_to_timespec(write_time);
                if (write_time_ts != NULL) {
			*write_time_ts = w_time_ts;
                }
                if (create_time_ts != NULL) {
                        *create_time_ts = w_time_ts;
                }
                if (access_time_ts != NULL) {
                        *access_time_ts = w_time_ts;
                }
                if (change_time_ts != NULL) {
                        *change_time_ts = w_time_ts;
                }
		if (ino) {
			*ino = 0;
		}
		TALLOC_FREE(frame);
		return True;
	}

all_failed:
	srv->no_pathinfo2 = False;
	srv->no_pathinfo3 = False;

        errno = EPERM;
	TALLOC_FREE(frame);
	return False;
}
Пример #4
0
int
SMBC_ftruncate_ctx(SMBCCTX *context,
                   SMBCFILE *file,
                   off_t length)
{
	off_t size = length;
	char *server = NULL;
	char *share = NULL;
	char *user = NULL;
	char *password = NULL;
	char *path = NULL;
        char *targetpath = NULL;
	struct cli_state *targetcli = NULL;
	TALLOC_CTX *frame = talloc_stackframe();
	NTSTATUS status;

	if (!context || !context->internal->initialized) {
		errno = EINVAL;
		TALLOC_FREE(frame);
		return -1;
	}

	if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
		errno = EBADF;
		TALLOC_FREE(frame);
		return -1;
	}

	if (!file->file) {
		errno = EINVAL;
		TALLOC_FREE(frame);
		return -1;
	}

	/*d_printf(">>>fstat: parsing %s\n", file->fname);*/
	if (SMBC_parse_path(frame,
                            context,
                            file->fname,
                            NULL,
                            &server,
                            &share,
                            &path,
                            &user,
                            &password,
                            NULL)) {
                errno = EINVAL;
		TALLOC_FREE(frame);
                return -1;
        }

	/*d_printf(">>>fstat: resolving %s\n", path);*/
	status = cli_resolve_path(frame, "", context->internal->auth_info,
				  file->srv->cli, path,
				  &targetcli, &targetpath);
	if (!NT_STATUS_IS_OK(status)) {
		d_printf("Could not resolve %s\n", path);
                errno = ENOENT;
		TALLOC_FREE(frame);
		return -1;
	}
	/*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/

        if (!NT_STATUS_IS_OK(cli_ftruncate(targetcli, file->cli_fd, (uint64_t)size))) {
                errno = EINVAL;
                TALLOC_FREE(frame);
                return -1;
        }

	TALLOC_FREE(frame);
	return 0;
}
Пример #5
0
int
SMBC_fstat_ctx(SMBCCTX *context,
               SMBCFILE *file,
               struct stat *st)
{
	struct timespec change_time_ts;
        struct timespec access_time_ts;
        struct timespec write_time_ts;
	SMB_OFF_T size;
	uint16 mode;
	char *server = NULL;
	char *share = NULL;
	char *user = NULL;
	char *password = NULL;
	char *path = NULL;
        char *targetpath = NULL;
	struct cli_state *targetcli = NULL;
	SMB_INO_T ino = 0;
	TALLOC_CTX *frame = talloc_stackframe();
	NTSTATUS status;

	if (!context || !context->internal->initialized) {
		errno = EINVAL;
		TALLOC_FREE(frame);
		return -1;
	}

	if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
		errno = EBADF;
		TALLOC_FREE(frame);
		return -1;
	}

	if (!file->file) {
		TALLOC_FREE(frame);
		return smbc_getFunctionFstatdir(context)(context, file, st);
	}

	/*d_printf(">>>fstat: parsing %s\n", file->fname);*/
	if (SMBC_parse_path(frame,
                            context,
                            file->fname,
                            NULL,
                            &server,
                            &share,
                            &path,
                            &user,
                            &password,
                            NULL)) {
                errno = EINVAL;
		TALLOC_FREE(frame);
                return -1;
        }

	/*d_printf(">>>fstat: resolving %s\n", path);*/
	status = cli_resolve_path(frame, "", context->internal->auth_info,
				  file->srv->cli, path,
				  &targetcli, &targetpath);
	if (!NT_STATUS_IS_OK(status)) {
		d_printf("Could not resolve %s\n", path);
                errno = ENOENT;
		TALLOC_FREE(frame);
		return -1;
	}
	/*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/

	if (!NT_STATUS_IS_OK(cli_qfileinfo_basic(
				     targetcli, file->cli_fd, &mode, &size,
				     NULL,
				     &access_time_ts,
				     &write_time_ts,
				     &change_time_ts,
				     &ino))) {
		time_t change_time, access_time, write_time;

		if (!NT_STATUS_IS_OK(cli_getattrE(targetcli, file->cli_fd, &mode, &size,
                                  &change_time, &access_time, &write_time))) {
			errno = EINVAL;
			TALLOC_FREE(frame);
			return -1;
		}
		change_time_ts = convert_time_t_to_timespec(change_time);
		access_time_ts = convert_time_t_to_timespec(access_time);
		write_time_ts = convert_time_t_to_timespec(write_time);
	}

	st->st_ino = ino;

	setup_stat(context, st, file->fname, size, mode);

	st->st_atime = convert_timespec_to_time_t(access_time_ts);
	st->st_ctime = convert_timespec_to_time_t(change_time_ts);
	st->st_mtime = convert_timespec_to_time_t(write_time_ts);
	st->st_dev = file->srv->dev;

	TALLOC_FREE(frame);
	return 0;
}
Пример #6
0
int
SMBC_close_ctx(SMBCCTX *context,
               SMBCFILE *file)
{
        SMBCSRV *srv;
	char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
	char *path = NULL;
	char *targetpath = NULL;
	struct cli_state *targetcli = NULL;
	TALLOC_CTX *frame = talloc_stackframe();
	NTSTATUS status;

	if (!context || !context->internal->initialized) {
		errno = EINVAL;
		TALLOC_FREE(frame);
		return -1;
	}

	if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
		errno = EBADF;
		TALLOC_FREE(frame);
		return -1;
	}

	/* IS a dir ... */
	if (!file->file) {
		TALLOC_FREE(frame);
		return smbc_getFunctionClosedir(context)(context, file);
	}

	/*d_printf(">>>close: parsing %s\n", file->fname);*/
	if (SMBC_parse_path(frame,
                            context,
                            file->fname,
                            NULL,
                            &server,
                            &share,
                            &path,
                            &user,
                            &password,
                            NULL)) {
                errno = EINVAL;
		TALLOC_FREE(frame);
                return -1;
        }

	/*d_printf(">>>close: resolving %s\n", path);*/
	status = cli_resolve_path(frame, "", context->internal->auth_info,
				  file->srv->cli, path,
				  &targetcli, &targetpath);
	if (!NT_STATUS_IS_OK(status)) {
		d_printf("Could not resolve %s\n", path);
                errno = ENOENT;
		TALLOC_FREE(frame);
		return -1;
	}
	/*d_printf(">>>close: resolved path as %s\n", targetpath);*/

	if (!NT_STATUS_IS_OK(cli_close(targetcli, file->cli_fd))) {
		DEBUG(3, ("cli_close failed on %s. purging server.\n", 
			  file->fname));
		/* Deallocate slot and remove the server 
		 * from the server cache if unused */
		errno = SMBC_errno(context, targetcli);
		srv = file->srv;
		DLIST_REMOVE(context->internal->files, file);
		SAFE_FREE(file->fname);
		SAFE_FREE(file);
		smbc_getFunctionRemoveUnusedServer(context)(context, srv);
		TALLOC_FREE(frame);
		return -1;
	}

	DLIST_REMOVE(context->internal->files, file);
	SAFE_FREE(file->fname);
	SAFE_FREE(file);
	TALLOC_FREE(frame);
	return 0;
}
Пример #7
0
off_t
SMBC_lseek_ctx(SMBCCTX *context,
               SMBCFILE *file,
               off_t offset,
               int whence)
{
	off_t size;
	char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
	char *path = NULL;
	char *targetpath = NULL;
	struct cli_state *targetcli = NULL;
	TALLOC_CTX *frame = talloc_stackframe();
	NTSTATUS status;

	if (!context || !context->internal->initialized) {
		errno = EINVAL;
		TALLOC_FREE(frame);
		return -1;
	}

	if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
		errno = EBADF;
		TALLOC_FREE(frame);
		return -1;
	}

	if (!file->file) {
		errno = EINVAL;
		TALLOC_FREE(frame);
		return -1;      /* Can't lseek a dir ... */
	}

	switch (whence) {
	case SEEK_SET:
		file->offset = offset;
		break;
	case SEEK_CUR:
		file->offset += offset;
		break;
	case SEEK_END:
		/*d_printf(">>>lseek: parsing %s\n", file->fname);*/
		if (SMBC_parse_path(frame,
                                    context,
                                    file->fname,
                                    NULL,
                                    &server,
                                    &share,
                                    &path,
                                    &user,
                                    &password,
                                    NULL)) {
			errno = EINVAL;
			TALLOC_FREE(frame);
			return -1;
		}

		/*d_printf(">>>lseek: resolving %s\n", path);*/
		status = cli_resolve_path(
			frame, "", context->internal->auth_info,
			file->srv->cli, path, &targetcli, &targetpath);
		if (!NT_STATUS_IS_OK(status)) {
			d_printf("Could not resolve %s\n", path);
                        errno = ENOENT;
			TALLOC_FREE(frame);
			return -1;
		}

		/*d_printf(">>>lseek: resolved path as %s\n", targetpath);*/
		if (!NT_STATUS_IS_OK(cli_qfileinfo_basic(
					     targetcli, file->cli_fd, NULL,
					     &size, NULL, NULL, NULL, NULL,
					     NULL))) {
                        off_t b_size = size;
			if (!NT_STATUS_IS_OK(cli_getattrE(targetcli, file->cli_fd,
                                          NULL, &b_size, NULL, NULL, NULL))) {
                                errno = EINVAL;
                                TALLOC_FREE(frame);
                                return -1;
                        } else
                                size = b_size;
		}
		file->offset = size + offset;
		break;
	default:
		errno = EINVAL;
		break;
	}

	TALLOC_FREE(frame);
	return file->offset;
}
Пример #8
0
ssize_t
SMBC_write_ctx(SMBCCTX *context,
               SMBCFILE *file,
               const void *buf,
               size_t count)
{
        off_t offset;
	char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
	char *path = NULL;
	char *targetpath = NULL;
	struct cli_state *targetcli = NULL;
	TALLOC_CTX *frame = talloc_stackframe();
	NTSTATUS status;

	/* First check all pointers before dereferencing them */

	if (!context || !context->internal->initialized) {
		errno = EINVAL;
		TALLOC_FREE(frame);
		return -1;
	}

	if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
		errno = EBADF;
		TALLOC_FREE(frame);
		return -1;
	}

	/* Check that the buffer exists ... */

	if (buf == NULL) {
		errno = EINVAL;
		TALLOC_FREE(frame);
		return -1;
	}

        offset = file->offset; /* See "offset" comment in SMBC_read_ctx() */

	/*d_printf(">>>write: parsing %s\n", file->fname);*/
	if (SMBC_parse_path(frame,
                            context,
                            file->fname,
                            NULL,
                            &server,
                            &share,
                            &path,
                            &user,
                            &password,
                            NULL)) {
                errno = EINVAL;
		TALLOC_FREE(frame);
                return -1;
        }

	/*d_printf(">>>write: resolving %s\n", path);*/
	status = cli_resolve_path(frame, "", context->internal->auth_info,
				  file->srv->cli, path,
				  &targetcli, &targetpath);
	if (!NT_STATUS_IS_OK(status)) {
		d_printf("Could not resolve %s\n", path);
                errno = ENOENT;
		TALLOC_FREE(frame);
		return -1;
	}
	/*d_printf(">>>write: resolved path as %s\n", targetpath);*/

	status = cli_writeall(targetcli, file->cli_fd,
			      0, (const uint8_t *)buf, offset, count, NULL);
	if (!NT_STATUS_IS_OK(status)) {
		errno = map_errno_from_nt_status(status);
		TALLOC_FREE(frame);
		return -1;
	}

	file->offset += count;

	TALLOC_FREE(frame);
	return count;  /* Success, 0 bytes of data ... */
}
Пример #9
0
ssize_t
SMBC_read_ctx(SMBCCTX *context,
              SMBCFILE *file,
              void *buf,
              size_t count)
{
	size_t ret;
	char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
	char *path = NULL;
	char *targetpath = NULL;
	struct cli_state *targetcli = NULL;
	TALLOC_CTX *frame = talloc_stackframe();
	NTSTATUS status;

        /*
         * offset:
         *
         * Compiler bug (possibly) -- gcc (GCC) 3.3.5 (Debian 1:3.3.5-2) --
         * appears to pass file->offset (which is type off_t) differently than
         * a local variable of type off_t.  Using local variable "offset" in
         * the call to cli_read() instead of file->offset fixes a problem
         * retrieving data at an offset greater than 4GB.
         */
        off_t offset;

	if (!context || !context->internal->initialized) {
		errno = EINVAL;
		TALLOC_FREE(frame);
		return -1;
	}

	DEBUG(4, ("smbc_read(%p, %d)\n", file, (int)count));

	if (!file || !SMBC_dlist_contains(context->internal->files, file)) {
		errno = EBADF;
		TALLOC_FREE(frame);
		return -1;
	}

	offset = file->offset;

	/* Check that the buffer exists ... */

	if (buf == NULL) {
		errno = EINVAL;
		TALLOC_FREE(frame);
		return -1;
	}

	/*d_printf(">>>read: parsing %s\n", file->fname);*/
	if (SMBC_parse_path(frame,
                            context,
                            file->fname,
                            NULL,
                            &server,
                            &share,
                            &path,
                            &user,
                            &password,
                            NULL)) {
                errno = EINVAL;
		TALLOC_FREE(frame);
                return -1;
        }

	/*d_printf(">>>read: resolving %s\n", path);*/
	status = cli_resolve_path(frame, "", context->internal->auth_info,
				  file->srv->cli, path,
				  &targetcli, &targetpath);
	if (!NT_STATUS_IS_OK(status)) {
		d_printf("Could not resolve %s\n", path);
                errno = ENOENT;
		TALLOC_FREE(frame);
		return -1;
	}
	/*d_printf(">>>fstat: resolved path as %s\n", targetpath);*/

	status = cli_read(targetcli, file->cli_fd, (char *)buf, offset,
			  count, &ret);
	if (!NT_STATUS_IS_OK(status)) {
		errno = SMBC_errno(context, targetcli);
		TALLOC_FREE(frame);
		return -1;
	}

	file->offset += ret;

	DEBUG(4, ("  --> %ld\n", (unsigned long)ret));

	TALLOC_FREE(frame);
	return ret;  /* Success, ret bytes of data ... */
}
Пример #10
0
NTSTATUS cli_resolve_path(TALLOC_CTX *ctx,
			  const char *mountpt,
			  const struct user_auth_info *dfs_auth_info,
			  struct cli_state *rootcli,
			  const char *path,
			  struct cli_state **targetcli,
			  char **pp_targetpath)
{
	struct client_dfs_referral *refs = NULL;
	size_t num_refs = 0;
	size_t consumed = 0;
	struct cli_state *cli_ipc = NULL;
	char *dfs_path = NULL;
	char *cleanpath = NULL;
	char *extrapath = NULL;
	int pathlen;
	char *server = NULL;
	char *share = NULL;
	struct cli_state *newcli = NULL;
	char *newpath = NULL;
	char *newmount = NULL;
	char *ppath = NULL;
	SMB_STRUCT_STAT sbuf;
	uint32 attributes;
	NTSTATUS status;

	if ( !rootcli || !path || !targetcli ) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	/* Don't do anything if this is not a DFS root. */

	if ( !rootcli->dfsroot) {
		*targetcli = rootcli;
		*pp_targetpath = talloc_strdup(ctx, path);
		if (!*pp_targetpath) {
			return NT_STATUS_NO_MEMORY;
		}
		return NT_STATUS_OK;
	}

	*targetcli = NULL;

	/* Send a trans2_query_path_info to check for a referral. */

	cleanpath = clean_path(ctx, path);
	if (!cleanpath) {
		return NT_STATUS_NO_MEMORY;
	}

	dfs_path = cli_dfs_make_full_path(ctx, rootcli, cleanpath);
	if (!dfs_path) {
		return NT_STATUS_NO_MEMORY;
	}

	status = cli_qpathinfo_basic( rootcli, dfs_path, &sbuf, &attributes);
	if (NT_STATUS_IS_OK(status)) {
		/* This is an ordinary path, just return it. */
		*targetcli = rootcli;
		*pp_targetpath = talloc_strdup(ctx, path);
		if (!*pp_targetpath) {
			return NT_STATUS_NO_MEMORY;
		}
		goto done;
	}

	/* Special case where client asked for a path that does not exist */

	if (cli_dfs_check_error(rootcli, NT_STATUS_OBJECT_NAME_NOT_FOUND,
				status)) {
		*targetcli = rootcli;
		*pp_targetpath = talloc_strdup(ctx, path);
		if (!*pp_targetpath) {
			return NT_STATUS_NO_MEMORY;
		}
		goto done;
	}

	/* We got an error, check for DFS referral. */

	if (!cli_dfs_check_error(rootcli, NT_STATUS_PATH_NOT_COVERED,
				 status)) {
		return status;
	}

	/* Check for the referral. */

	status = cli_cm_open(ctx,
			     rootcli,
			     cli_state_remote_name(rootcli),
			     "IPC$",
			     dfs_auth_info,
			     false,
			     cli_state_encryption_on(rootcli),
			     cli_state_protocol(rootcli),
			     0,
			     0x20,
			     &cli_ipc);
	if (!NT_STATUS_IS_OK(status)) {
		return status;
	}

	status = cli_dfs_get_referral(ctx, cli_ipc, dfs_path, &refs,
				      &num_refs, &consumed);
	if (!NT_STATUS_IS_OK(status) || !num_refs) {
		return status;
	}

	/* Just store the first referral for now. */

	if (!refs[0].dfspath) {
		return NT_STATUS_NOT_FOUND;
	}
	if (!split_dfs_path(ctx, refs[0].dfspath, &server, &share,
			    &extrapath)) {
		return NT_STATUS_NOT_FOUND;
	}

	/* Make sure to recreate the original string including any wildcards. */

	dfs_path = cli_dfs_make_full_path(ctx, rootcli, path);
	if (!dfs_path) {
		return NT_STATUS_NO_MEMORY;
	}
	pathlen = strlen(dfs_path);
	consumed = MIN(pathlen, consumed);
	*pp_targetpath = talloc_strdup(ctx, &dfs_path[consumed]);
	if (!*pp_targetpath) {
		return NT_STATUS_NO_MEMORY;
	}
	dfs_path[consumed] = '\0';

	/*
 	 * *pp_targetpath is now the unconsumed part of the path.
 	 * dfs_path is now the consumed part of the path
	 * (in \server\share\path format).
 	 */

	/* Open the connection to the target server & share */
	status = cli_cm_open(ctx, rootcli,
			     server,
			     share,
			     dfs_auth_info,
			     false,
			     cli_state_encryption_on(rootcli),
			     cli_state_protocol(rootcli),
			     0,
			     0x20,
			     targetcli);
	if (!NT_STATUS_IS_OK(status)) {
		d_printf("Unable to follow dfs referral [\\%s\\%s]\n",
			server, share );
		return status;
	}

	if (extrapath && strlen(extrapath) > 0) {
		/* EMC Celerra NAS version 5.6.50 (at least) doesn't appear to */
		/* put the trailing \ on the path, so to be save we put one in if needed */
		if (extrapath[strlen(extrapath)-1] != '\\' && **pp_targetpath != '\\') {
			*pp_targetpath = talloc_asprintf(ctx,
						  "%s\\%s",
						  extrapath,
						  *pp_targetpath);
		} else {
			*pp_targetpath = talloc_asprintf(ctx,
						  "%s%s",
						  extrapath,
						  *pp_targetpath);
		}
		if (!*pp_targetpath) {
			return NT_STATUS_NO_MEMORY;
		}
	}

	/* parse out the consumed mount path */
	/* trim off the \server\share\ */

	ppath = dfs_path;

	if (*ppath != '\\') {
		d_printf("cli_resolve_path: "
			"dfs_path (%s) not in correct format.\n",
			dfs_path );
		return NT_STATUS_NOT_FOUND;
	}

	ppath++; /* Now pointing at start of server name. */

	if ((ppath = strchr_m( dfs_path, '\\' )) == NULL) {
		return NT_STATUS_NOT_FOUND;
	}

	ppath++; /* Now pointing at start of share name. */

	if ((ppath = strchr_m( ppath+1, '\\' )) == NULL) {
		return NT_STATUS_NOT_FOUND;
	}

	ppath++; /* Now pointing at path component. */

	newmount = talloc_asprintf(ctx, "%s\\%s", mountpt, ppath );
	if (!newmount) {
		return NT_STATUS_NOT_FOUND;
	}

	cli_set_mntpoint(*targetcli, newmount);

	/* Check for another dfs referral, note that we are not
	   checking for loops here. */

	if (!strequal(*pp_targetpath, "\\") && !strequal(*pp_targetpath, "/")) {
		status = cli_resolve_path(ctx,
					  newmount,
					  dfs_auth_info,
					  *targetcli,
					  *pp_targetpath,
					  &newcli,
					  &newpath);
		if (NT_STATUS_IS_OK(status)) {
			/*
			 * When cli_resolve_path returns true here it's always
 			 * returning the complete path in newpath, so we're done
 			 * here.
 			 */
			*targetcli = newcli;
			*pp_targetpath = newpath;
			return status;
		}
	}

  done:

	/* If returning true ensure we return a dfs root full path. */
	if ((*targetcli)->dfsroot) {
		dfs_path = talloc_strdup(ctx, *pp_targetpath);
		if (!dfs_path) {
			return NT_STATUS_NO_MEMORY;
		}
		*pp_targetpath = cli_dfs_make_full_path(ctx, *targetcli, dfs_path);
		if (*pp_targetpath == NULL) {
			return NT_STATUS_NO_MEMORY;
		}
	}

	return NT_STATUS_OK;
}
Пример #11
0
off_t
SMBC_splice_ctx(SMBCCTX *context,
                SMBCFILE *srcfile,
                SMBCFILE *dstfile,
                off_t count,
                int (*splice_cb)(off_t n, void *priv),
                void *priv)
{
	off_t written;
	char *server = NULL, *share = NULL, *user = NULL, *password = NULL;
	char *path = NULL;
	char *targetpath = NULL;
	struct cli_state *srccli = NULL;
	struct cli_state *dstcli = NULL;
	uint16_t port = 0;
	TALLOC_CTX *frame = talloc_stackframe();
	NTSTATUS status;

	if (!context || !context->internal->initialized) {
		errno = EINVAL;
		TALLOC_FREE(frame);
		return -1;
	}

	if (!srcfile ||
	    !SMBC_dlist_contains(context->internal->files, srcfile))
	{
		errno = EBADF;
		TALLOC_FREE(frame);
		return -1;
	}

	if (!dstfile ||
	    !SMBC_dlist_contains(context->internal->files, dstfile))
	{
		errno = EBADF;
		TALLOC_FREE(frame);
		return -1;
	}

	if (SMBC_parse_path(frame,
                            context,
                            srcfile->fname,
                            NULL,
                            &server,
                            &port,
                            &share,
                            &path,
                            &user,
                            &password,
                            NULL)) {
                errno = EINVAL;
		TALLOC_FREE(frame);
                return -1;
        }

	status = cli_resolve_path(frame, "", context->internal->auth_info,
				  srcfile->srv->cli, path,
				  &srccli, &targetpath);
	if (!NT_STATUS_IS_OK(status)) {
		d_printf("Could not resolve %s\n", path);
                errno = ENOENT;
		TALLOC_FREE(frame);
		return -1;
	}

	if (SMBC_parse_path(frame,
                            context,
                            dstfile->fname,
                            NULL,
                            &server,
                            &port,
                            &share,
                            &path,
                            &user,
                            &password,
                            NULL)) {
                errno = EINVAL;
		TALLOC_FREE(frame);
                return -1;
        }

	status = cli_resolve_path(frame, "", context->internal->auth_info,
				  dstfile->srv->cli, path,
				  &dstcli, &targetpath);
	if (!NT_STATUS_IS_OK(status)) {
		d_printf("Could not resolve %s\n", path);
                errno = ENOENT;
		TALLOC_FREE(frame);
		return -1;
	}

	status = cli_splice(srccli, dstcli,
			    srcfile->cli_fd, dstfile->cli_fd,
			    count, srcfile->offset, dstfile->offset, &written,
			    splice_cb, priv);
	if (!NT_STATUS_IS_OK(status)) {
		errno = SMBC_errno(context, srccli);
		TALLOC_FREE(frame);
		return -1;
	}

	srcfile->offset += written;
	dstfile->offset += written;

	TALLOC_FREE(frame);
	return written;
}
Пример #12
0
BOOL cli_resolve_path( const char *mountpt, struct cli_state *rootcli, const char *path,
                       struct cli_state **targetcli, pstring targetpath )
{
	CLIENT_DFS_REFERRAL *refs = NULL;
	size_t num_refs;
	uint16 consumed;
	struct cli_state *cli_ipc;
	pstring fullpath, cleanpath;
	int pathlen;
	fstring server, share;
	struct cli_state *newcli;
	pstring newpath;
	pstring newmount;
	char *ppath;
	
	SMB_STRUCT_STAT sbuf;
	uint32 attributes;
	
	*targetcli = NULL;
	
	if ( !rootcli || !path || !targetcli )
		return False;
		
	/* send a trans2_query_path_info to check for a referral */
	
	clean_path( cleanpath, 	path );
	make_full_path( fullpath, rootcli->desthost, rootcli->share, cleanpath );

	/* don't bother continuing if this is not a dfs root */
	
	if ( !rootcli->dfsroot || cli_qpathinfo_basic( rootcli, cleanpath, &sbuf, &attributes ) ) {
		*targetcli = rootcli;
		pstrcpy( targetpath, path );
		return True;
	}

	/* we got an error, check for DFS referral */
			
	if ( !cli_dfs_check_error(rootcli) ) 
		return False;

	/* check for the referral */

	if ( !(cli_ipc = cli_cm_open( rootcli->desthost, "IPC$", False )) )
		return False;
	
	if ( !cli_dfs_get_referral(cli_ipc, fullpath, &refs, &num_refs, &consumed) 
		|| !num_refs )
	{
		return False;
	}
	
	/* just store the first referral for now
	   Make sure to recreate the original string including any wildcards */
	
	make_full_path( fullpath, rootcli->desthost, rootcli->share, path );
	pathlen = strlen( fullpath )*2;
	consumed = MIN(pathlen, consumed );
	pstrcpy( targetpath, &fullpath[consumed/2] );

	split_dfs_path( refs[0].dfspath, server, share );
	SAFE_FREE( refs );
	
	/* open the connection to the target path */
	
	if ( (*targetcli = cli_cm_open(server, share, False)) == NULL ) {
		d_printf("Unable to follow dfs referral [//%s/%s]\n",
			server, share );
			
		return False;
	}
	
	/* parse out the consumed mount path */
	/* trim off the \server\share\ */

	fullpath[consumed/2] = '\0';
	dos_clean_name( fullpath );
	ppath = strchr_m( fullpath, '\\' );
	ppath = strchr_m( ppath+1, '\\' );
	ppath = strchr_m( ppath+1, '\\' );
	ppath++;
	
	pstr_sprintf( newmount, "%s\\%s", mountpt, ppath );
	cli_cm_set_mntpoint( *targetcli, newmount );

	/* check for another dfs referral, note that we are not 
	   checking for loops here */

	if ( !strequal( targetpath, "\\" ) ) {
		if ( cli_resolve_path( newmount, *targetcli, targetpath, &newcli, newpath ) ) {
			*targetcli = newcli;
			pstrcpy( targetpath, newpath );
		}
	}

	return True;
}