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