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 }