예제 #1
0
static int
smb_usr_vc2spec(struct smbioc_ossn *dp, struct smb_vcspec *spec)
{
	int flags = 0;

	bzero(spec, sizeof(*spec));

#ifdef NETSMB_NO_ANON_USER
	if (dp->ioc_user[0] == 0)
		return EINVAL;
#endif

	if (dp->ioc_server == NULL)
		return EINVAL;
	if (dp->ioc_localcs[0] == 0) {
		SMBERROR("no local charset ?\n");
		return EINVAL;
	}

	spec->sap = smb_memdupin(dp->ioc_server, dp->ioc_svlen);
	if (spec->sap == NULL)
		return ENOMEM;
	if (dp->ioc_local) {
		spec->lap = smb_memdupin(dp->ioc_local, dp->ioc_lolen);
		if (spec->lap == NULL) {
			smb_usr_vcspec_free(spec);
			return ENOMEM;
		}
	}
	spec->srvname = dp->ioc_srvname;
	spec->pass = dp->ioc_password;
	spec->domain = dp->ioc_workgroup;
	spec->username = dp->ioc_user;
	spec->mode = dp->ioc_mode;
	spec->rights = dp->ioc_rights;
	spec->owner = dp->ioc_owner;
	spec->group = dp->ioc_group;
	spec->localcs = dp->ioc_localcs;
	spec->servercs = dp->ioc_servercs;
	if (dp->ioc_opt & SMBVOPT_PRIVATE)
		flags |= SMBV_PRIVATE;
	if (dp->ioc_opt & SMBVOPT_SINGLESHARE)
		flags |= SMBV_PRIVATE | SMBV_SINGLESHARE;
	spec->flags = flags;
	return 0;
}
예제 #2
0
파일: smb_usr_2.c 프로젝트: aosm/smb
/*
 * Called from user land so we always have a reference on the share.
 */
int
smb_usr_query_dir(struct smb_share *share,
                  struct smb2ioc_query_dir *query_dir_ioc,
                  vfs_context_t context)
{
	int error;
 	struct smb2_query_dir_rq *queryp = NULL;

    SMB_MALLOC(queryp,
               struct smb2_query_dir_rq *,
               sizeof(struct smb2_query_dir_rq),
               M_SMBTEMP,
               M_WAITOK | M_ZERO);
    if (queryp == NULL) {
		SMBERROR("SMB_MALLOC failed\n");
        error = ENOMEM;
        goto bad;
    }
    
    /* Take 32 bit world pointers and convert them to user_addr_t. */
    if (query_dir_ioc->ioc_rcv_output_len > 0) {
        if (vfs_context_is64bit(context)) {
            queryp->rcv_output_uio = uio_create(1, 0, UIO_USERSPACE64, UIO_READ);
        }
        else {
            query_dir_ioc->ioc_kern_rcv_output =
            CAST_USER_ADDR_T(query_dir_ioc->ioc_rcv_output);
            queryp->rcv_output_uio = uio_create(1, 0, UIO_USERSPACE32, UIO_READ);
        }
        
        if (queryp->rcv_output_uio) {
            uio_addiov(queryp->rcv_output_uio,
                       query_dir_ioc->ioc_kern_rcv_output,
                       query_dir_ioc->ioc_rcv_output_len);
        }
        else {
            SMBERROR("uio_create failed\n");
            error = ENOMEM;
            goto bad;
        }
    }

	/* Take the 32 bit world pointers and convert them to user_addr_t. */
	if (!vfs_context_is64bit (context)) {
		query_dir_ioc->ioc_kern_name = CAST_USER_ADDR_T(query_dir_ioc->ioc_name);
	}
	
	/* ioc_name_len includes the null byte, ioc_kern_name is a c-style string */
	if (query_dir_ioc->ioc_kern_name && query_dir_ioc->ioc_name_len) {
        queryp->name_len = query_dir_ioc->ioc_name_len;
		queryp->namep = smb_memdupin(query_dir_ioc->ioc_kern_name,
                                      query_dir_ioc->ioc_name_len);
		if (queryp->namep == NULL) {
            SMBERROR("smb_memdupin failed\n");
			error = ENOMEM;
			goto bad;
		}
	}
    
	queryp->file_info_class = query_dir_ioc->ioc_file_info_class;
	queryp->flags = query_dir_ioc->ioc_flags;
	queryp->file_index = query_dir_ioc->ioc_file_index;
	queryp->output_buffer_len = query_dir_ioc->ioc_rcv_output_len;
	queryp->fid = query_dir_ioc->ioc_fid;
	queryp->name_len = query_dir_ioc->ioc_name_len;
	queryp->name_flags = query_dir_ioc->ioc_name_flags;
    /* 
     * Never used for user ioctl query dir. User must have already opened
     * the dir to be searched.
     */
	queryp->dnp = NULL; 
    
    /* 
     * Since this is from user space, there is no mounted file system, so 
     * there are no vnodes and thus no queryp->dnp. This means that namep 
     * must be non NULL.
     *
     * If ioc_rcv_output_len is not 0, then copy results directly to user 
     * buffer and let them parse it.
     */
    if ((queryp->namep == NULL) || (queryp->name_len == 0)) {
        SMBERROR("missing name \n");
        error = EINVAL;
        goto bad;
    }
    
	/* Now do the real work */
	error = smb2_smb_query_dir(share, queryp, NULL, context);
    
    /* always return the ntstatus error */
    query_dir_ioc->ioc_ret_ntstatus = queryp->ret_ntstatus;
	if (error) {
		goto bad;
	}
    
    /* Fill in amount of data returned in Query Dir reply */
    query_dir_ioc->ioc_ret_output_len = queryp->ret_buffer_len;
    
    /* Fill in actual amount of data returned */
    query_dir_ioc->ioc_rcv_output_len = queryp->output_buffer_len;
    
bad:
    if (queryp != NULL) {
        if (queryp->ret_rqp != NULL) {
            smb_rq_done(queryp->ret_rqp);
        }
        if (queryp->namep)
            SMB_FREE(queryp->namep, M_SMBSTR);
        if (queryp->rcv_output_uio != NULL) {
            uio_free(queryp->rcv_output_uio);
        }
        SMB_FREE(queryp, M_SMBTEMP);
    }
    
	return error;
}
예제 #3
0
파일: smb_usr_2.c 프로젝트: aosm/smb
int
smb_usr_get_dfs_referral(struct smb_share *share, struct smb_vc *vcp,
                         struct smb2ioc_get_dfs_referral *get_dfs_refer_ioc,
                         vfs_context_t context)
{
	int error;
 	struct smb2_ioctl_rq *ioctlp = NULL;
 	struct smb2_get_dfs_referral dfs_referral;
    char *local_pathp = NULL;
    uint32_t local_path_len = get_dfs_refer_ioc->ioc_file_name_len;
	size_t network_path_len = PATH_MAX + 1;
	char *network_pathp = NULL;
    
    SMB_MALLOC(ioctlp,
               struct smb2_ioctl_rq *, 
               sizeof(struct smb2_ioctl_rq), 
               M_SMBTEMP, 
               M_WAITOK | M_ZERO);
    if (ioctlp == NULL) {
		SMBERROR("SMB_MALLOC failed\n");
        error = ENOMEM;
        goto bad;
    }

again:
	/* Take the 32 bit world pointers and convert them to user_addr_t. */
    bzero(&dfs_referral, sizeof(dfs_referral));

    dfs_referral.file_namep = NULL;
    dfs_referral.max_referral_level = get_dfs_refer_ioc->ioc_max_referral_level;
    
	if (!vfs_context_is64bit (context)) {
		get_dfs_refer_ioc->ioc_kern_file_name = CAST_USER_ADDR_T(get_dfs_refer_ioc->ioc_file_name);
	}
	
    if (!(get_dfs_refer_ioc->ioc_kern_file_name)) {
        error = EINVAL;
        goto bad;
    }

	/* ioc_file_name_len includes the null byte, ioc_kern_file_name is a c-style string */
	if (get_dfs_refer_ioc->ioc_kern_file_name && get_dfs_refer_ioc->ioc_file_name_len) {
		local_pathp = smb_memdupin(get_dfs_refer_ioc->ioc_kern_file_name,
                                   local_path_len);
	}

    if (local_pathp == NULL) {
        SMBERROR("smb_memdupin failed\n");
        error = ENOMEM;
        goto bad;
    }

    /*
     * Need to convert from local path to a network path 
     */
	SMB_MALLOC(network_pathp, char *, network_path_len, M_TEMP, M_WAITOK | M_ZERO);
	if (network_pathp == NULL) {
		error = ENOMEM;
		goto bad;		
	}
    
	error = smb_convert_path_to_network(local_pathp, local_path_len,
                                        network_pathp, &network_path_len,
										'\\', SMB_UTF_SFM_CONVERSIONS,
                                        SMB_UNICODE_STRINGS(vcp));
	if (error) {
		SMBERROR("smb_convert_path_to_network failed : %d\n", error);
		goto bad;
	}

    dfs_referral.file_namep = network_pathp;
    dfs_referral.file_name_len = (uint32_t) network_path_len;
    
    /* Take 32 bit world pointers and convert them to user_addr_t. */
    if (get_dfs_refer_ioc->ioc_rcv_output_len > 0) {
        if (vfs_context_is64bit(context)) {
            ioctlp->rcv_output_uio = uio_create(1, 0, UIO_USERSPACE64, UIO_READ);
        }
        else {
            get_dfs_refer_ioc->ioc_kern_rcv_output = CAST_USER_ADDR_T(get_dfs_refer_ioc->ioc_rcv_output);
            ioctlp->rcv_output_uio = uio_create(1, 0, UIO_USERSPACE32, UIO_READ);
        }
        
        if (ioctlp->rcv_output_uio) {
            uio_addiov(ioctlp->rcv_output_uio,
                       get_dfs_refer_ioc->ioc_kern_rcv_output, 
                       get_dfs_refer_ioc->ioc_rcv_output_len);
        } 
        else {
            error = ENOMEM;
            SMBERROR("uio_create failed\n");
            goto bad;
        }
    }

    ioctlp->share = share;
    ioctlp->ctl_code = FSCTL_DFS_GET_REFERRALS;
    ioctlp->fid = -1;
    
	ioctlp->snd_input_buffer = (uint8_t *) &dfs_referral;
	ioctlp->snd_input_len = sizeof(struct smb2_get_dfs_referral);
	ioctlp->snd_output_len = 0;
    
	ioctlp->rcv_input_len = 0;
    
    /* Handle servers that dislike large output buffer lengths */
    if (vcp->vc_misc_flags & SMBV_63K_IOCTL) {
        ioctlp->rcv_output_len = kSMB_63K;
    }
    else {
        ioctlp->rcv_output_len = get_dfs_refer_ioc->ioc_rcv_output_len;
    }

    /* Now do the real work */
	error = smb2_smb_ioctl(share, ioctlp, NULL, context);
    
    if ((error) &&
        (ioctlp->ret_ntstatus == STATUS_INVALID_PARAMETER) &&
        !(vcp->vc_misc_flags & SMBV_63K_IOCTL)) {
        /*
         * <14281932> Could this be a server that can not handle
         * larger than 65535 bytes in an IOCTL? 
         */
        SMBWARNING("SMB 2/3 server cant handle large OutputBufferLength in DFS Referral. Reducing to 63Kb.\n");
        vcp->vc_misc_flags |= SMBV_63K_IOCTL;
        
        ioctlp->ret_ntstatus = 0;
        
        if (ioctlp->snd_input_uio != NULL) {
            uio_free(ioctlp->snd_input_uio);
            ioctlp->snd_input_uio = NULL;
        }
        if (ioctlp->snd_output_uio != NULL) {
            uio_free(ioctlp->snd_output_uio);
            ioctlp->snd_output_uio = NULL;
        }
        if (ioctlp->rcv_input_uio != NULL) {
            uio_free(ioctlp->rcv_input_uio);
            ioctlp->rcv_input_uio = NULL;
        }
        if (ioctlp->rcv_output_uio != NULL) {
            uio_free(ioctlp->rcv_output_uio);
            ioctlp->rcv_output_uio = NULL;
        }

        goto again;
    }    
    
    /* always return the ntstatus error */
    get_dfs_refer_ioc->ioc_ret_ntstatus = ioctlp->ret_ntstatus;
	if (error) {
		goto bad;
	}
    
    /* Fill in actual bytes returned */
    get_dfs_refer_ioc->ioc_ret_output_len = ioctlp->ret_output_len;
    
bad:    
    if (ioctlp != NULL) {
        if (ioctlp->snd_input_uio != NULL) {
            uio_free(ioctlp->snd_input_uio);
        }
        if (ioctlp->snd_output_uio != NULL) {
            uio_free(ioctlp->snd_output_uio);
        }
        if (ioctlp->rcv_input_uio != NULL) {
            uio_free(ioctlp->rcv_input_uio);
        }
        if (ioctlp->rcv_output_uio != NULL) {
            uio_free(ioctlp->rcv_output_uio);
        }
        SMB_FREE(ioctlp, M_SMBTEMP);
    }
    
    if (local_pathp) {
        SMB_FREE(local_pathp, M_SMBSTR);
    }
    
    if (network_pathp) {
        SMB_FREE(network_pathp, M_SMBSTR);
    }

    return error;
}
예제 #4
0
파일: smb_usr_2.c 프로젝트: aosm/smb
/*
 * Called from user land so we always have a reference on the share.
 */
int 
smb_usr_check_dir(struct smb_share *share, struct smb_vc *vcp,
                  struct smb2ioc_check_dir *check_dir_ioc,
                  vfs_context_t context)
{
	int error;
    char *local_pathp = NULL;
    uint32_t local_path_len = check_dir_ioc->ioc_path_len;
    uint32_t desired_access = SMB2_FILE_READ_ATTRIBUTES | SMB2_SYNCHRONIZE;
    uint32_t share_access = NTCREATEX_SHARE_ACCESS_ALL;
    /* Tell create, the namep is a path to an item */
    uint64_t create_flags = SMB2_CREATE_NAME_IS_PATH;
    struct smbfattr *fap = NULL;
	size_t network_path_len = PATH_MAX + 1;
	char *network_pathp = NULL;
    
    /* Assume no error */
    check_dir_ioc->ioc_ret_ntstatus = 0;
        
    /* 
     * Compound Create/Close call should be sufficient. 
     * If item exists, verify it is a dir.
     */
    
	/* Take the 32 bit world pointers and convert them to user_addr_t. */
	if (!vfs_context_is64bit(context)) {
		check_dir_ioc->ioc_kern_path = CAST_USER_ADDR_T(check_dir_ioc->ioc_path);
	}
	
    if (!(check_dir_ioc->ioc_kern_path)) {
        error = EINVAL;
        goto bad;
    }

    /* local_path_len includes the null byte, ioc_kern_path is a c-style string */
	if (check_dir_ioc->ioc_kern_path && local_path_len) {
		local_pathp = smb_memdupin(check_dir_ioc->ioc_kern_path,
                                   local_path_len);
	}

    if (local_pathp == NULL) {
        SMBERROR("smb_memdupin failed\n");
        error = ENOMEM;
        goto bad;
    }

    /*
     * Need to convert from local path to a network path 
     */
	SMB_MALLOC(network_pathp, char *, network_path_len, M_TEMP, M_WAITOK | M_ZERO);
	if (network_pathp == NULL) {
		error = ENOMEM;
		goto bad;		
	}

	error = smb_convert_path_to_network(local_pathp, local_path_len,
                                        network_pathp, &network_path_len,
										'\\', SMB_UTF_SFM_CONVERSIONS,
                                        SMB_UNICODE_STRINGS(vcp));
	if (error) {
		SMBERROR("smb_convert_path_to_network failed : %d\n", error);
		goto bad;
	}
    
    /* 
     * Set up for Compound Create/Close call 
     */
    SMB_MALLOC(fap,
               struct smbfattr *, 
               sizeof(struct smbfattr), 
               M_SMBTEMP, 
               M_WAITOK | M_ZERO);
    if (fap == NULL) {
        SMBERROR("SMB_MALLOC failed\n");
        error = ENOMEM;
        goto bad;
    }

    /* Send a Create/Close */
    error = smb2fs_smb_cmpd_create(share, NULL,
                                   network_pathp, network_path_len,
                                   NULL, 0,
                                   desired_access, VDIR,
                                   share_access, FILE_OPEN,
                                   create_flags, &check_dir_ioc->ioc_ret_ntstatus,
                                   NULL, fap,
                                   NULL, context);
	if (error) {
		goto bad;
	}
    
    /* found something, verify its a dir */
    if (!(fap->fa_attr & SMB_EFA_DIRECTORY)) {
        error = ENOTDIR;
        check_dir_ioc->ioc_ret_ntstatus = STATUS_NOT_A_DIRECTORY;
    }

bad:    
    if (local_pathp) {
        SMB_FREE(local_pathp, M_SMBSTR);
    }
    
    if (network_pathp) {
        SMB_FREE(network_pathp, M_SMBSTR);
    }

    if (fap) {
        SMB_FREE(fap, M_SMBTEMP);
    }

	return error;
}
예제 #5
0
파일: smb_usr_2.c 프로젝트: aosm/smb
/*
 * Called from user land so we always have a reference on the share.
 */
int 
smb_usr_create(struct smb_share *share, struct smb2ioc_create *create_ioc,
               vfs_context_t context)
{
	int error;
 	struct smb2_create_rq *createp = NULL;
    
    SMB_MALLOC(createp, 
               struct smb2_create_rq *, 
               sizeof(struct smb2_create_rq), 
               M_SMBTEMP, 
               M_WAITOK | M_ZERO);
    if (createp == NULL) {
		SMBERROR("SMB_MALLOC failed\n");
        error = ENOMEM;
        goto bad;
    }
    
	/* Take the 32 bit world pointers and convert them to user_addr_t. */
	if (!vfs_context_is64bit (context)) {
		create_ioc->ioc_kern_name = CAST_USER_ADDR_T(create_ioc->ioc_name);
	}
	
	/* ioc_name_len includes the null byte, ioc_kern_name is a c-style string */
	if (create_ioc->ioc_kern_name && create_ioc->ioc_name_len) {
        createp->name_len = create_ioc->ioc_name_len;
		createp->namep = smb_memdupin(create_ioc->ioc_kern_name, 
                                   create_ioc->ioc_name_len);
		if (createp->namep == NULL) {
            SMBERROR("smb_memdupin failed\n");
			error = ENOMEM;
			goto bad;
		}
	}
    
    createp->flags = SMB2_CREATE_GET_MAX_ACCESS;
    createp->oplock_level = create_ioc->ioc_oplock_level;
    createp->impersonate_level = create_ioc->ioc_impersonate_level;
    createp->desired_access = create_ioc->ioc_desired_access;
    createp->file_attributes = create_ioc->ioc_file_attributes;
    createp->share_access = create_ioc->ioc_share_access;
    createp->disposition = create_ioc->ioc_disposition;
    createp->create_options = create_ioc->ioc_create_options;
    createp->dnp = NULL;
    
	/* Now do the real work */
	error = smb2_smb_create(share, createp, NULL, context);
    
    /* always return the ntstatus error */
    create_ioc->ioc_ret_ntstatus = createp->ret_ntstatus;
	if (error) {
		goto bad;
	}
    
    /* Fill in return parameters */
    create_ioc->ioc_ret_attributes = createp->ret_attributes;
    create_ioc->ioc_ret_oplock_level = createp->ret_oplock_level;
    create_ioc->ioc_ret_create_action = createp->ret_create_action;
    create_ioc->ioc_ret_create_time = createp->ret_create_time;
    create_ioc->ioc_ret_access_time = createp->ret_access_time;
    create_ioc->ioc_ret_write_time = createp->ret_write_time;
    create_ioc->ioc_ret_change_time = createp->ret_change_time;
    create_ioc->ioc_ret_alloc_size = createp->ret_alloc_size;
    create_ioc->ioc_ret_eof = createp->ret_eof;
    create_ioc->ioc_ret_fid = createp->ret_fid;
    create_ioc->ioc_ret_max_access = createp->ret_max_access;
    
bad:    
    if (createp != NULL) {
        if (createp->namep)
            SMB_FREE(createp->namep, M_SMBSTR);
        SMB_FREE(createp, M_SMBTEMP);
    }
    
	return error;
}