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