xref: /onnv-gate/usr/src/lib/smbsrv/libsmb/common/smb_reparse.c (revision 11963:061945695ce1)
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 <errno.h>
27*11963SAfshin.Ardakani@Sun.COM #include <unistd.h>
28*11963SAfshin.Ardakani@Sun.COM #include <strings.h>
29*11963SAfshin.Ardakani@Sun.COM #include <sys/fs_reparse.h>
30*11963SAfshin.Ardakani@Sun.COM #include <smbsrv/libsmb.h>
31*11963SAfshin.Ardakani@Sun.COM 
32*11963SAfshin.Ardakani@Sun.COM #include <syslog.h>
33*11963SAfshin.Ardakani@Sun.COM 
34*11963SAfshin.Ardakani@Sun.COM static int smb_reparse_init(const char *, nvlist_t **);
35*11963SAfshin.Ardakani@Sun.COM static void smb_reparse_free(nvlist_t *);
36*11963SAfshin.Ardakani@Sun.COM static int smb_reparse_set(const char *, nvlist_t *);
37*11963SAfshin.Ardakani@Sun.COM 
38*11963SAfshin.Ardakani@Sun.COM /*
39*11963SAfshin.Ardakani@Sun.COM  * Checks the status of the object specified by 'path'
40*11963SAfshin.Ardakani@Sun.COM  *
41*11963SAfshin.Ardakani@Sun.COM  * Returns 0 and fills 'stat' with the proper status on
42*11963SAfshin.Ardakani@Sun.COM  * success, otherwise returns an error code.
43*11963SAfshin.Ardakani@Sun.COM  */
44*11963SAfshin.Ardakani@Sun.COM int
smb_reparse_stat(const char * path,uint32_t * stat)45*11963SAfshin.Ardakani@Sun.COM smb_reparse_stat(const char *path, uint32_t *stat)
46*11963SAfshin.Ardakani@Sun.COM {
47*11963SAfshin.Ardakani@Sun.COM 	struct stat statbuf;
48*11963SAfshin.Ardakani@Sun.COM 	char symbuf[MAXREPARSELEN];
49*11963SAfshin.Ardakani@Sun.COM 	int rptaglen;
50*11963SAfshin.Ardakani@Sun.COM 
51*11963SAfshin.Ardakani@Sun.COM 	if (lstat(path, &statbuf) != 0) {
52*11963SAfshin.Ardakani@Sun.COM 		if (errno == ENOENT) {
53*11963SAfshin.Ardakani@Sun.COM 			*stat = SMB_REPARSE_NOTFOUND;
54*11963SAfshin.Ardakani@Sun.COM 			return (0);
55*11963SAfshin.Ardakani@Sun.COM 		}
56*11963SAfshin.Ardakani@Sun.COM 		return (errno);
57*11963SAfshin.Ardakani@Sun.COM 	}
58*11963SAfshin.Ardakani@Sun.COM 
59*11963SAfshin.Ardakani@Sun.COM 	if ((statbuf.st_mode & S_IFMT) != S_IFLNK) {
60*11963SAfshin.Ardakani@Sun.COM 		*stat = SMB_REPARSE_NOTREPARSE;
61*11963SAfshin.Ardakani@Sun.COM 		return (0);
62*11963SAfshin.Ardakani@Sun.COM 	}
63*11963SAfshin.Ardakani@Sun.COM 
64*11963SAfshin.Ardakani@Sun.COM 	bzero(symbuf, MAXREPARSELEN);
65*11963SAfshin.Ardakani@Sun.COM 	if (readlink(path, symbuf, MAXREPARSELEN) == -1)
66*11963SAfshin.Ardakani@Sun.COM 		return (errno);
67*11963SAfshin.Ardakani@Sun.COM 
68*11963SAfshin.Ardakani@Sun.COM 	rptaglen = strlen(FS_REPARSE_TAG_STR);
69*11963SAfshin.Ardakani@Sun.COM 	if (strncmp(symbuf, FS_REPARSE_TAG_STR, rptaglen) != 0)
70*11963SAfshin.Ardakani@Sun.COM 		*stat = SMB_REPARSE_NOTREPARSE;
71*11963SAfshin.Ardakani@Sun.COM 	else
72*11963SAfshin.Ardakani@Sun.COM 		*stat = SMB_REPARSE_ISREPARSE;
73*11963SAfshin.Ardakani@Sun.COM 
74*11963SAfshin.Ardakani@Sun.COM 	return (0);
75*11963SAfshin.Ardakani@Sun.COM }
76*11963SAfshin.Ardakani@Sun.COM 
77*11963SAfshin.Ardakani@Sun.COM /*
78*11963SAfshin.Ardakani@Sun.COM  * If the reparse point specified by the path already exists
79*11963SAfshin.Ardakani@Sun.COM  * it is updated by given service type and its data. Update means
80*11963SAfshin.Ardakani@Sun.COM  * that if such service type does not already exist, it is added
81*11963SAfshin.Ardakani@Sun.COM  * otherwise it is overwritten by given data.
82*11963SAfshin.Ardakani@Sun.COM  *
83*11963SAfshin.Ardakani@Sun.COM  * If the reparse point does not exist, one is created with given
84*11963SAfshin.Ardakani@Sun.COM  * service type and its data.
85*11963SAfshin.Ardakani@Sun.COM  */
86*11963SAfshin.Ardakani@Sun.COM int
smb_reparse_svcadd(const char * path,const char * svctype,const char * svcdata)87*11963SAfshin.Ardakani@Sun.COM smb_reparse_svcadd(const char *path, const char *svctype, const char *svcdata)
88*11963SAfshin.Ardakani@Sun.COM {
89*11963SAfshin.Ardakani@Sun.COM 	nvlist_t *nvl;
90*11963SAfshin.Ardakani@Sun.COM 	int rc;
91*11963SAfshin.Ardakani@Sun.COM 
92*11963SAfshin.Ardakani@Sun.COM 	if ((rc = smb_reparse_init(path, &nvl)) != 0)
93*11963SAfshin.Ardakani@Sun.COM 		return (rc);
94*11963SAfshin.Ardakani@Sun.COM 
95*11963SAfshin.Ardakani@Sun.COM 	if ((rc = reparse_add(nvl, svctype, svcdata)) != 0) {
96*11963SAfshin.Ardakani@Sun.COM 		smb_reparse_free(nvl);
97*11963SAfshin.Ardakani@Sun.COM 		return (rc);
98*11963SAfshin.Ardakani@Sun.COM 	}
99*11963SAfshin.Ardakani@Sun.COM 
100*11963SAfshin.Ardakani@Sun.COM 	rc = smb_reparse_set(path, nvl);
101*11963SAfshin.Ardakani@Sun.COM 	smb_reparse_free(nvl);
102*11963SAfshin.Ardakani@Sun.COM 
103*11963SAfshin.Ardakani@Sun.COM 	return (rc);
104*11963SAfshin.Ardakani@Sun.COM }
105*11963SAfshin.Ardakani@Sun.COM 
106*11963SAfshin.Ardakani@Sun.COM /*
107*11963SAfshin.Ardakani@Sun.COM  * Removes the entry for the given service type from the
108*11963SAfshin.Ardakani@Sun.COM  * specified reparse point. If there is no service entry
109*11963SAfshin.Ardakani@Sun.COM  * left, the reparse point object will be deleted.
110*11963SAfshin.Ardakani@Sun.COM  */
111*11963SAfshin.Ardakani@Sun.COM int
smb_reparse_svcdel(const char * path,const char * svctype)112*11963SAfshin.Ardakani@Sun.COM smb_reparse_svcdel(const char *path, const char *svctype)
113*11963SAfshin.Ardakani@Sun.COM {
114*11963SAfshin.Ardakani@Sun.COM 	nvlist_t *nvl;
115*11963SAfshin.Ardakani@Sun.COM 	int rc;
116*11963SAfshin.Ardakani@Sun.COM 
117*11963SAfshin.Ardakani@Sun.COM 	if ((rc = smb_reparse_init(path, &nvl)) != 0)
118*11963SAfshin.Ardakani@Sun.COM 		return (rc);
119*11963SAfshin.Ardakani@Sun.COM 
120*11963SAfshin.Ardakani@Sun.COM 	if ((rc = reparse_remove(nvl, svctype)) != 0) {
121*11963SAfshin.Ardakani@Sun.COM 		smb_reparse_free(nvl);
122*11963SAfshin.Ardakani@Sun.COM 		return (rc);
123*11963SAfshin.Ardakani@Sun.COM 	}
124*11963SAfshin.Ardakani@Sun.COM 
125*11963SAfshin.Ardakani@Sun.COM 	if (nvlist_next_nvpair(nvl, NULL) == NULL) {
126*11963SAfshin.Ardakani@Sun.COM 		/* list is empty remove the object */
127*11963SAfshin.Ardakani@Sun.COM 		rc = reparse_delete(path);
128*11963SAfshin.Ardakani@Sun.COM 		if ((rc != 0) && (rc == ENOENT))
129*11963SAfshin.Ardakani@Sun.COM 			rc = 0;
130*11963SAfshin.Ardakani@Sun.COM 	} else {
131*11963SAfshin.Ardakani@Sun.COM 		rc = smb_reparse_set(path, nvl);
132*11963SAfshin.Ardakani@Sun.COM 	}
133*11963SAfshin.Ardakani@Sun.COM 
134*11963SAfshin.Ardakani@Sun.COM 	smb_reparse_free(nvl);
135*11963SAfshin.Ardakani@Sun.COM 	return (rc);
136*11963SAfshin.Ardakani@Sun.COM }
137*11963SAfshin.Ardakani@Sun.COM 
138*11963SAfshin.Ardakani@Sun.COM /*
139*11963SAfshin.Ardakani@Sun.COM  * Obtains data of the given service type from the specified
140*11963SAfshin.Ardakani@Sun.COM  * reparse point. Function allocates the memory needed to hold
141*11963SAfshin.Ardakani@Sun.COM  * the service data so the caller must free this memory by
142*11963SAfshin.Ardakani@Sun.COM  * calling free().
143*11963SAfshin.Ardakani@Sun.COM  *
144*11963SAfshin.Ardakani@Sun.COM  * If 'svcdata' is NULL, successful return means that the reparse
145*11963SAfshin.Ardakani@Sun.COM  * point contains a record for the given service type.
146*11963SAfshin.Ardakani@Sun.COM  */
147*11963SAfshin.Ardakani@Sun.COM int
smb_reparse_svcget(const char * path,const char * svctype,char ** svcdata)148*11963SAfshin.Ardakani@Sun.COM smb_reparse_svcget(const char *path, const char *svctype, char **svcdata)
149*11963SAfshin.Ardakani@Sun.COM {
150*11963SAfshin.Ardakani@Sun.COM 	nvlist_t *nvl;
151*11963SAfshin.Ardakani@Sun.COM 	nvpair_t *nvp;
152*11963SAfshin.Ardakani@Sun.COM 	char *stype, *sdata;
153*11963SAfshin.Ardakani@Sun.COM 	int rc;
154*11963SAfshin.Ardakani@Sun.COM 
155*11963SAfshin.Ardakani@Sun.COM 	if ((rc = smb_reparse_init(path, &nvl)) != 0)
156*11963SAfshin.Ardakani@Sun.COM 		return (rc);
157*11963SAfshin.Ardakani@Sun.COM 
158*11963SAfshin.Ardakani@Sun.COM 	rc = ENODATA;
159*11963SAfshin.Ardakani@Sun.COM 	nvp = nvlist_next_nvpair(nvl, NULL);
160*11963SAfshin.Ardakani@Sun.COM 
161*11963SAfshin.Ardakani@Sun.COM 	while (nvp != NULL) {
162*11963SAfshin.Ardakani@Sun.COM 		stype = nvpair_name(nvp);
163*11963SAfshin.Ardakani@Sun.COM 
164*11963SAfshin.Ardakani@Sun.COM 		if ((stype != NULL) && (strcasecmp(stype, svctype) == 0)) {
165*11963SAfshin.Ardakani@Sun.COM 			if ((rc = nvpair_value_string(nvp, &sdata)) != 0)
166*11963SAfshin.Ardakani@Sun.COM 				break;
167*11963SAfshin.Ardakani@Sun.COM 
168*11963SAfshin.Ardakani@Sun.COM 			if (svcdata != NULL) {
169*11963SAfshin.Ardakani@Sun.COM 				if ((*svcdata = strdup(sdata)) == NULL)
170*11963SAfshin.Ardakani@Sun.COM 					rc = ENOMEM;
171*11963SAfshin.Ardakani@Sun.COM 			}
172*11963SAfshin.Ardakani@Sun.COM 
173*11963SAfshin.Ardakani@Sun.COM 			rc = 0;
174*11963SAfshin.Ardakani@Sun.COM 			break;
175*11963SAfshin.Ardakani@Sun.COM 		}
176*11963SAfshin.Ardakani@Sun.COM 		nvp = nvlist_next_nvpair(nvl, nvp);
177*11963SAfshin.Ardakani@Sun.COM 	}
178*11963SAfshin.Ardakani@Sun.COM 
179*11963SAfshin.Ardakani@Sun.COM 	smb_reparse_free(nvl);
180*11963SAfshin.Ardakani@Sun.COM 	return (rc);
181*11963SAfshin.Ardakani@Sun.COM }
182*11963SAfshin.Ardakani@Sun.COM 
183*11963SAfshin.Ardakani@Sun.COM /*
184*11963SAfshin.Ardakani@Sun.COM  * Initializes the given nvpair list.
185*11963SAfshin.Ardakani@Sun.COM  *
186*11963SAfshin.Ardakani@Sun.COM  * This function assumes that the object specified by this path
187*11963SAfshin.Ardakani@Sun.COM  * is a reparse point, so it does not do any verification.
188*11963SAfshin.Ardakani@Sun.COM  *
189*11963SAfshin.Ardakani@Sun.COM  * If specified reparse point does not exist the function
190*11963SAfshin.Ardakani@Sun.COM  * returns successfully with an empty nvpair list.
191*11963SAfshin.Ardakani@Sun.COM  *
192*11963SAfshin.Ardakani@Sun.COM  * If the object exists and readlink is successful then nvpair
193*11963SAfshin.Ardakani@Sun.COM  * list is polulated with the reparse service information, otherwise
194*11963SAfshin.Ardakani@Sun.COM  * an error code is returned.
195*11963SAfshin.Ardakani@Sun.COM  */
196*11963SAfshin.Ardakani@Sun.COM static int
smb_reparse_init(const char * path,nvlist_t ** nvl)197*11963SAfshin.Ardakani@Sun.COM smb_reparse_init(const char *path, nvlist_t **nvl)
198*11963SAfshin.Ardakani@Sun.COM {
199*11963SAfshin.Ardakani@Sun.COM 	char rp_data[MAXREPARSELEN];
200*11963SAfshin.Ardakani@Sun.COM 	int rc;
201*11963SAfshin.Ardakani@Sun.COM 
202*11963SAfshin.Ardakani@Sun.COM 	if ((*nvl = reparse_init()) == NULL)
203*11963SAfshin.Ardakani@Sun.COM 		return (ENOMEM);
204*11963SAfshin.Ardakani@Sun.COM 
205*11963SAfshin.Ardakani@Sun.COM 	bzero(rp_data, MAXREPARSELEN);
206*11963SAfshin.Ardakani@Sun.COM 	if ((rc = readlink(path, rp_data, MAXREPARSELEN)) == -1) {
207*11963SAfshin.Ardakani@Sun.COM 		if (errno == ENOENT)
208*11963SAfshin.Ardakani@Sun.COM 			return (0);
209*11963SAfshin.Ardakani@Sun.COM 
210*11963SAfshin.Ardakani@Sun.COM 		reparse_free(*nvl);
211*11963SAfshin.Ardakani@Sun.COM 		return (errno);
212*11963SAfshin.Ardakani@Sun.COM 	}
213*11963SAfshin.Ardakani@Sun.COM 
214*11963SAfshin.Ardakani@Sun.COM 	if ((rc = reparse_parse(rp_data, *nvl)) != 0) {
215*11963SAfshin.Ardakani@Sun.COM 		reparse_free(*nvl);
216*11963SAfshin.Ardakani@Sun.COM 		return (rc);
217*11963SAfshin.Ardakani@Sun.COM 	}
218*11963SAfshin.Ardakani@Sun.COM 
219*11963SAfshin.Ardakani@Sun.COM 	return (0);
220*11963SAfshin.Ardakani@Sun.COM }
221*11963SAfshin.Ardakani@Sun.COM 
222*11963SAfshin.Ardakani@Sun.COM /*
223*11963SAfshin.Ardakani@Sun.COM  * Frees given nvlist
224*11963SAfshin.Ardakani@Sun.COM  */
225*11963SAfshin.Ardakani@Sun.COM static void
smb_reparse_free(nvlist_t * nvl)226*11963SAfshin.Ardakani@Sun.COM smb_reparse_free(nvlist_t *nvl)
227*11963SAfshin.Ardakani@Sun.COM {
228*11963SAfshin.Ardakani@Sun.COM 	reparse_free(nvl);
229*11963SAfshin.Ardakani@Sun.COM }
230*11963SAfshin.Ardakani@Sun.COM 
231*11963SAfshin.Ardakani@Sun.COM /*
232*11963SAfshin.Ardakani@Sun.COM  * Create a reparse point with given services in the passed
233*11963SAfshin.Ardakani@Sun.COM  * nvlist. If the reparse point already exists, it will be
234*11963SAfshin.Ardakani@Sun.COM  * deleted and a new one with the given data is created.
235*11963SAfshin.Ardakani@Sun.COM  */
236*11963SAfshin.Ardakani@Sun.COM static int
smb_reparse_set(const char * path,nvlist_t * nvl)237*11963SAfshin.Ardakani@Sun.COM smb_reparse_set(const char *path, nvlist_t *nvl)
238*11963SAfshin.Ardakani@Sun.COM {
239*11963SAfshin.Ardakani@Sun.COM 	char *rp_data;
240*11963SAfshin.Ardakani@Sun.COM 	int rc;
241*11963SAfshin.Ardakani@Sun.COM 
242*11963SAfshin.Ardakani@Sun.COM 	if ((rc = reparse_unparse(nvl, &rp_data)) != 0)
243*11963SAfshin.Ardakani@Sun.COM 		return (rc);
244*11963SAfshin.Ardakani@Sun.COM 
245*11963SAfshin.Ardakani@Sun.COM 	rc = reparse_delete(path);
246*11963SAfshin.Ardakani@Sun.COM 	if ((rc != 0) && (rc != ENOENT)) {
247*11963SAfshin.Ardakani@Sun.COM 		free(rp_data);
248*11963SAfshin.Ardakani@Sun.COM 		return (rc);
249*11963SAfshin.Ardakani@Sun.COM 	}
250*11963SAfshin.Ardakani@Sun.COM 
251*11963SAfshin.Ardakani@Sun.COM 	rc = reparse_create(path, rp_data);
252*11963SAfshin.Ardakani@Sun.COM 	free(rp_data);
253*11963SAfshin.Ardakani@Sun.COM 
254*11963SAfshin.Ardakani@Sun.COM 	return (rc);
255*11963SAfshin.Ardakani@Sun.COM }
256