Use correct name-type in TGS-REQs for 2008R2 RODCs
[krb5.git] / src / lib / krb5 / krb / fwd_tgt.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/krb/fwd_tgt.c Definition of krb5_fwd_tgt_creds() routine */
3 /*
4  * Copyright 1995 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  *
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  Furthermore if you modify this software you must label
20  * your software as modified software and not distribute it in such a
21  * fashion that it might be confused with the original M.I.T. software.
22  * M.I.T. makes no representations about the suitability of
23  * this software for any purpose.  It is provided "as is" without express
24  * or implied warranty.
25  */
26
27 #include "k5-int.h"
28 #ifdef HAVE_MEMORY_H
29 #include <memory.h>
30 #endif
31 #include "int-proto.h"
32
33 /* helper function: convert flags to necessary KDC options */
34 #define flags2options(flags) (flags & KDC_TKT_COMMON_MASK)
35
36 /* Get a TGT for use at the remote host */
37 krb5_error_code KRB5_CALLCONV
38 krb5_fwd_tgt_creds(krb5_context context, krb5_auth_context auth_context,
39                    char *rhost, krb5_principal client, krb5_principal server,
40                    krb5_ccache cc, int forwardable, krb5_data *outbuf)
41 /* Should forwarded TGT also be forwardable? */
42 {
43     krb5_replay_data replaydata;
44     krb5_data * scratch = 0;
45     krb5_address **addrs = NULL;
46     krb5_error_code retval;
47     krb5_creds creds, tgt;
48     krb5_creds *pcreds;
49     krb5_flags kdcoptions;
50     int close_cc = 0;
51     int free_rhost = 0;
52     krb5_enctype enctype = 0;
53     krb5_keyblock *session_key;
54     krb5_boolean old_use_conf_ktypes = context->use_conf_ktypes;
55
56     memset(&creds, 0, sizeof(creds));
57     memset(&tgt, 0, sizeof(creds));
58
59     if (cc == 0) {
60         if ((retval = krb5int_cc_default(context, &cc)))
61             goto errout;
62         close_cc = 1;
63     }
64     retval = krb5_auth_con_getkey (context, auth_context, &session_key);
65     if (retval)
66         goto errout;
67     if (session_key) {
68         enctype = session_key->enctype;
69         krb5_free_keyblock (context, session_key);
70         session_key = NULL;
71     } else if (server) { /* must server be non-NULL when rhost is given? */
72         /* Try getting credentials to see what the remote side supports.
73            Not bulletproof, just a heuristic.  */
74         krb5_creds in, *out = 0;
75         memset (&in, 0, sizeof(in));
76
77         retval = krb5_copy_principal (context, server, &in.server);
78         if (retval)
79             goto punt;
80         retval = krb5_copy_principal (context, client, &in.client);
81         if (retval)
82             goto punt;
83         retval = krb5_get_credentials (context, 0, cc, &in, &out);
84         if (retval)
85             goto punt;
86         /* Got the credentials.  Okay, now record the enctype and
87            throw them away.  */
88         enctype = out->keyblock.enctype;
89         krb5_free_creds (context, out);
90     punt:
91         krb5_free_cred_contents (context, &in);
92     }
93
94     if ((retval = krb5_copy_principal(context, client, &creds.client)))
95         goto errout;
96
97     retval = krb5int_tgtname(context, &client->realm, &client->realm,
98                              &creds.server);
99     if (retval)
100         goto errout;
101
102     /* fetch tgt directly from cache */
103     context->use_conf_ktypes = 1;
104     retval = krb5_cc_retrieve_cred (context, cc, KRB5_TC_SUPPORTED_KTYPES,
105                                     &creds, &tgt);
106     context->use_conf_ktypes = old_use_conf_ktypes;
107     if (retval)
108         goto errout;
109
110     /* tgt->client must be equal to creds.client */
111     if (!krb5_principal_compare(context, tgt.client, creds.client)) {
112         retval = KRB5_PRINC_NOMATCH;
113         goto errout;
114     }
115
116     if (!tgt.ticket.length) {
117         retval = KRB5_NO_TKT_SUPPLIED;
118         goto errout;
119     }
120
121     if (tgt.addresses && *tgt.addresses) {
122         if (rhost == NULL) {
123             if (krb5_princ_type(context, server) != KRB5_NT_SRV_HST) {
124                 retval = KRB5_FWD_BAD_PRINCIPAL;
125                 goto errout;
126             }
127
128             if (krb5_princ_size(context, server) < 2){
129                 retval = KRB5_CC_BADNAME;
130                 goto errout;
131             }
132
133             rhost = malloc(server->data[1].length+1);
134             if (!rhost) {
135                 retval = ENOMEM;
136                 goto errout;
137             }
138             free_rhost = 1;
139             memcpy(rhost, server->data[1].data, server->data[1].length);
140             rhost[server->data[1].length] = '\0';
141         }
142
143         retval = krb5_os_hostaddr(context, rhost, &addrs);
144         if (retval)
145             goto errout;
146     }
147
148     creds.keyblock.enctype = enctype;
149     creds.times = tgt.times;
150     creds.times.starttime = 0;
151     kdcoptions = flags2options(tgt.ticket_flags)|KDC_OPT_FORWARDED;
152
153     if (!forwardable) /* Reset KDC_OPT_FORWARDABLE */
154         kdcoptions &= ~(KDC_OPT_FORWARDABLE);
155
156     if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions,
157                                         addrs, &creds, &pcreds))) {
158         if (enctype) {
159             creds.keyblock.enctype = 0;
160             if ((retval = krb5_get_cred_via_tkt(context, &tgt, kdcoptions,
161                                                 addrs, &creds, &pcreds)))
162                 goto errout;
163         }
164         else goto errout;
165     }
166     retval = krb5_mk_1cred(context, auth_context, pcreds,
167                            &scratch, &replaydata);
168     krb5_free_creds(context, pcreds);
169
170     if (retval) {
171         if (scratch)
172             krb5_free_data(context, scratch);
173     } else {
174         *outbuf = *scratch;
175         free(scratch);
176     }
177
178 errout:
179     if (addrs)
180         krb5_free_addresses(context, addrs);
181     if (close_cc)
182         krb5_cc_close(context, cc);
183     if (free_rhost)
184         free(rhost);
185     krb5_free_cred_contents(context, &creds);
186     krb5_free_cred_contents(context, &tgt);
187     return retval;
188 }