1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
24  */
25 
26 #include <sys/list.h>
27 #include <assert.h>
28 #include <alloca.h>
29 #include <door.h>
30 #include <errno.h>
31 #include <syslog.h>
32 #include <unistd.h>
33 #include <stdio.h>
34 #include <synch.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
39 #include <pthread.h>
40 #include <strings.h>
41 #include <umem.h>
42 
43 #include <smbsrv/smb_door.h>
44 #include <smbsrv/smb_xdr.h>
45 #include <smbsrv/smb_token.h>
46 #include <smbsrv/libmlsvc.h>
47 #include <smbsrv/libsmbns.h>
48 #include "smbd.h"
49 
50 
51 /*
52  * Special version of smb_door_dispatch() for the
53  * "fake" smbsrv (running in user space).
54  *
55  * This is called via function pointer from
56  * smbsrv: smb_kdoor_upcall()
57  *
58  * The args and response go RPC encoded, just so we can
59  * borrow some of the common doorsvc code, even though
60  * there's no need for RPC encoding in this scenario.
61  */
62 int
fksmbd_door_dispatch(smb_doorarg_t * da)63 fksmbd_door_dispatch(smb_doorarg_t *da)
64 {
65 
66 	smbd_arg_t	dop_arg;
67 	smb_doorhdr_t	*hdr;
68 	char		*rbuf = NULL;
69 	char		*argp = da->da_arg.data_ptr;
70 	size_t		arg_size = da->da_arg.data_size;
71 	size_t		hdr_size, rsize;
72 
73 	/*
74 	 * Decode
75 	 *
76 	 * da->da_arg.data_ptr  = (arg data, xdr encoded)
77 	 * da->da_arg.data_size = (arg data len)
78 	 */
79 
80 	bzero(&dop_arg, sizeof (smbd_arg_t));
81 	hdr = &dop_arg.hdr;
82 	hdr_size = xdr_sizeof(smb_doorhdr_xdr, hdr);
83 
84 	if ((argp == NULL) || (arg_size < hdr_size)) {
85 		syslog(LOG_DEBUG, "fksmbd_door_dispatch: bad args");
86 		return (-1);
87 	}
88 
89 	if (smb_doorhdr_decode(hdr, (uint8_t *)argp, hdr_size) == -1) {
90 		syslog(LOG_DEBUG, "smbd_door_dispatch: header decode failed");
91 		return (-1);
92 	}
93 
94 	if ((hdr->dh_magic != SMB_DOOR_HDR_MAGIC) ||
95 	    (hdr->dh_flags != SMB_DF_FAKE_KERNEL)) {
96 		syslog(LOG_DEBUG, "fksmbd_door_dispatch: invalid header");
97 		return (-1);
98 	}
99 
100 	dop_arg.opname = smb_doorhdr_opname(hdr->dh_op);
101 	dop_arg.data = argp + hdr_size;
102 	dop_arg.datalen = hdr->dh_datalen;
103 
104 	if (hdr->dh_op == SMB_DR_ASYNC_RESPONSE) {
105 		/*
106 		 * ASYNC_RESPONSE is not used here.
107 		 */
108 		syslog(LOG_DEBUG, "fksmbd_door_dispatch: ASYNC?");
109 		return (-1);
110 	}
111 
112 	/*
113 	 * Dispatch
114 	 *
115 	 * Call the common smbd_doorsvc.c code.
116 	 */
117 	(void) smbd_door_dispatch_op(&dop_arg);
118 
119 	/*
120 	 * Encode
121 	 *
122 	 * da->da_arg.rbuf  = (return data buf)
123 	 * da->da_arg.rsize = (return data size)
124 	 *
125 	 * Note that the return data buffer initially
126 	 * points to the same buffer as the args.
127 	 * If that's not large enough, umem_alloc.
128 	 */
129 
130 	rsize = dop_arg.rsize + hdr_size;
131 	rbuf = umem_alloc(rsize, UMEM_DEFAULT);
132 	if (rbuf == NULL) {
133 		syslog(LOG_DEBUG, "fksmbd_door_dispatch[%s]: alloc %m",
134 		    dop_arg.opname);
135 		return (-1);
136 	}
137 
138 	/* Copy caller's return data after the header. */
139 	if (dop_arg.rbuf != NULL) {
140 		(void) memcpy(rbuf + hdr_size, dop_arg.rbuf, dop_arg.rsize);
141 		free(dop_arg.rbuf);
142 	}
143 
144 	hdr->dh_datalen = dop_arg.rsize;
145 	(void) smb_doorhdr_encode(hdr, (uint8_t *)rbuf, hdr_size);
146 
147 	/* Let's update da->da_hdr too. */
148 	da->da_hdr = *hdr;
149 
150 	/*
151 	 * Was door_return()
152 	 * NB: The "fake kernel" smbsrv code will umem_free rbuf.
153 	 */
154 	da->da_arg.rbuf = rbuf;
155 	da->da_arg.rsize = rsize;
156 
157 	return (0);
158 }
159