예제 #1
0
/* Implements the remote pioctl(2) call */
afs_int32
SRMTSYS_Pioctl(struct rx_call *call, clientcred *creds, char *path,
	       afs_int32 cmd, afs_int32 follow, rmtbulk *InData,
	       rmtbulk *OutData, afs_int32 *errornumber)
{
    afs_int32 error;
    struct ViceIoctl data;
    char *pathp = path;
    afs_uint32 blob[PIOCTL_HEADER];

    *errornumber = 0;
    SETCLIENTCONTEXT(blob, rx_HostOf(call->conn->peer), creds->uid,
		     creds->group0, creds->group1, cmd, NFS_EXPORTER);
    data.in =
	(char *)malloc(InData->rmtbulk_len +
		       PIOCTL_HEADER * sizeof(afs_int32));
    if (!data.in)
	return (-1);		/* helpless here */
    if (!strcmp(path, NIL_PATHP))
	pathp = (char *)0;	/* It meant to be NIL */
    memcpy(data.in, blob, sizeof(blob));
    inparam_conversion(cmd, InData->rmtbulk_val, 1);
    memcpy(data.in + sizeof(blob), InData->rmtbulk_val, InData->rmtbulk_len);
    data.in_size = InData->rmtbulk_len + PIOCTL_HEADER * sizeof(afs_int32);
    data.out = OutData->rmtbulk_val;
    data.out_size = OutData->rmtbulk_len;
    /* force local pioctl call */
    error = lpioctl(pathp, _VICEIOCTL(PSetClientContext), &data, follow);
    if (error) {
	*errornumber = errno;
    } else {
	/* Send the results back in network order */
	outparam_conversion(cmd, data.out, 0);
    }
    free(data.in);
    /* Note that we return success (i.e. 0) even when pioctl fails; that's
     * because the actual errno is passed back via 'errornumber' and this call
     * MUST return success error in order to get that OUT params back (YUCK!)
     */
    return (0);
}
예제 #2
0
/* called with the GLOCK held */
int
afs_syscall_pioctl(char *path, unsigned int com, caddr_t cmarg, int follow)
{
    cred_t *credp = crref();	/* don't free until done! */
    struct afs_ioctl data;
    struct clientcred ccred;
    struct rmtbulk idata, odata;
    short in_size, out_size;
    afs_int32 code = 0, pag, err;
    gid_t g0, g1;
    char *abspath, *pathbuf = 0;

    AFS_STATCNT(afs_syscall_pioctl);
    if (follow)
	follow = 1;		/* compat. with old venus */
    code = copyin_afs_ioctl(cmarg, &data);
    if (code) goto out;

    if ((com & 0xff) == 90) {
	/* PSetClientContext, in any space */
	code = EINVAL;
	goto out;
    }

    /* Special handling for a few pioctls */
    switch (com & 0xffff) {
	case (0x5600 |  3): /* VIOCSETTOK */
	    code = afspag_PSetTokens(data.in, data.in_size, &credp);
	    if (code) goto out;
	    break;

	case (0x5600 |  9): /* VIOCUNLOG */
	case (0x5600 | 21): /* VIOCUNPAG */
	    code = afspag_PUnlog(data.in, data.in_size, &credp);
	    if (code) goto out;
	    break;

	case (0x5600 | 38): /* VIOC_AFS_SYSNAME */
	    code = afspag_PSetSysName(data.in, data.in_size, &credp);
	    if (code) goto out;
	    break;
    }

    /* Set up credentials */
    memset(&ccred, 0, sizeof(ccred));
    pag = PagInCred(credp);
    ccred.uid = afs_cr_uid(credp);
    if (pag != NOPAG) {
	 afs_get_groups_from_pag(pag, &g0, &g1);
	 ccred.group0 = g0;
	 ccred.group1 = g1;
    }

    /*
     * Copy the path and convert to absolute, if one was given.
     * NB: We can only use osI_AllocLargeSpace here as long as
     * RMTSYS_MAXPATHLEN is less than AFS_LRALLOCSIZ.
     */
    if (path) {
	pathbuf = osi_AllocLargeSpace(RMTSYS_MAXPATHLEN);
	if (!pathbuf) {
	    code = ENOMEM;
	    goto out;
	}
	code = osi_abspath(path, pathbuf, RMTSYS_MAXPATHLEN, 0, &abspath);
	if (code)
	    goto out_path;
    } else {
	abspath = NIL_PATHP;
    }

    /* Allocate, copy, and convert incoming data */
    idata.rmtbulk_len = in_size = data.in_size;
    if (in_size  < 0 || in_size  > MAXBUFFERLEN) {
	code = EINVAL;
	goto out_path;
    }
    if (in_size > AFS_LRALLOCSIZ)
	 idata.rmtbulk_val = osi_Alloc(in_size);
    else
	 idata.rmtbulk_val = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
    if (!idata.rmtbulk_val) {
	code = ENOMEM;
	goto out_path;
    }
    if (in_size) {
	AFS_COPYIN(data.in, idata.rmtbulk_val, in_size, code);
	if (code)
	    goto out_idata;
	inparam_conversion(com, idata.rmtbulk_val, in_size, 0);
    }

    /* Allocate space for outgoing data */
    odata.rmtbulk_len = out_size = data.out_size;
    if (out_size < 0 || out_size > MAXBUFFERLEN) {
	code = EINVAL;
	goto out_idata;
    }
    if (out_size > AFS_LRALLOCSIZ)
	 odata.rmtbulk_val = osi_Alloc(out_size);
    else
	 odata.rmtbulk_val = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
    if (!odata.rmtbulk_val) {
	code = ENOMEM;
	goto out_idata;
    }

    AFS_GUNLOCK();
    code = RMTSYS_Pioctl(rmtsys_conn, &ccred, abspath, com, follow,
			 &idata, &odata, &err);
    AFS_GLOCK();
    if (code)
	goto out_odata;

    /* Convert and copy out the result */
    if (odata.rmtbulk_len > out_size) {
	code = E2BIG;
	goto out_odata;
    }
    if (odata.rmtbulk_len) {
	outparam_conversion(com, odata.rmtbulk_val, odata.rmtbulk_len, 1);
	AFS_COPYOUT(odata.rmtbulk_val, data.out, odata.rmtbulk_len, code);
    }
    if (!code)
	code = err;

out_odata:
    if (out_size > AFS_LRALLOCSIZ)
	osi_Free(odata.rmtbulk_val, out_size);
    else
	osi_FreeLargeSpace(odata.rmtbulk_val);

out_idata:
    if (in_size > AFS_LRALLOCSIZ)
	osi_Free(idata.rmtbulk_val, in_size);
    else
	osi_FreeLargeSpace(idata.rmtbulk_val);

out_path:
    if (path)
	osi_FreeLargeSpace(pathbuf);

out:
    crfree(credp);
#if defined(KERNEL_HAVE_UERROR)
    if (!getuerror())
	setuerror(code);
    return (getuerror());
#else
    return (code);
#endif
}