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