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 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include "nfs4_prot.h"
28 #include "nfstcl4.h"
29 #include "tcl.h"
30
31
32 /*
33 * utility functions used by nfstcl client tool.
34 */
35
36 /*
37 * Return 1 if bitno is set in the bitmap
38 */
39 int
40 getbit(bitmap4 *bmp, int bitno) {
41 int inx = bitno / 32;
42 int off = bitno % 32;
43
44 if ((bmp->bitmap4_len == 0) ||
45 (inx > (bmp->bitmap4_len - 1)))
46 return (0);
47
48 return ((bmp->bitmap4_val[inx] & (1 << off)) != 0);
49 }
50
51 /*
52 * Set a specific bit in the bitmap
53 */
54 void
55 setbit(bitmap4 *bmp, int bitno) {
56 int inx = bitno / 32;
57 int off = bitno % 32;
58
59 if ((bmp->bitmap4_len == 0) ||
60 (inx > (bmp->bitmap4_len - 1)))
61 bmp->bitmap4_len = inx + 1;
62
63 bmp->bitmap4_val[inx] |= 1 << off;
64 }
65
66 /*
67 * Convert a binary string into a hexadecimal string
68 */
69 char *
70 bin2hex(char *p, unsigned len)
71 /* char *p; binary object to convert to a hex string */
72 /* unsigned len; size of the binary object in bytes */
73 {
74 int i, j;
75 static char hbuff[2049];
76 static char hexstr[] = "0123456789ABCDEF";
77 char toobig = 0;
78 static char toobigstr[] = "<Too Big>";
79
80 /* check for buffer overflow and truncate to fit */
81 if (len * 2 > sizeof (hbuff) - 1) {
82 toobig++;
83 len = (sizeof (hbuff) - sizeof (toobigstr) - 1)/ 2;
84 }
85
86 j = 0;
87 /* convert to ascii */
88 for (i = 0; i < len; i++) {
89 hbuff[j++] = hexstr[p[i] >> 4 & 0x0f];
90 hbuff[j++] = hexstr[p[i] & 0x0f];
91 }
92 hbuff[j] = '\0';
93
94 if (toobig) {
95 hbuff[sizeof (hbuff) - strlen(toobigstr) - 1] = '\0';
96 strcat(hbuff, toobigstr);
97 }
98
99 return (hbuff);
100 }
101
102 /*
103 * Convert a hexadecimal string into a binary string
104 */
105 char *
106 hex2bin(char *p, unsigned len)
107 /* char *p; hex string to convert to a binary object */
108 /* unsigned len; size in bytes for result (binary object) */
109 {
110 int i;
111 int c1, c2;
112 static char hbuff[1025]; /* XXX Max string is 1024 chars */
113 char *op = hbuff;
114 char *p2 = NULL;
115 unsigned cur_len;
116 static char inx[256];
117 static int toobig = 0;
118 char hexUpper[] = "0123456789ABCDEF";
119 char hexLower[] = "0123456789abcdef";
120
121 /* Build a mapping table */
122 for (i = 0; i < 16; i++) {
123 inx[hexUpper[i]] = i;
124 inx[hexLower[i]] = i;
125 }
126
127 /* number of hex characters needed */
128 len *= 2;
129
130 /* check for buffer overflow and truncate to fit */
131 cur_len = strlen(p);
132 if (cur_len > (sizeof (hbuff) - 1)*2) {
133 toobig++;
134 cur_len = (sizeof (hbuff) - 1)*2;
135 }
136 if (len > (sizeof (hbuff) - 1)*2) {
137 toobig++;
138 len = (sizeof (hbuff) - 1)*2;
139 }
140
141 /* if needed pad with leading zeros */
142 if (cur_len < len) {
143 unsigned j = len - cur_len;
144
145 p2 = malloc(len + 1);
146 if (p2 == NULL) {
147 perror("NOMEM");
148 exit(1);
149 }
150 memset(p2, '0', j);
151 p2[j] = '\0';
152 strcat(p2, p);
153 p = p2;
154 }
155
156 /* Now use the mapping table to map the chars to binary */
157 while (*p) {
158 if (strlen(p) == 1)
159 c1 = 0;
160 else
161 c1 = inx[*p++] & 0x0f;
162 c2 = inx[*p++] & 0x0f;
163 *op++ = c1 << 4 | c2;
164 }
165
166 if (p2 != NULL)
167 free(p2);
168
169 return (hbuff);
170 }
171
172
173 /*
174 * Convert an ASCII string to a UTF8 string.
175 * XXX Currently this routine just copies the
176 * string into a utf8string structure.
177 */
178 utf8string *
179 str2utf8(char *str)
180 {
181 utf8string *tmp;
182
183 tmp = malloc(sizeof (utf8string));
184
185 tmp->utf8string_val = (char *)strdup(str);
186 tmp->utf8string_len = strlen(str);
187
188 return (tmp);
189 }
190
191 /*
192 * Convert a UTF8 string to a C string
193 * XXX Currently this routine just copies the
194 * string from a utf8string structure.
195 */
196 char *
197 utf82str(utf8string u)
198 {
199 char *str = malloc(u.utf8string_len + 1);
200
201 (void) memcpy(str, u.utf8string_val, u.utf8string_len);
202 *(str + u.utf8string_len) = '\0';
203
204 return (str);
205 }
206
207 /*
208 * Given the string list of components of the pathname,
209 * convert them to pathname4 structure.
210 */
211 int
212 str2pathname(Tcl_Interp *interp, char *strs, pathname4 *pn)
213 {
214 int lc;
215 char **lv;
216 char buf[80];
217 component4 *tmp;
218 int i;
219
220 /*
221 * Convert the "strs" (in the form of components,
222 * e.g. {export v4 file}) argument into an array
223 * of strings.
224 */
225 if (Tcl_SplitList(interp, strs, &lc, (CONST84 char ***)&lv) != TCL_OK) {
226 sprintf(buf, "str2pathname error, can't split {%s}", strs);
227 interp->result = buf;
228 return (TCL_ERROR);
229 }
230
231 tmp = calloc(lc, sizeof (component4 *));
232
233 for (i = 0; i < lc; i++) {
234 tmp[i] = *str2utf8(lv[i]);
235 }
236
237 pn->pathname4_len = lc;
238 pn->pathname4_val = tmp;
239 free((char *)lv);
240
241 return (TCL_OK);
242 }
243
244 char *
245 errstr(nfsstat4 status)
246 {
247 switch (status) {
248 case NFS4_OK: return "OK";
249 case NFS4ERR_PERM: return "PERM";
250 case NFS4ERR_NOENT: return "NOENT";
251 case NFS4ERR_IO: return "IO";
252 case NFS4ERR_NXIO: return "NXIO";
253 case NFS4ERR_ACCESS: return "ACCESS";
254 case NFS4ERR_EXIST: return "EXIST";
255 case NFS4ERR_XDEV: return "XDEV";
256 /* error slot reserved for error 19 */
257 case NFS4ERR_NOTDIR: return "NOTDIR";
258 case NFS4ERR_ISDIR: return "ISDIR";
259 case NFS4ERR_INVAL: return "INVAL";
260 case NFS4ERR_FBIG: return "FBIG";
261 case NFS4ERR_NOSPC: return "NOSPC";
262 case NFS4ERR_ROFS: return "ROFS";
263 case NFS4ERR_MLINK: return "MLINK";
264 case NFS4ERR_NAMETOOLONG: return "NAMETOOLONG";
265 case NFS4ERR_NOTEMPTY: return "NOTEMPTY";
266 case NFS4ERR_DQUOT: return "DQUOT";
267 case NFS4ERR_STALE: return "STALE";
268 case NFS4ERR_BADHANDLE: return "BADHANDLE";
269 case NFS4ERR_BAD_COOKIE: return "BAD_COOKIE";
270 case NFS4ERR_NOTSUPP: return "NOTSUPP";
271 case NFS4ERR_TOOSMALL: return "TOOSMALL";
272 case NFS4ERR_SERVERFAULT: return "SERVERFAULT";
273 case NFS4ERR_BADTYPE: return "BADTYPE";
274 case NFS4ERR_DELAY: return "DELAY";
275 case NFS4ERR_SAME: return "SAME";
276 case NFS4ERR_DENIED: return "DENIED";
277 case NFS4ERR_EXPIRED: return "EXPIRED";
278 case NFS4ERR_LOCKED: return "LOCKED";
279 case NFS4ERR_GRACE: return "GRACE";
280 case NFS4ERR_FHEXPIRED: return "FHEXPIRED";
281 case NFS4ERR_SHARE_DENIED: return "SHARE_DENIED";
282 case NFS4ERR_WRONGSEC: return "WRONGSEC";
283 case NFS4ERR_CLID_INUSE: return "CLID_INUSE";
284 case NFS4ERR_RESOURCE: return "RESOURCE";
285 case NFS4ERR_MOVED: return "MOVED";
286 case NFS4ERR_NOFILEHANDLE: return "NOFILEHANDLE";
287 case NFS4ERR_MINOR_VERS_MISMATCH:return "MINOR_VERS_MISMATCH";
288 case NFS4ERR_STALE_CLIENTID: return "STALE_CLIENTID";
289 case NFS4ERR_STALE_STATEID: return "STALE_STATEID";
290 case NFS4ERR_OLD_STATEID: return "OLD_STATEID";
291 case NFS4ERR_BAD_STATEID: return "BAD_STATEID";
292 case NFS4ERR_BAD_SEQID: return "BAD_SEQID";
293 case NFS4ERR_NOT_SAME: return "NOT_SAME";
294 case NFS4ERR_LOCK_RANGE: return "LOCK_RANGE";
295 case NFS4ERR_SYMLINK: return "SYMLINK";
296 case NFS4ERR_RESTOREFH: return "RESTOREFH";
297 case NFS4ERR_LEASE_MOVED: return "LEASE_MOVED";
298 case NFS4ERR_ATTRNOTSUPP: return "ATTRNOTSUPP";
299 case NFS4ERR_NO_GRACE: return "NO_GRACE";
300 case NFS4ERR_RECLAIM_BAD: return "RECLAIM_BAD";
301 case NFS4ERR_RECLAIM_CONFLICT: return "RECLAIM_CONFLICT";
302 case NFS4ERR_BADXDR: return "BADXDR";
303 case NFS4ERR_LOCKS_HELD: return "LOCKS_HELD";
304 case NFS4ERR_OPENMODE: return "OPENMODE";
305 case NFS4ERR_BADOWNER: return "BADOWNER";
306 case NFS4ERR_BADCHAR: return "BADCHAR";
307 case NFS4ERR_BADNAME: return "BADNAME";
308 case NFS4ERR_BAD_RANGE: return "BAD_RANGE";
309 case NFS4ERR_LOCK_NOTSUPP: return "LOCK_NOTSUPP";
310 case NFS4ERR_OP_ILLEGAL: return "OP_ILLEGAL";
311 case NFS4ERR_DEADLOCK: return "DEADLOCK";
312 case NFS4ERR_FILE_OPEN: return "FILE_OPEN";
313 case NFS4ERR_ADMIN_REVOKED: return "ADMIN_REVOKED";
314 case NFS4ERR_CB_PATH_DOWN: return "CB_PATH_DOWN";
315
316 default: return "unknown err";
317 }
318 }
319
320 nfsstat4
321 str2err(char *status)
322 {
323 if ((strcmp("OK", status)) == 0)
324 return (NFS4_OK);
325 else if ((strcmp("PERM", status)) == 0)
326 return (NFS4ERR_PERM);
327 else if ((strcmp("NOENT", status)) == 0)
328 return (NFS4ERR_NOENT);
329 else if ((strcmp("IO", status)) == 0)
330 return (NFS4ERR_IO);
331 else if ((strcmp("NXIO", status)) == 0)
332 return (NFS4ERR_NXIO);
333 else if ((strcmp("ACCESS", status)) == 0)
334 return (NFS4ERR_ACCESS);
335 else if ((strcmp("EXIST", status)) == 0)
336 return (NFS4ERR_EXIST);
337 else if ((strcmp("XDEV", status)) == 0)
338 return (NFS4ERR_XDEV);
339 /* error slot reserved for error 19 */
340 /* available */
341 else if ((strcmp("NOTDIR", status)) == 0)
342 return (NFS4ERR_NOTDIR);
343 else if ((strcmp("ISDIR", status)) == 0)
344 return (NFS4ERR_ISDIR);
345 else if ((strcmp("INVAL", status)) == 0)
346 return (NFS4ERR_INVAL);
347 else if ((strcmp("FBIG", status)) == 0)
348 return (NFS4ERR_FBIG);
349 else if ((strcmp("NOSPC", status)) == 0)
350 return (NFS4ERR_NOSPC);
351 else if ((strcmp("ROFS", status)) == 0)
352 return (NFS4ERR_ROFS);
353 else if ((strcmp("MLINK", status)) == 0)
354 return (NFS4ERR_MLINK);
355 else if ((strcmp("NAMETOOLONG", status)) == 0)
356 return (NFS4ERR_NAMETOOLONG);
357 else if ((strcmp("NOTEMPTY", status)) == 0)
358 return (NFS4ERR_NOTEMPTY);
359 else if ((strcmp("DQUOT", status)) == 0)
360 return (NFS4ERR_DQUOT);
361 else if ((strcmp("STALE", status)) == 0)
362 return (NFS4ERR_STALE);
363 else if ((strcmp("BADHANDLE", status)) == 0)
364 return (NFS4ERR_BADHANDLE);
365 else if ((strcmp("BAD_COOKIE", status)) == 0)
366 return (NFS4ERR_BAD_COOKIE);
367 else if ((strcmp("NOTSUPP", status)) == 0)
368 return (NFS4ERR_NOTSUPP);
369 else if ((strcmp("TOOSMALL", status)) == 0)
370 return (NFS4ERR_TOOSMALL);
371 else if ((strcmp("SERVERFAULT", status)) == 0)
372 return (NFS4ERR_SERVERFAULT);
373 else if ((strcmp("BADTYPE", status)) == 0)
374 return (NFS4ERR_BADTYPE);
375 else if ((strcmp("DELAY", status)) == 0)
376 return (NFS4ERR_DELAY);
377 else if ((strcmp("SAME", status)) == 0)
378 return (NFS4ERR_SAME);
379 else if ((strcmp("DENIED", status)) == 0)
380 return (NFS4ERR_DENIED);
381 else if ((strcmp("EXPIRED", status)) == 0)
382 return (NFS4ERR_EXPIRED);
383 else if ((strcmp("LOCKED", status)) == 0)
384 return (NFS4ERR_LOCKED);
385 else if ((strcmp("GRACE", status)) == 0)
386 return (NFS4ERR_GRACE);
387 else if ((strcmp("FHEXPIRED", status)) == 0)
388 return (NFS4ERR_FHEXPIRED);
389 else if ((strcmp("SHARE_DENIED", status)) == 0)
390 return (NFS4ERR_SHARE_DENIED);
391 else if ((strcmp("WRONGSEC", status)) == 0)
392 return (NFS4ERR_WRONGSEC);
393 else if ((strcmp("CLID_INUSE", status)) == 0)
394 return (NFS4ERR_CLID_INUSE);
395 else if ((strcmp("RESOURCE", status)) == 0)
396 return (NFS4ERR_RESOURCE);
397 else if ((strcmp("MOVED", status)) == 0)
398 return (NFS4ERR_MOVED);
399 else if ((strcmp("NOFILEHANDLE", status)) == 0)
400 return (NFS4ERR_NOFILEHANDLE);
401 else if ((strcmp("MINOR_VERS_MISMATCH", status)) == 0)
402 return (NFS4ERR_MINOR_VERS_MISMATCH);
403 else if ((strcmp("STALE_CLIENTID", status)) == 0)
404 return (NFS4ERR_STALE_CLIENTID);
405 else if ((strcmp("STALE_STATEID", status)) == 0)
406 return (NFS4ERR_STALE_STATEID);
407 else if ((strcmp("OLD_STATEID", status)) == 0)
408 return (NFS4ERR_OLD_STATEID);
409 else if ((strcmp("BAD_STATEID", status)) == 0)
410 return (NFS4ERR_BAD_STATEID);
411 else if ((strcmp("BAD_SEQID", status)) == 0)
412 return (NFS4ERR_BAD_SEQID);
413 else if ((strcmp("NOT_SAME", status)) == 0)
414 return (NFS4ERR_NOT_SAME);
415 else if ((strcmp("LOCK_RANGE", status)) == 0)
416 return (NFS4ERR_LOCK_RANGE);
417 else if ((strcmp("SYMLINK", status)) == 0)
418 return (NFS4ERR_SYMLINK);
419 else if ((strcmp("RESTOREFH", status)) == 0)
420 return (NFS4ERR_RESTOREFH);
421 else if ((strcmp("LEASE_MOVED", status)) == 0)
422 return (NFS4ERR_LEASE_MOVED);
423 else if ((strcmp("ATTRNOTSUPP", status)) == 0)
424 return (NFS4ERR_ATTRNOTSUPP);
425 else if ((strcmp("NO_GRACE", status)) == 0)
426 return (NFS4ERR_NO_GRACE);
427 else if ((strcmp("RECLAIM_BAD", status)) == 0)
428 return (NFS4ERR_RECLAIM_BAD);
429 else if ((strcmp("RECLAIM_CONFLICT", status)) == 0)
430 return (NFS4ERR_RECLAIM_CONFLICT);
431 else if ((strcmp("BADXDR", status)) == 0)
432 return (NFS4ERR_BADXDR);
433 else if ((strcmp("LOCKS_HELD", status)) == 0)
434 return (NFS4ERR_LOCKS_HELD);
435 else if ((strcmp("OPENMODE", status)) == 0)
436 return (NFS4ERR_OPENMODE);
437 else if ((strcmp("BADOWNER", status)) == 0)
438 return (NFS4ERR_BADOWNER);
439 else if ((strcmp("BADCHAR", status)) == 0)
440 return (NFS4ERR_BADCHAR);
441 else if ((strcmp("BADNAME", status)) == 0)
442 return (NFS4ERR_BADNAME);
443 else if ((strcmp("BAD_RANGE", status)) == 0)
444 return (NFS4ERR_BAD_RANGE);
445 else if ((strcmp("LOCK_NOTSUPP", status)) == 0)
446 return (NFS4ERR_LOCK_NOTSUPP);
447 else if ((strcmp("OP_ILLEGAL", status)) == 0)
448 return (NFS4ERR_OP_ILLEGAL);
449 else if ((strcmp("DEADLOCK", status)) == 0)
450 return (NFS4ERR_DEADLOCK);
451 else if ((strcmp("FILE_OPEN", status)) == 0)
452 return (NFS4ERR_FILE_OPEN);
453 else if ((strcmp("ADMIN_REVOKED", status)) == 0)
454 return (NFS4ERR_ADMIN_REVOKED);
455 else if ((strcmp("CB_PATH_DOWN", status)) == 0)
456 return (NFS4ERR_CB_PATH_DOWN);
457 else
458 return (-1);
459 }
460
461 /*
462 * Convert an integer to ascii
463 */
464 char *
465 itoa(int i)
466 {
467 static char buff[32];
468
469 (void) sprintf(buff, "%d", i);
470
471 return (buff);
472 }
473
474 /*
475 * This converts a list of attribute names into
476 * a bitmap.
477 *
478 * The readdir, nverify, setattr and verify ops use this.
479 */
480 int
481 names2bitmap(Tcl_Interp *interp, char *names, bitmap4 *bmp)
482 {
483 int largc;
484 char **largv;
485 int i;
486 int bitno;
487
488 /*
489 * Convert the attribute names in the list
490 * argument into an array of strings.
491 */
492 if (Tcl_SplitList(interp, names, &largc,
493 (CONST84 char ***)&largv) != TCL_OK) {
494
495 interp->result = "List error in getattr";
496
497 return (TCL_ERROR);
498 }
499
500 /*
501 * Allocate an array big enough for 5*32 = 160 attrs
502 * and hope that's enough.
503 * Set the length to 0 word initially. The setbit()
504 * function will increase it if necessary.
505 */
506 bmp->bitmap4_len = 0;
507 bmp->bitmap4_val = calloc(5, sizeof (uint32_t));
508
509 /*
510 * Now go through the string array and for each
511 * attribute determine its bit number and set
512 * the bit in the bitmap.
513 */
514 for (i = 0; i < largc; i++) {
515 char buf[4096];
516
517 bitno = name2bit(largv[i]);
518 if (bitno < 0) {
519 sprintf(buf, "Invalid attr name [%s]", largv[i]);
520 interp->result = buf;
521 if (largv)
522 free((char *)largv);
523 return (TCL_ERROR);
524 }
525 setbit(bmp, bitno);
526 }
527
528 free((char *)largv);
529 return (TCL_OK);
530 }
531
532 /*
533 * This converts a list of access bits into associated string
534 */
535 char *
536 access2name(uint32_t abits)
537 {
538 static char buf[80];
539
540 buf[0] = '\0';
541 if (abits & ACCESS4_READ)
542 strcat(buf, "READ,");
543 if (abits & ACCESS4_LOOKUP)
544 strcat(buf, "LOOKUP,");
545 if (abits & ACCESS4_MODIFY)
546 strcat(buf, "MODIFY,");
547 if (abits & ACCESS4_EXTEND)
548 strcat(buf, "EXTEND,");
549 if (abits & ACCESS4_DELETE)
550 strcat(buf, "DELETE,");
551 if (abits & ACCESS4_EXECUTE)
552 strcat(buf, "EXECUTE,");
553 if (buf[0] != '\0')
554 buf[strlen(buf) - 1] = '\0';
555
556 return (buf);
557 }
558
559 /*
560 * Converts the nfsace4 structure to string list, and return the buffer
561 */
562 char *
563 prn_ace4(nfsace4 ace)
564 {
565 static char buf[256];
566 char acltype[20];
567 char aclflag[20];
568 char aclmask[20];
569
570 switch (ace.type) {
571 case ACE4_ACCESS_ALLOWED_ACE_TYPE:
572 sprintf(acltype, "ACCESS_ALLOWED_TYPE");
573 break;
574 case ACE4_ACCESS_DENIED_ACE_TYPE:
575 sprintf(acltype, "ACCESS_DENIED_TYPE");
576 break;
577 case ACE4_SYSTEM_AUDIT_ACE_TYPE:
578 sprintf(acltype, "SYSTEM_AUDIT_TYPE");
579 break;
580 case ACE4_SYSTEM_ALARM_ACE_TYPE:
581 sprintf(acltype, "SYSTEM_ALARM_TYPE");
582 break;
583 default:
584 break;
585 }
586 switch (ace.flag) {
587 case ACE4_FILE_INHERIT_ACE:
588 sprintf(aclmask, "FILE_INHERIT");
589 break;
590 case ACE4_DIRECTORY_INHERIT_ACE:
591 sprintf(aclmask, "DIR_INHERIT");
592 break;
593 case ACE4_NO_PROPAGATE_INHERIT_ACE:
594 sprintf(aclmask, "NO_PROPAGATE");
595 break;
596 case ACE4_INHERIT_ONLY_ACE:
597 sprintf(aclmask, "INHERIT_ONLY");
598 break;
599 case ACE4_SUCCESSFUL_ACCESS_ACE_FLAG:
600 sprintf(acltype, "SUCCESS_ACCESS");
601 break;
602 case ACE4_FAILED_ACCESS_ACE_FLAG:
603 sprintf(acltype, "FAILED_ACCESS");
604 break;
605 case ACE4_IDENTIFIER_GROUP:
606 sprintf(acltype, "ID_GROUP");
607 break;
608 default:
609 break;
610 }
611 sprintf(buf, "%s %s %s %s",
612 acltype, aclflag, aclmask, utf82str(ace.who));
613 return (buf);
614 }
615
616 /*
617 * Converts the nfsace4 structure to string list, and return the buffer
618 */
619 char *
620 out_ace4(nfsace4 ace, int symbolic_out)
621 {
622 #define ACL_MEMSIZE 20
623
624 size_t buf_size = 256;
625 char *buf;
626 size_t ret_len;
627 char acltype[ACL_MEMSIZE];
628 char aclflag[ACL_MEMSIZE];
629 char aclmask[ACL_MEMSIZE];
630
631 (void) snprintf(acltype, sizeof (acltype), "%d", ace.type);
632 (void) snprintf(aclflag, sizeof (aclflag), "%x", ace.flag);
633 (void) snprintf(aclmask, sizeof (aclmask), "%x", ace.access_mask);
634
635 #if DEBUG_ACL
636 (void) printf("%d %x %x %s\n", ace.type, ace.flag,
637 ace.access_mask, utf82str(ace.who));
638
639 out_ace4_type(ace);
640 out_ace4_flag(ace);
641 out_ace4_mask(ace);
642 ace4_check(ace);
643 #endif
644
645 buf = malloc(buf_size);
646 if (buf == NULL) {
647 perror("malloc(buf_size)");
648 (void) fprintf(stderr, " -- file %s, line %d\n",
649 __FILE__, __LINE__);
650 goto fin;
651 }
652 for (;;) {
653 ret_len = snprintf(buf, buf_size, "%s %s %s %s",
654 acltype, aclflag, aclmask, utf82str(ace.who));
655 if (ret_len < buf_size) {
656 break;
657 } else {
658 buf_size = ret_len + 1;
659 buf = realloc(buf, buf_size);
660 }
661 }
662 fin:
663 return (buf);
664
665 #undef ACL_MEMSIZE
666 }
667
668 void
669 out_ace4_type(nfsace4 ace)
670 {
671 switch (ace.type) {
672 case ACE4_ACCESS_ALLOWED_ACE_TYPE:
673 (void) printf("\ttype: ACE4_ACCESS_ALLOWED_ACE_TYPE\n");
674 break;
675 case ACE4_ACCESS_DENIED_ACE_TYPE:
676 (void) printf("\ttype: ACE4_ACCESS_DENIED_ACE_TYPE\n");
677 break;
678 case ACE4_SYSTEM_AUDIT_ACE_TYPE:
679 (void) printf("\ttype: ACE4_SYSTEM_AUDIT_ACE_TYPE\n");
680 break;
681 case ACE4_SYSTEM_ALARM_ACE_TYPE:
682 (void) printf("\ttype: ACE4_SYSTEM_ALARM_ACE_TYPE\n");
683 break;
684 default:
685 (void) printf("\ttype: Unknown type\n");
686 break;
687 }
688 }
689
690 void
691 out_ace4_flag(nfsace4 ace)
692 {
693 if (ace.flag == 0) {
694 (void) printf("\tflag: NOT SET\n");
695 return;
696 }
697
698 if (ace.flag & ACE4_FILE_INHERIT_ACE)
699 (void) printf("\tflag: ACE4_FILE_INHERIT_ACE\n");
700 if (ace.flag & ACE4_DIRECTORY_INHERIT_ACE)
701 (void) printf("\tflag: ACE4_DIRECTORY_INHERIT_ACE\n");
702 if (ace.flag & ACE4_NO_PROPAGATE_INHERIT_ACE)
703 (void) printf("\tflag: ACE4_NO_PROPAGATE_INHERIT_ACE\n");
704 if (ace.flag & ACE4_INHERIT_ONLY_ACE)
705 (void) printf("\tflag: ACE4_INHERIT_ONLY_ACE\n");
706 if (ace.flag & ACE4_SUCCESSFUL_ACCESS_ACE_FLAG)
707 (void) printf("\tflag: ACE4_SUCCESSFUL_ACCESS_ACE_FLAG\n");
708 if (ace.flag & ACE4_FAILED_ACCESS_ACE_FLAG)
709 (void) printf("\tflag: ACE4_FAILED_ACCESS_ACE_FLAG\n");
710 if (ace.flag & ACE4_IDENTIFIER_GROUP)
711 (void) printf("\tflag: ACE4_IDENTIFIER_GROUP\n");
712 }
713
714 void
715 out_ace4_mask(nfsace4 ace)
716 {
717 if (ace.access_mask == 0) {
718 (void) printf("\tmask: NOT SET\n");
719 return;
720 }
721
722 (void) printf("\tmask: ");
723
724 if (ace.access_mask & ACE4_READ_DATA)
725 (void) printf("ACE4_READ_DATA ");
726 if (ace.access_mask & ACE4_WRITE_DATA)
727 (void) printf("ACE4_WRITE_DATA ");
728 if (ace.access_mask & ACE4_APPEND_DATA)
729 (void) printf("ACE4_APPEND_DATA ");
730 if (ace.access_mask & ACE4_READ_NAMED_ATTRS)
731 (void) printf("ACE4_READ_NAMED_ATTRS ");
732 if (ace.access_mask & ACE4_WRITE_NAMED_ATTRS)
733 (void) printf("ACE4_WRITE_NAMED_ATTRS ");
734 if (ace.access_mask & ACE4_EXECUTE)
735 (void) printf("ACE4_EXECUTE ");
736 if (ace.access_mask & ACE4_DELETE_CHILD)
737 (void) printf("ACE4_DELETE_CHILD ");
738 if (ace.access_mask & ACE4_READ_ATTRIBUTES)
739 (void) printf("ACE4_READ_ATTRIBUTES ");
740 if (ace.access_mask & ACE4_WRITE_ATTRIBUTES)
741 (void) printf("ACE4_WRITE_ATTRIBUTES ");
742 if (ace.access_mask & ACE4_DELETE)
743 (void) printf("ACE4_DELETE ");
744 if (ace.access_mask & ACE4_READ_ACL)
745 (void) printf("ACE4_READ_ACL ");
746 if (ace.access_mask & ACE4_WRITE_ACL)
747 (void) printf("ACE4_WRITE_ACL ");
748 if (ace.access_mask & ACE4_WRITE_OWNER)
749 (void) printf("ACE4_WRITE_OWNER ");
750 if (ace.access_mask & ACE4_SYNCHRONIZE)
751 (void) printf("ACE4_SYNCHRONIZE ");
752
753 if (ace.access_mask == ACE4_GENERIC_READ)
754 (void) printf("ACE4_GENERIC_READ ");
755 if (ace.access_mask == ACE4_GENERIC_WRITE)
756 (void) printf("ACE4_GENERIC_WRITE ");
757 if (ace.access_mask == ACE4_GENERIC_EXECUTE)
758 (void) printf("ACE4_GENERIC_EXECUTE ");
759
760 (void) printf("\n");
761 }
762
763 /*
764 * Perform some basic minimal sanity checks. In time if these
765 * checks grow in complexity can be split into seperate functions.
766 */
767 void
768 ace4_check(nfsace4 ace)
769 {
770
771 /*
772 * Flag checks - check for illegal combinations and invalid
773 * values.
774 */
775 if (ace.flag & ACE4_INHERIT_ONLY_ACE) {
776 if (!(ace.flag & ACE4_FILE_INHERIT_ACE) ||
777 !(ace.flag & ACE4_DIRECTORY_INHERIT_ACE)) {
778 (void) printf("** Warning - Invalid FLAG settings\n");
779 }
780 }
781
782 if ((ace.flag & ACE4_SUCCESSFUL_ACCESS_ACE_FLAG) ||
783 (ace.flag & ACE4_FAILED_ACCESS_ACE_FLAG) ||
784 (ace.flag & ACE4_NO_PROPAGATE_INHERIT_ACE)) {
785 (void) printf("** Warning - Invalid FLAG settings\n");
786 }
787
788 /*
789 * Mask checks - check for invalid values.
790 */
791 if ((ace.access_mask & ACE4_DELETE) ||
792 (ace.access_mask & ACE4_WRITE_OWNER) ||
793 (ace.access_mask & ACE4_SYNCHRONIZE)) {
794 (void) printf("** Warning - Invalid MASK settings\n");
795 }
796
797 if (ace.type == ACE4_ACCESS_ALLOWED_ACE_TYPE) {
798 if (!(ace.access_mask & ACE4_READ_ATTRIBUTES) ||
799 !(ace.access_mask & ACE4_READ_ACL)) {
800 (void) printf("** Warninf - Missing attributes\n");
801 }
802 }
803 }
804
805
806 /*
807 * ----------------------------------------------------------------------
808 *
809 * getInnerCmd --
810 *
811 * This function is invoked within substitution to get any commands
812 * enclosed within brackets '[' ']'. It copies the enclosed text from
813 * the original string to the target string. Also, it advances the
814 * pointer of the original string to the next character after the
815 * closing bracket.
816 *
817 *
818 * ----------------------------------------------------------------------
819 */
820
821 int
822 getInnerCmd(char *target, char **original)
823 {
824 char *curr = *original;
825 int nested = 0,
826 i;
827
828 /* check for matching brackets */
829 while (*curr != 0) {
830 switch (*curr) {
831 case '[':
832 nested++;
833 break;
834 case ']':
835 nested--;
836 break;
837 default:
838 break;
839 }
840 if (nested == 0)
841 break;
842
843 i = (int)(curr - *original);
844 curr++;
845 }
846
847 if (nested != 0 && *curr == 0) {
848 sprintf(target, "ERROR Mismatched brackets. Missing %c.\n",
849 (nested > 0) ? ']' : '[');
850 return (TCL_ERROR);
851 }
852
853 if (*curr != ']') {
854 sprintf(target, "ERROR Unexpected syntax error getInnerCmd\n");
855 return (TCL_ERROR);
856 }
857
858 /* copy inner commands (skipping outer brakects) */
859 i = (int)(curr - *original);
860 strncpy(target, *original + 1, i);
861 target[i] = '\0';
862 /* move original pointer to next char after ']' */
863 *original = curr + 1;
864 return (TCL_OK);
865 }
866
867 /*
868 * ----------------------------------------------------------------------
869 *
870 * substitution --
871 *
872 * This function is invoked to process substitution on a single
873 * item(string). Performs backslash, variable and command substitution.
874 * Result string is stored in the standard place.
875 *
876 * Caution: 'result' is static memory and will be rewriten by each
877 * substitution call, as well as other TCL calls. It must be
878 * copied or used right after the call to substitution.
879 *
880 * ----------------------------------------------------------------------
881 */
882
883 int
884 substitution(Tcl_Interp *interp, char *CONST strng)
885 {
886 static Tcl_DString result;
887 char *p, *old, *value;
888 int code, count, doVars = 1, doCmds = 0, doBackslashes = 1;
889 Tcl_Interp *iPtr = (Tcl_Interp *) interp;
890
891 /*
892 * Scan through the string one character at a time, performing
893 * command, variable, and backslash substitutions.
894 */
895
896 Tcl_DStringInit(&result);
897 if (strng == NULL) { /* if no string, return success */
898 Tcl_DStringResult(interp, &result);
899 return (TCL_OK);
900 }
901 old = p = strng;
902 while (*p != 0) {
903 switch (*p) {
904 case '\\':
905 if (doBackslashes) {
906 char buf[TCL_UTF_MAX];
907
908 if (p != old) {
909 Tcl_DStringAppend(&result, old, p-old);
910 }
911 Tcl_DStringAppend(&result, buf,
912 Tcl_UtfBackslash(p, &count, buf));
913 p += count;
914 old = p;
915 } else {
916 p++;
917 }
918 break;
919
920 case '$':
921 if (doVars) {
922 if (p != old) {
923 Tcl_DStringAppend(&result, old, p-old);
924 }
925 value = (char *)Tcl_ParseVar(interp, p,
926 (CONST84 char **)&p);
927 if (value == NULL) {
928 Tcl_DStringFree(&result);
929 return (TCL_ERROR);
930 }
931 Tcl_DStringAppend(&result, value, -1);
932 old = p;
933 } else {
934 p++;
935 }
936 break;
937
938 case '[':
939 if (doCmds) {
940 if (p != old) {
941 Tcl_DStringAppend(&result, old, p-old);
942 }
943
944 {
945 int code;
946 char *tmp;
947
948 if ((tmp = malloc(strlen(p))) == NULL) {
949 perror("out of memory");
950 exit(1);
951 }
952
953 code = getInnerCmd(tmp, &p);
954 if (code == TCL_ERROR) {
955 fprintf(stderr, tmp);
956 Tcl_DStringFree(&result);
957 return (code);
958 }
959
960 code = Tcl_EvalEx(interp, tmp, -1, 0);
961 free(tmp);
962 if (code == TCL_ERROR) {
963 Tcl_DStringFree(&result);
964 return (code);
965 }
966 old = p;
967 }
968 Tcl_DStringAppend(&result, iPtr->result, -1);
969 Tcl_ResetResult(interp);
970 } else {
971 p++;
972 }
973 break;
974
975 default:
976 p++;
977 break;
978 }
979 }
980 if (p != old) {
981 Tcl_DStringAppend(&result, old, p-old);
982 }
983 Tcl_DStringResult(interp, &result);
984 return (TCL_OK);
985 }
986
987
988 /*
989 * ----------------------------------------------------------------------
990 *
991 * find_file --
992 *
993 * This function is used to search filename on the directories listed
994 * on the environment variable whose name is passed in mypath, using
995 * the field separators defined in mysep.
996 * Default values for mypath and mysep are "PATH" and ":", respectively.
997 * To use the default values pass an empty string to mypath and/ or mysep.
998 * If the environment variable is found, then a search for filename
999 * takes place under each directory listed in the path.
1000 * If filename is found, search stops and a string pointer to its
1001 * complete name (path included) is returned. Otherwise, NULL pointer
1002 * is returned. If filename is an empty string, NULL is returned.
1003 * This function is similar to the "which" command in unix.
1004 *
1005 *
1006 * ----------------------------------------------------------------------
1007 */
1008
1009 char *
1010 find_file(char *file, char *mypath, char *mysep)
1011 {
1012 int i;
1013 char path[4096],
1014 *orig_path,
1015 *rest_path;
1016 static char filename[PATH_MAX];
1017 const char *PATH = "PATH",
1018 *SEP = ":";
1019 struct stat buf;
1020
1021 if (file[0] == '\0')
1022 return (NULL);
1023
1024 /* use defaults if info not provided */
1025 if (mypath[0] == '\0')
1026 mypath = (char *)PATH;
1027 if (mysep[0] == '\0')
1028 mysep = (char *)SEP;
1029
1030 if ((orig_path = getenv(mypath)) == NULL) {
1031 fprintf(stderr, "%s was not found in the"
1032 " environment variables\n",
1033 mypath);
1034 return (NULL);
1035 }
1036
1037 strcpy(path, orig_path);
1038
1039 i = 0;
1040 rest_path = path;
1041 while (strtok(rest_path, mysep) != NULL) {
1042 sprintf(filename, "%s/%s", rest_path, file);
1043 if (stat(filename, &buf) == 0) {
1044 i = 1;
1045 break;
1046 }
1047 rest_path += strlen(rest_path) + 1;
1048 }
1049
1050 if (i)
1051 return (filename);
1052 else
1053 return (NULL);
1054 }
1055
1056
1057 /*
1058 * Given the string of the stateid in form of {seqid other}
1059 * convert them to stateid4 structure.
1060 */
1061 int
1062 str2stateid(Tcl_Interp *interp, char *strs, stateid4 *sp)
1063 {
1064 int lc;
1065 char **lv;
1066 char buf[80];
1067 uint_t slen;
1068 int tmp;
1069
1070 /* split the stateid4 strings to seqid and other */
1071 if (Tcl_SplitList(interp, strs, &lc, (CONST84 char ***)&lv) != TCL_OK) {
1072 sprintf(buf, "str2stateid error, can't split {%s}", strs);
1073 interp->result = buf;
1074 return (TCL_ERROR);
1075 }
1076 if (lc != 2) {
1077 sprintf(buf, "str2stateid error, {%s} needs 2 fields", strs);
1078 interp->result = buf;
1079 if (lv)
1080 free((char *)lv);
1081 return (TCL_ERROR);
1082 }
1083
1084 sp->seqid = (uint32_t)atoi(lv[0]);
1085
1086 /*
1087 * try to take care of special stateid cases,
1088 * e.g. all 0's or all 1's.
1089 */
1090 tmp = (uint64_t)strtoll(lv[1], NULL, 16);
1091 if ((sp->seqid == 0) && (tmp == 0)) {
1092 (void) memset((void *) sp, 0, sizeof (stateid4));
1093 } else if (((sp->seqid == 1) || (sp->seqid == 0)) && (tmp == 1)) {
1094 (void) memset((void *) sp, 0xFF, sizeof (stateid4));
1095 sp->seqid = 0xffffffff;
1096 } else {
1097 slen = strlen(lv[1]) / 2;
1098 (void) memcpy(&sp->other, hex2bin(lv[1], (unsigned)slen),
1099 sizeof (sp->other));
1100 }
1101
1102 free((char *)lv);
1103 return (TCL_OK);
1104 }