dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / smbsrv / libsmb / common / smb_kmod.c
blob33605bb7d258e166f593b506c93e22ee34900b28
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
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>
39 #include <smbsrv/smb_xdr.h>
40 #include <smbsrv/smbinfo.h>
41 #include <smbsrv/smb_ioctl.h>
42 #include <smbsrv/libsmb.h>
44 #define SMBDRV_DEVICE_PATH "/dev/smbsrv"
45 #define SMB_IOC_DATA_SIZE (256 * 1024)
47 int smb_kmod_ioctl(int, smb_ioc_header_t *, uint32_t);
50 int smbdrv_fd = -1;
52 int
53 smb_kmod_bind(void)
55 if (smbdrv_fd != -1)
56 (void) close(smbdrv_fd);
58 if ((smbdrv_fd = open(SMBDRV_DEVICE_PATH, O_RDONLY)) < 0) {
59 smbdrv_fd = -1;
60 return (errno);
63 return (0);
66 boolean_t
67 smb_kmod_isbound(void)
69 return ((smbdrv_fd == -1) ? B_FALSE : B_TRUE);
72 /* See also: smbsrv smb_server_store_cfg */
73 int
74 smb_kmod_setcfg(smb_kmod_cfg_t *cfg)
76 smb_ioc_cfg_t ioc;
78 ioc.maxworkers = cfg->skc_maxworkers;
79 ioc.maxconnections = cfg->skc_maxconnections;
80 ioc.keepalive = cfg->skc_keepalive;
81 ioc.restrict_anon = cfg->skc_restrict_anon;
82 ioc.signing_enable = cfg->skc_signing_enable;
83 ioc.signing_required = cfg->skc_signing_required;
84 ioc.oplock_enable = cfg->skc_oplock_enable;
85 ioc.sync_enable = cfg->skc_sync_enable;
86 ioc.secmode = cfg->skc_secmode;
87 ioc.netbios_enable = cfg->skc_netbios_enable;
88 ioc.ipv6_enable = cfg->skc_ipv6_enable;
89 ioc.print_enable = cfg->skc_print_enable;
90 ioc.traverse_mounts = cfg->skc_traverse_mounts;
91 ioc.max_protocol = cfg->skc_max_protocol;
92 ioc.exec_flags = cfg->skc_execflags;
93 ioc.negtok_len = cfg->skc_negtok_len;
94 ioc.version = cfg->skc_version;
95 ioc.initial_credits = cfg->skc_initial_credits;
96 ioc.maximum_credits = cfg->skc_maximum_credits;
98 (void) memcpy(ioc.machine_uuid, cfg->skc_machine_uuid, sizeof (uuid_t));
99 (void) memcpy(ioc.negtok, cfg->skc_negtok, sizeof (ioc.negtok));
100 (void) memcpy(ioc.native_os, cfg->skc_native_os,
101 sizeof (ioc.native_os));
102 (void) memcpy(ioc.native_lm, cfg->skc_native_lm,
103 sizeof (ioc.native_lm));
105 (void) strlcpy(ioc.nbdomain, cfg->skc_nbdomain, sizeof (ioc.nbdomain));
106 (void) strlcpy(ioc.fqdn, cfg->skc_fqdn, sizeof (ioc.fqdn));
107 (void) strlcpy(ioc.hostname, cfg->skc_hostname, sizeof (ioc.hostname));
108 (void) strlcpy(ioc.system_comment, cfg->skc_system_comment,
109 sizeof (ioc.system_comment));
111 return (smb_kmod_ioctl(SMB_IOC_CONFIG, &ioc.hdr, sizeof (ioc)));
115 smb_kmod_setgmtoff(int32_t gmtoff)
117 smb_ioc_gmt_t ioc;
119 ioc.offset = gmtoff;
120 return (smb_kmod_ioctl(SMB_IOC_GMTOFF, &ioc.hdr,
121 sizeof (ioc)));
125 smb_kmod_start(int opipe, int lmshr, int udoor)
127 smb_ioc_start_t ioc;
129 ioc.opipe = opipe;
130 ioc.lmshrd = lmshr;
131 ioc.udoor = udoor;
132 return (smb_kmod_ioctl(SMB_IOC_START, &ioc.hdr, sizeof (ioc)));
135 void
136 smb_kmod_stop(void)
138 smb_ioc_header_t ioc;
140 (void) smb_kmod_ioctl(SMB_IOC_STOP, &ioc, sizeof (ioc));
144 smb_kmod_event_notify(uint32_t txid)
146 smb_ioc_event_t ioc;
148 ioc.txid = txid;
149 return (smb_kmod_ioctl(SMB_IOC_EVENT, &ioc.hdr, sizeof (ioc)));
153 smb_kmod_share(nvlist_t *shrlist)
155 smb_ioc_share_t *ioc;
156 uint32_t ioclen;
157 char *shrbuf = NULL;
158 size_t bufsz;
159 int rc = ENOMEM;
161 if ((rc = nvlist_pack(shrlist, &shrbuf, &bufsz, NV_ENCODE_XDR, 0)) != 0)
162 return (rc);
164 ioclen = sizeof (smb_ioc_share_t) + bufsz;
166 if ((ioc = malloc(ioclen)) != NULL) {
167 ioc->shrlen = bufsz;
168 bcopy(shrbuf, ioc->shr, bufsz);
169 rc = smb_kmod_ioctl(SMB_IOC_SHARE, &ioc->hdr, ioclen);
170 free(ioc);
173 free(shrbuf);
174 return (rc);
178 smb_kmod_unshare(nvlist_t *shrlist)
180 smb_ioc_share_t *ioc;
181 uint32_t ioclen;
182 char *shrbuf = NULL;
183 size_t bufsz;
184 int rc = ENOMEM;
186 if ((rc = nvlist_pack(shrlist, &shrbuf, &bufsz, NV_ENCODE_XDR, 0)) != 0)
187 return (rc);
189 ioclen = sizeof (smb_ioc_share_t) + bufsz;
191 if ((ioc = malloc(ioclen)) != NULL) {
192 ioc->shrlen = bufsz;
193 bcopy(shrbuf, ioc->shr, bufsz);
194 rc = smb_kmod_ioctl(SMB_IOC_UNSHARE, &ioc->hdr, ioclen);
195 free(ioc);
198 free(shrbuf);
199 return (rc);
203 smb_kmod_shareinfo(char *shrname, boolean_t *shortnames)
205 smb_ioc_shareinfo_t ioc;
206 int rc;
208 bzero(&ioc, sizeof (ioc));
209 (void) strlcpy(ioc.shrname, shrname, MAXNAMELEN);
211 rc = smb_kmod_ioctl(SMB_IOC_SHAREINFO, &ioc.hdr, sizeof (ioc));
212 if (rc == 0)
213 *shortnames = ioc.shortnames;
214 else
215 *shortnames = B_TRUE;
217 return (rc);
221 smb_kmod_get_open_num(smb_opennum_t *opennum)
223 smb_ioc_opennum_t ioc;
224 int rc;
226 bzero(&ioc, sizeof (ioc));
227 ioc.qualtype = opennum->qualtype;
228 (void) strlcpy(ioc.qualifier, opennum->qualifier, MAXNAMELEN);
230 rc = smb_kmod_ioctl(SMB_IOC_NUMOPEN, &ioc.hdr, sizeof (ioc));
231 if (rc == 0) {
232 opennum->open_users = ioc.open_users;
233 opennum->open_trees = ioc.open_trees;
234 opennum->open_files = ioc.open_files;
237 return (rc);
241 smb_kmod_get_spool_doc(uint32_t *spool_num, char *username,
242 char *path, smb_inaddr_t *ipaddr)
244 smb_ioc_spooldoc_t ioc;
245 int rc;
247 bzero(&ioc, sizeof (ioc));
248 rc = smb_kmod_ioctl(SMB_IOC_SPOOLDOC, &ioc.hdr, sizeof (ioc));
249 if (rc == 0) {
250 *spool_num = ioc.spool_num;
251 (void) strlcpy(username, ioc.username, MAXNAMELEN);
252 (void) strlcpy(path, ioc.path, MAXPATHLEN);
253 *ipaddr = ioc.ipaddr;
255 return (rc);
259 * Initialization for an smb_kmod_enum request. If this call succeeds,
260 * smb_kmod_enum_fini() must be called later to deallocate resources.
262 smb_netsvc_t *
263 smb_kmod_enum_init(smb_svcenum_t *request)
265 smb_netsvc_t *ns;
266 smb_svcenum_t *svcenum;
267 smb_ioc_svcenum_t *ioc;
268 uint32_t ioclen;
270 if ((ns = calloc(1, sizeof (smb_netsvc_t))) == NULL)
271 return (NULL);
273 ioclen = sizeof (smb_ioc_svcenum_t) + SMB_IOC_DATA_SIZE;
274 if ((ioc = malloc(ioclen)) == NULL) {
275 free(ns);
276 return (NULL);
279 bzero(ioc, ioclen);
280 svcenum = &ioc->svcenum;
281 svcenum->se_type = request->se_type;
282 svcenum->se_level = request->se_level;
283 svcenum->se_bavail = SMB_IOC_DATA_SIZE;
284 svcenum->se_nlimit = request->se_nlimit;
285 svcenum->se_nskip = request->se_nskip;
286 svcenum->se_buflen = SMB_IOC_DATA_SIZE;
288 list_create(&ns->ns_list, sizeof (smb_netsvcitem_t),
289 offsetof(smb_netsvcitem_t, nsi_lnd));
291 ns->ns_ioc = ioc;
292 ns->ns_ioclen = ioclen;
293 return (ns);
297 * Cleanup resources allocated via smb_kmod_enum_init and smb_kmod_enum.
299 void
300 smb_kmod_enum_fini(smb_netsvc_t *ns)
302 list_t *lst;
303 smb_netsvcitem_t *item;
304 smb_netuserinfo_t *user;
305 smb_netconnectinfo_t *tree;
306 smb_netfileinfo_t *ofile;
307 uint32_t se_type;
309 if (ns == NULL)
310 return;
312 lst = &ns->ns_list;
313 se_type = ns->ns_ioc->svcenum.se_type;
315 while ((item = list_head(lst)) != NULL) {
316 list_remove(lst, item);
318 switch (se_type) {
319 case SMB_SVCENUM_TYPE_USER:
320 user = &item->nsi_un.nsi_user;
321 free(user->ui_domain);
322 free(user->ui_account);
323 free(user->ui_workstation);
324 break;
325 case SMB_SVCENUM_TYPE_TREE:
326 tree = &item->nsi_un.nsi_tree;
327 free(tree->ci_username);
328 free(tree->ci_share);
329 break;
330 case SMB_SVCENUM_TYPE_FILE:
331 ofile = &item->nsi_un.nsi_ofile;
332 free(ofile->fi_path);
333 free(ofile->fi_username);
334 break;
335 default:
336 break;
340 list_destroy(&ns->ns_list);
341 free(ns->ns_items);
342 free(ns->ns_ioc);
343 free(ns);
347 * Enumerate users, connections or files.
350 smb_kmod_enum(smb_netsvc_t *ns)
352 smb_ioc_svcenum_t *ioc;
353 uint32_t ioclen;
354 smb_svcenum_t *svcenum;
355 smb_netsvcitem_t *items;
356 smb_netuserinfo_t *user;
357 smb_netconnectinfo_t *tree;
358 smb_netfileinfo_t *ofile;
359 uint8_t *data;
360 uint32_t len;
361 uint32_t se_type;
362 uint_t nbytes;
363 int i;
364 int rc;
366 ioc = ns->ns_ioc;
367 ioclen = ns->ns_ioclen;
368 rc = smb_kmod_ioctl(SMB_IOC_SVCENUM, &ioc->hdr, ioclen);
369 if (rc != 0)
370 return (rc);
372 svcenum = &ioc->svcenum;
373 items = calloc(svcenum->se_nitems, sizeof (smb_netsvcitem_t));
374 if (items == NULL)
375 return (ENOMEM);
377 ns->ns_items = items;
378 se_type = ns->ns_ioc->svcenum.se_type;
379 data = svcenum->se_buf;
380 len = svcenum->se_bused;
382 for (i = 0; i < svcenum->se_nitems; ++i) {
383 switch (se_type) {
384 case SMB_SVCENUM_TYPE_USER:
385 user = &items->nsi_un.nsi_user;
386 rc = smb_netuserinfo_decode(user, data, len, &nbytes);
387 break;
388 case SMB_SVCENUM_TYPE_TREE:
389 tree = &items->nsi_un.nsi_tree;
390 rc = smb_netconnectinfo_decode(tree, data, len,
391 &nbytes);
392 break;
393 case SMB_SVCENUM_TYPE_FILE:
394 ofile = &items->nsi_un.nsi_ofile;
395 rc = smb_netfileinfo_decode(ofile, data, len, &nbytes);
396 break;
397 default:
398 rc = -1;
399 break;
402 if (rc != 0)
403 return (EINVAL);
405 list_insert_tail(&ns->ns_list, items);
407 ++items;
408 data += nbytes;
409 len -= nbytes;
412 return (0);
416 * A NULL pointer is a wildcard indicator, which we pass on
417 * as an empty string (by virtue of the bzero).
420 smb_kmod_session_close(const char *client, const char *username)
422 smb_ioc_session_t ioc;
423 int rc;
425 bzero(&ioc, sizeof (ioc));
427 if (client != NULL)
428 (void) strlcpy(ioc.client, client, MAXNAMELEN);
429 if (username != NULL)
430 (void) strlcpy(ioc.username, username, MAXNAMELEN);
432 rc = smb_kmod_ioctl(SMB_IOC_SESSION_CLOSE, &ioc.hdr, sizeof (ioc));
433 return (rc);
437 smb_kmod_file_close(uint32_t uniqid)
439 smb_ioc_fileid_t ioc;
440 int rc;
442 bzero(&ioc, sizeof (ioc));
443 ioc.uniqid = uniqid;
445 rc = smb_kmod_ioctl(SMB_IOC_FILE_CLOSE, &ioc.hdr, sizeof (ioc));
446 return (rc);
449 void
450 smb_kmod_unbind(void)
452 if (smbdrv_fd != -1) {
453 (void) close(smbdrv_fd);
454 smbdrv_fd = -1;
459 * Note: The user-space smbd-d provides it own version of this function
460 * which directly calls the "kernel" module code (in user space).
463 smb_kmod_ioctl(int cmd, smb_ioc_header_t *ioc, uint32_t len)
465 int rc = EINVAL;
467 ioc->version = SMB_IOC_VERSION;
468 ioc->cmd = cmd;
469 ioc->len = len;
470 ioc->crc = 0;
471 ioc->crc = smb_crc_gen((uint8_t *)ioc, sizeof (smb_ioc_header_t));
473 if (smbdrv_fd != -1) {
474 if (ioctl(smbdrv_fd, cmd, ioc) < 0)
475 rc = errno;
476 else
477 rc = 0;
479 return (rc);