smbd_mlsvc_doorsvc.c revision 3ad684d66b78e06edd37e2c4fd3b3949f095194b
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster/*
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * CDDL HEADER START
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * The contents of this file are subject to the terms of the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Common Development and Distribution License (the "License").
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * You may not use this file except in compliance with the License.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * or http://www.opensolaris.org/os/licensing.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * See the License for the specific language governing permissions
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * and limitations under the License.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * When distributing Covered Code, include this CDDL HEADER in each
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * If applicable, add the following below this CDDL HEADER, with the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * fields enclosed by brackets "[]" replaced with your own identifying
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * information: Portions Copyright [yyyy] [name of copyright owner]
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * CDDL HEADER END
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster/*
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Use is subject to license terms.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#pragma ident "%Z%%M% %I% %E% SMI"
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <stdio.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <strings.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <stdlib.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <unistd.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <fcntl.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <sys/types.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <sys/stat.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <door.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <errno.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <syslog.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <pthread.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <smbsrv/libsmb.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <smbsrv/mlsvc.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <smbsrv/mlsvc_util.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#include <smbsrv/smb_winpipe.h>
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster#define START_OUTDOOR_SIZE 65536
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterstatic int smb_winpipe_fd = -1;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterstatic int smb_winpipe_cookie = 0x50495045; /* PIPE */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterstatic pthread_mutex_t smb_winpipe_mutex = PTHREAD_MUTEX_INITIALIZER;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterstatic void smb_winpipe_request(void *, char *, size_t, door_desc_t *, uint_t);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster/*
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Create the winpipe door service.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Returns the door descriptor on success. Otherwise returns -1.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterint
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fostersmb_winpipe_doorsvc_start(void)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster{
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster (void) pthread_mutex_lock(&smb_winpipe_mutex);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (smb_winpipe_fd != -1) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster (void) pthread_mutex_unlock(&smb_winpipe_mutex);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster errno = EEXIST;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return (-1);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster errno = 0;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if ((smb_winpipe_fd = door_create(smb_winpipe_request,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster &smb_winpipe_cookie, (DOOR_UNREF | DOOR_REFUSE_DESC))) < 0) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster smb_winpipe_fd = -1;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster (void) pthread_mutex_unlock(&smb_winpipe_mutex);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return (smb_winpipe_fd);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster/*
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Stop the winpipe door service.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fostervoid
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fostersmb_winpipe_doorsvc_stop(void)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster{
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster (void) pthread_mutex_lock(&smb_winpipe_mutex);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (smb_winpipe_fd != -1) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster (void) door_revoke(smb_winpipe_fd);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster smb_winpipe_fd = -1;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster (void) pthread_mutex_unlock(&smb_winpipe_mutex);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterstatic smb_dr_user_ctx_t *
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fostersmb_user_ctx_mkabsolute(uint8_t *buf, uint32_t len)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster{
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster smb_dr_user_ctx_t *obj;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster XDR xdrs;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster xdrmem_create(&xdrs, (const caddr_t)buf, len, XDR_DECODE);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster obj = (smb_dr_user_ctx_t *)malloc(sizeof (smb_dr_user_ctx_t));
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (!obj) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster xdr_destroy(&xdrs);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster syslog(LOG_ERR, "smb_user_ctx_mkabsolute: resource shortage");
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return (NULL);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster bzero(obj, sizeof (smb_dr_user_ctx_t));
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (!xdr_smb_dr_user_ctx_t(&xdrs, obj)) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster syslog(LOG_ERR, "smb_user_ctx_mkabsolute: XDR decode error");
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster free(obj);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster obj = NULL;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster xdr_destroy(&xdrs);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return (obj);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterstatic void
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fostersmb_user_ctx_free(smb_dr_user_ctx_t *user_ctx)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster{
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (user_ctx) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster xdr_free(xdr_smb_dr_user_ctx_t, (char *)user_ctx);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster free(user_ctx);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster/*
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Winpipe door service request handler.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Door arg data is a previously marshalled in to flat buffer
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * that contains no pointers. This data is first unmarshalled into
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * common structures. The data from the door *argp contains a header structure,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * mlsvc_door_hdr_t. Following are its members.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * thread_id - kernel thread id
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * version number - possible use at a leter point
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * call_type - rpc_transact, rpc_read or rpc_write
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * length - max number of bytes that can be returned
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * rpc_ctx - some rpc context info such as domain, user account, ...
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * smb_pipe_t - pipeid, pipename, pipelen and data
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Convert the data and call mlrpc_process. The returned outpipe contains
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * the relevant data to be returned to the client.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster *
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster * Outgoing data must be marshalled again before returning.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster/*ARGSUSED*/
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterstatic void
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fostersmb_winpipe_request(void *cookie, char *argp, size_t arg_size,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster door_desc_t *dd, uint_t n_desc)
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster{
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster smb_pipe_t *inpipe = NULL;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster smb_pipe_t *outpipe = NULL;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster smb_pipe_t tmp_pipe;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster smb_dr_user_ctx_t *user_ctx = NULL;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster char *bufp;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster int bplen = 0;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster mlsvc_door_hdr_t mdhin, mdhout;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster int tbytes = 0;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster int bytes_off = 0;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster struct mlsvc_rpc_context *context;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster int current_out_len;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster uint32_t adj_len;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster char lfp[START_OUTDOOR_SIZE];
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster boolean_t more_data = B_FALSE;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if ((cookie != &smb_winpipe_cookie) || (argp == NULL) ||
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster (arg_size < SMB_WINPIPE_MIN_REQ_SIZE)) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster (void) door_return(NULL, 0, NULL, 0);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
bufp = argp;
bcopy(bufp, &mdhin.md_tid, sizeof (uint64_t));
bytes_off = sizeof (uint64_t);
bcopy(bufp+bytes_off, &mdhin.md_version, sizeof (uint16_t));
bytes_off += sizeof (uint16_t);
bcopy(bufp+bytes_off, &mdhin.md_call_type, sizeof (uint16_t));
bytes_off += sizeof (uint16_t);
bcopy(bufp+bytes_off, &mdhin.md_length, sizeof (uint32_t));
bytes_off += sizeof (uint32_t);
bcopy(bufp+bytes_off, &mdhin.md_reserved, sizeof (uint64_t));
bytes_off += sizeof (uint64_t);
/*
* Flush is a special case, just release the RPC context.
*/
if (mdhin.md_call_type == SMB_RPC_FLUSH) {
bcopy(bufp + bytes_off, &tmp_pipe.sp_pipeid, sizeof (uint32_t));
mlrpc_release(tmp_pipe.sp_pipeid);
goto zero_exit;
}
user_ctx = smb_user_ctx_mkabsolute((uchar_t *)bufp + bytes_off,
arg_size - bytes_off);
if (!user_ctx) {
syslog(LOG_ERR, "mds: user_ctx_mkabsolute failed");
goto zero_exit;
}
tbytes += xdr_sizeof(xdr_smb_dr_user_ctx_t, user_ctx) + bytes_off;
bufp += tbytes;
bzero(&tmp_pipe, sizeof (smb_pipe_t));
(void) strlcpy(tmp_pipe.sp_pipename, (char *)bufp, SMB_MAX_PIPENAMELEN);
bufp += SMB_MAX_PIPENAMELEN;
bcopy(bufp, &tmp_pipe.sp_pipeid, sizeof (uint32_t));
bufp += sizeof (uint32_t);
bcopy(bufp, &tmp_pipe.sp_datalen, sizeof (uint32_t));
bufp += sizeof (uint32_t);
if ((context = mlrpc_lookup(tmp_pipe.sp_pipeid)) == NULL)
goto zero_exit;
inpipe = context->inpipe;
(void) strcpy(inpipe->sp_pipename, tmp_pipe.sp_pipename);
outpipe = context->outpipe;
(void) strcpy(outpipe->sp_pipename, "OUTPIPE");
adj_len = mdhin.md_length;
/*
* If RPC_TRANSACT, save len, set cookie to 0 and store
* outpipe pointer into rpc_context. This will be used later
* by RPC_READ. See if we have pending writes.
* Clear the in context if we do.
*/
if ((mdhin.md_call_type == SMB_RPC_READ) && (context->inlen)) {
context = mlrpc_process(inpipe->sp_pipeid, user_ctx);
if (context == NULL)
goto zero_exit;
inpipe->sp_datalen = context->inlen;
context->inlen = 0;
context->outcookie = 0;
context->outlen = outpipe->sp_datalen;
}
if (mdhin.md_call_type == SMB_RPC_TRANSACT) {
/*
* Append trans data to the pipe
*/
if ((tmp_pipe.sp_datalen +
context->inlen) > SMB_CTXT_PIPE_SZ) {
context->inlen = 0;
goto zero_exit;
}
bcopy(bufp, inpipe->sp_data + context->inlen,
tmp_pipe.sp_datalen);
inpipe->sp_datalen += tmp_pipe.sp_datalen;
context = mlrpc_process(inpipe->sp_pipeid, user_ctx);
if (context == NULL)
goto zero_exit;
context->outcookie = 0;
context->outlen = outpipe->sp_datalen;
context->inlen = 0;
if (outpipe->sp_datalen < mdhin.md_length)
adj_len = outpipe->sp_datalen;
if (outpipe->sp_datalen > mdhin.md_length)
more_data = B_TRUE;
}
outpipe->sp_more_data = (uint32_t)more_data;
if (mdhin.md_call_type == SMB_RPC_WRITE) {
/*
* Append write data to the pipe
*/
if ((tmp_pipe.sp_datalen +
context->inlen) > SMB_CTXT_PIPE_SZ) {
context->inlen = 0;
goto zero_exit;
}
bcopy(bufp, inpipe->sp_data + context->inlen,
tmp_pipe.sp_datalen);
inpipe->sp_datalen += tmp_pipe.sp_datalen;
context->inlen += tmp_pipe.sp_datalen;
goto zero_exit;
}
/*
* check if this is the first transfer
* pipe and cookie management
*/
if (context->outcookie > 0) {
if (context->outcookie >= context->outlen) {
goto zero_exit;
} else {
bufp = outpipe->sp_data + context->outcookie;
if (adj_len < (context->outlen - context->outcookie)) {
context->outcookie += adj_len;
current_out_len = adj_len;
} else {
current_out_len = context->outlen -
context->outcookie;
context->outcookie = 0;
}
}
} else {
bufp = outpipe->sp_data;
if (adj_len < context->outlen) {
context->outcookie += adj_len;
current_out_len = adj_len;
} else {
current_out_len = context->outlen;
context->outcookie = 0;
}
}
mdhout = mdhin;
mdhout.md_tid = (uint64_t)getpid(); /* user process pid */
bytes_off = 0;
bcopy(&mdhout.md_tid, lfp, sizeof (uint64_t));
bytes_off = sizeof (uint64_t);
bcopy(&mdhout.md_version, lfp + bytes_off, sizeof (uint16_t));
bytes_off += sizeof (uint16_t);
bcopy(&mdhout.md_call_type, lfp + bytes_off, sizeof (uint16_t));
bytes_off += sizeof (uint16_t);
bcopy(&adj_len, lfp + bytes_off, sizeof (uint32_t));
bytes_off += sizeof (uint32_t);
bcopy(&mdhout.md_reserved, lfp + bytes_off, sizeof (uint64_t));
bytes_off += sizeof (uint64_t);
tbytes = bytes_off;
bcopy(outpipe->sp_pipename, lfp + tbytes, SMB_MAX_PIPENAMELEN);
bplen = SMB_MAX_PIPENAMELEN;
bcopy(&(outpipe->sp_pipeid), lfp + tbytes + bplen, sizeof (uint32_t));
bplen += sizeof (uint32_t);
bcopy(&(current_out_len), lfp + tbytes + bplen, sizeof (uint32_t));
bplen += sizeof (uint32_t);
bcopy(&(outpipe->sp_more_data), lfp + tbytes + bplen,
sizeof (uint32_t));
bplen += sizeof (uint32_t);
bcopy(bufp, lfp + tbytes + bplen, current_out_len);
tbytes += bplen + current_out_len;
smb_user_ctx_free(user_ctx);
(void) door_return((char *)lfp, tbytes, NULL, 0);
/*NOTREACHED*/
zero_exit:
smb_user_ctx_free(user_ctx);
(void) door_return(NULL, 0, NULL, 0);
}