2 * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
10 * -----------------------------------------------------------------------------
12 * Author: Markus Moeller (markus_moeller at compuserve.com)
14 * Copyright (C) 2007 Markus Moeller. All rights reserved.
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
30 * As a special exemption, M Moeller gives permission to link this program
31 * with MIT, Heimdal or other GSS/Kerberos libraries, and distribute
32 * the resulting executable, without including the source code for
33 * the Libraries in the source distribution.
35 * -----------------------------------------------------------------------------
39 #include "compat/getaddrinfo.h"
40 #include "compat/getnameinfo.h"
43 #include "negotiate_kerberos.h"
48 static krb5_data
*ad_data
;
49 static unsigned char *p
;
52 check_k5_err(krb5_context context
, const char *function
, krb5_error_code code
);
57 if ( bpos
% n
!= 0 ) {
60 bpos
= bpos
+(bpos
-n
*al
);
65 getustr(RPC_UNICODE_STRING
*string
)
68 string
->length
= (uint16_t)((p
[bpos
]<<0) | (p
[bpos
+1]<<8));
69 string
->maxlength
= (uint16_t)((p
[bpos
+2]<<0) | (p
[bpos
+2+1]<<8));
70 string
->pointer
= (uint32_t)((p
[bpos
+4]<<0) | (p
[bpos
+4+1]<<8) | (p
[bpos
+4+2]<<16) | (p
[bpos
+4+3]<<24));
80 var
= ((uint64_t)p
[bpos
+5]<<0) | ((uint64_t)p
[bpos
+4]<<8) | ((uint64_t)p
[bpos
+3]<<16) | ((uint64_t)p
[bpos
+2]<<24) | ((uint64_t)p
[bpos
+1]<<32) | ((uint64_t)p
[bpos
]<<40);
91 var
=(uint32_t)((p
[bpos
]<<0) | (p
[bpos
+1]<<8) | (p
[bpos
+2]<<16) | (p
[bpos
+3]<<24));
102 var
=(uint16_t)((p
[bpos
]<<0) | (p
[bpos
+1]<<8));
113 var
=(uint8_t)((p
[bpos
]<<0));
120 pstrcpy( char *src
, const char *dst
)
123 if (strlen(dst
)>MAX_PAC_GROUP_SIZE
)
126 return strcpy(src
,dst
);
132 pstrcat( char *src
, const char *dst
)
135 if (strlen(src
)+strlen(dst
)+1>MAX_PAC_GROUP_SIZE
)
138 return strcat(src
,dst
);
144 checkustr(RPC_UNICODE_STRING
*string
)
146 uint32_t size
,off
,len
;
148 if (string
->pointer
!= 0) {
150 size
= (uint32_t)((p
[bpos
]<<0) | (p
[bpos
+1]<<8) | (p
[bpos
+2]<<16) | (p
[bpos
+3]<<24));
152 off
= (uint32_t)((p
[bpos
]<<0) | (p
[bpos
+1]<<8) | (p
[bpos
+2]<<16) | (p
[bpos
+3]<<24));
154 len
= (uint32_t)((p
[bpos
]<<0) | (p
[bpos
+1]<<8) | (p
[bpos
+2]<<16) | (p
[bpos
+3]<<24));
156 if (len
> size
|| off
!= 0 ||
157 string
->length
> string
->maxlength
|| len
!= string
->length
/2) {
158 debug((char *) "%s| %s: ERROR: RPC_UNICODE_STRING encoding error => size: %d len: %d/%d maxlength: %d offset: %d\n",
159 LogTime(), PROGRAM
, size
, len
, string
->length
, string
->maxlength
, off
);
163 bpos
= bpos
+string
->length
;
169 getgids(char **Rids
, uint32_t GroupIds
, uint32_t GroupCount
)
178 if ( ngroup
!= GroupCount
) {
179 debug((char *) "%s| %s: ERROR: Group encoding error => GroupCount: %d Array size: %d\n",
180 LogTime(), PROGRAM
, GroupCount
, ngroup
);
183 debug((char *) "%s| %s: INFO: Found %d rids\n", LogTime(), PROGRAM
, GroupCount
);
185 Rids
=(char **)xcalloc(GroupCount
*sizeof(char*),1);
186 for ( l
=0; l
<(int)GroupCount
; l
++) {
187 Rids
[l
]=(char *)xcalloc(4*sizeof(char),1);
188 memcpy((void *)Rids
[l
],(void *)&p
[bpos
],4);
190 debug((char *) "%s| %s: Info: Got rid: %u\n", LogTime(), PROGRAM
, sauth
);
199 getdomaingids(char *ad_groups
, uint32_t DomainLogonId
, char **Rids
, uint32_t GroupCount
)
201 if (DomainLogonId
!= 0) {
215 /* prepend rids with DomainID */
216 length
=1+1+6+nauth
*4;
217 for (l
=0; l
<(int)GroupCount
; l
++) {
218 ag
=(char *)xcalloc((length
+4)*sizeof(char),1);
219 memcpy((void *)ag
,(const void*)&p
[bpos
],1);
220 memcpy((void *)&ag
[1],(const void*)&p
[bpos
+1],1);
222 memcpy((void *)&ag
[2],(const void*)&p
[bpos
+2],6+nauth
*4);
223 memcpy((void *)&ag
[length
],(const void*)Rids
[l
],4);
225 if (!pstrcpy(ad_groups
,"group=")) {
226 debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n",
227 LogTime(), PROGRAM
, MAX_PAC_GROUP_SIZE
, ad_groups
);
230 if (!pstrcat(ad_groups
," group=")) {
231 debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n",
232 LogTime(), PROGRAM
, MAX_PAC_GROUP_SIZE
, ad_groups
);
235 if (!pstrcat(ad_groups
,base64_encode_bin(ag
, (int)(length
+4)))) {
236 debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n",
237 LogTime(), PROGRAM
, MAX_PAC_GROUP_SIZE
, ad_groups
);
242 /* mainly for debug only */
244 bpos
= bpos
+ 1; /*nsub*/
245 idauth
= get6byt_be();
247 snprintf(dli
,sizeof(dli
),"S-%d-%lu",rev
,(long unsigned int)idauth
);
248 for ( l
=0; l
<(int)nauth
; l
++ ) {
250 snprintf((char *)&dli
[strlen(dli
)],sizeof(dli
)-strlen(dli
),"-%u",sauth
);
252 debug((char *) "%s| %s: INFO: Got DomainLogonId %s\n", LogTime(), PROGRAM
, dli
);
258 getextrasids(char *ad_groups
, uint32_t ExtraSids
, uint32_t SidCount
)
269 if ( ngroup
!= SidCount
) {
270 debug((char *) "%s| %s: ERROR: Group encoding error => SidCount: %d Array size: %d\n",
271 LogTime(), PROGRAM
, SidCount
, ngroup
);
274 debug((char *) "%s| %s: INFO: Found %d ExtraSIDs\n", LogTime(), PROGRAM
, SidCount
);
276 pa
=(uint32_t *)xmalloc(SidCount
*sizeof(uint32_t));
277 for ( l
=0; l
< (int)SidCount
; l
++ ) {
279 bpos
= bpos
+4; /* attr */
282 for ( l
=0; l
<(int)SidCount
; l
++ ) {
293 length
= 1+1+6+nauth
*4;
294 ag
= (char *)xcalloc((length
)*sizeof(char),1);
295 memcpy((void *)ag
,(const void*)&p
[bpos
],length
);
297 if (!pstrcpy(ad_groups
,"group=")) {
298 debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n",
299 LogTime(), PROGRAM
, MAX_PAC_GROUP_SIZE
, ad_groups
);
302 if (!pstrcat(ad_groups
," group=")) {
303 debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n",
304 LogTime(), PROGRAM
, MAX_PAC_GROUP_SIZE
, ad_groups
);
307 if (!pstrcat(ad_groups
,base64_encode_bin(ag
, (int)length
))) {
308 debug((char *) "%s| %s: WARN: Too many groups ! size > %d : %s\n",
309 LogTime(), PROGRAM
, MAX_PAC_GROUP_SIZE
, ad_groups
);
314 bpos
= bpos
+ 1; /* nsub */
315 idauth
= get6byt_be();
317 snprintf(es
,sizeof(es
),"S-%d-%lu",rev
,(long unsigned int)idauth
);
318 for ( k
=0; k
<(int)nauth
; k
++ ) {
320 snprintf((char *)&es
[strlen(es
)],sizeof(es
)-strlen(es
),"-%u",sauth
);
322 debug((char *) "%s| %s: INFO: Got ExtraSid %s\n", LogTime(), PROGRAM
, es
);
331 get_ad_groups(char *ad_groups
, krb5_context context
, krb5_pac pac
)
334 RPC_UNICODE_STRING EffectiveName
;
335 RPC_UNICODE_STRING FullName
;
336 RPC_UNICODE_STRING LogonScript
;
337 RPC_UNICODE_STRING ProfilePath
;
338 RPC_UNICODE_STRING HomeDirectory
;
339 RPC_UNICODE_STRING HomeDirectoryDrive
;
340 RPC_UNICODE_STRING LogonServer
;
341 RPC_UNICODE_STRING LogonDomainName
;
342 uint32_t GroupCount
=0;
344 uint32_t LogonDomainId
=0;
346 uint32_t ExtraSids
=0;
348 uint32_t ResourceGroupDomainSid=0;
349 uint32_t ResourceGroupCount=0;
350 uint32_t ResourceGroupIds=0;
355 ad_data
= (krb5_data
*)xcalloc(1,sizeof(krb5_data
));
357 #define KERB_LOGON_INFO 1
358 ret
= krb5_pac_get_buffer(context
, pac
, KERB_LOGON_INFO
, ad_data
);
359 if (check_k5_err(context
, "krb5_pac_get_buffer", ret
))
362 p
= (unsigned char *)ad_data
->data
;
364 debug((char *) "%s| %s: INFO: Got PAC data of lengh %d\n",
365 LogTime(), PROGRAM
, (int)ad_data
->length
);
367 /* Skip 16 bytes icommon RPC header
368 * Skip 4 bytes RPC unique pointer referent
369 * http://msdn.microsoft.com/en-gb/library/cc237933.aspx
371 /* Some data are pointers to data which follows the main KRB5 LOGON structure =>
372 * So need to read the data
373 * some logical consistency checks are done when analysineg the pointer data
378 * 8 bytes KickOffTime
379 * 8 bytes PasswordLastSet
380 * 8 bytes PasswordCanChange
381 * 8 bytes PasswordMustChange
384 getustr(&EffectiveName
);
386 getustr(&LogonScript
);
387 getustr(&ProfilePath
);
388 getustr(&HomeDirectory
);
389 getustr(&HomeDirectoryDrive
);
390 /* 2 bytes LogonCount
391 * 2 bytes BadPasswordCount
393 * 4 bytes PrimaryGroupId
396 GroupCount
= get4byt();
397 GroupIds
= get4byt();
399 * 16 bytes UserSessionKey
402 getustr(&LogonServer
);
403 getustr(&LogonDomainName
);
404 LogonDomainId
= get4byt();
406 * 4 bytes UserAccountControl
407 * 4 bytes SubAuthStatus
408 * 8 bytes LastSuccessfullLogon
409 * 8 bytes LastFailedLogon
410 * 4 bytes FailedLogonCount
414 SidCount
= get4byt();
415 ExtraSids
= get4byt();
416 /* 4 bytes ResourceGroupDomainSid
417 * 4 bytes ResourceGroupCount
418 * 4 bytes ResourceGroupIds
422 * Read all data from structure => Now check pointers
424 if (checkustr(&EffectiveName
)<0)
426 if (checkustr(&FullName
)<0)
428 if (checkustr(&LogonScript
)<0)
430 if (checkustr(&ProfilePath
)<0)
432 if (checkustr(&HomeDirectory
)<0)
434 if (checkustr(&HomeDirectoryDrive
)<0)
436 Rids
= getgids(Rids
,GroupIds
,GroupCount
);
437 if (checkustr(&LogonServer
)<0)
439 if (checkustr(&LogonDomainName
)<0)
441 ad_groups
= getdomaingids(ad_groups
,LogonDomainId
,Rids
,GroupCount
);
442 if ((ad_groups
= getextrasids(ad_groups
,ExtraSids
,SidCount
))==NULL
)
445 debug((char *) "%s| %s: INFO: Read %d of %d bytes \n", LogTime(), PROGRAM
, bpos
, (int)ad_data
->length
);
447 for ( l
=0; l
<(int)GroupCount
; l
++) {
452 krb5_free_data(context
, ad_data
);
456 for ( l
=0; l
<(int)GroupCount
; l
++) {
461 krb5_free_data(context
, ad_data
);