xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c (revision 56f33205c9ed776c3c909e07d52e94610a675740)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <sys/ioccom.h>
29 #include <sys/param.h>
30 #include <stddef.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <strings.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <errno.h>
38 
39 #include <smbsrv/smb_xdr.h>
40 #include <smbsrv/smbinfo.h>
41 #include <smbsrv/smb_ioctl.h>
42 #include <smbsrv/smb_ioctl.h>
43 #include <smbsrv/libsmb.h>
44 
45 #define	SMBDRV_DEVICE_PATH		"/devices/pseudo/smbsrv@0:smbsrv"
46 #define	SMB_IOC_DATA_SIZE		(256 * 1024)
47 
48 static int smb_kmod_ioctl(int, smb_ioc_header_t *, uint32_t);
49 
50 
51 int	smbdrv_fd = -1;
52 
53 int
54 smb_kmod_bind(void)
55 {
56 	if (smbdrv_fd != -1)
57 		(void) close(smbdrv_fd);
58 
59 	if ((smbdrv_fd = open(SMBDRV_DEVICE_PATH, 0)) < 0) {
60 		smbdrv_fd = -1;
61 		return (errno);
62 	}
63 
64 	return (0);
65 }
66 
67 int
68 smb_kmod_setcfg(smb_kmod_cfg_t *cfg)
69 {
70 	smb_ioc_cfg_t ioc;
71 
72 	ioc.maxworkers = cfg->skc_maxworkers;
73 	ioc.maxconnections = cfg->skc_maxconnections;
74 	ioc.keepalive = cfg->skc_keepalive;
75 	ioc.restrict_anon = cfg->skc_restrict_anon;
76 	ioc.signing_enable = cfg->skc_signing_enable;
77 	ioc.signing_required = cfg->skc_signing_required;
78 	ioc.oplock_enable = cfg->skc_oplock_enable;
79 	ioc.sync_enable = cfg->skc_sync_enable;
80 	ioc.secmode = cfg->skc_secmode;
81 	ioc.ipv6_enable = cfg->skc_ipv6_enable;
82 
83 	(void) strlcpy(ioc.nbdomain, cfg->skc_nbdomain, sizeof (ioc.nbdomain));
84 	(void) strlcpy(ioc.fqdn, cfg->skc_fqdn, sizeof (ioc.fqdn));
85 	(void) strlcpy(ioc.hostname, cfg->skc_hostname, sizeof (ioc.hostname));
86 	(void) strlcpy(ioc.system_comment, cfg->skc_system_comment,
87 	    sizeof (ioc.system_comment));
88 
89 	return (smb_kmod_ioctl(SMB_IOC_CONFIG, &ioc.hdr, sizeof (ioc)));
90 }
91 
92 int
93 smb_kmod_setgmtoff(int32_t gmtoff)
94 {
95 	smb_ioc_gmt_t ioc;
96 
97 	ioc.offset = gmtoff;
98 	return (smb_kmod_ioctl(SMB_IOC_GMTOFF, &ioc.hdr,
99 	    sizeof (ioc)));
100 }
101 
102 int
103 smb_kmod_start(int opipe, int lmshr, int udoor)
104 {
105 	smb_ioc_start_t ioc;
106 
107 	ioc.opipe = opipe;
108 	ioc.lmshrd = lmshr;
109 	ioc.udoor = udoor;
110 	return (smb_kmod_ioctl(SMB_IOC_START, &ioc.hdr, sizeof (ioc)));
111 }
112 
113 int
114 smb_kmod_tcplisten(int error)
115 {
116 	smb_ioc_listen_t ioc;
117 
118 	ioc.error = error;
119 	return (smb_kmod_ioctl(SMB_IOC_TCP_LISTEN, &ioc.hdr, sizeof (ioc)));
120 }
121 
122 int
123 smb_kmod_nbtlisten(int error)
124 {
125 	smb_ioc_listen_t ioc;
126 
127 	ioc.error = error;
128 	return (smb_kmod_ioctl(SMB_IOC_NBT_LISTEN, &ioc.hdr, sizeof (ioc)));
129 }
130 
131 int
132 smb_kmod_tcpreceive(void)
133 {
134 	smb_ioc_header_t ioc;
135 
136 	return (smb_kmod_ioctl(SMB_IOC_TCP_RECEIVE, &ioc, sizeof (ioc)));
137 }
138 
139 int
140 smb_kmod_nbtreceive(void)
141 {
142 	smb_ioc_header_t ioc;
143 
144 	return (smb_kmod_ioctl(SMB_IOC_NBT_RECEIVE, &ioc, sizeof (ioc)));
145 }
146 
147 int
148 smb_kmod_share(char *path, char *name)
149 {
150 	smb_ioc_share_t *ioc;
151 	int rc = ENOMEM;
152 
153 	ioc = malloc(sizeof (smb_ioc_share_t));
154 
155 	if (ioc != NULL) {
156 		(void) strlcpy(ioc->path, path, sizeof (ioc->path));
157 		(void) strlcpy(ioc->name, name, sizeof (ioc->name));
158 		rc = smb_kmod_ioctl(SMB_IOC_SHARE, &ioc->hdr,
159 		    sizeof (smb_ioc_share_t));
160 		free(ioc);
161 	}
162 	return (rc);
163 }
164 
165 int
166 smb_kmod_unshare(char *path, char *name)
167 {
168 	smb_ioc_share_t *ioc;
169 	int rc = ENOMEM;
170 
171 	ioc = malloc(sizeof (smb_ioc_share_t));
172 
173 	if (ioc != NULL) {
174 		(void) strlcpy(ioc->path, path, sizeof (ioc->path));
175 		(void) strlcpy(ioc->name, name, sizeof (ioc->name));
176 		rc = smb_kmod_ioctl(SMB_IOC_UNSHARE, &ioc->hdr,
177 		    sizeof (smb_ioc_share_t));
178 		free(ioc);
179 	}
180 	return (rc);
181 }
182 
183 int
184 smb_kmod_get_open_num(smb_opennum_t *opennum)
185 {
186 	smb_ioc_opennum_t ioc;
187 	int rc;
188 
189 	bzero(&ioc, sizeof (ioc));
190 	ioc.qualtype = opennum->qualtype;
191 	(void) strlcpy(ioc.qualifier, opennum->qualifier, MAXNAMELEN);
192 
193 	rc = smb_kmod_ioctl(SMB_IOC_NUMOPEN, &ioc.hdr, sizeof (ioc));
194 	if (rc == 0) {
195 		opennum->open_users = ioc.open_users;
196 		opennum->open_trees = ioc.open_trees;
197 		opennum->open_files = ioc.open_files;
198 	}
199 
200 	return (rc);
201 }
202 
203 /*
204  * Initialization for an smb_kmod_enum request.  If this call succeeds,
205  * smb_kmod_enum_fini() must be called later to deallocate resources.
206  */
207 smb_netsvc_t *
208 smb_kmod_enum_init(smb_svcenum_t *request)
209 {
210 	smb_netsvc_t		*ns;
211 	smb_svcenum_t		*svcenum;
212 	smb_ioc_svcenum_t	*ioc;
213 	uint32_t		ioclen;
214 
215 	if ((ns = calloc(1, sizeof (smb_netsvc_t))) == NULL)
216 		return (NULL);
217 
218 	ioclen = sizeof (smb_ioc_svcenum_t) + SMB_IOC_DATA_SIZE;
219 	if ((ioc = malloc(ioclen)) == NULL) {
220 		free(ns);
221 		return (NULL);
222 	}
223 
224 	bzero(ioc, ioclen);
225 	svcenum = &ioc->svcenum;
226 	svcenum->se_type   = request->se_type;
227 	svcenum->se_level  = request->se_level;
228 	svcenum->se_bavail = SMB_IOC_DATA_SIZE;
229 	svcenum->se_nlimit = request->se_nlimit;
230 	svcenum->se_nskip = request->se_nskip;
231 	svcenum->se_buflen = SMB_IOC_DATA_SIZE;
232 
233 	list_create(&ns->ns_list, sizeof (smb_netsvcitem_t),
234 	    offsetof(smb_netsvcitem_t, nsi_lnd));
235 
236 	ns->ns_ioc = ioc;
237 	ns->ns_ioclen = ioclen;
238 	return (ns);
239 }
240 
241 /*
242  * Cleanup resources allocated via smb_kmod_enum_init and smb_kmod_enum.
243  */
244 void
245 smb_kmod_enum_fini(smb_netsvc_t *ns)
246 {
247 	list_t			*lst;
248 	smb_netsvcitem_t	*item;
249 	smb_netuserinfo_t	*user;
250 	smb_netconnectinfo_t	*tree;
251 	smb_netfileinfo_t	*ofile;
252 	uint32_t		se_type;
253 
254 	if (ns == NULL)
255 		return;
256 
257 	lst = &ns->ns_list;
258 	se_type = ns->ns_ioc->svcenum.se_type;
259 
260 	while ((item = list_head(lst)) != NULL) {
261 		list_remove(lst, item);
262 
263 		switch (se_type) {
264 		case SMB_SVCENUM_TYPE_USER:
265 			user = &item->nsi_un.nsi_user;
266 			free(user->ui_domain);
267 			free(user->ui_account);
268 			free(user->ui_workstation);
269 			break;
270 		case SMB_SVCENUM_TYPE_TREE:
271 			tree = &item->nsi_un.nsi_tree;
272 			free(tree->ci_username);
273 			free(tree->ci_share);
274 			break;
275 		case SMB_SVCENUM_TYPE_FILE:
276 			ofile = &item->nsi_un.nsi_ofile;
277 			free(ofile->fi_path);
278 			free(ofile->fi_username);
279 			break;
280 		default:
281 			break;
282 		}
283 	}
284 
285 	list_destroy(&ns->ns_list);
286 	free(ns->ns_items);
287 	free(ns->ns_ioc);
288 	free(ns);
289 }
290 
291 /*
292  * Enumerate users, connections or files.
293  */
294 int
295 smb_kmod_enum(smb_netsvc_t *ns)
296 {
297 	smb_ioc_svcenum_t	*ioc;
298 	uint32_t		ioclen;
299 	smb_svcenum_t		*svcenum;
300 	smb_netsvcitem_t	*items;
301 	smb_netuserinfo_t	*user;
302 	smb_netconnectinfo_t	*tree;
303 	smb_netfileinfo_t	*ofile;
304 	uint8_t			*data;
305 	uint32_t		len;
306 	uint32_t		se_type;
307 	uint_t			nbytes;
308 	int			i;
309 	int			rc;
310 
311 	ioc = ns->ns_ioc;
312 	ioclen = ns->ns_ioclen;
313 	rc = smb_kmod_ioctl(SMB_IOC_SVCENUM, &ioc->hdr, ioclen);
314 	if (rc != 0)
315 		return (rc);
316 
317 	svcenum = &ioc->svcenum;
318 	items = calloc(svcenum->se_nitems, sizeof (smb_netsvcitem_t));
319 	if (items == NULL)
320 		return (ENOMEM);
321 
322 	ns->ns_items = items;
323 	se_type = ns->ns_ioc->svcenum.se_type;
324 	data = svcenum->se_buf;
325 	len = svcenum->se_bused;
326 
327 	for (i = 0; i < svcenum->se_nitems; ++i) {
328 		switch (se_type) {
329 		case SMB_SVCENUM_TYPE_USER:
330 			user = &items->nsi_un.nsi_user;
331 			rc = smb_netuserinfo_decode(user, data, len, &nbytes);
332 			break;
333 		case SMB_SVCENUM_TYPE_TREE:
334 			tree = &items->nsi_un.nsi_tree;
335 			rc = smb_netconnectinfo_decode(tree, data, len,
336 			    &nbytes);
337 			break;
338 		case SMB_SVCENUM_TYPE_FILE:
339 			ofile = &items->nsi_un.nsi_ofile;
340 			rc = smb_netfileinfo_decode(ofile, data, len, &nbytes);
341 			break;
342 		default:
343 			rc = -1;
344 			break;
345 		}
346 
347 		if (rc != 0)
348 			return (EINVAL);
349 
350 		list_insert_tail(&ns->ns_list, items);
351 
352 		++items;
353 		data += nbytes;
354 		len -= nbytes;
355 	}
356 
357 	return (0);
358 }
359 
360 /*
361  * A NULL pointer is a wildcard indicator, which we pass on
362  * as an empty string (by virtue of the bzero).
363  */
364 int
365 smb_kmod_session_close(const char *client, const char *username)
366 {
367 	smb_ioc_session_t ioc;
368 	int rc;
369 
370 	bzero(&ioc, sizeof (ioc));
371 
372 	if (client != NULL)
373 		(void) strlcpy(ioc.client, client, MAXNAMELEN);
374 	if (username != NULL)
375 		(void) strlcpy(ioc.username, username, MAXNAMELEN);
376 
377 	rc = smb_kmod_ioctl(SMB_IOC_SESSION_CLOSE, &ioc.hdr, sizeof (ioc));
378 	return (rc);
379 }
380 
381 int
382 smb_kmod_file_close(uint32_t uniqid)
383 {
384 	smb_ioc_fileid_t ioc;
385 	int rc;
386 
387 	bzero(&ioc, sizeof (ioc));
388 	ioc.uniqid = uniqid;
389 
390 	rc = smb_kmod_ioctl(SMB_IOC_FILE_CLOSE, &ioc.hdr, sizeof (ioc));
391 	return (rc);
392 }
393 
394 void
395 smb_kmod_unbind(void)
396 {
397 	if (smbdrv_fd != -1) {
398 		(void) close(smbdrv_fd);
399 		smbdrv_fd = -1;
400 	}
401 }
402 
403 static int
404 smb_kmod_ioctl(int cmd, smb_ioc_header_t *ioc, uint32_t len)
405 {
406 	int rc = EINVAL;
407 
408 	ioc->version = SMB_IOC_VERSION;
409 	ioc->cmd = cmd;
410 	ioc->len = len;
411 	ioc->crc = 0;
412 	ioc->crc = smb_crc_gen((uint8_t *)ioc, sizeof (smb_ioc_header_t));
413 
414 	if (smbdrv_fd != -1) {
415 		if (ioctl(smbdrv_fd, cmd, ioc) < 0)
416 			rc = errno;
417 		else
418 			rc = 0;
419 	}
420 	return (rc);
421 }
422