xref: /illumos-gate/usr/src/lib/smbsrv/libsmb/common/smb_kmod.c (revision 9fb67ea305c66b6a297583b9b0db6796b0dfe497)
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 2010 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 void
114 smb_kmod_stop(void)
115 {
116 	smb_ioc_header_t ioc;
117 
118 	(void) smb_kmod_ioctl(SMB_IOC_STOP, &ioc, sizeof (ioc));
119 }
120 
121 int
122 smb_kmod_event_notify(uint32_t txid)
123 {
124 	smb_ioc_event_t ioc;
125 
126 	ioc.txid = txid;
127 	return (smb_kmod_ioctl(SMB_IOC_EVENT, &ioc.hdr, sizeof (ioc)));
128 }
129 
130 int
131 smb_kmod_tcplisten(int error)
132 {
133 	smb_ioc_listen_t ioc;
134 
135 	ioc.error = error;
136 	return (smb_kmod_ioctl(SMB_IOC_TCP_LISTEN, &ioc.hdr, sizeof (ioc)));
137 }
138 
139 int
140 smb_kmod_nbtlisten(int error)
141 {
142 	smb_ioc_listen_t ioc;
143 
144 	ioc.error = error;
145 	return (smb_kmod_ioctl(SMB_IOC_NBT_LISTEN, &ioc.hdr, sizeof (ioc)));
146 }
147 
148 int
149 smb_kmod_tcpreceive(void)
150 {
151 	smb_ioc_header_t ioc;
152 
153 	return (smb_kmod_ioctl(SMB_IOC_TCP_RECEIVE, &ioc, sizeof (ioc)));
154 }
155 
156 int
157 smb_kmod_nbtreceive(void)
158 {
159 	smb_ioc_header_t ioc;
160 
161 	return (smb_kmod_ioctl(SMB_IOC_NBT_RECEIVE, &ioc, sizeof (ioc)));
162 }
163 
164 int
165 smb_kmod_share(char *path, char *name)
166 {
167 	smb_ioc_share_t *ioc;
168 	int rc = ENOMEM;
169 
170 	ioc = malloc(sizeof (smb_ioc_share_t));
171 
172 	if (ioc != NULL) {
173 		(void) strlcpy(ioc->path, path, sizeof (ioc->path));
174 		(void) strlcpy(ioc->name, name, sizeof (ioc->name));
175 		rc = smb_kmod_ioctl(SMB_IOC_SHARE, &ioc->hdr,
176 		    sizeof (smb_ioc_share_t));
177 		free(ioc);
178 	}
179 	return (rc);
180 }
181 
182 int
183 smb_kmod_unshare(char *path, char *name)
184 {
185 	smb_ioc_share_t *ioc;
186 	int rc = ENOMEM;
187 
188 	ioc = malloc(sizeof (smb_ioc_share_t));
189 
190 	if (ioc != NULL) {
191 		(void) strlcpy(ioc->path, path, sizeof (ioc->path));
192 		(void) strlcpy(ioc->name, name, sizeof (ioc->name));
193 		rc = smb_kmod_ioctl(SMB_IOC_UNSHARE, &ioc->hdr,
194 		    sizeof (smb_ioc_share_t));
195 		free(ioc);
196 	}
197 	return (rc);
198 }
199 
200 int
201 smb_kmod_get_open_num(smb_opennum_t *opennum)
202 {
203 	smb_ioc_opennum_t ioc;
204 	int rc;
205 
206 	bzero(&ioc, sizeof (ioc));
207 	ioc.qualtype = opennum->qualtype;
208 	(void) strlcpy(ioc.qualifier, opennum->qualifier, MAXNAMELEN);
209 
210 	rc = smb_kmod_ioctl(SMB_IOC_NUMOPEN, &ioc.hdr, sizeof (ioc));
211 	if (rc == 0) {
212 		opennum->open_users = ioc.open_users;
213 		opennum->open_trees = ioc.open_trees;
214 		opennum->open_files = ioc.open_files;
215 	}
216 
217 	return (rc);
218 }
219 
220 /*
221  * Initialization for an smb_kmod_enum request.  If this call succeeds,
222  * smb_kmod_enum_fini() must be called later to deallocate resources.
223  */
224 smb_netsvc_t *
225 smb_kmod_enum_init(smb_svcenum_t *request)
226 {
227 	smb_netsvc_t		*ns;
228 	smb_svcenum_t		*svcenum;
229 	smb_ioc_svcenum_t	*ioc;
230 	uint32_t		ioclen;
231 
232 	if ((ns = calloc(1, sizeof (smb_netsvc_t))) == NULL)
233 		return (NULL);
234 
235 	ioclen = sizeof (smb_ioc_svcenum_t) + SMB_IOC_DATA_SIZE;
236 	if ((ioc = malloc(ioclen)) == NULL) {
237 		free(ns);
238 		return (NULL);
239 	}
240 
241 	bzero(ioc, ioclen);
242 	svcenum = &ioc->svcenum;
243 	svcenum->se_type   = request->se_type;
244 	svcenum->se_level  = request->se_level;
245 	svcenum->se_bavail = SMB_IOC_DATA_SIZE;
246 	svcenum->se_nlimit = request->se_nlimit;
247 	svcenum->se_nskip = request->se_nskip;
248 	svcenum->se_buflen = SMB_IOC_DATA_SIZE;
249 
250 	list_create(&ns->ns_list, sizeof (smb_netsvcitem_t),
251 	    offsetof(smb_netsvcitem_t, nsi_lnd));
252 
253 	ns->ns_ioc = ioc;
254 	ns->ns_ioclen = ioclen;
255 	return (ns);
256 }
257 
258 /*
259  * Cleanup resources allocated via smb_kmod_enum_init and smb_kmod_enum.
260  */
261 void
262 smb_kmod_enum_fini(smb_netsvc_t *ns)
263 {
264 	list_t			*lst;
265 	smb_netsvcitem_t	*item;
266 	smb_netuserinfo_t	*user;
267 	smb_netconnectinfo_t	*tree;
268 	smb_netfileinfo_t	*ofile;
269 	uint32_t		se_type;
270 
271 	if (ns == NULL)
272 		return;
273 
274 	lst = &ns->ns_list;
275 	se_type = ns->ns_ioc->svcenum.se_type;
276 
277 	while ((item = list_head(lst)) != NULL) {
278 		list_remove(lst, item);
279 
280 		switch (se_type) {
281 		case SMB_SVCENUM_TYPE_USER:
282 			user = &item->nsi_un.nsi_user;
283 			free(user->ui_domain);
284 			free(user->ui_account);
285 			free(user->ui_workstation);
286 			break;
287 		case SMB_SVCENUM_TYPE_TREE:
288 			tree = &item->nsi_un.nsi_tree;
289 			free(tree->ci_username);
290 			free(tree->ci_share);
291 			break;
292 		case SMB_SVCENUM_TYPE_FILE:
293 			ofile = &item->nsi_un.nsi_ofile;
294 			free(ofile->fi_path);
295 			free(ofile->fi_username);
296 			break;
297 		default:
298 			break;
299 		}
300 	}
301 
302 	list_destroy(&ns->ns_list);
303 	free(ns->ns_items);
304 	free(ns->ns_ioc);
305 	free(ns);
306 }
307 
308 /*
309  * Enumerate users, connections or files.
310  */
311 int
312 smb_kmod_enum(smb_netsvc_t *ns)
313 {
314 	smb_ioc_svcenum_t	*ioc;
315 	uint32_t		ioclen;
316 	smb_svcenum_t		*svcenum;
317 	smb_netsvcitem_t	*items;
318 	smb_netuserinfo_t	*user;
319 	smb_netconnectinfo_t	*tree;
320 	smb_netfileinfo_t	*ofile;
321 	uint8_t			*data;
322 	uint32_t		len;
323 	uint32_t		se_type;
324 	uint_t			nbytes;
325 	int			i;
326 	int			rc;
327 
328 	ioc = ns->ns_ioc;
329 	ioclen = ns->ns_ioclen;
330 	rc = smb_kmod_ioctl(SMB_IOC_SVCENUM, &ioc->hdr, ioclen);
331 	if (rc != 0)
332 		return (rc);
333 
334 	svcenum = &ioc->svcenum;
335 	items = calloc(svcenum->se_nitems, sizeof (smb_netsvcitem_t));
336 	if (items == NULL)
337 		return (ENOMEM);
338 
339 	ns->ns_items = items;
340 	se_type = ns->ns_ioc->svcenum.se_type;
341 	data = svcenum->se_buf;
342 	len = svcenum->se_bused;
343 
344 	for (i = 0; i < svcenum->se_nitems; ++i) {
345 		switch (se_type) {
346 		case SMB_SVCENUM_TYPE_USER:
347 			user = &items->nsi_un.nsi_user;
348 			rc = smb_netuserinfo_decode(user, data, len, &nbytes);
349 			break;
350 		case SMB_SVCENUM_TYPE_TREE:
351 			tree = &items->nsi_un.nsi_tree;
352 			rc = smb_netconnectinfo_decode(tree, data, len,
353 			    &nbytes);
354 			break;
355 		case SMB_SVCENUM_TYPE_FILE:
356 			ofile = &items->nsi_un.nsi_ofile;
357 			rc = smb_netfileinfo_decode(ofile, data, len, &nbytes);
358 			break;
359 		default:
360 			rc = -1;
361 			break;
362 		}
363 
364 		if (rc != 0)
365 			return (EINVAL);
366 
367 		list_insert_tail(&ns->ns_list, items);
368 
369 		++items;
370 		data += nbytes;
371 		len -= nbytes;
372 	}
373 
374 	return (0);
375 }
376 
377 /*
378  * A NULL pointer is a wildcard indicator, which we pass on
379  * as an empty string (by virtue of the bzero).
380  */
381 int
382 smb_kmod_session_close(const char *client, const char *username)
383 {
384 	smb_ioc_session_t ioc;
385 	int rc;
386 
387 	bzero(&ioc, sizeof (ioc));
388 
389 	if (client != NULL)
390 		(void) strlcpy(ioc.client, client, MAXNAMELEN);
391 	if (username != NULL)
392 		(void) strlcpy(ioc.username, username, MAXNAMELEN);
393 
394 	rc = smb_kmod_ioctl(SMB_IOC_SESSION_CLOSE, &ioc.hdr, sizeof (ioc));
395 	return (rc);
396 }
397 
398 int
399 smb_kmod_file_close(uint32_t uniqid)
400 {
401 	smb_ioc_fileid_t ioc;
402 	int rc;
403 
404 	bzero(&ioc, sizeof (ioc));
405 	ioc.uniqid = uniqid;
406 
407 	rc = smb_kmod_ioctl(SMB_IOC_FILE_CLOSE, &ioc.hdr, sizeof (ioc));
408 	return (rc);
409 }
410 
411 void
412 smb_kmod_unbind(void)
413 {
414 	if (smbdrv_fd != -1) {
415 		(void) close(smbdrv_fd);
416 		smbdrv_fd = -1;
417 	}
418 }
419 
420 static int
421 smb_kmod_ioctl(int cmd, smb_ioc_header_t *ioc, uint32_t len)
422 {
423 	int rc = EINVAL;
424 
425 	ioc->version = SMB_IOC_VERSION;
426 	ioc->cmd = cmd;
427 	ioc->len = len;
428 	ioc->crc = 0;
429 	ioc->crc = smb_crc_gen((uint8_t *)ioc, sizeof (smb_ioc_header_t));
430 
431 	if (smbdrv_fd != -1) {
432 		if (ioctl(smbdrv_fd, cmd, ioc) < 0)
433 			rc = errno;
434 		else
435 			rc = 0;
436 	}
437 	return (rc);
438 }
439