2 * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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
38 static krb5_log_facility
*log_facility
;
41 connect_to_master (krb5_context context
, const char *master
)
44 struct sockaddr_in addr
;
47 fd
= socket (AF_INET
, SOCK_STREAM
, 0);
49 krb5_err (context
, 1, errno
, "socket AF_INET");
50 memset (&addr
, 0, sizeof(addr
));
51 addr
.sin_family
= AF_INET
;
52 addr
.sin_port
= krb5_getportbyname (context
,
53 IPROP_SERVICE
, "tcp", IPROP_PORT
);
54 he
= roken_gethostbyname (master
);
56 krb5_errx (context
, 1, "gethostbyname: %s", hstrerror(h_errno
));
57 memcpy (&addr
.sin_addr
, he
->h_addr
, sizeof(addr
.sin_addr
));
58 if(connect(fd
, (struct sockaddr
*)&addr
, sizeof(addr
)) < 0)
59 krb5_err (context
, 1, errno
, "connect");
64 get_creds(krb5_context context
, const char *keytab_str
,
65 krb5_ccache
*cache
, const char *host
)
68 krb5_principal client
;
70 krb5_get_init_creds_opt init_opts
;
75 if (keytab_str
== NULL
) {
76 ret
= krb5_kt_default_name (context
, keytab_buf
, sizeof(keytab_buf
));
78 krb5_err (context
, 1, ret
, "krb5_kt_default_name");
79 keytab_str
= keytab_buf
;
82 ret
= krb5_kt_resolve(context
, keytab_str
, &keytab
);
84 krb5_err(context
, 1, ret
, "%s", keytab_str
);
86 ret
= krb5_sname_to_principal (context
, NULL
, IPROP_NAME
,
87 KRB5_NT_SRV_HST
, &client
);
88 if (ret
) krb5_err(context
, 1, ret
, "krb5_sname_to_principal");
90 krb5_get_init_creds_opt_init(&init_opts
);
92 asprintf (&server
, "%s/%s", IPROP_NAME
, host
);
94 krb5_errx (context
, 1, "malloc: no memory");
96 ret
= krb5_get_init_creds_keytab(context
, &creds
, client
, keytab
,
97 0, server
, &init_opts
);
99 if(ret
) krb5_err(context
, 1, ret
, "krb5_get_init_creds");
101 ret
= krb5_kt_close(context
, keytab
);
102 if(ret
) krb5_err(context
, 1, ret
, "krb5_kt_close");
104 ret
= krb5_cc_gen_new(context
, &krb5_mcc_ops
, cache
);
105 if(ret
) krb5_err(context
, 1, ret
, "krb5_cc_gen_new");
107 ret
= krb5_cc_initialize(context
, *cache
, client
);
108 if(ret
) krb5_err(context
, 1, ret
, "krb5_cc_initialize");
110 ret
= krb5_cc_store_cred(context
, *cache
, &creds
);
111 if(ret
) krb5_err(context
, 1, ret
, "krb5_cc_store_cred");
115 ihave (krb5_context context
, krb5_auth_context auth_context
,
116 int fd
, u_int32_t version
)
121 krb5_data data
, priv_data
;
123 sp
= krb5_storage_from_mem (buf
, 8);
124 krb5_store_int32 (sp
, I_HAVE
);
125 krb5_store_int32 (sp
, version
);
126 krb5_storage_free (sp
);
130 ret
= krb5_mk_priv (context
, auth_context
, &data
, &priv_data
, NULL
);
132 krb5_err (context
, 1, ret
, "krb_mk_priv");
134 ret
= krb5_write_message (context
, &fd
, &priv_data
);
136 krb5_err (context
, 1, ret
, "krb5_write_message");
138 krb5_data_free (&priv_data
);
142 receive_loop (krb5_context context
,
144 kadm5_server_context
*server_context
)
152 int32_t len
, timestamp
, tmp
;
155 if(krb5_ret_int32 (sp
, &vers
) != 0)
157 krb5_ret_int32 (sp
, ×tamp
);
158 krb5_ret_int32 (sp
, &tmp
);
160 krb5_ret_int32 (sp
, &len
);
161 if (vers
<= server_context
->log_context
.version
)
162 krb5_storage_seek(sp
, len
, SEEK_CUR
);
163 } while(vers
<= server_context
->log_context
.version
);
165 left
= krb5_storage_seek (sp
, -16, SEEK_CUR
);
166 right
= krb5_storage_seek (sp
, 0, SEEK_END
);
167 buf
= malloc (right
- left
);
168 if (buf
== NULL
&& (right
- left
) != 0) {
169 krb5_warnx (context
, "malloc: no memory");
172 krb5_storage_seek (sp
, left
, SEEK_SET
);
173 krb5_storage_read (sp
, buf
, right
- left
);
174 write (server_context
->log_context
.log_fd
, buf
, right
-left
);
175 fsync (server_context
->log_context
.log_fd
);
178 krb5_storage_seek (sp
, left
, SEEK_SET
);
181 int32_t len
, timestamp
, tmp
;
184 if(krb5_ret_int32 (sp
, &vers
) != 0)
186 krb5_ret_int32 (sp
, ×tamp
);
187 krb5_ret_int32 (sp
, &tmp
);
189 krb5_ret_int32 (sp
, &len
);
191 ret
= kadm5_log_replay (server_context
,
194 krb5_warn (context
, ret
, "kadm5_log_replay");
196 server_context
->log_context
.version
= vers
;
197 krb5_storage_seek (sp
, 8, SEEK_CUR
);
202 receive (krb5_context context
,
204 kadm5_server_context
*server_context
)
208 ret
= server_context
->db
->open(context
,
210 O_RDWR
| O_CREAT
, 0600);
212 krb5_err (context
, 1, ret
, "db->open");
214 receive_loop (context
, sp
, server_context
);
216 ret
= server_context
->db
->close (context
, server_context
->db
);
218 krb5_err (context
, 1, ret
, "db->close");
222 receive_everything (krb5_context context
, int fd
,
223 kadm5_server_context
*server_context
,
224 krb5_auth_context auth_context
)
235 asprintf(&dbname
, "%s-NEW", server_context
->db
->name
);
236 ret
= hdb_create(context
, &mydb
, dbname
);
238 krb5_err(context
,1, ret
, "hdb_create");
241 ret
= hdb_set_master_keyfile (context
,
242 mydb
, server_context
->config
.stash_file
);
244 krb5_err(context
,1, ret
, "hdb_set_master_keyfile");
246 /* I really want to use O_EXCL here, but given that I can't easily clean
247 up on error, I won't */
248 ret
= mydb
->open(context
, mydb
, O_RDWR
| O_CREAT
| O_TRUNC
, 0600);
251 krb5_err (context
, 1, ret
, "db->open");
256 ret
= krb5_read_priv_message(context
, auth_context
, &fd
, &data
);
259 krb5_err (context
, 1, ret
, "krb5_read_priv_message");
261 sp
= krb5_storage_from_data (&data
);
262 krb5_ret_int32 (sp
, &opcode
);
263 if (opcode
== ONE_PRINC
) {
267 fake_data
.data
= (char *)data
.data
+ 4;
268 fake_data
.length
= data
.length
- 4;
270 ret
= hdb_value2entry (context
, &fake_data
, &entry
);
272 krb5_err (context
, 1, ret
, "hdb_value2entry");
273 ret
= mydb
->store(server_context
->context
,
277 krb5_err (context
, 1, ret
, "hdb_store");
279 hdb_free_entry (context
, &entry
);
280 krb5_data_free (&data
);
282 } while (opcode
== ONE_PRINC
);
284 if (opcode
!= NOW_YOU_HAVE
)
285 krb5_errx (context
, 1, "receive_everything: strange %d", opcode
);
287 _krb5_get_int ((char *)data
.data
+ 4, &tmp
, 4);
290 ret
= kadm5_log_reinit (server_context
);
292 krb5_err(context
, 1, ret
, "kadm5_log_reinit");
294 ret
= kadm5_log_set_version (server_context
, vno
- 1);
296 krb5_err (context
, 1, ret
, "kadm5_log_set_version");
298 ret
= kadm5_log_nop (server_context
);
300 krb5_err (context
, 1, ret
, "kadm5_log_nop");
302 krb5_data_free (&data
);
304 ret
= mydb
->close (context
, mydb
);
306 krb5_err (context
, 1, ret
, "db->close");
307 ret
= mydb
->rename (context
, mydb
, server_context
->db
->name
);
309 krb5_err (context
, 1, ret
, "db->rename");
310 ret
= mydb
->destroy (context
, mydb
);
312 krb5_err (context
, 1, ret
, "db->destroy");
316 static int version_flag
;
317 static int help_flag
;
318 static char *keytab_str
;
320 static struct getargs args
[] = {
321 { "realm", 'r', arg_string
, &realm
},
322 { "keytab", 'k', arg_string
, &keytab_str
,
323 "keytab to get authentication from", "kspec" },
324 { "version", 0, arg_flag
, &version_flag
},
325 { "help", 0, arg_flag
, &help_flag
}
328 static int num_args
= sizeof(args
) / sizeof(args
[0]);
331 usage (int code
, struct getargs
*args
, int num_args
)
333 arg_printusage (args
, num_args
, NULL
, "master");
338 main(int argc
, char **argv
)
341 krb5_context context
;
342 krb5_auth_context auth_context
;
344 kadm5_server_context
*server_context
;
345 kadm5_config_params conf
;
348 krb5_principal server
;
353 optind
= krb5_program_setup(&context
, argc
, argv
, args
, num_args
, usage
);
356 usage (0, args
, num_args
);
366 usage (1, args
, num_args
);
371 krb5_openlog (context
, "ipropd-slave", &log_facility
);
372 krb5_set_warn_dest(context
, log_facility
);
374 ret
= krb5_kt_register(context
, &hdb_kt_ops
);
376 krb5_err(context
, 1, ret
, "krb5_kt_register");
378 memset(&conf
, 0, sizeof(conf
));
380 conf
.mask
|= KADM5_CONFIG_REALM
;
383 ret
= kadm5_init_with_password_ctx (context
,
390 krb5_err (context
, 1, ret
, "kadm5_init_with_password_ctx");
392 server_context
= (kadm5_server_context
*)kadm_handle
;
394 ret
= kadm5_log_init (server_context
);
396 krb5_err (context
, 1, ret
, "kadm5_log_init");
398 get_creds(context
, keytab_str
, &ccache
, master
);
400 master_fd
= connect_to_master (context
, master
);
402 ret
= krb5_sname_to_principal (context
, master
, IPROP_NAME
,
403 KRB5_NT_SRV_HST
, &server
);
405 krb5_err (context
, 1, ret
, "krb5_sname_to_principal");
408 ret
= krb5_sendauth (context
, &auth_context
, &master_fd
,
409 IPROP_VERSION
, NULL
, server
,
410 AP_OPTS_MUTUAL_REQUIRED
, NULL
, NULL
,
411 ccache
, NULL
, NULL
, NULL
);
413 krb5_err (context
, 1, ret
, "krb5_sendauth");
415 ihave (context
, auth_context
, master_fd
,
416 server_context
->log_context
.version
);
424 ret
= krb5_read_priv_message(context
, auth_context
, &master_fd
, &out
);
427 krb5_err (context
, 1, ret
, "krb5_read_priv_message");
429 sp
= krb5_storage_from_mem (out
.data
, out
.length
);
430 krb5_ret_int32 (sp
, &tmp
);
433 receive (context
, sp
, server_context
);
434 ihave (context
, auth_context
, master_fd
,
435 server_context
->log_context
.version
);
437 case TELL_YOU_EVERYTHING
:
438 receive_everything (context
, master_fd
, server_context
,
445 krb5_warnx (context
, "Ignoring command %d", tmp
);
448 krb5_storage_free (sp
);
449 krb5_data_free (&out
);