xref: /illumos-gate/usr/src/cmd/fs.d/nfs/rp_basic/libnfs_basic.c (revision 27eb8000280e75ee2bcbb30b0622802c54a3dd04)
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 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <strings.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <sys/errno.h>
34 #include <limits.h>
35 #include <libnvpair.h>
36 #include <dlfcn.h>
37 #include <link.h>
38 #include <rp_plugin.h>
39 #include <fcntl.h>
40 #include <uuid/uuid.h>
41 #include <rpc/types.h>
42 #include <rpc/xdr.h>
43 #include <rpc/auth.h>
44 #include <rpc/clnt.h>
45 #include <rpc/rpc_msg.h>
46 #include <sys/param.h>
47 #include <nfs/nfs4.h>
48 #include <rpcsvc/nfs4_prot.h>
49 #include "ref_subr.h"
50 
51 extern int errno;
52 
53 #define	SERVICE_TYPE	"nfs-basic"
54 
55 char *nfs_basic_service_type(void);
56 boolean_t nfs_basic_supports_svc(const char *);
57 int nfs_basic_deref(const char *, const char *, char *, size_t *);
58 int nfs_basic_form(const char *, const char *, char *, size_t *);
59 
60 struct rp_plugin_ops rp_plugin_ops = {
61 	RP_PLUGIN_V1,
62 	NULL,			/* rpo_init */
63 	NULL,			/* rpo_fini */
64 	nfs_basic_service_type,
65 	nfs_basic_supports_svc,
66 	nfs_basic_form,
67 	nfs_basic_deref
68 };
69 
70 /*
71  * What service type does this module support?
72  */
73 char *
74 nfs_basic_service_type()
75 {
76 	return (SERVICE_TYPE);
77 }
78 
79 /*
80  * Does this module support a particular service type?
81  */
82 boolean_t
83 nfs_basic_supports_svc(const char *svc_type)
84 {
85 	if (!svc_type)
86 		return (0);
87 	return (!strncasecmp(svc_type, SERVICE_TYPE, strlen(SERVICE_TYPE)));
88 }
89 
90 /*
91  * Take a string with a set of locations like this:
92  *   host1:/path1 host2:/path2 host3:/path3
93  * and convert it to an fs_locations4 for the deref routine.
94  */
95 static fs_locations4 *
96 get_fs_locations(char *buf)
97 {
98 	fs_locations4 *result = NULL;
99 	fs_location4 *fsl_array;
100 	int i = 0, fsl_count = 0, gothost = 0, escape = 0, delimiter = 0;
101 	int len;
102 	char *p, *sp, *dp, buf2[SYMLINK_MAX];
103 
104 	if (buf == NULL)
105 		return (NULL);
106 #ifdef DEBUG
107 	printf("get_fs_locations: input %s\n", buf);
108 #endif
109 	/*
110 	 * Count fs_location entries by counting spaces.
111 	 * Remember that escaped spaces ("\ ") may exist.
112 	 * We mark the location boundaries with null bytes.
113 	 * Variable use:
114 	 *   escape -   set if we have found a backspace,
115 	 *		part of either "\ " or "\\"
116 	 *   delimiter - set if we have found a space and
117 	 *		 used to skip multiple spaces
118 	 */
119 	for (sp = buf; sp && *sp; sp++) {
120 		if (*sp == '\\') {
121 			escape = 1;
122 			delimiter = 0;
123 			continue;
124 		}
125 		if (*sp == ' ') {
126 			if (delimiter == 1)
127 				continue;
128 			if (escape == 0) {
129 				delimiter = 1;
130 				fsl_count++;
131 				*sp = '\0';
132 			} else
133 				escape = 0;
134 		} else
135 			delimiter = 0;
136 	}
137 	len = sp - buf;
138 	sp--;
139 	if (escape == 0 && *sp != '\0')
140 		fsl_count++;
141 #ifdef DEBUG
142 	printf("get_fs_locations: fsl_count %d\n", fsl_count);
143 #endif
144 	if (fsl_count == 0)
145 		goto out;
146 
147 	/* Alloc space for everything */
148 	result = malloc(sizeof (fs_locations4));
149 	if (result == NULL)
150 		goto out;
151 	fsl_array = malloc(fsl_count * sizeof (fs_location4));
152 	if (fsl_array == NULL) {
153 		free(result);
154 		result = NULL;
155 		goto out;
156 	}
157 	result->locations.locations_len = fsl_count;
158 	result->locations.locations_val = fsl_array;
159 	result->fs_root.pathname4_len = 0;
160 	result->fs_root.pathname4_val = NULL;
161 
162 	/*
163 	 * Copy input, removing escapes from host:/path/to/my\ files
164 	 */
165 	sp = buf;
166 	dp = buf2;
167 	bzero(buf2, sizeof (buf2));
168 
169 	while ((sp && *sp && (sp - buf < len)) || gothost) {
170 
171 		if (!gothost) {
172 			/* Drop leading spaces */
173 			if (*sp == ' ') {
174 				sp++;
175 				continue;
176 			}
177 
178 			/* Look for the rightmost colon for host */
179 			p = strrchr(sp, ':');
180 			if (!p) {
181 #ifdef DEBUG
182 				printf("get_fs_locations: skipping %s\n", sp);
183 #endif
184 				sp += strlen(sp) + 1;
185 			} else {
186 				bcopy(sp, dp, p - sp);
187 				sp = p + 1;
188 #ifdef DEBUG
189 				printf("get_fs_locations: host %s\n", buf2);
190 #endif
191 				fsl_array[i].server.server_len = 1;
192 				fsl_array[i].server.server_val =
193 				    malloc(sizeof (utf8string));
194 				if (fsl_array[i].server.server_val == NULL) {
195 					int j;
196 
197 					free(result);
198 					result = NULL;
199 					for (j = 0; j < i; j++)
200 						free(fsl_array[j].
201 						    server.server_val);
202 					free(fsl_array);
203 					goto out;
204 				}
205 				str_to_utf8(buf2,
206 				    fsl_array[i].server.server_val);
207 				gothost = 1;
208 				dp = buf2;
209 				bzero(buf2, sizeof (buf2));
210 			}
211 			continue;
212 		}
213 
214 		/* End of string should mean a pathname */
215 		if (*sp == '\0' && gothost) {
216 #ifdef DEBUG
217 			printf("get_fs_locations: path %s\n", buf2);
218 #endif
219 			(void) make_pathname4(buf2, &fsl_array[i].rootpath);
220 			i++;
221 			gothost = 0;
222 			dp = buf2;
223 			bzero(buf2, sizeof (buf2));
224 			if (sp - buf < len)
225 				sp++;
226 			continue;
227 		}
228 
229 		/* Skip a single escape character */
230 		if (*sp == '\\')
231 			sp++;
232 
233 		/* Plain char, just copy it */
234 		*dp++ = *sp++;
235 	}
236 
237 out:
238 	return (result);
239 }
240 
241 /*
242  * Deref function for nfs-basic service type returns an fs_locations4.
243  */
244 int
245 nfs_basic_deref(const char *svc_type, const char *svc_data, char *buf,
246     size_t *bufsz)
247 {
248 	int slen, err;
249 	fs_locations4 *fsl;
250 	XDR xdr;
251 
252 	if ((!svc_type) || (!svc_data) || (!buf) || (!bufsz) || (*bufsz == 0))
253 		return (EINVAL);
254 
255 	if (strcasecmp(svc_type, SERVICE_TYPE))
256 		return (ENOTSUP);
257 
258 	fsl = get_fs_locations((char *)svc_data);
259 	if (fsl == NULL)
260 		return (ENOENT);
261 #ifdef DEBUG
262 	printf("nfs_basic_deref: past get_fs_locations()\n");
263 #endif
264 	slen = xdr_sizeof(xdr_fs_locations4, (void *)fsl);
265 	if (slen > *bufsz) {
266 		*bufsz = slen;
267 		xdr_free(xdr_fs_locations4, (char *)fsl);
268 		return (EOVERFLOW);
269 	}
270 #ifdef DEBUG
271 	printf("nfs_basic_deref: past buffer check\n");
272 	print_referral_summary(fsl);
273 #endif
274 	xdrmem_create(&xdr, buf, *bufsz, XDR_ENCODE);
275 	err = xdr_fs_locations4(&xdr, fsl);
276 	XDR_DESTROY(&xdr);
277 	xdr_free(xdr_fs_locations4, (char *)fsl);
278 	if (err != TRUE)
279 		return (EINVAL);
280 	*bufsz = slen;
281 #ifdef DEBUG
282 	printf("nfs_basic_deref: past xdr_fs_locations4() and done\n");
283 #endif
284 	return (0);
285 }
286 
287 /*
288  * Form function for nfs-basic service type.
289  */
290 int
291 nfs_basic_form(const char *svc_type, const char *svc_data, char *buf,
292     size_t *bufsz)
293 {
294 	int slen;
295 
296 	if ((!svc_type) || (!svc_data) || (!buf) || (*bufsz == 0))
297 		return (EINVAL);
298 
299 	if (strcmp(svc_type, SERVICE_TYPE))
300 		return (ENOTSUP);
301 
302 	slen = strlen(svc_data) + 1;
303 	if (slen > *bufsz) {
304 		*bufsz = slen;
305 		return (EOVERFLOW);
306 	}
307 	*bufsz = slen;
308 	strncpy(buf, svc_data, slen);
309 	return (0);
310 }
311