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, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright (c) 1991, 1999 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26/*
27 * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
28 */
29
30#include <sys/types.h>
31#include <sys/errno.h>
32#include <setjmp.h>
33#include <sys/tiuser.h>
34#include <string.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 <rpc/pmap_prot.h>
42#include "snoop.h"
43
44/*
45 * Number of bytes to display from a string (address, netid, etc.).
46 */
47#define	MAXSTRINGLEN	64
48
49extern char *dlc_header;
50extern jmp_buf xdr_err;
51
52static void interpret_pmap_2(int, int, int, int, int, char *, int);
53static void interpret_pmap_4(int, int, int, int, int, char *, int);
54static void stash_callit(ulong_t, int, int, int, int);
55
56void
57interpret_pmap(flags, type, xid, vers, proc, data, len)
58	int flags, type, xid, vers, proc;
59	char *data;
60	int len;
61{
62	switch (vers) {
63	case 2:	interpret_pmap_2(flags, type, xid, vers, proc, data, len);
64		break;
65
66	/* Version 3 is a subset of version 4 */
67	case 3:
68	case 4:	interpret_pmap_4(flags, type, xid, vers, proc, data, len);
69		break;
70	}
71}
72
73void show_pmap();
74char *sum_pmaplist();
75void show_pmaplist();
76
77static char *procnames_short_2[] = {
78	"Null",		/* 0 */
79	"SET",		/* 1 */
80	"UNSET",	/* 2 */
81	"GETPORT",	/* 3 */
82	"DUMP",		/* 4 */
83	"CALLIT",	/* 5 */
84};
85
86static char *procnames_long_2[] = {
87	"Null procedure",	/* 0 */
88	"Set port",		/* 1 */
89	"Unset port",		/* 2 */
90	"Get port number",	/* 3 */
91	"Dump the mappings",	/* 4 */
92	"Indirect call",	/* 5 */
93};
94
95#define	MAXPROC_2	5
96
97void
98interpret_pmap_2(flags, type, xid, vers, proc, data, len)
99	int flags, type, xid, vers, proc;
100	char *data;
101	int len;
102{
103	char *line;
104	unsigned port, proto;
105	unsigned iprog, ivers, iproc, ilen;
106	extern int pi_frame;
107	struct cache_struct *x, *find_callit();
108	int trailer_done = 0;
109
110	if (proc < 0 || proc > MAXPROC_2)
111		return;
112
113	if (proc == PMAPPROC_CALLIT) {
114		if (type == CALL) {
115			iprog = getxdr_u_long();
116			ivers = getxdr_u_long();
117			iproc = getxdr_u_long();
118			stash_callit(xid, pi_frame, iprog, ivers, iproc);
119		} else {
120			x = find_callit(xid);
121		}
122	}
123
124	if (flags & F_SUM) {
125		if (setjmp(xdr_err)) {
126			return;
127		}
128
129		line = get_sum_line();
130
131		if (type == CALL) {
132			(void) sprintf(line, "PORTMAP C %s",
133			    procnames_short_2[proc]);
134			line += strlen(line);
135			switch (proc) {
136			case PMAPPROC_GETPORT:
137				iprog = getxdr_u_long();
138				ivers = getxdr_u_long();
139				proto = getxdr_u_long();
140				(void) sprintf(line,
141				    " prog=%d (%s) vers=%d proto=%s",
142				    iprog, nameof_prog(iprog),
143				    ivers,
144				    getproto(proto));
145				break;
146			case PMAPPROC_CALLIT:
147				(void) sprintf(line,
148				    " prog=%s vers=%d proc=%d",
149				    nameof_prog(iprog),
150				    ivers, iproc);
151				if (flags & F_ALLSUM) {
152					(void) getxdr_u_long(); /* length */
153					data += 16; /* prog+ver+proc+len */
154					len -= 16;
155					protoprint(flags, type, xid,
156					    iprog, ivers, iproc,
157					    data, len);
158				}
159				break;
160			default:
161				break;
162			}
163			check_retransmit(line, xid);
164		} else {
165			(void) sprintf(line, "PORTMAP R %s ",
166			    procnames_short_2[proc]);
167			line += strlen(line);
168			switch (proc) {
169			case PMAPPROC_GETPORT:
170				port = getxdr_u_long();
171				(void) sprintf(line, "port=%d", port);
172				break;
173			case PMAPPROC_DUMP:
174				(void) sprintf(line, "%s", sum_pmaplist());
175				break;
176			case PMAPPROC_CALLIT:
177				port = getxdr_u_long();
178				ilen = getxdr_u_long();
179				(void) sprintf(line, "port=%d len=%d",
180				    port, ilen);
181				if (flags & F_ALLSUM && x != NULL) {
182					data += 8; /* port+len */
183					len -= 8;
184					protoprint(flags, type, xid,
185					    x->xid_prog,
186					    x->xid_vers,
187					    x->xid_proc,
188					    data, len);
189				}
190				break;
191			default:
192				break;
193			}
194		}
195	}
196
197	if (flags & F_DTAIL) {
198		show_header("PMAP:  ", "Portmapper", len);
199		show_space();
200		if (setjmp(xdr_err)) {
201			return;
202		}
203		(void) sprintf(get_line(0, 0),
204			"Proc = %d (%s)",
205			proc, procnames_long_2[proc]);
206		if (type == CALL) {
207			switch (proc) {
208			case PMAPPROC_NULL:
209			case PMAPPROC_SET:
210			case PMAPPROC_UNSET:
211				break;
212			case PMAPPROC_GETPORT:
213				iprog = getxdr_u_long();
214				(void) sprintf(get_line(0, 0),
215				    "Program = %d (%s)",
216				    iprog, nameof_prog(iprog));
217				(void) showxdr_u_long("Version = %d");
218				proto = getxdr_u_long();
219				(void) sprintf(get_line(0, 0),
220				    "Protocol = %d (%s)",
221				    proto, getproto(proto));
222				break;
223			case PMAPPROC_DUMP:
224				break;
225			case PMAPPROC_CALLIT:
226				(void) sprintf(get_line(0, 0),
227				    "Program = %d (%s)",
228				    iprog, nameof_prog(iprog));
229				(void) sprintf(get_line(0, 0),
230				    "Version = %d", ivers);
231				(void) sprintf(get_line(0, 0),
232				    "Proc    = %d", iproc);
233				(void) showxdr_u_long("Callit data = %d bytes");
234				show_trailer();
235				trailer_done = 1;
236				data += 16; /* prog+ver+proc+len */
237				len -= 16;
238				protoprint(flags, type, xid,
239				    iprog, ivers, iproc,
240				    data, len);
241				break;
242			}
243		} else {
244			switch (proc) {
245			case PMAPPROC_NULL:
246			case PMAPPROC_SET:
247			case PMAPPROC_UNSET:
248				break;
249			case PMAPPROC_GETPORT:
250				(void) showxdr_u_long("Port = %d");
251				break;
252			case PMAPPROC_DUMP:
253				show_pmaplist();
254				break;
255			case PMAPPROC_CALLIT:
256				(void) showxdr_u_long("Port = %d");
257				(void) showxdr_u_long("Length = %d bytes");
258				show_trailer();
259				trailer_done = 1;
260				if (x != NULL) {
261					protoprint(flags, type, xid,
262					    x->xid_prog,
263					    x->xid_vers,
264					    x->xid_proc,
265					    data, len);
266				}
267				break;
268			}
269		}
270		if (!trailer_done)
271			show_trailer();
272	}
273}
274
275char *
276sum_pmaplist()
277{
278	int maps = 0;
279	static char buff[16];
280
281	if (setjmp(xdr_err)) {
282		(void) sprintf(buff, "%d+ map(s) found", maps);
283		return (buff);
284	}
285
286	while (getxdr_u_long()) {
287		(void) getxdr_u_long();	/* program */
288		(void) getxdr_u_long();	/* version */
289		(void) getxdr_u_long();	/* protocol */
290		(void) getxdr_u_long();	/* port */
291		maps++;
292	}
293
294	(void) sprintf(buff, "%d map(s) found", maps);
295	return (buff);
296}
297
298void
299show_pmaplist()
300{
301	unsigned prog, vers, proto, port;
302	int maps = 0;
303
304	if (setjmp(xdr_err)) {
305		(void) sprintf(get_line(0, 0),
306		    " %d+ maps. (Frame is incomplete)",
307		    maps);
308		return;
309	}
310
311	(void) sprintf(get_line(0, 0), " Program Version Protocol   Port");
312
313	while (getxdr_u_long()) {
314		prog  = getxdr_u_long();
315		vers  = getxdr_u_long();
316		proto = getxdr_u_long();
317		port  = getxdr_u_long();
318		(void) sprintf(get_line(0, 0),
319		    "%8d%8d%9d%7d  %s",
320		    prog, vers, proto, port, nameof_prog(prog));
321		maps++;
322	}
323
324	(void) sprintf(get_line(0, 0), " %d maps", maps);
325}
326
327/*
328 * ******************************************
329 */
330char *sum_rpcblist();
331void show_rpcblist();
332char *sum_rpcb_entry_list();
333void show_rpcb_entry_list();
334
335static char *procnames_short_4[] = {
336	/*
337	 * version 3 and 4 procs
338	 */
339	"Null",		/* 0 */
340	"SET",		/* 1 */
341	"UNSET",	/* 2 */
342	"GETADDR",	/* 3 */
343	"DUMP",		/* 4 */
344	"BCAST",	/* 5 */
345	"GETTIME",	/* 6 */
346	"UADDR2TADDR",	/* 7 */
347	"TADDR2UADDR",	/* 8 */
348	/*
349	 * version 4 procs only
350	 */
351	"GETVERSADDR",	/* 9 */
352	"INDIRECT",	/* 10 */
353	"GETADDRLIST",	/* 11 */
354	"GETSTAT",	/* 12 */
355};
356
357static char *procnames_long_4[] = {
358	/*
359	 * version 3 and 4 procs
360	 */
361	"Null procedure",			/* 0 */
362	"Set address",				/* 1 */
363	"Unset address",			/* 2 */
364	"Get address",				/* 3 */
365	"Dump the mappings",			/* 4 */
366	"Broadcast call (no error)",		/* 5 */
367	"Get the time",				/* 6 */
368	"Universal to transport address",	/* 7 */
369	"Transport to universal address",	/* 8 */
370	/*
371	 * version 4 procs only
372	 */
373	"Get address of specific version",	/* 9 */
374	"Indirect call (return error)",		/* 10 */
375	"Return addresses of prog/vers",	/* 11 */
376	"Get statistics",			/* 12 */
377};
378
379#define	MAXPROC_3		8
380#define	MAXPROC_4		12
381#define	RPCBPROC_NULL		0
382
383void
384interpret_pmap_4(flags, type, xid, vers, proc, data, len)
385	int flags, type, xid, vers, proc;
386	char *data;
387	int len;
388{
389	char *line;
390	unsigned prog, ver;
391	char buff1[MAXSTRINGLEN + 1];
392	int iprog, ivers, iproc, ilen;
393	extern int pi_frame;
394	struct cache_struct *x, *find_callit();
395	int trailer_done = 0;
396
397	if (proc < 0 || proc > MAXPROC_4 || (vers == 3 && proc > MAXPROC_3))
398		return;
399
400	if (proc == RPCBPROC_BCAST || proc == RPCBPROC_INDIRECT) {
401		if (type == CALL) {
402			iprog = getxdr_u_long();
403			ivers = getxdr_u_long();
404			iproc = getxdr_u_long();
405			stash_callit(xid, pi_frame,
406				iprog, ivers, iproc);
407		} else {
408			x = find_callit(xid);
409		}
410	}
411
412	if (flags & F_SUM) {
413		if (setjmp(xdr_err)) {
414			return;
415		}
416
417		line = get_sum_line();
418
419		if (type == CALL) {
420			(void) sprintf(line,
421				"RPCBIND C %s",
422				procnames_short_4[proc]);
423			line += strlen(line);
424			switch (proc) {
425			case RPCBPROC_SET:
426			case RPCBPROC_UNSET:
427			case RPCBPROC_GETADDR:
428			case RPCBPROC_GETVERSADDR:
429			case RPCBPROC_GETADDRLIST:
430				prog = getxdr_u_long();
431				ver  = getxdr_u_long();
432				(void) sprintf(line,
433					" prog=%d (%s) vers=%d",
434					prog, nameof_prog(prog),
435					ver);
436				break;
437			case RPCBPROC_BCAST:
438			case RPCBPROC_INDIRECT:
439				(void) sprintf(line,
440					" prog=%s vers=%d proc=%d",
441					nameof_prog(iprog),
442					ivers, iproc);
443				if (flags & F_ALLSUM) {
444					(void) getxdr_u_long(); /* length */
445					data += 16; /* prog+ver+proc+len */
446					len -= 16;
447					protoprint(flags, type, xid,
448						iprog, ivers, iproc,
449						data, len);
450				}
451				break;
452			default:
453				break;
454			}
455
456			check_retransmit(line, xid);
457		} else {
458			int pos;
459
460			(void) sprintf(line, "RPCBIND R %s ",
461				procnames_short_4[proc]);
462			line += strlen(line);
463			switch (proc) {
464			case RPCBPROC_GETADDR:
465			case RPCBPROC_TADDR2UADDR:
466			case RPCBPROC_GETVERSADDR:
467				(void) getxdr_string(buff1, MAXSTRINGLEN);
468				(void) sprintf(line,
469					" Uaddr=%s",
470					buff1);
471				break;
472			case RPCBPROC_BCAST:
473			case RPCBPROC_INDIRECT:
474				pos = getxdr_pos();
475				(void) getxdr_string(buff1, MAXSTRINGLEN);
476				ilen = getxdr_u_long();
477				(void) sprintf(line, "Uaddr=%s len=%d",
478					buff1, ilen);
479				if (flags & F_ALLSUM && x != NULL) {
480					pos = getxdr_pos() - pos;
481					data += pos; /* uaddr+len */
482					len -= pos;
483					protoprint(flags, type, xid,
484						x->xid_prog,
485						x->xid_vers,
486						x->xid_proc,
487						data, len);
488				}
489				break;
490			case RPCBPROC_DUMP:
491				(void) sprintf(line, "%s",
492					sum_rpcblist());
493				break;
494			case RPCBPROC_GETTIME:
495				{
496					time_t sec = getxdr_long();
497					struct tm *tmp = gmtime(&sec);
498					(void) strftime(line, MAXLINE,
499					    "%d-%h-%y %T GMT", tmp);
500				}
501				break;
502			case RPCBPROC_GETADDRLIST:
503				(void) sprintf(line, "%s",
504					sum_rpcb_entry_list());
505				break;
506			default:
507				break;
508			}
509		}
510	}
511
512	if (flags & F_DTAIL) {
513		show_header("RPCB:  ", "RPC Bind", len);
514		show_space();
515		if (setjmp(xdr_err)) {
516			return;
517		}
518		(void) sprintf(get_line(0, 0),
519			"Proc = %d (%s)",
520			proc, procnames_long_4[proc]);
521		if (type == CALL) {
522			switch (proc) {
523			case RPCBPROC_NULL:
524				break;
525			case RPCBPROC_SET:
526			case RPCBPROC_UNSET:
527			case RPCBPROC_GETADDR:
528			case RPCBPROC_GETVERSADDR:
529			case RPCBPROC_GETADDRLIST:
530				(void) showxdr_u_long("Program = %d");
531				(void) showxdr_u_long("Version = %d");
532				(void) showxdr_string(64, "Netid   = %s");
533				break;
534			case RPCBPROC_DUMP:
535				break;
536			case RPCBPROC_BCAST:
537			case RPCBPROC_INDIRECT:
538				(void) sprintf(get_line(0, 0),
539					"Program = %d (%s)",
540					iprog, nameof_prog(iprog));
541				(void) sprintf(get_line(0, 0),
542					"Version = %d", ivers);
543				(void) sprintf(get_line(0, 0),
544					"Proc    = %d", iproc);
545				(void) showxdr_u_long(
546					"Callit data = %d bytes");
547				show_trailer();
548				trailer_done = 1;
549				data += 16; /* prog+ver+proc+len */
550				len -= 16;
551				protoprint(flags, type, xid,
552					iprog, ivers, iproc,
553					data, len);
554				break;
555			case RPCBPROC_GETTIME:
556				break;
557			case RPCBPROC_UADDR2TADDR:
558			case RPCBPROC_TADDR2UADDR:
559				break;
560			}
561		} else {
562			switch (proc) {
563			case RPCBPROC_NULL:
564			case RPCBPROC_SET:
565			case RPCBPROC_UNSET:
566				break;
567			case RPCBPROC_GETADDR:
568			case RPCBPROC_TADDR2UADDR:
569			case RPCBPROC_GETVERSADDR:
570				(void) showxdr_string(64, "Uaddr = %s");
571				break;
572			case RPCBPROC_DUMP:
573				show_rpcblist();
574				break;
575			case RPCBPROC_BCAST:
576			case RPCBPROC_INDIRECT:
577				(void) showxdr_string(64, "Uaddr = %s");
578				(void) showxdr_u_long("Length = %d bytes");
579				show_trailer();
580				trailer_done = 1;
581				if (x != NULL) {
582					protoprint(flags, type, xid,
583						x->xid_prog,
584						x->xid_vers,
585						x->xid_proc,
586						data, len);
587				}
588				break;
589			case RPCBPROC_GETTIME:
590				{
591					int pos = getxdr_pos();
592					time_t sec = getxdr_long();
593					struct tm *tmp = gmtime(&sec);
594					(void) strftime(get_line(pos,
595					    getxdr_pos()), MAXLINE,
596					    "Time = %d-%h-%y %T GMT", tmp);
597				}
598				break;
599			case RPCBPROC_UADDR2TADDR:
600				break;
601			case RPCBPROC_GETADDRLIST:
602				show_rpcb_entry_list();
603				break;
604			}
605		}
606		if (!trailer_done)
607			show_trailer();
608	}
609}
610
611char *
612sum_rpcblist()
613{
614	int maps = 0;
615	static char buff[MAXSTRINGLEN + 1];
616
617	if (setjmp(xdr_err)) {
618		(void) sprintf(buff, "%d+ map(s) found", maps);
619		return (buff);
620	}
621
622	while (getxdr_u_long()) {
623		(void) getxdr_u_long();		/* program */
624		(void) getxdr_u_long();		/* version */
625		(void) getxdr_string(buff, MAXSTRINGLEN); /* netid */
626		(void) getxdr_string(buff, MAXSTRINGLEN); /* uaddr */
627		(void) getxdr_string(buff, MAXSTRINGLEN); /* owner */
628		maps++;
629	}
630
631	(void) sprintf(buff, "%d map(s) found", maps);
632	return (buff);
633}
634
635void
636show_rpcblist()
637{
638	unsigned prog, vers;
639	char netid[MAXSTRINGLEN + 1], uaddr[MAXSTRINGLEN + 1];
640	char owner[MAXSTRINGLEN + 1];
641	int maps = 0;
642
643	if (setjmp(xdr_err)) {
644		(void) sprintf(get_line(0, 0),
645		    " %d+ maps. (Frame is incomplete)",
646		    maps);
647		return;
648	}
649
650	show_space();
651	(void) sprintf(get_line(0, 0),
652	    " Program Vers Netid        Uaddr              Owner");
653
654	while (getxdr_u_long()) {
655		prog  = getxdr_u_long();
656		vers  = getxdr_u_long();
657		(void) getxdr_string(netid, MAXSTRINGLEN);
658		(void) getxdr_string(uaddr, MAXSTRINGLEN);
659		(void) getxdr_string(owner, MAXSTRINGLEN);
660		(void) sprintf(get_line(0, 0),
661		    "%8d%5d %-12s %-18s %-10s (%s)",
662		    prog, vers,
663		    netid, uaddr, owner,
664		    nameof_prog(prog));
665		maps++;
666	}
667
668	(void) sprintf(get_line(0, 0), " (%d maps)", maps);
669}
670
671char *
672sum_rpcb_entry_list()
673{
674	int maps = 0;
675	static char buff[MAXSTRINGLEN + 1];
676
677	if (setjmp(xdr_err)) {
678		(void) sprintf(buff, "%d+ map(s) found", maps);
679		return (buff);
680	}
681
682	while (getxdr_u_long()) {
683		(void) getxdr_string(buff, MAXSTRINGLEN); /* maddr	*/
684		(void) getxdr_string(buff, MAXSTRINGLEN); /* nc_netid	*/
685		(void) getxdr_u_long();			  /* nc_semantics */
686		(void) getxdr_string(buff, MAXSTRINGLEN); /* nc_protofmly */
687		(void) getxdr_string(buff, MAXSTRINGLEN); /* nc_proto	*/
688		maps++;
689	}
690
691	(void) sprintf(buff, "%d map(s) found", maps);
692	return (buff);
693}
694
695char *semantics_strs[] = {"", "CLTS", "COTS", "COTS-ORD", "RAW"};
696
697void
698show_rpcb_entry_list()
699{
700	char maddr[MAXSTRINGLEN + 1], netid[MAXSTRINGLEN + 1];
701	char protofmly[MAXSTRINGLEN + 1], proto[MAXSTRINGLEN + 1];
702	unsigned sem;
703	int maps = 0;
704
705	if (setjmp(xdr_err)) {
706		(void) sprintf(get_line(0, 0),
707		    " %d+ maps. (Frame is incomplete)",
708		    maps);
709		return;
710	}
711
712	show_space();
713	(void) sprintf(get_line(0, 0),
714	    " Maddr      Netid        Semantics Protofmly Proto");
715
716	while (getxdr_u_long()) {
717		(void) getxdr_string(maddr, MAXSTRINGLEN);
718		(void) getxdr_string(netid, MAXSTRINGLEN);
719		sem  = getxdr_u_long();
720		(void) getxdr_string(protofmly, MAXSTRINGLEN);
721		(void) getxdr_string(proto, MAXSTRINGLEN);
722		(void) sprintf(get_line(0, 0),
723		    "%-12s %-12s %-8s %-8s %-8s",
724		    maddr, netid,
725		    semantics_strs[sem],
726		    protofmly, proto);
727		maps++;
728	}
729
730	(void) sprintf(get_line(0, 0), " (%d maps)", maps);
731}
732
733#define	CXID_CACHE_SIZE	16
734struct cache_struct cxid_cache[CXID_CACHE_SIZE];
735struct cache_struct *cxcpfirst	= &cxid_cache[0];
736struct cache_struct *cxcp	= &cxid_cache[0];
737struct cache_struct *cxcplast   = &cxid_cache[CXID_CACHE_SIZE - 1];
738
739struct cache_struct *
740find_callit(xid)
741	ulong_t xid;
742{
743	struct cache_struct *x;
744
745	for (x = cxcp; x >= cxcpfirst; x--)
746		if (x->xid_num == xid)
747			return (x);
748	for (x = cxcplast; x > cxcp; x--)
749		if (x->xid_num == xid)
750			return (x);
751	return (NULL);
752}
753
754static void
755stash_callit(xid, frame, prog, vers, proc)
756	ulong_t xid;
757	int frame, prog, vers, proc;
758{
759	struct cache_struct *x;
760
761	x = find_callit(xid);
762	if (x == NULL) {
763		x = cxcp++;
764		if (cxcp > cxcplast)
765			cxcp = cxcpfirst;
766		x->xid_num = xid;
767		x->xid_frame = frame;
768	}
769	x->xid_prog = prog;
770	x->xid_vers = vers;
771	x->xid_proc = proc;
772}
773