xref: /freebsd/contrib/tcpdump/print-tftp.c (revision 076ad2f836d5f49dc1375f1677335a48fe0d4b82)
1 /*
2  * Copyright (c) 1990, 1991, 1993, 1994, 1995, 1996, 1997
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that: (1) source code distributions
7  * retain the above copyright notice and this paragraph in its entirety, (2)
8  * distributions including binary code include the above copyright notice and
9  * this paragraph in its entirety in the documentation or other materials
10  * provided with the distribution, and (3) all advertising materials mentioning
11  * features or use of this software display the following acknowledgement:
12  * ``This product includes software developed by the University of California,
13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14  * the University nor the names of its contributors may be used to endorse
15  * or promote products derived from this software without specific prior
16  * written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  */
21 
22 /* \summary: Trivial File Transfer Protocol (TFTP) printer */
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include <netdissect-stdinc.h>
29 
30 #include <string.h>
31 
32 #include "netdissect.h"
33 #include "extract.h"
34 
35 /*
36  * Trivial File Transfer Protocol (IEN-133)
37  */
38 
39 /*
40  * Packet types.
41  */
42 #define	RRQ	01			/* read request */
43 #define	WRQ	02			/* write request */
44 #define	DATA	03			/* data packet */
45 #define	ACK	04			/* acknowledgement */
46 #define	TFTP_ERROR	05			/* error code */
47 #define OACK	06			/* option acknowledgement */
48 
49 struct	tftphdr {
50 	unsigned short	th_opcode;		/* packet type */
51 	union {
52 		unsigned short	tu_block;	/* block # */
53 		unsigned short	tu_code;	/* error code */
54 		char	tu_stuff[1];	/* request packet stuff */
55 	} th_u;
56 	char	th_data[1];		/* data or error string */
57 };
58 
59 #define	th_block	th_u.tu_block
60 #define	th_code		th_u.tu_code
61 #define	th_stuff	th_u.tu_stuff
62 #define	th_msg		th_data
63 
64 /*
65  * Error codes.
66  */
67 #define	EUNDEF		0		/* not defined */
68 #define	ENOTFOUND	1		/* file not found */
69 #define	EACCESS		2		/* access violation */
70 #define	ENOSPACE	3		/* disk full or allocation exceeded */
71 #define	EBADOP		4		/* illegal TFTP operation */
72 #define	EBADID		5		/* unknown transfer ID */
73 #define	EEXISTS		6		/* file already exists */
74 #define	ENOUSER		7		/* no such user */
75 
76 static const char tstr[] = " [|tftp]";
77 
78 /* op code to string mapping */
79 static const struct tok op2str[] = {
80 	{ RRQ,		"RRQ" },	/* read request */
81 	{ WRQ,		"WRQ" },	/* write request */
82 	{ DATA,		"DATA" },	/* data packet */
83 	{ ACK,		"ACK" },	/* acknowledgement */
84 	{ TFTP_ERROR,	"ERROR" },	/* error code */
85 	{ OACK,		"OACK" },	/* option acknowledgement */
86 	{ 0,		NULL }
87 };
88 
89 /* error code to string mapping */
90 static const struct tok err2str[] = {
91 	{ EUNDEF,	"EUNDEF" },	/* not defined */
92 	{ ENOTFOUND,	"ENOTFOUND" },	/* file not found */
93 	{ EACCESS,	"EACCESS" },	/* access violation */
94 	{ ENOSPACE,	"ENOSPACE" },	/* disk full or allocation exceeded */
95 	{ EBADOP,	"EBADOP" },	/* illegal TFTP operation */
96 	{ EBADID,	"EBADID" },	/* unknown transfer ID */
97 	{ EEXISTS,	"EEXISTS" },	/* file already exists */
98 	{ ENOUSER,	"ENOUSER" },	/* no such user */
99 	{ 0,		NULL }
100 };
101 
102 /*
103  * Print trivial file transfer program requests
104  */
105 void
106 tftp_print(netdissect_options *ndo,
107            register const u_char *bp, u_int length)
108 {
109 	register const struct tftphdr *tp;
110 	register const char *cp;
111 	register const u_char *p;
112 	register int opcode;
113 	u_int ui;
114 
115 	tp = (const struct tftphdr *)bp;
116 
117 	/* Print length */
118 	ND_PRINT((ndo, " %d", length));
119 
120 	/* Print tftp request type */
121 	if (length < 2)
122 		goto trunc;
123 	ND_TCHECK(tp->th_opcode);
124 	opcode = EXTRACT_16BITS(&tp->th_opcode);
125 	cp = tok2str(op2str, "tftp-#%d", opcode);
126 	length -= 2;
127 	ND_PRINT((ndo, " %s", cp));
128 	/* Bail if bogus opcode */
129 	if (*cp == 't')
130 		return;
131 
132 	switch (opcode) {
133 
134 	case RRQ:
135 	case WRQ:
136 		p = (const u_char *)tp->th_stuff;
137 		if (length == 0)
138 			goto trunc;
139 		ND_PRINT((ndo, " "));
140 		/* Print filename */
141 		ND_PRINT((ndo, "\""));
142 		ui = fn_printztn(ndo, p, length, ndo->ndo_snapend);
143 		ND_PRINT((ndo, "\""));
144 		if (ui == 0)
145 			goto trunc;
146 		p += ui;
147 		length -= ui;
148 
149 		/* Print the mode - RRQ and WRQ only */
150 		if (length == 0)
151 			goto trunc;	/* no mode */
152 		ND_PRINT((ndo, " "));
153 		ui = fn_printztn(ndo, p, length, ndo->ndo_snapend);
154 		if (ui == 0)
155 			goto trunc;
156 		p += ui;
157 		length -= ui;
158 
159 		/* Print options, if any */
160 		while (length != 0) {
161 			ND_TCHECK(*p);
162 			if (*p != '\0')
163 				ND_PRINT((ndo, " "));
164 			ui = fn_printztn(ndo, p, length, ndo->ndo_snapend);
165 			if (ui == 0)
166 				goto trunc;
167 			p += ui;
168 			length -= ui;
169 		}
170 		break;
171 
172 	case OACK:
173 		p = (const u_char *)tp->th_stuff;
174 		/* Print options */
175 		while (length != 0) {
176 			ND_TCHECK(*p);
177 			if (*p != '\0')
178 				ND_PRINT((ndo, " "));
179 			ui = fn_printztn(ndo, p, length, ndo->ndo_snapend);
180 			if (ui == 0)
181 				goto trunc;
182 			p += ui;
183 			length -= ui;
184 		}
185 		break;
186 
187 	case ACK:
188 	case DATA:
189 		if (length < 2)
190 			goto trunc;	/* no block number */
191 		ND_TCHECK(tp->th_block);
192 		ND_PRINT((ndo, " block %d", EXTRACT_16BITS(&tp->th_block)));
193 		break;
194 
195 	case TFTP_ERROR:
196 		/* Print error code string */
197 		if (length < 2)
198 			goto trunc;	/* no error code */
199 		ND_TCHECK(tp->th_code);
200 		ND_PRINT((ndo, " %s", tok2str(err2str, "tftp-err-#%d \"",
201 				       EXTRACT_16BITS(&tp->th_code))));
202 		length -= 2;
203 		/* Print error message string */
204 		if (length == 0)
205 			goto trunc;	/* no error message */
206 		ND_PRINT((ndo, " \""));
207 		ui = fn_printztn(ndo, (const u_char *)tp->th_data, length, ndo->ndo_snapend);
208 		ND_PRINT((ndo, "\""));
209 		if (ui == 0)
210 			goto trunc;
211 		break;
212 
213 	default:
214 		/* We shouldn't get here */
215 		ND_PRINT((ndo, "(unknown #%d)", opcode));
216 		break;
217 	}
218 	return;
219 trunc:
220 	ND_PRINT((ndo, "%s", tstr));
221 	return;
222 }
223