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