1*11963SAfshin.Ardakani@Sun.COM /* 2*11963SAfshin.Ardakani@Sun.COM * CDDL HEADER START 3*11963SAfshin.Ardakani@Sun.COM * 4*11963SAfshin.Ardakani@Sun.COM * The contents of this file are subject to the terms of the 5*11963SAfshin.Ardakani@Sun.COM * Common Development and Distribution License (the "License"). 6*11963SAfshin.Ardakani@Sun.COM * You may not use this file except in compliance with the License. 7*11963SAfshin.Ardakani@Sun.COM * 8*11963SAfshin.Ardakani@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*11963SAfshin.Ardakani@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*11963SAfshin.Ardakani@Sun.COM * See the License for the specific language governing permissions 11*11963SAfshin.Ardakani@Sun.COM * and limitations under the License. 12*11963SAfshin.Ardakani@Sun.COM * 13*11963SAfshin.Ardakani@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*11963SAfshin.Ardakani@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*11963SAfshin.Ardakani@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*11963SAfshin.Ardakani@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*11963SAfshin.Ardakani@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*11963SAfshin.Ardakani@Sun.COM * 19*11963SAfshin.Ardakani@Sun.COM * CDDL HEADER END 20*11963SAfshin.Ardakani@Sun.COM */ 21*11963SAfshin.Ardakani@Sun.COM /* 22*11963SAfshin.Ardakani@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23*11963SAfshin.Ardakani@Sun.COM * Use is subject to license terms. 24*11963SAfshin.Ardakani@Sun.COM */ 25*11963SAfshin.Ardakani@Sun.COM 26*11963SAfshin.Ardakani@Sun.COM #include <strings.h> 27*11963SAfshin.Ardakani@Sun.COM #include <errno.h> 28*11963SAfshin.Ardakani@Sun.COM #include <unistd.h> 29*11963SAfshin.Ardakani@Sun.COM #include <fcntl.h> 30*11963SAfshin.Ardakani@Sun.COM #include <dirent.h> 31*11963SAfshin.Ardakani@Sun.COM #include <pthread.h> 32*11963SAfshin.Ardakani@Sun.COM #include <syslog.h> 33*11963SAfshin.Ardakani@Sun.COM #include <sys/fs_reparse.h> 34*11963SAfshin.Ardakani@Sun.COM #include <uuid/uuid.h> 35*11963SAfshin.Ardakani@Sun.COM 36*11963SAfshin.Ardakani@Sun.COM #include <smbsrv/nterror.h> 37*11963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_dfs.h> 38*11963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_share.h> 39*11963SAfshin.Ardakani@Sun.COM #include <smbsrv/libsmb.h> 40*11963SAfshin.Ardakani@Sun.COM #include <smbsrv/libmlsvc.h> 41*11963SAfshin.Ardakani@Sun.COM #include <dfs.h> 42*11963SAfshin.Ardakani@Sun.COM 43*11963SAfshin.Ardakani@Sun.COM /* 44*11963SAfshin.Ardakani@Sun.COM * default timeout (TTL) values (in second) for root and link 45*11963SAfshin.Ardakani@Sun.COM */ 46*11963SAfshin.Ardakani@Sun.COM #define DFS_ROOT_TIMEOUT 300 47*11963SAfshin.Ardakani@Sun.COM #define DFS_LINK_TIMEOUT 1800 48*11963SAfshin.Ardakani@Sun.COM 49*11963SAfshin.Ardakani@Sun.COM /* 50*11963SAfshin.Ardakani@Sun.COM * DFS link data format in reparse point 51*11963SAfshin.Ardakani@Sun.COM * 52*11963SAfshin.Ardakani@Sun.COM * ver:state:prop:timeout:guid:ntarget:cmntlen:comment 53*11963SAfshin.Ardakani@Sun.COM * [[:tserver:tshare:tstate:pclass:prank]...] 54*11963SAfshin.Ardakani@Sun.COM */ 55*11963SAfshin.Ardakani@Sun.COM #define DFS_LINK_V1 1 56*11963SAfshin.Ardakani@Sun.COM #define DFS_LINK_HDR_NFIELDS 7 /* # fields in header section */ 57*11963SAfshin.Ardakani@Sun.COM #define DFS_LINK_TRGT_NFIELDS 5 /* # fields for each target */ 58*11963SAfshin.Ardakani@Sun.COM 59*11963SAfshin.Ardakani@Sun.COM #define DFS_ROOT_XATTR "SUNWdfs.rootinfo" 60*11963SAfshin.Ardakani@Sun.COM 61*11963SAfshin.Ardakani@Sun.COM #define DFS_INFO_ALL 0 62*11963SAfshin.Ardakani@Sun.COM 63*11963SAfshin.Ardakani@Sun.COM /* 64*11963SAfshin.Ardakani@Sun.COM * Namespace cache 65*11963SAfshin.Ardakani@Sun.COM * 66*11963SAfshin.Ardakani@Sun.COM * Caches links' UNC and filesystem path where the key is the UNC path. 67*11963SAfshin.Ardakani@Sun.COM */ 68*11963SAfshin.Ardakani@Sun.COM static smb_cache_t dfs_nscache; 69*11963SAfshin.Ardakani@Sun.COM static char dfs_nbname[NETBIOS_NAME_SZ]; 70*11963SAfshin.Ardakani@Sun.COM 71*11963SAfshin.Ardakani@Sun.COM /* 72*11963SAfshin.Ardakani@Sun.COM * Lock for accessing root information (extended attribute) 73*11963SAfshin.Ardakani@Sun.COM */ 74*11963SAfshin.Ardakani@Sun.COM static rwlock_t dfs_root_rwl; 75*11963SAfshin.Ardakani@Sun.COM 76*11963SAfshin.Ardakani@Sun.COM extern uint32_t srvsvc_shr_setdfsroot(smb_share_t *, boolean_t); 77*11963SAfshin.Ardakani@Sun.COM 78*11963SAfshin.Ardakani@Sun.COM /* 79*11963SAfshin.Ardakani@Sun.COM * Namespace functions 80*11963SAfshin.Ardakani@Sun.COM */ 81*11963SAfshin.Ardakani@Sun.COM static boolean_t dfs_namespace_findlink(const char *, char *, char *, size_t); 82*11963SAfshin.Ardakani@Sun.COM static void *dfs_namespace_cache(void *); 83*11963SAfshin.Ardakani@Sun.COM 84*11963SAfshin.Ardakani@Sun.COM /* 85*11963SAfshin.Ardakani@Sun.COM * Root functions 86*11963SAfshin.Ardakani@Sun.COM */ 87*11963SAfshin.Ardakani@Sun.COM static int dfs_root_add(const char *, dfs_info_t *); 88*11963SAfshin.Ardakani@Sun.COM static uint32_t dfs_root_remove(const char *); 89*11963SAfshin.Ardakani@Sun.COM static uint32_t dfs_root_encode(dfs_info_t *, char **, size_t *); 90*11963SAfshin.Ardakani@Sun.COM static uint32_t dfs_root_decode(dfs_info_t *, char *, size_t, uint32_t); 91*11963SAfshin.Ardakani@Sun.COM static uint32_t dfs_root_isvalidstate(uint32_t); 92*11963SAfshin.Ardakani@Sun.COM 93*11963SAfshin.Ardakani@Sun.COM static int dfs_root_xopen(const char *, int); 94*11963SAfshin.Ardakani@Sun.COM static void dfs_root_xclose(int); 95*11963SAfshin.Ardakani@Sun.COM static uint32_t dfs_root_xwrite(int, dfs_info_t *); 96*11963SAfshin.Ardakani@Sun.COM static uint32_t dfs_root_xread(int, dfs_info_t *, uint32_t); 97*11963SAfshin.Ardakani@Sun.COM 98*11963SAfshin.Ardakani@Sun.COM /* 99*11963SAfshin.Ardakani@Sun.COM * Link functions 100*11963SAfshin.Ardakani@Sun.COM */ 101*11963SAfshin.Ardakani@Sun.COM static uint32_t dfs_link_encode(dfs_info_t *, char *, size_t); 102*11963SAfshin.Ardakani@Sun.COM static uint32_t dfs_link_decode(dfs_info_t *, char *, uint32_t); 103*11963SAfshin.Ardakani@Sun.COM static uint32_t dfs_link_commit(const char *, dfs_info_t *); 104*11963SAfshin.Ardakani@Sun.COM static boolean_t dfs_link_isvalidstate(uint32_t); 105*11963SAfshin.Ardakani@Sun.COM 106*11963SAfshin.Ardakani@Sun.COM /* 107*11963SAfshin.Ardakani@Sun.COM * Target functions 108*11963SAfshin.Ardakani@Sun.COM */ 109*11963SAfshin.Ardakani@Sun.COM static void dfs_target_init(dfs_target_t *, const char *, const char *, 110*11963SAfshin.Ardakani@Sun.COM uint32_t); 111*11963SAfshin.Ardakani@Sun.COM static int dfs_target_find(dfs_target_t *, uint32_t, const char *, 112*11963SAfshin.Ardakani@Sun.COM const char *); 113*11963SAfshin.Ardakani@Sun.COM static boolean_t dfs_target_isvalidstate(uint32_t); 114*11963SAfshin.Ardakani@Sun.COM 115*11963SAfshin.Ardakani@Sun.COM /* 116*11963SAfshin.Ardakani@Sun.COM * Cache functions 117*11963SAfshin.Ardakani@Sun.COM */ 118*11963SAfshin.Ardakani@Sun.COM static uint32_t dfs_cache_add_byunc(const char *, const char *, uint32_t); 119*11963SAfshin.Ardakani@Sun.COM static void dfs_cache_populate(const char *, const char *); 120*11963SAfshin.Ardakani@Sun.COM static int dfs_cache_cmp(const void *, const void *); 121*11963SAfshin.Ardakani@Sun.COM 122*11963SAfshin.Ardakani@Sun.COM /* 123*11963SAfshin.Ardakani@Sun.COM * Utility functions 124*11963SAfshin.Ardakani@Sun.COM */ 125*11963SAfshin.Ardakani@Sun.COM static boolean_t dfs_path_isdir(const char *); 126*11963SAfshin.Ardakani@Sun.COM static uint32_t dfs_modinfo(uint32_t, dfs_info_t *, dfs_info_t *, uint32_t); 127*11963SAfshin.Ardakani@Sun.COM 128*11963SAfshin.Ardakani@Sun.COM /* 129*11963SAfshin.Ardakani@Sun.COM * DFS module initializationr: 130*11963SAfshin.Ardakani@Sun.COM * 131*11963SAfshin.Ardakani@Sun.COM * - creates the namespace cache 132*11963SAfshin.Ardakani@Sun.COM * - gets system's NetBIOS name 133*11963SAfshin.Ardakani@Sun.COM */ 134*11963SAfshin.Ardakani@Sun.COM void 135*11963SAfshin.Ardakani@Sun.COM dfs_init(void) 136*11963SAfshin.Ardakani@Sun.COM { 137*11963SAfshin.Ardakani@Sun.COM smb_domain_t di; 138*11963SAfshin.Ardakani@Sun.COM 139*11963SAfshin.Ardakani@Sun.COM smb_cache_create(&dfs_nscache, 0, dfs_cache_cmp, free, bcopy, 140*11963SAfshin.Ardakani@Sun.COM sizeof (dfs_nscnode_t)); 141*11963SAfshin.Ardakani@Sun.COM 142*11963SAfshin.Ardakani@Sun.COM if (!smb_domain_lookup_type(SMB_DOMAIN_LOCAL, &di)) 143*11963SAfshin.Ardakani@Sun.COM return; 144*11963SAfshin.Ardakani@Sun.COM 145*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(dfs_nbname, di.di_nbname, NETBIOS_NAME_SZ); 146*11963SAfshin.Ardakani@Sun.COM } 147*11963SAfshin.Ardakani@Sun.COM 148*11963SAfshin.Ardakani@Sun.COM /* 149*11963SAfshin.Ardakani@Sun.COM * DFS module cleanup: 150*11963SAfshin.Ardakani@Sun.COM * 151*11963SAfshin.Ardakani@Sun.COM * - destroys the namespace cache 152*11963SAfshin.Ardakani@Sun.COM */ 153*11963SAfshin.Ardakani@Sun.COM void 154*11963SAfshin.Ardakani@Sun.COM dfs_fini(void) 155*11963SAfshin.Ardakani@Sun.COM { 156*11963SAfshin.Ardakani@Sun.COM smb_cache_destroy(&dfs_nscache); 157*11963SAfshin.Ardakani@Sun.COM } 158*11963SAfshin.Ardakani@Sun.COM 159*11963SAfshin.Ardakani@Sun.COM /* 160*11963SAfshin.Ardakani@Sun.COM * To successfully handle some of link/root requests, some 161*11963SAfshin.Ardakani@Sun.COM * file system operations need to be performed. These operations 162*11963SAfshin.Ardakani@Sun.COM * should take place on behalf of the connected user (typically 163*11963SAfshin.Ardakani@Sun.COM * Administrator) and to do so we need to have an infrastructure 164*11963SAfshin.Ardakani@Sun.COM * in place so that smbd can act as a client and sends request to 165*11963SAfshin.Ardakani@Sun.COM * the kernel. Right now, we lack this infrastructure, so we make 166*11963SAfshin.Ardakani@Sun.COM * a compromise by temporarily enabling some privileges for smbd 167*11963SAfshin.Ardakani@Sun.COM * to be able to fulfill various link/root requests. 168*11963SAfshin.Ardakani@Sun.COM */ 169*11963SAfshin.Ardakani@Sun.COM void 170*11963SAfshin.Ardakani@Sun.COM dfs_setpriv(priv_op_t op) 171*11963SAfshin.Ardakani@Sun.COM { 172*11963SAfshin.Ardakani@Sun.COM (void) priv_set(op, PRIV_EFFECTIVE, 173*11963SAfshin.Ardakani@Sun.COM PRIV_FILE_DAC_READ, 174*11963SAfshin.Ardakani@Sun.COM PRIV_FILE_DAC_WRITE, 175*11963SAfshin.Ardakani@Sun.COM PRIV_FILE_DAC_EXECUTE, 176*11963SAfshin.Ardakani@Sun.COM PRIV_FILE_DAC_SEARCH, NULL); 177*11963SAfshin.Ardakani@Sun.COM } 178*11963SAfshin.Ardakani@Sun.COM 179*11963SAfshin.Ardakani@Sun.COM /* 180*11963SAfshin.Ardakani@Sun.COM * ======================== 181*11963SAfshin.Ardakani@Sun.COM * Namespace API (public) 182*11963SAfshin.Ardakani@Sun.COM * ======================== 183*11963SAfshin.Ardakani@Sun.COM */ 184*11963SAfshin.Ardakani@Sun.COM 185*11963SAfshin.Ardakani@Sun.COM /* 186*11963SAfshin.Ardakani@Sun.COM * Launches a thread to cache the specified namespace 187*11963SAfshin.Ardakani@Sun.COM */ 188*11963SAfshin.Ardakani@Sun.COM void 189*11963SAfshin.Ardakani@Sun.COM dfs_namespace_load(const char *name) 190*11963SAfshin.Ardakani@Sun.COM { 191*11963SAfshin.Ardakani@Sun.COM pthread_t thr; 192*11963SAfshin.Ardakani@Sun.COM pthread_attr_t tattr; 193*11963SAfshin.Ardakani@Sun.COM char *rootshr; 194*11963SAfshin.Ardakani@Sun.COM int rc; 195*11963SAfshin.Ardakani@Sun.COM 196*11963SAfshin.Ardakani@Sun.COM if ((rootshr = strdup(name)) == NULL) { 197*11963SAfshin.Ardakani@Sun.COM syslog(LOG_ERR, "dfs: failed to load %s namespace (no memory)", 198*11963SAfshin.Ardakani@Sun.COM name); 199*11963SAfshin.Ardakani@Sun.COM return; 200*11963SAfshin.Ardakani@Sun.COM } 201*11963SAfshin.Ardakani@Sun.COM 202*11963SAfshin.Ardakani@Sun.COM (void) pthread_attr_init(&tattr); 203*11963SAfshin.Ardakani@Sun.COM (void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); 204*11963SAfshin.Ardakani@Sun.COM rc = pthread_create(&thr, &tattr, dfs_namespace_cache, rootshr); 205*11963SAfshin.Ardakani@Sun.COM (void) pthread_attr_destroy(&tattr); 206*11963SAfshin.Ardakani@Sun.COM 207*11963SAfshin.Ardakani@Sun.COM if (rc != 0) 208*11963SAfshin.Ardakani@Sun.COM syslog(LOG_ERR, "dfs: fail to loading %s namespace (%d)", 209*11963SAfshin.Ardakani@Sun.COM name, rc); 210*11963SAfshin.Ardakani@Sun.COM } 211*11963SAfshin.Ardakani@Sun.COM 212*11963SAfshin.Ardakani@Sun.COM /* 213*11963SAfshin.Ardakani@Sun.COM * Flushes the cache when a DFS root share is removed 214*11963SAfshin.Ardakani@Sun.COM */ 215*11963SAfshin.Ardakani@Sun.COM void /*ARGSUSED*/ 216*11963SAfshin.Ardakani@Sun.COM dfs_namespace_unload(const char *name) 217*11963SAfshin.Ardakani@Sun.COM { 218*11963SAfshin.Ardakani@Sun.COM smb_cache_flush(&dfs_nscache); 219*11963SAfshin.Ardakani@Sun.COM } 220*11963SAfshin.Ardakani@Sun.COM 221*11963SAfshin.Ardakani@Sun.COM /* 222*11963SAfshin.Ardakani@Sun.COM * Returns the file system path for the given share if it 223*11963SAfshin.Ardakani@Sun.COM * is a DFS root share. 224*11963SAfshin.Ardakani@Sun.COM * If 'path' is NULL, this function only indicates whether 225*11963SAfshin.Ardakani@Sun.COM * or not the given share represents a DFS namespace 226*11963SAfshin.Ardakani@Sun.COM */ 227*11963SAfshin.Ardakani@Sun.COM uint32_t 228*11963SAfshin.Ardakani@Sun.COM dfs_namespace_path(const char *name, char *path, size_t pathsz) 229*11963SAfshin.Ardakani@Sun.COM { 230*11963SAfshin.Ardakani@Sun.COM smb_share_t si; 231*11963SAfshin.Ardakani@Sun.COM 232*11963SAfshin.Ardakani@Sun.COM if (smb_shr_get((char *)name, &si) != NERR_Success) 233*11963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND); 234*11963SAfshin.Ardakani@Sun.COM 235*11963SAfshin.Ardakani@Sun.COM if ((si.shr_flags & SMB_SHRF_DFSROOT) == 0) 236*11963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND); 237*11963SAfshin.Ardakani@Sun.COM 238*11963SAfshin.Ardakani@Sun.COM if (path != NULL) 239*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(path, si.shr_path, pathsz); 240*11963SAfshin.Ardakani@Sun.COM 241*11963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 242*11963SAfshin.Ardakani@Sun.COM } 243*11963SAfshin.Ardakani@Sun.COM 244*11963SAfshin.Ardakani@Sun.COM /* 245*11963SAfshin.Ardakani@Sun.COM * Returns the number of DFS root shares i.e. the number 246*11963SAfshin.Ardakani@Sun.COM * of standalone namespaces. 247*11963SAfshin.Ardakani@Sun.COM */ 248*11963SAfshin.Ardakani@Sun.COM uint32_t 249*11963SAfshin.Ardakani@Sun.COM dfs_namespace_count(void) 250*11963SAfshin.Ardakani@Sun.COM { 251*11963SAfshin.Ardakani@Sun.COM smb_shriter_t shi; 252*11963SAfshin.Ardakani@Sun.COM smb_share_t *si; 253*11963SAfshin.Ardakani@Sun.COM uint32_t nroot = 0; 254*11963SAfshin.Ardakani@Sun.COM 255*11963SAfshin.Ardakani@Sun.COM smb_shr_iterinit(&shi); 256*11963SAfshin.Ardakani@Sun.COM while ((si = smb_shr_iterate(&shi)) != NULL) { 257*11963SAfshin.Ardakani@Sun.COM if ((si->shr_flags & SMB_SHRF_DFSROOT) != 0) 258*11963SAfshin.Ardakani@Sun.COM nroot++; 259*11963SAfshin.Ardakani@Sun.COM } 260*11963SAfshin.Ardakani@Sun.COM 261*11963SAfshin.Ardakani@Sun.COM return (nroot); 262*11963SAfshin.Ardakani@Sun.COM } 263*11963SAfshin.Ardakani@Sun.COM 264*11963SAfshin.Ardakani@Sun.COM /* 265*11963SAfshin.Ardakani@Sun.COM * Creates a DFS root with the given name and comment. 266*11963SAfshin.Ardakani@Sun.COM * 267*11963SAfshin.Ardakani@Sun.COM * This function does not create the root share, it 268*11963SAfshin.Ardakani@Sun.COM * should already exist. 269*11963SAfshin.Ardakani@Sun.COM */ 270*11963SAfshin.Ardakani@Sun.COM uint32_t 271*11963SAfshin.Ardakani@Sun.COM dfs_namespace_add(const char *rootshr, const char *cmnt) 272*11963SAfshin.Ardakani@Sun.COM { 273*11963SAfshin.Ardakani@Sun.COM dfs_info_t info; 274*11963SAfshin.Ardakani@Sun.COM dfs_target_t t; 275*11963SAfshin.Ardakani@Sun.COM smb_share_t si; 276*11963SAfshin.Ardakani@Sun.COM uuid_t uuid; 277*11963SAfshin.Ardakani@Sun.COM uint32_t status; 278*11963SAfshin.Ardakani@Sun.COM 279*11963SAfshin.Ardakani@Sun.COM if (*rootshr == '\\') { 280*11963SAfshin.Ardakani@Sun.COM /* Windows has a special case here! */ 281*11963SAfshin.Ardakani@Sun.COM return (ERROR_BAD_PATHNAME); 282*11963SAfshin.Ardakani@Sun.COM } 283*11963SAfshin.Ardakani@Sun.COM 284*11963SAfshin.Ardakani@Sun.COM if (smb_shr_get((char *)rootshr, &si) != NERR_Success) 285*11963SAfshin.Ardakani@Sun.COM return (NERR_NetNameNotFound); 286*11963SAfshin.Ardakani@Sun.COM 287*11963SAfshin.Ardakani@Sun.COM if (si.shr_flags & SMB_SHRF_DFSROOT) { 288*11963SAfshin.Ardakani@Sun.COM /* Share is already a DFS root */ 289*11963SAfshin.Ardakani@Sun.COM return (ERROR_FILE_EXISTS); 290*11963SAfshin.Ardakani@Sun.COM } 291*11963SAfshin.Ardakani@Sun.COM 292*11963SAfshin.Ardakani@Sun.COM bzero(&info, sizeof (info)); 293*11963SAfshin.Ardakani@Sun.COM if (cmnt) 294*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(info.i_comment, cmnt, sizeof (info.i_comment)); 295*11963SAfshin.Ardakani@Sun.COM info.i_state = DFS_VOLUME_STATE_OK | DFS_VOLUME_FLAVOR_STANDALONE; 296*11963SAfshin.Ardakani@Sun.COM info.i_timeout = DFS_ROOT_TIMEOUT; 297*11963SAfshin.Ardakani@Sun.COM info.i_propflags = 0; 298*11963SAfshin.Ardakani@Sun.COM 299*11963SAfshin.Ardakani@Sun.COM uuid_generate_random(uuid); 300*11963SAfshin.Ardakani@Sun.COM uuid_unparse(uuid, info.i_guid); 301*11963SAfshin.Ardakani@Sun.COM 302*11963SAfshin.Ardakani@Sun.COM dfs_target_init(&t, dfs_nbname, rootshr, DFS_STORAGE_STATE_ONLINE); 303*11963SAfshin.Ardakani@Sun.COM 304*11963SAfshin.Ardakani@Sun.COM info.i_ntargets = 1; 305*11963SAfshin.Ardakani@Sun.COM info.i_targets = &t; 306*11963SAfshin.Ardakani@Sun.COM 307*11963SAfshin.Ardakani@Sun.COM if ((status = dfs_root_add(si.shr_path, &info)) != ERROR_SUCCESS) 308*11963SAfshin.Ardakani@Sun.COM return (status); 309*11963SAfshin.Ardakani@Sun.COM 310*11963SAfshin.Ardakani@Sun.COM status = srvsvc_shr_setdfsroot(&si, B_TRUE); 311*11963SAfshin.Ardakani@Sun.COM if (status == ERROR_SUCCESS) 312*11963SAfshin.Ardakani@Sun.COM (void) dfs_cache_add_byname(rootshr, NULL, DFS_OBJECT_ROOT); 313*11963SAfshin.Ardakani@Sun.COM 314*11963SAfshin.Ardakani@Sun.COM return (status); 315*11963SAfshin.Ardakani@Sun.COM } 316*11963SAfshin.Ardakani@Sun.COM 317*11963SAfshin.Ardakani@Sun.COM /* 318*11963SAfshin.Ardakani@Sun.COM * Removes the namespace and all the links in it. 319*11963SAfshin.Ardakani@Sun.COM */ 320*11963SAfshin.Ardakani@Sun.COM uint32_t 321*11963SAfshin.Ardakani@Sun.COM dfs_namespace_remove(const char *name) 322*11963SAfshin.Ardakani@Sun.COM { 323*11963SAfshin.Ardakani@Sun.COM smb_cache_cursor_t cursor; 324*11963SAfshin.Ardakani@Sun.COM dfs_nscnode_t nscnode; 325*11963SAfshin.Ardakani@Sun.COM smb_share_t si; 326*11963SAfshin.Ardakani@Sun.COM uint32_t status; 327*11963SAfshin.Ardakani@Sun.COM 328*11963SAfshin.Ardakani@Sun.COM if (smb_shr_get((char *)name, &si) != NERR_Success) 329*11963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND); 330*11963SAfshin.Ardakani@Sun.COM 331*11963SAfshin.Ardakani@Sun.COM if ((si.shr_flags & SMB_SHRF_DFSROOT) == 0) 332*11963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND); 333*11963SAfshin.Ardakani@Sun.COM 334*11963SAfshin.Ardakani@Sun.COM if ((status = dfs_root_remove(si.shr_path)) != ERROR_SUCCESS) 335*11963SAfshin.Ardakani@Sun.COM return (status); 336*11963SAfshin.Ardakani@Sun.COM 337*11963SAfshin.Ardakani@Sun.COM status = srvsvc_shr_setdfsroot(&si, B_FALSE); 338*11963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) 339*11963SAfshin.Ardakani@Sun.COM syslog(LOG_WARNING, "dfs: failed to disable root share %s (%d)", 340*11963SAfshin.Ardakani@Sun.COM name, status); 341*11963SAfshin.Ardakani@Sun.COM 342*11963SAfshin.Ardakani@Sun.COM smb_cache_iterinit(&dfs_nscache, &cursor); 343*11963SAfshin.Ardakani@Sun.COM 344*11963SAfshin.Ardakani@Sun.COM while (smb_cache_iterate(&dfs_nscache, &cursor, &nscnode)) { 345*11963SAfshin.Ardakani@Sun.COM if (nscnode.nsc_type == DFS_OBJECT_ROOT) 346*11963SAfshin.Ardakani@Sun.COM continue; 347*11963SAfshin.Ardakani@Sun.COM status = dfs_link_remove(nscnode.nsc_fspath, NULL, NULL); 348*11963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) 349*11963SAfshin.Ardakani@Sun.COM syslog(LOG_WARNING, "dfs: failed to remove %s (%d)", 350*11963SAfshin.Ardakani@Sun.COM nscnode.nsc_fspath, status); 351*11963SAfshin.Ardakani@Sun.COM } 352*11963SAfshin.Ardakani@Sun.COM 353*11963SAfshin.Ardakani@Sun.COM smb_cache_flush(&dfs_nscache); 354*11963SAfshin.Ardakani@Sun.COM 355*11963SAfshin.Ardakani@Sun.COM /* TODO: remove empty dirs */ 356*11963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 357*11963SAfshin.Ardakani@Sun.COM } 358*11963SAfshin.Ardakani@Sun.COM 359*11963SAfshin.Ardakani@Sun.COM /* 360*11963SAfshin.Ardakani@Sun.COM * ================== 361*11963SAfshin.Ardakani@Sun.COM * Root API (public) 362*11963SAfshin.Ardakani@Sun.COM * ================== 363*11963SAfshin.Ardakani@Sun.COM */ 364*11963SAfshin.Ardakani@Sun.COM 365*11963SAfshin.Ardakani@Sun.COM /* 366*11963SAfshin.Ardakani@Sun.COM * Retrieves the information of the root specified by its path. 367*11963SAfshin.Ardakani@Sun.COM * 368*11963SAfshin.Ardakani@Sun.COM * Info level (1) only needs the UNC path which is not stored, 369*11963SAfshin.Ardakani@Sun.COM * it is constructed so the function will return without 370*11963SAfshin.Ardakani@Sun.COM * accessing the backend storage. 371*11963SAfshin.Ardakani@Sun.COM */ 372*11963SAfshin.Ardakani@Sun.COM uint32_t 373*11963SAfshin.Ardakani@Sun.COM dfs_root_getinfo(const char *rootdir, dfs_info_t *info, uint32_t infolvl) 374*11963SAfshin.Ardakani@Sun.COM { 375*11963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_INTERNAL_ERROR; 376*11963SAfshin.Ardakani@Sun.COM int xfd; 377*11963SAfshin.Ardakani@Sun.COM 378*11963SAfshin.Ardakani@Sun.COM bzero(info, sizeof (dfs_info_t)); 379*11963SAfshin.Ardakani@Sun.COM info->i_type = DFS_OBJECT_ROOT; 380*11963SAfshin.Ardakani@Sun.COM 381*11963SAfshin.Ardakani@Sun.COM if (infolvl == 1) 382*11963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 383*11963SAfshin.Ardakani@Sun.COM 384*11963SAfshin.Ardakani@Sun.COM (void) rw_rdlock(&dfs_root_rwl); 385*11963SAfshin.Ardakani@Sun.COM if ((xfd = dfs_root_xopen(rootdir, O_RDONLY)) > 0) { 386*11963SAfshin.Ardakani@Sun.COM status = dfs_root_xread(xfd, info, infolvl); 387*11963SAfshin.Ardakani@Sun.COM dfs_root_xclose(xfd); 388*11963SAfshin.Ardakani@Sun.COM } 389*11963SAfshin.Ardakani@Sun.COM (void) rw_unlock(&dfs_root_rwl); 390*11963SAfshin.Ardakani@Sun.COM 391*11963SAfshin.Ardakani@Sun.COM return (status); 392*11963SAfshin.Ardakani@Sun.COM } 393*11963SAfshin.Ardakani@Sun.COM 394*11963SAfshin.Ardakani@Sun.COM /* 395*11963SAfshin.Ardakani@Sun.COM * Sets the provided information for the specified root or root target. 396*11963SAfshin.Ardakani@Sun.COM * Root is specified by 'rootdir' and the target is specified by 397*11963SAfshin.Ardakani@Sun.COM * (t_server, t_share) pair. Only information items needed for given 398*11963SAfshin.Ardakani@Sun.COM * information level (infolvl) is valid in the passed DFS info structure 399*11963SAfshin.Ardakani@Sun.COM * 'info'. 400*11963SAfshin.Ardakani@Sun.COM */ 401*11963SAfshin.Ardakani@Sun.COM uint32_t 402*11963SAfshin.Ardakani@Sun.COM dfs_root_setinfo(const char *rootdir, dfs_info_t *info, uint32_t infolvl) 403*11963SAfshin.Ardakani@Sun.COM { 404*11963SAfshin.Ardakani@Sun.COM dfs_info_t curinfo; 405*11963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_SUCCESS; 406*11963SAfshin.Ardakani@Sun.COM int xfd; 407*11963SAfshin.Ardakani@Sun.COM 408*11963SAfshin.Ardakani@Sun.COM (void) rw_wrlock(&dfs_root_rwl); 409*11963SAfshin.Ardakani@Sun.COM if ((xfd = dfs_root_xopen(rootdir, O_RDWR)) < 0) { 410*11963SAfshin.Ardakani@Sun.COM (void) rw_unlock(&dfs_root_rwl); 411*11963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 412*11963SAfshin.Ardakani@Sun.COM } 413*11963SAfshin.Ardakani@Sun.COM 414*11963SAfshin.Ardakani@Sun.COM status = dfs_root_xread(xfd, &curinfo, DFS_INFO_ALL); 415*11963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) { 416*11963SAfshin.Ardakani@Sun.COM dfs_root_xclose(xfd); 417*11963SAfshin.Ardakani@Sun.COM (void) rw_unlock(&dfs_root_rwl); 418*11963SAfshin.Ardakani@Sun.COM return (status); 419*11963SAfshin.Ardakani@Sun.COM } 420*11963SAfshin.Ardakani@Sun.COM 421*11963SAfshin.Ardakani@Sun.COM status = dfs_modinfo(DFS_OBJECT_ROOT, &curinfo, info, infolvl); 422*11963SAfshin.Ardakani@Sun.COM if (status == ERROR_SUCCESS) 423*11963SAfshin.Ardakani@Sun.COM status = dfs_root_xwrite(xfd, &curinfo); 424*11963SAfshin.Ardakani@Sun.COM 425*11963SAfshin.Ardakani@Sun.COM dfs_root_xclose(xfd); 426*11963SAfshin.Ardakani@Sun.COM (void) rw_unlock(&dfs_root_rwl); 427*11963SAfshin.Ardakani@Sun.COM 428*11963SAfshin.Ardakani@Sun.COM dfs_info_free(&curinfo); 429*11963SAfshin.Ardakani@Sun.COM return (status); 430*11963SAfshin.Ardakani@Sun.COM } 431*11963SAfshin.Ardakani@Sun.COM 432*11963SAfshin.Ardakani@Sun.COM /* 433*11963SAfshin.Ardakani@Sun.COM * ================== 434*11963SAfshin.Ardakani@Sun.COM * Link API (public) 435*11963SAfshin.Ardakani@Sun.COM * ================== 436*11963SAfshin.Ardakani@Sun.COM */ 437*11963SAfshin.Ardakani@Sun.COM 438*11963SAfshin.Ardakani@Sun.COM /* 439*11963SAfshin.Ardakani@Sun.COM * Gets the status of the given path as a link 440*11963SAfshin.Ardakani@Sun.COM */ 441*11963SAfshin.Ardakani@Sun.COM uint32_t 442*11963SAfshin.Ardakani@Sun.COM dfs_link_stat(const char *path, uint32_t *stat) 443*11963SAfshin.Ardakani@Sun.COM { 444*11963SAfshin.Ardakani@Sun.COM if (smb_reparse_stat(path, stat) != 0) 445*11963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 446*11963SAfshin.Ardakani@Sun.COM 447*11963SAfshin.Ardakani@Sun.COM switch (*stat) { 448*11963SAfshin.Ardakani@Sun.COM case SMB_REPARSE_NOTFOUND: 449*11963SAfshin.Ardakani@Sun.COM *stat = DFS_STAT_NOTFOUND; 450*11963SAfshin.Ardakani@Sun.COM break; 451*11963SAfshin.Ardakani@Sun.COM case SMB_REPARSE_NOTREPARSE: 452*11963SAfshin.Ardakani@Sun.COM *stat = DFS_STAT_NOTLINK; 453*11963SAfshin.Ardakani@Sun.COM break; 454*11963SAfshin.Ardakani@Sun.COM case SMB_REPARSE_ISREPARSE: 455*11963SAfshin.Ardakani@Sun.COM *stat = DFS_STAT_ISREPARSE; 456*11963SAfshin.Ardakani@Sun.COM if (smb_reparse_svcget(path, DFS_REPARSE_SVCTYPE, NULL) == 0) 457*11963SAfshin.Ardakani@Sun.COM *stat = DFS_STAT_ISDFS; 458*11963SAfshin.Ardakani@Sun.COM break; 459*11963SAfshin.Ardakani@Sun.COM default: 460*11963SAfshin.Ardakani@Sun.COM *stat = DFS_STAT_UNKNOWN; 461*11963SAfshin.Ardakani@Sun.COM break; 462*11963SAfshin.Ardakani@Sun.COM } 463*11963SAfshin.Ardakani@Sun.COM 464*11963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 465*11963SAfshin.Ardakani@Sun.COM } 466*11963SAfshin.Ardakani@Sun.COM 467*11963SAfshin.Ardakani@Sun.COM /* 468*11963SAfshin.Ardakani@Sun.COM * Creates a new DFS link or adds a new target to an existing link 469*11963SAfshin.Ardakani@Sun.COM */ 470*11963SAfshin.Ardakani@Sun.COM uint32_t 471*11963SAfshin.Ardakani@Sun.COM dfs_link_add(const char *path, const char *server, const char *share, 472*11963SAfshin.Ardakani@Sun.COM const char *cmnt, uint32_t flags, boolean_t *newlink) 473*11963SAfshin.Ardakani@Sun.COM { 474*11963SAfshin.Ardakani@Sun.COM dfs_info_t info; 475*11963SAfshin.Ardakani@Sun.COM dfs_target_t *t; 476*11963SAfshin.Ardakani@Sun.COM int ntargets; 477*11963SAfshin.Ardakani@Sun.COM uint32_t status; 478*11963SAfshin.Ardakani@Sun.COM uint32_t stat; 479*11963SAfshin.Ardakani@Sun.COM 480*11963SAfshin.Ardakani@Sun.COM *newlink = B_FALSE; 481*11963SAfshin.Ardakani@Sun.COM 482*11963SAfshin.Ardakani@Sun.COM if ((status = dfs_link_stat(path, &stat)) != ERROR_SUCCESS) 483*11963SAfshin.Ardakani@Sun.COM return (status); 484*11963SAfshin.Ardakani@Sun.COM 485*11963SAfshin.Ardakani@Sun.COM switch (stat) { 486*11963SAfshin.Ardakani@Sun.COM case DFS_STAT_NOTFOUND: 487*11963SAfshin.Ardakani@Sun.COM case DFS_STAT_ISREPARSE: 488*11963SAfshin.Ardakani@Sun.COM /* Create a new DFS link */ 489*11963SAfshin.Ardakani@Sun.COM 490*11963SAfshin.Ardakani@Sun.COM status = dfs_link_getinfo(NULL, &info, DFS_INFO_ALL); 491*11963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) 492*11963SAfshin.Ardakani@Sun.COM return (status); 493*11963SAfshin.Ardakani@Sun.COM 494*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(info.i_comment, (cmnt) ? cmnt : "", 495*11963SAfshin.Ardakani@Sun.COM sizeof (info.i_comment)); 496*11963SAfshin.Ardakani@Sun.COM *newlink = B_TRUE; 497*11963SAfshin.Ardakani@Sun.COM break; 498*11963SAfshin.Ardakani@Sun.COM 499*11963SAfshin.Ardakani@Sun.COM case DFS_STAT_ISDFS: 500*11963SAfshin.Ardakani@Sun.COM /* Add a target to an existing link */ 501*11963SAfshin.Ardakani@Sun.COM 502*11963SAfshin.Ardakani@Sun.COM if (flags & DFS_ADD_VOLUME) 503*11963SAfshin.Ardakani@Sun.COM return (ERROR_FILE_EXISTS); 504*11963SAfshin.Ardakani@Sun.COM 505*11963SAfshin.Ardakani@Sun.COM status = dfs_link_getinfo(path, &info, DFS_INFO_ALL); 506*11963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) 507*11963SAfshin.Ardakani@Sun.COM return (status); 508*11963SAfshin.Ardakani@Sun.COM 509*11963SAfshin.Ardakani@Sun.COM break; 510*11963SAfshin.Ardakani@Sun.COM 511*11963SAfshin.Ardakani@Sun.COM case DFS_STAT_NOTLINK: 512*11963SAfshin.Ardakani@Sun.COM /* specified path points to a non-reparse object */ 513*11963SAfshin.Ardakani@Sun.COM return (ERROR_FILE_EXISTS); 514*11963SAfshin.Ardakani@Sun.COM 515*11963SAfshin.Ardakani@Sun.COM default: 516*11963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 517*11963SAfshin.Ardakani@Sun.COM } 518*11963SAfshin.Ardakani@Sun.COM 519*11963SAfshin.Ardakani@Sun.COM /* checks to see if the target already exists */ 520*11963SAfshin.Ardakani@Sun.COM ntargets = info.i_ntargets; 521*11963SAfshin.Ardakani@Sun.COM if (dfs_target_find(info.i_targets, ntargets, server, share) != -1) { 522*11963SAfshin.Ardakani@Sun.COM dfs_info_free(&info); 523*11963SAfshin.Ardakani@Sun.COM return (ERROR_FILE_EXISTS); 524*11963SAfshin.Ardakani@Sun.COM } 525*11963SAfshin.Ardakani@Sun.COM 526*11963SAfshin.Ardakani@Sun.COM /* add the new target */ 527*11963SAfshin.Ardakani@Sun.COM t = realloc(info.i_targets, (ntargets + 1) * sizeof (dfs_target_t)); 528*11963SAfshin.Ardakani@Sun.COM if (t == NULL) { 529*11963SAfshin.Ardakani@Sun.COM dfs_info_free(&info); 530*11963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY); 531*11963SAfshin.Ardakani@Sun.COM } 532*11963SAfshin.Ardakani@Sun.COM 533*11963SAfshin.Ardakani@Sun.COM info.i_targets = t; 534*11963SAfshin.Ardakani@Sun.COM dfs_target_init(&info.i_targets[ntargets], server, share, 535*11963SAfshin.Ardakani@Sun.COM DFS_STORAGE_STATE_ONLINE); 536*11963SAfshin.Ardakani@Sun.COM info.i_ntargets++; 537*11963SAfshin.Ardakani@Sun.COM 538*11963SAfshin.Ardakani@Sun.COM status = dfs_link_commit(path, &info); 539*11963SAfshin.Ardakani@Sun.COM 540*11963SAfshin.Ardakani@Sun.COM dfs_info_free(&info); 541*11963SAfshin.Ardakani@Sun.COM return (status); 542*11963SAfshin.Ardakani@Sun.COM } 543*11963SAfshin.Ardakani@Sun.COM 544*11963SAfshin.Ardakani@Sun.COM /* 545*11963SAfshin.Ardakani@Sun.COM * Removes a link or a link target from a DFS namespace. A link can be 546*11963SAfshin.Ardakani@Sun.COM * removed regardless of the number of targets associated with it. 547*11963SAfshin.Ardakani@Sun.COM * 548*11963SAfshin.Ardakani@Sun.COM * 'server' and 'share' parameters specify a target, so if they are NULL 549*11963SAfshin.Ardakani@Sun.COM * it means the link should be removed, otherwise the specified target 550*11963SAfshin.Ardakani@Sun.COM * is removed if found. 551*11963SAfshin.Ardakani@Sun.COM */ 552*11963SAfshin.Ardakani@Sun.COM uint32_t 553*11963SAfshin.Ardakani@Sun.COM dfs_link_remove(const char *path, const char *server, const char *share) 554*11963SAfshin.Ardakani@Sun.COM { 555*11963SAfshin.Ardakani@Sun.COM dfs_info_t info; 556*11963SAfshin.Ardakani@Sun.COM uint32_t status, stat; 557*11963SAfshin.Ardakani@Sun.COM int rc, idx; 558*11963SAfshin.Ardakani@Sun.COM 559*11963SAfshin.Ardakani@Sun.COM if ((status = dfs_link_stat(path, &stat)) != ERROR_SUCCESS) 560*11963SAfshin.Ardakani@Sun.COM return (status); 561*11963SAfshin.Ardakani@Sun.COM 562*11963SAfshin.Ardakani@Sun.COM if (stat != DFS_STAT_ISDFS) 563*11963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND); 564*11963SAfshin.Ardakani@Sun.COM 565*11963SAfshin.Ardakani@Sun.COM if (server == NULL && share == NULL) { 566*11963SAfshin.Ardakani@Sun.COM /* remove the link */ 567*11963SAfshin.Ardakani@Sun.COM if (smb_reparse_svcdel(path, DFS_REPARSE_SVCTYPE) != 0) 568*11963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 569*11963SAfshin.Ardakani@Sun.COM 570*11963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 571*11963SAfshin.Ardakani@Sun.COM } 572*11963SAfshin.Ardakani@Sun.COM 573*11963SAfshin.Ardakani@Sun.COM /* remove the specified target in the link */ 574*11963SAfshin.Ardakani@Sun.COM 575*11963SAfshin.Ardakani@Sun.COM status = dfs_link_getinfo(path, &info, DFS_INFO_ALL); 576*11963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) 577*11963SAfshin.Ardakani@Sun.COM return (status); 578*11963SAfshin.Ardakani@Sun.COM 579*11963SAfshin.Ardakani@Sun.COM /* checks to see if the target exists */ 580*11963SAfshin.Ardakani@Sun.COM idx = dfs_target_find(info.i_targets, info.i_ntargets, server, share); 581*11963SAfshin.Ardakani@Sun.COM if (idx != -1) { 582*11963SAfshin.Ardakani@Sun.COM bcopy(&info.i_targets[idx + 1], &info.i_targets[idx], 583*11963SAfshin.Ardakani@Sun.COM (info.i_ntargets - idx - 1) * sizeof (dfs_target_t)); 584*11963SAfshin.Ardakani@Sun.COM info.i_ntargets--; 585*11963SAfshin.Ardakani@Sun.COM } else { 586*11963SAfshin.Ardakani@Sun.COM dfs_info_free(&info); 587*11963SAfshin.Ardakani@Sun.COM return (ERROR_FILE_NOT_FOUND); 588*11963SAfshin.Ardakani@Sun.COM } 589*11963SAfshin.Ardakani@Sun.COM 590*11963SAfshin.Ardakani@Sun.COM if (info.i_ntargets == 0) { 591*11963SAfshin.Ardakani@Sun.COM /* if last target, then remove the link */ 592*11963SAfshin.Ardakani@Sun.COM rc = smb_reparse_svcdel(path, DFS_REPARSE_SVCTYPE); 593*11963SAfshin.Ardakani@Sun.COM status = (rc == 0) ? ERROR_SUCCESS : ERROR_INTERNAL_ERROR; 594*11963SAfshin.Ardakani@Sun.COM } else { 595*11963SAfshin.Ardakani@Sun.COM status = dfs_link_commit(path, &info); 596*11963SAfshin.Ardakani@Sun.COM } 597*11963SAfshin.Ardakani@Sun.COM 598*11963SAfshin.Ardakani@Sun.COM dfs_info_free(&info); 599*11963SAfshin.Ardakani@Sun.COM return (status); 600*11963SAfshin.Ardakani@Sun.COM } 601*11963SAfshin.Ardakani@Sun.COM 602*11963SAfshin.Ardakani@Sun.COM /* 603*11963SAfshin.Ardakani@Sun.COM * Sets the provided information for the specified link or link target. 604*11963SAfshin.Ardakani@Sun.COM * Link is specified by 'path' and the target is specified by 605*11963SAfshin.Ardakani@Sun.COM * (t_server, t_share) pair. Only information items needed for given 606*11963SAfshin.Ardakani@Sun.COM * information level (infolvl) is valid in the passed DFS info structure 607*11963SAfshin.Ardakani@Sun.COM * 'info'. 608*11963SAfshin.Ardakani@Sun.COM */ 609*11963SAfshin.Ardakani@Sun.COM uint32_t 610*11963SAfshin.Ardakani@Sun.COM dfs_link_setinfo(const char *path, dfs_info_t *info, uint32_t infolvl) 611*11963SAfshin.Ardakani@Sun.COM { 612*11963SAfshin.Ardakani@Sun.COM dfs_info_t curinfo; 613*11963SAfshin.Ardakani@Sun.COM uint32_t status; 614*11963SAfshin.Ardakani@Sun.COM 615*11963SAfshin.Ardakani@Sun.COM status = dfs_link_getinfo(path, &curinfo, DFS_INFO_ALL); 616*11963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) 617*11963SAfshin.Ardakani@Sun.COM return (status); 618*11963SAfshin.Ardakani@Sun.COM 619*11963SAfshin.Ardakani@Sun.COM status = dfs_modinfo(DFS_OBJECT_LINK, &curinfo, info, infolvl); 620*11963SAfshin.Ardakani@Sun.COM if (status == ERROR_SUCCESS) 621*11963SAfshin.Ardakani@Sun.COM status = dfs_link_commit(path, &curinfo); 622*11963SAfshin.Ardakani@Sun.COM 623*11963SAfshin.Ardakani@Sun.COM dfs_info_free(&curinfo); 624*11963SAfshin.Ardakani@Sun.COM return (status); 625*11963SAfshin.Ardakani@Sun.COM } 626*11963SAfshin.Ardakani@Sun.COM 627*11963SAfshin.Ardakani@Sun.COM /* 628*11963SAfshin.Ardakani@Sun.COM * Gets the DFS link info. 629*11963SAfshin.Ardakani@Sun.COM * 630*11963SAfshin.Ardakani@Sun.COM * If path is NULL, it just does some initialization. 631*11963SAfshin.Ardakani@Sun.COM * 632*11963SAfshin.Ardakani@Sun.COM * Info level (1) only needs the UNC path which is not 633*11963SAfshin.Ardakani@Sun.COM * stored, it is constructed so the function will return 634*11963SAfshin.Ardakani@Sun.COM * without accessing the backend storage. 635*11963SAfshin.Ardakani@Sun.COM */ 636*11963SAfshin.Ardakani@Sun.COM uint32_t 637*11963SAfshin.Ardakani@Sun.COM dfs_link_getinfo(const char *path, dfs_info_t *info, uint32_t infolvl) 638*11963SAfshin.Ardakani@Sun.COM { 639*11963SAfshin.Ardakani@Sun.COM char *link_data; 640*11963SAfshin.Ardakani@Sun.COM uint32_t status; 641*11963SAfshin.Ardakani@Sun.COM uuid_t uuid; 642*11963SAfshin.Ardakani@Sun.COM int rc; 643*11963SAfshin.Ardakani@Sun.COM 644*11963SAfshin.Ardakani@Sun.COM bzero(info, sizeof (dfs_info_t)); 645*11963SAfshin.Ardakani@Sun.COM info->i_type = DFS_OBJECT_LINK; 646*11963SAfshin.Ardakani@Sun.COM 647*11963SAfshin.Ardakani@Sun.COM if (path == NULL) { 648*11963SAfshin.Ardakani@Sun.COM info->i_state = DFS_VOLUME_STATE_OK; 649*11963SAfshin.Ardakani@Sun.COM info->i_timeout = DFS_LINK_TIMEOUT; 650*11963SAfshin.Ardakani@Sun.COM info->i_propflags = 0; 651*11963SAfshin.Ardakani@Sun.COM uuid_generate_random(uuid); 652*11963SAfshin.Ardakani@Sun.COM uuid_unparse(uuid, info->i_guid); 653*11963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 654*11963SAfshin.Ardakani@Sun.COM } 655*11963SAfshin.Ardakani@Sun.COM 656*11963SAfshin.Ardakani@Sun.COM if (infolvl == 1) 657*11963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 658*11963SAfshin.Ardakani@Sun.COM 659*11963SAfshin.Ardakani@Sun.COM rc = smb_reparse_svcget(path, DFS_REPARSE_SVCTYPE, &link_data); 660*11963SAfshin.Ardakani@Sun.COM if (rc != 0) 661*11963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 662*11963SAfshin.Ardakani@Sun.COM 663*11963SAfshin.Ardakani@Sun.COM status = dfs_link_decode(info, link_data, infolvl); 664*11963SAfshin.Ardakani@Sun.COM free(link_data); 665*11963SAfshin.Ardakani@Sun.COM 666*11963SAfshin.Ardakani@Sun.COM return (status); 667*11963SAfshin.Ardakani@Sun.COM } 668*11963SAfshin.Ardakani@Sun.COM 669*11963SAfshin.Ardakani@Sun.COM /* 670*11963SAfshin.Ardakani@Sun.COM * =================== 671*11963SAfshin.Ardakani@Sun.COM * Cache API (public) 672*11963SAfshin.Ardakani@Sun.COM * =================== 673*11963SAfshin.Ardakani@Sun.COM */ 674*11963SAfshin.Ardakani@Sun.COM 675*11963SAfshin.Ardakani@Sun.COM /* 676*11963SAfshin.Ardakani@Sun.COM * Adds an entry with given DFS name (root sharename) and relative path 677*11963SAfshin.Ardakani@Sun.COM * to the share (relpath) and the specified entry type (i.e. root/link) 678*11963SAfshin.Ardakani@Sun.COM * to the namespace cache. 679*11963SAfshin.Ardakani@Sun.COM */ 680*11963SAfshin.Ardakani@Sun.COM uint32_t 681*11963SAfshin.Ardakani@Sun.COM dfs_cache_add_byname(const char *name, const char *relpath, uint32_t type) 682*11963SAfshin.Ardakani@Sun.COM { 683*11963SAfshin.Ardakani@Sun.COM char uncpath[DFS_PATH_MAX]; 684*11963SAfshin.Ardakani@Sun.COM char fspath[DFS_PATH_MAX]; 685*11963SAfshin.Ardakani@Sun.COM smb_share_t si; 686*11963SAfshin.Ardakani@Sun.COM 687*11963SAfshin.Ardakani@Sun.COM if (smb_shr_get((char *)name, &si) != NERR_Success) 688*11963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND); 689*11963SAfshin.Ardakani@Sun.COM 690*11963SAfshin.Ardakani@Sun.COM if (type == DFS_OBJECT_ROOT) { 691*11963SAfshin.Ardakani@Sun.COM (void) snprintf(uncpath, DFS_PATH_MAX, "\\\\%s\\%s", 692*11963SAfshin.Ardakani@Sun.COM dfs_nbname, name); 693*11963SAfshin.Ardakani@Sun.COM return (dfs_cache_add_byunc(uncpath, si.shr_path, type)); 694*11963SAfshin.Ardakani@Sun.COM } 695*11963SAfshin.Ardakani@Sun.COM 696*11963SAfshin.Ardakani@Sun.COM /* add link entry */ 697*11963SAfshin.Ardakani@Sun.COM (void) snprintf(fspath, DFS_PATH_MAX, "%s/%s", si.shr_path, relpath); 698*11963SAfshin.Ardakani@Sun.COM (void) snprintf(uncpath, DFS_PATH_MAX, "\\\\%s\\%s\\%s", dfs_nbname, 699*11963SAfshin.Ardakani@Sun.COM name, relpath); 700*11963SAfshin.Ardakani@Sun.COM 701*11963SAfshin.Ardakani@Sun.COM /* relpath may contain '/' */ 702*11963SAfshin.Ardakani@Sun.COM (void) strsubst(uncpath, '/', '\\'); 703*11963SAfshin.Ardakani@Sun.COM 704*11963SAfshin.Ardakani@Sun.COM return (dfs_cache_add_byunc(uncpath, fspath, type)); 705*11963SAfshin.Ardakani@Sun.COM } 706*11963SAfshin.Ardakani@Sun.COM 707*11963SAfshin.Ardakani@Sun.COM /* 708*11963SAfshin.Ardakani@Sun.COM * Removes the namespace cache entry for the given link 709*11963SAfshin.Ardakani@Sun.COM * in the namespace ('name') with 'relpath' 710*11963SAfshin.Ardakani@Sun.COM */ 711*11963SAfshin.Ardakani@Sun.COM void 712*11963SAfshin.Ardakani@Sun.COM dfs_cache_remove(const char *name, const char *relpath) 713*11963SAfshin.Ardakani@Sun.COM { 714*11963SAfshin.Ardakani@Sun.COM dfs_nscnode_t dn; 715*11963SAfshin.Ardakani@Sun.COM 716*11963SAfshin.Ardakani@Sun.COM (void) snprintf(dn.nsc_uncpath, sizeof (dn.nsc_uncpath), 717*11963SAfshin.Ardakani@Sun.COM "\\\\%s\\%s\\%s", dfs_nbname, name, relpath); 718*11963SAfshin.Ardakani@Sun.COM 719*11963SAfshin.Ardakani@Sun.COM /* relpath may contain '/' */ 720*11963SAfshin.Ardakani@Sun.COM (void) strsubst(dn.nsc_uncpath, '/', '\\'); 721*11963SAfshin.Ardakani@Sun.COM 722*11963SAfshin.Ardakani@Sun.COM smb_cache_remove(&dfs_nscache, &dn); 723*11963SAfshin.Ardakani@Sun.COM } 724*11963SAfshin.Ardakani@Sun.COM 725*11963SAfshin.Ardakani@Sun.COM /* 726*11963SAfshin.Ardakani@Sun.COM * Get the DFS data for the specified cache entry 727*11963SAfshin.Ardakani@Sun.COM */ 728*11963SAfshin.Ardakani@Sun.COM uint32_t 729*11963SAfshin.Ardakani@Sun.COM dfs_cache_getinfo(dfs_nscnode_t *dn, dfs_info_t *info, uint32_t infolvl) 730*11963SAfshin.Ardakani@Sun.COM { 731*11963SAfshin.Ardakani@Sun.COM uint32_t status; 732*11963SAfshin.Ardakani@Sun.COM 733*11963SAfshin.Ardakani@Sun.COM if (dn->nsc_type == DFS_OBJECT_LINK) 734*11963SAfshin.Ardakani@Sun.COM status = dfs_link_getinfo(dn->nsc_fspath, info, infolvl); 735*11963SAfshin.Ardakani@Sun.COM else 736*11963SAfshin.Ardakani@Sun.COM status = dfs_root_getinfo(dn->nsc_fspath, info, infolvl); 737*11963SAfshin.Ardakani@Sun.COM 738*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_uncpath, dn->nsc_uncpath, 739*11963SAfshin.Ardakani@Sun.COM sizeof (info->i_uncpath)); 740*11963SAfshin.Ardakani@Sun.COM 741*11963SAfshin.Ardakani@Sun.COM if (status == ERROR_SUCCESS) 742*11963SAfshin.Ardakani@Sun.COM dfs_info_trace("dfs_cache_getinfo", info); 743*11963SAfshin.Ardakani@Sun.COM 744*11963SAfshin.Ardakani@Sun.COM return (status); 745*11963SAfshin.Ardakani@Sun.COM } 746*11963SAfshin.Ardakani@Sun.COM 747*11963SAfshin.Ardakani@Sun.COM /* 748*11963SAfshin.Ardakani@Sun.COM * Returns the number of cache entries i.e. the number of 749*11963SAfshin.Ardakani@Sun.COM * root(s) and link(s) 750*11963SAfshin.Ardakani@Sun.COM */ 751*11963SAfshin.Ardakani@Sun.COM uint32_t 752*11963SAfshin.Ardakani@Sun.COM dfs_cache_num(void) 753*11963SAfshin.Ardakani@Sun.COM { 754*11963SAfshin.Ardakani@Sun.COM return (smb_cache_num(&dfs_nscache)); 755*11963SAfshin.Ardakani@Sun.COM } 756*11963SAfshin.Ardakani@Sun.COM 757*11963SAfshin.Ardakani@Sun.COM void 758*11963SAfshin.Ardakani@Sun.COM dfs_cache_iterinit(smb_cache_cursor_t *cursor) 759*11963SAfshin.Ardakani@Sun.COM { 760*11963SAfshin.Ardakani@Sun.COM smb_cache_iterinit(&dfs_nscache, cursor); 761*11963SAfshin.Ardakani@Sun.COM } 762*11963SAfshin.Ardakani@Sun.COM 763*11963SAfshin.Ardakani@Sun.COM boolean_t 764*11963SAfshin.Ardakani@Sun.COM dfs_cache_iterate(smb_cache_cursor_t *cursor, dfs_nscnode_t *dn) 765*11963SAfshin.Ardakani@Sun.COM { 766*11963SAfshin.Ardakani@Sun.COM return (smb_cache_iterate(&dfs_nscache, cursor, dn)); 767*11963SAfshin.Ardakani@Sun.COM } 768*11963SAfshin.Ardakani@Sun.COM 769*11963SAfshin.Ardakani@Sun.COM /* 770*11963SAfshin.Ardakani@Sun.COM * ================== 771*11963SAfshin.Ardakani@Sun.COM * Misc API (public) 772*11963SAfshin.Ardakani@Sun.COM * ================== 773*11963SAfshin.Ardakani@Sun.COM */ 774*11963SAfshin.Ardakani@Sun.COM 775*11963SAfshin.Ardakani@Sun.COM /* 776*11963SAfshin.Ardakani@Sun.COM * This is the function that is called by smbd door server to 777*11963SAfshin.Ardakani@Sun.COM * fullfil a GetReferrals request from smbsrv kernel module 778*11963SAfshin.Ardakani@Sun.COM * 779*11963SAfshin.Ardakani@Sun.COM * 'reftype' specifies the requested referral type. If it is 780*11963SAfshin.Ardakani@Sun.COM * DFS_REFERRAL_ROOT then dfs_path should point to a namespace 781*11963SAfshin.Ardakani@Sun.COM * root. If it is DFS_REFERRAL_LINK then dfs_path should CONTAIN 782*11963SAfshin.Ardakani@Sun.COM * a link, in which case this function will find the link and 783*11963SAfshin.Ardakani@Sun.COM * returns its target information. 784*11963SAfshin.Ardakani@Sun.COM */ 785*11963SAfshin.Ardakani@Sun.COM uint32_t 786*11963SAfshin.Ardakani@Sun.COM dfs_get_referrals(const char *dfs_path, dfs_reftype_t reftype, 787*11963SAfshin.Ardakani@Sun.COM dfs_info_t *referrals) 788*11963SAfshin.Ardakani@Sun.COM { 789*11963SAfshin.Ardakani@Sun.COM dfs_path_t path; 790*11963SAfshin.Ardakani@Sun.COM smb_unc_t *unc; 791*11963SAfshin.Ardakani@Sun.COM char linkpath[DFS_PATH_MAX]; 792*11963SAfshin.Ardakani@Sun.COM uint32_t status; 793*11963SAfshin.Ardakani@Sun.COM 794*11963SAfshin.Ardakani@Sun.COM status = dfs_path_parse(&path, dfs_path, DFS_OBJECT_ANY); 795*11963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) 796*11963SAfshin.Ardakani@Sun.COM return (status); 797*11963SAfshin.Ardakani@Sun.COM 798*11963SAfshin.Ardakani@Sun.COM dfs_setpriv(PRIV_ON); 799*11963SAfshin.Ardakani@Sun.COM 800*11963SAfshin.Ardakani@Sun.COM referrals->i_type = path.p_type; 801*11963SAfshin.Ardakani@Sun.COM 802*11963SAfshin.Ardakani@Sun.COM switch (reftype) { 803*11963SAfshin.Ardakani@Sun.COM case DFS_REFERRAL_ROOT: 804*11963SAfshin.Ardakani@Sun.COM if (path.p_type != DFS_OBJECT_ROOT) { 805*11963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER; 806*11963SAfshin.Ardakani@Sun.COM break; 807*11963SAfshin.Ardakani@Sun.COM } 808*11963SAfshin.Ardakani@Sun.COM 809*11963SAfshin.Ardakani@Sun.COM status = dfs_root_getinfo((const char *)path.p_fspath, 810*11963SAfshin.Ardakani@Sun.COM referrals, DFS_INFO_ALL); 811*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(referrals->i_uncpath, dfs_path, DFS_PATH_MAX); 812*11963SAfshin.Ardakani@Sun.COM break; 813*11963SAfshin.Ardakani@Sun.COM 814*11963SAfshin.Ardakani@Sun.COM case DFS_REFERRAL_LINK: 815*11963SAfshin.Ardakani@Sun.COM if (path.p_type != DFS_OBJECT_LINK) { 816*11963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER; 817*11963SAfshin.Ardakani@Sun.COM break; 818*11963SAfshin.Ardakani@Sun.COM } 819*11963SAfshin.Ardakani@Sun.COM 820*11963SAfshin.Ardakani@Sun.COM unc = &path.p_unc; 821*11963SAfshin.Ardakani@Sun.COM if (!dfs_namespace_findlink(unc->unc_share, unc->unc_path, 822*11963SAfshin.Ardakani@Sun.COM linkpath, DFS_PATH_MAX)) { 823*11963SAfshin.Ardakani@Sun.COM status = ERROR_NOT_FOUND; 824*11963SAfshin.Ardakani@Sun.COM break; 825*11963SAfshin.Ardakani@Sun.COM } 826*11963SAfshin.Ardakani@Sun.COM 827*11963SAfshin.Ardakani@Sun.COM status = dfs_link_getinfo(linkpath, referrals, DFS_INFO_ALL); 828*11963SAfshin.Ardakani@Sun.COM (void) snprintf(referrals->i_uncpath, DFS_PATH_MAX, "/%s/%s/%s", 829*11963SAfshin.Ardakani@Sun.COM unc->unc_server, unc->unc_share, unc->unc_path); 830*11963SAfshin.Ardakani@Sun.COM break; 831*11963SAfshin.Ardakani@Sun.COM 832*11963SAfshin.Ardakani@Sun.COM default: 833*11963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER; 834*11963SAfshin.Ardakani@Sun.COM break; 835*11963SAfshin.Ardakani@Sun.COM } 836*11963SAfshin.Ardakani@Sun.COM 837*11963SAfshin.Ardakani@Sun.COM dfs_setpriv(PRIV_OFF); 838*11963SAfshin.Ardakani@Sun.COM dfs_path_free(&path); 839*11963SAfshin.Ardakani@Sun.COM return (status); 840*11963SAfshin.Ardakani@Sun.COM } 841*11963SAfshin.Ardakani@Sun.COM 842*11963SAfshin.Ardakani@Sun.COM /* 843*11963SAfshin.Ardakani@Sun.COM * Takes a DFS path in UNC format (dfs_path) and parse it into a dfs_path_t 844*11963SAfshin.Ardakani@Sun.COM * structure. 845*11963SAfshin.Ardakani@Sun.COM * 846*11963SAfshin.Ardakani@Sun.COM * dfs_path_free() MUST be called to free the allocated memory in this 847*11963SAfshin.Ardakani@Sun.COM * function. 848*11963SAfshin.Ardakani@Sun.COM * 849*11963SAfshin.Ardakani@Sun.COM * Returns: 850*11963SAfshin.Ardakani@Sun.COM * 851*11963SAfshin.Ardakani@Sun.COM * ERROR_INVALID_PARAMETER path is not a valid UNC or not valid for the 852*11963SAfshin.Ardakani@Sun.COM * specified object type 853*11963SAfshin.Ardakani@Sun.COM * ERROR_NOT_ENOUGH_MEMORY not enough memory to peform the parse 854*11963SAfshin.Ardakani@Sun.COM * ERROR_NOT_FOUND namespace specified does not exist 855*11963SAfshin.Ardakani@Sun.COM */ 856*11963SAfshin.Ardakani@Sun.COM uint32_t 857*11963SAfshin.Ardakani@Sun.COM dfs_path_parse(dfs_path_t *path, const char *dfs_path, uint32_t path_type) 858*11963SAfshin.Ardakani@Sun.COM { 859*11963SAfshin.Ardakani@Sun.COM char rootdir[DFS_PATH_MAX]; 860*11963SAfshin.Ardakani@Sun.COM smb_unc_t *unc; 861*11963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_SUCCESS; 862*11963SAfshin.Ardakani@Sun.COM int rc; 863*11963SAfshin.Ardakani@Sun.COM 864*11963SAfshin.Ardakani@Sun.COM bzero(path, sizeof (dfs_path_t)); 865*11963SAfshin.Ardakani@Sun.COM unc = &path->p_unc; 866*11963SAfshin.Ardakani@Sun.COM 867*11963SAfshin.Ardakani@Sun.COM rc = smb_unc_init(dfs_path, unc); 868*11963SAfshin.Ardakani@Sun.COM switch (rc) { 869*11963SAfshin.Ardakani@Sun.COM case EINVAL: 870*11963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_PARAMETER); 871*11963SAfshin.Ardakani@Sun.COM case ENOMEM: 872*11963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY); 873*11963SAfshin.Ardakani@Sun.COM default: 874*11963SAfshin.Ardakani@Sun.COM break; 875*11963SAfshin.Ardakani@Sun.COM } 876*11963SAfshin.Ardakani@Sun.COM 877*11963SAfshin.Ardakani@Sun.COM if (dfs_namespace_path(unc->unc_share, rootdir, DFS_PATH_MAX) 878*11963SAfshin.Ardakani@Sun.COM != ERROR_SUCCESS) { 879*11963SAfshin.Ardakani@Sun.COM smb_unc_free(unc); 880*11963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_FOUND); 881*11963SAfshin.Ardakani@Sun.COM } 882*11963SAfshin.Ardakani@Sun.COM 883*11963SAfshin.Ardakani@Sun.COM if (path_type == DFS_OBJECT_ANY) 884*11963SAfshin.Ardakani@Sun.COM path->p_type = (unc->unc_path != NULL) 885*11963SAfshin.Ardakani@Sun.COM ? DFS_OBJECT_LINK : DFS_OBJECT_ROOT; 886*11963SAfshin.Ardakani@Sun.COM else 887*11963SAfshin.Ardakani@Sun.COM path->p_type = path_type; 888*11963SAfshin.Ardakani@Sun.COM 889*11963SAfshin.Ardakani@Sun.COM switch (path->p_type) { 890*11963SAfshin.Ardakani@Sun.COM case DFS_OBJECT_LINK: 891*11963SAfshin.Ardakani@Sun.COM if ((unc->unc_path == NULL) || (*unc->unc_path == '\0')) 892*11963SAfshin.Ardakani@Sun.COM status = ERROR_NOT_FOUND; 893*11963SAfshin.Ardakani@Sun.COM else 894*11963SAfshin.Ardakani@Sun.COM (void) snprintf(path->p_fspath, sizeof (path->p_fspath), 895*11963SAfshin.Ardakani@Sun.COM "%s/%s", rootdir, unc->unc_path); 896*11963SAfshin.Ardakani@Sun.COM break; 897*11963SAfshin.Ardakani@Sun.COM 898*11963SAfshin.Ardakani@Sun.COM case DFS_OBJECT_ROOT: 899*11963SAfshin.Ardakani@Sun.COM if (unc->unc_path == NULL) 900*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(path->p_fspath, rootdir, 901*11963SAfshin.Ardakani@Sun.COM sizeof (path->p_fspath)); 902*11963SAfshin.Ardakani@Sun.COM else 903*11963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER; 904*11963SAfshin.Ardakani@Sun.COM break; 905*11963SAfshin.Ardakani@Sun.COM 906*11963SAfshin.Ardakani@Sun.COM default: 907*11963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER; 908*11963SAfshin.Ardakani@Sun.COM } 909*11963SAfshin.Ardakani@Sun.COM 910*11963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) 911*11963SAfshin.Ardakani@Sun.COM smb_unc_free(unc); 912*11963SAfshin.Ardakani@Sun.COM 913*11963SAfshin.Ardakani@Sun.COM return (status); 914*11963SAfshin.Ardakani@Sun.COM } 915*11963SAfshin.Ardakani@Sun.COM 916*11963SAfshin.Ardakani@Sun.COM /* 917*11963SAfshin.Ardakani@Sun.COM * Frees the allocated memory for p_unc field of the passed path 918*11963SAfshin.Ardakani@Sun.COM */ 919*11963SAfshin.Ardakani@Sun.COM void 920*11963SAfshin.Ardakani@Sun.COM dfs_path_free(dfs_path_t *path) 921*11963SAfshin.Ardakani@Sun.COM { 922*11963SAfshin.Ardakani@Sun.COM if (path != NULL) 923*11963SAfshin.Ardakani@Sun.COM smb_unc_free(&path->p_unc); 924*11963SAfshin.Ardakani@Sun.COM } 925*11963SAfshin.Ardakani@Sun.COM 926*11963SAfshin.Ardakani@Sun.COM /* 927*11963SAfshin.Ardakani@Sun.COM * Free the allocated memory for targets in the given info 928*11963SAfshin.Ardakani@Sun.COM * structure 929*11963SAfshin.Ardakani@Sun.COM */ 930*11963SAfshin.Ardakani@Sun.COM void 931*11963SAfshin.Ardakani@Sun.COM dfs_info_free(dfs_info_t *info) 932*11963SAfshin.Ardakani@Sun.COM { 933*11963SAfshin.Ardakani@Sun.COM if (info) 934*11963SAfshin.Ardakani@Sun.COM free(info->i_targets); 935*11963SAfshin.Ardakani@Sun.COM } 936*11963SAfshin.Ardakani@Sun.COM 937*11963SAfshin.Ardakani@Sun.COM /* 938*11963SAfshin.Ardakani@Sun.COM * Trace the given DFS info structure 939*11963SAfshin.Ardakani@Sun.COM */ 940*11963SAfshin.Ardakani@Sun.COM void 941*11963SAfshin.Ardakani@Sun.COM dfs_info_trace(const char *msg, dfs_info_t *info) 942*11963SAfshin.Ardakani@Sun.COM { 943*11963SAfshin.Ardakani@Sun.COM dfs_target_t *t; 944*11963SAfshin.Ardakani@Sun.COM int i; 945*11963SAfshin.Ardakani@Sun.COM 946*11963SAfshin.Ardakani@Sun.COM smb_tracef("%s", msg); 947*11963SAfshin.Ardakani@Sun.COM if (info == NULL) 948*11963SAfshin.Ardakani@Sun.COM return; 949*11963SAfshin.Ardakani@Sun.COM 950*11963SAfshin.Ardakani@Sun.COM smb_tracef("UNC\t%s", info->i_uncpath); 951*11963SAfshin.Ardakani@Sun.COM smb_tracef("comment\t%s", info->i_comment); 952*11963SAfshin.Ardakani@Sun.COM smb_tracef("GUID\t%s", info->i_guid); 953*11963SAfshin.Ardakani@Sun.COM smb_tracef("state\t%X", info->i_state); 954*11963SAfshin.Ardakani@Sun.COM smb_tracef("timeout\t%d", info->i_timeout); 955*11963SAfshin.Ardakani@Sun.COM smb_tracef("props\t%X", info->i_propflags); 956*11963SAfshin.Ardakani@Sun.COM smb_tracef("# targets\t%X", info->i_ntargets); 957*11963SAfshin.Ardakani@Sun.COM 958*11963SAfshin.Ardakani@Sun.COM if (info->i_targets == NULL) 959*11963SAfshin.Ardakani@Sun.COM return; 960*11963SAfshin.Ardakani@Sun.COM 961*11963SAfshin.Ardakani@Sun.COM for (i = 0, t = info->i_targets; i < info->i_ntargets; i++, t++) { 962*11963SAfshin.Ardakani@Sun.COM smb_tracef("[%d] \\\\%s\\%s", i, t->t_server, t->t_share); 963*11963SAfshin.Ardakani@Sun.COM smb_tracef("[%d] state\t%X", i, t->t_state); 964*11963SAfshin.Ardakani@Sun.COM smb_tracef("[%d] priority\t%d:%d", i, t->t_priority.p_class, 965*11963SAfshin.Ardakani@Sun.COM t->t_priority.p_rank); 966*11963SAfshin.Ardakani@Sun.COM } 967*11963SAfshin.Ardakani@Sun.COM } 968*11963SAfshin.Ardakani@Sun.COM 969*11963SAfshin.Ardakani@Sun.COM /* 970*11963SAfshin.Ardakani@Sun.COM * Search the path specified by 'relpath' to see if it contains 971*11963SAfshin.Ardakani@Sun.COM * a DFS link starting from the last component. If a link is found 972*11963SAfshin.Ardakani@Sun.COM * the full path is returned in 'linkpath' 973*11963SAfshin.Ardakani@Sun.COM */ 974*11963SAfshin.Ardakani@Sun.COM static boolean_t 975*11963SAfshin.Ardakani@Sun.COM dfs_namespace_findlink(const char *name, char *relpath, 976*11963SAfshin.Ardakani@Sun.COM char *linkpath, size_t bufsz) 977*11963SAfshin.Ardakani@Sun.COM { 978*11963SAfshin.Ardakani@Sun.COM char rootdir[DFS_PATH_MAX]; 979*11963SAfshin.Ardakani@Sun.COM uint32_t stat; 980*11963SAfshin.Ardakani@Sun.COM char *p; 981*11963SAfshin.Ardakani@Sun.COM 982*11963SAfshin.Ardakani@Sun.COM if (dfs_namespace_path(name, rootdir, DFS_PATH_MAX) != ERROR_SUCCESS) 983*11963SAfshin.Ardakani@Sun.COM return (B_FALSE); 984*11963SAfshin.Ardakani@Sun.COM 985*11963SAfshin.Ardakani@Sun.COM (void) snprintf(linkpath, bufsz, "%s/%s", rootdir, relpath); 986*11963SAfshin.Ardakani@Sun.COM 987*11963SAfshin.Ardakani@Sun.COM for (;;) { 988*11963SAfshin.Ardakani@Sun.COM if (dfs_link_stat(linkpath, &stat) != ERROR_SUCCESS) 989*11963SAfshin.Ardakani@Sun.COM return (B_FALSE); 990*11963SAfshin.Ardakani@Sun.COM 991*11963SAfshin.Ardakani@Sun.COM if (stat == DFS_STAT_ISDFS) 992*11963SAfshin.Ardakani@Sun.COM return (B_TRUE); 993*11963SAfshin.Ardakani@Sun.COM 994*11963SAfshin.Ardakani@Sun.COM if ((p = strrchr(relpath, '/')) == NULL) 995*11963SAfshin.Ardakani@Sun.COM return (B_FALSE); 996*11963SAfshin.Ardakani@Sun.COM *p = '\0'; 997*11963SAfshin.Ardakani@Sun.COM 998*11963SAfshin.Ardakani@Sun.COM (void) snprintf(linkpath, bufsz, "%s/%s", rootdir, relpath); 999*11963SAfshin.Ardakani@Sun.COM } 1000*11963SAfshin.Ardakani@Sun.COM 1001*11963SAfshin.Ardakani@Sun.COM /*NOTREACHED*/ 1002*11963SAfshin.Ardakani@Sun.COM return (B_FALSE); 1003*11963SAfshin.Ardakani@Sun.COM } 1004*11963SAfshin.Ardakani@Sun.COM 1005*11963SAfshin.Ardakani@Sun.COM /* 1006*11963SAfshin.Ardakani@Sun.COM * Caches the specified namespace 1007*11963SAfshin.Ardakani@Sun.COM */ 1008*11963SAfshin.Ardakani@Sun.COM static void * 1009*11963SAfshin.Ardakani@Sun.COM dfs_namespace_cache(void *arg) 1010*11963SAfshin.Ardakani@Sun.COM { 1011*11963SAfshin.Ardakani@Sun.COM char *share = arg; 1012*11963SAfshin.Ardakani@Sun.COM char uncpath[DFS_PATH_MAX]; 1013*11963SAfshin.Ardakani@Sun.COM smb_share_t si; 1014*11963SAfshin.Ardakani@Sun.COM 1015*11963SAfshin.Ardakani@Sun.COM if (smb_shr_get(share, &si) != NERR_Success) { 1016*11963SAfshin.Ardakani@Sun.COM free(share); 1017*11963SAfshin.Ardakani@Sun.COM return (NULL); 1018*11963SAfshin.Ardakani@Sun.COM } 1019*11963SAfshin.Ardakani@Sun.COM 1020*11963SAfshin.Ardakani@Sun.COM (void) snprintf(uncpath, DFS_PATH_MAX, "\\\\%s\\%s", dfs_nbname, share); 1021*11963SAfshin.Ardakani@Sun.COM (void) dfs_cache_add_byunc(uncpath, si.shr_path, DFS_OBJECT_ROOT); 1022*11963SAfshin.Ardakani@Sun.COM 1023*11963SAfshin.Ardakani@Sun.COM dfs_cache_populate(uncpath, si.shr_path); 1024*11963SAfshin.Ardakani@Sun.COM 1025*11963SAfshin.Ardakani@Sun.COM free(share); 1026*11963SAfshin.Ardakani@Sun.COM return (NULL); 1027*11963SAfshin.Ardakani@Sun.COM } 1028*11963SAfshin.Ardakani@Sun.COM 1029*11963SAfshin.Ardakani@Sun.COM static int 1030*11963SAfshin.Ardakani@Sun.COM dfs_root_add(const char *rootdir, dfs_info_t *info) 1031*11963SAfshin.Ardakani@Sun.COM { 1032*11963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_INTERNAL_ERROR; 1033*11963SAfshin.Ardakani@Sun.COM int xfd; 1034*11963SAfshin.Ardakani@Sun.COM 1035*11963SAfshin.Ardakani@Sun.COM (void) rw_wrlock(&dfs_root_rwl); 1036*11963SAfshin.Ardakani@Sun.COM if ((xfd = dfs_root_xopen(rootdir, O_CREAT | O_TRUNC | O_RDWR)) > 0) { 1037*11963SAfshin.Ardakani@Sun.COM status = dfs_root_xwrite(xfd, info); 1038*11963SAfshin.Ardakani@Sun.COM dfs_root_xclose(xfd); 1039*11963SAfshin.Ardakani@Sun.COM } 1040*11963SAfshin.Ardakani@Sun.COM (void) rw_unlock(&dfs_root_rwl); 1041*11963SAfshin.Ardakani@Sun.COM 1042*11963SAfshin.Ardakani@Sun.COM return (status); 1043*11963SAfshin.Ardakani@Sun.COM } 1044*11963SAfshin.Ardakani@Sun.COM 1045*11963SAfshin.Ardakani@Sun.COM /* 1046*11963SAfshin.Ardakani@Sun.COM * Deletes the specified root information 1047*11963SAfshin.Ardakani@Sun.COM */ 1048*11963SAfshin.Ardakani@Sun.COM static uint32_t 1049*11963SAfshin.Ardakani@Sun.COM dfs_root_remove(const char *rootdir) 1050*11963SAfshin.Ardakani@Sun.COM { 1051*11963SAfshin.Ardakani@Sun.COM int attrdirfd; 1052*11963SAfshin.Ardakani@Sun.COM int err = 0; 1053*11963SAfshin.Ardakani@Sun.COM 1054*11963SAfshin.Ardakani@Sun.COM (void) rw_wrlock(&dfs_root_rwl); 1055*11963SAfshin.Ardakani@Sun.COM 1056*11963SAfshin.Ardakani@Sun.COM if ((attrdirfd = attropen(rootdir, ".", O_RDONLY)) > 0) { 1057*11963SAfshin.Ardakani@Sun.COM if (unlinkat(attrdirfd, DFS_ROOT_XATTR, 0) == -1) { 1058*11963SAfshin.Ardakani@Sun.COM if (errno != ENOENT) 1059*11963SAfshin.Ardakani@Sun.COM err = errno; 1060*11963SAfshin.Ardakani@Sun.COM } 1061*11963SAfshin.Ardakani@Sun.COM (void) close(attrdirfd); 1062*11963SAfshin.Ardakani@Sun.COM } else { 1063*11963SAfshin.Ardakani@Sun.COM err = errno; 1064*11963SAfshin.Ardakani@Sun.COM } 1065*11963SAfshin.Ardakani@Sun.COM 1066*11963SAfshin.Ardakani@Sun.COM (void) rw_unlock(&dfs_root_rwl); 1067*11963SAfshin.Ardakani@Sun.COM 1068*11963SAfshin.Ardakani@Sun.COM if (err != 0) { 1069*11963SAfshin.Ardakani@Sun.COM syslog(LOG_DEBUG, "dfs: failed to remove root info %s (%d)", 1070*11963SAfshin.Ardakani@Sun.COM rootdir, err); 1071*11963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 1072*11963SAfshin.Ardakani@Sun.COM } 1073*11963SAfshin.Ardakani@Sun.COM 1074*11963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 1075*11963SAfshin.Ardakani@Sun.COM } 1076*11963SAfshin.Ardakani@Sun.COM 1077*11963SAfshin.Ardakani@Sun.COM /* 1078*11963SAfshin.Ardakani@Sun.COM * Opens DFS root directory's extended attribute with the given mode. 1079*11963SAfshin.Ardakani@Sun.COM */ 1080*11963SAfshin.Ardakani@Sun.COM static int 1081*11963SAfshin.Ardakani@Sun.COM dfs_root_xopen(const char *rootdir, int oflag) 1082*11963SAfshin.Ardakani@Sun.COM { 1083*11963SAfshin.Ardakani@Sun.COM int dfd; 1084*11963SAfshin.Ardakani@Sun.COM int xfd = -1; 1085*11963SAfshin.Ardakani@Sun.COM int err = 0; 1086*11963SAfshin.Ardakani@Sun.COM 1087*11963SAfshin.Ardakani@Sun.COM if ((dfd = open(rootdir, O_RDONLY)) > 0) { 1088*11963SAfshin.Ardakani@Sun.COM xfd = openat(dfd, DFS_ROOT_XATTR, oflag | O_XATTR, 0600); 1089*11963SAfshin.Ardakani@Sun.COM if (xfd == -1) 1090*11963SAfshin.Ardakani@Sun.COM err = errno; 1091*11963SAfshin.Ardakani@Sun.COM (void) close(dfd); 1092*11963SAfshin.Ardakani@Sun.COM } else { 1093*11963SAfshin.Ardakani@Sun.COM err = errno; 1094*11963SAfshin.Ardakani@Sun.COM } 1095*11963SAfshin.Ardakani@Sun.COM 1096*11963SAfshin.Ardakani@Sun.COM if (err != 0) { 1097*11963SAfshin.Ardakani@Sun.COM syslog(LOG_DEBUG, "dfs: failed to open root directory %s (%d)", 1098*11963SAfshin.Ardakani@Sun.COM rootdir, err); 1099*11963SAfshin.Ardakani@Sun.COM } 1100*11963SAfshin.Ardakani@Sun.COM 1101*11963SAfshin.Ardakani@Sun.COM return (xfd); 1102*11963SAfshin.Ardakani@Sun.COM } 1103*11963SAfshin.Ardakani@Sun.COM 1104*11963SAfshin.Ardakani@Sun.COM /* 1105*11963SAfshin.Ardakani@Sun.COM * Closes given extended attribute file descriptor 1106*11963SAfshin.Ardakani@Sun.COM */ 1107*11963SAfshin.Ardakani@Sun.COM static void 1108*11963SAfshin.Ardakani@Sun.COM dfs_root_xclose(int xfd) 1109*11963SAfshin.Ardakani@Sun.COM { 1110*11963SAfshin.Ardakani@Sun.COM (void) close(xfd); 1111*11963SAfshin.Ardakani@Sun.COM } 1112*11963SAfshin.Ardakani@Sun.COM 1113*11963SAfshin.Ardakani@Sun.COM /* 1114*11963SAfshin.Ardakani@Sun.COM * Writes the given DFS data in the DFS root directory's 1115*11963SAfshin.Ardakani@Sun.COM * extended attribute specified with xfd file descriptor. 1116*11963SAfshin.Ardakani@Sun.COM */ 1117*11963SAfshin.Ardakani@Sun.COM static uint32_t 1118*11963SAfshin.Ardakani@Sun.COM dfs_root_xwrite(int xfd, dfs_info_t *info) 1119*11963SAfshin.Ardakani@Sun.COM { 1120*11963SAfshin.Ardakani@Sun.COM size_t nbytes; 1121*11963SAfshin.Ardakani@Sun.COM char *buf = NULL; 1122*11963SAfshin.Ardakani@Sun.COM size_t buflen; 1123*11963SAfshin.Ardakani@Sun.COM uint32_t status; 1124*11963SAfshin.Ardakani@Sun.COM 1125*11963SAfshin.Ardakani@Sun.COM if ((status = dfs_root_encode(info, &buf, &buflen)) != ERROR_SUCCESS) 1126*11963SAfshin.Ardakani@Sun.COM return (status); 1127*11963SAfshin.Ardakani@Sun.COM 1128*11963SAfshin.Ardakani@Sun.COM (void) lseek(xfd, 0, SEEK_SET); 1129*11963SAfshin.Ardakani@Sun.COM nbytes = write(xfd, buf, buflen); 1130*11963SAfshin.Ardakani@Sun.COM free(buf); 1131*11963SAfshin.Ardakani@Sun.COM 1132*11963SAfshin.Ardakani@Sun.COM return ((nbytes == buflen) ? ERROR_SUCCESS : ERROR_INTERNAL_ERROR); 1133*11963SAfshin.Ardakani@Sun.COM } 1134*11963SAfshin.Ardakani@Sun.COM 1135*11963SAfshin.Ardakani@Sun.COM /* 1136*11963SAfshin.Ardakani@Sun.COM * Reads DFS root information from its directory extended attribute 1137*11963SAfshin.Ardakani@Sun.COM * and parse it into given dfs_info_t structure 1138*11963SAfshin.Ardakani@Sun.COM */ 1139*11963SAfshin.Ardakani@Sun.COM static uint32_t 1140*11963SAfshin.Ardakani@Sun.COM dfs_root_xread(int xfd, dfs_info_t *info, uint32_t infolvl) 1141*11963SAfshin.Ardakani@Sun.COM { 1142*11963SAfshin.Ardakani@Sun.COM struct stat statbuf; 1143*11963SAfshin.Ardakani@Sun.COM uint32_t status; 1144*11963SAfshin.Ardakani@Sun.COM char *buf; 1145*11963SAfshin.Ardakani@Sun.COM 1146*11963SAfshin.Ardakani@Sun.COM if (fstat(xfd, &statbuf) != 0) 1147*11963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 1148*11963SAfshin.Ardakani@Sun.COM 1149*11963SAfshin.Ardakani@Sun.COM if ((buf = malloc(statbuf.st_size)) == NULL) 1150*11963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY); 1151*11963SAfshin.Ardakani@Sun.COM 1152*11963SAfshin.Ardakani@Sun.COM if (read(xfd, buf, statbuf.st_size) == statbuf.st_size) 1153*11963SAfshin.Ardakani@Sun.COM status = dfs_root_decode(info, buf, statbuf.st_size, infolvl); 1154*11963SAfshin.Ardakani@Sun.COM else 1155*11963SAfshin.Ardakani@Sun.COM status = ERROR_INTERNAL_ERROR; 1156*11963SAfshin.Ardakani@Sun.COM 1157*11963SAfshin.Ardakani@Sun.COM free(buf); 1158*11963SAfshin.Ardakani@Sun.COM return (status); 1159*11963SAfshin.Ardakani@Sun.COM } 1160*11963SAfshin.Ardakani@Sun.COM 1161*11963SAfshin.Ardakani@Sun.COM /* 1162*11963SAfshin.Ardakani@Sun.COM * Encodes (packs) DFS information in 'info' into a flat 1163*11963SAfshin.Ardakani@Sun.COM * buffer in a name-value format. This function allocates a 1164*11963SAfshin.Ardakani@Sun.COM * buffer with appropriate size to contain all the information 1165*11963SAfshin.Ardakani@Sun.COM * so the caller MUST free the allocated memory by calling free(). 1166*11963SAfshin.Ardakani@Sun.COM */ 1167*11963SAfshin.Ardakani@Sun.COM static uint32_t 1168*11963SAfshin.Ardakani@Sun.COM dfs_root_encode(dfs_info_t *info, char **buf, size_t *bufsz) 1169*11963SAfshin.Ardakani@Sun.COM { 1170*11963SAfshin.Ardakani@Sun.COM dfs_target_t *t; 1171*11963SAfshin.Ardakani@Sun.COM nvlist_t *nvl; 1172*11963SAfshin.Ardakani@Sun.COM int rc; 1173*11963SAfshin.Ardakani@Sun.COM 1174*11963SAfshin.Ardakani@Sun.COM if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) 1175*11963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY); 1176*11963SAfshin.Ardakani@Sun.COM 1177*11963SAfshin.Ardakani@Sun.COM rc = nvlist_add_string(nvl, "comment", info->i_comment); 1178*11963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_string(nvl, "guid", info->i_guid); 1179*11963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_uint32(nvl, "state", info->i_state); 1180*11963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_uint32(nvl, "timeout", info->i_timeout); 1181*11963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_uint32(nvl, "propflags", info->i_propflags); 1182*11963SAfshin.Ardakani@Sun.COM t = info->i_targets; 1183*11963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_string(nvl, "t_server", t->t_server); 1184*11963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_string(nvl, "t_share", t->t_share); 1185*11963SAfshin.Ardakani@Sun.COM rc |= nvlist_add_uint32(nvl, "t_state", t->t_state); 1186*11963SAfshin.Ardakani@Sun.COM 1187*11963SAfshin.Ardakani@Sun.COM if (rc == 0) 1188*11963SAfshin.Ardakani@Sun.COM rc = nvlist_pack(nvl, buf, bufsz, NV_ENCODE_NATIVE, 0); 1189*11963SAfshin.Ardakani@Sun.COM 1190*11963SAfshin.Ardakani@Sun.COM nvlist_free(nvl); 1191*11963SAfshin.Ardakani@Sun.COM 1192*11963SAfshin.Ardakani@Sun.COM return ((rc == 0) ? ERROR_SUCCESS : ERROR_INTERNAL_ERROR); 1193*11963SAfshin.Ardakani@Sun.COM } 1194*11963SAfshin.Ardakani@Sun.COM 1195*11963SAfshin.Ardakani@Sun.COM /* 1196*11963SAfshin.Ardakani@Sun.COM * Decodes (unpack) provided buffer which contains a list of name-value 1197*11963SAfshin.Ardakani@Sun.COM * pairs into given dfs_info_t structure 1198*11963SAfshin.Ardakani@Sun.COM */ 1199*11963SAfshin.Ardakani@Sun.COM static uint32_t 1200*11963SAfshin.Ardakani@Sun.COM dfs_root_decode(dfs_info_t *info, char *buf, size_t bufsz, uint32_t infolvl) 1201*11963SAfshin.Ardakani@Sun.COM { 1202*11963SAfshin.Ardakani@Sun.COM nvlist_t *nvl; 1203*11963SAfshin.Ardakani@Sun.COM char *cmnt, *guid; 1204*11963SAfshin.Ardakani@Sun.COM char *t_server, *t_share; 1205*11963SAfshin.Ardakani@Sun.COM uint32_t t_state; 1206*11963SAfshin.Ardakani@Sun.COM int rc; 1207*11963SAfshin.Ardakani@Sun.COM 1208*11963SAfshin.Ardakani@Sun.COM if (nvlist_unpack(buf, bufsz, &nvl, 0) != 0) 1209*11963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 1210*11963SAfshin.Ardakani@Sun.COM 1211*11963SAfshin.Ardakani@Sun.COM rc = nvlist_lookup_string(nvl, "comment", &cmnt); 1212*11963SAfshin.Ardakani@Sun.COM rc |= nvlist_lookup_string(nvl, "guid", &guid); 1213*11963SAfshin.Ardakani@Sun.COM rc |= nvlist_lookup_uint32(nvl, "state", &info->i_state); 1214*11963SAfshin.Ardakani@Sun.COM rc |= nvlist_lookup_uint32(nvl, "timeout", &info->i_timeout); 1215*11963SAfshin.Ardakani@Sun.COM rc |= nvlist_lookup_uint32(nvl, "propflags", &info->i_propflags); 1216*11963SAfshin.Ardakani@Sun.COM 1217*11963SAfshin.Ardakani@Sun.COM if (rc != 0) { 1218*11963SAfshin.Ardakani@Sun.COM nvlist_free(nvl); 1219*11963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 1220*11963SAfshin.Ardakani@Sun.COM } 1221*11963SAfshin.Ardakani@Sun.COM 1222*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_comment, (cmnt) ? cmnt : "", 1223*11963SAfshin.Ardakani@Sun.COM sizeof (info->i_comment)); 1224*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_guid, (guid) ? guid : "", sizeof (info->i_guid)); 1225*11963SAfshin.Ardakani@Sun.COM 1226*11963SAfshin.Ardakani@Sun.COM info->i_targets = NULL; 1227*11963SAfshin.Ardakani@Sun.COM info->i_ntargets = 1; 1228*11963SAfshin.Ardakani@Sun.COM 1229*11963SAfshin.Ardakani@Sun.COM switch (infolvl) { 1230*11963SAfshin.Ardakani@Sun.COM case DFS_INFO_ALL: 1231*11963SAfshin.Ardakani@Sun.COM case 3: 1232*11963SAfshin.Ardakani@Sun.COM case 4: 1233*11963SAfshin.Ardakani@Sun.COM case 6: 1234*11963SAfshin.Ardakani@Sun.COM case 9: 1235*11963SAfshin.Ardakani@Sun.COM /* need target information */ 1236*11963SAfshin.Ardakani@Sun.COM break; 1237*11963SAfshin.Ardakani@Sun.COM default: 1238*11963SAfshin.Ardakani@Sun.COM nvlist_free(nvl); 1239*11963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 1240*11963SAfshin.Ardakani@Sun.COM } 1241*11963SAfshin.Ardakani@Sun.COM 1242*11963SAfshin.Ardakani@Sun.COM info->i_targets = malloc(sizeof (dfs_target_t)); 1243*11963SAfshin.Ardakani@Sun.COM if (info->i_targets == NULL) { 1244*11963SAfshin.Ardakani@Sun.COM nvlist_free(nvl); 1245*11963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY); 1246*11963SAfshin.Ardakani@Sun.COM } 1247*11963SAfshin.Ardakani@Sun.COM 1248*11963SAfshin.Ardakani@Sun.COM rc = nvlist_lookup_string(nvl, "t_server", &t_server); 1249*11963SAfshin.Ardakani@Sun.COM rc |= nvlist_lookup_string(nvl, "t_share", &t_share); 1250*11963SAfshin.Ardakani@Sun.COM rc |= nvlist_lookup_uint32(nvl, "t_state", &t_state); 1251*11963SAfshin.Ardakani@Sun.COM if (rc != 0) { 1252*11963SAfshin.Ardakani@Sun.COM nvlist_free(nvl); 1253*11963SAfshin.Ardakani@Sun.COM free(info->i_targets); 1254*11963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 1255*11963SAfshin.Ardakani@Sun.COM } 1256*11963SAfshin.Ardakani@Sun.COM dfs_target_init(info->i_targets, t_server, t_share, t_state); 1257*11963SAfshin.Ardakani@Sun.COM 1258*11963SAfshin.Ardakani@Sun.COM nvlist_free(nvl); 1259*11963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 1260*11963SAfshin.Ardakani@Sun.COM } 1261*11963SAfshin.Ardakani@Sun.COM 1262*11963SAfshin.Ardakani@Sun.COM /* 1263*11963SAfshin.Ardakani@Sun.COM * Determines if the passed state is valid for a DFS root 1264*11963SAfshin.Ardakani@Sun.COM * 1265*11963SAfshin.Ardakani@Sun.COM * This is based on test results against Win2003 and in some cases 1266*11963SAfshin.Ardakani@Sun.COM * does not match [MS-DFSNM] spec. 1267*11963SAfshin.Ardakani@Sun.COM */ 1268*11963SAfshin.Ardakani@Sun.COM static uint32_t 1269*11963SAfshin.Ardakani@Sun.COM dfs_root_isvalidstate(uint32_t state) 1270*11963SAfshin.Ardakani@Sun.COM { 1271*11963SAfshin.Ardakani@Sun.COM switch (state) { 1272*11963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_OK: 1273*11963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_RESYNCHRONIZE: 1274*11963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 1275*11963SAfshin.Ardakani@Sun.COM 1276*11963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_INCONSISTENT: 1277*11963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_FORCE_SYNC: 1278*11963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_PARAMETER); 1279*11963SAfshin.Ardakani@Sun.COM 1280*11963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_OFFLINE: 1281*11963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_ONLINE: 1282*11963SAfshin.Ardakani@Sun.COM case DFS_VOLUME_STATE_STANDBY: 1283*11963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_SUPPORTED); 1284*11963SAfshin.Ardakani@Sun.COM default: 1285*11963SAfshin.Ardakani@Sun.COM break; 1286*11963SAfshin.Ardakani@Sun.COM } 1287*11963SAfshin.Ardakani@Sun.COM 1288*11963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_PARAMETER); 1289*11963SAfshin.Ardakani@Sun.COM } 1290*11963SAfshin.Ardakani@Sun.COM 1291*11963SAfshin.Ardakani@Sun.COM /* 1292*11963SAfshin.Ardakani@Sun.COM * Decodes the link info from given string buffer (buf) into 1293*11963SAfshin.Ardakani@Sun.COM * dfs_info_t structure. 1294*11963SAfshin.Ardakani@Sun.COM */ 1295*11963SAfshin.Ardakani@Sun.COM static uint32_t 1296*11963SAfshin.Ardakani@Sun.COM dfs_link_decode(dfs_info_t *info, char *buf, uint32_t infolvl) 1297*11963SAfshin.Ardakani@Sun.COM { 1298*11963SAfshin.Ardakani@Sun.COM char *lfield[DFS_LINK_HDR_NFIELDS]; 1299*11963SAfshin.Ardakani@Sun.COM dfs_target_t *t; 1300*11963SAfshin.Ardakani@Sun.COM uint32_t linkver; 1301*11963SAfshin.Ardakani@Sun.COM uint32_t cmntlen; 1302*11963SAfshin.Ardakani@Sun.COM uint32_t cpylen; 1303*11963SAfshin.Ardakani@Sun.COM int i, j; 1304*11963SAfshin.Ardakani@Sun.COM 1305*11963SAfshin.Ardakani@Sun.COM /* 1306*11963SAfshin.Ardakani@Sun.COM * Header format 1307*11963SAfshin.Ardakani@Sun.COM * ver:state:prop:timeout:guid:ntarget:cmntlen:comment: 1308*11963SAfshin.Ardakani@Sun.COM */ 1309*11963SAfshin.Ardakani@Sun.COM for (i = 0; i < DFS_LINK_HDR_NFIELDS; i++) { 1310*11963SAfshin.Ardakani@Sun.COM if ((lfield[i] = strsep((char **)&buf, ":")) == NULL) 1311*11963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_DATA); 1312*11963SAfshin.Ardakani@Sun.COM } 1313*11963SAfshin.Ardakani@Sun.COM 1314*11963SAfshin.Ardakani@Sun.COM i = 0; 1315*11963SAfshin.Ardakani@Sun.COM linkver = strtoul(lfield[i++], NULL, 10); 1316*11963SAfshin.Ardakani@Sun.COM if (linkver != DFS_LINK_V1) 1317*11963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_DATA); 1318*11963SAfshin.Ardakani@Sun.COM 1319*11963SAfshin.Ardakani@Sun.COM info->i_state = strtoul(lfield[i++], NULL, 10); 1320*11963SAfshin.Ardakani@Sun.COM info->i_propflags = strtoul(lfield[i++], NULL, 10); 1321*11963SAfshin.Ardakani@Sun.COM info->i_timeout = strtoul(lfield[i++], NULL, 10); 1322*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_guid, lfield[i++], sizeof (info->i_guid)); 1323*11963SAfshin.Ardakani@Sun.COM info->i_ntargets = strtoul(lfield[i++], NULL, 10); 1324*11963SAfshin.Ardakani@Sun.COM info->i_targets = NULL; 1325*11963SAfshin.Ardakani@Sun.COM 1326*11963SAfshin.Ardakani@Sun.COM cpylen = cmntlen = strtoul(lfield[i++], NULL, 10); 1327*11963SAfshin.Ardakani@Sun.COM 1328*11963SAfshin.Ardakani@Sun.COM if (cmntlen > sizeof (info->i_comment)) 1329*11963SAfshin.Ardakani@Sun.COM cpylen = sizeof (info->i_comment); 1330*11963SAfshin.Ardakani@Sun.COM else if (cmntlen != 0) 1331*11963SAfshin.Ardakani@Sun.COM cpylen = cmntlen + 1; 1332*11963SAfshin.Ardakani@Sun.COM 1333*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_comment, buf, cpylen); 1334*11963SAfshin.Ardakani@Sun.COM buf += (cmntlen + 1); 1335*11963SAfshin.Ardakani@Sun.COM 1336*11963SAfshin.Ardakani@Sun.COM switch (infolvl) { 1337*11963SAfshin.Ardakani@Sun.COM case DFS_INFO_ALL: 1338*11963SAfshin.Ardakani@Sun.COM case 3: 1339*11963SAfshin.Ardakani@Sun.COM case 4: 1340*11963SAfshin.Ardakani@Sun.COM case 6: 1341*11963SAfshin.Ardakani@Sun.COM case 9: 1342*11963SAfshin.Ardakani@Sun.COM /* need target information */ 1343*11963SAfshin.Ardakani@Sun.COM break; 1344*11963SAfshin.Ardakani@Sun.COM default: 1345*11963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 1346*11963SAfshin.Ardakani@Sun.COM } 1347*11963SAfshin.Ardakani@Sun.COM 1348*11963SAfshin.Ardakani@Sun.COM info->i_targets = calloc(info->i_ntargets, sizeof (dfs_target_t)); 1349*11963SAfshin.Ardakani@Sun.COM if (info->i_targets == NULL) 1350*11963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY); 1351*11963SAfshin.Ardakani@Sun.COM 1352*11963SAfshin.Ardakani@Sun.COM /* 1353*11963SAfshin.Ardakani@Sun.COM * Format for each target 1354*11963SAfshin.Ardakani@Sun.COM * server:share:state:class:rank 1355*11963SAfshin.Ardakani@Sun.COM */ 1356*11963SAfshin.Ardakani@Sun.COM for (i = 0, t = info->i_targets; i < info->i_ntargets; i++, t++) { 1357*11963SAfshin.Ardakani@Sun.COM for (j = 0; j < DFS_LINK_TRGT_NFIELDS; j++) { 1358*11963SAfshin.Ardakani@Sun.COM if ((lfield[j] = strsep((char **)&buf, ":")) == NULL) { 1359*11963SAfshin.Ardakani@Sun.COM dfs_info_free(info); 1360*11963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_DATA); 1361*11963SAfshin.Ardakani@Sun.COM } 1362*11963SAfshin.Ardakani@Sun.COM } 1363*11963SAfshin.Ardakani@Sun.COM 1364*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(t->t_server, lfield[0], sizeof (t->t_server)); 1365*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(t->t_share, lfield[1], sizeof (t->t_share)); 1366*11963SAfshin.Ardakani@Sun.COM t->t_state = strtoul(lfield[2], NULL, 10); 1367*11963SAfshin.Ardakani@Sun.COM t->t_priority.p_class = strtoul(lfield[3], NULL, 10); 1368*11963SAfshin.Ardakani@Sun.COM t->t_priority.p_rank = strtoul(lfield[4], NULL, 10); 1369*11963SAfshin.Ardakani@Sun.COM } 1370*11963SAfshin.Ardakani@Sun.COM 1371*11963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 1372*11963SAfshin.Ardakani@Sun.COM } 1373*11963SAfshin.Ardakani@Sun.COM 1374*11963SAfshin.Ardakani@Sun.COM /* 1375*11963SAfshin.Ardakani@Sun.COM * Encodes given link information (info) 1376*11963SAfshin.Ardakani@Sun.COM */ 1377*11963SAfshin.Ardakani@Sun.COM static uint32_t 1378*11963SAfshin.Ardakani@Sun.COM dfs_link_encode(dfs_info_t *info, char *buf, size_t bufsz) 1379*11963SAfshin.Ardakani@Sun.COM { 1380*11963SAfshin.Ardakani@Sun.COM char linkdata[MAXREPARSELEN]; 1381*11963SAfshin.Ardakani@Sun.COM dfs_target_t *t; 1382*11963SAfshin.Ardakani@Sun.COM int i, sz; 1383*11963SAfshin.Ardakani@Sun.COM 1384*11963SAfshin.Ardakani@Sun.COM /* 1385*11963SAfshin.Ardakani@Sun.COM * Header format 1386*11963SAfshin.Ardakani@Sun.COM * ver:state:prop:timeout:guid:ntarget:cmntlen:comment 1387*11963SAfshin.Ardakani@Sun.COM */ 1388*11963SAfshin.Ardakani@Sun.COM sz = snprintf(buf, bufsz, "%u:%u:%u:%u:%s:%u:%u:%s", 1389*11963SAfshin.Ardakani@Sun.COM DFS_LINK_V1, info->i_state, info->i_propflags, info->i_timeout, 1390*11963SAfshin.Ardakani@Sun.COM info->i_guid, info->i_ntargets, 1391*11963SAfshin.Ardakani@Sun.COM strlen(info->i_comment), info->i_comment); 1392*11963SAfshin.Ardakani@Sun.COM 1393*11963SAfshin.Ardakani@Sun.COM if (sz > bufsz) { 1394*11963SAfshin.Ardakani@Sun.COM syslog(LOG_WARNING, "dfs: link data is too large"); 1395*11963SAfshin.Ardakani@Sun.COM dfs_info_trace("DFS link encode", info); 1396*11963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 1397*11963SAfshin.Ardakani@Sun.COM } 1398*11963SAfshin.Ardakani@Sun.COM 1399*11963SAfshin.Ardakani@Sun.COM /* 1400*11963SAfshin.Ardakani@Sun.COM * Format for each target 1401*11963SAfshin.Ardakani@Sun.COM * :server:share:state:class:rank 1402*11963SAfshin.Ardakani@Sun.COM */ 1403*11963SAfshin.Ardakani@Sun.COM bufsz -= sz; 1404*11963SAfshin.Ardakani@Sun.COM for (i = 0, t = info->i_targets; i < info->i_ntargets; i++, t++) { 1405*11963SAfshin.Ardakani@Sun.COM if (strchr(t->t_server, ':') || strchr(t->t_share, ':')) 1406*11963SAfshin.Ardakani@Sun.COM return (ERROR_INVALID_NAME); 1407*11963SAfshin.Ardakani@Sun.COM 1408*11963SAfshin.Ardakani@Sun.COM sz = snprintf(linkdata, MAXREPARSELEN, ":%s:%s:%u:%u:%u", 1409*11963SAfshin.Ardakani@Sun.COM t->t_server, t->t_share, t->t_state, 1410*11963SAfshin.Ardakani@Sun.COM t->t_priority.p_class, t->t_priority.p_rank); 1411*11963SAfshin.Ardakani@Sun.COM if (sz > bufsz) { 1412*11963SAfshin.Ardakani@Sun.COM syslog(LOG_WARNING, "dfs: link data is too large"); 1413*11963SAfshin.Ardakani@Sun.COM dfs_info_trace("DFS link encode", info); 1414*11963SAfshin.Ardakani@Sun.COM return (ERROR_INTERNAL_ERROR); 1415*11963SAfshin.Ardakani@Sun.COM } 1416*11963SAfshin.Ardakani@Sun.COM (void) strcat(buf, linkdata); 1417*11963SAfshin.Ardakani@Sun.COM bufsz -= sz; 1418*11963SAfshin.Ardakani@Sun.COM } 1419*11963SAfshin.Ardakani@Sun.COM 1420*11963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 1421*11963SAfshin.Ardakani@Sun.COM } 1422*11963SAfshin.Ardakani@Sun.COM 1423*11963SAfshin.Ardakani@Sun.COM /* 1424*11963SAfshin.Ardakani@Sun.COM * Stores given information for the specified link 1425*11963SAfshin.Ardakani@Sun.COM */ 1426*11963SAfshin.Ardakani@Sun.COM static uint32_t 1427*11963SAfshin.Ardakani@Sun.COM dfs_link_commit(const char *path, dfs_info_t *info) 1428*11963SAfshin.Ardakani@Sun.COM { 1429*11963SAfshin.Ardakani@Sun.COM char linkdata[MAXREPARSELEN]; 1430*11963SAfshin.Ardakani@Sun.COM uint32_t status; 1431*11963SAfshin.Ardakani@Sun.COM int rc; 1432*11963SAfshin.Ardakani@Sun.COM 1433*11963SAfshin.Ardakani@Sun.COM status = dfs_link_encode(info, linkdata, MAXREPARSELEN); 1434*11963SAfshin.Ardakani@Sun.COM if (status == ERROR_SUCCESS) { 1435*11963SAfshin.Ardakani@Sun.COM rc = smb_reparse_svcadd(path, DFS_REPARSE_SVCTYPE, linkdata); 1436*11963SAfshin.Ardakani@Sun.COM if (rc != 0) 1437*11963SAfshin.Ardakani@Sun.COM status = ERROR_INTERNAL_ERROR; 1438*11963SAfshin.Ardakani@Sun.COM } 1439*11963SAfshin.Ardakani@Sun.COM 1440*11963SAfshin.Ardakani@Sun.COM return (status); 1441*11963SAfshin.Ardakani@Sun.COM } 1442*11963SAfshin.Ardakani@Sun.COM 1443*11963SAfshin.Ardakani@Sun.COM /* 1444*11963SAfshin.Ardakani@Sun.COM * Determines if the passed state is valid for a link 1445*11963SAfshin.Ardakani@Sun.COM */ 1446*11963SAfshin.Ardakani@Sun.COM static boolean_t 1447*11963SAfshin.Ardakani@Sun.COM dfs_link_isvalidstate(uint32_t state) 1448*11963SAfshin.Ardakani@Sun.COM { 1449*11963SAfshin.Ardakani@Sun.COM return (state == DFS_VOLUME_STATE_OK || 1450*11963SAfshin.Ardakani@Sun.COM state == DFS_VOLUME_STATE_OFFLINE || 1451*11963SAfshin.Ardakani@Sun.COM state == DFS_VOLUME_STATE_ONLINE); 1452*11963SAfshin.Ardakani@Sun.COM } 1453*11963SAfshin.Ardakani@Sun.COM 1454*11963SAfshin.Ardakani@Sun.COM /* 1455*11963SAfshin.Ardakani@Sun.COM * Initializes the given target structure (t) with provided information. 1456*11963SAfshin.Ardakani@Sun.COM */ 1457*11963SAfshin.Ardakani@Sun.COM static void 1458*11963SAfshin.Ardakani@Sun.COM dfs_target_init(dfs_target_t *t, const char *srv, const char *share, 1459*11963SAfshin.Ardakani@Sun.COM uint32_t state) 1460*11963SAfshin.Ardakani@Sun.COM { 1461*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(t->t_server, (srv) ? srv : "", sizeof (t->t_server)); 1462*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(t->t_share, (share) ? share : "", sizeof (t->t_share)); 1463*11963SAfshin.Ardakani@Sun.COM t->t_state = state; 1464*11963SAfshin.Ardakani@Sun.COM t->t_priority.p_class = DfsSiteCostNormalPriorityClass; 1465*11963SAfshin.Ardakani@Sun.COM t->t_priority.p_rank = 0; 1466*11963SAfshin.Ardakani@Sun.COM } 1467*11963SAfshin.Ardakani@Sun.COM 1468*11963SAfshin.Ardakani@Sun.COM /* 1469*11963SAfshin.Ardakani@Sun.COM * Lookup the specified target (server, share) in the given 1470*11963SAfshin.Ardakani@Sun.COM * target list (targets). If there is a match its index is 1471*11963SAfshin.Ardakani@Sun.COM * returned, otherwise -1 will be returned. 1472*11963SAfshin.Ardakani@Sun.COM */ 1473*11963SAfshin.Ardakani@Sun.COM static int 1474*11963SAfshin.Ardakani@Sun.COM dfs_target_find(dfs_target_t *targets, uint32_t ntargets, 1475*11963SAfshin.Ardakani@Sun.COM const char *server, const char *share) 1476*11963SAfshin.Ardakani@Sun.COM { 1477*11963SAfshin.Ardakani@Sun.COM dfs_target_t *t; 1478*11963SAfshin.Ardakani@Sun.COM int i; 1479*11963SAfshin.Ardakani@Sun.COM 1480*11963SAfshin.Ardakani@Sun.COM for (i = 0, t = targets; i < ntargets; i++, t++) { 1481*11963SAfshin.Ardakani@Sun.COM if ((smb_strcasecmp(t->t_server, server, 0) == 0) && 1482*11963SAfshin.Ardakani@Sun.COM (smb_strcasecmp(t->t_share, share, 0) == 0)) 1483*11963SAfshin.Ardakani@Sun.COM return (i); 1484*11963SAfshin.Ardakani@Sun.COM } 1485*11963SAfshin.Ardakani@Sun.COM 1486*11963SAfshin.Ardakani@Sun.COM return (-1); 1487*11963SAfshin.Ardakani@Sun.COM } 1488*11963SAfshin.Ardakani@Sun.COM 1489*11963SAfshin.Ardakani@Sun.COM /* 1490*11963SAfshin.Ardakani@Sun.COM * Determines if the passed state is valid for a link/root target 1491*11963SAfshin.Ardakani@Sun.COM */ 1492*11963SAfshin.Ardakani@Sun.COM static boolean_t 1493*11963SAfshin.Ardakani@Sun.COM dfs_target_isvalidstate(uint32_t state) 1494*11963SAfshin.Ardakani@Sun.COM { 1495*11963SAfshin.Ardakani@Sun.COM return (state == DFS_STORAGE_STATE_ONLINE || 1496*11963SAfshin.Ardakani@Sun.COM state == DFS_STORAGE_STATE_OFFLINE); 1497*11963SAfshin.Ardakani@Sun.COM } 1498*11963SAfshin.Ardakani@Sun.COM 1499*11963SAfshin.Ardakani@Sun.COM /* 1500*11963SAfshin.Ardakani@Sun.COM * Cache compare function, the key is UNC path 1501*11963SAfshin.Ardakani@Sun.COM */ 1502*11963SAfshin.Ardakani@Sun.COM static int 1503*11963SAfshin.Ardakani@Sun.COM dfs_cache_cmp(const void *p1, const void *p2) 1504*11963SAfshin.Ardakani@Sun.COM { 1505*11963SAfshin.Ardakani@Sun.COM smb_cache_node_t *cn1 = (smb_cache_node_t *)p1; 1506*11963SAfshin.Ardakani@Sun.COM smb_cache_node_t *cn2 = (smb_cache_node_t *)p2; 1507*11963SAfshin.Ardakani@Sun.COM dfs_nscnode_t *dn1 = cn1->cn_data; 1508*11963SAfshin.Ardakani@Sun.COM dfs_nscnode_t *dn2 = cn2->cn_data; 1509*11963SAfshin.Ardakani@Sun.COM int rc; 1510*11963SAfshin.Ardakani@Sun.COM 1511*11963SAfshin.Ardakani@Sun.COM rc = smb_strcasecmp(dn1->nsc_uncpath, dn2->nsc_uncpath, 0); 1512*11963SAfshin.Ardakani@Sun.COM 1513*11963SAfshin.Ardakani@Sun.COM if (rc < 0) 1514*11963SAfshin.Ardakani@Sun.COM return (-1); 1515*11963SAfshin.Ardakani@Sun.COM 1516*11963SAfshin.Ardakani@Sun.COM if (rc > 0) 1517*11963SAfshin.Ardakani@Sun.COM return (1); 1518*11963SAfshin.Ardakani@Sun.COM 1519*11963SAfshin.Ardakani@Sun.COM return (0); 1520*11963SAfshin.Ardakani@Sun.COM } 1521*11963SAfshin.Ardakani@Sun.COM 1522*11963SAfshin.Ardakani@Sun.COM /* 1523*11963SAfshin.Ardakani@Sun.COM * Adds an entry with given UNC and filesystem path and the specified 1524*11963SAfshin.Ardakani@Sun.COM * entry type (i.e. root/link) to the namespace cache. 1525*11963SAfshin.Ardakani@Sun.COM */ 1526*11963SAfshin.Ardakani@Sun.COM static uint32_t 1527*11963SAfshin.Ardakani@Sun.COM dfs_cache_add_byunc(const char *uncpath, const char *fspath, uint32_t type) 1528*11963SAfshin.Ardakani@Sun.COM { 1529*11963SAfshin.Ardakani@Sun.COM dfs_nscnode_t *dn; 1530*11963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_SUCCESS; 1531*11963SAfshin.Ardakani@Sun.COM 1532*11963SAfshin.Ardakani@Sun.COM if ((dn = malloc(sizeof (dfs_nscnode_t))) == NULL) 1533*11963SAfshin.Ardakani@Sun.COM return (ERROR_NOT_ENOUGH_MEMORY); 1534*11963SAfshin.Ardakani@Sun.COM 1535*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(dn->nsc_uncpath, uncpath, sizeof (dn->nsc_uncpath)); 1536*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(dn->nsc_fspath, fspath, sizeof (dn->nsc_fspath)); 1537*11963SAfshin.Ardakani@Sun.COM dn->nsc_type = type; 1538*11963SAfshin.Ardakani@Sun.COM if (smb_cache_add(&dfs_nscache, dn, SMB_CACHE_ADD) != 0) { 1539*11963SAfshin.Ardakani@Sun.COM free(dn); 1540*11963SAfshin.Ardakani@Sun.COM status = ERROR_INTERNAL_ERROR; 1541*11963SAfshin.Ardakani@Sun.COM } 1542*11963SAfshin.Ardakani@Sun.COM 1543*11963SAfshin.Ardakani@Sun.COM return (status); 1544*11963SAfshin.Ardakani@Sun.COM } 1545*11963SAfshin.Ardakani@Sun.COM 1546*11963SAfshin.Ardakani@Sun.COM /* 1547*11963SAfshin.Ardakani@Sun.COM * starting from DFS root directory, scans the tree for DFS links 1548*11963SAfshin.Ardakani@Sun.COM * and adds them to the cache. 1549*11963SAfshin.Ardakani@Sun.COM */ 1550*11963SAfshin.Ardakani@Sun.COM static void 1551*11963SAfshin.Ardakani@Sun.COM dfs_cache_populate(const char *unc_prefix, const char *dir) 1552*11963SAfshin.Ardakani@Sun.COM { 1553*11963SAfshin.Ardakani@Sun.COM char fspath[DFS_PATH_MAX]; 1554*11963SAfshin.Ardakani@Sun.COM char uncpath[DFS_PATH_MAX]; 1555*11963SAfshin.Ardakani@Sun.COM char *fname; 1556*11963SAfshin.Ardakani@Sun.COM int nentries, i; 1557*11963SAfshin.Ardakani@Sun.COM struct dirent **entry_list; 1558*11963SAfshin.Ardakani@Sun.COM uint32_t stat; 1559*11963SAfshin.Ardakani@Sun.COM 1560*11963SAfshin.Ardakani@Sun.COM nentries = scandir(dir, &entry_list, NULL, NULL); 1561*11963SAfshin.Ardakani@Sun.COM if (nentries == -1) 1562*11963SAfshin.Ardakani@Sun.COM return; 1563*11963SAfshin.Ardakani@Sun.COM 1564*11963SAfshin.Ardakani@Sun.COM for (i = 0; i < nentries; i++) { 1565*11963SAfshin.Ardakani@Sun.COM fname = entry_list[i]->d_name; 1566*11963SAfshin.Ardakani@Sun.COM 1567*11963SAfshin.Ardakani@Sun.COM if (strcmp(fname, ".") == 0 || 1568*11963SAfshin.Ardakani@Sun.COM strcmp(fname, "..") == 0) { 1569*11963SAfshin.Ardakani@Sun.COM free(entry_list[i]); 1570*11963SAfshin.Ardakani@Sun.COM continue; 1571*11963SAfshin.Ardakani@Sun.COM } 1572*11963SAfshin.Ardakani@Sun.COM 1573*11963SAfshin.Ardakani@Sun.COM (void) snprintf(fspath, DFS_PATH_MAX, "%s/%s", dir, fname); 1574*11963SAfshin.Ardakani@Sun.COM (void) snprintf(uncpath, DFS_PATH_MAX, "%s\\%s", unc_prefix, 1575*11963SAfshin.Ardakani@Sun.COM fname); 1576*11963SAfshin.Ardakani@Sun.COM 1577*11963SAfshin.Ardakani@Sun.COM if (dfs_path_isdir(fspath)) { 1578*11963SAfshin.Ardakani@Sun.COM dfs_cache_populate(uncpath, fspath); 1579*11963SAfshin.Ardakani@Sun.COM } else if (dfs_link_stat(fspath, &stat) == ERROR_SUCCESS) { 1580*11963SAfshin.Ardakani@Sun.COM if (stat == DFS_STAT_ISDFS) 1581*11963SAfshin.Ardakani@Sun.COM (void) dfs_cache_add_byunc(uncpath, fspath, 1582*11963SAfshin.Ardakani@Sun.COM DFS_OBJECT_LINK); 1583*11963SAfshin.Ardakani@Sun.COM } 1584*11963SAfshin.Ardakani@Sun.COM 1585*11963SAfshin.Ardakani@Sun.COM free(entry_list[i]); 1586*11963SAfshin.Ardakani@Sun.COM } 1587*11963SAfshin.Ardakani@Sun.COM 1588*11963SAfshin.Ardakani@Sun.COM for (; i < nentries; i++) 1589*11963SAfshin.Ardakani@Sun.COM free(entry_list[i]); 1590*11963SAfshin.Ardakani@Sun.COM 1591*11963SAfshin.Ardakani@Sun.COM free(entry_list); 1592*11963SAfshin.Ardakani@Sun.COM } 1593*11963SAfshin.Ardakani@Sun.COM 1594*11963SAfshin.Ardakani@Sun.COM /* 1595*11963SAfshin.Ardakani@Sun.COM * Determines whether the given path is a directory. 1596*11963SAfshin.Ardakani@Sun.COM */ 1597*11963SAfshin.Ardakani@Sun.COM static boolean_t 1598*11963SAfshin.Ardakani@Sun.COM dfs_path_isdir(const char *path) 1599*11963SAfshin.Ardakani@Sun.COM { 1600*11963SAfshin.Ardakani@Sun.COM struct stat statbuf; 1601*11963SAfshin.Ardakani@Sun.COM 1602*11963SAfshin.Ardakani@Sun.COM if (lstat(path, &statbuf) != 0) 1603*11963SAfshin.Ardakani@Sun.COM return (B_FALSE); 1604*11963SAfshin.Ardakani@Sun.COM 1605*11963SAfshin.Ardakani@Sun.COM return ((statbuf.st_mode & S_IFMT) == S_IFDIR); 1606*11963SAfshin.Ardakani@Sun.COM } 1607*11963SAfshin.Ardakani@Sun.COM 1608*11963SAfshin.Ardakani@Sun.COM /* 1609*11963SAfshin.Ardakani@Sun.COM * Validates the given state based on the object type (root/link) 1610*11963SAfshin.Ardakani@Sun.COM * and whether it is the object's state or its target's state 1611*11963SAfshin.Ardakani@Sun.COM */ 1612*11963SAfshin.Ardakani@Sun.COM static uint32_t 1613*11963SAfshin.Ardakani@Sun.COM dfs_isvalidstate(uint32_t state, uint32_t type, boolean_t target) 1614*11963SAfshin.Ardakani@Sun.COM { 1615*11963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_SUCCESS; 1616*11963SAfshin.Ardakani@Sun.COM 1617*11963SAfshin.Ardakani@Sun.COM if (type == DFS_OBJECT_ROOT) { 1618*11963SAfshin.Ardakani@Sun.COM if (!target) 1619*11963SAfshin.Ardakani@Sun.COM return (dfs_root_isvalidstate(state)); 1620*11963SAfshin.Ardakani@Sun.COM 1621*11963SAfshin.Ardakani@Sun.COM if (!dfs_target_isvalidstate(state)) 1622*11963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER; 1623*11963SAfshin.Ardakani@Sun.COM else if (state == DFS_STORAGE_STATE_OFFLINE) 1624*11963SAfshin.Ardakani@Sun.COM status = ERROR_NOT_SUPPORTED; 1625*11963SAfshin.Ardakani@Sun.COM } else { 1626*11963SAfshin.Ardakani@Sun.COM if (!target) { 1627*11963SAfshin.Ardakani@Sun.COM if (!dfs_link_isvalidstate(state)) 1628*11963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER; 1629*11963SAfshin.Ardakani@Sun.COM } else { 1630*11963SAfshin.Ardakani@Sun.COM if (!dfs_target_isvalidstate(state)) 1631*11963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_PARAMETER; 1632*11963SAfshin.Ardakani@Sun.COM } 1633*11963SAfshin.Ardakani@Sun.COM } 1634*11963SAfshin.Ardakani@Sun.COM 1635*11963SAfshin.Ardakani@Sun.COM return (status); 1636*11963SAfshin.Ardakani@Sun.COM } 1637*11963SAfshin.Ardakani@Sun.COM 1638*11963SAfshin.Ardakani@Sun.COM /* 1639*11963SAfshin.Ardakani@Sun.COM * Based on the specified information level (infolvl) copy parts of the 1640*11963SAfshin.Ardakani@Sun.COM * information provided through newinfo into the existing information 1641*11963SAfshin.Ardakani@Sun.COM * (info) for the given object. 1642*11963SAfshin.Ardakani@Sun.COM */ 1643*11963SAfshin.Ardakani@Sun.COM static uint32_t 1644*11963SAfshin.Ardakani@Sun.COM dfs_modinfo(uint32_t type, dfs_info_t *info, dfs_info_t *newinfo, 1645*11963SAfshin.Ardakani@Sun.COM uint32_t infolvl) 1646*11963SAfshin.Ardakani@Sun.COM { 1647*11963SAfshin.Ardakani@Sun.COM boolean_t target_op = B_FALSE; 1648*11963SAfshin.Ardakani@Sun.COM uint32_t status = ERROR_SUCCESS; 1649*11963SAfshin.Ardakani@Sun.COM uint32_t state; 1650*11963SAfshin.Ardakani@Sun.COM int target_idx; 1651*11963SAfshin.Ardakani@Sun.COM 1652*11963SAfshin.Ardakani@Sun.COM if (newinfo->i_targets != NULL) { 1653*11963SAfshin.Ardakani@Sun.COM target_idx = dfs_target_find(info->i_targets, info->i_ntargets, 1654*11963SAfshin.Ardakani@Sun.COM newinfo->i_targets->t_server, newinfo->i_targets->t_share); 1655*11963SAfshin.Ardakani@Sun.COM if (target_idx == -1) 1656*11963SAfshin.Ardakani@Sun.COM return (ERROR_FILE_NOT_FOUND); 1657*11963SAfshin.Ardakani@Sun.COM target_op = B_TRUE; 1658*11963SAfshin.Ardakani@Sun.COM } 1659*11963SAfshin.Ardakani@Sun.COM 1660*11963SAfshin.Ardakani@Sun.COM switch (infolvl) { 1661*11963SAfshin.Ardakani@Sun.COM case 100: 1662*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_comment, newinfo->i_comment, 1663*11963SAfshin.Ardakani@Sun.COM sizeof (newinfo->i_comment)); 1664*11963SAfshin.Ardakani@Sun.COM break; 1665*11963SAfshin.Ardakani@Sun.COM 1666*11963SAfshin.Ardakani@Sun.COM case 101: 1667*11963SAfshin.Ardakani@Sun.COM state = (target_op) 1668*11963SAfshin.Ardakani@Sun.COM ? newinfo->i_targets->t_state : newinfo->i_state; 1669*11963SAfshin.Ardakani@Sun.COM status = dfs_isvalidstate(state, type, target_op); 1670*11963SAfshin.Ardakani@Sun.COM if (status != ERROR_SUCCESS) 1671*11963SAfshin.Ardakani@Sun.COM return (status); 1672*11963SAfshin.Ardakani@Sun.COM 1673*11963SAfshin.Ardakani@Sun.COM if (!target_op) { 1674*11963SAfshin.Ardakani@Sun.COM /* 1675*11963SAfshin.Ardakani@Sun.COM * states specified by this mask should not be stored 1676*11963SAfshin.Ardakani@Sun.COM */ 1677*11963SAfshin.Ardakani@Sun.COM if (state & DFS_VOLUME_STATES_SRV_OPS) 1678*11963SAfshin.Ardakani@Sun.COM return (ERROR_SUCCESS); 1679*11963SAfshin.Ardakani@Sun.COM 1680*11963SAfshin.Ardakani@Sun.COM info->i_state = state; 1681*11963SAfshin.Ardakani@Sun.COM } else { 1682*11963SAfshin.Ardakani@Sun.COM info->i_targets[target_idx].t_state = state; 1683*11963SAfshin.Ardakani@Sun.COM } 1684*11963SAfshin.Ardakani@Sun.COM break; 1685*11963SAfshin.Ardakani@Sun.COM 1686*11963SAfshin.Ardakani@Sun.COM case 102: 1687*11963SAfshin.Ardakani@Sun.COM info->i_timeout = newinfo->i_timeout; 1688*11963SAfshin.Ardakani@Sun.COM break; 1689*11963SAfshin.Ardakani@Sun.COM 1690*11963SAfshin.Ardakani@Sun.COM case 103: 1691*11963SAfshin.Ardakani@Sun.COM info->i_propflags = newinfo->i_propflags; 1692*11963SAfshin.Ardakani@Sun.COM break; 1693*11963SAfshin.Ardakani@Sun.COM 1694*11963SAfshin.Ardakani@Sun.COM case 104: 1695*11963SAfshin.Ardakani@Sun.COM info->i_targets[target_idx].t_priority = 1696*11963SAfshin.Ardakani@Sun.COM newinfo->i_targets->t_priority; 1697*11963SAfshin.Ardakani@Sun.COM break; 1698*11963SAfshin.Ardakani@Sun.COM 1699*11963SAfshin.Ardakani@Sun.COM case 105: 1700*11963SAfshin.Ardakani@Sun.COM (void) strlcpy(info->i_comment, newinfo->i_comment, 1701*11963SAfshin.Ardakani@Sun.COM sizeof (newinfo->i_comment)); 1702*11963SAfshin.Ardakani@Sun.COM info->i_state = newinfo->i_state; 1703*11963SAfshin.Ardakani@Sun.COM info->i_timeout = newinfo->i_timeout; 1704*11963SAfshin.Ardakani@Sun.COM info->i_propflags = newinfo->i_propflags; 1705*11963SAfshin.Ardakani@Sun.COM break; 1706*11963SAfshin.Ardakani@Sun.COM 1707*11963SAfshin.Ardakani@Sun.COM default: 1708*11963SAfshin.Ardakani@Sun.COM status = ERROR_INVALID_LEVEL; 1709*11963SAfshin.Ardakani@Sun.COM } 1710*11963SAfshin.Ardakani@Sun.COM 1711*11963SAfshin.Ardakani@Sun.COM return (status); 1712*11963SAfshin.Ardakani@Sun.COM } 1713