OpenSolaris_b135/lib/smbsrv/libsmb/common/smb_door_encdec.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <stdlib.h>
#include <strings.h>
#include <rpc/xdr.h>
#include <errno.h>
#include <smbsrv/libsmb.h>
#include <smbsrv/smb_xdr.h>
#include <smbsrv/smb_common_door.h>
#include <smbsrv/smb_door_svc.h>

/*
 * smb_dr_decode_common
 *
 * This function can be used to decode both door request and result buffer.
 * pre-condition: data is non-null pointer, and is bzero'd.
 */
int
smb_dr_decode_common(char *buf, size_t len, xdrproc_t proc, void *data)
{
	XDR xdrs;
	int rc = 0;

	if (!data)
		return (-1);

	xdrmem_create(&xdrs, buf, len, XDR_DECODE);
	if (!proc(&xdrs, data))
		rc = -1;

	xdr_destroy(&xdrs);
	return (rc);
}

/*
 * smb_dr_encode_common
 *
 * This function can be used to encode both request and result door buffer.
 * The 'opcode' paramater is set to the 'opcode' of the operation to be invoked
 * on the server, by the client. The server sets the same 'opcode' paramater
 * to indicate the 'status' of the door call.
 *
 * This function will first encode integer value 'opcode' (opcode/status),
 * followed by the data (which will be encoded via the specified XDR routine).
 *
 * Returns encoded buffer upon success. Otherwise, returns NULL.
 */
char *
smb_dr_encode_common(uint_t opcode, void *data, xdrproc_t proc, size_t *len)
{
	XDR xdrs;
	char *buf;

	if (proc && !data) {
		syslog(LOG_ERR, "smb_dr_encode_common: invalid param");
		*len = 0;
		return (NULL);
	}

	*len = xdr_sizeof(xdr_uint32_t, &opcode);
	if (proc)
		*len += xdr_sizeof(proc, data);
	buf = (char *)malloc(*len);
	if (!buf) {
		syslog(LOG_ERR, "smb_dr_encode_common: resource shortage");
		*len = 0;
		return (NULL);
	}
	xdrmem_create(&xdrs, buf, *len, XDR_ENCODE);
	if (!xdr_uint32_t(&xdrs, &opcode)) {
		syslog(LOG_DEBUG, "smb_dr_encode_common: encode error 1");
		free(buf);
		*len = 0;
		xdr_destroy(&xdrs);
		return (NULL);
	}

	if (proc && !proc(&xdrs, data)) {
		syslog(LOG_DEBUG, "smb_dr_encode_common: encode error 2");
		free(buf);
		buf = NULL;
		*len = 0;
	}

	xdr_destroy(&xdrs);
	return (buf);
}

/*
 * Get the opcode of the door argument buffer.
 */
int
smb_dr_get_opcode(char *argp, size_t arg_size)
{
	int opcode;

	if (smb_dr_decode_common(argp, arg_size, xdr_uint32_t, &opcode) != 0)
		opcode = -1;
	return (opcode);
}

/*
 * Set the opcode of the door argument buffer.
 */
char *
smb_dr_set_opcode(uint32_t opcode, size_t *len)
{
	char *buf;

	buf = smb_dr_encode_common(opcode, NULL, NULL, len);
	return (buf);
}

/*
 * Get the status of the door result buffer.
 */
int
smb_dr_get_res_stat(char *rbufp, size_t rbuf_size)
{
	int status;

	if (smb_dr_decode_common(rbufp, rbuf_size, xdr_uint32_t, &status) != 0)
		status = -1;

	return (status);
}

/*
 * Set the status of the door result buffer.
 */
char *
smb_dr_set_res_stat(uint32_t stat, size_t *len)
{
	char *buf;

	buf = smb_dr_encode_common(stat, NULL, NULL, len);
	return (buf);
}

char *
smb_dr_encode_res_token(smb_token_t *token, size_t *len)
{
	smb_dr_bytes_t res;
	char *buf = NULL;

	res.bytes_val = smb_token_mkselfrel(token, &res.bytes_len);
	if (!res.bytes_val) {
		syslog(LOG_ERR, "smb_dr_encode_res_token: mkselfrel error");
		*len = 0;
		return (NULL);
	}

	if ((buf = smb_dr_encode_common(SMB_DR_OP_SUCCESS, &res,
	    xdr_smb_dr_bytes_t, len)) == NULL) {
		syslog(LOG_ERR, "smb_dr_encode_res_token: failed");
		*len = 0;
		free(res.bytes_val);
		return (NULL);

	}
	free(res.bytes_val);
	return (buf);
}

/*
 * smb_kshare_mkselfrel
 *
 * encode: structure -> flat buffer (buffer size)
 * Pre-condition: kshare is non-null.
 */

uint8_t *
smb_kshare_mkselfrel(smb_dr_kshare_t *kshare, uint32_t *len)
{
	uint8_t *buf;
	XDR xdrs;

	if (!kshare)
		return (NULL);

	*len = xdr_sizeof(xdr_smb_dr_kshare_t, kshare);
	buf = (uint8_t *)malloc(*len);
	if (!buf)
		return (NULL);

	xdrmem_create(&xdrs, (const caddr_t)buf, *len, XDR_ENCODE);

	if (!xdr_smb_dr_kshare_t(&xdrs, kshare)) {
		*len = 0;
		free(buf);
		buf = NULL;
	}

	xdr_destroy(&xdrs);
	return (buf);
}

char *
smb_dr_encode_string(uint32_t opcode, char *str, size_t *len)
{
	char *buf;
	smb_dr_string_t res;

	res.buf = str;

	if ((buf = smb_dr_encode_common(opcode, &res,
	    xdr_smb_dr_string_t, len)) == NULL)
		syslog(LOG_ERR, "smb_dr_encode_string: failed");
	return (buf);
}

char *
smb_dr_decode_string(char *buf, size_t len)
{
	smb_dr_string_t res;
	char *str = NULL;

	bzero(&res, sizeof (smb_dr_string_t));
	if (smb_dr_decode_common(buf, len, xdr_smb_dr_string_t,
	    &res) == 0) {
		str = res.buf;
	} else {
		syslog(LOG_ERR, "smb_dr_decode_string: failed");
	}
	return (str);
}

netr_client_t *
smb_dr_decode_arg_get_token(char *buf, size_t len)
{
	smb_dr_bytes_t arg;
	netr_client_t *clnt_info;

	bzero(&arg, sizeof (smb_dr_bytes_t));
	if (smb_dr_decode_common(buf, len, xdr_smb_dr_bytes_t, &arg)
	    != 0) {
		syslog(LOG_ERR, "smb_dr_decode_arg_get_token: failed");
		xdr_free(xdr_smb_dr_bytes_t, (char *)&arg);
		return (NULL);
	}
	clnt_info = netr_client_mkabsolute(arg.bytes_val,
	    arg.bytes_len);
	xdr_free(xdr_smb_dr_bytes_t, (char *)&arg);
	return (clnt_info);
}

/*
 * Encode an lsa_account_t into a buffer.
 */
int
lsa_account_encode(lsa_account_t *acct, uint8_t *buf, uint32_t buflen)
{
	XDR xdrs;
	int rc = 0;

	xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_ENCODE);

	if (!lsa_account_xdr(&xdrs, acct))
		rc = -1;

	xdr_destroy(&xdrs);
	return (rc);
}

/*
 * Decode an XDR buffer into an lsa_account_t.
 */
int
lsa_account_decode(lsa_account_t *acct, uint8_t *buf, uint32_t buflen)
{
	XDR xdrs;
	int rc = 0;

	xdrmem_create(&xdrs, (const caddr_t)buf, buflen, XDR_DECODE);

	bzero(acct, sizeof (lsa_account_t));
	if (!lsa_account_xdr(&xdrs, acct))
		rc = -1;

	xdr_destroy(&xdrs);
	return (rc);
}

bool_t
lsa_account_xdr(XDR *xdrs, lsa_account_t *objp)
{
	if (!xdr_uint16_t(xdrs, &objp->a_sidtype))
		return (FALSE);
	if (!xdr_uint32_t(xdrs, &objp->a_status))
		return (FALSE);
	if (!xdr_vector(xdrs, (char *)objp->a_domain, MAXNAMELEN,
	    sizeof (char), (xdrproc_t)xdr_char))
		return (FALSE);
	if (!xdr_vector(xdrs, (char *)objp->a_name, MAXNAMELEN,
	    sizeof (char), (xdrproc_t)xdr_char))
		return (FALSE);
	if (!xdr_vector(xdrs, (char *)objp->a_sid, SMB_SID_STRSZ,
	    sizeof (char), (xdrproc_t)xdr_char))
		return (FALSE);
	return (TRUE);
}