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