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