Home | History | Annotate | Download | only in snoop
      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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #include <sys/types.h>
     27 #include <sys/errno.h>
     28 #include <sys/tiuser.h>
     29 #include <setjmp.h>
     30 #include <pwd.h>
     31 #include <grp.h>
     32 
     33 #include <rpc/types.h>
     34 #include <rpc/xdr.h>
     35 #include <rpc/auth.h>
     36 #include <rpc/clnt.h>
     37 #include <rpc/rpc_msg.h>
     38 #include <string.h>
     39 #include "snoop.h"
     40 
     41 #include <sys/stat.h>
     42 
     43 extern char *get_sum_line();
     44 extern void check_retransmit();
     45 extern char *sum_nfsfh();
     46 extern int sum_nfsstat();
     47 extern int detail_nfsstat();
     48 extern void detail_nfsfh();
     49 extern void detail_fattr();
     50 extern void skip_fattr();
     51 extern char *sum_nfsfh3();
     52 extern int sum_nfsstat3();
     53 extern int detail_nfsstat3();
     54 extern void detail_post_op_attr();
     55 extern void detail_nfsfh3();
     56 extern int sum_nfsstat4();
     57 extern int detail_nfsstat4();
     58 
     59 extern jmp_buf xdr_err;
     60 
     61 static void aclcall2();
     62 static void aclreply2();
     63 static void aclcall3();
     64 static void aclreply3();
     65 static void aclcall4();
     66 static void aclreply4();
     67 static void detail_access2();
     68 static char *sum_access2();
     69 static void detail_mask();
     70 static void detail_secattr();
     71 static void detail_aclent();
     72 static char *detail_uname();
     73 static char *detail_gname();
     74 static char *detail_perm(ushort_t);
     75 static void interpret_nfs_acl2(int, int, int, int, int, char *, int);
     76 static void interpret_nfs_acl3(int, int, int, int, int, char *, int);
     77 static void interpret_nfs_acl4(int, int, int, int, int, char *, int);
     78 
     79 #define	ACLPROC2_NULL		((unsigned long)(0))
     80 #define	ACLPROC2_GETACL		((unsigned long)(1))
     81 #define	ACLPROC2_SETACL		((unsigned long)(2))
     82 #define	ACLPROC2_GETATTR	((unsigned long)(3))
     83 #define	ACLPROC2_ACCESS		((unsigned long)(4))
     84 #define	ACLPROC2_GETXATTRDIR	((unsigned long)(5))
     85 
     86 #define	ACLPROC3_NULL		((unsigned long)(0))
     87 #define	ACLPROC3_GETACL		((unsigned long)(1))
     88 #define	ACLPROC3_SETACL		((unsigned long)(2))
     89 #define	ACLPROC3_GETXATTRDIR	((unsigned long)(3))
     90 
     91 #define	ACLPROC4_NULL		((unsigned long)(0))
     92 #define	ACLPROC4_GETACL		((unsigned long)(1))
     93 #define	ACLPROC4_SETACL		((unsigned long)(2))
     94 
     95 #define	NA_USER_OBJ	0x1
     96 #define	NA_USER		0x2
     97 #define	NA_GROUP_OBJ	0x4
     98 #define	NA_GROUP	0x8
     99 #define	NA_CLASS_OBJ	0x10
    100 #define	NA_OTHER_OBJ	0x20
    101 #define	NA_ACL_DEFAULT	0x1000
    102 
    103 #define	NA_DEF_USER_OBJ		(NA_USER_OBJ | NA_ACL_DEFAULT)
    104 #define	NA_DEF_USER		(NA_USER | NA_ACL_DEFAULT)
    105 #define	NA_DEF_GROUP_OBJ	(NA_GROUP_OBJ | NA_ACL_DEFAULT)
    106 #define	NA_DEF_GROUP		(NA_GROUP | NA_ACL_DEFAULT)
    107 #define	NA_DEF_CLASS_OBJ	(NA_CLASS_OBJ | NA_ACL_DEFAULT)
    108 #define	NA_DEF_OTHER_OBJ	(NA_OTHER_OBJ | NA_ACL_DEFAULT)
    109 
    110 #define	NA_ACL		0x1
    111 #define	NA_ACLCNT	0x2
    112 #define	NA_DFACL	0x4
    113 #define	NA_DFACLCNT	0x8
    114 
    115 #define	ACCESS2_READ	0x0001
    116 #define	ACCESS2_LOOKUP	0x0002
    117 #define	ACCESS2_MODIFY	0x0004
    118 #define	ACCESS2_EXTEND	0x0008
    119 #define	ACCESS2_DELETE	0x0010
    120 #define	ACCESS2_EXECUTE	0x0020
    121 
    122 static char *procnames_short_v2[] = {
    123 	"NULL2",	/*  0 */
    124 	"GETACL2",	/*  1 */
    125 	"SETACL2",	/*  2 */
    126 	"GETATTR2",	/*  3 */
    127 	"ACCESS2",	/*  4 */
    128 	"GETXATTRDIR2",	/*  5 */
    129 };
    130 static char *procnames_short_v3[] = {
    131 	"NULL3",	/*  0 */
    132 	"GETACL3",	/*  1 */
    133 	"SETACL3",	/*  2 */
    134 	"GETXATTRDIR3",	/*  3 */
    135 };
    136 static char *procnames_short_v4[] = {
    137 	"NULL4",	/*  0 */
    138 	"GETACL4",	/*  1 */
    139 	"SETACL4",	/*  2 */
    140 };
    141 
    142 static char *procnames_long_v2[] = {
    143 	"Null procedure",			/*  0 */
    144 	"Get file access control list",		/*  1 */
    145 	"Set file access control list",		/*  2 */
    146 	"Get file attributes",			/*  3 */
    147 	"Check access permission",		/*  4 */
    148 	"Get extended attribute directory",	/*  5 */
    149 };
    150 static char *procnames_long_v3[] = {
    151 	"Null procedure",			/*  0 */
    152 	"Get file access control list",		/*  1 */
    153 	"Set file access control list",		/*  2 */
    154 	"Get extended attribute directory",	/*  3 */
    155 };
    156 static char *procnames_long_v4[] = {
    157 	"Null procedure",			/*  0 */
    158 	"Get file access control list",		/*  1 */
    159 	"Set file access control list",		/*  2 */
    160 };
    161 
    162 #define	MAXPROC_V2	5
    163 #define	MAXPROC_V3	3
    164 #define	MAXPROC_V4	2
    165 
    166 /* ARGSUSED */
    167 void
    168 interpret_nfs_acl(flags, type, xid, vers, proc, data, len)
    169 	int flags, type, xid, vers, proc;
    170 	char *data;
    171 	int len;
    172 {
    173 
    174 	if (vers == 2) {
    175 		interpret_nfs_acl2(flags, type, xid, vers, proc, data, len);
    176 		return;
    177 	}
    178 
    179 	if (vers == 3) {
    180 		interpret_nfs_acl3(flags, type, xid, vers, proc, data, len);
    181 		return;
    182 	}
    183 
    184 	if (vers == 4) {
    185 		interpret_nfs_acl4(flags, type, xid, vers, proc, data, len);
    186 		return;
    187 	}
    188 }
    189 
    190 static void
    191 interpret_nfs_acl2(int flags, int type, int xid, int vers, int proc,
    192     char *data, int len)
    193 {
    194 	char *line;
    195 	char buff[2048];
    196 	int off, sz;
    197 	char *fh;
    198 	ulong_t mask;
    199 
    200 	if (proc < 0 || proc > MAXPROC_V2)
    201 		return;
    202 
    203 	if (flags & F_SUM) {
    204 		line = get_sum_line();
    205 
    206 		if (type == CALL) {
    207 			(void) sprintf(line, "NFS_ACL C %s",
    208 			    procnames_short_v2[proc]);
    209 			line += strlen(line);
    210 			switch (proc) {
    211 			case ACLPROC2_GETACL:
    212 				fh = sum_nfsfh();
    213 				mask = getxdr_u_long();
    214 				(void) sprintf(line, "%s mask=%lu", fh, mask);
    215 				break;
    216 			case ACLPROC2_SETACL:
    217 				(void) sprintf(line, sum_nfsfh());
    218 				break;
    219 			case ACLPROC2_GETATTR:
    220 				(void) sprintf(line, sum_nfsfh());
    221 				break;
    222 			case ACLPROC2_ACCESS:
    223 				fh = sum_nfsfh();
    224 				(void) sprintf(line, "%s (%s)", fh,
    225 				    sum_access2());
    226 				break;
    227 			case ACLPROC2_GETXATTRDIR:
    228 				fh = sum_nfsfh();
    229 				(void) sprintf(line, "%s create=%s", fh,
    230 				    getxdr_bool() ? "true" : "false");
    231 				break;
    232 			default:
    233 				break;
    234 			}
    235 
    236 			check_retransmit(line, (ulong_t)xid);
    237 		} else {
    238 			(void) sprintf(line, "NFS_ACL R %s ",
    239 			    procnames_short_v2[proc]);
    240 			line += strlen(line);
    241 			switch (proc) {
    242 			case ACLPROC2_GETACL:
    243 				(void) sum_nfsstat(line);
    244 				break;
    245 			case ACLPROC2_SETACL:
    246 				(void) sum_nfsstat(line);
    247 				break;
    248 			case ACLPROC2_GETATTR:
    249 				(void) sum_nfsstat(line);
    250 				break;
    251 			case ACLPROC2_ACCESS:
    252 				if (sum_nfsstat(line) == 0) {
    253 					skip_fattr();
    254 					line += strlen(line);
    255 					(void) sprintf(line, " (%s)",
    256 					    sum_access2());
    257 				}
    258 				break;
    259 			case ACLPROC2_GETXATTRDIR:
    260 				if (sum_nfsstat(line) == 0) {
    261 					line += strlen(line);
    262 					(void) sprintf(line, sum_nfsfh());
    263 				}
    264 				break;
    265 			default:
    266 				break;
    267 			}
    268 		}
    269 	}
    270 
    271 	if (flags & F_DTAIL) {
    272 		show_header("NFS_ACL:  ", "Sun NFS_ACL", len);
    273 		show_space();
    274 		(void) sprintf(get_line(0, 0), "Proc = %d (%s)",
    275 		    proc, procnames_long_v2[proc]);
    276 		if (type == CALL)
    277 			aclcall2(proc);
    278 		else
    279 			aclreply2(proc);
    280 		show_trailer();
    281 	}
    282 }
    283 
    284 static void
    285 interpret_nfs_acl3(int flags, int type, int xid, int vers, int proc,
    286     char *data, int len)
    287 {
    288 	char *line;
    289 	char buff[2048];
    290 	int off, sz;
    291 	char *fh;
    292 	ulong_t mask;
    293 
    294 	if (proc < 0 || proc > MAXPROC_V3)
    295 		return;
    296 
    297 	if (flags & F_SUM) {
    298 		line = get_sum_line();
    299 
    300 		if (type == CALL) {
    301 			(void) sprintf(line, "NFS_ACL C %s",
    302 			    procnames_short_v3[proc]);
    303 			line += strlen(line);
    304 			switch (proc) {
    305 			case ACLPROC3_GETACL:
    306 				fh = sum_nfsfh3();
    307 				mask = getxdr_u_long();
    308 				(void) sprintf(line, "%s mask=%lu", fh, mask);
    309 				break;
    310 			case ACLPROC3_SETACL:
    311 				(void) sprintf(line, sum_nfsfh3());
    312 				break;
    313 			case ACLPROC3_GETXATTRDIR:
    314 				fh = sum_nfsfh3();
    315 				(void) sprintf(line, "%s create=%s", fh,
    316 				    getxdr_bool() ? "true" : "false");
    317 				break;
    318 			default:
    319 				break;
    320 			}
    321 
    322 			check_retransmit(line, (ulong_t)xid);
    323 		} else {
    324 			(void) sprintf(line, "NFS_ACL R %s ",
    325 			    procnames_short_v3[proc]);
    326 			line += strlen(line);
    327 			switch (proc) {
    328 			case ACLPROC3_GETACL:
    329 				(void) sum_nfsstat3(line);
    330 				break;
    331 			case ACLPROC3_SETACL:
    332 				(void) sum_nfsstat3(line);
    333 				break;
    334 			case ACLPROC3_GETXATTRDIR:
    335 				if (sum_nfsstat3(line) == 0) {
    336 					line += strlen(line);
    337 					(void) sprintf(line, sum_nfsfh3());
    338 				}
    339 				break;
    340 			default:
    341 				break;
    342 			}
    343 		}
    344 	}
    345 
    346 	if (flags & F_DTAIL) {
    347 		show_header("NFS_ACL:  ", "Sun NFS_ACL", len);
    348 		show_space();
    349 		(void) sprintf(get_line(0, 0), "Proc = %d (%s)",
    350 		    proc, procnames_long_v3[proc]);
    351 		if (type == CALL)
    352 			aclcall3(proc);
    353 		else
    354 			aclreply3(proc);
    355 		show_trailer();
    356 	}
    357 }
    358 
    359 static void
    360 interpret_nfs_acl4(int flags, int type, int xid, int vers, int proc,
    361     char *data, int len)
    362 {
    363 	char *line;
    364 	char buff[2048];
    365 	int off, sz;
    366 	char *fh;
    367 	ulong_t mask;
    368 
    369 	if (proc < 0 || proc > MAXPROC_V4)
    370 		return;
    371 
    372 	if (flags & F_SUM) {
    373 		line = get_sum_line();
    374 
    375 		if (type == CALL) {
    376 			(void) sprintf(line, "NFS_ACL C %s",
    377 			    procnames_short_v4[proc]);
    378 			line += strlen(line);
    379 			switch (proc) {
    380 			case ACLPROC4_GETACL:
    381 				fh = sum_nfsfh3();
    382 				mask = getxdr_u_long();
    383 				(void) sprintf(line, "%s mask=%lu", fh, mask);
    384 				break;
    385 			case ACLPROC4_SETACL:
    386 				(void) sprintf(line, sum_nfsfh3());
    387 				break;
    388 			default:
    389 				break;
    390 			}
    391 
    392 			check_retransmit(line, (ulong_t)xid);
    393 		} else {
    394 			(void) sprintf(line, "NFS_ACL R %s ",
    395 			    procnames_short_v4[proc]);
    396 			line += strlen(line);
    397 			switch (proc) {
    398 			case ACLPROC4_GETACL:
    399 				(void) sum_nfsstat4(line);
    400 				break;
    401 			case ACLPROC4_SETACL:
    402 				(void) sum_nfsstat4(line);
    403 				break;
    404 			default:
    405 				break;
    406 			}
    407 		}
    408 	}
    409 
    410 	if (flags & F_DTAIL) {
    411 		show_header("NFS_ACL:  ", "Sun NFS_ACL", len);
    412 		show_space();
    413 		(void) sprintf(get_line(0, 0), "Proc = %d (%s)",
    414 		    proc, procnames_long_v4[proc]);
    415 		if (type == CALL)
    416 			aclcall4(proc);
    417 		else
    418 			aclreply4(proc);
    419 		show_trailer();
    420 	}
    421 }
    422 
    423 int
    424 sum_nfsstat4(char *line)
    425 {
    426 	ulong_t status;
    427 	char *p, *nfsstat4_to_name(int);
    428 
    429 	status = getxdr_long();
    430 	p = nfsstat4_to_name(status);
    431 	(void) strcpy(line, p);
    432 	return (status);
    433 }
    434 
    435 int
    436 detail_nfsstat4()
    437 {
    438 	ulong_t status;
    439 	char buff[64];
    440 	int pos;
    441 
    442 	pos = getxdr_pos();
    443 	status = sum_nfsstat4(buff);
    444 
    445 	(void) sprintf(get_line(pos, getxdr_pos()), "Status = %d (%s)",
    446 	    status, buff);
    447 
    448 	return ((int)status);
    449 }
    450 
    451 /*
    452  * Print out version 2 NFS_ACL call packets
    453  */
    454 static void
    455 aclcall2(proc)
    456 	int proc;
    457 {
    458 
    459 	switch (proc) {
    460 	case ACLPROC2_GETACL:
    461 		detail_nfsfh();
    462 		detail_mask();
    463 		break;
    464 	case ACLPROC2_SETACL:
    465 		detail_nfsfh();
    466 		detail_secattr();
    467 		break;
    468 	case ACLPROC2_GETATTR:
    469 		detail_nfsfh();
    470 		break;
    471 	case ACLPROC2_ACCESS:
    472 		detail_nfsfh();
    473 		detail_access2();
    474 		break;
    475 	default:
    476 		break;
    477 	}
    478 }
    479 
    480 /*
    481  * Print out version 2 NFS_ACL reply packets
    482  */
    483 static void
    484 aclreply2(proc)
    485 	int proc;
    486 {
    487 
    488 	switch (proc) {
    489 	case ACLPROC2_GETACL:
    490 		if (detail_nfsstat() == 0) {
    491 			detail_fattr();
    492 			detail_secattr();
    493 		}
    494 		break;
    495 	case ACLPROC2_SETACL:
    496 		if (detail_nfsstat() == 0)
    497 			detail_fattr();
    498 		break;
    499 	case ACLPROC2_GETATTR:
    500 		if (detail_nfsstat() == 0)
    501 			detail_fattr();
    502 		break;
    503 	case ACLPROC2_ACCESS:
    504 		if (detail_nfsstat() == 0) {
    505 			detail_fattr();
    506 			detail_access2();
    507 		}
    508 		break;
    509 	default:
    510 		break;
    511 	}
    512 }
    513 
    514 /*
    515  * Print out version 3 NFS_ACL call packets
    516  */
    517 static void
    518 aclcall3(proc)
    519 	int proc;
    520 {
    521 
    522 	switch (proc) {
    523 	case ACLPROC3_GETACL:
    524 		detail_nfsfh3();
    525 		detail_mask();
    526 		break;
    527 	case ACLPROC3_SETACL:
    528 		detail_nfsfh3();
    529 		detail_secattr();
    530 		break;
    531 	default:
    532 		break;
    533 	}
    534 }
    535 
    536 /*
    537  * Print out version 3 NFS_ACL reply packets
    538  */
    539 static void
    540 aclreply3(proc)
    541 	int proc;
    542 {
    543 
    544 	switch (proc) {
    545 	case ACLPROC3_GETACL:
    546 		if (detail_nfsstat3() == 0) {
    547 			detail_post_op_attr("");
    548 			detail_secattr();
    549 		}
    550 		break;
    551 	case ACLPROC3_SETACL:
    552 		if (detail_nfsstat3() == 0)
    553 			detail_post_op_attr("");
    554 		break;
    555 	default:
    556 		break;
    557 	}
    558 }
    559 
    560 /*
    561  * Print out version 4 NFS_ACL call packets
    562  */
    563 static void
    564 aclcall4(proc)
    565 	int proc;
    566 {
    567 
    568 	switch (proc) {
    569 	case ACLPROC4_GETACL:
    570 		detail_nfsfh3();
    571 		detail_mask();
    572 		break;
    573 	case ACLPROC4_SETACL:
    574 		detail_nfsfh3();
    575 		detail_secattr();
    576 		break;
    577 	default:
    578 		break;
    579 	}
    580 }
    581 
    582 /*
    583  * Print out version 4 NFS_ACL reply packets
    584  */
    585 static void
    586 aclreply4(proc)
    587 	int proc;
    588 {
    589 
    590 	switch (proc) {
    591 	case ACLPROC4_GETACL:
    592 		if (detail_nfsstat4() == 0) {
    593 			detail_post_op_attr("");
    594 			detail_secattr();
    595 		}
    596 		break;
    597 	case ACLPROC4_SETACL:
    598 		if (detail_nfsstat4() == 0)
    599 			detail_post_op_attr("");
    600 		break;
    601 	default:
    602 		break;
    603 	}
    604 }
    605 
    606 static void
    607 detail_access2()
    608 {
    609 	uint_t bits;
    610 
    611 	bits = showxdr_u_long("Access bits = 0x%08x");
    612 	(void) sprintf(get_line(0, 0), "	%s",
    613 	    getflag(bits, ACCESS2_READ, "Read", "(no read)"));
    614 	(void) sprintf(get_line(0, 0), "	%s",
    615 	    getflag(bits, ACCESS2_LOOKUP, "Lookup", "(no lookup)"));
    616 	(void) sprintf(get_line(0, 0), "	%s",
    617 	    getflag(bits, ACCESS2_MODIFY, "Modify", "(no modify)"));
    618 	(void) sprintf(get_line(0, 0), "	%s",
    619 	    getflag(bits, ACCESS2_EXTEND, "Extend", "(no extend)"));
    620 	(void) sprintf(get_line(0, 0), "	%s",
    621 	    getflag(bits, ACCESS2_DELETE, "Delete", "(no delete)"));
    622 	(void) sprintf(get_line(0, 0), "	%s",
    623 	    getflag(bits, ACCESS2_EXECUTE, "Execute", "(no execute)"));
    624 }
    625 
    626 static char *
    627 sum_access2()
    628 {
    629 	int bits;
    630 	static char buff[22];
    631 
    632 	bits = getxdr_u_long();
    633 	buff[0] = '\0';
    634 
    635 	if (bits & ACCESS2_READ)
    636 		(void) strcat(buff, "read,");
    637 	if (bits & ACCESS2_LOOKUP)
    638 		(void) strcat(buff, "lookup,");
    639 	if (bits & ACCESS2_MODIFY)
    640 		(void) strcat(buff, "modify,");
    641 	if (bits & ACCESS2_EXTEND)
    642 		(void) strcat(buff, "extend,");
    643 	if (bits & ACCESS2_DELETE)
    644 		(void) strcat(buff, "delete,");
    645 	if (bits & ACCESS2_EXECUTE)
    646 		(void) strcat(buff, "execute,");
    647 	if (buff[0] != '\0')
    648 		buff[strlen(buff) - 1] = '\0';
    649 
    650 	return (buff);
    651 }
    652 
    653 static void
    654 detail_mask()
    655 {
    656 	ulong_t mask;
    657 
    658 	mask = showxdr_u_long("Mask = 0x%lx");
    659 	(void) sprintf(get_line(0, 0), "	%s",
    660 	    getflag(mask, NA_ACL, "aclent", "(no aclent)"));
    661 	(void) sprintf(get_line(0, 0), "	%s",
    662 	    getflag(mask, NA_ACLCNT, "aclcnt", "(no aclcnt)"));
    663 	(void) sprintf(get_line(0, 0), "	%s",
    664 	    getflag(mask, NA_DFACL, "dfaclent", "(no dfaclent)"));
    665 	(void) sprintf(get_line(0, 0), "	%s",
    666 	    getflag(mask, NA_DFACLCNT, "dfaclcnt", "(no dfaclcnt)"));
    667 }
    668 
    669 static void
    670 detail_secattr()
    671 {
    672 
    673 	detail_mask();
    674 	showxdr_long("Aclcnt = %d");
    675 	detail_aclent();
    676 	showxdr_long("Dfaclcnt = %d");
    677 	detail_aclent();
    678 }
    679 
    680 static void
    681 detail_aclent()
    682 {
    683 	int count;
    684 	int type;
    685 	int id;
    686 	ushort_t perm;
    687 
    688 	count = getxdr_long();
    689 	while (count-- > 0) {
    690 		type = getxdr_long();
    691 		id = getxdr_long();
    692 		perm = getxdr_u_short();
    693 		switch (type) {
    694 		case NA_USER:
    695 			(void) sprintf(get_line(0, 0), "\tuser:%s:%s",
    696 			    detail_uname(id), detail_perm(perm));
    697 			break;
    698 		case NA_USER_OBJ:
    699 			(void) sprintf(get_line(0, 0), "\tuser::%s",
    700 			    detail_perm(perm));
    701 			break;
    702 		case NA_GROUP:
    703 			(void) sprintf(get_line(0, 0), "\tgroup:%s:%s",
    704 			    detail_gname(id), detail_perm(perm));
    705 			break;
    706 		case NA_GROUP_OBJ:
    707 			(void) sprintf(get_line(0, 0), "\tgroup::%s",
    708 			    detail_perm(perm));
    709 			break;
    710 		case NA_CLASS_OBJ:
    711 			(void) sprintf(get_line(0, 0), "\tmask:%s",
    712 			    detail_perm(perm));
    713 			break;
    714 		case NA_OTHER_OBJ:
    715 			(void) sprintf(get_line(0, 0), "\tother:%s",
    716 			    detail_perm(perm));
    717 			break;
    718 		case NA_DEF_USER:
    719 			(void) sprintf(get_line(0, 0), "\tdefault:user:%s:%s",
    720 			    detail_uname(id), detail_perm(perm));
    721 			break;
    722 		case NA_DEF_USER_OBJ:
    723 			(void) sprintf(get_line(0, 0), "\tdefault:user::%s",
    724 			    detail_perm(perm));
    725 			break;
    726 		case NA_DEF_GROUP:
    727 			(void) sprintf(get_line(0, 0), "\tdefault:group:%s:%s",
    728 			    detail_gname(id), detail_perm(perm));
    729 			break;
    730 		case NA_DEF_GROUP_OBJ:
    731 			(void) sprintf(get_line(0, 0), "\tdefault:group::%s",
    732 			    detail_perm(perm));
    733 			break;
    734 		case NA_DEF_CLASS_OBJ:
    735 			(void) sprintf(get_line(0, 0), "\tdefault:mask:%s",
    736 			    detail_perm(perm));
    737 			break;
    738 		case NA_DEF_OTHER_OBJ:
    739 			(void) sprintf(get_line(0, 0), "\tdefault:other:%s",
    740 			    detail_perm(perm));
    741 			break;
    742 		default:
    743 			(void) sprintf(get_line(0, 0), "\tunrecognized entry");
    744 			break;
    745 		}
    746 	}
    747 }
    748 
    749 static char *
    750 detail_uname(uid_t uid)
    751 {
    752 	struct passwd *pwd;
    753 	static char uidp[10];
    754 
    755 	pwd = getpwuid(uid);
    756 	if (pwd == NULL) {
    757 		sprintf(uidp, "%d", uid);
    758 		return (uidp);
    759 	}
    760 	return (pwd->pw_name);
    761 }
    762 
    763 static char *
    764 detail_gname(gid_t gid)
    765 {
    766 	struct group *grp;
    767 	static char gidp[10];
    768 
    769 	grp = getgrgid(gid);
    770 	if (grp == NULL) {
    771 		sprintf(gidp, "%d", gid);
    772 		return (gidp);
    773 	}
    774 	return (grp->gr_name);
    775 }
    776 
    777 static char *perms[] = {
    778 	"---",
    779 	"--x",
    780 	"-w-",
    781 	"-wx",
    782 	"r--",
    783 	"r-x",
    784 	"rw-",
    785 	"rwx"
    786 };
    787 static char *
    788 detail_perm(ushort_t perm)
    789 {
    790 
    791 	if (perm >= sizeof (perms) / sizeof (perms[0]))
    792 		return ("?");
    793 	return (perms[perm]);
    794 }
    795