12f172c55SRobert Thurlow /*
22f172c55SRobert Thurlow  * CDDL HEADER START
32f172c55SRobert Thurlow  *
42f172c55SRobert Thurlow  * The contents of this file are subject to the terms of the
52f172c55SRobert Thurlow  * Common Development and Distribution License (the "License").
62f172c55SRobert Thurlow  * You may not use this file except in compliance with the License.
72f172c55SRobert Thurlow  *
82f172c55SRobert Thurlow  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92f172c55SRobert Thurlow  * or http://www.opensolaris.org/os/licensing.
102f172c55SRobert Thurlow  * See the License for the specific language governing permissions
112f172c55SRobert Thurlow  * and limitations under the License.
122f172c55SRobert Thurlow  *
132f172c55SRobert Thurlow  * When distributing Covered Code, include this CDDL HEADER in each
142f172c55SRobert Thurlow  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152f172c55SRobert Thurlow  * If applicable, add the following below this CDDL HEADER, with the
162f172c55SRobert Thurlow  * fields enclosed by brackets "[]" replaced with your own identifying
172f172c55SRobert Thurlow  * information: Portions Copyright [yyyy] [name of copyright owner]
182f172c55SRobert Thurlow  *
192f172c55SRobert Thurlow  * CDDL HEADER END
202f172c55SRobert Thurlow  */
212f172c55SRobert Thurlow 
222f172c55SRobert Thurlow /*
232f172c55SRobert Thurlow  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
242f172c55SRobert Thurlow  * Use is subject to license terms.
252f172c55SRobert Thurlow  */
262f172c55SRobert Thurlow 
272f172c55SRobert Thurlow #include <stdio.h>
282f172c55SRobert Thurlow #include <unistd.h>
292f172c55SRobert Thurlow #include <strings.h>
302f172c55SRobert Thurlow #include <string.h>
312f172c55SRobert Thurlow #include <sys/types.h>
322f172c55SRobert Thurlow #include <sys/stat.h>
332f172c55SRobert Thurlow #include <sys/errno.h>
342f172c55SRobert Thurlow #include <limits.h>
352f172c55SRobert Thurlow #include <libnvpair.h>
362f172c55SRobert Thurlow #include <dlfcn.h>
372f172c55SRobert Thurlow #include <link.h>
382f172c55SRobert Thurlow #include <rp_plugin.h>
392f172c55SRobert Thurlow #include <fcntl.h>
402f172c55SRobert Thurlow #include <uuid/uuid.h>
412f172c55SRobert Thurlow #include <rpc/types.h>
422f172c55SRobert Thurlow #include <rpc/xdr.h>
432f172c55SRobert Thurlow #include <rpc/auth.h>
442f172c55SRobert Thurlow #include <rpc/clnt.h>
452f172c55SRobert Thurlow #include <rpc/rpc_msg.h>
462f172c55SRobert Thurlow #include <sys/param.h>
472f172c55SRobert Thurlow #include <nfs/nfs4.h>
482f172c55SRobert Thurlow #include <rpcsvc/nfs4_prot.h>
492f172c55SRobert Thurlow #include "ref_subr.h"
502f172c55SRobert Thurlow 
512f172c55SRobert Thurlow extern int errno;
522f172c55SRobert Thurlow 
532f172c55SRobert Thurlow #define	SERVICE_TYPE	"nfs-basic"
542f172c55SRobert Thurlow 
552f172c55SRobert Thurlow char *nfs_basic_service_type(void);
562f172c55SRobert Thurlow boolean_t nfs_basic_supports_svc(const char *);
572f172c55SRobert Thurlow int nfs_basic_deref(const char *, const char *, char *, size_t *);
582f172c55SRobert Thurlow int nfs_basic_form(const char *, const char *, char *, size_t *);
592f172c55SRobert Thurlow 
602f172c55SRobert Thurlow struct rp_plugin_ops rp_plugin_ops = {
612f172c55SRobert Thurlow 	RP_PLUGIN_V1,
622f172c55SRobert Thurlow 	NULL,			/* rpo_init */
632f172c55SRobert Thurlow 	NULL,			/* rpo_fini */
642f172c55SRobert Thurlow 	nfs_basic_service_type,
652f172c55SRobert Thurlow 	nfs_basic_supports_svc,
662f172c55SRobert Thurlow 	nfs_basic_form,
672f172c55SRobert Thurlow 	nfs_basic_deref
682f172c55SRobert Thurlow };
692f172c55SRobert Thurlow 
702f172c55SRobert Thurlow /*
712f172c55SRobert Thurlow  * What service type does this module support?
722f172c55SRobert Thurlow  */
732f172c55SRobert Thurlow char *
nfs_basic_service_type()742f172c55SRobert Thurlow nfs_basic_service_type()
752f172c55SRobert Thurlow {
762f172c55SRobert Thurlow 	return (SERVICE_TYPE);
772f172c55SRobert Thurlow }
782f172c55SRobert Thurlow 
792f172c55SRobert Thurlow /*
802f172c55SRobert Thurlow  * Does this module support a particular service type?
812f172c55SRobert Thurlow  */
822f172c55SRobert Thurlow boolean_t
nfs_basic_supports_svc(const char * svc_type)832f172c55SRobert Thurlow nfs_basic_supports_svc(const char *svc_type)
842f172c55SRobert Thurlow {
852f172c55SRobert Thurlow 	if (!svc_type)
862f172c55SRobert Thurlow 		return (0);
872f172c55SRobert Thurlow 	return (!strncasecmp(svc_type, SERVICE_TYPE, strlen(SERVICE_TYPE)));
882f172c55SRobert Thurlow }
892f172c55SRobert Thurlow 
902f172c55SRobert Thurlow /*
912f172c55SRobert Thurlow  * Take a string with a set of locations like this:
922f172c55SRobert Thurlow  *   host1:/path1 host2:/path2 host3:/path3
932f172c55SRobert Thurlow  * and convert it to an fs_locations4 for the deref routine.
942f172c55SRobert Thurlow  */
952f172c55SRobert Thurlow static fs_locations4 *
get_fs_locations(char * buf)962f172c55SRobert Thurlow get_fs_locations(char *buf)
972f172c55SRobert Thurlow {
982f172c55SRobert Thurlow 	fs_locations4 *result = NULL;
992f172c55SRobert Thurlow 	fs_location4 *fsl_array;
100*24571565SRobert Thurlow 	int i, gothost;
101*24571565SRobert Thurlow 	int fsl_count = 0, escape = 0, delimiter = 0;
1022f172c55SRobert Thurlow 	int len;
1032f172c55SRobert Thurlow 	char *p, *sp, *dp, buf2[SYMLINK_MAX];
1042f172c55SRobert Thurlow 
1052f172c55SRobert Thurlow 	if (buf == NULL)
1062f172c55SRobert Thurlow 		return (NULL);
1072f172c55SRobert Thurlow #ifdef DEBUG
1082f172c55SRobert Thurlow 	printf("get_fs_locations: input %s\n", buf);
1092f172c55SRobert Thurlow #endif
1102f172c55SRobert Thurlow 	/*
1112f172c55SRobert Thurlow 	 * Count fs_location entries by counting spaces.
1122f172c55SRobert Thurlow 	 * Remember that escaped spaces ("\ ") may exist.
1132f172c55SRobert Thurlow 	 * We mark the location boundaries with null bytes.
1142f172c55SRobert Thurlow 	 * Variable use:
1152f172c55SRobert Thurlow 	 *   escape -   set if we have found a backspace,
1162f172c55SRobert Thurlow 	 *		part of either "\ " or "\\"
1172f172c55SRobert Thurlow 	 *   delimiter - set if we have found a space and
1182f172c55SRobert Thurlow 	 *		 used to skip multiple spaces
1192f172c55SRobert Thurlow 	 */
1202f172c55SRobert Thurlow 	for (sp = buf; sp && *sp; sp++) {
1212f172c55SRobert Thurlow 		if (*sp == '\\') {
1222f172c55SRobert Thurlow 			escape = 1;
1232f172c55SRobert Thurlow 			delimiter = 0;
1242f172c55SRobert Thurlow 			continue;
1252f172c55SRobert Thurlow 		}
1262f172c55SRobert Thurlow 		if (*sp == ' ') {
1272f172c55SRobert Thurlow 			if (delimiter == 1)
1282f172c55SRobert Thurlow 				continue;
1292f172c55SRobert Thurlow 			if (escape == 0) {
1302f172c55SRobert Thurlow 				delimiter = 1;
1312f172c55SRobert Thurlow 				fsl_count++;
1322f172c55SRobert Thurlow 				*sp = '\0';
1332f172c55SRobert Thurlow 			} else
1342f172c55SRobert Thurlow 				escape = 0;
1352f172c55SRobert Thurlow 		} else
1362f172c55SRobert Thurlow 			delimiter = 0;
1372f172c55SRobert Thurlow 	}
1382f172c55SRobert Thurlow 	len = sp - buf;
1392f172c55SRobert Thurlow 	sp--;
1402f172c55SRobert Thurlow 	if (escape == 0 && *sp != '\0')
1412f172c55SRobert Thurlow 		fsl_count++;
1422f172c55SRobert Thurlow #ifdef DEBUG
1432f172c55SRobert Thurlow 	printf("get_fs_locations: fsl_count %d\n", fsl_count);
1442f172c55SRobert Thurlow #endif
1452f172c55SRobert Thurlow 	if (fsl_count == 0)
1462f172c55SRobert Thurlow 		goto out;
1472f172c55SRobert Thurlow 
1482f172c55SRobert Thurlow 	/* Alloc space for everything */
149*24571565SRobert Thurlow 	result = calloc(1, sizeof (fs_locations4));
1502f172c55SRobert Thurlow 	if (result == NULL)
1512f172c55SRobert Thurlow 		goto out;
152*24571565SRobert Thurlow 	fsl_array = calloc(fsl_count, sizeof (fs_location4));
1532f172c55SRobert Thurlow 	if (fsl_array == NULL) {
1542f172c55SRobert Thurlow 		free(result);
1552f172c55SRobert Thurlow 		result = NULL;
1562f172c55SRobert Thurlow 		goto out;
1572f172c55SRobert Thurlow 	}
1582f172c55SRobert Thurlow 	result->locations.locations_len = fsl_count;
1592f172c55SRobert Thurlow 	result->locations.locations_val = fsl_array;
1602f172c55SRobert Thurlow 	result->fs_root.pathname4_len = 0;
1612f172c55SRobert Thurlow 	result->fs_root.pathname4_val = NULL;
1622f172c55SRobert Thurlow 
1632f172c55SRobert Thurlow 	/*
1642f172c55SRobert Thurlow 	 * Copy input, removing escapes from host:/path/to/my\ files
1652f172c55SRobert Thurlow 	 */
1662f172c55SRobert Thurlow 	sp = buf;
1672f172c55SRobert Thurlow 	dp = buf2;
1682f172c55SRobert Thurlow 	bzero(buf2, sizeof (buf2));
1692f172c55SRobert Thurlow 
170*24571565SRobert Thurlow 	i = gothost = 0;
1712f172c55SRobert Thurlow 	while ((sp && *sp && (sp - buf < len)) || gothost) {
1722f172c55SRobert Thurlow 
1732f172c55SRobert Thurlow 		if (!gothost) {
1742f172c55SRobert Thurlow 			/* Drop leading spaces */
1752f172c55SRobert Thurlow 			if (*sp == ' ') {
1762f172c55SRobert Thurlow 				sp++;
1772f172c55SRobert Thurlow 				continue;
1782f172c55SRobert Thurlow 			}
1792f172c55SRobert Thurlow 
1802f172c55SRobert Thurlow 			/* Look for the rightmost colon for host */
1812f172c55SRobert Thurlow 			p = strrchr(sp, ':');
1822f172c55SRobert Thurlow 			if (!p) {
1832f172c55SRobert Thurlow #ifdef DEBUG
1842f172c55SRobert Thurlow 				printf("get_fs_locations: skipping %s\n", sp);
1852f172c55SRobert Thurlow #endif
186*24571565SRobert Thurlow 				fsl_count--;
1872f172c55SRobert Thurlow 				sp += strlen(sp) + 1;
1882f172c55SRobert Thurlow 			} else {
1892f172c55SRobert Thurlow 				bcopy(sp, dp, p - sp);
1902f172c55SRobert Thurlow 				sp = p + 1;
1912f172c55SRobert Thurlow #ifdef DEBUG
1922f172c55SRobert Thurlow 				printf("get_fs_locations: host %s\n", buf2);
1932f172c55SRobert Thurlow #endif
1942f172c55SRobert Thurlow 				fsl_array[i].server.server_len = 1;
1952f172c55SRobert Thurlow 				fsl_array[i].server.server_val =
1962f172c55SRobert Thurlow 				    malloc(sizeof (utf8string));
1972f172c55SRobert Thurlow 				if (fsl_array[i].server.server_val == NULL) {
1982f172c55SRobert Thurlow 					int j;
1992f172c55SRobert Thurlow 
2002f172c55SRobert Thurlow 					free(result);
2012f172c55SRobert Thurlow 					result = NULL;
2022f172c55SRobert Thurlow 					for (j = 0; j < i; j++)
2032f172c55SRobert Thurlow 						free(fsl_array[j].
2042f172c55SRobert Thurlow 						    server.server_val);
2052f172c55SRobert Thurlow 					free(fsl_array);
2062f172c55SRobert Thurlow 					goto out;
2072f172c55SRobert Thurlow 				}
2082f172c55SRobert Thurlow 				str_to_utf8(buf2,
2092f172c55SRobert Thurlow 				    fsl_array[i].server.server_val);
2102f172c55SRobert Thurlow 				gothost = 1;
2112f172c55SRobert Thurlow 				dp = buf2;
2122f172c55SRobert Thurlow 				bzero(buf2, sizeof (buf2));
2132f172c55SRobert Thurlow 			}
2142f172c55SRobert Thurlow 			continue;
2152f172c55SRobert Thurlow 		}
2162f172c55SRobert Thurlow 
2172f172c55SRobert Thurlow 		/* End of string should mean a pathname */
2182f172c55SRobert Thurlow 		if (*sp == '\0' && gothost) {
2192f172c55SRobert Thurlow #ifdef DEBUG
2202f172c55SRobert Thurlow 			printf("get_fs_locations: path %s\n", buf2);
2212f172c55SRobert Thurlow #endif
2222f172c55SRobert Thurlow 			(void) make_pathname4(buf2, &fsl_array[i].rootpath);
2232f172c55SRobert Thurlow 			i++;
2242f172c55SRobert Thurlow 			gothost = 0;
2252f172c55SRobert Thurlow 			dp = buf2;
2262f172c55SRobert Thurlow 			bzero(buf2, sizeof (buf2));
2272f172c55SRobert Thurlow 			if (sp - buf < len)
2282f172c55SRobert Thurlow 				sp++;
2292f172c55SRobert Thurlow 			continue;
2302f172c55SRobert Thurlow 		}
2312f172c55SRobert Thurlow 
2322f172c55SRobert Thurlow 		/* Skip a single escape character */
2332f172c55SRobert Thurlow 		if (*sp == '\\')
2342f172c55SRobert Thurlow 			sp++;
2352f172c55SRobert Thurlow 
2362f172c55SRobert Thurlow 		/* Plain char, just copy it */
2372f172c55SRobert Thurlow 		*dp++ = *sp++;
2382f172c55SRobert Thurlow 	}
2392f172c55SRobert Thurlow 
240*24571565SRobert Thurlow 	/*
241*24571565SRobert Thurlow 	 * If we're still expecting a path name, we don't have a
242*24571565SRobert Thurlow 	 * server:/path pair and should discard the server and
243*24571565SRobert Thurlow 	 * note that we got fewer locations than expected.
244*24571565SRobert Thurlow 	 */
245*24571565SRobert Thurlow 	if (gothost) {
246*24571565SRobert Thurlow 		fsl_count--;
247*24571565SRobert Thurlow 		free(fsl_array[i].server.server_val);
248*24571565SRobert Thurlow 		fsl_array[i].server.server_val = NULL;
249*24571565SRobert Thurlow 		fsl_array[i].server.server_len = 0;
250*24571565SRobert Thurlow 	}
251*24571565SRobert Thurlow 
252*24571565SRobert Thurlow 	/*
253*24571565SRobert Thurlow 	 * If we have zero entries, we never got a whole server:/path
254*24571565SRobert Thurlow 	 * pair, and so cannot have anything else allocated.
255*24571565SRobert Thurlow 	 */
256*24571565SRobert Thurlow 	if (fsl_count <= 0) {
257*24571565SRobert Thurlow 		free(result);
258*24571565SRobert Thurlow 		free(fsl_array);
259*24571565SRobert Thurlow 		return (NULL);
260*24571565SRobert Thurlow 	}
261*24571565SRobert Thurlow 
262*24571565SRobert Thurlow 	/*
263*24571565SRobert Thurlow 	 * Make sure we reflect the right number of locations.
264*24571565SRobert Thurlow 	 */
265*24571565SRobert Thurlow 	if (fsl_count < result->locations.locations_len)
266*24571565SRobert Thurlow 		result->locations.locations_len = fsl_count;
267*24571565SRobert Thurlow 
2682f172c55SRobert Thurlow out:
2692f172c55SRobert Thurlow 	return (result);
2702f172c55SRobert Thurlow }
2712f172c55SRobert Thurlow 
2722f172c55SRobert Thurlow /*
2732f172c55SRobert Thurlow  * Deref function for nfs-basic service type returns an fs_locations4.
2742f172c55SRobert Thurlow  */
2752f172c55SRobert Thurlow int
nfs_basic_deref(const char * svc_type,const char * svc_data,char * buf,size_t * bufsz)2762f172c55SRobert Thurlow nfs_basic_deref(const char *svc_type, const char *svc_data, char *buf,
2772f172c55SRobert Thurlow     size_t *bufsz)
2782f172c55SRobert Thurlow {
2792f172c55SRobert Thurlow 	int slen, err;
2802f172c55SRobert Thurlow 	fs_locations4 *fsl;
2812f172c55SRobert Thurlow 	XDR xdr;
2822f172c55SRobert Thurlow 
2832f172c55SRobert Thurlow 	if ((!svc_type) || (!svc_data) || (!buf) || (!bufsz) || (*bufsz == 0))
2842f172c55SRobert Thurlow 		return (EINVAL);
2852f172c55SRobert Thurlow 
2862f172c55SRobert Thurlow 	if (strcasecmp(svc_type, SERVICE_TYPE))
2872f172c55SRobert Thurlow 		return (ENOTSUP);
2882f172c55SRobert Thurlow 
2892f172c55SRobert Thurlow 	fsl = get_fs_locations((char *)svc_data);
2902f172c55SRobert Thurlow 	if (fsl == NULL)
2912f172c55SRobert Thurlow 		return (ENOENT);
2922f172c55SRobert Thurlow #ifdef DEBUG
2932f172c55SRobert Thurlow 	printf("nfs_basic_deref: past get_fs_locations()\n");
2942f172c55SRobert Thurlow #endif
2952f172c55SRobert Thurlow 	slen = xdr_sizeof(xdr_fs_locations4, (void *)fsl);
2962f172c55SRobert Thurlow 	if (slen > *bufsz) {
2972f172c55SRobert Thurlow 		*bufsz = slen;
2982f172c55SRobert Thurlow 		xdr_free(xdr_fs_locations4, (char *)fsl);
2992f172c55SRobert Thurlow 		return (EOVERFLOW);
3002f172c55SRobert Thurlow 	}
3012f172c55SRobert Thurlow #ifdef DEBUG
3022f172c55SRobert Thurlow 	printf("nfs_basic_deref: past buffer check\n");
3032f172c55SRobert Thurlow 	print_referral_summary(fsl);
3042f172c55SRobert Thurlow #endif
3052f172c55SRobert Thurlow 	xdrmem_create(&xdr, buf, *bufsz, XDR_ENCODE);
3062f172c55SRobert Thurlow 	err = xdr_fs_locations4(&xdr, fsl);
3072f172c55SRobert Thurlow 	XDR_DESTROY(&xdr);
3082f172c55SRobert Thurlow 	xdr_free(xdr_fs_locations4, (char *)fsl);
3092f172c55SRobert Thurlow 	if (err != TRUE)
3102f172c55SRobert Thurlow 		return (EINVAL);
3112f172c55SRobert Thurlow 	*bufsz = slen;
3122f172c55SRobert Thurlow #ifdef DEBUG
3132f172c55SRobert Thurlow 	printf("nfs_basic_deref: past xdr_fs_locations4() and done\n");
3142f172c55SRobert Thurlow #endif
3152f172c55SRobert Thurlow 	return (0);
3162f172c55SRobert Thurlow }
3172f172c55SRobert Thurlow 
3182f172c55SRobert Thurlow /*
3192f172c55SRobert Thurlow  * Form function for nfs-basic service type.
3202f172c55SRobert Thurlow  */
3212f172c55SRobert Thurlow int
nfs_basic_form(const char * svc_type,const char * svc_data,char * buf,size_t * bufsz)3222f172c55SRobert Thurlow nfs_basic_form(const char *svc_type, const char *svc_data, char *buf,
3232f172c55SRobert Thurlow     size_t *bufsz)
3242f172c55SRobert Thurlow {
3252f172c55SRobert Thurlow 	int slen;
3262f172c55SRobert Thurlow 
3272f172c55SRobert Thurlow 	if ((!svc_type) || (!svc_data) || (!buf) || (*bufsz == 0))
3282f172c55SRobert Thurlow 		return (EINVAL);
3292f172c55SRobert Thurlow 
3302f172c55SRobert Thurlow 	if (strcmp(svc_type, SERVICE_TYPE))
3312f172c55SRobert Thurlow 		return (ENOTSUP);
3322f172c55SRobert Thurlow 
3332f172c55SRobert Thurlow 	slen = strlen(svc_data) + 1;
3342f172c55SRobert Thurlow 	if (slen > *bufsz) {
3352f172c55SRobert Thurlow 		*bufsz = slen;
3362f172c55SRobert Thurlow 		return (EOVERFLOW);
3372f172c55SRobert Thurlow 	}
3382f172c55SRobert Thurlow 	*bufsz = slen;
3392f172c55SRobert Thurlow 	strncpy(buf, svc_data, slen);
3402f172c55SRobert Thurlow 	return (0);
3412f172c55SRobert Thurlow }
342