1 /*        $NetBSD: kdc-replay.c,v 1.3 2023/06/19 21:41:41 christos Exp $        */
2 
3 /*
4  * Copyright (c) 2007 Kungliga Tekniska Högskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the Institute nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include "kdc_locl.h"
37 
38 static int version_flag;
39 static int help_flag;
40 
41 struct getargs args[] = {
42     { "version",   0,         arg_flag, &version_flag, NULL, NULL },
43     { "help",     'h',        arg_flag, &help_flag,    NULL, NULL }
44 };
45 
46 static const int num_args = sizeof(args) / sizeof(args[0]);
47 
48 static void
usage(int ret)49 usage(int ret)
50 {
51     arg_printusage (args, num_args, NULL, "kdc-request-log-file");
52     exit (ret);
53 }
54 
55 int
main(int argc,char ** argv)56 main(int argc, char **argv)
57 {
58     krb5_error_code ret;
59     krb5_context context;
60     krb5_kdc_configuration *config;
61     krb5_storage *sp;
62     int fd, optidx = 0;
63 
64     setprogname(argv[0]);
65 
66     if(getarg(args, num_args, argc, argv, &optidx))
67           usage(1);
68 
69     if(help_flag)
70           usage(0);
71 
72     if(version_flag){
73           print_version(NULL);
74           exit(0);
75     }
76 
77     ret = krb5_init_context(&context);
78     if (ret)
79           errx (1, "krb5_init_context failed to parse configuration file");
80 
81     ret = krb5_kdc_get_config(context, &config);
82     if (ret)
83           krb5_err(context, 1, ret, "krb5_kdc_default_config");
84 
85     kdc_openlog(context, "kdc-replay", config);
86 
87     ret = krb5_kdc_set_dbinfo(context, config);
88     if (ret)
89           krb5_err(context, 1, ret, "krb5_kdc_set_dbinfo");
90 
91 #ifdef PKINIT
92     if (config->enable_pkinit) {
93           if (config->pkinit_kdc_identity == NULL)
94               krb5_errx(context, 1, "pkinit enabled but no identity");
95 
96           if (config->pkinit_kdc_anchors == NULL)
97               krb5_errx(context, 1, "pkinit enabled but no X509 anchors");
98 
99           krb5_kdc_pk_initialize(context, config,
100                                      config->pkinit_kdc_identity,
101                                      config->pkinit_kdc_anchors,
102                                      config->pkinit_kdc_cert_pool,
103                                      config->pkinit_kdc_revoke);
104 
105     }
106 #endif /* PKINIT */
107 
108     if (argc != 2)
109           errx(1, "argc != 2");
110 
111     printf("kdc replay\n");
112 
113     fd = open(argv[1], O_RDONLY);
114     if (fd < 0)
115           err(1, "open: %s", argv[1]);
116 
117     sp = krb5_storage_from_fd(fd);
118     if (sp == NULL)
119           krb5_errx(context, 1, "krb5_storage_from_fd");
120 
121     while(1) {
122           struct sockaddr_storage sa;
123           krb5_socklen_t salen = sizeof(sa);
124           struct timeval tv;
125           krb5_address a;
126           krb5_data d, r;
127           uint32_t t, clty, tag;
128           char astr[80];
129 
130           ret = krb5_ret_uint32(sp, &t);
131           if (ret == HEIM_ERR_EOF)
132               break;
133           else if (ret)
134               krb5_errx(context, 1, "krb5_ret_uint32(version)");
135           if (t != 1)
136               krb5_errx(context, 1, "version not 1");
137           ret = krb5_ret_uint32(sp, &t);
138           if (ret)
139               krb5_errx(context, 1, "krb5_ret_uint32(time)");
140           ret = krb5_ret_address(sp, &a);
141           if (ret)
142               krb5_errx(context, 1, "krb5_ret_address");
143           ret = krb5_ret_data(sp, &d);
144           if (ret)
145               krb5_errx(context, 1, "krb5_ret_data");
146           ret = krb5_ret_uint32(sp, &clty);
147           if (ret)
148               krb5_errx(context, 1, "krb5_ret_uint32(class|type)");
149           ret = krb5_ret_uint32(sp, &tag);
150           if (ret)
151               krb5_errx(context, 1, "krb5_ret_uint32(tag)");
152 
153 
154           ret = krb5_addr2sockaddr (context, &a, (struct sockaddr *)&sa,
155                                           &salen, 88);
156           if (ret == KRB5_PROG_ATYPE_NOSUPP)
157               goto out;
158           else if (ret)
159               krb5_err(context, 1, ret, "krb5_addr2sockaddr");
160 
161           ret = krb5_print_address(&a, astr, sizeof(astr), NULL);
162           if (ret)
163               krb5_err(context, 1, ret, "krb5_print_address");
164 
165           printf("processing request from %s, %lu bytes\n",
166                  astr, (unsigned long)d.length);
167 
168           r.length = 0;
169           r.data = NULL;
170 
171           tv.tv_sec = t;
172           tv.tv_usec = 0;
173 
174           krb5_kdc_update_time(&tv);
175           krb5_set_real_time(context, tv.tv_sec, 0);
176 
177           ret = krb5_kdc_process_request(context, config, d.data, d.length,
178                                                &r, NULL, astr,
179                                                (struct sockaddr *)&sa, 0);
180           if (ret)
181               krb5_err(context, 1, ret, "krb5_kdc_process_request");
182 
183           if (r.length) {
184               Der_class cl;
185               Der_type ty;
186               unsigned int tag2;
187               ret = der_get_tag (r.data, r.length,
188                                      &cl, &ty, &tag2, NULL);
189             if (ret)
190                 krb5_err(context, 1, ret, "Could not decode replay data");
191               if (MAKE_TAG(cl, ty, 0) != clty)
192                     krb5_errx(context, 1, "class|type mismatch: %d != %d",
193                                 (int)MAKE_TAG(cl, ty, 0), (int)clty);
194               if (tag != tag2)
195                     krb5_errx(context, 1, "tag mismatch");
196 
197               krb5_data_free(&r);
198           } else {
199               if (clty != 0xffffffff)
200                     krb5_errx(context, 1, "clty not invalid");
201               if (tag != 0xffffffff)
202                     krb5_errx(context, 1, "tag not invalid");
203           }
204 
205     out:
206           krb5_data_free(&d);
207           krb5_free_address(context, &a);
208     }
209 
210     krb5_storage_free(sp);
211     krb5_free_context(context);
212 
213     printf("done\n");
214 
215     return 0;
216 }
217