Obtaining Kerberos Tickets without the Microsoft PAC
Douglas E. Engert
deengert at anl.gov
Thu Aug 21 14:53:29 EDT 2003
The Microsoft AD issues Kerberos tickets with an authorization data
called a PAC. I would like to request Microsoft make a change in this area
as stated below. The PAC and its use has been documented in:
Kerberos working group John Brezak
Internet Draft Microsoft
Document: draft-brezak-win2k-krb-authz-01.txt
Category: Informational October, 2002
Utilizing the Windows 2000 Authorization Data in Kerberos Tickets for
Access Control to Resources
The PAC is large, and can easily increase the size of a ticket more then 500%.
Tickets without the PAC are about 240 bytes. With a simple PAC, they may be
1,200 bytes. With Windows 2003, the max size of the ticket was increased
from 8,000 to 12,000 bytes! (Someone must have run into this limit!!)
This increase in size can cause problems with older applications. where
a ticket might be used with UDP or RPCs.
The draft describes in its section 6, a PA-DATA element that can be used
to request a ticket without a PAC. But unfortunately it has limited value
in my option.
The PA-DATA element can only be used with an AS-REQ, and not a TGS-REQ.
(Some tests confirm that W2K works this way.) This means that the pa-data must
be requested at the time of the initial TGT when the password is entered, and
all subsequent ticket will have or not have a PAC. This restricts the use of
the forwarded tickets, when some services may need a PAC, and others don't.
The Microsoft runas.exe for example has the /netonly option. If a client sets
the SEC_WINNT_AUTH_IDENTITY_ONLY flag in the SEC_WINNT_AUTH_IDENTITY_EX
structure when calling the SSPI AcquireCredentialsHandle, the service ticket
obtained will not have a PAC. The best I can tell, it appears to actually
use the stashed password from login to get a new TGT using a AS-REQ.
If they have not done so already, I would like to request Microsoft to do
one or both of the following:
o Honor the PA-PAC-REQUEST when sent in with an TGT-REQ. This would allow
the client to authenticate only once, but request a service ticket with or
without the PAC. Having to use the stashed password, is not acceptable,
and can not be used in situations where the password in not available.
(This would require a change to the KDC which should be backward compatable.)
o Add a flag in the registry for each service, indicating if a PAC should
be added to tickets for this service. Service either will use
the PAC or ignore it. If you know a service does not understand the PAC,
don't add it! This is especially true for some services where the size
of the ticket is a problem. (This would require a change to the KDC, and
the registry which are also backwards compatible.)
I would prefer the second choice, as it should not be up to the client to
decide if the server needs or wants a PAC. It is really an attribute of the
server which the KDC could know.
Attached are some mods to the MIT krb5-1.3.1 kinit.c and the library
that will send the KERB-PA-PAC-REQUEST in the AS-REQ if a -m is added
to the kinit command. This works to a W2K KDC, but since the MIT KDC
does not understand this pa-data type, it gets rejected.
A simple test of getting a TGT and a service ticket for afs/cell at realm show
the size of the ticket cache with a PAC was 2,637 bytes, and without the PACs
(both the TGT and the service ticket have a copy) was 769 bytes. The actual
size of the ticket for use by AFS dropped from 1,176 to 242 bytes.
So without these changes or major changes to AFS it is not practical to use
the Microsoft KDC to directly issue a ticket that can be used for an AFS token.
An intermediate conversion server, such as krb524d or gssklogd is needed
to decrypt the ticket, and discard the unused PAC.
Here are the mods to krb5-1.3.1 used for testing. You need to compile with
the -DNOMSPAC flag, then use the kinit -m option.
*** ./include/,krb5.hin Mon Jul 21 13:43:37 2003
--- ./include/krb5.hin Wed Aug 20 15:46:45 2003
***************
*** 876,881 ****
--- 876,884 ----
#define KRB5_PADATA_SAM_CHALLENGE_2 30 /* draft challenge system, updated */
#define KRB5_PADATA_SAM_RESPONSE_2 31 /* draft challenge system, updated */
+ #ifdef NOMSPAC
+ #define KRB5_PADATA_PAC_REQUEST 128
+ #endif
#define KRB5_SAM_USE_SAD_AS_KEY 0x80000000
#define KRB5_SAM_SEND_ENCRYPTED_SAD 0x40000000
#define KRB5_SAM_MUST_PK_ENCRYPT_SAD 0x20000000 /* currently must be zero */
***************
*** 2414,2419 ****
--- 2417,2425 ----
#define KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST 0x0020
#define KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST 0x0040
#define KRB5_GET_INIT_CREDS_OPT_SALT 0x0080
+ #ifdef NOMSPAC
+ #define KRB5_GET_INIT_CREDS_OPT_PA_PAC_REQUEST 0x0100
+ #endif
void KRB5_CALLCONV
***************
*** 2461,2466 ****
--- 2467,2479 ----
krb5_get_init_creds_opt_set_salt
(krb5_get_init_creds_opt *opt,
krb5_data *salt);
+
+ #ifdef NOMSPAC
+ void KRB5_CALLCONV
+ krb5_get_init_creds_opt_set_pa_pac_request
+ (krb5_get_init_creds_opt *opt);
+ #endif
+
krb5_error_code KRB5_CALLCONV
krb5_get_init_creds_password
*** ./clients/kinit/,kinit.c Thu Aug 14 10:46:02 2003
--- ./clients/kinit/kinit.c Wed Aug 20 15:56:39 2003
***************
*** 141,146 ****
--- 142,150 ----
char* k4_cache_name;
action_type action;
+ #ifdef NOMSPAC
+ int nomspac;
+ #endif
};
struct k5_data
***************
*** 211,220 ****
--- 215,226 ----
USAGE_BREAK_LONG
"[-A" USAGE_LONG_ADDRESSES "] "
USAGE_BREAK
+ "[-m] "
"[-v] [-R] "
"[-k [-t keytab_file]] "
USAGE_BREAK
"[-c cachename] "
"[-S service_name] [principal]"
"\n\n",
progname);
***************
*** 257,266 ****
--- 263,276 ----
ULINE("\t", "-p proxiable", OPTTYPE_KRB5);
ULINE("\t", "-P not proxiable", OPTTYPE_KRB5);
ULINE("\t", "-A do not include addresses", OPTTYPE_KRB5);
+ #ifdef NOMSPAC
+ ULINE("\t", "-m No PAC in ticket", OPTTYPE_KRB5);
+ #endif
ULINE("\t", "-v validate", OPTTYPE_KRB5);
ULINE("\t", "-R renew", OPTTYPE_BOTH);
ULINE("\t", "-k use keytab", OPTTYPE_BOTH);
ULINE("\t", "-t filename of keytab to use", OPTTYPE_BOTH);
ULINE("\t", "-c Kerberos 5 cache name", OPTTYPE_KRB5);
/* This options is not yet available: */
/* ULINE("\t", "-C Kerberos 4 cache name", OPTTYPE_KRB4); */
***************
*** 281,289 ****
int use_k5 = 0;
int i;
! while ((i = GETOPT(argc, argv, "r:fpFP54AVl:s:c:kt:RS:v"))
!= -1) {
switch (i) {
case 'V':
opts->verbose = 1;
break;
--- 291,304 ----
int use_k5 = 0;
int i;
! while ((i = GETOPT(argc, argv, "r:fpFP54AVl:s:c:kt:RS:vm"))
!= -1) {
switch (i) {
+ #ifdef NOMSPAC
+ case 'm':
+ opts->nomspac = 1;
+ break;
+ #endif
case 'V':
opts->verbose = 1;
break;
***************
*** 749,754 ****
--- 769,778 ----
initialized.
*/
+ #ifdef NOMSPAC
+ if (opts->nomspac)
+ krb5_get_init_creds_opt_set_pa_pac_request(&options);
+ #endif
if (opts->lifetime)
krb5_get_init_creds_opt_set_tkt_life(&options, opts->lifetime);
if (opts->rlife)
*** ./lib/krb5/krb/,gic_opt.c Mon Sep 2 20:13:46 2002
--- ./lib/krb5/krb/gic_opt.c Wed Aug 20 15:29:41 2003
***************
*** 63,65 ****
--- 63,73 ----
opt->flags |= KRB5_GET_INIT_CREDS_OPT_SALT;
opt->salt = salt;
}
+
+ #ifdef NOMSPAC
+ void KRB5_CALLCONV
+ krb5_get_init_creds_opt_set_pa_pac_request(krb5_get_init_creds_opt *opt)
+ {
+ opt->flags |= KRB5_GET_INIT_CREDS_OPT_PA_PAC_REQUEST;
+ }
+ #endif
*** ./lib/krb5/krb/,get_in_tkt.c Fri Jun 6 17:02:01 2003
--- ./lib/krb5/krb/get_in_tkt.c Wed Aug 20 16:10:06 2003
***************
*** 78,83 ****
--- 78,147 ----
static krb5_error_code make_preauth_list (krb5_context,
krb5_preauthtype *,
int, krb5_pa_data ***);
+ #ifdef NOMSPAC
+ /* Add the Microsoft PA_PAC_REQUEST to the AS
+ * request. Since this needs to be sent on each AS_REQ
+ * the krb5_preauth routines can not be used, as they
+ * add a list the first time, but then only respond to the
+ * pa-data in the error response.
+ * See draft-brezak-win2k-krb-authz-01.txt section 6
+ * Also see MSDN for SEC_WINNT_AUTH_IDENTITY_ONLY
+ */
+ static krb5_error_code add_ms_pac_req(krb5_context context,
+ krb5_pa_data *** padata)
+ {
+ int i;
+ /* ASN1 for:
+ * KERB-PA-PAC-REQUEST ::= SEQUENCE {
+ * include-pac[0] BOOLEAN
+ * }
+ * where the value is false
+ */
+ static krb5_octet booldata[] = {"\x30\x05\xa0\x03\x01\x01\x00"};
+ void * tmp;
+ krb5_pa_data * pa;
+ krb5_pa_data * * new_padata;
+
+ if ((tmp = (void *)malloc(sizeof(booldata)-1)) == NULL)
+ return(ENOMEM);
+ memcpy(tmp, booldata, sizeof(booldata)-1);
+
+ if ((pa = (krb5_pa_data *)malloc(sizeof(krb5_pa_data))) == NULL) {
+ krb5_xfree(tmp);
+ return(ENOMEM);
+ }
+
+ pa->magic = KV5M_PA_DATA;
+ pa->pa_type = KRB5_PADATA_PAC_REQUEST;
+ pa->length = sizeof(booldata)-1;
+ pa->contents = tmp;
+
+ if (*padata == NULL) {
+ new_padata = (krb5_pa_data **)
+ malloc(2 * sizeof(krb5_pa_data *));
+ i = 0;
+ } else {
+ for (i=0; (*padata)[i]; i++); /* count */
+
+ new_padata = *padata;
+ new_padata = (krb5_pa_data **)
+ realloc(new_padata, (i+2) * sizeof(krb5_pa_data *));
+ }
+ if (new_padata == NULL) {
+ krb5_xfree(pa->contents);
+ krb5_xfree(pa);
+ return(ENOMEM);
+ }
+
+ new_padata[i++] = pa;
+ new_padata[i] = NULL;
+
+ *padata = new_padata;
+
+ return(0);
+ }
+ #endif
+
/*
* This function sends a request to the KDC, and gets back a response;
* the response is parsed into ret_err_reply or ret_as_reply if the
***************
*** 951,956 ****
--- 1015,1029 ----
prompter_data, gak_fct, gak_data)))
goto cleanup;
+ #ifdef NOMSPAC
+ if (options && (options->flags &
+ KRB5_GET_INIT_CREDS_OPT_PA_PAC_REQUEST)) {
+ if (ret = add_ms_pac_req(context, &request.padata)) {
+ goto cleanup;
+ }
+ }
+ #endif
+
if (padata) {
krb5_free_pa_data(context, padata);
padata = 0;
***************
*** 996,1001 ****
--- 1069,1082 ----
&salt, &s2kparams, &etype, &as_key, prompter,
prompter_data, gak_fct, gak_data)))
goto cleanup;
+ #ifdef NOMSPAC
+ if (options && (options->flags &
+ KRB5_GET_INIT_CREDS_OPT_PA_PAC_REQUEST)) {
+ if (ret = add_ms_pac_req(context, &padata)) {
+ goto cleanup;
+ }
+ }
+ #endif
/* XXX if there's padata on output, something is wrong, but it's
not obviously an error */
--
Douglas E. Engert <DEEngert at anl.gov>
Argonne National Laboratory
9700 South Cass Avenue
Argonne, Illinois 60439
(630) 252-5444
More information about the krbdev
mailing list