Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/kdc/dispatch.c
34869 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* kdc/dispatch.c - Dispatch an incoming packet */
3
/*
4
* Copyright 1990, 2009 by the Massachusetts Institute of Technology.
5
*
6
* Export of this software from the United States of America may
7
* require a specific license from the United States Government.
8
* It is the responsibility of any person or organization contemplating
9
* export to obtain such a license before exporting.
10
*
11
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
12
* distribute this software and its documentation for any purpose and
13
* without fee is hereby granted, provided that the above copyright
14
* notice appear in all copies and that both that copyright notice and
15
* this permission notice appear in supporting documentation, and that
16
* the name of M.I.T. not be used in advertising or publicity pertaining
17
* to distribution of the software without specific, written prior
18
* permission. Furthermore if you modify this software you must label
19
* your software as modified software and not distribute it in such a
20
* fashion that it might be confused with the original M.I.T. software.
21
* M.I.T. makes no representations about the suitability of
22
* this software for any purpose. It is provided "as is" without express
23
* or implied warranty.
24
*/
25
26
#include "k5-int.h"
27
#include <syslog.h>
28
#include "kdc_util.h"
29
#include "extern.h"
30
#include "adm_proto.h"
31
#include "realm_data.h"
32
#include <netinet/in.h>
33
#include <arpa/inet.h>
34
#include <string.h>
35
36
static krb5_error_code make_too_big_error(kdc_realm_t *realm, krb5_data **out);
37
38
struct dispatch_state {
39
loop_respond_fn respond;
40
void *arg;
41
krb5_data *request;
42
int is_tcp;
43
kdc_realm_t *active_realm;
44
krb5_context kdc_err_context;
45
};
46
47
static void
48
finish_dispatch(struct dispatch_state *state, krb5_error_code code,
49
krb5_data *response)
50
{
51
loop_respond_fn oldrespond = state->respond;
52
void *oldarg = state->arg;
53
54
if (state->is_tcp == 0 && response &&
55
response->length > (unsigned int)max_dgram_reply_size) {
56
krb5_free_data(NULL, response);
57
response = NULL;
58
code = make_too_big_error(state->active_realm, &response);
59
if (code)
60
krb5_klog_syslog(LOG_ERR, "error constructing "
61
"KRB_ERR_RESPONSE_TOO_BIG error: %s",
62
error_message(code));
63
}
64
65
free(state);
66
(*oldrespond)(oldarg, code, response);
67
}
68
69
static void
70
finish_dispatch_cache(void *arg, krb5_error_code code, krb5_data *response)
71
{
72
struct dispatch_state *state = arg;
73
krb5_context kdc_err_context = state->kdc_err_context;
74
75
#ifndef NOCACHE
76
/* Remove the null cache entry unless we actually want to discard this
77
* request. */
78
if (code != KRB5KDC_ERR_DISCARD)
79
kdc_remove_lookaside(kdc_err_context, state->request);
80
81
/* Put the response into the lookaside buffer (if we produced one). */
82
if (code == 0 && response != NULL)
83
kdc_insert_lookaside(kdc_err_context, state->request, response);
84
#endif
85
86
finish_dispatch(state, code, response);
87
}
88
89
void
90
dispatch(void *cb, const struct sockaddr *local_addr,
91
const struct sockaddr *remote_addr, krb5_data *pkt, int is_tcp,
92
verto_ctx *vctx, loop_respond_fn respond, void *arg)
93
{
94
krb5_error_code retval;
95
krb5_kdc_req *req = NULL;
96
krb5_data *response = NULL;
97
struct dispatch_state *state;
98
struct server_handle *handle = cb;
99
krb5_context kdc_err_context = handle->kdc_err_context;
100
101
state = k5alloc(sizeof(*state), &retval);
102
if (state == NULL) {
103
(*respond)(arg, retval, NULL);
104
return;
105
}
106
state->respond = respond;
107
state->arg = arg;
108
state->request = pkt;
109
state->is_tcp = is_tcp;
110
state->kdc_err_context = kdc_err_context;
111
112
/* decode incoming packet, and dispatch */
113
114
#ifndef NOCACHE
115
/* try the replay lookaside buffer */
116
if (kdc_check_lookaside(kdc_err_context, pkt, &response)) {
117
/* a hit! */
118
const char *name = 0;
119
char buf[128];
120
121
k5_print_addr(remote_addr, buf, sizeof(buf));
122
if (name == 0)
123
name = "[unknown address type]";
124
if (response)
125
krb5_klog_syslog(LOG_INFO,
126
"DISPATCH: repeated (retransmitted?) request "
127
"from %s, resending previous response", name);
128
else
129
krb5_klog_syslog(LOG_INFO,
130
"DISPATCH: repeated (retransmitted?) request "
131
"from %s during request processing, dropping "
132
"repeated request", name);
133
134
finish_dispatch(state, response ? 0 : KRB5KDC_ERR_DISCARD, response);
135
return;
136
}
137
138
/* Insert a NULL entry into the lookaside to indicate that this request
139
* is currently being processed. */
140
kdc_insert_lookaside(kdc_err_context, pkt, NULL);
141
#endif
142
143
/* try TGS_REQ first; they are more common! */
144
145
if (krb5_is_tgs_req(pkt))
146
retval = decode_krb5_tgs_req(pkt, &req);
147
else if (krb5_is_as_req(pkt))
148
retval = decode_krb5_as_req(pkt, &req);
149
else
150
retval = KRB5KRB_AP_ERR_MSG_TYPE;
151
if (retval)
152
goto done;
153
154
state->active_realm = setup_server_realm(handle, req->server);
155
if (state->active_realm == NULL) {
156
retval = KRB5KDC_ERR_WRONG_REALM;
157
goto done;
158
}
159
160
if (krb5_is_tgs_req(pkt)) {
161
/* process_tgs_req frees the request */
162
retval = process_tgs_req(req, pkt, remote_addr, state->active_realm,
163
&response);
164
req = NULL;
165
} else if (krb5_is_as_req(pkt)) {
166
/* process_as_req frees the request and calls finish_dispatch_cache. */
167
process_as_req(req, pkt, local_addr, remote_addr, state->active_realm,
168
vctx, finish_dispatch_cache, state);
169
return;
170
}
171
172
done:
173
krb5_free_kdc_req(kdc_err_context, req);
174
finish_dispatch_cache(state, retval, response);
175
}
176
177
static krb5_error_code
178
make_too_big_error(kdc_realm_t *realm, krb5_data **out)
179
{
180
krb5_context context = realm->realm_context;
181
krb5_error errpkt;
182
krb5_error_code retval;
183
krb5_data *scratch;
184
185
*out = NULL;
186
memset(&errpkt, 0, sizeof(errpkt));
187
188
retval = krb5_us_timeofday(context, &errpkt.stime, &errpkt.susec);
189
if (retval)
190
return retval;
191
errpkt.error = KRB_ERR_RESPONSE_TOO_BIG;
192
errpkt.server = realm->realm_tgsprinc;
193
errpkt.client = NULL;
194
errpkt.text.length = 0;
195
errpkt.text.data = 0;
196
errpkt.e_data.length = 0;
197
errpkt.e_data.data = 0;
198
scratch = malloc(sizeof(*scratch));
199
if (scratch == NULL)
200
return ENOMEM;
201
retval = krb5_mk_error(context, &errpkt, scratch);
202
if (retval) {
203
free(scratch);
204
return retval;
205
}
206
207
*out = scratch;
208
return 0;
209
}
210
211
krb5_context get_context(void *handle)
212
{
213
struct server_handle *sh = handle;
214
215
return sh->kdc_err_context;
216
}
217
218