xref: /freebsd/crypto/heimdal/lib/kadm5/ipropd_slave.c (revision b528cefc6b8f9670b31a865051741d946cb37085)
1 /*
2  * Copyright (c) 1997, 1998 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 "iprop.h"
35 
36 RCSID("$Id: ipropd_slave.c,v 1.10 1999/12/02 17:05:06 joda Exp $");
37 
38 static int
39 connect_to_master (krb5_context context, const char *master)
40 {
41     int fd;
42     struct sockaddr_in addr;
43     struct hostent *he;
44 
45     fd = socket (AF_INET, SOCK_STREAM, 0);
46     if (fd < 0)
47 	krb5_err (context, 1, errno, "socket AF_INET");
48     memset (&addr, 0, sizeof(addr));
49     addr.sin_family = AF_INET;
50     addr.sin_port   = htons(4711);
51     he = roken_gethostbyname (master);
52     if (he == NULL)
53 	krb5_errx (context, 1, "gethostbyname: %s", hstrerror(h_errno));
54     memcpy (&addr.sin_addr, he->h_addr, sizeof(addr.sin_addr));
55     if(connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
56 	krb5_err (context, 1, errno, "connect");
57     return fd;
58 }
59 
60 static void
61 get_creds(krb5_context context, krb5_ccache *cache, const char *host)
62 {
63     krb5_keytab keytab;
64     krb5_principal client;
65     krb5_error_code ret;
66     krb5_get_init_creds_opt init_opts;
67 #if 0
68     krb5_preauthtype preauth = KRB5_PADATA_ENC_TIMESTAMP;
69 #endif
70     krb5_creds creds;
71     char my_hostname[128];
72     char *server;
73 
74     ret = krb5_kt_default(context, &keytab);
75     if(ret) krb5_err(context, 1, ret, "krb5_kt_default");
76 
77     gethostname (my_hostname, sizeof(my_hostname));
78     ret = krb5_sname_to_principal (context, my_hostname, IPROP_NAME,
79 				   KRB5_NT_SRV_HST, &client);
80     if (ret) krb5_err(context, 1, ret, "krb5_sname_to_principal");
81 
82     krb5_get_init_creds_opt_init(&init_opts);
83 #if 0
84     krb5_get_init_creds_opt_set_preauth_list(&init_opts, &preauth, 1);
85 #endif
86 
87     asprintf (&server, "%s/%s", IPROP_NAME, host);
88     if (server == NULL)
89 	krb5_errx (context, 1, "malloc: no memory");
90 
91     ret = krb5_get_init_creds_keytab(context, &creds, client, keytab,
92 				     0, server, &init_opts);
93     free (server);
94     if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds");
95 
96     ret = krb5_kt_close(context, keytab);
97     if(ret) krb5_err(context, 1, ret, "krb5_kt_close");
98 
99     ret = krb5_cc_gen_new(context, &krb5_mcc_ops, cache);
100     if(ret) krb5_err(context, 1, ret, "krb5_cc_gen_new");
101 
102     ret = krb5_cc_initialize(context, *cache, client);
103     if(ret) krb5_err(context, 1, ret, "krb5_cc_initialize");
104 
105     ret = krb5_cc_store_cred(context, *cache, &creds);
106     if(ret) krb5_err(context, 1, ret, "krb5_cc_store_cred");
107 }
108 
109 static void
110 ihave (krb5_context context, krb5_auth_context auth_context,
111        int fd, u_int32_t version)
112 {
113     int ret;
114     u_char buf[8];
115     krb5_storage *sp;
116     krb5_data data, priv_data;
117 
118     sp = krb5_storage_from_mem (buf, 8);
119     krb5_store_int32 (sp, I_HAVE);
120     krb5_store_int32 (sp, version);
121     krb5_storage_free (sp);
122     data.length = 8;
123     data.data   = buf;
124 
125     ret = krb5_mk_priv (context, auth_context, &data, &priv_data, NULL);
126     if (ret)
127 	krb5_err (context, 1, ret, "krb_mk_priv");
128 
129     ret = krb5_write_message (context, &fd, &priv_data);
130     if (ret)
131 	krb5_err (context, 1, ret, "krb5_write_message");
132 
133     krb5_data_free (&priv_data);
134 }
135 
136 static void
137 receive (krb5_context context,
138 	 krb5_storage *sp,
139 	 kadm5_server_context *server_context)
140 {
141     int ret;
142     off_t left, right;
143     void *buf;
144     int32_t vers;
145 
146     ret = server_context->db->open(context,
147 				   server_context->db,
148 				   O_RDWR | O_CREAT, 0);
149     if (ret)
150 	krb5_err (context, 1, ret, "db->open");
151 
152     do {
153 	int32_t len, timestamp, tmp;
154 	enum kadm_ops op;
155 
156 	if(krb5_ret_int32 (sp, &vers) != 0)
157 	    return;
158 	krb5_ret_int32 (sp, &timestamp);
159 	krb5_ret_int32 (sp, &tmp);
160 	op = tmp;
161 	krb5_ret_int32 (sp, &len);
162 	if (vers <= server_context->log_context.version)
163 	    sp->seek(sp, len, SEEK_CUR);
164     } while(vers <= server_context->log_context.version);
165 
166     left  = sp->seek (sp, -16, SEEK_CUR);
167     right = sp->seek (sp, 0, SEEK_END);
168     buf = malloc (right - left);
169     if (buf == NULL) {
170 	krb5_warnx (context, "malloc: no memory");
171 	return;
172     }
173     sp->seek (sp, left, SEEK_SET);
174     sp->fetch (sp, buf, right - left);
175     write (server_context->log_context.log_fd, buf, right-left);
176     fsync (server_context->log_context.log_fd);
177     free (buf);
178 
179     sp->seek (sp, left, SEEK_SET);
180 
181     for(;;) {
182 	int32_t len, timestamp, tmp;
183 	enum kadm_ops op;
184 
185 	if(krb5_ret_int32 (sp, &vers) != 0)
186 	    break;
187 	krb5_ret_int32 (sp, &timestamp);
188 	krb5_ret_int32 (sp, &tmp);
189 	op = tmp;
190 	krb5_ret_int32 (sp, &len);
191 
192 	ret = kadm5_log_replay (server_context,
193 				op, vers, len, sp);
194 	if (ret)
195 	    krb5_warn (context, ret, "kadm5_log_replay");
196 	else
197 	    server_context->log_context.version = vers;
198 	sp->seek (sp, 8, SEEK_CUR);
199     }
200 
201     ret = server_context->db->close (context, server_context->db);
202     if (ret)
203 	krb5_err (context, 1, ret, "db->close");
204 }
205 
206 char *realm;
207 int version_flag;
208 int help_flag;
209 struct getargs args[] = {
210     { "realm", 'r', arg_string, &realm },
211     { "version", 0, arg_flag, &version_flag },
212     { "help", 0, arg_flag, &help_flag }
213 };
214 int num_args = sizeof(args) / sizeof(args[0]);
215 
216 int
217 main(int argc, char **argv)
218 {
219     krb5_error_code ret;
220     krb5_context context;
221     krb5_auth_context auth_context;
222     void *kadm_handle;
223     kadm5_server_context *server_context;
224     kadm5_config_params conf;
225     int master_fd;
226     krb5_ccache ccache;
227     krb5_principal server;
228 
229     int optind;
230 
231     optind = krb5_program_setup(&context, argc, argv, args, num_args, NULL);
232 
233     if(help_flag)
234 	krb5_std_usage(0, args, num_args);
235     if(version_flag) {
236 	print_version(NULL);
237 	exit(0);
238     }
239 
240     memset(&conf, 0, sizeof(conf));
241     if(realm) {
242 	conf.mask |= KADM5_CONFIG_REALM;
243 	conf.realm = realm;
244     }
245     ret = kadm5_init_with_password_ctx (context,
246 					KADM5_ADMIN_SERVICE,
247 					NULL,
248 					KADM5_ADMIN_SERVICE,
249 					&conf, 0, 0,
250 					&kadm_handle);
251     if (ret)
252 	krb5_err (context, 1, ret, "kadm5_init_with_password_ctx");
253 
254     server_context = (kadm5_server_context *)kadm_handle;
255 
256     ret = kadm5_log_init (server_context);
257     if (ret)
258 	krb5_err (context, 1, ret, "kadm5_log_init");
259 
260     get_creds(context, &ccache, argv[1]);
261 
262     master_fd = connect_to_master (context, argv[1]);
263 
264     ret = krb5_sname_to_principal (context, argv[1], IPROP_NAME,
265 				   KRB5_NT_SRV_HST, &server);
266     if (ret)
267 	krb5_err (context, 1, ret, "krb5_sname_to_principal");
268 
269     auth_context = NULL;
270     ret = krb5_sendauth (context, &auth_context, &master_fd,
271 			 IPROP_VERSION, NULL, server,
272 			 AP_OPTS_MUTUAL_REQUIRED, NULL, NULL,
273 			 ccache, NULL, NULL, NULL);
274     if (ret)
275 	krb5_err (context, 1, ret, "krb5_sendauth");
276 
277     ihave (context, auth_context, master_fd,
278 	   server_context->log_context.version);
279 
280     for (;;) {
281 	int ret;
282 	krb5_data data, out;
283 	krb5_storage *sp;
284 	int32_t tmp;
285 
286 	ret = krb5_read_message (context, &master_fd, &data);
287 	if (ret)
288 	    krb5_err (context, 1, ret, "krb5_read_message");
289 
290 	ret = krb5_rd_priv (context, auth_context,  &data, &out, NULL);
291 	krb5_data_free (&data);
292 	if (ret)
293 	    krb5_err (context, 1, ret, "krb5_rd_priv");
294 
295 	sp = krb5_storage_from_mem (out.data, out.length);
296 	krb5_ret_int32 (sp, &tmp);
297 	switch (tmp) {
298 	case FOR_YOU :
299 	    receive (context, sp, server_context);
300 	    ihave (context, auth_context, master_fd,
301 		   server_context->log_context.version);
302 	    break;
303 	case I_HAVE :
304 	default :
305 	    krb5_warnx (context, "Ignoring command %d", tmp);
306 	    break;
307 	}
308 	krb5_storage_free (sp);
309 	krb5_data_free (&out);
310     }
311 
312     return 0;
313 }
314