1ba7b222eSGlenn Barry /*
2*5e01956fSGlenn Barry  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
3ba7b222eSGlenn Barry  */
4ba7b222eSGlenn Barry /*
5ba7b222eSGlenn Barry  * lib/krb5/krb/pac.c
6ba7b222eSGlenn Barry  *
7ba7b222eSGlenn Barry  * Copyright 2008 by the Massachusetts Institute of Technology.
8ba7b222eSGlenn Barry  * All Rights Reserved.
9ba7b222eSGlenn Barry  *
10ba7b222eSGlenn Barry  * Export of this software from the United States of America may
11ba7b222eSGlenn Barry  *   require a specific license from the United States Government.
12ba7b222eSGlenn Barry  *   It is the responsibility of any person or organization contemplating
13ba7b222eSGlenn Barry  *   export to obtain such a license before exporting.
14ba7b222eSGlenn Barry  *
15ba7b222eSGlenn Barry  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
16ba7b222eSGlenn Barry  * distribute this software and its documentation for any purpose and
17ba7b222eSGlenn Barry  * without fee is hereby granted, provided that the above copyright
18ba7b222eSGlenn Barry  * notice appear in all copies and that both that copyright notice and
19ba7b222eSGlenn Barry  * this permission notice appear in supporting documentation, and that
20ba7b222eSGlenn Barry  * the name of M.I.T. not be used in advertising or publicity pertaining
21ba7b222eSGlenn Barry  * to distribution of the software without specific, written prior
22ba7b222eSGlenn Barry  * permission.  Furthermore if you modify this software you must label
23ba7b222eSGlenn Barry  * your software as modified software and not distribute it in such a
24ba7b222eSGlenn Barry  * fashion that it might be confused with the original M.I.T. software.
25ba7b222eSGlenn Barry  * M.I.T. makes no representations about the suitability of
26ba7b222eSGlenn Barry  * this software for any purpose.  It is provided "as is" without express
27ba7b222eSGlenn Barry  * or implied warranty.
28ba7b222eSGlenn Barry  *
29ba7b222eSGlenn Barry  */
30ba7b222eSGlenn Barry 
31ba7b222eSGlenn Barry #include "k5-int.h"
32ba7b222eSGlenn Barry #include "k5-utf8.h"
33ba7b222eSGlenn Barry 
34ba7b222eSGlenn Barry /* draft-brezak-win2k-krb-authz-00 */
35ba7b222eSGlenn Barry 
36ba7b222eSGlenn Barry /*
37ba7b222eSGlenn Barry  * A PAC consists of a sequence of PAC_INFO_BUFFERs, preceeded by
38ba7b222eSGlenn Barry  * a PACTYPE header. Decoding the contents of the buffers is left
39ba7b222eSGlenn Barry  * to the application (notwithstanding signature verification).
40ba7b222eSGlenn Barry  */
41ba7b222eSGlenn Barry 
42ba7b222eSGlenn Barry /*
43ba7b222eSGlenn Barry  * SUNW17PACresync
44ba7b222eSGlenn Barry  * These should eventually go to k5-platform.h or equiv.
45ba7b222eSGlenn Barry  */
46ba7b222eSGlenn Barry static inline unsigned short
load_16_le(const void * cvp)47ba7b222eSGlenn Barry load_16_le (const void *cvp)
48ba7b222eSGlenn Barry {
49ba7b222eSGlenn Barry     const unsigned char *p = cvp;
50ba7b222eSGlenn Barry #if defined(__GNUC__) && defined(K5_LE)
51ba7b222eSGlenn Barry     return GET(16,p);
52ba7b222eSGlenn Barry #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP16)
53ba7b222eSGlenn Barry     return GETSWAPPED(16,p);
54ba7b222eSGlenn Barry #else
55ba7b222eSGlenn Barry     return (p[0] | (p[1] << 8));
56ba7b222eSGlenn Barry #endif
57ba7b222eSGlenn Barry }
58ba7b222eSGlenn Barry 
59ba7b222eSGlenn Barry static inline unsigned int
load_32_le(const void * cvp)60ba7b222eSGlenn Barry load_32_le (const void *cvp)
61ba7b222eSGlenn Barry {
62ba7b222eSGlenn Barry     const unsigned char *p = cvp;
63ba7b222eSGlenn Barry #if defined(__GNUC__) && defined(K5_LE)
64ba7b222eSGlenn Barry     return GET(32,p);
65ba7b222eSGlenn Barry #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP32)
66ba7b222eSGlenn Barry     return GETSWAPPED(32,p);
67ba7b222eSGlenn Barry #else
68ba7b222eSGlenn Barry     return (p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24));
69ba7b222eSGlenn Barry #endif
70ba7b222eSGlenn Barry }
71ba7b222eSGlenn Barry static inline UINT64_TYPE
load_64_le(const void * cvp)72ba7b222eSGlenn Barry load_64_le (const void *cvp)
73ba7b222eSGlenn Barry {
74ba7b222eSGlenn Barry     const unsigned char *p = cvp;
75ba7b222eSGlenn Barry #if defined(__GNUC__) && defined(K5_LE)
76ba7b222eSGlenn Barry     return GET(64,p);
77ba7b222eSGlenn Barry #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP64)
78ba7b222eSGlenn Barry     return GETSWAPPED(64,p);
79ba7b222eSGlenn Barry #else
80ba7b222eSGlenn Barry     return ((UINT64_TYPE)load_32_le(p+4) << 32) | load_32_le(p);
81ba7b222eSGlenn Barry #endif
82ba7b222eSGlenn Barry }
83ba7b222eSGlenn Barry 
84ba7b222eSGlenn Barry static inline void
store_16_le(unsigned int val,void * vp)85ba7b222eSGlenn Barry store_16_le (unsigned int val, void *vp)
86ba7b222eSGlenn Barry {
87ba7b222eSGlenn Barry     unsigned char *p = vp;
88ba7b222eSGlenn Barry #if defined(__GNUC__) && defined(K5_LE)
89ba7b222eSGlenn Barry     PUT(16,p,val);
90ba7b222eSGlenn Barry #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP16)
91ba7b222eSGlenn Barry     PUTSWAPPED(16,p,val);
92ba7b222eSGlenn Barry #else
93ba7b222eSGlenn Barry     p[1] = (val >>  8) & 0xff;
94ba7b222eSGlenn Barry     p[0] = (val      ) & 0xff;
95ba7b222eSGlenn Barry #endif
96ba7b222eSGlenn Barry }
97ba7b222eSGlenn Barry 
98ba7b222eSGlenn Barry static inline void
store_32_le(unsigned int val,void * vp)99ba7b222eSGlenn Barry store_32_le (unsigned int val, void *vp)
100ba7b222eSGlenn Barry {
101ba7b222eSGlenn Barry     unsigned char *p = vp;
102ba7b222eSGlenn Barry #if defined(__GNUC__) && defined(K5_LE)
103ba7b222eSGlenn Barry     PUT(32,p,val);
104ba7b222eSGlenn Barry #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP32)
105ba7b222eSGlenn Barry     PUTSWAPPED(32,p,val);
106ba7b222eSGlenn Barry #else
107ba7b222eSGlenn Barry     p[3] = (val >> 24) & 0xff;
108ba7b222eSGlenn Barry     p[2] = (val >> 16) & 0xff;
109ba7b222eSGlenn Barry     p[1] = (val >>  8) & 0xff;
110ba7b222eSGlenn Barry     p[0] = (val      ) & 0xff;
111ba7b222eSGlenn Barry #endif
112ba7b222eSGlenn Barry }
113ba7b222eSGlenn Barry static inline void
store_64_le(UINT64_TYPE val,void * vp)114ba7b222eSGlenn Barry store_64_le (UINT64_TYPE val, void *vp)
115ba7b222eSGlenn Barry {
116ba7b222eSGlenn Barry     unsigned char *p = vp;
117ba7b222eSGlenn Barry #if defined(__GNUC__) && defined(K5_LE)
118ba7b222eSGlenn Barry     PUT(64,p,val);
119ba7b222eSGlenn Barry #elif defined(__GNUC__) && defined(K5_BE) && defined(SWAP64)
120ba7b222eSGlenn Barry     PUTSWAPPED(64,p,val);
121ba7b222eSGlenn Barry #else
122ba7b222eSGlenn Barry     p[7] = (unsigned char)((val >> 56) & 0xff);
123ba7b222eSGlenn Barry     p[6] = (unsigned char)((val >> 48) & 0xff);
124ba7b222eSGlenn Barry     p[5] = (unsigned char)((val >> 40) & 0xff);
125ba7b222eSGlenn Barry     p[4] = (unsigned char)((val >> 32) & 0xff);
126ba7b222eSGlenn Barry     p[3] = (unsigned char)((val >> 24) & 0xff);
127ba7b222eSGlenn Barry     p[2] = (unsigned char)((val >> 16) & 0xff);
128ba7b222eSGlenn Barry     p[1] = (unsigned char)((val >>  8) & 0xff);
129ba7b222eSGlenn Barry     p[0] = (unsigned char)((val      ) & 0xff);
130ba7b222eSGlenn Barry #endif
131ba7b222eSGlenn Barry }
132ba7b222eSGlenn Barry 
133ba7b222eSGlenn Barry 
134ba7b222eSGlenn Barry typedef struct _PAC_INFO_BUFFER {
135ba7b222eSGlenn Barry     krb5_ui_4 ulType;
136ba7b222eSGlenn Barry     krb5_ui_4 cbBufferSize;
137ba7b222eSGlenn Barry     krb5_ui_8 Offset;
138ba7b222eSGlenn Barry } PAC_INFO_BUFFER;
139ba7b222eSGlenn Barry 
140ba7b222eSGlenn Barry #define PAC_INFO_BUFFER_LENGTH	16
141ba7b222eSGlenn Barry 
142ba7b222eSGlenn Barry /* ulType */
143ba7b222eSGlenn Barry #define PAC_LOGON_INFO		1
144ba7b222eSGlenn Barry #define PAC_SERVER_CHECKSUM	6
145ba7b222eSGlenn Barry #define PAC_PRIVSVR_CHECKSUM	7
146ba7b222eSGlenn Barry #define PAC_CLIENT_INFO		10
147ba7b222eSGlenn Barry 
148ba7b222eSGlenn Barry typedef struct _PACTYPE {
149ba7b222eSGlenn Barry     krb5_ui_4 cBuffers;
150ba7b222eSGlenn Barry     krb5_ui_4 Version;
151ba7b222eSGlenn Barry     PAC_INFO_BUFFER Buffers[1];
152ba7b222eSGlenn Barry } PACTYPE;
153ba7b222eSGlenn Barry 
154ba7b222eSGlenn Barry #define PAC_ALIGNMENT		    8
155ba7b222eSGlenn Barry #define PACTYPE_LENGTH		    8U
156ba7b222eSGlenn Barry #define PAC_SIGNATURE_DATA_LENGTH   4U
157ba7b222eSGlenn Barry #define PAC_CLIENT_INFO_LENGTH	    10U
158ba7b222eSGlenn Barry 
159ba7b222eSGlenn Barry #define NT_TIME_EPOCH		    11644473600LL
160ba7b222eSGlenn Barry 
161ba7b222eSGlenn Barry struct krb5_pac_data {
162ba7b222eSGlenn Barry     PACTYPE *pac;	/* PAC header + info buffer array */
163ba7b222eSGlenn Barry     krb5_data data;	/* PAC data (including uninitialised header) */
164ba7b222eSGlenn Barry };
165ba7b222eSGlenn Barry 
166ba7b222eSGlenn Barry static krb5_error_code
167ba7b222eSGlenn Barry k5_pac_locate_buffer(krb5_context context,
168ba7b222eSGlenn Barry 		     const krb5_pac pac,
169ba7b222eSGlenn Barry 		     krb5_ui_4 type,
170ba7b222eSGlenn Barry 		     krb5_data *data);
171ba7b222eSGlenn Barry 
172ba7b222eSGlenn Barry /*
173ba7b222eSGlenn Barry  * Add a buffer to the provided PAC and update header.
174ba7b222eSGlenn Barry  */
175ba7b222eSGlenn Barry static krb5_error_code
k5_pac_add_buffer(krb5_context context,krb5_pac pac,krb5_ui_4 type,const krb5_data * data,krb5_boolean zerofill,krb5_data * out_data)176ba7b222eSGlenn Barry k5_pac_add_buffer(krb5_context context,
177ba7b222eSGlenn Barry 		  krb5_pac pac,
178ba7b222eSGlenn Barry 		  krb5_ui_4 type,
179ba7b222eSGlenn Barry 		  const krb5_data *data,
180ba7b222eSGlenn Barry 		  krb5_boolean zerofill,
181ba7b222eSGlenn Barry 		  krb5_data *out_data)
182ba7b222eSGlenn Barry {
183ba7b222eSGlenn Barry     PACTYPE *header;
184ba7b222eSGlenn Barry     size_t header_len, i, pad = 0;
185ba7b222eSGlenn Barry     char *pac_data;
186ba7b222eSGlenn Barry 
187ba7b222eSGlenn Barry     assert((data->data == NULL) == zerofill);
188ba7b222eSGlenn Barry 
189ba7b222eSGlenn Barry     /* Check there isn't already a buffer of this type */
190ba7b222eSGlenn Barry     if (k5_pac_locate_buffer(context, pac, type, NULL) == 0) {
191*5e01956fSGlenn Barry 	/* Solaris Kerberos */
192*5e01956fSGlenn Barry 	krb5_set_error_message(context, EINVAL,
193*5e01956fSGlenn Barry 			    "Duplicate PAC buffer of type %d",
194*5e01956fSGlenn Barry 			    type);
195ba7b222eSGlenn Barry 	return EINVAL;
196ba7b222eSGlenn Barry     }
197ba7b222eSGlenn Barry 
198ba7b222eSGlenn Barry     header = (PACTYPE *)realloc(pac->pac,
199ba7b222eSGlenn Barry 				sizeof(PACTYPE) +
200ba7b222eSGlenn Barry 				(pac->pac->cBuffers * sizeof(PAC_INFO_BUFFER)));
201ba7b222eSGlenn Barry     if (header == NULL) {
202ba7b222eSGlenn Barry 	return ENOMEM;
203ba7b222eSGlenn Barry     }
204ba7b222eSGlenn Barry     pac->pac = header;
205ba7b222eSGlenn Barry 
206ba7b222eSGlenn Barry     header_len = PACTYPE_LENGTH + (pac->pac->cBuffers * PAC_INFO_BUFFER_LENGTH);
207ba7b222eSGlenn Barry 
208ba7b222eSGlenn Barry     if (data->length % PAC_ALIGNMENT)
209ba7b222eSGlenn Barry 	pad = PAC_ALIGNMENT - (data->length % PAC_ALIGNMENT);
210ba7b222eSGlenn Barry 
211ba7b222eSGlenn Barry     pac_data = realloc(pac->data.data,
212ba7b222eSGlenn Barry 		       pac->data.length + PAC_INFO_BUFFER_LENGTH + data->length + pad);
213ba7b222eSGlenn Barry     if (pac_data == NULL) {
214ba7b222eSGlenn Barry 	return ENOMEM;
215ba7b222eSGlenn Barry     }
216ba7b222eSGlenn Barry     pac->data.data = pac_data;
217ba7b222eSGlenn Barry 
218ba7b222eSGlenn Barry     /* Update offsets of existing buffers */
219ba7b222eSGlenn Barry     for (i = 0; i < pac->pac->cBuffers; i++)
220ba7b222eSGlenn Barry 	pac->pac->Buffers[i].Offset += PAC_INFO_BUFFER_LENGTH;
221ba7b222eSGlenn Barry 
222ba7b222eSGlenn Barry     /* Make room for new PAC_INFO_BUFFER */
223ba7b222eSGlenn Barry     memmove(pac->data.data + header_len + PAC_INFO_BUFFER_LENGTH,
224ba7b222eSGlenn Barry 	    pac->data.data + header_len,
225ba7b222eSGlenn Barry 	    pac->data.length - header_len);
226ba7b222eSGlenn Barry     memset(pac->data.data + header_len, 0, PAC_INFO_BUFFER_LENGTH);
227ba7b222eSGlenn Barry 
228ba7b222eSGlenn Barry     /* Initialise new PAC_INFO_BUFFER */
229ba7b222eSGlenn Barry     pac->pac->Buffers[i].ulType = type;
230ba7b222eSGlenn Barry     pac->pac->Buffers[i].cbBufferSize = data->length;
231ba7b222eSGlenn Barry     pac->pac->Buffers[i].Offset = pac->data.length + PAC_INFO_BUFFER_LENGTH;
232ba7b222eSGlenn Barry     assert((pac->pac->Buffers[i].Offset % PAC_ALIGNMENT) == 0);
233ba7b222eSGlenn Barry 
234ba7b222eSGlenn Barry     /* Copy in new PAC data and zero padding bytes */
235ba7b222eSGlenn Barry     if (zerofill)
236ba7b222eSGlenn Barry 	memset(pac->data.data + pac->pac->Buffers[i].Offset, 0, data->length);
237ba7b222eSGlenn Barry     else
238ba7b222eSGlenn Barry 	memcpy(pac->data.data + pac->pac->Buffers[i].Offset, data->data, data->length);
239ba7b222eSGlenn Barry 
240ba7b222eSGlenn Barry     memset(pac->data.data + pac->pac->Buffers[i].Offset + data->length, 0, pad);
241ba7b222eSGlenn Barry 
242ba7b222eSGlenn Barry     pac->pac->cBuffers++;
243ba7b222eSGlenn Barry     pac->data.length += PAC_INFO_BUFFER_LENGTH + data->length + pad;
244ba7b222eSGlenn Barry 
245ba7b222eSGlenn Barry     if (out_data != NULL) {
246ba7b222eSGlenn Barry 	out_data->data = pac->data.data + pac->pac->Buffers[i].Offset;
247ba7b222eSGlenn Barry 	out_data->length = data->length;
248ba7b222eSGlenn Barry     }
249ba7b222eSGlenn Barry 
250ba7b222eSGlenn Barry     return 0;
251ba7b222eSGlenn Barry }
252ba7b222eSGlenn Barry 
253ba7b222eSGlenn Barry krb5_error_code KRB5_CALLCONV
krb5_pac_add_buffer(krb5_context context,krb5_pac pac,krb5_ui_4 type,const krb5_data * data)254ba7b222eSGlenn Barry krb5_pac_add_buffer(krb5_context context,
255ba7b222eSGlenn Barry 		    krb5_pac pac,
256ba7b222eSGlenn Barry 		    krb5_ui_4 type,
257ba7b222eSGlenn Barry 		    const krb5_data *data)
258ba7b222eSGlenn Barry {
259ba7b222eSGlenn Barry     return k5_pac_add_buffer(context, pac, type, data, FALSE, NULL);
260ba7b222eSGlenn Barry }
261ba7b222eSGlenn Barry 
262ba7b222eSGlenn Barry /*
263ba7b222eSGlenn Barry  * Free a PAC
264ba7b222eSGlenn Barry  */
265ba7b222eSGlenn Barry void KRB5_CALLCONV
krb5_pac_free(krb5_context context,krb5_pac pac)266ba7b222eSGlenn Barry krb5_pac_free(krb5_context context,
267ba7b222eSGlenn Barry 	      krb5_pac pac)
268ba7b222eSGlenn Barry {
269ba7b222eSGlenn Barry     if (pac != NULL) {
270ba7b222eSGlenn Barry 	if (pac->data.data != NULL) {
271ba7b222eSGlenn Barry 	    memset(pac->data.data, 0, pac->data.length);
272ba7b222eSGlenn Barry 	    free(pac->data.data);
273ba7b222eSGlenn Barry 	}
274ba7b222eSGlenn Barry 	if (pac->pac != NULL)
275ba7b222eSGlenn Barry 	    free(pac->pac);
276ba7b222eSGlenn Barry 	memset(pac, 0, sizeof(*pac));
277ba7b222eSGlenn Barry 	free(pac);
278ba7b222eSGlenn Barry     }
279ba7b222eSGlenn Barry }
280ba7b222eSGlenn Barry 
281ba7b222eSGlenn Barry static krb5_error_code
k5_pac_locate_buffer(krb5_context context,const krb5_pac pac,krb5_ui_4 type,krb5_data * data)282ba7b222eSGlenn Barry k5_pac_locate_buffer(krb5_context context,
283ba7b222eSGlenn Barry 		     const krb5_pac pac,
284ba7b222eSGlenn Barry 		     krb5_ui_4 type,
285ba7b222eSGlenn Barry 		     krb5_data *data)
286ba7b222eSGlenn Barry {
287ba7b222eSGlenn Barry     PAC_INFO_BUFFER *buffer = NULL;
288ba7b222eSGlenn Barry     size_t i;
289ba7b222eSGlenn Barry 
290*5e01956fSGlenn Barry     if (pac == NULL) {
291*5e01956fSGlenn Barry 	/* Solaris Kerberos */
292*5e01956fSGlenn Barry 	krb5_set_error_message(context, EINVAL,
293*5e01956fSGlenn Barry 			    "Invalid argument 'pac' is NULL");
294ba7b222eSGlenn Barry 	return EINVAL;
295*5e01956fSGlenn Barry     }
296ba7b222eSGlenn Barry 
297ba7b222eSGlenn Barry     for (i = 0; i < pac->pac->cBuffers; i++) {
298ba7b222eSGlenn Barry 	if (pac->pac->Buffers[i].ulType == type) {
299ba7b222eSGlenn Barry 	    if (buffer == NULL)
300ba7b222eSGlenn Barry 		buffer = &pac->pac->Buffers[i];
301*5e01956fSGlenn Barry 	    else {
302*5e01956fSGlenn Barry 	        /* Solaris Kerberos */
303*5e01956fSGlenn Barry 	        krb5_set_error_message(context, EINVAL,
304*5e01956fSGlenn Barry 				    "Invalid buffer found looping thru PAC buffers (type=%d, i=%d)",
305*5e01956fSGlenn Barry 				    type, i);
306ba7b222eSGlenn Barry 		return EINVAL;
307*5e01956fSGlenn Barry 	    }
308ba7b222eSGlenn Barry 	}
309ba7b222eSGlenn Barry     }
310ba7b222eSGlenn Barry 
311*5e01956fSGlenn Barry     if (buffer == NULL) {
312*5e01956fSGlenn Barry 	/* Solaris Kerberos */
313*5e01956fSGlenn Barry 	krb5_set_error_message(context, ENOENT,
314*5e01956fSGlenn Barry 			    "No PAC buffer found (type=%d)",
315*5e01956fSGlenn Barry 			    type);
316*5e01956fSGlenn Barry 
317ba7b222eSGlenn Barry 	return ENOENT;
318*5e01956fSGlenn Barry     }
319ba7b222eSGlenn Barry 
320ba7b222eSGlenn Barry     assert(buffer->Offset + buffer->cbBufferSize <= pac->data.length);
321ba7b222eSGlenn Barry 
322ba7b222eSGlenn Barry     if (data != NULL) {
323ba7b222eSGlenn Barry 	data->length = buffer->cbBufferSize;
324ba7b222eSGlenn Barry 	data->data = pac->data.data + buffer->Offset;
325ba7b222eSGlenn Barry     }
326ba7b222eSGlenn Barry 
327ba7b222eSGlenn Barry     return 0;
328ba7b222eSGlenn Barry }
329ba7b222eSGlenn Barry 
330ba7b222eSGlenn Barry /*
331ba7b222eSGlenn Barry  * Find a buffer and copy data into output
332ba7b222eSGlenn Barry  */
333ba7b222eSGlenn Barry krb5_error_code KRB5_CALLCONV
krb5_pac_get_buffer(krb5_context context,krb5_pac pac,krb5_ui_4 type,krb5_data * data)334ba7b222eSGlenn Barry krb5_pac_get_buffer(krb5_context context,
335ba7b222eSGlenn Barry 		    krb5_pac pac,
336ba7b222eSGlenn Barry 		    krb5_ui_4 type,
337ba7b222eSGlenn Barry 		    krb5_data *data)
338ba7b222eSGlenn Barry {
339ba7b222eSGlenn Barry     krb5_data d;
340ba7b222eSGlenn Barry     krb5_error_code ret;
341ba7b222eSGlenn Barry 
342ba7b222eSGlenn Barry     ret = k5_pac_locate_buffer(context, pac, type, &d);
343ba7b222eSGlenn Barry     if (ret != 0)
344ba7b222eSGlenn Barry 	return ret;
345ba7b222eSGlenn Barry 
346ba7b222eSGlenn Barry     data->data = malloc(d.length);
347ba7b222eSGlenn Barry     if (data->data == NULL)
348ba7b222eSGlenn Barry 	return ENOMEM;
349ba7b222eSGlenn Barry 
350ba7b222eSGlenn Barry     data->length = d.length;
351ba7b222eSGlenn Barry     memcpy(data->data, d.data, d.length);
352ba7b222eSGlenn Barry 
353ba7b222eSGlenn Barry     return 0;
354ba7b222eSGlenn Barry }
355ba7b222eSGlenn Barry 
356ba7b222eSGlenn Barry /*
357ba7b222eSGlenn Barry  * Return an array of the types of data in the PAC
358ba7b222eSGlenn Barry  */
359ba7b222eSGlenn Barry krb5_error_code KRB5_CALLCONV
krb5_pac_get_types(krb5_context context,krb5_pac pac,size_t * len,krb5_ui_4 ** types)360ba7b222eSGlenn Barry krb5_pac_get_types(krb5_context context,
361ba7b222eSGlenn Barry 		   krb5_pac pac,
362ba7b222eSGlenn Barry 		   size_t *len,
363ba7b222eSGlenn Barry 		   krb5_ui_4 **types)
364ba7b222eSGlenn Barry {
365ba7b222eSGlenn Barry     size_t i;
366ba7b222eSGlenn Barry 
367ba7b222eSGlenn Barry     *types = (krb5_ui_4 *)malloc(pac->pac->cBuffers * sizeof(krb5_ui_4));
368ba7b222eSGlenn Barry     if (*types == NULL)
369ba7b222eSGlenn Barry 	return ENOMEM;
370ba7b222eSGlenn Barry 
371ba7b222eSGlenn Barry     *len = pac->pac->cBuffers;
372ba7b222eSGlenn Barry 
373ba7b222eSGlenn Barry     for (i = 0; i < pac->pac->cBuffers; i++)
374ba7b222eSGlenn Barry 	(*types)[i] = pac->pac->Buffers[i].ulType;
375ba7b222eSGlenn Barry 
376ba7b222eSGlenn Barry     return 0;
377ba7b222eSGlenn Barry }
378ba7b222eSGlenn Barry 
379ba7b222eSGlenn Barry /*
380ba7b222eSGlenn Barry  * Initialize PAC
381ba7b222eSGlenn Barry  */
382ba7b222eSGlenn Barry krb5_error_code KRB5_CALLCONV
krb5_pac_init(krb5_context context,krb5_pac * ppac)383ba7b222eSGlenn Barry krb5_pac_init(krb5_context context,
384ba7b222eSGlenn Barry 	      krb5_pac *ppac)
385ba7b222eSGlenn Barry {
386ba7b222eSGlenn Barry     krb5_pac pac;
387ba7b222eSGlenn Barry 
388ba7b222eSGlenn Barry     pac = (krb5_pac)malloc(sizeof(*pac));
389ba7b222eSGlenn Barry     if (pac == NULL)
390ba7b222eSGlenn Barry 	return ENOMEM;
391ba7b222eSGlenn Barry 
392ba7b222eSGlenn Barry     pac->pac = (PACTYPE *)malloc(sizeof(PACTYPE));
393ba7b222eSGlenn Barry     if (pac->pac == NULL) {
394ba7b222eSGlenn Barry 	free( pac);
395ba7b222eSGlenn Barry 	return ENOMEM;
396ba7b222eSGlenn Barry     }
397ba7b222eSGlenn Barry 
398ba7b222eSGlenn Barry     pac->pac->cBuffers = 0;
399ba7b222eSGlenn Barry     pac->pac->Version = 0;
400ba7b222eSGlenn Barry 
401ba7b222eSGlenn Barry     pac->data.length = PACTYPE_LENGTH;
402ba7b222eSGlenn Barry     pac->data.data = calloc(1, pac->data.length);
403ba7b222eSGlenn Barry     if (pac->data.data == NULL) {
404ba7b222eSGlenn Barry 	krb5_pac_free(context, pac);
405ba7b222eSGlenn Barry 	return ENOMEM;
406ba7b222eSGlenn Barry     }
407ba7b222eSGlenn Barry 
408ba7b222eSGlenn Barry     *ppac = pac;
409ba7b222eSGlenn Barry 
410ba7b222eSGlenn Barry     return 0;
411ba7b222eSGlenn Barry }
412ba7b222eSGlenn Barry 
413ba7b222eSGlenn Barry /*
414ba7b222eSGlenn Barry  * Parse the supplied data into the PAC allocated by this function
415ba7b222eSGlenn Barry  */
416ba7b222eSGlenn Barry krb5_error_code KRB5_CALLCONV
krb5_pac_parse(krb5_context context,const void * ptr,size_t len,krb5_pac * ppac)417ba7b222eSGlenn Barry krb5_pac_parse(krb5_context context,
418ba7b222eSGlenn Barry 	       const void *ptr,
419ba7b222eSGlenn Barry 	       size_t len,
420ba7b222eSGlenn Barry 	       krb5_pac *ppac)
421ba7b222eSGlenn Barry {
422ba7b222eSGlenn Barry     krb5_error_code ret;
423ba7b222eSGlenn Barry     size_t i;
424ba7b222eSGlenn Barry     const unsigned char *p = (const unsigned char *)ptr;
425ba7b222eSGlenn Barry     krb5_pac pac;
426ba7b222eSGlenn Barry     size_t header_len;
427ba7b222eSGlenn Barry     krb5_ui_4 cbuffers, version;
428ba7b222eSGlenn Barry 
429ba7b222eSGlenn Barry     *ppac = NULL;
430ba7b222eSGlenn Barry 
431*5e01956fSGlenn Barry     if (len < PACTYPE_LENGTH) {
432*5e01956fSGlenn Barry 	/* Solaris Kerberos */
433*5e01956fSGlenn Barry 	krb5_set_error_message(context, ERANGE,
434*5e01956fSGlenn Barry 			    "PAC type length is out of range (len=%d)",
435*5e01956fSGlenn Barry 			    len);
436ba7b222eSGlenn Barry 	return ERANGE;
437*5e01956fSGlenn Barry     }
438ba7b222eSGlenn Barry 
439ba7b222eSGlenn Barry     cbuffers = load_32_le(p);
440ba7b222eSGlenn Barry     p += 4;
441ba7b222eSGlenn Barry     version = load_32_le(p);
442ba7b222eSGlenn Barry     p += 4;
443ba7b222eSGlenn Barry 
444*5e01956fSGlenn Barry     if (version != 0) {
445*5e01956fSGlenn Barry 	/* Solaris Kerberos */
446*5e01956fSGlenn Barry 	krb5_set_error_message(context, EINVAL,
447*5e01956fSGlenn Barry 			    "Invalid PAC version is %d, should be 0",
448*5e01956fSGlenn Barry 			    version);
449ba7b222eSGlenn Barry 	return EINVAL;
450*5e01956fSGlenn Barry     }
451ba7b222eSGlenn Barry 
452ba7b222eSGlenn Barry     header_len = PACTYPE_LENGTH + (cbuffers * PAC_INFO_BUFFER_LENGTH);
453*5e01956fSGlenn Barry     if (len < header_len) {
454*5e01956fSGlenn Barry 	/* Solaris Kerberos */
455*5e01956fSGlenn Barry 	krb5_set_error_message(context, ERANGE,
456*5e01956fSGlenn Barry 			    "PAC header len (%d) out of range",
457*5e01956fSGlenn Barry 			    len);
458ba7b222eSGlenn Barry 	return ERANGE;
459*5e01956fSGlenn Barry     }
460ba7b222eSGlenn Barry 
461ba7b222eSGlenn Barry     ret = krb5_pac_init(context, &pac);
462ba7b222eSGlenn Barry     if (ret != 0)
463ba7b222eSGlenn Barry 	return ret;
464ba7b222eSGlenn Barry 
465ba7b222eSGlenn Barry     pac->pac = (PACTYPE *)realloc(pac->pac,
466ba7b222eSGlenn Barry 	sizeof(PACTYPE) + ((cbuffers - 1) * sizeof(PAC_INFO_BUFFER)));
467ba7b222eSGlenn Barry     if (pac->pac == NULL) {
468ba7b222eSGlenn Barry 	krb5_pac_free(context, pac);
469ba7b222eSGlenn Barry 	return ENOMEM;
470ba7b222eSGlenn Barry     }
471ba7b222eSGlenn Barry 
472ba7b222eSGlenn Barry     pac->pac->cBuffers = cbuffers;
473ba7b222eSGlenn Barry     pac->pac->Version = version;
474ba7b222eSGlenn Barry 
475ba7b222eSGlenn Barry     for (i = 0; i < pac->pac->cBuffers; i++) {
476ba7b222eSGlenn Barry 	PAC_INFO_BUFFER *buffer = &pac->pac->Buffers[i];
477ba7b222eSGlenn Barry 
478ba7b222eSGlenn Barry 	buffer->ulType = load_32_le(p);
479ba7b222eSGlenn Barry 	p += 4;
480ba7b222eSGlenn Barry 	buffer->cbBufferSize = load_32_le(p);
481ba7b222eSGlenn Barry 	p += 4;
482ba7b222eSGlenn Barry 	buffer->Offset = load_64_le(p);
483ba7b222eSGlenn Barry 	p += 8;
484ba7b222eSGlenn Barry 
485ba7b222eSGlenn Barry 	if (buffer->Offset % PAC_ALIGNMENT) {
486ba7b222eSGlenn Barry 	    krb5_pac_free(context, pac);
487*5e01956fSGlenn Barry 	    /* Solaris Kerberos */
488*5e01956fSGlenn Barry 	    krb5_set_error_message(context, EINVAL,
489*5e01956fSGlenn Barry 				"PAC buffer offset mis-aligned");
490ba7b222eSGlenn Barry 	    return EINVAL;
491ba7b222eSGlenn Barry 	}
492ba7b222eSGlenn Barry 	if (buffer->Offset < header_len ||
493ba7b222eSGlenn Barry 	    buffer->Offset + buffer->cbBufferSize > len) {
494ba7b222eSGlenn Barry 	    krb5_pac_free(context, pac);
495*5e01956fSGlenn Barry 	    /* Solaris Kerberos */
496*5e01956fSGlenn Barry 	    krb5_set_error_message(context, ERANGE,
497*5e01956fSGlenn Barry 				"PAC offset is out of range");
498ba7b222eSGlenn Barry 	    return ERANGE;
499ba7b222eSGlenn Barry 	}
500ba7b222eSGlenn Barry     }
501ba7b222eSGlenn Barry 
502ba7b222eSGlenn Barry     pac->data.data = realloc(pac->data.data, len);
503ba7b222eSGlenn Barry     if (pac->data.data == NULL) {
504ba7b222eSGlenn Barry 	krb5_pac_free(context, pac);
505ba7b222eSGlenn Barry 	return ENOMEM;
506ba7b222eSGlenn Barry     }
507ba7b222eSGlenn Barry     memcpy(pac->data.data, ptr, len);
508ba7b222eSGlenn Barry 
509ba7b222eSGlenn Barry     pac->data.length = len;
510ba7b222eSGlenn Barry 
511ba7b222eSGlenn Barry     *ppac = pac;
512ba7b222eSGlenn Barry 
513ba7b222eSGlenn Barry     return 0;
514ba7b222eSGlenn Barry }
515ba7b222eSGlenn Barry 
516ba7b222eSGlenn Barry static krb5_error_code
k5_time_to_seconds_since_1970(krb5_context context,krb5_int64 ntTime,krb5_timestamp * elapsedSeconds)517*5e01956fSGlenn Barry k5_time_to_seconds_since_1970(krb5_context context, krb5_int64 ntTime, krb5_timestamp *elapsedSeconds)
518ba7b222eSGlenn Barry {
519ba7b222eSGlenn Barry     krb5_ui_8 abstime;
520ba7b222eSGlenn Barry 
521ba7b222eSGlenn Barry     ntTime /= 10000000;
522ba7b222eSGlenn Barry 
523ba7b222eSGlenn Barry     abstime = ntTime > 0 ? ntTime - NT_TIME_EPOCH : -ntTime;
524ba7b222eSGlenn Barry 
525*5e01956fSGlenn Barry     if (abstime > KRB5_INT32_MAX) {
526ba7b222eSGlenn Barry 	return ERANGE;
527*5e01956fSGlenn Barry     }
528ba7b222eSGlenn Barry 
529ba7b222eSGlenn Barry     *elapsedSeconds = abstime;
530ba7b222eSGlenn Barry 
531ba7b222eSGlenn Barry     return 0;
532ba7b222eSGlenn Barry }
533ba7b222eSGlenn Barry 
534ba7b222eSGlenn Barry static krb5_error_code
k5_seconds_since_1970_to_time(krb5_timestamp elapsedSeconds,krb5_ui_8 * ntTime)535ba7b222eSGlenn Barry k5_seconds_since_1970_to_time(krb5_timestamp elapsedSeconds, krb5_ui_8 *ntTime)
536ba7b222eSGlenn Barry {
537ba7b222eSGlenn Barry     *ntTime = elapsedSeconds;
538ba7b222eSGlenn Barry 
539ba7b222eSGlenn Barry     if (elapsedSeconds > 0)
540ba7b222eSGlenn Barry 	*ntTime += NT_TIME_EPOCH;
541ba7b222eSGlenn Barry 
542ba7b222eSGlenn Barry     *ntTime *= 10000000;
543ba7b222eSGlenn Barry 
544ba7b222eSGlenn Barry     return 0;
545ba7b222eSGlenn Barry }
546ba7b222eSGlenn Barry 
547ba7b222eSGlenn Barry static krb5_error_code
k5_pac_validate_client(krb5_context context,const krb5_pac pac,krb5_timestamp authtime,krb5_const_principal principal)548ba7b222eSGlenn Barry k5_pac_validate_client(krb5_context context,
549ba7b222eSGlenn Barry 		       const krb5_pac pac,
550ba7b222eSGlenn Barry 		       krb5_timestamp authtime,
551ba7b222eSGlenn Barry 		       krb5_const_principal principal)
552ba7b222eSGlenn Barry {
553ba7b222eSGlenn Barry     krb5_error_code ret;
554ba7b222eSGlenn Barry     krb5_data client_info;
555ba7b222eSGlenn Barry     char *pac_princname;
556ba7b222eSGlenn Barry     unsigned char *p;
557ba7b222eSGlenn Barry     krb5_timestamp pac_authtime;
558ba7b222eSGlenn Barry     krb5_ui_2 pac_princname_length;
559ba7b222eSGlenn Barry     krb5_int64 pac_nt_authtime;
560ba7b222eSGlenn Barry     krb5_principal pac_principal;
561ba7b222eSGlenn Barry 
562ba7b222eSGlenn Barry     ret = k5_pac_locate_buffer(context, pac, PAC_CLIENT_INFO, &client_info);
563ba7b222eSGlenn Barry     if (ret != 0)
564ba7b222eSGlenn Barry 	return ret;
565ba7b222eSGlenn Barry 
566*5e01956fSGlenn Barry     if (client_info.length < PAC_CLIENT_INFO_LENGTH) {
567*5e01956fSGlenn Barry 	/* Solaris Kerberos */
568*5e01956fSGlenn Barry 	krb5_set_error_message(context, ERANGE,
569*5e01956fSGlenn Barry 			    "PAC client info length out of range",
570*5e01956fSGlenn Barry 			    client_info.length);
571ba7b222eSGlenn Barry 	return ERANGE;
572*5e01956fSGlenn Barry     }
573ba7b222eSGlenn Barry 
574ba7b222eSGlenn Barry     p = (unsigned char *)client_info.data;
575ba7b222eSGlenn Barry     pac_nt_authtime = load_64_le(p);
576ba7b222eSGlenn Barry     p += 8;
577ba7b222eSGlenn Barry     pac_princname_length = load_16_le(p);
578ba7b222eSGlenn Barry     p += 2;
579ba7b222eSGlenn Barry 
580*5e01956fSGlenn Barry     ret = k5_time_to_seconds_since_1970(context, pac_nt_authtime, &pac_authtime);
581ba7b222eSGlenn Barry     if (ret != 0)
582ba7b222eSGlenn Barry 	return ret;
583ba7b222eSGlenn Barry 
584ba7b222eSGlenn Barry     if (client_info.length < PAC_CLIENT_INFO_LENGTH + pac_princname_length ||
585*5e01956fSGlenn Barry         pac_princname_length % 2) {
586*5e01956fSGlenn Barry 	/* Solaris Kerberos */
587*5e01956fSGlenn Barry 	krb5_set_error_message(context, ERANGE,
588*5e01956fSGlenn Barry 			    "PAC client info length is out of range");
589ba7b222eSGlenn Barry 	return ERANGE;
590*5e01956fSGlenn Barry     }
591ba7b222eSGlenn Barry 
592ba7b222eSGlenn Barry     ret = krb5int_ucs2lecs_to_utf8s(p, (size_t)pac_princname_length / 2, &pac_princname, NULL);
593ba7b222eSGlenn Barry     if (ret != 0)
594ba7b222eSGlenn Barry 	return ret;
595ba7b222eSGlenn Barry 
596ba7b222eSGlenn Barry     ret = krb5_parse_name_flags(context, pac_princname, 0, &pac_principal);
597ba7b222eSGlenn Barry     if (ret != 0) {
598ba7b222eSGlenn Barry 	free(pac_princname);
599ba7b222eSGlenn Barry 	return ret;
600ba7b222eSGlenn Barry     }
601ba7b222eSGlenn Barry 
602ba7b222eSGlenn Barry 
603*5e01956fSGlenn Barry     if (pac_authtime != authtime) {
604*5e01956fSGlenn Barry 	/* Solaris Kerberos */
605*5e01956fSGlenn Barry 	char timestring[17];
606*5e01956fSGlenn Barry 	char pac_timestring[17];
607*5e01956fSGlenn Barry 	char fill = ' ';
608*5e01956fSGlenn Barry 	int err, pac_err;
609*5e01956fSGlenn Barry 	/* Need better ret code here but don't see one */
610ba7b222eSGlenn Barry 	ret = KRB5KRB_AP_WRONG_PRINC;
611*5e01956fSGlenn Barry 	err = krb5_timestamp_to_sfstring(pac_authtime,
612*5e01956fSGlenn Barry 					timestring,
613*5e01956fSGlenn Barry 					sizeof (timestring), &fill);
614*5e01956fSGlenn Barry 	pac_err = krb5_timestamp_to_sfstring(pac_authtime,
615*5e01956fSGlenn Barry 					pac_timestring,
616*5e01956fSGlenn Barry 					    sizeof (pac_timestring), &fill);
617*5e01956fSGlenn Barry 	if (pac_princname && !err && !pac_err) {
618*5e01956fSGlenn Barry 	    krb5_set_error_message(context, ret,
619*5e01956fSGlenn Barry 				"PAC verify fail: PAC authtime '%s' does not match authtime '%s'.  PAC principal is '%s'",
620*5e01956fSGlenn Barry 				pac_timestring, timestring, pac_princname);
621*5e01956fSGlenn Barry 	}
622*5e01956fSGlenn Barry     } else if (krb5_principal_compare(context, pac_principal, principal) == FALSE) {
623*5e01956fSGlenn Barry 	/* Solaris Kerberos */
624*5e01956fSGlenn Barry 	char *p_name = NULL;
625*5e01956fSGlenn Barry 	krb5_error_code perr;
626*5e01956fSGlenn Barry 	ret = KRB5KRB_AP_WRONG_PRINC;
627*5e01956fSGlenn Barry 	perr = krb5_unparse_name(context, principal, &p_name);
628*5e01956fSGlenn Barry 	if (pac_princname && !perr) {
629*5e01956fSGlenn Barry 	    krb5_set_error_message(context, ret,
630*5e01956fSGlenn Barry 				"Wrong principal in request: PAC verify: Principal in PAC is '%s' and does not match '%s'",
631*5e01956fSGlenn Barry 				pac_princname, p_name);
632*5e01956fSGlenn Barry 	}
633*5e01956fSGlenn Barry 	if (p_name)
634*5e01956fSGlenn Barry 	    krb5_free_unparsed_name(context, p_name);
635*5e01956fSGlenn Barry     }
636ba7b222eSGlenn Barry 
637*5e01956fSGlenn Barry     free(pac_princname);
638ba7b222eSGlenn Barry     krb5_free_principal(context, pac_principal);
639ba7b222eSGlenn Barry 
640ba7b222eSGlenn Barry     return ret;
641ba7b222eSGlenn Barry }
642ba7b222eSGlenn Barry 
643ba7b222eSGlenn Barry static krb5_error_code
k5_pac_zero_signature(krb5_context context,const krb5_pac pac,krb5_ui_4 type,krb5_data * data)644ba7b222eSGlenn Barry k5_pac_zero_signature(krb5_context context,
645ba7b222eSGlenn Barry 		      const krb5_pac pac,
646ba7b222eSGlenn Barry 		      krb5_ui_4 type,
647ba7b222eSGlenn Barry 		      krb5_data *data)
648ba7b222eSGlenn Barry {
649ba7b222eSGlenn Barry     PAC_INFO_BUFFER *buffer = NULL;
650ba7b222eSGlenn Barry     size_t i;
651ba7b222eSGlenn Barry 
652ba7b222eSGlenn Barry     assert(type == PAC_SERVER_CHECKSUM || type == PAC_PRIVSVR_CHECKSUM);
653ba7b222eSGlenn Barry     assert(data->length >= pac->data.length);
654ba7b222eSGlenn Barry 
655ba7b222eSGlenn Barry     for (i = 0; i < pac->pac->cBuffers; i++) {
656ba7b222eSGlenn Barry 	if (pac->pac->Buffers[i].ulType == type) {
657ba7b222eSGlenn Barry 	    buffer = &pac->pac->Buffers[i];
658ba7b222eSGlenn Barry 	    break;
659ba7b222eSGlenn Barry 	}
660ba7b222eSGlenn Barry     }
661ba7b222eSGlenn Barry 
662*5e01956fSGlenn Barry     if (buffer == NULL) {
663*5e01956fSGlenn Barry 	/* Solaris Kerberos */
664*5e01956fSGlenn Barry 	krb5_set_error_message(context, ENOENT,
665*5e01956fSGlenn Barry 			    "No PAC buffer found (type=%d)",
666*5e01956fSGlenn Barry 			    type);
667ba7b222eSGlenn Barry 	return ENOENT;
668*5e01956fSGlenn Barry     }
669ba7b222eSGlenn Barry 
670*5e01956fSGlenn Barry     if (buffer->Offset + buffer->cbBufferSize > pac->data.length) {
671ba7b222eSGlenn Barry 	return ERANGE;
672*5e01956fSGlenn Barry     }
673ba7b222eSGlenn Barry 
674*5e01956fSGlenn Barry     if (buffer->cbBufferSize < PAC_SIGNATURE_DATA_LENGTH) {
675ba7b222eSGlenn Barry 	return KRB5_BAD_MSIZE;
676*5e01956fSGlenn Barry     }
677ba7b222eSGlenn Barry 
678ba7b222eSGlenn Barry     /* Zero out the data portion of the checksum only */
679ba7b222eSGlenn Barry     memset(data->data + buffer->Offset + PAC_SIGNATURE_DATA_LENGTH,
680ba7b222eSGlenn Barry 	   0,
681ba7b222eSGlenn Barry 	   buffer->cbBufferSize - PAC_SIGNATURE_DATA_LENGTH);
682ba7b222eSGlenn Barry 
683ba7b222eSGlenn Barry     return 0;
684ba7b222eSGlenn Barry }
685ba7b222eSGlenn Barry 
686ba7b222eSGlenn Barry static krb5_error_code
k5_pac_verify_server_checksum(krb5_context context,const krb5_pac pac,const krb5_keyblock * server)687ba7b222eSGlenn Barry k5_pac_verify_server_checksum(krb5_context context,
688ba7b222eSGlenn Barry 			      const krb5_pac pac,
689ba7b222eSGlenn Barry 			      const krb5_keyblock *server)
690ba7b222eSGlenn Barry {
691ba7b222eSGlenn Barry     krb5_error_code ret;
692ba7b222eSGlenn Barry     krb5_data pac_data; /* PAC with zeroed checksums */
693ba7b222eSGlenn Barry     krb5_checksum checksum;
694ba7b222eSGlenn Barry     krb5_data checksum_data;
695ba7b222eSGlenn Barry     krb5_boolean valid;
696ba7b222eSGlenn Barry     krb5_octet *p;
697ba7b222eSGlenn Barry 
698ba7b222eSGlenn Barry     ret = k5_pac_locate_buffer(context, pac, PAC_SERVER_CHECKSUM, &checksum_data);
699ba7b222eSGlenn Barry     if (ret != 0)
700ba7b222eSGlenn Barry 	return ret;
701ba7b222eSGlenn Barry 
702*5e01956fSGlenn Barry     if (checksum_data.length < PAC_SIGNATURE_DATA_LENGTH) {
703ba7b222eSGlenn Barry 	return KRB5_BAD_MSIZE;
704*5e01956fSGlenn Barry     }
705ba7b222eSGlenn Barry 
706ba7b222eSGlenn Barry     p = (krb5_octet *)checksum_data.data;
707ba7b222eSGlenn Barry     checksum.checksum_type = load_32_le(p);
708ba7b222eSGlenn Barry     checksum.length = checksum_data.length - PAC_SIGNATURE_DATA_LENGTH;
709ba7b222eSGlenn Barry     checksum.contents = p + PAC_SIGNATURE_DATA_LENGTH;
710ba7b222eSGlenn Barry 
711ba7b222eSGlenn Barry     pac_data.length = pac->data.length;
712ba7b222eSGlenn Barry     pac_data.data = malloc(pac->data.length);
713ba7b222eSGlenn Barry     if (pac_data.data == NULL)
714ba7b222eSGlenn Barry 	return ENOMEM;
715ba7b222eSGlenn Barry 
716ba7b222eSGlenn Barry     memcpy(pac_data.data, pac->data.data, pac->data.length);
717ba7b222eSGlenn Barry 
718ba7b222eSGlenn Barry     /* Zero out both checksum buffers */
719ba7b222eSGlenn Barry     ret = k5_pac_zero_signature(context, pac, PAC_SERVER_CHECKSUM, &pac_data);
720ba7b222eSGlenn Barry     if (ret != 0) {
721ba7b222eSGlenn Barry 	free(pac_data.data);
722ba7b222eSGlenn Barry 	return ret;
723ba7b222eSGlenn Barry     }
724ba7b222eSGlenn Barry 
725ba7b222eSGlenn Barry     ret = k5_pac_zero_signature(context, pac, PAC_PRIVSVR_CHECKSUM, &pac_data);
726ba7b222eSGlenn Barry     if (ret != 0) {
727ba7b222eSGlenn Barry 	free(pac_data.data);
728ba7b222eSGlenn Barry 	return ret;
729ba7b222eSGlenn Barry     }
730ba7b222eSGlenn Barry 
731ba7b222eSGlenn Barry     ret = krb5_c_verify_checksum(context, server, KRB5_KEYUSAGE_APP_DATA_CKSUM,
732ba7b222eSGlenn Barry 				 &pac_data, &checksum, &valid);
733ba7b222eSGlenn Barry     if (ret != 0) {
734ba7b222eSGlenn Barry         free(pac_data.data);
735ba7b222eSGlenn Barry 	return ret;
736ba7b222eSGlenn Barry     }
737ba7b222eSGlenn Barry 
738*5e01956fSGlenn Barry     if (valid == FALSE) {
739ba7b222eSGlenn Barry 	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
740*5e01956fSGlenn Barry 	/* Solaris Kerberos */
741*5e01956fSGlenn Barry 	krb5_set_error_message(context, ret,
742*5e01956fSGlenn Barry 			    "Decrypt integrity check failed for PAC");
743*5e01956fSGlenn Barry     }
744ba7b222eSGlenn Barry 
745ba7b222eSGlenn Barry     free(pac_data.data); /* SUNW17PACresync - mem leak fix */
746ba7b222eSGlenn Barry     return ret;
747ba7b222eSGlenn Barry }
748ba7b222eSGlenn Barry 
749ba7b222eSGlenn Barry static krb5_error_code
k5_pac_verify_kdc_checksum(krb5_context context,const krb5_pac pac,const krb5_keyblock * privsvr)750ba7b222eSGlenn Barry k5_pac_verify_kdc_checksum(krb5_context context,
751ba7b222eSGlenn Barry 			   const krb5_pac pac,
752ba7b222eSGlenn Barry 			   const krb5_keyblock *privsvr)
753ba7b222eSGlenn Barry {
754ba7b222eSGlenn Barry     krb5_error_code ret;
755ba7b222eSGlenn Barry     krb5_data server_checksum, privsvr_checksum;
756ba7b222eSGlenn Barry     krb5_checksum checksum;
757ba7b222eSGlenn Barry     krb5_boolean valid;
758ba7b222eSGlenn Barry     krb5_octet *p;
759ba7b222eSGlenn Barry 
760ba7b222eSGlenn Barry     ret = k5_pac_locate_buffer(context, pac, PAC_PRIVSVR_CHECKSUM, &privsvr_checksum);
761ba7b222eSGlenn Barry     if (ret != 0)
762ba7b222eSGlenn Barry 	return ret;
763ba7b222eSGlenn Barry 
764*5e01956fSGlenn Barry     if (privsvr_checksum.length < PAC_SIGNATURE_DATA_LENGTH) {