1 /*
2  * decode_pptp.c
3  *
4  * Microsoft PPTP MS-CHAP. Derived from Aleph One's anger.c.
5  *
6  * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
7  * Copyright (c) 2000 Aleph One <aleph1@securityfocus.com>
8  *
9  * $Id: decode_pptp.c,v 1.4 2001/03/15 08:33:02 dugsong Exp $
10  */
11 
12 #include "config.h"
13 
14 #include <sys/types.h>
15 #include <netinet/in.h>
16 #include <openssl/sha.h>
17 
18 #include <stdio.h>
19 #include <string.h>
20 
21 #include "buf.h"
22 #include "decode.h"
23 
24 struct pptp_gre_header {
25 	u_char flags;		/* bitfield */
26 	u_char ver;		/* should be PPTP_GRE_VER (enhanced GRE) */
27 	u_short protocol;	/* should be PPTP_GRE_PROTO (ppp-encaps) */
28 	u_short payload_len;	/* size of ppp payload, not inc. gre header */
29 	u_short call_id;	/* peer's call_id for this session */
30 	u_int32_t seq;		/* sequence number.  Present if S==1 */
31 	u_int32_t ack;		/* seq number of highest packet recieved by */
32 				/*  sender in this session */
33 };
34 
35 #define PPTP_GRE_PROTO	0x880B
36 #define PPTP_GRE_VER	0x1
37 
38 #define PPTP_GRE_IS_C(f) ((f) & 0x80)
39 #define PPTP_GRE_IS_R(f) ((f) & 0x40)
40 #define PPTP_GRE_IS_K(f) ((f) & 0x20)
41 #define PPTP_GRE_IS_S(f) ((f) & 0x10)
42 #define PPTP_GRE_IS_A(f) ((f) & 0x80)
43 
44 struct ppp_header {
45 	u_char address;
46 	u_char control;
47 	u_short proto;
48 };
49 
50 #define PPP_PROTO_CHAP		0xc223
51 
52 struct ppp_lcp_chap_header {
53 	u_char code;
54 	u_char ident;
55 	u_short length;
56 };
57 
58 #define PPP_CHAP_CODE_CHALLENGE	1
59 #define PPP_CHAP_CODE_RESPONSE	2
60 
61 struct ppp_chap_challenge {
62 	u_char size;
63 	union {
64 		u_char challenge_v1[8];
65 		u_char challenge_v2[16];
66 		struct {
67 			u_char lanman[24];
68 			u_char nt[24];
69 			u_char flag;
70 		} response_v1;
71 		struct {
72 			u_char peer_challenge[16];
73 			u_char reserved[8];
74 			u_char nt[24];
75 			u_char flag;
76 		} response_v2;
77 	} value;
78 	/* name */
79 };
80 
81 struct challenge {
82 	u_char version;
83 	u_char challenge[16];
84 };
85 
86 int
decode_pptp(u_char * buf,int len,u_char * obuf,int olen)87 decode_pptp(u_char *buf, int len, u_char *obuf, int olen)
88 {
89 	static struct challenge save_challenge;
90 	struct buf outbuf;
91 	struct pptp_gre_header *pgh;
92 	struct ppp_header *ppp;
93 	struct ppp_lcp_chap_header *chap;
94 	struct ppp_chap_challenge *chapch;
95 	u_short proto;
96 	u_char *p, name[64], digest[SHA_DIGEST_LENGTH];
97 	SHA_CTX ctx;
98 	int i, pghlen;
99 
100 	buf_init(&outbuf, obuf, olen);
101 
102 	if (len < (pghlen = sizeof(*pgh)))
103 		return (0);
104 
105 	pgh = (struct pptp_gre_header *)buf;
106 
107 	if ((pgh->ver & 0x7f) != PPTP_GRE_VER ||
108 	    ntohs(pgh->protocol) != PPTP_GRE_PROTO ||
109 	    PPTP_GRE_IS_C(pgh->flags) || PPTP_GRE_IS_R(pgh->flags) ||
110 	    PPTP_GRE_IS_K(pgh->flags) == 0 || (pgh->flags & 0xf) != 0) {
111 		return (0);
112 	}
113 	if (PPTP_GRE_IS_S(pgh->flags) == 0)
114 		return (0);
115 
116 	if (PPTP_GRE_IS_A(pgh->ver) == 0)
117 		pghlen -= sizeof(pgh->ack);
118 
119 	if (len - pghlen < ntohs(pgh->payload_len))
120 		return (0);
121 
122 	ppp = (struct ppp_header *)(pgh + 1);
123 
124 	if (ppp->address != 0xff && ppp->control != 0x3) {
125 		proto = pntohs(ppp);
126 		chap = (struct ppp_lcp_chap_header *)
127 			((u_char *)ppp + sizeof(proto));
128 	}
129 	else {
130 		proto = ntohs(ppp->proto);
131 		chap = (struct ppp_lcp_chap_header *)(ppp + 1);
132 	}
133 	if (proto != PPP_PROTO_CHAP)
134 		return (0);
135 
136 	switch (chap->code) {
137 
138 	case PPP_CHAP_CODE_CHALLENGE:
139 		chapch = (struct ppp_chap_challenge *)(chap + 1);
140 
141 		if (chapch->size == 8) {
142 			save_challenge.version = 1;
143 			memcpy(save_challenge.challenge,
144 			       chapch->value.challenge_v1, 8);
145 		}
146 		else if (chapch->size == 16) {
147 			save_challenge.version = 2;
148 			memcpy(save_challenge.challenge,
149 			       chapch->value.challenge_v2, 16);
150 		}
151 		else save_challenge.version = 0;
152 		break;
153 
154 	case PPP_CHAP_CODE_RESPONSE:
155 		if (save_challenge.version == 0)
156 			break;
157 
158 		chapch = (struct ppp_chap_challenge *)(chap + 1);
159 		i = ntohs(chap->length) - 54;
160 		if (i > 63) i = 63;
161 		memcpy(name, (u_char *)chap + 54, i);
162 		name[i] = '\0';
163 
164 		buf_putf(&outbuf, "%s:0:", name);
165 
166 		if (save_challenge.version == 1) {
167 			for (i = 0; i < 8; i++) {
168 				buf_putf(&outbuf, "%02X",
169 					 save_challenge.challenge[i]);
170 			}
171 			buf_put(&outbuf, ":", 1);
172 
173 			for (i = 0; i < 24; i++) {
174 				buf_putf(&outbuf, "%02X",
175 					 chapch->value.response_v1.lanman[i]);
176 			}
177 			buf_put(&outbuf, ":", 1);
178 
179 			for (i = 0; i < 24; i++) {
180 				buf_putf(&outbuf, "%02X",
181 					 chapch->value.response_v1.nt[i]);
182 			}
183 			buf_put(&outbuf, "\n", 1);
184 		}
185 		else if (save_challenge.version == 2) {
186 			chapch = (struct ppp_chap_challenge *)(chap + 1);
187 			if ((p = strchr(name, '\\')) == NULL)
188 				p = name;
189 
190 			SHA1_Init(&ctx);
191 			SHA1_Update(&ctx, chapch->value.response_v2.peer_challenge, 16);
192 			SHA1_Update(&ctx, save_challenge.challenge, 16);
193 			SHA1_Update(&ctx, p, strlen(p));
194 			SHA1_Final(digest, &ctx);
195 
196 			for (i = 0; i < 8; i++) {
197 				buf_putf(&outbuf, "%02X", digest[i]);
198 			}
199 			buf_putf(&outbuf, ":000000000000000000000000000000000000000000000000:");
200 			for (i = 0; i < 24; i++) {
201 				buf_putf(&outbuf, "%02X",
202 					 chapch->value.response_v2.nt[i]);
203 			}
204 			buf_put(&outbuf, "\n", 1);
205 
206 			save_challenge.version = 0;
207 		}
208 		break;
209 	}
210 	buf_end(&outbuf);
211 
212 	return (buf_len(&outbuf));
213 }
214 
215