kdc: principals of type NT-UNKNOWN can be anonymous
[metze/heimdal/wip.git] / kdc / misc.c
1 /*
2  * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the Institute nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #include "kdc_locl.h"
35
36 struct timeval _kdc_now;
37
38 krb5_error_code
39 _kdc_db_fetch(krb5_context context,
40               krb5_kdc_configuration *config,
41               krb5_const_principal principal,
42               unsigned flags,
43               krb5uint32 *kvno_ptr,
44               HDB **db,
45               hdb_entry_ex **h)
46 {
47     hdb_entry_ex *ent;
48     krb5_error_code ret = HDB_ERR_NOENTRY;
49     int i;
50     unsigned kvno = 0;
51     krb5_principal enterprise_principal = NULL;
52     krb5_const_principal princ;
53
54     *h = NULL;
55
56     if (kvno_ptr != NULL && *kvno_ptr != 0) {
57         kvno = *kvno_ptr;
58         flags |= HDB_F_KVNO_SPECIFIED;
59     } else {
60         flags |= HDB_F_ALL_KVNOS;
61     }
62
63     ent = calloc(1, sizeof (*ent));
64     if (ent == NULL)
65         return krb5_enomem(context);
66
67     if (principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
68         if (principal->name.name_string.len != 1) {
69             ret = KRB5_PARSE_MALFORMED;
70             krb5_set_error_message(context, ret,
71                                    "malformed request: "
72                                    "enterprise name with %d name components",
73                                    principal->name.name_string.len);
74             goto out;
75         }
76         ret = krb5_parse_name(context, principal->name.name_string.val[0],
77                               &enterprise_principal);
78         if (ret)
79             goto out;
80     }
81
82     for (i = 0; i < config->num_db; i++) {
83         ret = config->db[i]->hdb_open(context, config->db[i], O_RDONLY, 0);
84         if (ret) {
85             const char *msg = krb5_get_error_message(context, ret);
86             kdc_log(context, config, 0, "Failed to open database: %s", msg);
87             krb5_free_error_message(context, msg);
88             continue;
89         }
90
91         princ = principal;
92         if (!(config->db[i]->hdb_capability_flags & HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL) && enterprise_principal)
93             princ = enterprise_principal;
94
95         ret = config->db[i]->hdb_fetch_kvno(context,
96                                             config->db[i],
97                                             princ,
98                                             flags | HDB_F_DECRYPT,
99                                             kvno,
100                                             ent);
101         config->db[i]->hdb_close(context, config->db[i]);
102
103         switch (ret) {
104         case HDB_ERR_WRONG_REALM:
105             /*
106              * the ent->entry.principal just contains hints for the client
107              * to retry. This is important for enterprise principal routing
108              * between trusts.
109              */
110             /* fall through */
111         case 0:
112             if (db)
113                 *db = config->db[i];
114             *h = ent;
115             ent = NULL;
116             goto out;
117
118         case HDB_ERR_NOENTRY:
119             /* Check the other databases */
120             continue;
121
122         default:
123             /* 
124              * This is really important, because errors like
125              * HDB_ERR_NOT_FOUND_HERE (used to indicate to Samba that
126              * the RODC on which this code is running does not have
127              * the key we need, and so a proxy to the KDC is required)
128              * have specific meaning, and need to be propogated up.
129              */
130             goto out;
131         }
132     }
133
134     if (ret == HDB_ERR_NOENTRY) {
135         krb5_set_error_message(context, ret, "no such entry found in hdb");
136     }
137 out:
138     krb5_free_principal(context, enterprise_principal);
139     free(ent);
140     return ret;
141 }
142
143 void
144 _kdc_free_ent(krb5_context context, hdb_entry_ex *ent)
145 {
146     hdb_free_entry (context, ent);
147     free (ent);
148 }
149
150 /*
151  * Use the order list of preferred encryption types and sort the
152  * available keys and return the most preferred key.
153  */
154
155 krb5_error_code
156 _kdc_get_preferred_key(krb5_context context,
157                        krb5_kdc_configuration *config,
158                        hdb_entry_ex *h,
159                        const char *name,
160                        krb5_enctype *enctype,
161                        Key **key)
162 {
163     krb5_error_code ret;
164     int i;
165
166     if (config->use_strongest_server_key) {
167         const krb5_enctype *p = krb5_kerberos_enctypes(context);
168
169         for (i = 0; p[i] != (krb5_enctype)ETYPE_NULL; i++) {
170             if (krb5_enctype_valid(context, p[i]) != 0 &&
171                 !_kdc_is_weak_exception(h->entry.principal, p[i]))
172                 continue;
173             ret = hdb_enctype2key(context, &h->entry, NULL, p[i], key);
174             if (ret != 0)
175                 continue;
176             if (enctype != NULL)
177                 *enctype = p[i];
178             return 0;
179         }
180     } else {
181         *key = NULL;
182
183         for (i = 0; i < h->entry.keys.len; i++) {
184             if (krb5_enctype_valid(context, h->entry.keys.val[i].key.keytype) != 0 &&
185                 !_kdc_is_weak_exception(h->entry.principal, h->entry.keys.val[i].key.keytype))
186                 continue;
187             ret = hdb_enctype2key(context, &h->entry, NULL,
188                                   h->entry.keys.val[i].key.keytype, key);
189             if (ret != 0)
190                 continue;
191             if (enctype != NULL)
192                 *enctype = (*key)->key.keytype;
193             return 0;
194         }
195     }
196
197     krb5_set_error_message(context, EINVAL,
198                            "No valid kerberos key found for %s", name);
199     return EINVAL; /* XXX */
200 }
201