111963SAfshin.Ardakani@Sun.COM /* 211963SAfshin.Ardakani@Sun.COM * CDDL HEADER START 311963SAfshin.Ardakani@Sun.COM * 411963SAfshin.Ardakani@Sun.COM * The contents of this file are subject to the terms of the 511963SAfshin.Ardakani@Sun.COM * Common Development and Distribution License (the "License"). 611963SAfshin.Ardakani@Sun.COM * You may not use this file except in compliance with the License. 711963SAfshin.Ardakani@Sun.COM * 811963SAfshin.Ardakani@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 911963SAfshin.Ardakani@Sun.COM * or http://www.opensolaris.org/os/licensing. 1011963SAfshin.Ardakani@Sun.COM * See the License for the specific language governing permissions 1111963SAfshin.Ardakani@Sun.COM * and limitations under the License. 1211963SAfshin.Ardakani@Sun.COM * 1311963SAfshin.Ardakani@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 1411963SAfshin.Ardakani@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1511963SAfshin.Ardakani@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 1611963SAfshin.Ardakani@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 1711963SAfshin.Ardakani@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 1811963SAfshin.Ardakani@Sun.COM * 1911963SAfshin.Ardakani@Sun.COM * CDDL HEADER END 2011963SAfshin.Ardakani@Sun.COM */ 21*12508Samw@Sun.COM 2211963SAfshin.Ardakani@Sun.COM /* 23*12508Samw@Sun.COM * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 2411963SAfshin.Ardakani@Sun.COM */ 2511963SAfshin.Ardakani@Sun.COM 2611963SAfshin.Ardakani@Sun.COM #include <strings.h> 2711963SAfshin.Ardakani@Sun.COM #include <errno.h> 2811963SAfshin.Ardakani@Sun.COM #include <unistd.h> 2911963SAfshin.Ardakani@Sun.COM #include <fcntl.h> 3011963SAfshin.Ardakani@Sun.COM #include <dirent.h> 31*12508Samw@Sun.COM #include <dlfcn.h> 3211963SAfshin.Ardakani@Sun.COM #include <pthread.h> 3311963SAfshin.Ardakani@Sun.COM #include <syslog.h> 3411963SAfshin.Ardakani@Sun.COM #include <sys/fs_reparse.h> 3511963SAfshin.Ardakani@Sun.COM #include <uuid/uuid.h> 3611963SAfshin.Ardakani@Sun.COM 37*12508Samw@Sun.COM #include <smbsrv/libsmb.h> 38*12508Samw@Sun.COM #include <smbsrv/libmlsvc.h> 3911963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_dfs.h> 4011963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_share.h> 4111963SAfshin.Ardakani@Sun.COM #include <dfs.h> 4211963SAfshin.Ardakani@Sun.COM 4311963SAfshin.Ardakani@Sun.COM /* 4411963SAfshin.Ardakani@Sun.COM * default timeout (TTL) values (in second) for root and link 4511963SAfshin.Ardakani@Sun.COM */ 4611963SAfshin.Ardakani@Sun.COM #define DFS_ROOT_TIMEOUT 300 4711963SAfshin.Ardakani@Sun.COM #define DFS_LINK_TIMEOUT 1800 4811963SAfshin.Ardakani@Sun.COM 4911963SAfshin.Ardakani@Sun.COM /* 5011963SAfshin.Ardakani@Sun.COM * DFS link data format in reparse point 5111963SAfshin.Ardakani@Sun.COM * 5211963SAfshin.Ardakani@Sun.COM * ver:state:prop:timeout:guid:ntarget:cmntlen:comment 5311963SAfshin.Ardakani@Sun.COM * [[:tserver:tshare:tstate:pclass:prank]...] 5411963SAfshin.Ardakani@Sun.COM */ 5511963SAfshin.Ardakani@Sun.COM #define DFS_LINK_V1 1 5611963SAfshin.Ardakani@Sun.COM #define DFS_LINK_HDR_NFIELDS 7 /* # fields in header section */ 5711963SAfshin.Ardakani@Sun.COM #define DFS_LINK_TRGT_NFIELDS 5 /* # fields for each target */ 5811963SAfshin.Ardakani@Sun.COM 5911963SAfshin.Ardakani@Sun.COM #define DFS_ROOT_XATTR "SUNWdfs.rootinfo" 6011963SAfshin.Ardakani@Sun.COM 6111963SAfshin.Ardakani@Sun.COM #define DFS_INFO_ALL 0 6211963SAfshin.Ardakani@Sun.COM 63*12508Samw@Sun.COM static void *dfs_intr_hdl = NULL; 64*12508Samw@Sun.COM 65*12508Samw@Sun.COM static struct { 66*12508Samw@Sun.COM int (*dfsops_remote_count)(uint32_t *); 67*12508Samw@Sun.COM } dfs_intr_ops; 68*12508Samw@Sun.COM 6911963SAfshin.Ardakani@Sun.COM /* 7011963SAfshin.Ardakani@Sun.COM * Namespace cache 7111963SAfshin.Ardakani@Sun.COM * 7211963SAfshin.Ardakani@Sun.COM * Caches links' UNC and filesystem path where the key is the UNC path. 7311963SAfshin.Ardakani@Sun.COM */ 7411963SAfshin.Ardakani@Sun.COM static smb_cache_t dfs_nscache; 7511963SAfshin.Ardakani@Sun.COM static char dfs_nbname[NETBIOS_NAME_SZ]; 7611963SAfshin.Ardakani@Sun.COM 7711963SAfshin.Ardakani@Sun.COM /* 7811963SAfshin.Ardakani@Sun.COM * Lock for accessing root information (extended attribute) 7911963SAfshin.Ardakani@Sun.COM */ 8011963SAfshin.Ardakani@Sun.COM static rwlock_t dfs_root_rwl; 8111963SAfshin.Ardakani@Sun.COM 8211963SAfshin.Ardakani@Sun.COM extern uint32_t srvsvc_shr_setdfsroot(smb_share_t *, boolean_t); 8311963SAfshin.Ardakani@Sun.COM 8411963SAfshin.Ardakani@Sun.COM /* 8511963SAfshin.Ardakani@Sun.COM * Namespace functions 8611963SAfshin.Ardakani@Sun.COM */ 8711963SAfshin.Ardakani@Sun.COM static boolean_t dfs_namespace_findlink(const char *, char *, char *, size_t); 8811963SAfshin.Ardakani@Sun.COM static void *dfs_namespace_cache(void *); 8911963SAfshin.Ardakani@Sun.COM 9011963SAfshin.Ardakani@Sun.COM /* 9111963SAfshin.Ardakani@Sun.COM * Root functions 9211963SAfshin.Ardakani@Sun.COM */ 9311963SAfshin.Ardakani@Sun.COM static int dfs_root_add(const char *, dfs_info_t *); 9411963SAfshin.Ardakani@Sun.COM static uint32_t dfs_root_remove(const char *); 9511963SAfshin.Ardakani@Sun.COM static uint32_t dfs_root_encode(dfs_info_t *, char **, size_t *); 9611963SAfshin.Ardakani@Sun.COM static uint32_t dfs_root_decode(dfs_info_t *, char *, size_t, uint32_t); 9711963SAfshin.Ardakani@Sun.COM static uint32_t dfs_root_isvalidstate(uint32_t); 9811963SAfshin.Ardakani@Sun.COM 9911963SAfshin.Ardakani@Sun.COM static int dfs_root_xopen(const char *, int); 10011963SAfshin.Ardakani@Sun.COM static void dfs_root_xclose(int); 10111963SAfshin.Ardakani@Sun.COM static uint32_t dfs_root_xwrite(int, dfs_info_t *); 10211963SAfshin.Ardakani@Sun.COM static uint32_t dfs_root_xread(int, dfs_info_t *, uint32_t); 10311963SAfshin.Ardakani@Sun.COM 10411963SAfshin.Ardakani@Sun.COM /* 10511963SAfshin.Ardakani@Sun.COM * Link functions 10611963SAfshin.Ardakani@Sun.COM */ 10711963SAfshin.Ardakani@Sun.COM static uint32_t dfs_link_encode(dfs_info_t *, char *, size_t); 10811963SAfshin.Ardakani@Sun.COM static uint32_t dfs_link_decode(dfs_info_t *, char *, uint32_t); 10911963SAfshin.Ardakani@Sun.COM static uint32_t dfs_link_commit(const char *, dfs_info_t *); 11011963SAfshin.Ardakani@Sun.COM static boolean_t dfs_link_isvalidstate(uint32_t); 11111963SAfshin.Ardakani@Sun.COM 11211963SAfshin.Ardakani@Sun.COM /* 11311963SAfshin.Ardakani@Sun.COM * Target functions 11411963SAfshin.Ardakani@Sun.COM */ 11511963SAfshin.Ardakani@Sun.COM static void dfs_target_init(dfs_target_t *, const char *, const char *, 11611963SAfshin.Ardakani@Sun.COM uint32_t); 11711963SAfshin.Ardakani@Sun.COM static int dfs_target_find(dfs_target_t *, uint32_t, const char *, 11811963SAfshin.Ardakani@Sun.COM const char *); 11911963SAfshin.Ardakani@Sun.COM static boolean_t dfs_target_isvalidstate(uint32_t); 12011963SAfshin.Ardakani@Sun.COM 12111963SAfshin.Ardakani@Sun.COM /* 12211963SAfshin.Ardakani@Sun.COM * Cache functions 12311963SAfshin.Ardakani@Sun.COM */ 12411963SAfshin.Ardakani@Sun.COM static uint32_t dfs_cache_add_byunc(const char *, const char *, uint32_t); 12511963SAfshin.Ardakani@Sun.COM static void dfs_cache_populate(const char *, const char *); 12611963SAfshin.Ardakani@Sun.COM static int dfs_cache_cmp(const void *, const void *); 12711963SAfshin.Ardakani@Sun.COM 12811963SAfshin.Ardakani@Sun.COM /* 12911963SAfshin.Ardakani@Sun.COM * Utility functions 13011963SAfshin.Ardakani@Sun.COM */ 13111963SAfshin.Ardakani@Sun.COM static boolean_t dfs_path_isdir(const char *); 13211963SAfshin.Ardakani@Sun.COM static uint32_t dfs_modinfo(uint32_t, dfs_info_t *, dfs_info_t *, uint32_t); 13311963SAfshin.Ardakani@Sun.COM 13411963SAfshin.Ardakani@Sun.COM /* 13511963SAfshin.Ardakani@Sun.COM * DFS module initializationr: 13611963SAfshin.Ardakani@Sun.COM * 13711963SAfshin.Ardakani@Sun.COM * - creates the namespace cache 13811963SAfshin.Ardakani@Sun.COM * - gets system's NetBIOS name 13911963SAfshin.Ardakani@Sun.COM */ 14011963SAfshin.Ardakani@Sun.COM void 14111963SAfshin.Ardakani@Sun.COM dfs_init(void) 14211963SAfshin.Ardakani@Sun.COM { 14311963SAfshin.Ardakani@Sun.COM smb_domain_t di; 14411963SAfshin.Ardakani@Sun.COM 14511963SAfshin.Ardakani@Sun.COM smb_cache_create(&dfs_nscache, 0, dfs_cache_cmp, free, bcopy, 14611963SAfshin.Ardakani@Sun.COM sizeof (dfs_nscnode_t)); 14711963SAfshin.Ardakani@Sun.COM 14811963SAfshin.Ardakani@Sun.COM if (!smb_domain_lookup_type(SMB_DOMAIN_LOCAL, &di)) 14911963SAfshin.Ardakani@Sun.COM return; 15011963SAfshin.Ardakani@Sun.COM 15111963SAfshin.Ardakani@Sun.COM (void) strlcpy(dfs_nbname, di.di_nbname, NETBIOS_NAME_SZ); 152*12508Samw@Sun.COM 153*12508Samw@Sun.COM bzero((void *)&dfs_intr_ops, sizeof (dfs_intr_ops)); 154*12508Samw@Sun.COM 155*12508Samw@Sun.COM if ((dfs_intr_hdl = smb_dlopen()) == NULL) 156*12508Samw@Sun.COM return; 157*12508Samw@Sun.COM 158*12508Samw@Sun.COM if ((dfs_intr_ops.dfsops_remote_count = 159*12508Samw@Sun.COM (int (*)())dlsym(dfs_intr_hdl, "smb_dfs_remote_count")) == NULL) { 160*12508Samw@Sun.COM smb_dlclose(dfs_intr_hdl); 161*12508Samw@Sun.COM dfs_intr_hdl = NULL; 162*12508Samw@Sun.COM bzero((void *)&dfs_intr_ops, sizeof (dfs_intr_ops)); 163*12508Samw@Sun.COM } 16411963SAfshin.Ardakani@Sun.COM } 16511963SAfshin.Ardakani@Sun.COM 16611963SAfshin.Ardakani@Sun.COM /* 16711963SAfshin.Ardakani@Sun.COM * DFS module cleanup: 16811963SAfshin.Ardakani@Sun.COM * 16911963SAfshin.Ardakani@Sun.COM * - destroys the namespace cache 17011963SAfshin.Ardakani@Sun.COM */ 17111963SAfshin.Ardakani@Sun.COM void 17211963SAfshin.Ardakani@Sun.COM dfs_fini(void) 17311963SAfshin.Ardakani@Sun.COM { 174*12508Samw@Sun.COM smb_dlclose(dfs_intr_hdl); 17511963SAfshin.Ardakani@Sun.COM smb_cache_destroy(&dfs_nscache); 17611963SAfshin.Ardakani@Sun.COM } 17711963SAfshin.Ardakani@Sun.COM 17811963SAfshin.Ardakani@Sun.COM /* 17911963SAfshin.Ardakani@Sun.COM * To successfully handle some of link/root requests, some 18011963SAfshin.Ardakani@Sun.COM * file system operations need to be performed. These operations 18111963SAfshin.Ardakani@Sun.COM * should take place on behalf of the connected user (typically 18211963SAfshin.Ardakani@Sun.COM * Administrator) and to do so we need to have an infrastructure 18311963SAfshin.Ardakani@Sun.COM * in place so that smbd can act as a client and sends request to 18411963SAfshin.Ardakani@Sun.COM * the kernel. Right now, we lack this infrastructure, so we make 18511963SAfshin.Ardakani@Sun.COM * a compromise by temporarily enabling some privileges for smbd 18611963SAfshin.Ardakani@Sun.COM * to be able to fulfill various link/root requests. 18711963SAfshin.Ardakani@Sun.COM */ 18811963SAfshin.Ardakani@Sun.COM void 18911963SAfshin.Ardakani@Sun.COM dfs_setpriv(priv_op_t op) 19011963SAfshin.Ardakani@Sun.COM { 19111963SAfshin.Ardakani@Sun.COM (void) priv_set(op, PRIV_EFFECTIVE, 19211963SAfshin.Ardakani@Sun.COM PRIV_FILE_DAC_READ, 19311963SAfshin.Ardakani@Sun.COM PRIV_FILE_DAC_WRITE, 19411963SAfshin.Ardakani@Sun.COM PRIV_FILE_DAC_EXECUTE, 19511963SAfshin.Ardakani@Sun.COM PRIV_FILE_DAC_SEARCH, NULL); 19611963SAfshin.Ardakani@Sun.COM } 19711963SAfshin.Ardakani@Sun.COM 19811963SAfshin.Ardakani@Sun.COM /* 19911963SAfshin.Ardakani@Sun.COM * ======================== 20011963SAfshin.Ardakani@Sun.COM * Namespace API (public) 20111963SAfshin.Ardakani@Sun.COM * ======================== 20211963SAfshin.Ardakani@Sun.COM */ 20311963SAfshin.Ardakani@Sun.COM 20411963SAfshin.Ardakani@Sun.COM /* 20511963SAfshin.Ardakani@Sun.COM * Launches a thread to cache the specified namespace 20611963SAfshin.Ardakani@Sun.COM */ 20711963SAfshin.Ardakani@Sun.COM void 20811963SAfshin.Ardakani@Sun.COM dfs_namespace_load(const char *name) 20911963SAfshin.Ardakani@Sun.COM { 21011963SAfshin.Ardakani@Sun.COM pthread_t thr; 21111963SAfshin.Ardakani@Sun.COM pthread_attr_t tattr; 21211963SAfshin.Ardakani@Sun.COM char *rootshr; 21311963SAfshin.Ardakani@Sun.COM int rc; 21411963SAfshin.Ardakani@Sun.COM 21511963SAfshin.Ardakani@Sun.COM if ((rootshr = strdup(name)) == NULL) { 21611963SAfshin.Ardakani@Sun.COM syslog(LOG_ERR, "dfs: failed to load %s namespace (no memory)", 21711963SAfshin.Ardakani@Sun.COM name); 21811963SAfshin.Ardakani@Sun.COM return; 21911963SAfshin.Ardakani@Sun.COM } 22011963SAfshin.Ardakani@Sun.COM 22111963SAfshin.Ardakani@Sun.COM (void) pthread_attr_init(&tattr); 22211963SAfshin.Ardakani@Sun.COM (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 22311963SAfshin.Ardakani@Sun.COM rc = pthread_create(&thr, &tattr, dfs_namespace_cache, rootshr); 22411963SAfshin.Ardakani@Sun.COM (void) pthread_attr_destroy(&tattr); 22511963SAfshin.Ardakani@Sun.COM 22611963SAfshin.Ardakani@Sun.COM if (rc != 0) 22711963SAfshin.Ardakani@Sun.COM syslog(LOG_ERR, "dfs: fail to loading %s namespace (%d)", 22811963SAfshin.Ardakani@Sun.COM name, rc); 22911963SAfshin.Ardakani@Sun.COM } 23011963SAfshin.Ardakani@Sun.COM 23111963SAfshin.Ardakani@Sun.COM /* 23211963SAfshin.Ardakani@Sun.COM * Flushes the cache when a DFS root share is removed 23311963SAfshin.Ardakani@Sun.COM */ 23411963SAfshin.Ardakani@Sun.COM void /*ARGSUSED*/ 23511963SAfshin.Ardakani@Sun.COM dfs_namespace_unload(const char *name) 23611963SAfshin.Ardakani@Sun.COM { 23711963SAfshin.Ardakani@Sun.COM smb_cache_flush(&dfs_nscache); 23811963SAfshin.Ardakani@Sun.COM } 23911963SAfshin.Ardakani@Sun.COM 24011963SAfshin.Ardakani@Sun.COM /* 24111963SAfshin.Ardakani@Sun.COM * Returns the file system path for the given share if it 24211963SAfshin.Ardakani@Sun.COM * is a DFS root share. 24311963SAfshin.Ardakani@Sun.COM * If 'path' is NULL, this function only indicates whether 24411963SAfshin.Ardakani@Sun.COM * or not the given share represents a DFS namespace 24511963SAfshin.Ardakani@Sun.COM */ 24611963SAfshin.Ardakani@Sun.COM uint32_t 24711963SAfshin.Ardakani@Sun.COM dfs_namespace_path(const char *name, char *path, size_t pathsz) 24811963SAfshin.Ardakani@Sun.COM { 24911963SAfshin.Ardakani@Sun.COM smb_share_t si; 25011963SAfshin.Ardakani@Sun.COM 25111963SAfshin.Ardakani@Sun.COM if (smb_shr_get((char *)name, &si) != NERR_Success) 25211963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND); 25311963SAfshin.Ardakani@Sun.COM 25411963SAfshin.Ardakani@Sun.COM if ((si.shr_flags & SMB_SHRF_DFSROOT) == 0) 25511963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND); 25611963SAfshin.Ardakani@Sun.COM 25711963SAfshin.Ardakani@Sun.COM if (path != NULL) 25811963SAfshin.Ardakani@Sun.COM (void) strlcpy(path, si.shr_path, pathsz); 25911963SAfshin.Ardakani@Sun.COM 26011963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 26111963SAfshin.Ardakani@Sun.COM } 26211963SAfshin.Ardakani@Sun.COM 26311963SAfshin.Ardakani@Sun.COM /* 26411963SAfshin.Ardakani@Sun.COM * Returns the number of DFS root shares i.e. the number 26511963SAfshin.Ardakani@Sun.COM * of standalone namespaces. 26611963SAfshin.Ardakani@Sun.COM */ 26711963SAfshin.Ardakani@Sun.COM uint32_t 26811963SAfshin.Ardakani@Sun.COM dfs_namespace_count(void) 26911963SAfshin.Ardakani@Sun.COM { 27011963SAfshin.Ardakani@Sun.COM smb_shriter_t shi; 27111963SAfshin.Ardakani@Sun.COM smb_share_t *si; 27211963SAfshin.Ardakani@Sun.COM uint32_t nroot = 0; 273*12508Samw@Sun.COM int rc; 274*12508Samw@Sun.COM 275*12508Samw@Sun.COM if (dfs_intr_ops.dfsops_remote_count != NULL && 276*12508Samw@Sun.COM (rc = dfs_intr_ops.dfsops_remote_count(&nroot)) != 0) { 277*12508Samw@Sun.COM /* 278*12508Samw@Sun.COM * If this call fails, let's assume there's at least one root 279*12508Samw@Sun.COM * namespace already configured. The interposer library cannot 280*12508Samw@Sun.COM * confirm or deny the presence of a namespace, so let's take 281*12508Samw@Sun.COM * the safe approach and assume one exists. 282*12508Samw@Sun.COM */ 283*12508Samw@Sun.COM nroot = 1; 284*12508Samw@Sun.COM syslog(LOG_WARNING, "dfs: dfsops_remote_count() failed: %d, " 285*12508Samw@Sun.COM "assuming one namespace exists", rc); 286*12508Samw@Sun.COM } 28711963SAfshin.Ardakani@Sun.COM 28811963SAfshin.Ardakani@Sun.COM smb_shr_iterinit(&shi); 28911963SAfshin.Ardakani@Sun.COM while ((si = smb_shr_iterate(&shi)) != NULL) { 29011963SAfshin.Ardakani@Sun.COM if ((si->shr_flags & SMB_SHRF_DFSROOT) != 0) 29111963SAfshin.Ardakani@Sun.COM nroot++; 29211963SAfshin.Ardakani@Sun.COM } 29311963SAfshin.Ardakani@Sun.COM 29411963SAfshin.Ardakani@Sun.COM return (nroot); 29511963SAfshin.Ardakani@Sun.COM } 29611963SAfshin.Ardakani@Sun.COM 29711963SAfshin.Ardakani@Sun.COM /* 29811963SAfshin.Ardakani@Sun.COM * Creates a DFS root with the given name and comment. 29911963SAfshin.Ardakani@Sun.COM * 30011963SAfshin.Ardakani@Sun.COM * This function does not create the root share, it 30111963SAfshin.Ardakani@Sun.COM * should already exist. 30211963SAfshin.Ardakani@Sun.COM */ 30311963SAfshin.Ardakani@Sun.COM uint32_t 30411963SAfshin.Ardakani@Sun.COM dfs_namespace_add(const char *rootshr, const char *cmnt) 30511963SAfshin.Ardakani@Sun.COM { 30611963SAfshin.Ardakani@Sun.COM dfs_info_t info; 30711963SAfshin.Ardakani@Sun.COM dfs_target_t t; 30811963SAfshin.Ardakani@Sun.COM smb_share_t si; 30911963SAfshin.Ardakani@Sun.COM uuid_t uuid; 31011963SAfshin.Ardakani@Sun.COM uint32_t status; 31111963SAfshin.Ardakani@Sun.COM 31211963SAfshin.Ardakani@Sun.COM if (*rootshr == '\\') { 31311963SAfshin.Ardakani@Sun.COM /* Windows has a special case here! */ 31411963SAfshin.Ardakani@Sun.COM return (ERROR_BAD_PATHNAME); 31511963SAfshin.Ardakani@Sun.COM } 31611963SAfshin.Ardakani@Sun.COM 31711963SAfshin.Ardakani@Sun.COM if (smb_shr_get((char *)rootshr, &si) != NERR_Success) 31811963SAfshin.Ardakani@Sun.COM return (NERR_NetNameNotFound); 31911963SAfshin.Ardakani@Sun.COM 32011963SAfshin.Ardakani@Sun.COM if (si.shr_flags & SMB_SHRF_DFSROOT) { 32111963SAfshin.Ardakani@Sun.COM /* Share is already a DFS root */ 32211963SAfshin.Ardakani@Sun.COM return (ERROR_FILE_EXISTS); 32311963SAfshin.Ardakani@Sun.COM } 32411963SAfshin.Ardakani@Sun.COM 32511963SAfshin.Ardakani@Sun.COM bzero(&info, sizeof (info)); 32611963SAfshin.Ardakani@Sun.COM if (cmnt) 32711963SAfshin.Ardakani@Sun.COM (void) strlcpy(info.i_comment, cmnt, sizeof (info.i_comment)); 32811963SAfshin.Ardakani@Sun.COM info.i_state = DFS_VOLUME_STATE_OK | DFS_VOLUME_FLAVOR_STANDALONE; 32911963SAfshin.Ardakani@Sun.COM info.i_timeout = DFS_ROOT_TIMEOUT; 33011963SAfshin.Ardakani@Sun.COM info.i_propflags = 0; 33111963SAfshin.Ardakani@Sun.COM 33211963SAfshin.Ardakani@Sun.COM uuid_generate_random(uuid); 33311963SAfshin.Ardakani@Sun.COM uuid_unparse(uuid, info.i_guid); 33411963SAfshin.Ardakani@Sun.COM 33511963SAfshin.Ardakani@Sun.COM dfs_target_init(&t, dfs_nbname, rootshr, DFS_STORAGE_STATE_ONLINE); 33611963SAfshin.Ardakani@Sun.COM 33711963SAfshin.Ardakani@Sun.COM info.i_ntargets = 1; 33811963SAfshin.Ardakani@Sun.COM info.i_targets = &t; 33911963SAfshin.Ardakani@Sun.COM 34011963SAfshin.Ardakani@Sun.COM if ((status = dfs_root_add(si.shr_path, &info)) != ERROR_SUCCESS) 34111963SAfshin.Ardakani@Sun.COM return (status); 34211963SAfshin.Ardakani@Sun.COM 34311963SAfshin.Ardakani@Sun.COM status = srvsvc_shr_setdfsroot(&si, B_TRUE); 34411963SAfshin.Ardakani@Sun.COM if (status == ERROR_SUCCESS) 34511963SAfshin.Ardakani@Sun.COM (void) dfs_cache_add_byname(rootshr, NULL, DFS_OBJECT_ROOT); 34611963SAfshin.Ardakani@Sun.COM 34711963SAfshin.Ardakani@Sun.COM return (status); 34811963SAfshin.Ardakani@Sun.COM } 34911963SAfshin.Ardakani@Sun.COM 35011963SAfshin.Ardakani@Sun.COM /* 35111963SAfshin.Ardakani@Sun.COM * Removes the namespace and all the links in it. 35211963SAfshin.Ardakani@Sun.COM */ 35311963SAfshin.Ardakani@Sun.COM uint32_t 35411963SAfshin.Ardakani@Sun.COM dfs_namespace_remove(const char *name) 35511963SAfshin.Ardakani@Sun.COM { 35611963SAfshin.Ardakani@Sun.COM smb_cache_cursor_t cursor; 35711963SAfshin.Ardakani@Sun.COM dfs_nscnode_t nscnode; 35811963SAfshin.Ardakani@Sun.COM smb_share_t si; 35911963SAfshin.Ardakani@Sun.COM uint32_t status; 36011963SAfshin.Ardakani@Sun.COM 36111963SAfshin.Ardakani@Sun.COM if (smb_shr_get((char *)name, &si) != NERR_Success) 36211963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND); 36311963SAfshin.Ardakani@Sun.COM 36411963SAfshin.Ardakani@Sun.COM if ((si.shr_flags & SMB_SHRF_DFSROOT) == 0) 36511963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND); 36611963SAfshin.Ardakani@Sun.COM 36711963SAfshin.Ardakani@Sun.COM if ((status = dfs_root_remove(si.shr_path)) != ERROR_SUCCESS) 36811963SAfshin.Ardakani@Sun.COM return (status); 36911963SAfshin.Ardakani@Sun.COM 37011963SAfshin.Ardakani@Sun.COM status = srvsvc_shr_setdfsroot(&si, B_FALSE); 37111963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) 37211963SAfshin.Ardakani@Sun.COM syslog(LOG_WARNING, "dfs: failed to disable root share %s (%d)", 37311963SAfshin.Ardakani@Sun.COM name, status); 37411963SAfshin.Ardakani@Sun.COM 37511963SAfshin.Ardakani@Sun.COM smb_cache_iterinit(&dfs_nscache, &cursor); 37611963SAfshin.Ardakani@Sun.COM 37711963SAfshin.Ardakani@Sun.COM while (smb_cache_iterate(&dfs_nscache, &cursor, &nscnode)) { 37811963SAfshin.Ardakani@Sun.COM if (nscnode.nsc_type == DFS_OBJECT_ROOT) 37911963SAfshin.Ardakani@Sun.COM continue; 38011963SAfshin.Ardakani@Sun.COM status = dfs_link_remove(nscnode.nsc_fspath, NULL, NULL); 38111963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) 38211963SAfshin.Ardakani@Sun.COM syslog(LOG_WARNING, "dfs: failed to remove %s (%d)", 38311963SAfshin.Ardakani@Sun.COM nscnode.nsc_fspath, status); 38411963SAfshin.Ardakani@Sun.COM } 38511963SAfshin.Ardakani@Sun.COM 38611963SAfshin.Ardakani@Sun.COM smb_cache_flush(&dfs_nscache); 38711963SAfshin.Ardakani@Sun.COM 38811963SAfshin.Ardakani@Sun.COM /* TODO: remove empty dirs */ 38911963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 39011963SAfshin.Ardakani@Sun.COM } 39111963SAfshin.Ardakani@Sun.COM 39211963SAfshin.Ardakani@Sun.COM /* 39311963SAfshin.Ardakani@Sun.COM * ================== 39411963SAfshin.Ardakani@Sun.COM * Root API (public) 39511963SAfshin.Ardakani@Sun.COM * ================== 39611963SAfshin.Ardakani@Sun.COM */ 39711963SAfshin.Ardakani@Sun.COM 39811963SAfshin.Ardakani@Sun.COM /* 39911963SAfshin.Ardakani@Sun.COM * Retrieves the information of the root specified by its path. 40011963SAfshin.Ardakani@Sun.COM * 40111963SAfshin.Ardakani@Sun.COM * Info level (1) only needs the UNC path which is not stored, 40211963SAfshin.Ardakani@Sun.COM * it is constructed so the function will return without 40311963SAfshin.Ardakani@Sun.COM * accessing the backend storage. 40411963SAfshin.Ardakani@Sun.COM */ 40511963SAfshin.Ardakani@Sun.COM uint32_t 40611963SAfshin.Ardakani@Sun.COM dfs_root_getinfo(const char *rootdir, dfs_info_t *info, uint32_t infolvl) 40711963SAfshin.Ardakani@Sun.COM { 40811963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_INTERNAL_ERROR; 40911963SAfshin.Ardakani@Sun.COM int xfd; 41011963SAfshin.Ardakani@Sun.COM 41111963SAfshin.Ardakani@Sun.COM bzero(info, sizeof (dfs_info_t)); 41211963SAfshin.Ardakani@Sun.COM info->i_type = DFS_OBJECT_ROOT; 41311963SAfshin.Ardakani@Sun.COM 41411963SAfshin.Ardakani@Sun.COM if (infolvl == 1) 41511963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 41611963SAfshin.Ardakani@Sun.COM 41711963SAfshin.Ardakani@Sun.COM (void) rw_rdlock(&dfs_root_rwl); 41811963SAfshin.Ardakani@Sun.COM if ((xfd = dfs_root_xopen(rootdir, O_RDONLY)) > 0) { 41911963SAfshin.Ardakani@Sun.COM status = dfs_root_xread(xfd, info, infolvl); 42011963SAfshin.Ardakani@Sun.COM dfs_root_xclose(xfd); 42111963SAfshin.Ardakani@Sun.COM } 42211963SAfshin.Ardakani@Sun.COM (void) rw_unlock(&dfs_root_rwl); 42311963SAfshin.Ardakani@Sun.COM 42411963SAfshin.Ardakani@Sun.COM return (status); 42511963SAfshin.Ardakani@Sun.COM } 42611963SAfshin.Ardakani@Sun.COM 42711963SAfshin.Ardakani@Sun.COM /* 42811963SAfshin.Ardakani@Sun.COM * Sets the provided information for the specified root or root target. 42911963SAfshin.Ardakani@Sun.COM * Root is specified by 'rootdir' and the target is specified by 43011963SAfshin.Ardakani@Sun.COM * (t_server, t_share) pair. Only information items needed for given 43111963SAfshin.Ardakani@Sun.COM * information level (infolvl) is valid in the passed DFS info structure 43211963SAfshin.Ardakani@Sun.COM * 'info'. 43311963SAfshin.Ardakani@Sun.COM */ 43411963SAfshin.Ardakani@Sun.COM uint32_t 43511963SAfshin.Ardakani@Sun.COM dfs_root_setinfo(const char *rootdir, dfs_info_t *info, uint32_t infolvl) 43611963SAfshin.Ardakani@Sun.COM { 43711963SAfshin.Ardakani@Sun.COM dfs_info_t curinfo; 43811963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_SUCCESS; 43911963SAfshin.Ardakani@Sun.COM int xfd; 44011963SAfshin.Ardakani@Sun.COM 44111963SAfshin.Ardakani@Sun.COM (void) rw_wrlock(&dfs_root_rwl); 44211963SAfshin.Ardakani@Sun.COM if ((xfd = dfs_root_xopen(rootdir, O_RDWR)) < 0) { 44311963SAfshin.Ardakani@Sun.COM (void) rw_unlock(&dfs_root_rwl); 44411963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 44511963SAfshin.Ardakani@Sun.COM } 44611963SAfshin.Ardakani@Sun.COM 44711963SAfshin.Ardakani@Sun.COM status = dfs_root_xread(xfd, &curinfo, DFS_INFO_ALL); 44811963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) { 44911963SAfshin.Ardakani@Sun.COM dfs_root_xclose(xfd); 45011963SAfshin.Ardakani@Sun.COM (void) rw_unlock(&dfs_root_rwl); 45111963SAfshin.Ardakani@Sun.COM return (status); 45211963SAfshin.Ardakani@Sun.COM } 45311963SAfshin.Ardakani@Sun.COM 45411963SAfshin.Ardakani@Sun.COM status = dfs_modinfo(DFS_OBJECT_ROOT, &curinfo, info, infolvl); 45511963SAfshin.Ardakani@Sun.COM if (status == ERROR_SUCCESS) 45611963SAfshin.Ardakani@Sun.COM status = dfs_root_xwrite(xfd, &curinfo); 45711963SAfshin.Ardakani@Sun.COM 45811963SAfshin.Ardakani@Sun.COM dfs_root_xclose(xfd); 45911963SAfshin.Ardakani@Sun.COM (void) rw_unlock(&dfs_root_rwl); 46011963SAfshin.Ardakani@Sun.COM 46111963SAfshin.Ardakani@Sun.COM dfs_info_free(&curinfo); 46211963SAfshin.Ardakani@Sun.COM return (status); 46311963SAfshin.Ardakani@Sun.COM } 46411963SAfshin.Ardakani@Sun.COM 46511963SAfshin.Ardakani@Sun.COM /* 46611963SAfshin.Ardakani@Sun.COM * ================== 46711963SAfshin.Ardakani@Sun.COM * Link API (public) 46811963SAfshin.Ardakani@Sun.COM * ================== 46911963SAfshin.Ardakani@Sun.COM */ 47011963SAfshin.Ardakani@Sun.COM 47111963SAfshin.Ardakani@Sun.COM /* 47211963SAfshin.Ardakani@Sun.COM * Gets the status of the given path as a link 47311963SAfshin.Ardakani@Sun.COM */ 47411963SAfshin.Ardakani@Sun.COM uint32_t 47511963SAfshin.Ardakani@Sun.COM dfs_link_stat(const char *path, uint32_t *stat) 47611963SAfshin.Ardakani@Sun.COM { 47711963SAfshin.Ardakani@Sun.COM if (smb_reparse_stat(path, stat) != 0) 47811963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 47911963SAfshin.Ardakani@Sun.COM 48011963SAfshin.Ardakani@Sun.COM switch (*stat) { 48111963SAfshin.Ardakani@Sun.COM case SMB_REPARSE_NOTFOUND: 48211963SAfshin.Ardakani@Sun.COM *stat = DFS_STAT_NOTFOUND; 48311963SAfshin.Ardakani@Sun.COM break; 48411963SAfshin.Ardakani@Sun.COM case SMB_REPARSE_NOTREPARSE: 48511963SAfshin.Ardakani@Sun.COM *stat = DFS_STAT_NOTLINK; 48611963SAfshin.Ardakani@Sun.COM break; 48711963SAfshin.Ardakani@Sun.COM case SMB_REPARSE_ISREPARSE: 48811963SAfshin.Ardakani@Sun.COM *stat = DFS_STAT_ISREPARSE; 48911963SAfshin.Ardakani@Sun.COM if (smb_reparse_svcget(path, DFS_REPARSE_SVCTYPE, NULL) == 0) 49011963SAfshin.Ardakani@Sun.COM *stat = DFS_STAT_ISDFS; 49111963SAfshin.Ardakani@Sun.COM break; 49211963SAfshin.Ardakani@Sun.COM default: 49311963SAfshin.Ardakani@Sun.COM *stat = DFS_STAT_UNKNOWN; 49411963SAfshin.Ardakani@Sun.COM break; 49511963SAfshin.Ardakani@Sun.COM } 49611963SAfshin.Ardakani@Sun.COM 49711963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 49811963SAfshin.Ardakani@Sun.COM } 49911963SAfshin.Ardakani@Sun.COM 50011963SAfshin.Ardakani@Sun.COM /* 50111963SAfshin.Ardakani@Sun.COM * Creates a new DFS link or adds a new target to an existing link 50211963SAfshin.Ardakani@Sun.COM */ 50311963SAfshin.Ardakani@Sun.COM uint32_t 50411963SAfshin.Ardakani@Sun.COM dfs_link_add(const char *path, const char *server, const char *share, 50511963SAfshin.Ardakani@Sun.COM const char *cmnt, uint32_t flags, boolean_t *newlink) 50611963SAfshin.Ardakani@Sun.COM { 50711963SAfshin.Ardakani@Sun.COM dfs_info_t info; 50811963SAfshin.Ardakani@Sun.COM dfs_target_t *t; 50911963SAfshin.Ardakani@Sun.COM int ntargets; 51011963SAfshin.Ardakani@Sun.COM uint32_t status; 51111963SAfshin.Ardakani@Sun.COM uint32_t stat; 51211963SAfshin.Ardakani@Sun.COM 51311963SAfshin.Ardakani@Sun.COM *newlink = B_FALSE; 51411963SAfshin.Ardakani@Sun.COM 51511963SAfshin.Ardakani@Sun.COM if ((status = dfs_link_stat(path, &stat)) != ERROR_SUCCESS) 51611963SAfshin.Ardakani@Sun.COM return (status); 51711963SAfshin.Ardakani@Sun.COM 51811963SAfshin.Ardakani@Sun.COM switch (stat) { 51911963SAfshin.Ardakani@Sun.COM case DFS_STAT_NOTFOUND: 52011963SAfshin.Ardakani@Sun.COM case DFS_STAT_ISREPARSE: 52111963SAfshin.Ardakani@Sun.COM /* Create a new DFS link */ 52211963SAfshin.Ardakani@Sun.COM 52311963SAfshin.Ardakani@Sun.COM status = dfs_link_getinfo(NULL, &info, DFS_INFO_ALL); 52411963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) 52511963SAfshin.Ardakani@Sun.COM return (status); 52611963SAfshin.Ardakani@Sun.COM 52711963SAfshin.Ardakani@Sun.COM (void) strlcpy(info.i_comment, (cmnt) ? cmnt : "", 52811963SAfshin.Ardakani@Sun.COM sizeof (info.i_comment)); 52911963SAfshin.Ardakani@Sun.COM *newlink = B_TRUE; 53011963SAfshin.Ardakani@Sun.COM break; 53111963SAfshin.Ardakani@Sun.COM 53211963SAfshin.Ardakani@Sun.COM case DFS_STAT_ISDFS: 53311963SAfshin.Ardakani@Sun.COM /* Add a target to an existing link */ 53411963SAfshin.Ardakani@Sun.COM 53511963SAfshin.Ardakani@Sun.COM if (flags & DFS_ADD_VOLUME) 53611963SAfshin.Ardakani@Sun.COM return (ERROR_FILE_EXISTS); 53711963SAfshin.Ardakani@Sun.COM 53811963SAfshin.Ardakani@Sun.COM status = dfs_link_getinfo(path, &info, DFS_INFO_ALL); 53911963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) 54011963SAfshin.Ardakani@Sun.COM return (status); 54111963SAfshin.Ardakani@Sun.COM 54211963SAfshin.Ardakani@Sun.COM break; 54311963SAfshin.Ardakani@Sun.COM 54411963SAfshin.Ardakani@Sun.COM case DFS_STAT_NOTLINK: 54511963SAfshin.Ardakani@Sun.COM /* specified path points to a non-reparse object */ 54611963SAfshin.Ardakani@Sun.COM return (ERROR_FILE_EXISTS); 54711963SAfshin.Ardakani@Sun.COM 54811963SAfshin.Ardakani@Sun.COM default: 54911963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 55011963SAfshin.Ardakani@Sun.COM } 55111963SAfshin.Ardakani@Sun.COM 55211963SAfshin.Ardakani@Sun.COM /* checks to see if the target already exists */ 55311963SAfshin.Ardakani@Sun.COM ntargets = info.i_ntargets; 55411963SAfshin.Ardakani@Sun.COM if (dfs_target_find(info.i_targets, ntargets, server, share) != -1) { 55511963SAfshin.Ardakani@Sun.COM dfs_info_free(&info); 55611963SAfshin.Ardakani@Sun.COM return (ERROR_FILE_EXISTS); 55711963SAfshin.Ardakani@Sun.COM } 55811963SAfshin.Ardakani@Sun.COM 55911963SAfshin.Ardakani@Sun.COM /* add the new target */ 56011963SAfshin.Ardakani@Sun.COM t = realloc(info.i_targets, (ntargets + 1) * sizeof (dfs_target_t)); 56111963SAfshin.Ardakani@Sun.COM if (t == NULL) { 56211963SAfshin.Ardakani@Sun.COM dfs_info_free(&info); 56311963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY); 56411963SAfshin.Ardakani@Sun.COM } 56511963SAfshin.Ardakani@Sun.COM 56611963SAfshin.Ardakani@Sun.COM info.i_targets = t; 56711963SAfshin.Ardakani@Sun.COM dfs_target_init(&info.i_targets[ntargets], server, share, 56811963SAfshin.Ardakani@Sun.COM DFS_STORAGE_STATE_ONLINE); 56911963SAfshin.Ardakani@Sun.COM info.i_ntargets++; 57011963SAfshin.Ardakani@Sun.COM 57111963SAfshin.Ardakani@Sun.COM status = dfs_link_commit(path, &info); 57211963SAfshin.Ardakani@Sun.COM 57311963SAfshin.Ardakani@Sun.COM dfs_info_free(&info); 57411963SAfshin.Ardakani@Sun.COM return (status); 57511963SAfshin.Ardakani@Sun.COM } 57611963SAfshin.Ardakani@Sun.COM 57711963SAfshin.Ardakani@Sun.COM /* 57811963SAfshin.Ardakani@Sun.COM * Removes a link or a link target from a DFS namespace. A link can be 57911963SAfshin.Ardakani@Sun.COM * removed regardless of the number of targets associated with it. 58011963SAfshin.Ardakani@Sun.COM * 58111963SAfshin.Ardakani@Sun.COM * 'server' and 'share' parameters specify a target, so if they are NULL 58211963SAfshin.Ardakani@Sun.COM * it means the link should be removed, otherwise the specified target 58311963SAfshin.Ardakani@Sun.COM * is removed if found. 58411963SAfshin.Ardakani@Sun.COM */ 58511963SAfshin.Ardakani@Sun.COM uint32_t 58611963SAfshin.Ardakani@Sun.COM dfs_link_remove(const char *path, const char *server, const char *share) 58711963SAfshin.Ardakani@Sun.COM { 58811963SAfshin.Ardakani@Sun.COM dfs_info_t info; 58911963SAfshin.Ardakani@Sun.COM uint32_t status, stat; 59011963SAfshin.Ardakani@Sun.COM int rc, idx; 59111963SAfshin.Ardakani@Sun.COM 59211963SAfshin.Ardakani@Sun.COM if ((status = dfs_link_stat(path, &stat)) != ERROR_SUCCESS) 59311963SAfshin.Ardakani@Sun.COM return (status); 59411963SAfshin.Ardakani@Sun.COM 59511963SAfshin.Ardakani@Sun.COM if (stat != DFS_STAT_ISDFS) 59611963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND); 59711963SAfshin.Ardakani@Sun.COM 59811963SAfshin.Ardakani@Sun.COM if (server == NULL && share == NULL) { 59911963SAfshin.Ardakani@Sun.COM /* remove the link */ 60011963SAfshin.Ardakani@Sun.COM if (smb_reparse_svcdel(path, DFS_REPARSE_SVCTYPE) != 0) 60111963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 60211963SAfshin.Ardakani@Sun.COM 60311963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 60411963SAfshin.Ardakani@Sun.COM } 60511963SAfshin.Ardakani@Sun.COM 60611963SAfshin.Ardakani@Sun.COM /* remove the specified target in the link */ 60711963SAfshin.Ardakani@Sun.COM 60811963SAfshin.Ardakani@Sun.COM status = dfs_link_getinfo(path, &info, DFS_INFO_ALL); 60911963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) 61011963SAfshin.Ardakani@Sun.COM return (status); 61111963SAfshin.Ardakani@Sun.COM 61211963SAfshin.Ardakani@Sun.COM /* checks to see if the target exists */ 61311963SAfshin.Ardakani@Sun.COM idx = dfs_target_find(info.i_targets, info.i_ntargets, server, share); 61411963SAfshin.Ardakani@Sun.COM if (idx != -1) { 61511963SAfshin.Ardakani@Sun.COM bcopy(&info.i_targets[idx + 1], &info.i_targets[idx], 61611963SAfshin.Ardakani@Sun.COM (info.i_ntargets - idx - 1) * sizeof (dfs_target_t)); 61711963SAfshin.Ardakani@Sun.COM info.i_ntargets--; 61811963SAfshin.Ardakani@Sun.COM } else { 61911963SAfshin.Ardakani@Sun.COM dfs_info_free(&info); 62011963SAfshin.Ardakani@Sun.COM return (ERROR_FILE_NOT_FOUND); 62111963SAfshin.Ardakani@Sun.COM } 62211963SAfshin.Ardakani@Sun.COM 62311963SAfshin.Ardakani@Sun.COM if (info.i_ntargets == 0) { 62411963SAfshin.Ardakani@Sun.COM /* if last target, then remove the link */ 62511963SAfshin.Ardakani@Sun.COM rc = smb_reparse_svcdel(path, DFS_REPARSE_SVCTYPE); 62611963SAfshin.Ardakani@Sun.COM status = (rc == 0) ? ERROR_SUCCESS : ERROR_INTERNAL_ERROR; 62711963SAfshin.Ardakani@Sun.COM } else { 62811963SAfshin.Ardakani@Sun.COM status = dfs_link_commit(path, &info); 62911963SAfshin.Ardakani@Sun.COM } 63011963SAfshin.Ardakani@Sun.COM 63111963SAfshin.Ardakani@Sun.COM dfs_info_free(&info); 63211963SAfshin.Ardakani@Sun.COM return (status); 63311963SAfshin.Ardakani@Sun.COM } 63411963SAfshin.Ardakani@Sun.COM 63511963SAfshin.Ardakani@Sun.COM /* 63611963SAfshin.Ardakani@Sun.COM * Sets the provided information for the specified link or link target. 63711963SAfshin.Ardakani@Sun.COM * Link is specified by 'path' and the target is specified by 63811963SAfshin.Ardakani@Sun.COM * (t_server, t_share) pair. Only information items needed for given 63911963SAfshin.Ardakani@Sun.COM * information level (infolvl) is valid in the passed DFS info structure 64011963SAfshin.Ardakani@Sun.COM * 'info'. 64111963SAfshin.Ardakani@Sun.COM */ 64211963SAfshin.Ardakani@Sun.COM uint32_t 64311963SAfshin.Ardakani@Sun.COM dfs_link_setinfo(const char *path, dfs_info_t *info, uint32_t infolvl) 64411963SAfshin.Ardakani@Sun.COM { 64511963SAfshin.Ardakani@Sun.COM dfs_info_t curinfo; 64611963SAfshin.Ardakani@Sun.COM uint32_t status; 64711963SAfshin.Ardakani@Sun.COM 64811963SAfshin.Ardakani@Sun.COM status = dfs_link_getinfo(path, &curinfo, DFS_INFO_ALL); 64911963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) 65011963SAfshin.Ardakani@Sun.COM return (status); 65111963SAfshin.Ardakani@Sun.COM 65211963SAfshin.Ardakani@Sun.COM status = dfs_modinfo(DFS_OBJECT_LINK, &curinfo, info, infolvl); 65311963SAfshin.Ardakani@Sun.COM if (status == ERROR_SUCCESS) 65411963SAfshin.Ardakani@Sun.COM status = dfs_link_commit(path, &curinfo); 65511963SAfshin.Ardakani@Sun.COM 65611963SAfshin.Ardakani@Sun.COM dfs_info_free(&curinfo); 65711963SAfshin.Ardakani@Sun.COM return (status); 65811963SAfshin.Ardakani@Sun.COM } 65911963SAfshin.Ardakani@Sun.COM 66011963SAfshin.Ardakani@Sun.COM /* 66111963SAfshin.Ardakani@Sun.COM * Gets the DFS link info. 66211963SAfshin.Ardakani@Sun.COM * 66311963SAfshin.Ardakani@Sun.COM * If path is NULL, it just does some initialization. 66411963SAfshin.Ardakani@Sun.COM * 66511963SAfshin.Ardakani@Sun.COM * Info level (1) only needs the UNC path which is not 66611963SAfshin.Ardakani@Sun.COM * stored, it is constructed so the function will return 66711963SAfshin.Ardakani@Sun.COM * without accessing the backend storage. 66811963SAfshin.Ardakani@Sun.COM */ 66911963SAfshin.Ardakani@Sun.COM uint32_t 67011963SAfshin.Ardakani@Sun.COM dfs_link_getinfo(const char *path, dfs_info_t *info, uint32_t infolvl) 67111963SAfshin.Ardakani@Sun.COM { 67211963SAfshin.Ardakani@Sun.COM char *link_data; 67311963SAfshin.Ardakani@Sun.COM uint32_t status; 67411963SAfshin.Ardakani@Sun.COM uuid_t uuid; 67511963SAfshin.Ardakani@Sun.COM int rc; 67611963SAfshin.Ardakani@Sun.COM 67711963SAfshin.Ardakani@Sun.COM bzero(info, sizeof (dfs_info_t)); 67811963SAfshin.Ardakani@Sun.COM info->i_type = DFS_OBJECT_LINK; 67911963SAfshin.Ardakani@Sun.COM 68011963SAfshin.Ardakani@Sun.COM if (path == NULL) { 68111963SAfshin.Ardakani@Sun.COM info->i_state = DFS_VOLUME_STATE_OK; 68211963SAfshin.Ardakani@Sun.COM info->i_timeout = DFS_LINK_TIMEOUT; 68311963SAfshin.Ardakani@Sun.COM info->i_propflags = 0; 68411963SAfshin.Ardakani@Sun.COM uuid_generate_random(uuid); 68511963SAfshin.Ardakani@Sun.COM uuid_unparse(uuid, info->i_guid); 68611963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 68711963SAfshin.Ardakani@Sun.COM } 68811963SAfshin.Ardakani@Sun.COM 68911963SAfshin.Ardakani@Sun.COM if (infolvl == 1) 69011963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 69111963SAfshin.Ardakani@Sun.COM 69211963SAfshin.Ardakani@Sun.COM rc = smb_reparse_svcget(path, DFS_REPARSE_SVCTYPE, &link_data); 69311963SAfshin.Ardakani@Sun.COM if (rc != 0) 69411963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 69511963SAfshin.Ardakani@Sun.COM 69611963SAfshin.Ardakani@Sun.COM status = dfs_link_decode(info, link_data, infolvl); 69711963SAfshin.Ardakani@Sun.COM free(link_data); 69811963SAfshin.Ardakani@Sun.COM 69911963SAfshin.Ardakani@Sun.COM return (status); 70011963SAfshin.Ardakani@Sun.COM } 70111963SAfshin.Ardakani@Sun.COM 70211963SAfshin.Ardakani@Sun.COM /* 70311963SAfshin.Ardakani@Sun.COM * =================== 70411963SAfshin.Ardakani@Sun.COM * Cache API (public) 70511963SAfshin.Ardakani@Sun.COM * =================== 70611963SAfshin.Ardakani@Sun.COM */ 70711963SAfshin.Ardakani@Sun.COM 70811963SAfshin.Ardakani@Sun.COM /* 70911963SAfshin.Ardakani@Sun.COM * Adds an entry with given DFS name (root sharename) and relative path 71011963SAfshin.Ardakani@Sun.COM * to the share (relpath) and the specified entry type (i.e. root/link) 71111963SAfshin.Ardakani@Sun.COM * to the namespace cache. 71211963SAfshin.Ardakani@Sun.COM */ 71311963SAfshin.Ardakani@Sun.COM uint32_t 71411963SAfshin.Ardakani@Sun.COM dfs_cache_add_byname(const char *name, const char *relpath, uint32_t type) 71511963SAfshin.Ardakani@Sun.COM { 71611963SAfshin.Ardakani@Sun.COM char uncpath[DFS_PATH_MAX]; 71711963SAfshin.Ardakani@Sun.COM char fspath[DFS_PATH_MAX]; 71811963SAfshin.Ardakani@Sun.COM smb_share_t si; 71911963SAfshin.Ardakani@Sun.COM 72011963SAfshin.Ardakani@Sun.COM if (smb_shr_get((char *)name, &si) != NERR_Success) 72111963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND); 72211963SAfshin.Ardakani@Sun.COM 72311963SAfshin.Ardakani@Sun.COM if (type == DFS_OBJECT_ROOT) { 72411963SAfshin.Ardakani@Sun.COM (void) snprintf(uncpath, DFS_PATH_MAX, "\\\\%s\\%s", 72511963SAfshin.Ardakani@Sun.COM dfs_nbname, name); 72611963SAfshin.Ardakani@Sun.COM return (dfs_cache_add_byunc(uncpath, si.shr_path, type)); 72711963SAfshin.Ardakani@Sun.COM } 72811963SAfshin.Ardakani@Sun.COM 72911963SAfshin.Ardakani@Sun.COM /* add link entry */ 73011963SAfshin.Ardakani@Sun.COM (void) snprintf(fspath, DFS_PATH_MAX, "%s/%s", si.shr_path, relpath); 73111963SAfshin.Ardakani@Sun.COM (void) snprintf(uncpath, DFS_PATH_MAX, "\\\\%s\\%s\\%s", dfs_nbname, 73211963SAfshin.Ardakani@Sun.COM name, relpath); 73311963SAfshin.Ardakani@Sun.COM 73411963SAfshin.Ardakani@Sun.COM /* relpath may contain '/' */ 73511963SAfshin.Ardakani@Sun.COM (void) strsubst(uncpath, '/', '\\'); 73611963SAfshin.Ardakani@Sun.COM 73711963SAfshin.Ardakani@Sun.COM return (dfs_cache_add_byunc(uncpath, fspath, type)); 73811963SAfshin.Ardakani@Sun.COM } 73911963SAfshin.Ardakani@Sun.COM 74011963SAfshin.Ardakani@Sun.COM /* 74111963SAfshin.Ardakani@Sun.COM * Removes the namespace cache entry for the given link 74211963SAfshin.Ardakani@Sun.COM * in the namespace ('name') with 'relpath' 74311963SAfshin.Ardakani@Sun.COM */ 74411963SAfshin.Ardakani@Sun.COM void 74511963SAfshin.Ardakani@Sun.COM dfs_cache_remove(const char *name, const char *relpath) 74611963SAfshin.Ardakani@Sun.COM { 74711963SAfshin.Ardakani@Sun.COM dfs_nscnode_t dn; 74811963SAfshin.Ardakani@Sun.COM 74911963SAfshin.Ardakani@Sun.COM (void) snprintf(dn.nsc_uncpath, sizeof (dn.nsc_uncpath), 75011963SAfshin.Ardakani@Sun.COM "\\\\%s\\%s\\%s", dfs_nbname, name, relpath); 75111963SAfshin.Ardakani@Sun.COM 75211963SAfshin.Ardakani@Sun.COM /* relpath may contain '/' */ 75311963SAfshin.Ardakani@Sun.COM (void) strsubst(dn.nsc_uncpath, '/', '\\'); 75411963SAfshin.Ardakani@Sun.COM 75511963SAfshin.Ardakani@Sun.COM smb_cache_remove(&dfs_nscache, &dn); 75611963SAfshin.Ardakani@Sun.COM } 75711963SAfshin.Ardakani@Sun.COM 75811963SAfshin.Ardakani@Sun.COM /* 75911963SAfshin.Ardakani@Sun.COM * Get the DFS data for the specified cache entry 76011963SAfshin.Ardakani@Sun.COM */ 76111963SAfshin.Ardakani@Sun.COM uint32_t 76211963SAfshin.Ardakani@Sun.COM dfs_cache_getinfo(dfs_nscnode_t *dn, dfs_info_t *info, uint32_t infolvl) 76311963SAfshin.Ardakani@Sun.COM { 76411963SAfshin.Ardakani@Sun.COM uint32_t status; 76511963SAfshin.Ardakani@Sun.COM 76611963SAfshin.Ardakani@Sun.COM if (dn->nsc_type == DFS_OBJECT_LINK) 76711963SAfshin.Ardakani@Sun.COM status = dfs_link_getinfo(dn->nsc_fspath, info, infolvl); 76811963SAfshin.Ardakani@Sun.COM else 76911963SAfshin.Ardakani@Sun.COM status = dfs_root_getinfo(dn->nsc_fspath, info, infolvl); 77011963SAfshin.Ardakani@Sun.COM 77111963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_uncpath, dn->nsc_uncpath, 77211963SAfshin.Ardakani@Sun.COM sizeof (info->i_uncpath)); 77311963SAfshin.Ardakani@Sun.COM 77411963SAfshin.Ardakani@Sun.COM if (status == ERROR_SUCCESS) 77511963SAfshin.Ardakani@Sun.COM dfs_info_trace("dfs_cache_getinfo", info); 77611963SAfshin.Ardakani@Sun.COM 77711963SAfshin.Ardakani@Sun.COM return (status); 77811963SAfshin.Ardakani@Sun.COM } 77911963SAfshin.Ardakani@Sun.COM 78011963SAfshin.Ardakani@Sun.COM /* 78111963SAfshin.Ardakani@Sun.COM * Returns the number of cache entries i.e. the number of 78211963SAfshin.Ardakani@Sun.COM * root(s) and link(s) 78311963SAfshin.Ardakani@Sun.COM */ 78411963SAfshin.Ardakani@Sun.COM uint32_t 78511963SAfshin.Ardakani@Sun.COM dfs_cache_num(void) 78611963SAfshin.Ardakani@Sun.COM { 78711963SAfshin.Ardakani@Sun.COM return (smb_cache_num(&dfs_nscache)); 78811963SAfshin.Ardakani@Sun.COM } 78911963SAfshin.Ardakani@Sun.COM 79011963SAfshin.Ardakani@Sun.COM void 79111963SAfshin.Ardakani@Sun.COM dfs_cache_iterinit(smb_cache_cursor_t *cursor) 79211963SAfshin.Ardakani@Sun.COM { 79311963SAfshin.Ardakani@Sun.COM smb_cache_iterinit(&dfs_nscache, cursor); 79411963SAfshin.Ardakani@Sun.COM } 79511963SAfshin.Ardakani@Sun.COM 79611963SAfshin.Ardakani@Sun.COM boolean_t 79711963SAfshin.Ardakani@Sun.COM dfs_cache_iterate(smb_cache_cursor_t *cursor, dfs_nscnode_t *dn) 79811963SAfshin.Ardakani@Sun.COM { 79911963SAfshin.Ardakani@Sun.COM return (smb_cache_iterate(&dfs_nscache, cursor, dn)); 80011963SAfshin.Ardakani@Sun.COM } 80111963SAfshin.Ardakani@Sun.COM 80211963SAfshin.Ardakani@Sun.COM /* 80311963SAfshin.Ardakani@Sun.COM * ================== 80411963SAfshin.Ardakani@Sun.COM * Misc API (public) 80511963SAfshin.Ardakani@Sun.COM * ================== 80611963SAfshin.Ardakani@Sun.COM */ 80711963SAfshin.Ardakani@Sun.COM 80811963SAfshin.Ardakani@Sun.COM /* 80911963SAfshin.Ardakani@Sun.COM * This is the function that is called by smbd door server to 81011963SAfshin.Ardakani@Sun.COM * fullfil a GetReferrals request from smbsrv kernel module 81111963SAfshin.Ardakani@Sun.COM * 81211963SAfshin.Ardakani@Sun.COM * 'reftype' specifies the requested referral type. If it is 81311963SAfshin.Ardakani@Sun.COM * DFS_REFERRAL_ROOT then dfs_path should point to a namespace 81411963SAfshin.Ardakani@Sun.COM * root. If it is DFS_REFERRAL_LINK then dfs_path should CONTAIN 81511963SAfshin.Ardakani@Sun.COM * a link, in which case this function will find the link and 81611963SAfshin.Ardakani@Sun.COM * returns its target information. 81711963SAfshin.Ardakani@Sun.COM */ 81811963SAfshin.Ardakani@Sun.COM uint32_t 81911963SAfshin.Ardakani@Sun.COM dfs_get_referrals(const char *dfs_path, dfs_reftype_t reftype, 82011963SAfshin.Ardakani@Sun.COM dfs_info_t *referrals) 82111963SAfshin.Ardakani@Sun.COM { 82211963SAfshin.Ardakani@Sun.COM dfs_path_t path; 82311963SAfshin.Ardakani@Sun.COM smb_unc_t *unc; 82411963SAfshin.Ardakani@Sun.COM char linkpath[DFS_PATH_MAX]; 82511963SAfshin.Ardakani@Sun.COM uint32_t status; 82611963SAfshin.Ardakani@Sun.COM 82711963SAfshin.Ardakani@Sun.COM status = dfs_path_parse(&path, dfs_path, DFS_OBJECT_ANY); 82811963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) 82911963SAfshin.Ardakani@Sun.COM return (status); 83011963SAfshin.Ardakani@Sun.COM 83111963SAfshin.Ardakani@Sun.COM dfs_setpriv(PRIV_ON); 83211963SAfshin.Ardakani@Sun.COM 83311963SAfshin.Ardakani@Sun.COM referrals->i_type = path.p_type; 83411963SAfshin.Ardakani@Sun.COM 83511963SAfshin.Ardakani@Sun.COM switch (reftype) { 83611963SAfshin.Ardakani@Sun.COM case DFS_REFERRAL_ROOT: 83711963SAfshin.Ardakani@Sun.COM if (path.p_type != DFS_OBJECT_ROOT) { 83811963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER; 83911963SAfshin.Ardakani@Sun.COM break; 84011963SAfshin.Ardakani@Sun.COM } 84111963SAfshin.Ardakani@Sun.COM 84211963SAfshin.Ardakani@Sun.COM status = dfs_root_getinfo((const char *)path.p_fspath, 84311963SAfshin.Ardakani@Sun.COM referrals, DFS_INFO_ALL); 84411963SAfshin.Ardakani@Sun.COM (void) strlcpy(referrals->i_uncpath, dfs_path, DFS_PATH_MAX); 84511963SAfshin.Ardakani@Sun.COM break; 84611963SAfshin.Ardakani@Sun.COM 84711963SAfshin.Ardakani@Sun.COM case DFS_REFERRAL_LINK: 84811963SAfshin.Ardakani@Sun.COM if (path.p_type != DFS_OBJECT_LINK) { 84911963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER; 85011963SAfshin.Ardakani@Sun.COM break; 85111963SAfshin.Ardakani@Sun.COM } 85211963SAfshin.Ardakani@Sun.COM 85311963SAfshin.Ardakani@Sun.COM unc = &path.p_unc; 85411963SAfshin.Ardakani@Sun.COM if (!dfs_namespace_findlink(unc->unc_share, unc->unc_path, 85511963SAfshin.Ardakani@Sun.COM linkpath, DFS_PATH_MAX)) { 85611963SAfshin.Ardakani@Sun.COM status = ERROR_NOT_FOUND; 85711963SAfshin.Ardakani@Sun.COM break; 85811963SAfshin.Ardakani@Sun.COM } 85911963SAfshin.Ardakani@Sun.COM 86011963SAfshin.Ardakani@Sun.COM status = dfs_link_getinfo(linkpath, referrals, DFS_INFO_ALL); 86111963SAfshin.Ardakani@Sun.COM (void) snprintf(referrals->i_uncpath, DFS_PATH_MAX, "/%s/%s/%s", 86211963SAfshin.Ardakani@Sun.COM unc->unc_server, unc->unc_share, unc->unc_path); 86311963SAfshin.Ardakani@Sun.COM break; 86411963SAfshin.Ardakani@Sun.COM 86511963SAfshin.Ardakani@Sun.COM default: 86611963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER; 86711963SAfshin.Ardakani@Sun.COM break; 86811963SAfshin.Ardakani@Sun.COM } 86911963SAfshin.Ardakani@Sun.COM 87011963SAfshin.Ardakani@Sun.COM dfs_setpriv(PRIV_OFF); 87111963SAfshin.Ardakani@Sun.COM dfs_path_free(&path); 87211963SAfshin.Ardakani@Sun.COM return (status); 87311963SAfshin.Ardakani@Sun.COM } 87411963SAfshin.Ardakani@Sun.COM 87511963SAfshin.Ardakani@Sun.COM /* 87611963SAfshin.Ardakani@Sun.COM * Takes a DFS path in UNC format (dfs_path) and parse it into a dfs_path_t 87711963SAfshin.Ardakani@Sun.COM * structure. 87811963SAfshin.Ardakani@Sun.COM * 87911963SAfshin.Ardakani@Sun.COM * dfs_path_free() MUST be called to free the allocated memory in this 88011963SAfshin.Ardakani@Sun.COM * function. 88111963SAfshin.Ardakani@Sun.COM * 88211963SAfshin.Ardakani@Sun.COM * Returns: 88311963SAfshin.Ardakani@Sun.COM * 88411963SAfshin.Ardakani@Sun.COM * ERROR_INVALID_PARAMETER path is not a valid UNC or not valid for the 88511963SAfshin.Ardakani@Sun.COM * specified object type 88611963SAfshin.Ardakani@Sun.COM * ERROR_NOT_ENOUGH_MEMORY not enough memory to peform the parse 88711963SAfshin.Ardakani@Sun.COM * ERROR_NOT_FOUND namespace specified does not exist 88811963SAfshin.Ardakani@Sun.COM */ 88911963SAfshin.Ardakani@Sun.COM uint32_t 89011963SAfshin.Ardakani@Sun.COM dfs_path_parse(dfs_path_t *path, const char *dfs_path, uint32_t path_type) 89111963SAfshin.Ardakani@Sun.COM { 89211963SAfshin.Ardakani@Sun.COM char rootdir[DFS_PATH_MAX]; 89311963SAfshin.Ardakani@Sun.COM smb_unc_t *unc; 89411963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_SUCCESS; 89511963SAfshin.Ardakani@Sun.COM int rc; 89611963SAfshin.Ardakani@Sun.COM 89711963SAfshin.Ardakani@Sun.COM bzero(path, sizeof (dfs_path_t)); 89811963SAfshin.Ardakani@Sun.COM unc = &path->p_unc; 89911963SAfshin.Ardakani@Sun.COM 90011963SAfshin.Ardakani@Sun.COM rc = smb_unc_init(dfs_path, unc); 90111963SAfshin.Ardakani@Sun.COM switch (rc) { 90211963SAfshin.Ardakani@Sun.COM case EINVAL: 90311963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_PARAMETER); 90411963SAfshin.Ardakani@Sun.COM case ENOMEM: 90511963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY); 90611963SAfshin.Ardakani@Sun.COM default: 90711963SAfshin.Ardakani@Sun.COM break; 90811963SAfshin.Ardakani@Sun.COM } 90911963SAfshin.Ardakani@Sun.COM 91011963SAfshin.Ardakani@Sun.COM if (dfs_namespace_path(unc->unc_share, rootdir, DFS_PATH_MAX) 91111963SAfshin.Ardakani@Sun.COM != ERROR_SUCCESS) { 91211963SAfshin.Ardakani@Sun.COM smb_unc_free(unc); 91311963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND); 91411963SAfshin.Ardakani@Sun.COM } 91511963SAfshin.Ardakani@Sun.COM 91611963SAfshin.Ardakani@Sun.COM if (path_type == DFS_OBJECT_ANY) 91711963SAfshin.Ardakani@Sun.COM path->p_type = (unc->unc_path != NULL) 91811963SAfshin.Ardakani@Sun.COM ? DFS_OBJECT_LINK : DFS_OBJECT_ROOT; 91911963SAfshin.Ardakani@Sun.COM else 92011963SAfshin.Ardakani@Sun.COM path->p_type = path_type; 92111963SAfshin.Ardakani@Sun.COM 92211963SAfshin.Ardakani@Sun.COM switch (path->p_type) { 92311963SAfshin.Ardakani@Sun.COM case DFS_OBJECT_LINK: 92411963SAfshin.Ardakani@Sun.COM if ((unc->unc_path == NULL) || (*unc->unc_path == '\0')) 92511963SAfshin.Ardakani@Sun.COM status = ERROR_NOT_FOUND; 92611963SAfshin.Ardakani@Sun.COM else 92711963SAfshin.Ardakani@Sun.COM (void) snprintf(path->p_fspath, sizeof (path->p_fspath), 92811963SAfshin.Ardakani@Sun.COM "%s/%s", rootdir, unc->unc_path); 92911963SAfshin.Ardakani@Sun.COM break; 93011963SAfshin.Ardakani@Sun.COM 93111963SAfshin.Ardakani@Sun.COM case DFS_OBJECT_ROOT: 93211963SAfshin.Ardakani@Sun.COM if (unc->unc_path == NULL) 93311963SAfshin.Ardakani@Sun.COM (void) strlcpy(path->p_fspath, rootdir, 93411963SAfshin.Ardakani@Sun.COM sizeof (path->p_fspath)); 93511963SAfshin.Ardakani@Sun.COM else 93611963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER; 93711963SAfshin.Ardakani@Sun.COM break; 93811963SAfshin.Ardakani@Sun.COM 93911963SAfshin.Ardakani@Sun.COM default: 94011963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER; 94111963SAfshin.Ardakani@Sun.COM } 94211963SAfshin.Ardakani@Sun.COM 94311963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) 94411963SAfshin.Ardakani@Sun.COM smb_unc_free(unc); 94511963SAfshin.Ardakani@Sun.COM 94611963SAfshin.Ardakani@Sun.COM return (status); 94711963SAfshin.Ardakani@Sun.COM } 94811963SAfshin.Ardakani@Sun.COM 94911963SAfshin.Ardakani@Sun.COM /* 95011963SAfshin.Ardakani@Sun.COM * Frees the allocated memory for p_unc field of the passed path 95111963SAfshin.Ardakani@Sun.COM */ 95211963SAfshin.Ardakani@Sun.COM void 95311963SAfshin.Ardakani@Sun.COM dfs_path_free(dfs_path_t *path) 95411963SAfshin.Ardakani@Sun.COM { 95511963SAfshin.Ardakani@Sun.COM if (path != NULL) 95611963SAfshin.Ardakani@Sun.COM smb_unc_free(&path->p_unc); 95711963SAfshin.Ardakani@Sun.COM } 95811963SAfshin.Ardakani@Sun.COM 95911963SAfshin.Ardakani@Sun.COM /* 96011963SAfshin.Ardakani@Sun.COM * Free the allocated memory for targets in the given info 96111963SAfshin.Ardakani@Sun.COM * structure 96211963SAfshin.Ardakani@Sun.COM */ 96311963SAfshin.Ardakani@Sun.COM void 96411963SAfshin.Ardakani@Sun.COM dfs_info_free(dfs_info_t *info) 96511963SAfshin.Ardakani@Sun.COM { 96611963SAfshin.Ardakani@Sun.COM if (info) 96711963SAfshin.Ardakani@Sun.COM free(info->i_targets); 96811963SAfshin.Ardakani@Sun.COM } 96911963SAfshin.Ardakani@Sun.COM 97011963SAfshin.Ardakani@Sun.COM /* 97111963SAfshin.Ardakani@Sun.COM * Trace the given DFS info structure 97211963SAfshin.Ardakani@Sun.COM */ 97311963SAfshin.Ardakani@Sun.COM void 97411963SAfshin.Ardakani@Sun.COM dfs_info_trace(const char *msg, dfs_info_t *info) 97511963SAfshin.Ardakani@Sun.COM { 97611963SAfshin.Ardakani@Sun.COM dfs_target_t *t; 97711963SAfshin.Ardakani@Sun.COM int i; 97811963SAfshin.Ardakani@Sun.COM 97911963SAfshin.Ardakani@Sun.COM smb_tracef("%s", msg); 98011963SAfshin.Ardakani@Sun.COM if (info == NULL) 98111963SAfshin.Ardakani@Sun.COM return; 98211963SAfshin.Ardakani@Sun.COM 98311963SAfshin.Ardakani@Sun.COM smb_tracef("UNC\t%s", info->i_uncpath); 98411963SAfshin.Ardakani@Sun.COM smb_tracef("comment\t%s", info->i_comment); 98511963SAfshin.Ardakani@Sun.COM smb_tracef("GUID\t%s", info->i_guid); 98611963SAfshin.Ardakani@Sun.COM smb_tracef("state\t%X", info->i_state); 98711963SAfshin.Ardakani@Sun.COM smb_tracef("timeout\t%d", info->i_timeout); 98811963SAfshin.Ardakani@Sun.COM smb_tracef("props\t%X", info->i_propflags); 98911963SAfshin.Ardakani@Sun.COM smb_tracef("# targets\t%X", info->i_ntargets); 99011963SAfshin.Ardakani@Sun.COM 99111963SAfshin.Ardakani@Sun.COM if (info->i_targets == NULL) 99211963SAfshin.Ardakani@Sun.COM return; 99311963SAfshin.Ardakani@Sun.COM 99411963SAfshin.Ardakani@Sun.COM for (i = 0, t = info->i_targets; i < info->i_ntargets; i++, t++) { 99511963SAfshin.Ardakani@Sun.COM smb_tracef("[%d] \\\\%s\\%s", i, t->t_server, t->t_share); 99611963SAfshin.Ardakani@Sun.COM smb_tracef("[%d] state\t%X", i, t->t_state); 99711963SAfshin.Ardakani@Sun.COM smb_tracef("[%d] priority\t%d:%d", i, t->t_priority.p_class, 99811963SAfshin.Ardakani@Sun.COM t->t_priority.p_rank); 99911963SAfshin.Ardakani@Sun.COM } 100011963SAfshin.Ardakani@Sun.COM } 100111963SAfshin.Ardakani@Sun.COM 100211963SAfshin.Ardakani@Sun.COM /* 100311963SAfshin.Ardakani@Sun.COM * Search the path specified by 'relpath' to see if it contains 100411963SAfshin.Ardakani@Sun.COM * a DFS link starting from the last component. If a link is found 100511963SAfshin.Ardakani@Sun.COM * the full path is returned in 'linkpath' 100611963SAfshin.Ardakani@Sun.COM */ 100711963SAfshin.Ardakani@Sun.COM static boolean_t 100811963SAfshin.Ardakani@Sun.COM dfs_namespace_findlink(const char *name, char *relpath, 100911963SAfshin.Ardakani@Sun.COM char *linkpath, size_t bufsz) 101011963SAfshin.Ardakani@Sun.COM { 101111963SAfshin.Ardakani@Sun.COM char rootdir[DFS_PATH_MAX]; 101211963SAfshin.Ardakani@Sun.COM uint32_t stat; 101311963SAfshin.Ardakani@Sun.COM char *p; 101411963SAfshin.Ardakani@Sun.COM 101511963SAfshin.Ardakani@Sun.COM if (dfs_namespace_path(name, rootdir, DFS_PATH_MAX) != ERROR_SUCCESS) 101611963SAfshin.Ardakani@Sun.COM return (B_FALSE); 101711963SAfshin.Ardakani@Sun.COM 101811963SAfshin.Ardakani@Sun.COM (void) snprintf(linkpath, bufsz, "%s/%s", rootdir, relpath); 101911963SAfshin.Ardakani@Sun.COM 102011963SAfshin.Ardakani@Sun.COM for (;;) { 102111963SAfshin.Ardakani@Sun.COM if (dfs_link_stat(linkpath, &stat) != ERROR_SUCCESS) 102211963SAfshin.Ardakani@Sun.COM return (B_FALSE); 102311963SAfshin.Ardakani@Sun.COM 102411963SAfshin.Ardakani@Sun.COM if (stat == DFS_STAT_ISDFS) 102511963SAfshin.Ardakani@Sun.COM return (B_TRUE); 102611963SAfshin.Ardakani@Sun.COM 102711963SAfshin.Ardakani@Sun.COM if ((p = strrchr(relpath, '/')) == NULL) 102811963SAfshin.Ardakani@Sun.COM return (B_FALSE); 102911963SAfshin.Ardakani@Sun.COM *p = '\0'; 103011963SAfshin.Ardakani@Sun.COM 103111963SAfshin.Ardakani@Sun.COM (void) snprintf(linkpath, bufsz, "%s/%s", rootdir, relpath); 103211963SAfshin.Ardakani@Sun.COM } 103311963SAfshin.Ardakani@Sun.COM 103411963SAfshin.Ardakani@Sun.COM /*NOTREACHED*/ 103511963SAfshin.Ardakani@Sun.COM return (B_FALSE); 103611963SAfshin.Ardakani@Sun.COM } 103711963SAfshin.Ardakani@Sun.COM 103811963SAfshin.Ardakani@Sun.COM /* 103911963SAfshin.Ardakani@Sun.COM * Caches the specified namespace 104011963SAfshin.Ardakani@Sun.COM */ 104111963SAfshin.Ardakani@Sun.COM static void * 104211963SAfshin.Ardakani@Sun.COM dfs_namespace_cache(void *arg) 104311963SAfshin.Ardakani@Sun.COM { 104411963SAfshin.Ardakani@Sun.COM char *share = arg; 104511963SAfshin.Ardakani@Sun.COM char uncpath[DFS_PATH_MAX]; 104611963SAfshin.Ardakani@Sun.COM smb_share_t si; 104711963SAfshin.Ardakani@Sun.COM 104811963SAfshin.Ardakani@Sun.COM if (smb_shr_get(share, &si) != NERR_Success) { 104911963SAfshin.Ardakani@Sun.COM free(share); 105011963SAfshin.Ardakani@Sun.COM return (NULL); 105111963SAfshin.Ardakani@Sun.COM } 105211963SAfshin.Ardakani@Sun.COM 105311963SAfshin.Ardakani@Sun.COM (void) snprintf(uncpath, DFS_PATH_MAX, "\\\\%s\\%s", dfs_nbname, share); 105411963SAfshin.Ardakani@Sun.COM (void) dfs_cache_add_byunc(uncpath, si.shr_path, DFS_OBJECT_ROOT); 105511963SAfshin.Ardakani@Sun.COM 105611963SAfshin.Ardakani@Sun.COM dfs_cache_populate(uncpath, si.shr_path); 105711963SAfshin.Ardakani@Sun.COM 105811963SAfshin.Ardakani@Sun.COM free(share); 105911963SAfshin.Ardakani@Sun.COM return (NULL); 106011963SAfshin.Ardakani@Sun.COM } 106111963SAfshin.Ardakani@Sun.COM 106211963SAfshin.Ardakani@Sun.COM static int 106311963SAfshin.Ardakani@Sun.COM dfs_root_add(const char *rootdir, dfs_info_t *info) 106411963SAfshin.Ardakani@Sun.COM { 106511963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_INTERNAL_ERROR; 106611963SAfshin.Ardakani@Sun.COM int xfd; 106711963SAfshin.Ardakani@Sun.COM 106811963SAfshin.Ardakani@Sun.COM (void) rw_wrlock(&dfs_root_rwl); 106911963SAfshin.Ardakani@Sun.COM if ((xfd = dfs_root_xopen(rootdir, O_CREAT | O_TRUNC | O_RDWR)) > 0) { 107011963SAfshin.Ardakani@Sun.COM status = dfs_root_xwrite(xfd, info); 107111963SAfshin.Ardakani@Sun.COM dfs_root_xclose(xfd); 107211963SAfshin.Ardakani@Sun.COM } 107311963SAfshin.Ardakani@Sun.COM (void) rw_unlock(&dfs_root_rwl); 107411963SAfshin.Ardakani@Sun.COM 107511963SAfshin.Ardakani@Sun.COM return (status); 107611963SAfshin.Ardakani@Sun.COM } 107711963SAfshin.Ardakani@Sun.COM 107811963SAfshin.Ardakani@Sun.COM /* 107911963SAfshin.Ardakani@Sun.COM * Deletes the specified root information 108011963SAfshin.Ardakani@Sun.COM */ 108111963SAfshin.Ardakani@Sun.COM static uint32_t 108211963SAfshin.Ardakani@Sun.COM dfs_root_remove(const char *rootdir) 108311963SAfshin.Ardakani@Sun.COM { 108411963SAfshin.Ardakani@Sun.COM int attrdirfd; 108511963SAfshin.Ardakani@Sun.COM int err = 0; 108611963SAfshin.Ardakani@Sun.COM 108711963SAfshin.Ardakani@Sun.COM (void) rw_wrlock(&dfs_root_rwl); 108811963SAfshin.Ardakani@Sun.COM 108911963SAfshin.Ardakani@Sun.COM if ((attrdirfd = attropen(rootdir, ".", O_RDONLY)) > 0) { 109011963SAfshin.Ardakani@Sun.COM if (unlinkat(attrdirfd, DFS_ROOT_XATTR, 0) == -1) { 109111963SAfshin.Ardakani@Sun.COM if (errno != ENOENT) 109211963SAfshin.Ardakani@Sun.COM err = errno; 109311963SAfshin.Ardakani@Sun.COM } 109411963SAfshin.Ardakani@Sun.COM (void) close(attrdirfd); 109511963SAfshin.Ardakani@Sun.COM } else { 109611963SAfshin.Ardakani@Sun.COM err = errno; 109711963SAfshin.Ardakani@Sun.COM } 109811963SAfshin.Ardakani@Sun.COM 109911963SAfshin.Ardakani@Sun.COM (void) rw_unlock(&dfs_root_rwl); 110011963SAfshin.Ardakani@Sun.COM 110111963SAfshin.Ardakani@Sun.COM if (err != 0) { 110211963SAfshin.Ardakani@Sun.COM syslog(LOG_DEBUG, "dfs: failed to remove root info %s (%d)", 110311963SAfshin.Ardakani@Sun.COM rootdir, err); 110411963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 110511963SAfshin.Ardakani@Sun.COM } 110611963SAfshin.Ardakani@Sun.COM 110711963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 110811963SAfshin.Ardakani@Sun.COM } 110911963SAfshin.Ardakani@Sun.COM 111011963SAfshin.Ardakani@Sun.COM /* 111111963SAfshin.Ardakani@Sun.COM * Opens DFS root directory's extended attribute with the given mode. 111211963SAfshin.Ardakani@Sun.COM */ 111311963SAfshin.Ardakani@Sun.COM static int 111411963SAfshin.Ardakani@Sun.COM dfs_root_xopen(const char *rootdir, int oflag) 111511963SAfshin.Ardakani@Sun.COM { 111611963SAfshin.Ardakani@Sun.COM int dfd; 111711963SAfshin.Ardakani@Sun.COM int xfd = -1; 111811963SAfshin.Ardakani@Sun.COM int err = 0; 111911963SAfshin.Ardakani@Sun.COM 112011963SAfshin.Ardakani@Sun.COM if ((dfd = open(rootdir, O_RDONLY)) > 0) { 112111963SAfshin.Ardakani@Sun.COM xfd = openat(dfd, DFS_ROOT_XATTR, oflag | O_XATTR, 0600); 112211963SAfshin.Ardakani@Sun.COM if (xfd == -1) 112311963SAfshin.Ardakani@Sun.COM err = errno; 112411963SAfshin.Ardakani@Sun.COM (void) close(dfd); 112511963SAfshin.Ardakani@Sun.COM } else { 112611963SAfshin.Ardakani@Sun.COM err = errno; 112711963SAfshin.Ardakani@Sun.COM } 112811963SAfshin.Ardakani@Sun.COM 112911963SAfshin.Ardakani@Sun.COM if (err != 0) { 113011963SAfshin.Ardakani@Sun.COM syslog(LOG_DEBUG, "dfs: failed to open root directory %s (%d)", 113111963SAfshin.Ardakani@Sun.COM rootdir, err); 113211963SAfshin.Ardakani@Sun.COM } 113311963SAfshin.Ardakani@Sun.COM 113411963SAfshin.Ardakani@Sun.COM return (xfd); 113511963SAfshin.Ardakani@Sun.COM } 113611963SAfshin.Ardakani@Sun.COM 113711963SAfshin.Ardakani@Sun.COM /* 113811963SAfshin.Ardakani@Sun.COM * Closes given extended attribute file descriptor 113911963SAfshin.Ardakani@Sun.COM */ 114011963SAfshin.Ardakani@Sun.COM static void 114111963SAfshin.Ardakani@Sun.COM dfs_root_xclose(int xfd) 114211963SAfshin.Ardakani@Sun.COM { 114311963SAfshin.Ardakani@Sun.COM (void) close(xfd); 114411963SAfshin.Ardakani@Sun.COM } 114511963SAfshin.Ardakani@Sun.COM 114611963SAfshin.Ardakani@Sun.COM /* 114711963SAfshin.Ardakani@Sun.COM * Writes the given DFS data in the DFS root directory's 114811963SAfshin.Ardakani@Sun.COM * extended attribute specified with xfd file descriptor. 114911963SAfshin.Ardakani@Sun.COM */ 115011963SAfshin.Ardakani@Sun.COM static uint32_t 115111963SAfshin.Ardakani@Sun.COM dfs_root_xwrite(int xfd, dfs_info_t *info) 115211963SAfshin.Ardakani@Sun.COM { 115311963SAfshin.Ardakani@Sun.COM size_t nbytes; 115411963SAfshin.Ardakani@Sun.COM char *buf = NULL; 115511963SAfshin.Ardakani@Sun.COM size_t buflen; 115611963SAfshin.Ardakani@Sun.COM uint32_t status; 115711963SAfshin.Ardakani@Sun.COM 115811963SAfshin.Ardakani@Sun.COM if ((status = dfs_root_encode(info, &buf, &buflen)) != ERROR_SUCCESS) 115911963SAfshin.Ardakani@Sun.COM return (status); 116011963SAfshin.Ardakani@Sun.COM 116111963SAfshin.Ardakani@Sun.COM (void) lseek(xfd, 0, SEEK_SET); 116211963SAfshin.Ardakani@Sun.COM nbytes = write(xfd, buf, buflen); 116311963SAfshin.Ardakani@Sun.COM free(buf); 116411963SAfshin.Ardakani@Sun.COM 116511963SAfshin.Ardakani@Sun.COM return ((nbytes == buflen) ? ERROR_SUCCESS : ERROR_INTERNAL_ERROR); 116611963SAfshin.Ardakani@Sun.COM } 116711963SAfshin.Ardakani@Sun.COM 116811963SAfshin.Ardakani@Sun.COM /* 116911963SAfshin.Ardakani@Sun.COM * Reads DFS root information from its directory extended attribute 117011963SAfshin.Ardakani@Sun.COM * and parse it into given dfs_info_t structure 117111963SAfshin.Ardakani@Sun.COM */ 117211963SAfshin.Ardakani@Sun.COM static uint32_t 117311963SAfshin.Ardakani@Sun.COM dfs_root_xread(int xfd, dfs_info_t *info, uint32_t infolvl) 117411963SAfshin.Ardakani@Sun.COM { 117511963SAfshin.Ardakani@Sun.COM struct stat statbuf; 117611963SAfshin.Ardakani@Sun.COM uint32_t status; 117711963SAfshin.Ardakani@Sun.COM char *buf; 117811963SAfshin.Ardakani@Sun.COM 117911963SAfshin.Ardakani@Sun.COM if (fstat(xfd, &statbuf) != 0) 118011963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 118111963SAfshin.Ardakani@Sun.COM 118211963SAfshin.Ardakani@Sun.COM if ((buf = malloc(statbuf.st_size)) == NULL) 118311963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY); 118411963SAfshin.Ardakani@Sun.COM 118511963SAfshin.Ardakani@Sun.COM if (read(xfd, buf, statbuf.st_size) == statbuf.st_size) 118611963SAfshin.Ardakani@Sun.COM status = dfs_root_decode(info, buf, statbuf.st_size, infolvl); 118711963SAfshin.Ardakani@Sun.COM else 118811963SAfshin.Ardakani@Sun.COM status = ERROR_INTERNAL_ERROR; 118911963SAfshin.Ardakani@Sun.COM 119011963SAfshin.Ardakani@Sun.COM free(buf); 119111963SAfshin.Ardakani@Sun.COM return (status); 119211963SAfshin.Ardakani@Sun.COM } 119311963SAfshin.Ardakani@Sun.COM 119411963SAfshin.Ardakani@Sun.COM /* 119511963SAfshin.Ardakani@Sun.COM * Encodes (packs) DFS information in 'info' into a flat 119611963SAfshin.Ardakani@Sun.COM * buffer in a name-value format. This function allocates a 119711963SAfshin.Ardakani@Sun.COM * buffer with appropriate size to contain all the information 119811963SAfshin.Ardakani@Sun.COM * so the caller MUST free the allocated memory by calling free(). 119911963SAfshin.Ardakani@Sun.COM */ 120011963SAfshin.Ardakani@Sun.COM static uint32_t 120111963SAfshin.Ardakani@Sun.COM dfs_root_encode(dfs_info_t *info, char **buf, size_t *bufsz) 120211963SAfshin.Ardakani@Sun.COM { 120311963SAfshin.Ardakani@Sun.COM dfs_target_t *t; 120411963SAfshin.Ardakani@Sun.COM nvlist_t *nvl; 120511963SAfshin.Ardakani@Sun.COM int rc; 120611963SAfshin.Ardakani@Sun.COM 120711963SAfshin.Ardakani@Sun.COM if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 120811963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY); 120911963SAfshin.Ardakani@Sun.COM 121011963SAfshin.Ardakani@Sun.COM rc = nvlist_add_string(nvl, "comment", info->i_comment); 121111963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_string(nvl, "guid", info->i_guid); 121211963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_uint32(nvl, "state", info->i_state); 121311963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_uint32(nvl, "timeout", info->i_timeout); 121411963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_uint32(nvl, "propflags", info->i_propflags); 121511963SAfshin.Ardakani@Sun.COM t = info->i_targets; 121611963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_string(nvl, "t_server", t->t_server); 121711963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_string(nvl, "t_share", t->t_share); 121811963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_uint32(nvl, "t_state", t->t_state); 121911963SAfshin.Ardakani@Sun.COM 122011963SAfshin.Ardakani@Sun.COM if (rc == 0) 122111963SAfshin.Ardakani@Sun.COM rc = nvlist_pack(nvl, buf, bufsz, NV_ENCODE_NATIVE, 0); 122211963SAfshin.Ardakani@Sun.COM 122311963SAfshin.Ardakani@Sun.COM nvlist_free(nvl); 122411963SAfshin.Ardakani@Sun.COM 122511963SAfshin.Ardakani@Sun.COM return ((rc == 0) ? ERROR_SUCCESS : ERROR_INTERNAL_ERROR); 122611963SAfshin.Ardakani@Sun.COM } 122711963SAfshin.Ardakani@Sun.COM 122811963SAfshin.Ardakani@Sun.COM /* 122911963SAfshin.Ardakani@Sun.COM * Decodes (unpack) provided buffer which contains a list of name-value 123011963SAfshin.Ardakani@Sun.COM * pairs into given dfs_info_t structure 123111963SAfshin.Ardakani@Sun.COM */ 123211963SAfshin.Ardakani@Sun.COM static uint32_t 123311963SAfshin.Ardakani@Sun.COM dfs_root_decode(dfs_info_t *info, char *buf, size_t bufsz, uint32_t infolvl) 123411963SAfshin.Ardakani@Sun.COM { 123511963SAfshin.Ardakani@Sun.COM nvlist_t *nvl; 123611963SAfshin.Ardakani@Sun.COM char *cmnt, *guid; 123711963SAfshin.Ardakani@Sun.COM char *t_server, *t_share; 123811963SAfshin.Ardakani@Sun.COM uint32_t t_state; 123911963SAfshin.Ardakani@Sun.COM int rc; 124011963SAfshin.Ardakani@Sun.COM 124111963SAfshin.Ardakani@Sun.COM if (nvlist_unpack(buf, bufsz, &nvl, 0) != 0) 124211963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 124311963SAfshin.Ardakani@Sun.COM 124411963SAfshin.Ardakani@Sun.COM rc = nvlist_lookup_string(nvl, "comment", &cmnt); 124511963SAfshin.Ardakani@Sun.COM rc |= nvlist_lookup_string(nvl, "guid", &guid); 124611963SAfshin.Ardakani@Sun.COM rc |= nvlist_lookup_uint32(nvl, "state", &info->i_state); 124711963SAfshin.Ardakani@Sun.COM rc |= nvlist_lookup_uint32(nvl, "timeout", &info->i_timeout); 124811963SAfshin.Ardakani@Sun.COM rc |= nvlist_lookup_uint32(nvl, "propflags", &info->i_propflags); 124911963SAfshin.Ardakani@Sun.COM 125011963SAfshin.Ardakani@Sun.COM if (rc != 0) { 125111963SAfshin.Ardakani@Sun.COM nvlist_free(nvl); 125211963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 125311963SAfshin.Ardakani@Sun.COM } 125411963SAfshin.Ardakani@Sun.COM 125511963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_comment, (cmnt) ? cmnt : "", 125611963SAfshin.Ardakani@Sun.COM sizeof (info->i_comment)); 125711963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_guid, (guid) ? guid : "", sizeof (info->i_guid)); 125811963SAfshin.Ardakani@Sun.COM 125911963SAfshin.Ardakani@Sun.COM info->i_targets = NULL; 126011963SAfshin.Ardakani@Sun.COM info->i_ntargets = 1; 126111963SAfshin.Ardakani@Sun.COM 126211963SAfshin.Ardakani@Sun.COM switch (infolvl) { 126311963SAfshin.Ardakani@Sun.COM case DFS_INFO_ALL: 126411963SAfshin.Ardakani@Sun.COM case 3: 126511963SAfshin.Ardakani@Sun.COM case 4: 126611963SAfshin.Ardakani@Sun.COM case 6: 126711963SAfshin.Ardakani@Sun.COM case 9: 126811963SAfshin.Ardakani@Sun.COM /* need target information */ 126911963SAfshin.Ardakani@Sun.COM break; 127011963SAfshin.Ardakani@Sun.COM default: 127111963SAfshin.Ardakani@Sun.COM nvlist_free(nvl); 127211963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 127311963SAfshin.Ardakani@Sun.COM } 127411963SAfshin.Ardakani@Sun.COM 127511963SAfshin.Ardakani@Sun.COM info->i_targets = malloc(sizeof (dfs_target_t)); 127611963SAfshin.Ardakani@Sun.COM if (info->i_targets == NULL) { 127711963SAfshin.Ardakani@Sun.COM nvlist_free(nvl); 127811963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY); 127911963SAfshin.Ardakani@Sun.COM } 128011963SAfshin.Ardakani@Sun.COM 128111963SAfshin.Ardakani@Sun.COM rc = nvlist_lookup_string(nvl, "t_server", &t_server); 128211963SAfshin.Ardakani@Sun.COM rc |= nvlist_lookup_string(nvl, "t_share", &t_share); 128311963SAfshin.Ardakani@Sun.COM rc |= nvlist_lookup_uint32(nvl, "t_state", &t_state); 128411963SAfshin.Ardakani@Sun.COM if (rc != 0) { 128511963SAfshin.Ardakani@Sun.COM nvlist_free(nvl); 128611963SAfshin.Ardakani@Sun.COM free(info->i_targets); 128711963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 128811963SAfshin.Ardakani@Sun.COM } 128911963SAfshin.Ardakani@Sun.COM dfs_target_init(info->i_targets, t_server, t_share, t_state); 129011963SAfshin.Ardakani@Sun.COM 129111963SAfshin.Ardakani@Sun.COM nvlist_free(nvl); 129211963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 129311963SAfshin.Ardakani@Sun.COM } 129411963SAfshin.Ardakani@Sun.COM 129511963SAfshin.Ardakani@Sun.COM /* 129611963SAfshin.Ardakani@Sun.COM * Determines if the passed state is valid for a DFS root 129711963SAfshin.Ardakani@Sun.COM * 129811963SAfshin.Ardakani@Sun.COM * This is based on test results against Win2003 and in some cases 129911963SAfshin.Ardakani@Sun.COM * does not match [MS-DFSNM] spec. 130011963SAfshin.Ardakani@Sun.COM */ 130111963SAfshin.Ardakani@Sun.COM static uint32_t 130211963SAfshin.Ardakani@Sun.COM dfs_root_isvalidstate(uint32_t state) 130311963SAfshin.Ardakani@Sun.COM { 130411963SAfshin.Ardakani@Sun.COM switch (state) { 130511963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_OK: 130611963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_RESYNCHRONIZE: 130711963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 130811963SAfshin.Ardakani@Sun.COM 130911963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_INCONSISTENT: 131011963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_FORCE_SYNC: 131111963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_PARAMETER); 131211963SAfshin.Ardakani@Sun.COM 131311963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_OFFLINE: 131411963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_ONLINE: 131511963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_STANDBY: 131611963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_SUPPORTED); 131711963SAfshin.Ardakani@Sun.COM default: 131811963SAfshin.Ardakani@Sun.COM break; 131911963SAfshin.Ardakani@Sun.COM } 132011963SAfshin.Ardakani@Sun.COM 132111963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_PARAMETER); 132211963SAfshin.Ardakani@Sun.COM } 132311963SAfshin.Ardakani@Sun.COM 132411963SAfshin.Ardakani@Sun.COM /* 132511963SAfshin.Ardakani@Sun.COM * Decodes the link info from given string buffer (buf) into 132611963SAfshin.Ardakani@Sun.COM * dfs_info_t structure. 132711963SAfshin.Ardakani@Sun.COM */ 132811963SAfshin.Ardakani@Sun.COM static uint32_t 132911963SAfshin.Ardakani@Sun.COM dfs_link_decode(dfs_info_t *info, char *buf, uint32_t infolvl) 133011963SAfshin.Ardakani@Sun.COM { 133111963SAfshin.Ardakani@Sun.COM char *lfield[DFS_LINK_HDR_NFIELDS]; 133211963SAfshin.Ardakani@Sun.COM dfs_target_t *t; 133311963SAfshin.Ardakani@Sun.COM uint32_t linkver; 133411963SAfshin.Ardakani@Sun.COM uint32_t cmntlen; 133511963SAfshin.Ardakani@Sun.COM uint32_t cpylen; 133611963SAfshin.Ardakani@Sun.COM int i, j; 133711963SAfshin.Ardakani@Sun.COM 133811963SAfshin.Ardakani@Sun.COM /* 133911963SAfshin.Ardakani@Sun.COM * Header format 134011963SAfshin.Ardakani@Sun.COM * ver:state:prop:timeout:guid:ntarget:cmntlen:comment: 134111963SAfshin.Ardakani@Sun.COM */ 134211963SAfshin.Ardakani@Sun.COM for (i = 0; i < DFS_LINK_HDR_NFIELDS; i++) { 134311963SAfshin.Ardakani@Sun.COM if ((lfield[i] = strsep((char **)&buf, ":")) == NULL) 134411963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_DATA); 134511963SAfshin.Ardakani@Sun.COM } 134611963SAfshin.Ardakani@Sun.COM 134711963SAfshin.Ardakani@Sun.COM i = 0; 134811963SAfshin.Ardakani@Sun.COM linkver = strtoul(lfield[i++], NULL, 10); 134911963SAfshin.Ardakani@Sun.COM if (linkver != DFS_LINK_V1) 135011963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_DATA); 135111963SAfshin.Ardakani@Sun.COM 135211963SAfshin.Ardakani@Sun.COM info->i_state = strtoul(lfield[i++], NULL, 10); 135311963SAfshin.Ardakani@Sun.COM info->i_propflags = strtoul(lfield[i++], NULL, 10); 135411963SAfshin.Ardakani@Sun.COM info->i_timeout = strtoul(lfield[i++], NULL, 10); 135511963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_guid, lfield[i++], sizeof (info->i_guid)); 135611963SAfshin.Ardakani@Sun.COM info->i_ntargets = strtoul(lfield[i++], NULL, 10); 135711963SAfshin.Ardakani@Sun.COM info->i_targets = NULL; 135811963SAfshin.Ardakani@Sun.COM 135911963SAfshin.Ardakani@Sun.COM cpylen = cmntlen = strtoul(lfield[i++], NULL, 10); 136011963SAfshin.Ardakani@Sun.COM 136111963SAfshin.Ardakani@Sun.COM if (cmntlen > sizeof (info->i_comment)) 136211963SAfshin.Ardakani@Sun.COM cpylen = sizeof (info->i_comment); 136311963SAfshin.Ardakani@Sun.COM else if (cmntlen != 0) 136411963SAfshin.Ardakani@Sun.COM cpylen = cmntlen + 1; 136511963SAfshin.Ardakani@Sun.COM 136611963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_comment, buf, cpylen); 136711963SAfshin.Ardakani@Sun.COM buf += (cmntlen + 1); 136811963SAfshin.Ardakani@Sun.COM 136911963SAfshin.Ardakani@Sun.COM switch (infolvl) { 137011963SAfshin.Ardakani@Sun.COM case DFS_INFO_ALL: 137111963SAfshin.Ardakani@Sun.COM case 3: 137211963SAfshin.Ardakani@Sun.COM case 4: 137311963SAfshin.Ardakani@Sun.COM case 6: 137411963SAfshin.Ardakani@Sun.COM case 9: 137511963SAfshin.Ardakani@Sun.COM /* need target information */ 137611963SAfshin.Ardakani@Sun.COM break; 137711963SAfshin.Ardakani@Sun.COM default: 137811963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 137911963SAfshin.Ardakani@Sun.COM } 138011963SAfshin.Ardakani@Sun.COM 138111963SAfshin.Ardakani@Sun.COM info->i_targets = calloc(info->i_ntargets, sizeof (dfs_target_t)); 138211963SAfshin.Ardakani@Sun.COM if (info->i_targets == NULL) 138311963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY); 138411963SAfshin.Ardakani@Sun.COM 138511963SAfshin.Ardakani@Sun.COM /* 138611963SAfshin.Ardakani@Sun.COM * Format for each target 138711963SAfshin.Ardakani@Sun.COM * server:share:state:class:rank 138811963SAfshin.Ardakani@Sun.COM */ 138911963SAfshin.Ardakani@Sun.COM for (i = 0, t = info->i_targets; i < info->i_ntargets; i++, t++) { 139011963SAfshin.Ardakani@Sun.COM for (j = 0; j < DFS_LINK_TRGT_NFIELDS; j++) { 139111963SAfshin.Ardakani@Sun.COM if ((lfield[j] = strsep((char **)&buf, ":")) == NULL) { 139211963SAfshin.Ardakani@Sun.COM dfs_info_free(info); 139311963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_DATA); 139411963SAfshin.Ardakani@Sun.COM } 139511963SAfshin.Ardakani@Sun.COM } 139611963SAfshin.Ardakani@Sun.COM 139711963SAfshin.Ardakani@Sun.COM (void) strlcpy(t->t_server, lfield[0], sizeof (t->t_server)); 139811963SAfshin.Ardakani@Sun.COM (void) strlcpy(t->t_share, lfield[1], sizeof (t->t_share)); 139911963SAfshin.Ardakani@Sun.COM t->t_state = strtoul(lfield[2], NULL, 10); 140011963SAfshin.Ardakani@Sun.COM t->t_priority.p_class = strtoul(lfield[3], NULL, 10); 140111963SAfshin.Ardakani@Sun.COM t->t_priority.p_rank = strtoul(lfield[4], NULL, 10); 140211963SAfshin.Ardakani@Sun.COM } 140311963SAfshin.Ardakani@Sun.COM 140411963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 140511963SAfshin.Ardakani@Sun.COM } 140611963SAfshin.Ardakani@Sun.COM 140711963SAfshin.Ardakani@Sun.COM /* 140811963SAfshin.Ardakani@Sun.COM * Encodes given link information (info) 140911963SAfshin.Ardakani@Sun.COM */ 141011963SAfshin.Ardakani@Sun.COM static uint32_t 141111963SAfshin.Ardakani@Sun.COM dfs_link_encode(dfs_info_t *info, char *buf, size_t bufsz) 141211963SAfshin.Ardakani@Sun.COM { 141311963SAfshin.Ardakani@Sun.COM char linkdata[MAXREPARSELEN]; 141411963SAfshin.Ardakani@Sun.COM dfs_target_t *t; 141511963SAfshin.Ardakani@Sun.COM int i, sz; 141611963SAfshin.Ardakani@Sun.COM 141711963SAfshin.Ardakani@Sun.COM /* 141811963SAfshin.Ardakani@Sun.COM * Header format 141911963SAfshin.Ardakani@Sun.COM * ver:state:prop:timeout:guid:ntarget:cmntlen:comment 142011963SAfshin.Ardakani@Sun.COM */ 142111963SAfshin.Ardakani@Sun.COM sz = snprintf(buf, bufsz, "%u:%u:%u:%u:%s:%u:%u:%s", 142211963SAfshin.Ardakani@Sun.COM DFS_LINK_V1, info->i_state, info->i_propflags, info->i_timeout, 142311963SAfshin.Ardakani@Sun.COM info->i_guid, info->i_ntargets, 142411963SAfshin.Ardakani@Sun.COM strlen(info->i_comment), info->i_comment); 142511963SAfshin.Ardakani@Sun.COM 142611963SAfshin.Ardakani@Sun.COM if (sz > bufsz) { 142711963SAfshin.Ardakani@Sun.COM syslog(LOG_WARNING, "dfs: link data is too large"); 142811963SAfshin.Ardakani@Sun.COM dfs_info_trace("DFS link encode", info); 142911963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 143011963SAfshin.Ardakani@Sun.COM } 143111963SAfshin.Ardakani@Sun.COM 143211963SAfshin.Ardakani@Sun.COM /* 143311963SAfshin.Ardakani@Sun.COM * Format for each target 143411963SAfshin.Ardakani@Sun.COM * :server:share:state:class:rank 143511963SAfshin.Ardakani@Sun.COM */ 143611963SAfshin.Ardakani@Sun.COM bufsz -= sz; 143711963SAfshin.Ardakani@Sun.COM for (i = 0, t = info->i_targets; i < info->i_ntargets; i++, t++) { 143811963SAfshin.Ardakani@Sun.COM if (strchr(t->t_server, ':') || strchr(t->t_share, ':')) 143911963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_NAME); 144011963SAfshin.Ardakani@Sun.COM 144111963SAfshin.Ardakani@Sun.COM sz = snprintf(linkdata, MAXREPARSELEN, ":%s:%s:%u:%u:%u", 144211963SAfshin.Ardakani@Sun.COM t->t_server, t->t_share, t->t_state, 144311963SAfshin.Ardakani@Sun.COM t->t_priority.p_class, t->t_priority.p_rank); 144411963SAfshin.Ardakani@Sun.COM if (sz > bufsz) { 144511963SAfshin.Ardakani@Sun.COM syslog(LOG_WARNING, "dfs: link data is too large"); 144611963SAfshin.Ardakani@Sun.COM dfs_info_trace("DFS link encode", info); 144711963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 144811963SAfshin.Ardakani@Sun.COM } 144911963SAfshin.Ardakani@Sun.COM (void) strcat(buf, linkdata); 145011963SAfshin.Ardakani@Sun.COM bufsz -= sz; 145111963SAfshin.Ardakani@Sun.COM } 145211963SAfshin.Ardakani@Sun.COM 145311963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 145411963SAfshin.Ardakani@Sun.COM } 145511963SAfshin.Ardakani@Sun.COM 145611963SAfshin.Ardakani@Sun.COM /* 145711963SAfshin.Ardakani@Sun.COM * Stores given information for the specified link 145811963SAfshin.Ardakani@Sun.COM */ 145911963SAfshin.Ardakani@Sun.COM static uint32_t 146011963SAfshin.Ardakani@Sun.COM dfs_link_commit(const char *path, dfs_info_t *info) 146111963SAfshin.Ardakani@Sun.COM { 146211963SAfshin.Ardakani@Sun.COM char linkdata[MAXREPARSELEN]; 146311963SAfshin.Ardakani@Sun.COM uint32_t status; 146411963SAfshin.Ardakani@Sun.COM int rc; 146511963SAfshin.Ardakani@Sun.COM 146611963SAfshin.Ardakani@Sun.COM status = dfs_link_encode(info, linkdata, MAXREPARSELEN); 146711963SAfshin.Ardakani@Sun.COM if (status == ERROR_SUCCESS) { 146811963SAfshin.Ardakani@Sun.COM rc = smb_reparse_svcadd(path, DFS_REPARSE_SVCTYPE, linkdata); 146911963SAfshin.Ardakani@Sun.COM if (rc != 0) 147011963SAfshin.Ardakani@Sun.COM status = ERROR_INTERNAL_ERROR; 147111963SAfshin.Ardakani@Sun.COM } 147211963SAfshin.Ardakani@Sun.COM 147311963SAfshin.Ardakani@Sun.COM return (status); 147411963SAfshin.Ardakani@Sun.COM } 147511963SAfshin.Ardakani@Sun.COM 147611963SAfshin.Ardakani@Sun.COM /* 147711963SAfshin.Ardakani@Sun.COM * Determines if the passed state is valid for a link 147811963SAfshin.Ardakani@Sun.COM */ 147911963SAfshin.Ardakani@Sun.COM static boolean_t 148011963SAfshin.Ardakani@Sun.COM dfs_link_isvalidstate(uint32_t state) 148111963SAfshin.Ardakani@Sun.COM { 148211963SAfshin.Ardakani@Sun.COM return (state == DFS_VOLUME_STATE_OK || 148311963SAfshin.Ardakani@Sun.COM state == DFS_VOLUME_STATE_OFFLINE || 148411963SAfshin.Ardakani@Sun.COM state == DFS_VOLUME_STATE_ONLINE); 148511963SAfshin.Ardakani@Sun.COM } 148611963SAfshin.Ardakani@Sun.COM 148711963SAfshin.Ardakani@Sun.COM /* 148811963SAfshin.Ardakani@Sun.COM * Initializes the given target structure (t) with provided information. 148911963SAfshin.Ardakani@Sun.COM */ 149011963SAfshin.Ardakani@Sun.COM static void 149111963SAfshin.Ardakani@Sun.COM dfs_target_init(dfs_target_t *t, const char *srv, const char *share, 149211963SAfshin.Ardakani@Sun.COM uint32_t state) 149311963SAfshin.Ardakani@Sun.COM { 149411963SAfshin.Ardakani@Sun.COM (void) strlcpy(t->t_server, (srv) ? srv : "", sizeof (t->t_server)); 149511963SAfshin.Ardakani@Sun.COM (void) strlcpy(t->t_share, (share) ? share : "", sizeof (t->t_share)); 149611963SAfshin.Ardakani@Sun.COM t->t_state = state; 149711963SAfshin.Ardakani@Sun.COM t->t_priority.p_class = DfsSiteCostNormalPriorityClass; 149811963SAfshin.Ardakani@Sun.COM t->t_priority.p_rank = 0; 149911963SAfshin.Ardakani@Sun.COM } 150011963SAfshin.Ardakani@Sun.COM 150111963SAfshin.Ardakani@Sun.COM /* 150211963SAfshin.Ardakani@Sun.COM * Lookup the specified target (server, share) in the given 150311963SAfshin.Ardakani@Sun.COM * target list (targets). If there is a match its index is 150411963SAfshin.Ardakani@Sun.COM * returned, otherwise -1 will be returned. 150511963SAfshin.Ardakani@Sun.COM */ 150611963SAfshin.Ardakani@Sun.COM static int 150711963SAfshin.Ardakani@Sun.COM dfs_target_find(dfs_target_t *targets, uint32_t ntargets, 150811963SAfshin.Ardakani@Sun.COM const char *server, const char *share) 150911963SAfshin.Ardakani@Sun.COM { 151011963SAfshin.Ardakani@Sun.COM dfs_target_t *t; 151111963SAfshin.Ardakani@Sun.COM int i; 151211963SAfshin.Ardakani@Sun.COM 151311963SAfshin.Ardakani@Sun.COM for (i = 0, t = targets; i < ntargets; i++, t++) { 151411963SAfshin.Ardakani@Sun.COM if ((smb_strcasecmp(t->t_server, server, 0) == 0) && 151511963SAfshin.Ardakani@Sun.COM (smb_strcasecmp(t->t_share, share, 0) == 0)) 151611963SAfshin.Ardakani@Sun.COM return (i); 151711963SAfshin.Ardakani@Sun.COM } 151811963SAfshin.Ardakani@Sun.COM 151911963SAfshin.Ardakani@Sun.COM return (-1); 152011963SAfshin.Ardakani@Sun.COM } 152111963SAfshin.Ardakani@Sun.COM 152211963SAfshin.Ardakani@Sun.COM /* 152311963SAfshin.Ardakani@Sun.COM * Determines if the passed state is valid for a link/root target 152411963SAfshin.Ardakani@Sun.COM */ 152511963SAfshin.Ardakani@Sun.COM static boolean_t 152611963SAfshin.Ardakani@Sun.COM dfs_target_isvalidstate(uint32_t state) 152711963SAfshin.Ardakani@Sun.COM { 152811963SAfshin.Ardakani@Sun.COM return (state == DFS_STORAGE_STATE_ONLINE || 152911963SAfshin.Ardakani@Sun.COM state == DFS_STORAGE_STATE_OFFLINE); 153011963SAfshin.Ardakani@Sun.COM } 153111963SAfshin.Ardakani@Sun.COM 153211963SAfshin.Ardakani@Sun.COM /* 153311963SAfshin.Ardakani@Sun.COM * Cache compare function, the key is UNC path 153411963SAfshin.Ardakani@Sun.COM */ 153511963SAfshin.Ardakani@Sun.COM static int 153611963SAfshin.Ardakani@Sun.COM dfs_cache_cmp(const void *p1, const void *p2) 153711963SAfshin.Ardakani@Sun.COM { 153811963SAfshin.Ardakani@Sun.COM smb_cache_node_t *cn1 = (smb_cache_node_t *)p1; 153911963SAfshin.Ardakani@Sun.COM smb_cache_node_t *cn2 = (smb_cache_node_t *)p2; 154011963SAfshin.Ardakani@Sun.COM dfs_nscnode_t *dn1 = cn1->cn_data; 154111963SAfshin.Ardakani@Sun.COM dfs_nscnode_t *dn2 = cn2->cn_data; 154211963SAfshin.Ardakani@Sun.COM int rc; 154311963SAfshin.Ardakani@Sun.COM 154411963SAfshin.Ardakani@Sun.COM rc = smb_strcasecmp(dn1->nsc_uncpath, dn2->nsc_uncpath, 0); 154511963SAfshin.Ardakani@Sun.COM 154611963SAfshin.Ardakani@Sun.COM if (rc < 0) 154711963SAfshin.Ardakani@Sun.COM return (-1); 154811963SAfshin.Ardakani@Sun.COM 154911963SAfshin.Ardakani@Sun.COM if (rc > 0) 155011963SAfshin.Ardakani@Sun.COM return (1); 155111963SAfshin.Ardakani@Sun.COM 155211963SAfshin.Ardakani@Sun.COM return (0); 155311963SAfshin.Ardakani@Sun.COM } 155411963SAfshin.Ardakani@Sun.COM 155511963SAfshin.Ardakani@Sun.COM /* 155611963SAfshin.Ardakani@Sun.COM * Adds an entry with given UNC and filesystem path and the specified 155711963SAfshin.Ardakani@Sun.COM * entry type (i.e. root/link) to the namespace cache. 155811963SAfshin.Ardakani@Sun.COM */ 155911963SAfshin.Ardakani@Sun.COM static uint32_t 156011963SAfshin.Ardakani@Sun.COM dfs_cache_add_byunc(const char *uncpath, const char *fspath, uint32_t type) 156111963SAfshin.Ardakani@Sun.COM { 156211963SAfshin.Ardakani@Sun.COM dfs_nscnode_t *dn; 156311963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_SUCCESS; 156411963SAfshin.Ardakani@Sun.COM 156511963SAfshin.Ardakani@Sun.COM if ((dn = malloc(sizeof (dfs_nscnode_t))) == NULL) 156611963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY); 156711963SAfshin.Ardakani@Sun.COM 156811963SAfshin.Ardakani@Sun.COM (void) strlcpy(dn->nsc_uncpath, uncpath, sizeof (dn->nsc_uncpath)); 156911963SAfshin.Ardakani@Sun.COM (void) strlcpy(dn->nsc_fspath, fspath, sizeof (dn->nsc_fspath)); 157011963SAfshin.Ardakani@Sun.COM dn->nsc_type = type; 157111963SAfshin.Ardakani@Sun.COM if (smb_cache_add(&dfs_nscache, dn, SMB_CACHE_ADD) != 0) { 157211963SAfshin.Ardakani@Sun.COM free(dn); 157311963SAfshin.Ardakani@Sun.COM status = ERROR_INTERNAL_ERROR; 157411963SAfshin.Ardakani@Sun.COM } 157511963SAfshin.Ardakani@Sun.COM 157611963SAfshin.Ardakani@Sun.COM return (status); 157711963SAfshin.Ardakani@Sun.COM } 157811963SAfshin.Ardakani@Sun.COM 157911963SAfshin.Ardakani@Sun.COM /* 158011963SAfshin.Ardakani@Sun.COM * starting from DFS root directory, scans the tree for DFS links 158111963SAfshin.Ardakani@Sun.COM * and adds them to the cache. 158211963SAfshin.Ardakani@Sun.COM */ 158311963SAfshin.Ardakani@Sun.COM static void 158411963SAfshin.Ardakani@Sun.COM dfs_cache_populate(const char *unc_prefix, const char *dir) 158511963SAfshin.Ardakani@Sun.COM { 158611963SAfshin.Ardakani@Sun.COM char fspath[DFS_PATH_MAX]; 158711963SAfshin.Ardakani@Sun.COM char uncpath[DFS_PATH_MAX]; 158811963SAfshin.Ardakani@Sun.COM char *fname; 158911963SAfshin.Ardakani@Sun.COM int nentries, i; 159011963SAfshin.Ardakani@Sun.COM struct dirent **entry_list; 159111963SAfshin.Ardakani@Sun.COM uint32_t stat; 159211963SAfshin.Ardakani@Sun.COM 159311963SAfshin.Ardakani@Sun.COM nentries = scandir(dir, &entry_list, NULL, NULL); 159411963SAfshin.Ardakani@Sun.COM if (nentries == -1) 159511963SAfshin.Ardakani@Sun.COM return; 159611963SAfshin.Ardakani@Sun.COM 159711963SAfshin.Ardakani@Sun.COM for (i = 0; i < nentries; i++) { 159811963SAfshin.Ardakani@Sun.COM fname = entry_list[i]->d_name; 159911963SAfshin.Ardakani@Sun.COM 160011963SAfshin.Ardakani@Sun.COM if (strcmp(fname, ".") == 0 || 160111963SAfshin.Ardakani@Sun.COM strcmp(fname, "..") == 0) { 160211963SAfshin.Ardakani@Sun.COM free(entry_list[i]); 160311963SAfshin.Ardakani@Sun.COM continue; 160411963SAfshin.Ardakani@Sun.COM } 160511963SAfshin.Ardakani@Sun.COM 160611963SAfshin.Ardakani@Sun.COM (void) snprintf(fspath, DFS_PATH_MAX, "%s/%s", dir, fname); 160711963SAfshin.Ardakani@Sun.COM (void) snprintf(uncpath, DFS_PATH_MAX, "%s\\%s", unc_prefix, 160811963SAfshin.Ardakani@Sun.COM fname); 160911963SAfshin.Ardakani@Sun.COM 161011963SAfshin.Ardakani@Sun.COM if (dfs_path_isdir(fspath)) { 161111963SAfshin.Ardakani@Sun.COM dfs_cache_populate(uncpath, fspath); 161211963SAfshin.Ardakani@Sun.COM } else if (dfs_link_stat(fspath, &stat) == ERROR_SUCCESS) { 161311963SAfshin.Ardakani@Sun.COM if (stat == DFS_STAT_ISDFS) 161411963SAfshin.Ardakani@Sun.COM (void) dfs_cache_add_byunc(uncpath, fspath, 161511963SAfshin.Ardakani@Sun.COM DFS_OBJECT_LINK); 161611963SAfshin.Ardakani@Sun.COM } 161711963SAfshin.Ardakani@Sun.COM 161811963SAfshin.Ardakani@Sun.COM free(entry_list[i]); 161911963SAfshin.Ardakani@Sun.COM } 162011963SAfshin.Ardakani@Sun.COM 162111963SAfshin.Ardakani@Sun.COM for (; i < nentries; i++) 162211963SAfshin.Ardakani@Sun.COM free(entry_list[i]); 162311963SAfshin.Ardakani@Sun.COM 162411963SAfshin.Ardakani@Sun.COM free(entry_list); 162511963SAfshin.Ardakani@Sun.COM } 162611963SAfshin.Ardakani@Sun.COM 162711963SAfshin.Ardakani@Sun.COM /* 162811963SAfshin.Ardakani@Sun.COM * Determines whether the given path is a directory. 162911963SAfshin.Ardakani@Sun.COM */ 163011963SAfshin.Ardakani@Sun.COM static boolean_t 163111963SAfshin.Ardakani@Sun.COM dfs_path_isdir(const char *path) 163211963SAfshin.Ardakani@Sun.COM { 163311963SAfshin.Ardakani@Sun.COM struct stat statbuf; 163411963SAfshin.Ardakani@Sun.COM 163511963SAfshin.Ardakani@Sun.COM if (lstat(path, &statbuf) != 0) 163611963SAfshin.Ardakani@Sun.COM return (B_FALSE); 163711963SAfshin.Ardakani@Sun.COM 163811963SAfshin.Ardakani@Sun.COM return ((statbuf.st_mode & S_IFMT) == S_IFDIR); 163911963SAfshin.Ardakani@Sun.COM } 164011963SAfshin.Ardakani@Sun.COM 164111963SAfshin.Ardakani@Sun.COM /* 164211963SAfshin.Ardakani@Sun.COM * Validates the given state based on the object type (root/link) 164311963SAfshin.Ardakani@Sun.COM * and whether it is the object's state or its target's state 164411963SAfshin.Ardakani@Sun.COM */ 164511963SAfshin.Ardakani@Sun.COM static uint32_t 164611963SAfshin.Ardakani@Sun.COM dfs_isvalidstate(uint32_t state, uint32_t type, boolean_t target) 164711963SAfshin.Ardakani@Sun.COM { 164811963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_SUCCESS; 164911963SAfshin.Ardakani@Sun.COM 165011963SAfshin.Ardakani@Sun.COM if (type == DFS_OBJECT_ROOT) { 165111963SAfshin.Ardakani@Sun.COM if (!target) 165211963SAfshin.Ardakani@Sun.COM return (dfs_root_isvalidstate(state)); 165311963SAfshin.Ardakani@Sun.COM 165411963SAfshin.Ardakani@Sun.COM if (!dfs_target_isvalidstate(state)) 165511963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER; 165611963SAfshin.Ardakani@Sun.COM else if (state == DFS_STORAGE_STATE_OFFLINE) 165711963SAfshin.Ardakani@Sun.COM status = ERROR_NOT_SUPPORTED; 165811963SAfshin.Ardakani@Sun.COM } else { 165911963SAfshin.Ardakani@Sun.COM if (!target) { 166011963SAfshin.Ardakani@Sun.COM if (!dfs_link_isvalidstate(state)) 166111963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER; 166211963SAfshin.Ardakani@Sun.COM } else { 166311963SAfshin.Ardakani@Sun.COM if (!dfs_target_isvalidstate(state)) 166411963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER; 166511963SAfshin.Ardakani@Sun.COM } 166611963SAfshin.Ardakani@Sun.COM } 166711963SAfshin.Ardakani@Sun.COM 166811963SAfshin.Ardakani@Sun.COM return (status); 166911963SAfshin.Ardakani@Sun.COM } 167011963SAfshin.Ardakani@Sun.COM 167111963SAfshin.Ardakani@Sun.COM /* 167211963SAfshin.Ardakani@Sun.COM * Based on the specified information level (infolvl) copy parts of the 167311963SAfshin.Ardakani@Sun.COM * information provided through newinfo into the existing information 167411963SAfshin.Ardakani@Sun.COM * (info) for the given object. 167511963SAfshin.Ardakani@Sun.COM */ 167611963SAfshin.Ardakani@Sun.COM static uint32_t 167711963SAfshin.Ardakani@Sun.COM dfs_modinfo(uint32_t type, dfs_info_t *info, dfs_info_t *newinfo, 167811963SAfshin.Ardakani@Sun.COM uint32_t infolvl) 167911963SAfshin.Ardakani@Sun.COM { 168011963SAfshin.Ardakani@Sun.COM boolean_t target_op = B_FALSE; 168111963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_SUCCESS; 168211963SAfshin.Ardakani@Sun.COM uint32_t state; 168311963SAfshin.Ardakani@Sun.COM int target_idx; 168411963SAfshin.Ardakani@Sun.COM 168511963SAfshin.Ardakani@Sun.COM if (newinfo->i_targets != NULL) { 168611963SAfshin.Ardakani@Sun.COM target_idx = dfs_target_find(info->i_targets, info->i_ntargets, 168711963SAfshin.Ardakani@Sun.COM newinfo->i_targets->t_server, newinfo->i_targets->t_share); 168811963SAfshin.Ardakani@Sun.COM if (target_idx == -1) 168911963SAfshin.Ardakani@Sun.COM return (ERROR_FILE_NOT_FOUND); 169011963SAfshin.Ardakani@Sun.COM target_op = B_TRUE; 169111963SAfshin.Ardakani@Sun.COM } 169211963SAfshin.Ardakani@Sun.COM 169311963SAfshin.Ardakani@Sun.COM switch (infolvl) { 169411963SAfshin.Ardakani@Sun.COM case 100: 169511963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_comment, newinfo->i_comment, 169611963SAfshin.Ardakani@Sun.COM sizeof (newinfo->i_comment)); 169711963SAfshin.Ardakani@Sun.COM break; 169811963SAfshin.Ardakani@Sun.COM 169911963SAfshin.Ardakani@Sun.COM case 101: 170011963SAfshin.Ardakani@Sun.COM state = (target_op) 170111963SAfshin.Ardakani@Sun.COM ? newinfo->i_targets->t_state : newinfo->i_state; 170211963SAfshin.Ardakani@Sun.COM status = dfs_isvalidstate(state, type, target_op); 170311963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) 170411963SAfshin.Ardakani@Sun.COM return (status); 170511963SAfshin.Ardakani@Sun.COM 170611963SAfshin.Ardakani@Sun.COM if (!target_op) { 170711963SAfshin.Ardakani@Sun.COM /* 170811963SAfshin.Ardakani@Sun.COM * states specified by this mask should not be stored 170911963SAfshin.Ardakani@Sun.COM */ 171011963SAfshin.Ardakani@Sun.COM if (state & DFS_VOLUME_STATES_SRV_OPS) 171111963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 171211963SAfshin.Ardakani@Sun.COM 171311963SAfshin.Ardakani@Sun.COM info->i_state = state; 171411963SAfshin.Ardakani@Sun.COM } else { 171511963SAfshin.Ardakani@Sun.COM info->i_targets[target_idx].t_state = state; 171611963SAfshin.Ardakani@Sun.COM } 171711963SAfshin.Ardakani@Sun.COM break; 171811963SAfshin.Ardakani@Sun.COM 171911963SAfshin.Ardakani@Sun.COM case 102: 172011963SAfshin.Ardakani@Sun.COM info->i_timeout = newinfo->i_timeout; 172111963SAfshin.Ardakani@Sun.COM break; 172211963SAfshin.Ardakani@Sun.COM 172311963SAfshin.Ardakani@Sun.COM case 103: 172411963SAfshin.Ardakani@Sun.COM info->i_propflags = newinfo->i_propflags; 172511963SAfshin.Ardakani@Sun.COM break; 172611963SAfshin.Ardakani@Sun.COM 172711963SAfshin.Ardakani@Sun.COM case 104: 172811963SAfshin.Ardakani@Sun.COM info->i_targets[target_idx].t_priority = 172911963SAfshin.Ardakani@Sun.COM newinfo->i_targets->t_priority; 173011963SAfshin.Ardakani@Sun.COM break; 173111963SAfshin.Ardakani@Sun.COM 173211963SAfshin.Ardakani@Sun.COM case 105: 173311963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_comment, newinfo->i_comment, 173411963SAfshin.Ardakani@Sun.COM sizeof (newinfo->i_comment)); 173511963SAfshin.Ardakani@Sun.COM info->i_state = newinfo->i_state; 173611963SAfshin.Ardakani@Sun.COM info->i_timeout = newinfo->i_timeout; 173711963SAfshin.Ardakani@Sun.COM info->i_propflags = newinfo->i_propflags; 173811963SAfshin.Ardakani@Sun.COM break; 173911963SAfshin.Ardakani@Sun.COM 174011963SAfshin.Ardakani@Sun.COM default: 174111963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_LEVEL; 174211963SAfshin.Ardakani@Sun.COM } 174311963SAfshin.Ardakani@Sun.COM 174411963SAfshin.Ardakani@Sun.COM return (status); 174511963SAfshin.Ardakani@Sun.COM } 1746