1ba7b222eSGlenn Barry /*
25e01956fSGlenn 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.
14*55fea89dSDan Cross  *
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) {
1915e01956fSGlenn Barry 	/* Solaris Kerberos */
1925e01956fSGlenn Barry 	krb5_set_error_message(context, EINVAL,
1935e01956fSGlenn Barry 			    "Duplicate PAC buffer of type %d",
1945e01956fSGlenn 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 
2905e01956fSGlenn Barry     if (pac == NULL) {
2915e01956fSGlenn Barry 	/* Solaris Kerberos */
2925e01956fSGlenn Barry 	krb5_set_error_message(context, EINVAL,
2935e01956fSGlenn Barry 			    "Invalid argument 'pac' is NULL");
294ba7b222eSGlenn Barry 	return EINVAL;
2955e01956fSGlenn 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];
3015e01956fSGlenn Barry 	    else {
3025e01956fSGlenn Barry 	        /* Solaris Kerberos */
3035e01956fSGlenn Barry 	        krb5_set_error_message(context, EINVAL,
3045e01956fSGlenn Barry 				    "Invalid buffer found looping thru PAC buffers (type=%d, i=%d)",
3055e01956fSGlenn Barry 				    type, i);
306ba7b222eSGlenn Barry 		return EINVAL;
3075e01956fSGlenn Barry 	    }
308ba7b222eSGlenn Barry 	}
309ba7b222eSGlenn Barry     }
310ba7b222eSGlenn Barry 
3115e01956fSGlenn Barry     if (buffer == NULL) {
3125e01956fSGlenn Barry 	/* Solaris Kerberos */
3135e01956fSGlenn Barry 	krb5_set_error_message(context, ENOENT,
3145e01956fSGlenn Barry 			    "No PAC buffer found (type=%d)",
3155e01956fSGlenn Barry 			    type);
3165e01956fSGlenn Barry 
317ba7b222eSGlenn Barry 	return ENOENT;
3185e01956fSGlenn 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;
345*55fea89dSDan Cross 
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 
4315e01956fSGlenn Barry     if (len < PACTYPE_LENGTH) {
4325e01956fSGlenn Barry 	/* Solaris Kerberos */
4335e01956fSGlenn Barry 	krb5_set_error_message(context, ERANGE,
4345e01956fSGlenn Barry 			    "PAC type length is out of range (len=%d)",
4355e01956fSGlenn Barry 			    len);
436ba7b222eSGlenn Barry 	return ERANGE;
4375e01956fSGlenn 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 
4445e01956fSGlenn Barry     if (version != 0) {
4455e01956fSGlenn Barry 	/* Solaris Kerberos */
4465e01956fSGlenn Barry 	krb5_set_error_message(context, EINVAL,
4475e01956fSGlenn Barry 			    "Invalid PAC version is %d, should be 0",
4485e01956fSGlenn Barry 			    version);
449ba7b222eSGlenn Barry 	return EINVAL;
4505e01956fSGlenn Barry     }
451ba7b222eSGlenn Barry 
452ba7b222eSGlenn Barry     header_len = PACTYPE_LENGTH + (cbuffers * PAC_INFO_BUFFER_LENGTH);
4535e01956fSGlenn Barry     if (len < header_len) {
4545e01956fSGlenn Barry 	/* Solaris Kerberos */
4555e01956fSGlenn Barry 	krb5_set_error_message(context, ERANGE,
4565e01956fSGlenn Barry 			    "PAC header len (%d) out of range",
4575e01956fSGlenn Barry 			    len);
458ba7b222eSGlenn Barry 	return ERANGE;
4595e01956fSGlenn 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);
4875e01956fSGlenn Barry 	    /* Solaris Kerberos */
4885e01956fSGlenn Barry 	    krb5_set_error_message(context, EINVAL,
4895e01956fSGlenn 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);
4955e01956fSGlenn Barry 	    /* Solaris Kerberos */
4965e01956fSGlenn Barry 	    krb5_set_error_message(context, ERANGE,
4975e01956fSGlenn 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)5175e01956fSGlenn 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 
5255e01956fSGlenn Barry     if (abstime > KRB5_INT32_MAX) {
526ba7b222eSGlenn Barry 	return ERANGE;
5275e01956fSGlenn Barry     }
528ba7b222eSGlenn Barry 
529ba7b222eSGlenn Barry     *elapsedSeconds = abstime;
530ba7b222eSGlenn Barry 
531ba7b222eSGlenn Barry     return 0;
532*55fea89dSDan Cross }
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;
543*55fea89dSDan Cross 
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 
5665e01956fSGlenn Barry     if (client_info.length < PAC_CLIENT_INFO_LENGTH) {
5675e01956fSGlenn Barry 	/* Solaris Kerberos */
5685e01956fSGlenn Barry 	krb5_set_error_message(context, ERANGE,
5695e01956fSGlenn Barry 			    "PAC client info length out of range",
5705e01956fSGlenn Barry 			    client_info.length);
571ba7b222eSGlenn Barry 	return ERANGE;
5725e01956fSGlenn 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 
5805e01956fSGlenn 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 ||
5855e01956fSGlenn Barry         pac_princname_length % 2) {
5865e01956fSGlenn Barry 	/* Solaris Kerberos */
5875e01956fSGlenn Barry 	krb5_set_error_message(context, ERANGE,
5885e01956fSGlenn Barry 			    "PAC client info length is out of range");
589ba7b222eSGlenn Barry 	return ERANGE;
5905e01956fSGlenn 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 
6035e01956fSGlenn Barry     if (pac_authtime != authtime) {
6045e01956fSGlenn Barry 	/* Solaris Kerberos */
6055e01956fSGlenn Barry 	char timestring[17];
6065e01956fSGlenn Barry 	char pac_timestring[17];
6075e01956fSGlenn Barry 	char fill = ' ';
6085e01956fSGlenn Barry 	int err, pac_err;
6095e01956fSGlenn Barry 	/* Need better ret code here but don't see one */
610ba7b222eSGlenn Barry 	ret = KRB5KRB_AP_WRONG_PRINC;
6115e01956fSGlenn Barry 	err = krb5_timestamp_to_sfstring(pac_authtime,
6125e01956fSGlenn Barry 					timestring,
6135e01956fSGlenn Barry 					sizeof (timestring), &fill);
6145e01956fSGlenn Barry 	pac_err = krb5_timestamp_to_sfstring(pac_authtime,
6155e01956fSGlenn Barry 					pac_timestring,
6165e01956fSGlenn Barry 					    sizeof (pac_timestring), &fill);
6175e01956fSGlenn Barry 	if (pac_princname && !err && !pac_err) {
6185e01956fSGlenn Barry 	    krb5_set_error_message(context, ret,
6195e01956fSGlenn Barry 				"PAC verify fail: PAC authtime '%s' does not match authtime '%s'.  PAC principal is '%s'",
6205e01956fSGlenn Barry 				pac_timestring, timestring, pac_princname);
6215e01956fSGlenn Barry 	}
6225e01956fSGlenn Barry     } else if (krb5_principal_compare(context, pac_principal, principal) == FALSE) {
6235e01956fSGlenn Barry 	/* Solaris Kerberos */
6245e01956fSGlenn Barry 	char *p_name = NULL;
6255e01956fSGlenn Barry 	krb5_error_code perr;
6265e01956fSGlenn Barry 	ret = KRB5KRB_AP_WRONG_PRINC;
6275e01956fSGlenn Barry 	perr = krb5_unparse_name(context, principal, &p_name);
6285e01956fSGlenn Barry 	if (pac_princname && !perr) {
6295e01956fSGlenn Barry 	    krb5_set_error_message(context, ret,
6305e01956fSGlenn Barry 				"Wrong principal in request: PAC verify: Principal in PAC is '%s' and does not match '%s'",
6315e01956fSGlenn Barry 				pac_princname, p_name);
6325e01956fSGlenn Barry 	}
6335e01956fSGlenn Barry 	if (p_name)
6345e01956fSGlenn Barry 	    krb5_free_unparsed_name(context, p_name);
6355e01956fSGlenn Barry     }
636ba7b222eSGlenn Barry 
6375e01956fSGlenn 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 
6625e01956fSGlenn Barry     if (buffer == NULL) {
6635e01956fSGlenn Barry 	/* Solaris Kerberos */
6645e01956fSGlenn Barry 	krb5_set_error_message(context, ENOENT,
6655e01956fSGlenn Barry 			    "No PAC buffer found (type=%d)",
6665e01956fSGlenn Barry 			    type);
667ba7b222eSGlenn Barry 	return ENOENT;
6685e01956fSGlenn Barry     }
669ba7b222eSGlenn Barry 
6705e01956fSGlenn Barry     if (buffer->Offset + buffer->cbBufferSize > pac->data.length) {
671ba7b222eSGlenn Barry 	return ERANGE;
6725e01956fSGlenn Barry     }
673ba7b222eSGlenn Barry 
6745e01956fSGlenn Barry     if (buffer->cbBufferSize < PAC_SIGNATURE_DATA_LENGTH) {
675ba7b222eSGlenn Barry 	return KRB5_BAD_MSIZE;
6765e01956fSGlenn 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 
7025e01956fSGlenn Barry     if (checksum_data.length < PAC_SIGNATURE_DATA_LENGTH) {
703ba7b222eSGlenn Barry 	return KRB5_BAD_MSIZE;
7045e01956fSGlenn 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 
7385e01956fSGlenn Barry     if (valid == FALSE) {
739ba7b222eSGlenn Barry 	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
7405e01956fSGlenn Barry 	/* Solaris Kerberos */
7415e01956fSGlenn Barry 	krb5_set_error_message(context, ret,
7425e01956fSGlenn Barry 			    "Decrypt integrity check failed for PAC");
7435e01956fSGlenn 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 
7645e01956fSGlenn Barry     if (privsvr_checksum.length < PAC_SIGNATURE_DATA_LENGTH) {
765ba7b222eSGlenn Barry 	return KRB5_BAD_MSIZE;
7665e01956fSGlenn Barry     }
767ba7b222eSGlenn Barry 
768ba7b222eSGlenn Barry     ret = k5_pac_locate_buffer(context, pac, PAC_SERVER_CHECKSUM, &server_checksum);
769ba7b222eSGlenn Barry     if (ret != 0)
770ba7b222eSGlenn Barry 	return ret;
771ba7b222eSGlenn Barry 
7725e01956fSGlenn Barry     if (server_checksum.length < PAC_SIGNATURE_DATA_LENGTH) {
773ba7b222eSGlenn Barry 	return KRB5_BAD_MSIZE;
7745e01956fSGlenn Barry     }
775ba7b222eSGlenn Barry 
776ba7b222eSGlenn Barry     p = (krb5_octet *)privsvr_checksum.data;
777ba7b222eSGlenn Barry     checksum.checksum_type = load_32_le(p);
778ba7b222eSGlenn Barry     checksum.length = privsvr_checksum.length - PAC_SIGNATURE_DATA_LENGTH;
779ba7b222eSGlenn Barry     checksum.contents = p + PAC_SIGNATURE_DATA_LENGTH;
780ba7b222eSGlenn Barry 
781ba7b222eSGlenn Barry     server_checksum.data += PAC_SIGNATURE_DATA_LENGTH;
782ba7b222eSGlenn Barry     server_checksum.length -= PAC_SIGNATURE_DATA_LENGTH;
783ba7b222eSGlenn Barry 
784ba7b222eSGlenn Barry     ret = krb5_c_verify_checksum(context, privsvr, KRB5_KEYUSAGE_APP_DATA_CKSUM,
785ba7b222eSGlenn Barry 				 &server_checksum, &checksum, &valid);
786ba7b222eSGlenn Barry     if (ret != 0)
787ba7b222eSGlenn Barry 	return ret;
788ba7b222eSGlenn Barry 
7895e01956fSGlenn Barry     if (valid == FALSE) {
790ba7b222eSGlenn Barry 	ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
7915e01956fSGlenn Barry 	/* Solaris Kerberos */
7925e01956fSGlenn Barry 	krb5_set_error_message(context, ret,
7935e01956fSGlenn Barry 			    "Decrypt integrity check failed for PAC");
7945e01956fSGlenn Barry     }
795ba7b222eSGlenn Barry 
796ba7b222eSGlenn Barry     return ret;
797ba7b222eSGlenn Barry }
798ba7b222eSGlenn Barry 
799ba7b222eSGlenn Barry krb5_error_code KRB5_CALLCONV
krb5_pac_verify(krb5_context context,const krb5_pac pac,krb5_timestamp authtime,krb5_const_principal principal,const krb5_keyblock * server,const krb5_keyblock * privsvr)800ba7b222eSGlenn Barry krb5_pac_verify(krb5_context context,
801ba7b222eSGlenn Barry 		const krb5_pac pac,
802ba7b222eSGlenn Barry 		krb5_timestamp authtime,
803ba7b222eSGlenn Barry 		krb5_const_principal principal,
804ba7b222eSGlenn Barry 		const krb5_keyblock *server,
805ba7b222eSGlenn Barry 		const krb5_keyblock *privsvr)
806ba7b222eSGlenn Barry {
807ba7b222eSGlenn Barry     krb5_error_code ret;
808ba7b222eSGlenn Barry 
8095e01956fSGlenn Barry     if (server == NULL) {
810ba7b222eSGlenn Barry 	return EINVAL;
8115e01956fSGlenn Barry     }
812ba7b222eSGlenn Barry 
813ba7b222eSGlenn Barry     ret = k5_pac_verify_server_checksum(context, pac, server);
814ba7b222eSGlenn Barry     if (ret != 0)
815ba7b222eSGlenn Barry 	return ret;
816ba7b222eSGlenn Barry 
817ba7b222eSGlenn Barry     if (privsvr != NULL) {
818ba7b222eSGlenn Barry 	ret = k5_pac_verify_kdc_checksum(context, pac, privsvr);
819ba7b222eSGlenn Barry 	if (ret != 0)
820ba7b222eSGlenn Barry 	    return ret;
821ba7b222eSGlenn Barry     }
822ba7b222eSGlenn Barry 
823ba7b222eSGlenn Barry     if (principal != NULL) {
824ba7b222eSGlenn Barry 	ret = k5_pac_validate_client(context, pac, authtime, principal);
825ba7b222eSGlenn Barry 	if (ret != 0)
826ba7b222eSGlenn Barry 	    return ret;
827ba7b222eSGlenn Barry     }
828ba7b222eSGlenn Barry 
829ba7b222eSGlenn Barry     return 0;
830ba7b222eSGlenn Barry }
831ba7b222eSGlenn Barry 
832ba7b222eSGlenn Barry static krb5_error_code
k5_insert_client_info(krb5_context context,krb5_pac pac,krb5_timestamp authtime,krb5_const_principal principal)833ba7b222eSGlenn Barry k5_insert_client_info(krb5_context context,
834ba7b222eSGlenn Barry 		      krb5_pac pac,
835ba7b222eSGlenn Barry 		      krb5_timestamp authtime,
836ba7b222eSGlenn Barry 		      krb5_const_principal principal)
837ba7b222eSGlenn Barry {
838ba7b222eSGlenn Barry     krb5_error_code ret;
839ba7b222eSGlenn Barry     krb5_data client_info;
840ba7b222eSGlenn Barry     char *princ_name_utf8 = NULL;
841ba7b222eSGlenn Barry     unsigned char *princ_name_ucs2 = NULL, *p;
842ba7b222eSGlenn Barry     size_t princ_name_ucs2_len = 0;
843ba7b222eSGlenn Barry     krb5_ui_8 nt_authtime;
844ba7b222eSGlenn Barry 
845ba7b222eSGlenn Barry     /* If we already have a CLIENT_INFO buffer, then just validate it */
846ba7b222eSGlenn Barry     if (k5_pac_locate_buffer(context, pac, PAC_CLIENT_INFO, &client_info) == 0) {
847ba7b222eSGlenn Barry 	return k5_pac_validate_client(context, pac, authtime, principal);
848ba7b222eSGlenn Barry     }
849ba7b222eSGlenn Barry 
850ba7b222eSGlenn Barry     ret = krb5_unparse_name_flags(context, principal,
851ba7b222eSGlenn Barry 				  KRB5_PRINCIPAL_UNPARSE_NO_REALM, &princ_name_utf8);
852ba7b222eSGlenn Barry     if (ret != 0)
853ba7b222eSGlenn Barry 	goto cleanup;
854ba7b222eSGlenn Barry 
855ba7b222eSGlenn Barry     ret = krb5int_utf8s_to_ucs2les(princ_name_utf8,
856ba7b222eSGlenn Barry 				   &princ_name_ucs2,
857ba7b222eSGlenn Barry 				   &princ_name_ucs2_len);
858ba7b222eSGlenn Barry     if (ret != 0)
859ba7b222eSGlenn Barry 	goto cleanup;
860ba7b222eSGlenn Barry 
861ba7b222eSGlenn Barry     client_info.length = PAC_CLIENT_INFO_LENGTH + princ_name_ucs2_len;
862ba7b222eSGlenn Barry     client_info.data = NULL;
863ba7b222eSGlenn Barry 
864ba7b222eSGlenn Barry     ret = k5_pac_add_buffer(context, pac, PAC_CLIENT_INFO, &client_info, TRUE, &client_info);
865ba7b222eSGlenn Barry     if (ret != 0)
866ba7b222eSGlenn Barry 	goto cleanup;
867ba7b222eSGlenn Barry 
868ba7b222eSGlenn Barry     p = (unsigned char *)client_info.data;
869ba7b222eSGlenn Barry 
870ba7b222eSGlenn Barry     /* copy in authtime converted to a 64-bit NT time */
871ba7b222eSGlenn Barry     k5_seconds_since_1970_to_time(authtime, &nt_authtime);
872ba7b222eSGlenn Barry     store_64_le(nt_authtime, p);
873ba7b222eSGlenn Barry     p += 8;
874ba7b222eSGlenn Barry 
875ba7b222eSGlenn Barry     /* copy in number of UCS-2 characters in principal name */
876ba7b222eSGlenn Barry     store_16_le(princ_name_ucs2_len, p);
877ba7b222eSGlenn Barry     p += 2;
878ba7b222eSGlenn Barry 
879ba7b222eSGlenn Barry     /* copy in principal name */
880ba7b222eSGlenn Barry     memcpy(p, princ_name_ucs2, princ_name_ucs2_len);
881*55fea89dSDan Cross 
882ba7b222eSGlenn Barry cleanup:
883ba7b222eSGlenn Barry     if (princ_name_utf8 != NULL)
884ba7b222eSGlenn Barry 	free(princ_name_utf8);
885ba7b222eSGlenn Barry     if (princ_name_ucs2 != NULL)
886ba7b222eSGlenn Barry 	free(princ_name_ucs2);
887ba7b222eSGlenn Barry 
888ba7b222eSGlenn Barry     return ret;
889ba7b222eSGlenn Barry }
890ba7b222eSGlenn Barry 
891ba7b222eSGlenn Barry static krb5_error_code
k5_insert_checksum(krb5_context context,krb5_pac pac,krb5_ui_4 type,const krb5_keyblock * key,krb5_cksumtype * cksumtype)892ba7b222eSGlenn Barry k5_insert_checksum(krb5_context context,
893ba7b222eSGlenn Barry 		   krb5_pac pac,
894ba7b222eSGlenn Barry 		   krb5_ui_4 type,
895ba7b222eSGlenn Barry 		   const krb5_keyblock *key,
896ba7b222eSGlenn Barry 		   krb5_cksumtype *cksumtype)
897ba7b222eSGlenn Barry {
898ba7b222eSGlenn Barry     krb5_error_code ret;
899ba7b222eSGlenn Barry     size_t len;
900ba7b222eSGlenn Barry     krb5_data cksumdata;
901ba7b222eSGlenn Barry 
902ba7b222eSGlenn Barry     ret = krb5int_c_mandatory_cksumtype(context, key->enctype, cksumtype);
903ba7b222eSGlenn Barry     if (ret != 0)
904ba7b222eSGlenn Barry 	return ret;
905ba7b222eSGlenn Barry 
906ba7b222eSGlenn Barry     ret = krb5_c_checksum_length(context, *cksumtype, &len);
907ba7b222eSGlenn Barry     if (ret != 0)
908ba7b222eSGlenn Barry 	return ret;
909ba7b222eSGlenn Barry 
910ba7b222eSGlenn Barry     ret = k5_pac_locate_buffer(context, pac, type, &cksumdata);
911ba7b222eSGlenn Barry     if (ret == 0) {
912ba7b222eSGlenn Barry 	/* If we're resigning PAC, make sure we can fit checksum into existing buffer */
9135e01956fSGlenn Barry 	if (cksumdata.length != PAC_SIGNATURE_DATA_LENGTH + len) {
914ba7b222eSGlenn Barry 	    return ERANGE;
9155e01956fSGlenn Barry 	}
916ba7b222eSGlenn Barry 
917ba7b222eSGlenn Barry 	memset(cksumdata.data, 0, cksumdata.length);
918ba7b222eSGlenn Barry     } else {
919ba7b222eSGlenn Barry 	/* Add a zero filled buffer */
920ba7b222eSGlenn Barry 	cksumdata.length = PAC_SIGNATURE_DATA_LENGTH + len;
921ba7b222eSGlenn Barry 	cksumdata.data = NULL;
922ba7b222eSGlenn Barry 
923ba7b222eSGlenn Barry 	ret = k5_pac_add_buffer(context, pac, type, &cksumdata, TRUE, &cksumdata);
924ba7b222eSGlenn Barry 	if (ret != 0)
925ba7b222eSGlenn Barry 	    return ret;
926ba7b222eSGlenn Barry     }
927ba7b222eSGlenn Barry 
928ba7b222eSGlenn Barry     /* Encode checksum type into buffer */
929ba7b222eSGlenn Barry     store_32_le((krb5_ui_4)*cksumtype, cksumdata.data);
930ba7b222eSGlenn Barry 
931ba7b222eSGlenn Barry     return 0;
932ba7b222eSGlenn Barry }
933ba7b222eSGlenn Barry 
934ba7b222eSGlenn Barry /* in-place encoding of PAC header */
935ba7b222eSGlenn Barry static krb5_error_code
k5_pac_encode_header(krb5_context context,krb5_pac pac)936ba7b222eSGlenn Barry k5_pac_encode_header(krb5_context context, krb5_pac pac)
937ba7b222eSGlenn Barry {
938ba7b222eSGlenn Barry     size_t i;
939ba7b222eSGlenn Barry     unsigned char *p;
940ba7b222eSGlenn Barry     size_t header_len;
941ba7b222eSGlenn Barry 
942ba7b222eSGlenn Barry     header_len = PACTYPE_LENGTH + (pac->pac->cBuffers * PAC_INFO_BUFFER_LENGTH);
943ba7b222eSGlenn Barry     assert(pac->data.length >= header_len);
944ba7b222eSGlenn Barry 
945ba7b222eSGlenn Barry     p = (unsigned char *)pac->data.data;
946ba7b222eSGlenn Barry 
947ba7b222eSGlenn Barry     store_32_le(pac->pac->cBuffers, p);
948ba7b222eSGlenn Barry     p += 4;
949ba7b222eSGlenn Barry     store_32_le(pac->pac->Version, p);
950ba7b222eSGlenn Barry     p += 4;
951ba7b222eSGlenn Barry 
952ba7b222eSGlenn Barry     for (i = 0; i < pac->pac->cBuffers; i++) {
953ba7b222eSGlenn Barry 	PAC_INFO_BUFFER *buffer = &pac->pac->Buffers[i];
954ba7b222eSGlenn Barry 
955ba7b222eSGlenn Barry 	store_32_le(buffer->ulType, p);
956ba7b222eSGlenn Barry 	p += 4;
957ba7b222eSGlenn Barry 	store_32_le(buffer->cbBufferSize, p);
958ba7b222eSGlenn Barry 	p += 4;
959ba7b222eSGlenn Barry 	store_64_le(buffer->Offset, p);
960ba7b222eSGlenn Barry 	p += 8;
961ba7b222eSGlenn Barry 
962ba7b222eSGlenn Barry 	assert((buffer->Offset % PAC_ALIGNMENT) == 0);
963ba7b222eSGlenn Barry 	assert(buffer->Offset + buffer->cbBufferSize <= pac->data.length);
964ba7b222eSGlenn Barry 	assert(buffer->Offset >= header_len);
965ba7b222eSGlenn Barry 
966ba7b222eSGlenn Barry 	if (buffer->Offset % PAC_ALIGNMENT ||
967ba7b222eSGlenn Barry 	    buffer->Offset + buffer->cbBufferSize > pac->data.length ||
9685e01956fSGlenn Barry 	    buffer->Offset < header_len) {
969ba7b222eSGlenn Barry 	    return ERANGE;
9705e01956fSGlenn Barry 	}
971ba7b222eSGlenn Barry     }
972ba7b222eSGlenn Barry 
973ba7b222eSGlenn Barry     return 0;
974ba7b222eSGlenn Barry }
975ba7b222eSGlenn Barry 
976ba7b222eSGlenn Barry 
977ba7b222eSGlenn Barry #if 0
978ba7b222eSGlenn Barry /*
979ba7b222eSGlenn Barry  * SUNW17PACresync
980ba7b222eSGlenn Barry  * We don't have the new MIT iov interfaces yet and don't need them yet.
981ba7b222eSGlenn Barry  * We'll need this for full 1.7 resync.
982ba7b222eSGlenn Barry  */
983ba7b222eSGlenn Barry krb5_error_code KRB5_CALLCONV
984ba7b222eSGlenn Barry krb5int_pac_sign(krb5_context context,
985ba7b222eSGlenn Barry 		 krb5_pac pac,
986ba7b222eSGlenn Barry 		 krb5_timestamp authtime,
987ba7b222eSGlenn Barry 		 krb5_const_principal principal,
988ba7b222eSGlenn Barry 		 const krb5_keyblock *server_key,
989ba7b222eSGlenn Barry 		 const krb5_keyblock *privsvr_key,
990ba7b222eSGlenn Barry 		 krb5_data *data)
991ba7b222eSGlenn Barry {
992ba7b222eSGlenn Barry     krb5_error_code ret;
993ba7b222eSGlenn Barry     krb5_data server_cksum, privsvr_cksum;
994ba7b222eSGlenn Barry     krb5_cksumtype server_cksumtype, privsvr_cksumtype;
995ba7b222eSGlenn Barry     krb5_crypto_iov iov[2];
996ba7b222eSGlenn Barry 
997ba7b222eSGlenn Barry     data->length = 0;
998ba7b222eSGlenn Barry     data->data = NULL;
999ba7b222eSGlenn Barry 
1000ba7b222eSGlenn Barry     if (principal != NULL) {
1001ba7b222eSGlenn Barry 	ret = k5_insert_client_info(context, pac, authtime, principal);
1002ba7b222eSGlenn Barry 	if (ret != 0)
1003ba7b222eSGlenn Barry 	    return ret;
1004ba7b222eSGlenn Barry     }
1005ba7b222eSGlenn Barry 
1006ba7b222eSGlenn Barry     /* Create zeroed buffers for both checksums */
1007ba7b222eSGlenn Barry     ret = k5_insert_checksum(context, pac, PAC_SERVER_CHECKSUM,
1008ba7b222eSGlenn Barry 			     server_key, &server_cksumtype);
1009ba7b222eSGlenn Barry     if (ret != 0)
1010ba7b222eSGlenn Barry 	return ret;
1011ba7b222eSGlenn Barry 
1012ba7b222eSGlenn Barry     ret = k5_insert_checksum(context, pac, PAC_PRIVSVR_CHECKSUM,
1013ba7b222eSGlenn Barry 			     privsvr_key, &privsvr_cksumtype);
1014ba7b222eSGlenn Barry     if (ret != 0)
1015ba7b222eSGlenn Barry 	return ret;
1016ba7b222eSGlenn Barry 
1017ba7b222eSGlenn Barry     /* Now, encode the PAC header so that the checksums will include it */
1018ba7b222eSGlenn Barry     ret = k5_pac_encode_header(context, pac);
1019ba7b222eSGlenn Barry     if (ret != 0)
1020ba7b222eSGlenn Barry 	return ret;
1021ba7b222eSGlenn Barry 
1022ba7b222eSGlenn Barry     /* Generate the server checksum over the entire PAC */
1023ba7b222eSGlenn Barry     ret = k5_pac_locate_buffer(context, pac, PAC_SERVER_CHECKSUM, &server_cksum);
1024ba7b222eSGlenn Barry     if (ret != 0)
1025ba7b222eSGlenn Barry 	return ret;
1026ba7b222eSGlenn Barry 
1027ba7b222eSGlenn Barry     assert(server_cksum.length > PAC_SIGNATURE_DATA_LENGTH);
1028ba7b222eSGlenn Barry 
1029ba7b222eSGlenn Barry     iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
1030ba7b222eSGlenn Barry     iov[0].data = pac->data;
1031ba7b222eSGlenn Barry 
1032ba7b222eSGlenn Barry     iov[1].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
1033ba7b222eSGlenn Barry     iov[1].data.data = server_cksum.data + PAC_SIGNATURE_DATA_LENGTH;
1034ba7b222eSGlenn Barry     iov[1].data.length = server_cksum.length - PAC_SIGNATURE_DATA_LENGTH;
1035ba7b222eSGlenn Barry 
1036ba7b222eSGlenn Barry     ret = krb5_c_make_checksum_iov(context, server_cksumtype,
1037ba7b222eSGlenn Barry 				   server_key, KRB5_KEYUSAGE_APP_DATA_CKSUM,
1038ba7b222eSGlenn Barry 				   iov, sizeof(iov)/sizeof(iov[0]));
1039ba7b222eSGlenn Barry     if (ret != 0)
1040ba7b222eSGlenn Barry 	return ret;
1041ba7b222eSGlenn Barry 
1042ba7b222eSGlenn Barry     /* Generate the privsvr checksum over the server checksum buffer */
1043ba7b222eSGlenn Barry     ret = k5_pac_locate_buffer(context, pac, PAC_PRIVSVR_CHECKSUM, &privsvr_cksum);
1044ba7b222eSGlenn Barry     if (ret != 0)
1045ba7b222eSGlenn Barry 	return ret;
1046ba7b222eSGlenn Barry 
1047ba7b222eSGlenn Barry     assert(privsvr_cksum.length > PAC_SIGNATURE_DATA_LENGTH);
1048ba7b222eSGlenn Barry 
1049ba7b222eSGlenn Barry     iov[0].flags = KRB5_CRYPTO_TYPE_DATA;
1050ba7b222eSGlenn Barry     iov[0].data.data = server_cksum.data + PAC_SIGNATURE_DATA_LENGTH;
1051ba7b222eSGlenn Barry     iov[0].data.length = server_cksum.length - PAC_SIGNATURE_DATA_LENGTH;
1052ba7b222eSGlenn Barry 
1053ba7b222eSGlenn Barry     iov[1].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
1054ba7b222eSGlenn Barry     iov[1].data.data = privsvr_cksum.data + PAC_SIGNATURE_DATA_LENGTH;
1055ba7b222eSGlenn Barry     iov[1].data.length = privsvr_cksum.length - PAC_SIGNATURE_DATA_LENGTH;
1056ba7b222eSGlenn Barry 
1057ba7b222eSGlenn Barry     ret = krb5_c_make_checksum_iov(context, privsvr_cksumtype,
1058ba7b222eSGlenn Barry 				   privsvr_key, KRB5_KEYUSAGE_APP_DATA_CKSUM,
1059ba7b222eSGlenn Barry 				   iov, sizeof(iov)/sizeof(iov[0]));
1060ba7b222eSGlenn Barry     if (ret != 0)
1061ba7b222eSGlenn Barry 	return ret;
1062ba7b222eSGlenn Barry 
1063ba7b222eSGlenn Barry     data->data = malloc(pac->data.length);
1064ba7b222eSGlenn Barry     if (data->data == NULL)
1065ba7b222eSGlenn Barry 	return ENOMEM;
1066ba7b222eSGlenn Barry 
1067ba7b222eSGlenn Barry     data->length = pac->data.length;
1068ba7b222eSGlenn Barry 
1069ba7b222eSGlenn Barry     memcpy(data->data, pac->data.data, pac->data.length);
1070ba7b222eSGlenn Barry     memset(pac->data.data, 0, PACTYPE_LENGTH + (pac->pac->cBuffers * PAC_INFO_BUFFER_LENGTH));
1071ba7b222eSGlenn Barry 
1072ba7b222eSGlenn Barry     return 0;
1073ba7b222eSGlenn Barry }
1074ba7b222eSGlenn Barry #endif
1075ba7b222eSGlenn Barry 
1076