1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <errno.h> 27 #include <unistd.h> 28 #include <strings.h> 29 #include <sys/fs_reparse.h> 30 #include <smbsrv/libsmb.h> 31 32 #include <syslog.h> 33 34 static int smb_reparse_init(const char *, nvlist_t **); 35 static void smb_reparse_free(nvlist_t *); 36 static int smb_reparse_set(const char *, nvlist_t *); 37 38 /* 39 * Checks the status of the object specified by 'path' 40 * 41 * Returns 0 and fills 'stat' with the proper status on 42 * success, otherwise returns an error code. 43 */ 44 int 45 smb_reparse_stat(const char *path, uint32_t *stat) 46 { 47 struct stat statbuf; 48 char symbuf[MAXREPARSELEN]; 49 int rptaglen; 50 51 if (lstat(path, &statbuf) != 0) { 52 if (errno == ENOENT) { 53 *stat = SMB_REPARSE_NOTFOUND; 54 return (0); 55 } 56 return (errno); 57 } 58 59 if ((statbuf.st_mode & S_IFMT) != S_IFLNK) { 60 *stat = SMB_REPARSE_NOTREPARSE; 61 return (0); 62 } 63 64 bzero(symbuf, MAXREPARSELEN); 65 if (readlink(path, symbuf, MAXREPARSELEN) == -1) 66 return (errno); 67 68 rptaglen = strlen(FS_REPARSE_TAG_STR); 69 if (strncmp(symbuf, FS_REPARSE_TAG_STR, rptaglen) != 0) 70 *stat = SMB_REPARSE_NOTREPARSE; 71 else 72 *stat = SMB_REPARSE_ISREPARSE; 73 74 return (0); 75 } 76 77 /* 78 * If the reparse point specified by the path already exists 79 * it is updated by given service type and its data. Update means 80 * that if such service type does not already exist, it is added 81 * otherwise it is overwritten by given data. 82 * 83 * If the reparse point does not exist, one is created with given 84 * service type and its data. 85 */ 86 int 87 smb_reparse_svcadd(const char *path, const char *svctype, const char *svcdata) 88 { 89 nvlist_t *nvl; 90 int rc; 91 92 if ((rc = smb_reparse_init(path, &nvl)) != 0) 93 return (rc); 94 95 if ((rc = reparse_add(nvl, svctype, svcdata)) != 0) { 96 smb_reparse_free(nvl); 97 return (rc); 98 } 99 100 rc = smb_reparse_set(path, nvl); 101 smb_reparse_free(nvl); 102 103 return (rc); 104 } 105 106 /* 107 * Removes the entry for the given service type from the 108 * specified reparse point. If there is no service entry 109 * left, the reparse point object will be deleted. 110 */ 111 int 112 smb_reparse_svcdel(const char *path, const char *svctype) 113 { 114 nvlist_t *nvl; 115 int rc; 116 117 if ((rc = smb_reparse_init(path, &nvl)) != 0) 118 return (rc); 119 120 if ((rc = reparse_remove(nvl, svctype)) != 0) { 121 smb_reparse_free(nvl); 122 return (rc); 123 } 124 125 if (nvlist_next_nvpair(nvl, NULL) == NULL) { 126 /* list is empty remove the object */ 127 rc = reparse_delete(path); 128 if ((rc != 0) && (rc == ENOENT)) 129 rc = 0; 130 } else { 131 rc = smb_reparse_set(path, nvl); 132 } 133 134 smb_reparse_free(nvl); 135 return (rc); 136 } 137 138 /* 139 * Obtains data of the given service type from the specified 140 * reparse point. Function allocates the memory needed to hold 141 * the service data so the caller must free this memory by 142 * calling free(). 143 * 144 * If 'svcdata' is NULL, successful return means that the reparse 145 * point contains a record for the given service type. 146 */ 147 int 148 smb_reparse_svcget(const char *path, const char *svctype, char **svcdata) 149 { 150 nvlist_t *nvl; 151 nvpair_t *nvp; 152 char *stype, *sdata; 153 int rc; 154 155 if ((rc = smb_reparse_init(path, &nvl)) != 0) 156 return (rc); 157 158 rc = ENODATA; 159 nvp = nvlist_next_nvpair(nvl, NULL); 160 161 while (nvp != NULL) { 162 stype = nvpair_name(nvp); 163 164 if ((stype != NULL) && (strcasecmp(stype, svctype) == 0)) { 165 if ((rc = nvpair_value_string(nvp, &sdata)) != 0) 166 break; 167 168 if (svcdata != NULL) { 169 if ((*svcdata = strdup(sdata)) == NULL) 170 rc = ENOMEM; 171 } 172 173 rc = 0; 174 break; 175 } 176 nvp = nvlist_next_nvpair(nvl, nvp); 177 } 178 179 smb_reparse_free(nvl); 180 return (rc); 181 } 182 183 /* 184 * Initializes the given nvpair list. 185 * 186 * This function assumes that the object specified by this path 187 * is a reparse point, so it does not do any verification. 188 * 189 * If specified reparse point does not exist the function 190 * returns successfully with an empty nvpair list. 191 * 192 * If the object exists and readlink is successful then nvpair 193 * list is polulated with the reparse service information, otherwise 194 * an error code is returned. 195 */ 196 static int 197 smb_reparse_init(const char *path, nvlist_t **nvl) 198 { 199 char rp_data[MAXREPARSELEN]; 200 int rc; 201 202 if ((*nvl = reparse_init()) == NULL) 203 return (ENOMEM); 204 205 bzero(rp_data, MAXREPARSELEN); 206 if ((rc = readlink(path, rp_data, MAXREPARSELEN)) == -1) { 207 if (errno == ENOENT) 208 return (0); 209 210 reparse_free(*nvl); 211 return (errno); 212 } 213 214 if ((rc = reparse_parse(rp_data, *nvl)) != 0) { 215 reparse_free(*nvl); 216 return (rc); 217 } 218 219 return (0); 220 } 221 222 /* 223 * Frees given nvlist 224 */ 225 static void 226 smb_reparse_free(nvlist_t *nvl) 227 { 228 reparse_free(nvl); 229 } 230 231 /* 232 * Create a reparse point with given services in the passed 233 * nvlist. If the reparse point already exists, it will be 234 * deleted and a new one with the given data is created. 235 */ 236 static int 237 smb_reparse_set(const char *path, nvlist_t *nvl) 238 { 239 char *rp_data; 240 int rc; 241 242 if ((rc = reparse_unparse(nvl, &rp_data)) != 0) 243 return (rc); 244 245 rc = reparse_delete(path); 246 if ((rc != 0) && (rc != ENOENT)) { 247 free(rp_data); 248 return (rc); 249 } 250 251 rc = reparse_create(path, rp_data); 252 free(rp_data); 253 254 return (rc); 255 } 256