155682Smarkm/*
2233294Sstas * Copyright (c) 1997 - 2007 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
555682Smarkm *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
955682Smarkm *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
2055682Smarkm *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "kadm5_locl.h"
35178825Sdfr#include "heim_threads.h"
3655682Smarkm
37233294SstasRCSID("$Id$");
3855682Smarkm
3955682Smarkm/*
4055682Smarkm * A log record consists of:
4155682Smarkm *
4255682Smarkm * version number		4 bytes
4355682Smarkm * time in seconds		4 bytes
4455682Smarkm * operation (enum kadm_ops)	4 bytes
4555682Smarkm * length of record		4 bytes
4655682Smarkm * data...			n bytes
4755682Smarkm * length of record		4 bytes
4855682Smarkm * version number		4 bytes
4955682Smarkm *
5055682Smarkm */
5155682Smarkm
5255682Smarkmkadm5_ret_t
5372445Sassarkadm5_log_get_version_fd (int fd,
54178825Sdfr			  uint32_t *ver)
5555682Smarkm{
5655682Smarkm    int ret;
5755682Smarkm    krb5_storage *sp;
5855682Smarkm    int32_t old_version;
5955682Smarkm
6055682Smarkm    ret = lseek (fd, 0, SEEK_END);
6155682Smarkm    if(ret < 0)
6255682Smarkm	return errno;
6355682Smarkm    if(ret == 0) {
6455682Smarkm	*ver = 0;
6555682Smarkm	return 0;
6655682Smarkm    }
6755682Smarkm    sp = krb5_storage_from_fd (fd);
68102644Snectar    krb5_storage_seek(sp, -4, SEEK_CUR);
6955682Smarkm    krb5_ret_int32 (sp, &old_version);
7055682Smarkm    *ver = old_version;
7155682Smarkm    krb5_storage_free(sp);
7255682Smarkm    lseek (fd, 0, SEEK_END);
7355682Smarkm    return 0;
7455682Smarkm}
7555682Smarkm
7655682Smarkmkadm5_ret_t
77178825Sdfrkadm5_log_get_version (kadm5_server_context *context, uint32_t *ver)
7872445Sassar{
7972445Sassar    return kadm5_log_get_version_fd (context->log_context.log_fd, ver);
8072445Sassar}
8172445Sassar
8272445Sassarkadm5_ret_t
83178825Sdfrkadm5_log_set_version (kadm5_server_context *context, uint32_t vno)
8472445Sassar{
8572445Sassar    kadm5_log_context *log_context = &context->log_context;
8672445Sassar
8772445Sassar    log_context->version = vno;
8872445Sassar    return 0;
8972445Sassar}
9072445Sassar
9172445Sassarkadm5_ret_t
9255682Smarkmkadm5_log_init (kadm5_server_context *context)
9355682Smarkm{
9455682Smarkm    int fd;
9555682Smarkm    kadm5_ret_t ret;
9655682Smarkm    kadm5_log_context *log_context = &context->log_context;
9755682Smarkm
9855682Smarkm    if (log_context->log_fd != -1)
9955682Smarkm	return 0;
10055682Smarkm    fd = open (log_context->log_file, O_RDWR | O_CREAT, 0600);
101178825Sdfr    if (fd < 0) {
102233294Sstas	ret = errno;
103233294Sstas	krb5_set_error_message(context->context, ret, "kadm5_log_init: open %s",
104178825Sdfr			      log_context->log_file);
105233294Sstas	return ret;
106178825Sdfr    }
10755682Smarkm    if (flock (fd, LOCK_EX) < 0) {
108233294Sstas	ret = errno;
109233294Sstas	krb5_set_error_message(context->context, ret, "kadm5_log_init: flock %s",
110233294Sstas			       log_context->log_file);
11155682Smarkm	close (fd);
11255682Smarkm	return errno;
11355682Smarkm    }
11455682Smarkm
11572445Sassar    ret = kadm5_log_get_version_fd (fd, &log_context->version);
11655682Smarkm    if (ret)
11755682Smarkm	return ret;
11855682Smarkm
11955682Smarkm    log_context->log_fd  = fd;
12055682Smarkm    return 0;
12155682Smarkm}
12255682Smarkm
12355682Smarkmkadm5_ret_t
12472445Sassarkadm5_log_reinit (kadm5_server_context *context)
12572445Sassar{
12672445Sassar    int fd;
12772445Sassar    kadm5_log_context *log_context = &context->log_context;
12872445Sassar
12972445Sassar    if (log_context->log_fd != -1) {
130178825Sdfr	flock (log_context->log_fd, LOCK_UN);
13172445Sassar	close (log_context->log_fd);
13272445Sassar	log_context->log_fd = -1;
13372445Sassar    }
13472445Sassar    fd = open (log_context->log_file, O_RDWR | O_CREAT | O_TRUNC, 0600);
13572445Sassar    if (fd < 0)
13672445Sassar	return errno;
13772445Sassar    if (flock (fd, LOCK_EX) < 0) {
13872445Sassar	close (fd);
13972445Sassar	return errno;
14072445Sassar    }
14172445Sassar
14272445Sassar    log_context->version = 0;
14372445Sassar    log_context->log_fd  = fd;
14472445Sassar    return 0;
14572445Sassar}
14672445Sassar
14772445Sassar
14872445Sassarkadm5_ret_t
14955682Smarkmkadm5_log_end (kadm5_server_context *context)
15055682Smarkm{
15155682Smarkm    kadm5_log_context *log_context = &context->log_context;
15255682Smarkm    int fd = log_context->log_fd;
15355682Smarkm
15455682Smarkm    flock (fd, LOCK_UN);
15555682Smarkm    close(fd);
15655682Smarkm    log_context->log_fd = -1;
15755682Smarkm    return 0;
15855682Smarkm}
15955682Smarkm
16055682Smarkmstatic kadm5_ret_t
16155682Smarkmkadm5_log_preamble (kadm5_server_context *context,
16255682Smarkm		    krb5_storage *sp,
16355682Smarkm		    enum kadm_ops op)
16455682Smarkm{
16555682Smarkm    kadm5_log_context *log_context = &context->log_context;
16655682Smarkm    kadm5_ret_t kadm_ret;
16755682Smarkm
16855682Smarkm    kadm_ret = kadm5_log_init (context);
16955682Smarkm    if (kadm_ret)
17055682Smarkm	return kadm_ret;
17155682Smarkm
17255682Smarkm    krb5_store_int32 (sp, ++log_context->version);
17355682Smarkm    krb5_store_int32 (sp, time(NULL));
17455682Smarkm    krb5_store_int32 (sp, op);
17555682Smarkm    return 0;
17655682Smarkm}
17755682Smarkm
17855682Smarkmstatic kadm5_ret_t
17955682Smarkmkadm5_log_postamble (kadm5_log_context *context,
18055682Smarkm		     krb5_storage *sp)
18155682Smarkm{
18255682Smarkm    krb5_store_int32 (sp, context->version);
18355682Smarkm    return 0;
18455682Smarkm}
18555682Smarkm
18655682Smarkm/*
18755682Smarkm * flush the log record in `sp'.
18855682Smarkm */
18955682Smarkm
19055682Smarkmstatic kadm5_ret_t
19155682Smarkmkadm5_log_flush (kadm5_log_context *log_context,
19255682Smarkm		 krb5_storage *sp)
19355682Smarkm{
19455682Smarkm    krb5_data data;
19555682Smarkm    size_t len;
196233294Sstas    ssize_t ret;
19755682Smarkm
19855682Smarkm    krb5_storage_to_data(sp, &data);
19955682Smarkm    len = data.length;
20055682Smarkm    ret = write (log_context->log_fd, data.data, len);
201233294Sstas    if (ret < 0 || (size_t)ret != len) {
20255682Smarkm	krb5_data_free(&data);
20355682Smarkm	return errno;
20455682Smarkm    }
20555682Smarkm    if (fsync (log_context->log_fd) < 0) {
20655682Smarkm	krb5_data_free(&data);
20755682Smarkm	return errno;
20855682Smarkm    }
209233294Sstas
21055682Smarkm    /*
21155682Smarkm     * Try to send a signal to any running `ipropd-master'
21255682Smarkm     */
213233294Sstas#ifndef NO_UNIX_SOCKETS
21455682Smarkm    sendto (log_context->socket_fd,
21555682Smarkm	    (void *)&log_context->version,
21655682Smarkm	    sizeof(log_context->version),
21755682Smarkm	    0,
21855682Smarkm	    (struct sockaddr *)&log_context->socket_name,
21955682Smarkm	    sizeof(log_context->socket_name));
220233294Sstas#else
221233294Sstas    sendto (log_context->socket_fd,
222233294Sstas	    (void *)&log_context->version,
223233294Sstas	    sizeof(log_context->version),
224233294Sstas	    0,
225233294Sstas	    log_context->socket_info->ai_addr,
226233294Sstas	    log_context->socket_info->ai_addrlen);
227233294Sstas#endif
22855682Smarkm
22955682Smarkm    krb5_data_free(&data);
23055682Smarkm    return 0;
23155682Smarkm}
23255682Smarkm
23355682Smarkm/*
23455682Smarkm * Add a `create' operation to the log.
23555682Smarkm */
23655682Smarkm
23755682Smarkmkadm5_ret_t
23855682Smarkmkadm5_log_create (kadm5_server_context *context,
23955682Smarkm		  hdb_entry *ent)
24055682Smarkm{
24155682Smarkm    krb5_storage *sp;
24255682Smarkm    kadm5_ret_t ret;
24355682Smarkm    krb5_data value;
24455682Smarkm    kadm5_log_context *log_context = &context->log_context;
24555682Smarkm
24655682Smarkm    sp = krb5_storage_emem();
24755682Smarkm    ret = hdb_entry2value (context->context, ent, &value);
24855682Smarkm    if (ret) {
24955682Smarkm	krb5_storage_free(sp);
25055682Smarkm	return ret;
25155682Smarkm    }
25255682Smarkm    ret = kadm5_log_preamble (context, sp, kadm_create);
25355682Smarkm    if (ret) {
25455682Smarkm	krb5_data_free (&value);
25555682Smarkm	krb5_storage_free(sp);
25655682Smarkm	return ret;
25755682Smarkm    }
25855682Smarkm    krb5_store_int32 (sp, value.length);
259102644Snectar    krb5_storage_write(sp, value.data, value.length);
26055682Smarkm    krb5_store_int32 (sp, value.length);
26155682Smarkm    krb5_data_free (&value);
26255682Smarkm    ret = kadm5_log_postamble (log_context, sp);
26355682Smarkm    if (ret) {
26455682Smarkm	krb5_storage_free (sp);
26555682Smarkm	return ret;
26655682Smarkm    }
26755682Smarkm    ret = kadm5_log_flush (log_context, sp);
26855682Smarkm    krb5_storage_free (sp);
26955682Smarkm    if (ret)
27055682Smarkm	return ret;
27155682Smarkm    ret = kadm5_log_end (context);
27255682Smarkm    return ret;
27355682Smarkm}
27455682Smarkm
27555682Smarkm/*
27655682Smarkm * Read the data of a create log record from `sp' and change the
27755682Smarkm * database.
27855682Smarkm */
27955682Smarkm
280178825Sdfrstatic kadm5_ret_t
28155682Smarkmkadm5_log_replay_create (kadm5_server_context *context,
282178825Sdfr			 uint32_t ver,
283178825Sdfr			 uint32_t len,
28455682Smarkm			 krb5_storage *sp)
28555682Smarkm{
28655682Smarkm    krb5_error_code ret;
28755682Smarkm    krb5_data data;
288178825Sdfr    hdb_entry_ex ent;
28955682Smarkm
290178825Sdfr    memset(&ent, 0, sizeof(ent));
291178825Sdfr
292120945Snectar    ret = krb5_data_alloc (&data, len);
293178825Sdfr    if (ret) {
294233294Sstas	krb5_set_error_message(context->context, ret, "out of memory");
295120945Snectar	return ret;
296178825Sdfr    }
297102644Snectar    krb5_storage_read (sp, data.data, len);
298178825Sdfr    ret = hdb_value2entry (context->context, &data, &ent.entry);
29955682Smarkm    krb5_data_free(&data);
300178825Sdfr    if (ret) {
301233294Sstas	krb5_set_error_message(context->context, ret,
302233294Sstas			       "Unmarshaling hdb entry failed");
30355682Smarkm	return ret;
304178825Sdfr    }
305178825Sdfr    ret = context->db->hdb_store(context->context, context->db, 0, &ent);
30655682Smarkm    hdb_free_entry (context->context, &ent);
30755682Smarkm    return ret;
30855682Smarkm}
30955682Smarkm
31055682Smarkm/*
31155682Smarkm * Add a `delete' operation to the log.
31255682Smarkm */
31355682Smarkm
31455682Smarkmkadm5_ret_t
31555682Smarkmkadm5_log_delete (kadm5_server_context *context,
31655682Smarkm		  krb5_principal princ)
31755682Smarkm{
31855682Smarkm    krb5_storage *sp;
31955682Smarkm    kadm5_ret_t ret;
32055682Smarkm    off_t off;
32155682Smarkm    off_t len;
32255682Smarkm    kadm5_log_context *log_context = &context->log_context;
32355682Smarkm
32455682Smarkm    sp = krb5_storage_emem();
325178825Sdfr    if (sp == NULL)
326178825Sdfr	return ENOMEM;
32755682Smarkm    ret = kadm5_log_preamble (context, sp, kadm_delete);
328178825Sdfr    if (ret)
329178825Sdfr	goto out;
330178825Sdfr    ret = krb5_store_int32 (sp, 0);
331178825Sdfr    if (ret)
332178825Sdfr	goto out;
333102644Snectar    off = krb5_storage_seek (sp, 0, SEEK_CUR);
334178825Sdfr    ret = krb5_store_principal (sp, princ);
335178825Sdfr    if (ret)
336178825Sdfr	goto out;
337102644Snectar    len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
338102644Snectar    krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
339178825Sdfr    ret = krb5_store_int32 (sp, len);
340178825Sdfr    if (ret)
341178825Sdfr	goto out;
342102644Snectar    krb5_storage_seek(sp, len, SEEK_CUR);
343178825Sdfr    ret = krb5_store_int32 (sp, len);
344178825Sdfr    if (ret)
345178825Sdfr	goto out;
34655682Smarkm    ret = kadm5_log_postamble (log_context, sp);
347178825Sdfr    if (ret)
348178825Sdfr	goto out;
34955682Smarkm    ret = kadm5_log_flush (log_context, sp);
35055682Smarkm    if (ret)
351178825Sdfr	goto out;
35255682Smarkm    ret = kadm5_log_end (context);
353178825Sdfrout:
354178825Sdfr    krb5_storage_free (sp);
35555682Smarkm    return ret;
35655682Smarkm}
35755682Smarkm
35855682Smarkm/*
35955682Smarkm * Read a `delete' log operation from `sp' and apply it.
36055682Smarkm */
36155682Smarkm
362178825Sdfrstatic kadm5_ret_t
36355682Smarkmkadm5_log_replay_delete (kadm5_server_context *context,
364178825Sdfr			 uint32_t ver,
365178825Sdfr			 uint32_t len,
36655682Smarkm			 krb5_storage *sp)
36755682Smarkm{
36855682Smarkm    krb5_error_code ret;
369178825Sdfr    krb5_principal principal;
37055682Smarkm
371178825Sdfr    ret = krb5_ret_principal (sp, &principal);
372178825Sdfr    if (ret) {
373233294Sstas	krb5_set_error_message(context->context,  ret, "Failed to read deleted "
374233294Sstas			       "principal from log version: %ld",  (long)ver);
375178825Sdfr	return ret;
376178825Sdfr    }
37755682Smarkm
378178825Sdfr    ret = context->db->hdb_remove(context->context, context->db, principal);
379178825Sdfr    krb5_free_principal (context->context, principal);
38055682Smarkm    return ret;
38155682Smarkm}
38255682Smarkm
38355682Smarkm/*
38455682Smarkm * Add a `rename' operation to the log.
38555682Smarkm */
38655682Smarkm
38755682Smarkmkadm5_ret_t
38855682Smarkmkadm5_log_rename (kadm5_server_context *context,
38955682Smarkm		  krb5_principal source,
39055682Smarkm		  hdb_entry *ent)
39155682Smarkm{
39255682Smarkm    krb5_storage *sp;
39355682Smarkm    kadm5_ret_t ret;
39455682Smarkm    off_t off;
39555682Smarkm    off_t len;
39655682Smarkm    krb5_data value;
39755682Smarkm    kadm5_log_context *log_context = &context->log_context;
39855682Smarkm
399178825Sdfr    krb5_data_zero(&value);
400178825Sdfr
40155682Smarkm    sp = krb5_storage_emem();
40255682Smarkm    ret = hdb_entry2value (context->context, ent, &value);
403178825Sdfr    if (ret)
404178825Sdfr	goto failed;
405178825Sdfr
40655682Smarkm    ret = kadm5_log_preamble (context, sp, kadm_rename);
407178825Sdfr    if (ret)
408178825Sdfr	goto failed;
409178825Sdfr
410178825Sdfr    ret = krb5_store_int32 (sp, 0);
411178825Sdfr    if (ret)
412178825Sdfr	goto failed;
413102644Snectar    off = krb5_storage_seek (sp, 0, SEEK_CUR);
414178825Sdfr    ret = krb5_store_principal (sp, source);
415178825Sdfr    if (ret)
416178825Sdfr	goto failed;
417178825Sdfr
418102644Snectar    krb5_storage_write(sp, value.data, value.length);
419102644Snectar    len = krb5_storage_seek (sp, 0, SEEK_CUR) - off;
42055682Smarkm
421102644Snectar    krb5_storage_seek(sp, -(len + 4), SEEK_CUR);
422178825Sdfr    ret = krb5_store_int32 (sp, len);
423178825Sdfr    if (ret)
424178825Sdfr	goto failed;
425178825Sdfr
426102644Snectar    krb5_storage_seek(sp, len, SEEK_CUR);
427178825Sdfr    ret = krb5_store_int32 (sp, len);
428178825Sdfr    if (ret)
429178825Sdfr	goto failed;
430178825Sdfr
43155682Smarkm    ret = kadm5_log_postamble (log_context, sp);
432178825Sdfr    if (ret)
433178825Sdfr	goto failed;
434178825Sdfr
43555682Smarkm    ret = kadm5_log_flush (log_context, sp);
436178825Sdfr    if (ret)
437178825Sdfr	goto failed;
43855682Smarkm    krb5_storage_free (sp);
439178825Sdfr    krb5_data_free (&value);
440178825Sdfr
441178825Sdfr    return kadm5_log_end (context);
442178825Sdfr
443178825Sdfrfailed:
444178825Sdfr    krb5_data_free(&value);
445178825Sdfr    krb5_storage_free(sp);
44655682Smarkm    return ret;
44755682Smarkm}
44855682Smarkm
44955682Smarkm/*
45055682Smarkm * Read a `rename' log operation from `sp' and apply it.
45155682Smarkm */
45255682Smarkm
453178825Sdfrstatic kadm5_ret_t
45455682Smarkmkadm5_log_replay_rename (kadm5_server_context *context,
455178825Sdfr			 uint32_t ver,
456178825Sdfr			 uint32_t len,
45755682Smarkm			 krb5_storage *sp)
45855682Smarkm{
45955682Smarkm    krb5_error_code ret;
46055682Smarkm    krb5_principal source;
461178825Sdfr    hdb_entry_ex target_ent;
46255682Smarkm    krb5_data value;
46355682Smarkm    off_t off;
46455682Smarkm    size_t princ_len, data_len;
46555682Smarkm
466178825Sdfr    memset(&target_ent, 0, sizeof(target_ent));
467178825Sdfr
468102644Snectar    off = krb5_storage_seek(sp, 0, SEEK_CUR);
469178825Sdfr    ret = krb5_ret_principal (sp, &source);
470178825Sdfr    if (ret) {
471233294Sstas	krb5_set_error_message(context->context, ret, "Failed to read renamed "
472233294Sstas			       "principal in log, version: %ld", (long)ver);
473178825Sdfr	return ret;
474178825Sdfr    }
475102644Snectar    princ_len = krb5_storage_seek(sp, 0, SEEK_CUR) - off;
47655682Smarkm    data_len = len - princ_len;
477120945Snectar    ret = krb5_data_alloc (&value, data_len);
478120945Snectar    if (ret) {
479120945Snectar	krb5_free_principal (context->context, source);
480120945Snectar	return ret;
481120945Snectar    }
482102644Snectar    krb5_storage_read (sp, value.data, data_len);
483178825Sdfr    ret = hdb_value2entry (context->context, &value, &target_ent.entry);
48455682Smarkm    krb5_data_free(&value);
48555682Smarkm    if (ret) {
48655682Smarkm	krb5_free_principal (context->context, source);
48755682Smarkm	return ret;
48855682Smarkm    }
489233294Sstas    ret = context->db->hdb_store (context->context, context->db,
490178825Sdfr				  0, &target_ent);
49155682Smarkm    hdb_free_entry (context->context, &target_ent);
49255682Smarkm    if (ret) {
49355682Smarkm	krb5_free_principal (context->context, source);
49455682Smarkm	return ret;
49555682Smarkm    }
496178825Sdfr    ret = context->db->hdb_remove (context->context, context->db, source);
49755682Smarkm    krb5_free_principal (context->context, source);
49855682Smarkm    return ret;
49955682Smarkm}
50055682Smarkm
50155682Smarkm
50255682Smarkm/*
50355682Smarkm * Add a `modify' operation to the log.
50455682Smarkm */
50555682Smarkm
50655682Smarkmkadm5_ret_t
50755682Smarkmkadm5_log_modify (kadm5_server_context *context,
50855682Smarkm		  hdb_entry *ent,
509178825Sdfr		  uint32_t mask)
51055682Smarkm{
51155682Smarkm    krb5_storage *sp;
51255682Smarkm    kadm5_ret_t ret;
51355682Smarkm    krb5_data value;
514178825Sdfr    uint32_t len;
51555682Smarkm    kadm5_log_context *log_context = &context->log_context;
51655682Smarkm
517178825Sdfr    krb5_data_zero(&value);
518178825Sdfr
51955682Smarkm    sp = krb5_storage_emem();
52055682Smarkm    ret = hdb_entry2value (context->context, ent, &value);
521178825Sdfr    if (ret)
522178825Sdfr	goto failed;
523178825Sdfr
52455682Smarkm    ret = kadm5_log_preamble (context, sp, kadm_modify);
525178825Sdfr    if (ret)
526178825Sdfr	goto failed;
527178825Sdfr
52855682Smarkm    len = value.length + 4;
529178825Sdfr    ret = krb5_store_int32 (sp, len);
530178825Sdfr    if (ret)
531178825Sdfr	goto failed;
532178825Sdfr    ret = krb5_store_int32 (sp, mask);
533178825Sdfr    if (ret)
534178825Sdfr	goto failed;
535102644Snectar    krb5_storage_write (sp, value.data, value.length);
536178825Sdfr
537178825Sdfr    ret = krb5_store_int32 (sp, len);
538178825Sdfr    if (ret)
539178825Sdfr	goto failed;
54055682Smarkm    ret = kadm5_log_postamble (log_context, sp);
541178825Sdfr    if (ret)
542178825Sdfr	goto failed;
54355682Smarkm    ret = kadm5_log_flush (log_context, sp);
544178825Sdfr    if (ret)
545178825Sdfr	goto failed;
546178825Sdfr    krb5_data_free(&value);
54755682Smarkm    krb5_storage_free (sp);
548178825Sdfr    return kadm5_log_end (context);
549178825Sdfrfailed:
550178825Sdfr    krb5_data_free(&value);
551178825Sdfr    krb5_storage_free(sp);
55255682Smarkm    return ret;
55355682Smarkm}
55455682Smarkm
55555682Smarkm/*
55655682Smarkm * Read a `modify' log operation from `sp' and apply it.
55755682Smarkm */
55855682Smarkm
559178825Sdfrstatic kadm5_ret_t
56055682Smarkmkadm5_log_replay_modify (kadm5_server_context *context,
561178825Sdfr			 uint32_t ver,
562178825Sdfr			 uint32_t len,
56355682Smarkm			 krb5_storage *sp)
56455682Smarkm{
56555682Smarkm    krb5_error_code ret;
56655682Smarkm    int32_t mask;
56755682Smarkm    krb5_data value;
568178825Sdfr    hdb_entry_ex ent, log_ent;
56955682Smarkm
570178825Sdfr    memset(&log_ent, 0, sizeof(log_ent));
571178825Sdfr
57255682Smarkm    krb5_ret_int32 (sp, &mask);
57355682Smarkm    len -= 4;
574120945Snectar    ret = krb5_data_alloc (&value, len);
575178825Sdfr    if (ret) {
576233294Sstas	krb5_set_error_message(context->context, ret, "out of memory");
577120945Snectar	return ret;
578178825Sdfr    }
579102644Snectar    krb5_storage_read (sp, value.data, len);
580178825Sdfr    ret = hdb_value2entry (context->context, &value, &log_ent.entry);
58155682Smarkm    krb5_data_free(&value);
58255682Smarkm    if (ret)
58355682Smarkm	return ret;
584178825Sdfr
585178825Sdfr    memset(&ent, 0, sizeof(ent));
586233294Sstas    ret = context->db->hdb_fetch_kvno(context->context, context->db,
587233294Sstas				      log_ent.entry.principal,
588233294Sstas				      HDB_F_DECRYPT|HDB_F_GET_ANY|HDB_F_ADMIN_DATA, 0, &ent);
58955682Smarkm    if (ret)
590178825Sdfr	goto out;
59155682Smarkm    if (mask & KADM5_PRINC_EXPIRE_TIME) {
592178825Sdfr	if (log_ent.entry.valid_end == NULL) {
593178825Sdfr	    ent.entry.valid_end = NULL;
59472445Sassar	} else {
595178825Sdfr	    if (ent.entry.valid_end == NULL) {
596178825Sdfr		ent.entry.valid_end = malloc(sizeof(*ent.entry.valid_end));
597178825Sdfr		if (ent.entry.valid_end == NULL) {
598178825Sdfr		    ret = ENOMEM;
599233294Sstas		    krb5_set_error_message(context->context, ret, "out of memory");
600178825Sdfr		    goto out;
601178825Sdfr		}
602178825Sdfr	    }
603178825Sdfr	    *ent.entry.valid_end = *log_ent.entry.valid_end;
60472445Sassar	}
60555682Smarkm    }
60655682Smarkm    if (mask & KADM5_PW_EXPIRATION) {
607178825Sdfr	if (log_ent.entry.pw_end == NULL) {
608178825Sdfr	    ent.entry.pw_end = NULL;
60972445Sassar	} else {
610178825Sdfr	    if (ent.entry.pw_end == NULL) {
611178825Sdfr		ent.entry.pw_end = malloc(sizeof(*ent.entry.pw_end));
612178825Sdfr		if (ent.entry.pw_end == NULL) {
613178825Sdfr		    ret = ENOMEM;
614233294Sstas		    krb5_set_error_message(context->context, ret, "out of memory");
615178825Sdfr		    goto out;
616178825Sdfr		}
617178825Sdfr	    }
618178825Sdfr	    *ent.entry.pw_end = *log_ent.entry.pw_end;
61972445Sassar	}
62055682Smarkm    }
62155682Smarkm    if (mask & KADM5_LAST_PWD_CHANGE) {
62255682Smarkm	abort ();		/* XXX */
62355682Smarkm    }
62455682Smarkm    if (mask & KADM5_ATTRIBUTES) {
625178825Sdfr	ent.entry.flags = log_ent.entry.flags;
62655682Smarkm    }
62755682Smarkm    if (mask & KADM5_MAX_LIFE) {
628178825Sdfr	if (log_ent.entry.max_life == NULL) {
629178825Sdfr	    ent.entry.max_life = NULL;
63072445Sassar	} else {
631178825Sdfr	    if (ent.entry.max_life == NULL) {
632178825Sdfr		ent.entry.max_life = malloc (sizeof(*ent.entry.max_life));
633178825Sdfr		if (ent.entry.max_life == NULL) {
634178825Sdfr		    ret = ENOMEM;
635233294Sstas		    krb5_set_error_message(context->context, ret, "out of memory");
636178825Sdfr		    goto out;
637178825Sdfr		}
638178825Sdfr	    }
639178825Sdfr	    *ent.entry.max_life = *log_ent.entry.max_life;
64072445Sassar	}
64155682Smarkm    }
64255682Smarkm    if ((mask & KADM5_MOD_TIME) && (mask & KADM5_MOD_NAME)) {
643178825Sdfr	if (ent.entry.modified_by == NULL) {
644178825Sdfr	    ent.entry.modified_by = malloc(sizeof(*ent.entry.modified_by));
645178825Sdfr	    if (ent.entry.modified_by == NULL) {
646178825Sdfr		ret = ENOMEM;
647233294Sstas		krb5_set_error_message(context->context, ret, "out of memory");
648178825Sdfr		goto out;
649178825Sdfr	    }
65055682Smarkm	} else
651178825Sdfr	    free_Event(ent.entry.modified_by);
652178825Sdfr	ret = copy_Event(log_ent.entry.modified_by, ent.entry.modified_by);
653178825Sdfr	if (ret) {
654233294Sstas	    krb5_set_error_message(context->context, ret, "out of memory");
655178825Sdfr	    goto out;
656178825Sdfr	}
65755682Smarkm    }
65855682Smarkm    if (mask & KADM5_KVNO) {
659178825Sdfr	ent.entry.kvno = log_ent.entry.kvno;
66055682Smarkm    }
66155682Smarkm    if (mask & KADM5_MKVNO) {
66255682Smarkm	abort ();		/* XXX */
66355682Smarkm    }
66455682Smarkm    if (mask & KADM5_AUX_ATTRIBUTES) {
66555682Smarkm	abort ();		/* XXX */
66655682Smarkm    }
66755682Smarkm    if (mask & KADM5_POLICY) {
66855682Smarkm	abort ();		/* XXX */
66955682Smarkm    }
67055682Smarkm    if (mask & KADM5_POLICY_CLR) {
67155682Smarkm	abort ();		/* XXX */
67255682Smarkm    }
67355682Smarkm    if (mask & KADM5_MAX_RLIFE) {
674178825Sdfr	if (log_ent.entry.max_renew == NULL) {
675178825Sdfr	    ent.entry.max_renew = NULL;
67672445Sassar	} else {
677178825Sdfr	    if (ent.entry.max_renew == NULL) {
678178825Sdfr		ent.entry.max_renew = malloc (sizeof(*ent.entry.max_renew));
679178825Sdfr		if (ent.entry.max_renew == NULL) {
680178825Sdfr		    ret = ENOMEM;
681233294Sstas		    krb5_set_error_message(context->context, ret, "out of memory");
682178825Sdfr		    goto out;
683178825Sdfr		}
684178825Sdfr	    }
685178825Sdfr	    *ent.entry.max_renew = *log_ent.entry.max_renew;
68672445Sassar	}
68755682Smarkm    }
68855682Smarkm    if (mask & KADM5_LAST_SUCCESS) {
68955682Smarkm	abort ();		/* XXX */
69055682Smarkm    }
69155682Smarkm    if (mask & KADM5_LAST_FAILED) {
69255682Smarkm	abort ();		/* XXX */
69355682Smarkm    }
69455682Smarkm    if (mask & KADM5_FAIL_AUTH_COUNT) {
69555682Smarkm	abort ();		/* XXX */
69655682Smarkm    }
69755682Smarkm    if (mask & KADM5_KEY_DATA) {
698178825Sdfr	size_t num;
699233294Sstas	size_t i;
70055682Smarkm
701178825Sdfr	for (i = 0; i < ent.entry.keys.len; ++i)
702178825Sdfr	    free_Key(&ent.entry.keys.val[i]);
703178825Sdfr	free (ent.entry.keys.val);
70455682Smarkm
705178825Sdfr	num = log_ent.entry.keys.len;
70655682Smarkm
707178825Sdfr	ent.entry.keys.len = num;
708178825Sdfr	ent.entry.keys.val = malloc(len * sizeof(*ent.entry.keys.val));
709178825Sdfr	if (ent.entry.keys.val == NULL) {
710233294Sstas	    krb5_set_error_message(context->context, ENOMEM, "out of memory");
711178825Sdfr	    return ENOMEM;
712178825Sdfr	}
713178825Sdfr	for (i = 0; i < ent.entry.keys.len; ++i) {
714178825Sdfr	    ret = copy_Key(&log_ent.entry.keys.val[i],
715178825Sdfr			   &ent.entry.keys.val[i]);
716178825Sdfr	    if (ret) {
717233294Sstas		krb5_set_error_message(context->context, ret, "out of memory");
718178825Sdfr		goto out;
719178825Sdfr	    }
720178825Sdfr	}
72155682Smarkm    }
722178825Sdfr    if ((mask & KADM5_TL_DATA) && log_ent.entry.extensions) {
723178825Sdfr	HDB_extensions *es = ent.entry.extensions;
724178825Sdfr
725178825Sdfr	ent.entry.extensions = calloc(1, sizeof(*ent.entry.extensions));
726178825Sdfr	if (ent.entry.extensions == NULL)
727178825Sdfr	    goto out;
728178825Sdfr
729178825Sdfr	ret = copy_HDB_extensions(log_ent.entry.extensions,
730178825Sdfr				  ent.entry.extensions);
731178825Sdfr	if (ret) {
732233294Sstas	    krb5_set_error_message(context->context, ret, "out of memory");
733178825Sdfr	    free(ent.entry.extensions);
734178825Sdfr	    ent.entry.extensions = es;
735178825Sdfr	    goto out;
736178825Sdfr	}
737178825Sdfr	if (es) {
738178825Sdfr	    free_HDB_extensions(es);
739178825Sdfr	    free(es);
740178825Sdfr	}
741178825Sdfr    }
742233294Sstas    ret = context->db->hdb_store(context->context, context->db,
743178825Sdfr				 HDB_F_REPLACE, &ent);
744178825Sdfr out:
74555682Smarkm    hdb_free_entry (context->context, &ent);
74655682Smarkm    hdb_free_entry (context->context, &log_ent);
74755682Smarkm    return ret;
74855682Smarkm}
74955682Smarkm
75055682Smarkm/*
751178825Sdfr * Add a `nop' operation to the log. Does not close the log.
75272445Sassar */
75372445Sassar
75472445Sassarkadm5_ret_t
75572445Sassarkadm5_log_nop (kadm5_server_context *context)
75672445Sassar{
75772445Sassar    krb5_storage *sp;
75872445Sassar    kadm5_ret_t ret;
75972445Sassar    kadm5_log_context *log_context = &context->log_context;
76072445Sassar
76172445Sassar    sp = krb5_storage_emem();
76272445Sassar    ret = kadm5_log_preamble (context, sp, kadm_nop);
76372445Sassar    if (ret) {
76472445Sassar	krb5_storage_free (sp);
76572445Sassar	return ret;
76672445Sassar    }
76772445Sassar    krb5_store_int32 (sp, 0);
76872445Sassar    krb5_store_int32 (sp, 0);
76972445Sassar    ret = kadm5_log_postamble (log_context, sp);
77072445Sassar    if (ret) {
77172445Sassar	krb5_storage_free (sp);
77272445Sassar	return ret;
77372445Sassar    }
77472445Sassar    ret = kadm5_log_flush (log_context, sp);
77572445Sassar    krb5_storage_free (sp);
776178825Sdfr
77772445Sassar    return ret;
77872445Sassar}
77972445Sassar
78072445Sassar/*
78172445Sassar * Read a `nop' log operation from `sp' and apply it.
78272445Sassar */
78372445Sassar
784178825Sdfrstatic kadm5_ret_t
78572445Sassarkadm5_log_replay_nop (kadm5_server_context *context,
786178825Sdfr		      uint32_t ver,
787178825Sdfr		      uint32_t len,
78872445Sassar		      krb5_storage *sp)
78972445Sassar{
79072445Sassar    return 0;
79172445Sassar}
79272445Sassar
79372445Sassar/*
79455682Smarkm * Call `func' for each log record in the log in `context'
79555682Smarkm */
79655682Smarkm
79755682Smarkmkadm5_ret_t
79855682Smarkmkadm5_log_foreach (kadm5_server_context *context,
79955682Smarkm		   void (*func)(kadm5_server_context *server_context,
800178825Sdfr				uint32_t ver,
80155682Smarkm				time_t timestamp,
80255682Smarkm				enum kadm_ops op,
803178825Sdfr				uint32_t len,
804178825Sdfr				krb5_storage *,
805178825Sdfr				void *),
806178825Sdfr		   void *ctx)
80755682Smarkm{
80855682Smarkm    int fd = context->log_context.log_fd;
80955682Smarkm    krb5_storage *sp;
81055682Smarkm
81155682Smarkm    lseek (fd, 0, SEEK_SET);
81255682Smarkm    sp = krb5_storage_from_fd (fd);
81355682Smarkm    for (;;) {
814178825Sdfr	int32_t ver, timestamp, op, len, len2, ver2;
81555682Smarkm
81655682Smarkm	if(krb5_ret_int32 (sp, &ver) != 0)
81755682Smarkm	    break;
81855682Smarkm	krb5_ret_int32 (sp, &timestamp);
81955682Smarkm	krb5_ret_int32 (sp, &op);
82055682Smarkm	krb5_ret_int32 (sp, &len);
821178825Sdfr	(*func)(context, ver, timestamp, op, len, sp, ctx);
822178825Sdfr	krb5_ret_int32 (sp, &len2);
823178825Sdfr	krb5_ret_int32 (sp, &ver2);
824178825Sdfr	if (len != len2)
825178825Sdfr	    abort();
826178825Sdfr	if (ver != ver2)
827178825Sdfr	    abort();
82855682Smarkm    }
829178825Sdfr    krb5_storage_free(sp);
83055682Smarkm    return 0;
83155682Smarkm}
83255682Smarkm
83355682Smarkm/*
83455682Smarkm * Go to end of log.
83555682Smarkm */
83655682Smarkm
83755682Smarkmkrb5_storage *
83855682Smarkmkadm5_log_goto_end (int fd)
83955682Smarkm{
84055682Smarkm    krb5_storage *sp;
84155682Smarkm
84255682Smarkm    sp = krb5_storage_from_fd (fd);
843102644Snectar    krb5_storage_seek(sp, 0, SEEK_END);
84455682Smarkm    return sp;
84555682Smarkm}
84655682Smarkm
84755682Smarkm/*
84855682Smarkm * Return previous log entry.
849233294Sstas *
850233294Sstas * The pointer in `sp�� is assumed to be at the top of the entry before
851233294Sstas * previous entry. On success, the `sp�� pointer is set to data portion
852178825Sdfr * of previous entry. In case of error, it's not changed at all.
85355682Smarkm */
85455682Smarkm
85555682Smarkmkadm5_ret_t
856178825Sdfrkadm5_log_previous (krb5_context context,
857178825Sdfr		    krb5_storage *sp,
858178825Sdfr		    uint32_t *ver,
85955682Smarkm		    time_t *timestamp,
86055682Smarkm		    enum kadm_ops *op,
861178825Sdfr		    uint32_t *len)
86255682Smarkm{
863178825Sdfr    krb5_error_code ret;
864178825Sdfr    off_t off, oldoff;
86555682Smarkm    int32_t tmp;
86655682Smarkm
867178825Sdfr    oldoff = krb5_storage_seek(sp, 0, SEEK_CUR);
868178825Sdfr
869102644Snectar    krb5_storage_seek(sp, -8, SEEK_CUR);
870178825Sdfr    ret = krb5_ret_int32 (sp, &tmp);
871178825Sdfr    if (ret)
872178825Sdfr	goto end_of_storage;
87355682Smarkm    *len = tmp;
874178825Sdfr    ret = krb5_ret_int32 (sp, &tmp);
875233294Sstas    if (ret)
876233294Sstas	goto end_of_storage;
87755682Smarkm    *ver = tmp;
87855682Smarkm    off = 24 + *len;
879102644Snectar    krb5_storage_seek(sp, -off, SEEK_CUR);
880178825Sdfr    ret = krb5_ret_int32 (sp, &tmp);
881178825Sdfr    if (ret)
882178825Sdfr	goto end_of_storage;
883233294Sstas    if ((uint32_t)tmp != *ver) {
884178825Sdfr	krb5_storage_seek(sp, oldoff, SEEK_SET);
885233294Sstas	krb5_set_error_message(context, KADM5_BAD_DB,
886233294Sstas			       "kadm5_log_previous: log entry "
887233294Sstas			       "have consistency failure, version number wrong "
888233294Sstas			       "(tmp %lu ver %lu)",
889233294Sstas			       (unsigned long)tmp,
890233294Sstas			       (unsigned long)*ver);
891178825Sdfr	return KADM5_BAD_DB;
892178825Sdfr    }
893178825Sdfr    ret = krb5_ret_int32 (sp, &tmp);
894178825Sdfr    if (ret)
895178825Sdfr	goto end_of_storage;
89655682Smarkm    *timestamp = tmp;
897178825Sdfr    ret = krb5_ret_int32 (sp, &tmp);
898233294Sstas    if (ret)
899233294Sstas	goto end_of_storage;
90055682Smarkm    *op = tmp;
901178825Sdfr    ret = krb5_ret_int32 (sp, &tmp);
902178825Sdfr    if (ret)
903178825Sdfr	goto end_of_storage;
904233294Sstas    if ((uint32_t)tmp != *len) {
905178825Sdfr	krb5_storage_seek(sp, oldoff, SEEK_SET);
906233294Sstas	krb5_set_error_message(context, KADM5_BAD_DB,
907233294Sstas			       "kadm5_log_previous: log entry "
908233294Sstas			       "have consistency failure, length wrong");
909178825Sdfr	return KADM5_BAD_DB;
910178825Sdfr    }
91155682Smarkm    return 0;
912178825Sdfr
913178825Sdfr end_of_storage:
914178825Sdfr    krb5_storage_seek(sp, oldoff, SEEK_SET);
915233294Sstas    krb5_set_error_message(context, ret, "kadm5_log_previous: end of storage "
916233294Sstas			   "reached before end");
917178825Sdfr    return ret;
91855682Smarkm}
91955682Smarkm
92055682Smarkm/*
92155682Smarkm * Replay a record from the log
92255682Smarkm */
92355682Smarkm
92455682Smarkmkadm5_ret_t
92555682Smarkmkadm5_log_replay (kadm5_server_context *context,
92655682Smarkm		  enum kadm_ops op,
927178825Sdfr		  uint32_t ver,
928178825Sdfr		  uint32_t len,
92955682Smarkm		  krb5_storage *sp)
93055682Smarkm{
93155682Smarkm    switch (op) {
93255682Smarkm    case kadm_create :
93355682Smarkm	return kadm5_log_replay_create (context, ver, len, sp);
93455682Smarkm    case kadm_delete :
93555682Smarkm	return kadm5_log_replay_delete (context, ver, len, sp);
93655682Smarkm    case kadm_rename :
93755682Smarkm	return kadm5_log_replay_rename (context, ver, len, sp);
93855682Smarkm    case kadm_modify :
93955682Smarkm	return kadm5_log_replay_modify (context, ver, len, sp);
94072445Sassar    case kadm_nop :
94172445Sassar	return kadm5_log_replay_nop (context, ver, len, sp);
94255682Smarkm    default :
943233294Sstas	krb5_set_error_message(context->context, KADM5_FAILURE,
944233294Sstas			       "Unsupported replay op %d", (int)op);
94555682Smarkm	return KADM5_FAILURE;
94655682Smarkm    }
94755682Smarkm}
94872445Sassar
94972445Sassar/*
95072445Sassar * truncate the log - i.e. create an empty file with just (nop vno + 2)
95172445Sassar */
95272445Sassar
95372445Sassarkadm5_ret_t
95472445Sassarkadm5_log_truncate (kadm5_server_context *server_context)
95572445Sassar{
95672445Sassar    kadm5_ret_t ret;
957178825Sdfr    uint32_t vno;
95872445Sassar
95972445Sassar    ret = kadm5_log_init (server_context);
96072445Sassar    if (ret)
96172445Sassar	return ret;
96272445Sassar
96372445Sassar    ret = kadm5_log_get_version (server_context, &vno);
96472445Sassar    if (ret)
96572445Sassar	return ret;
96672445Sassar
96772445Sassar    ret = kadm5_log_reinit (server_context);
96872445Sassar    if (ret)
96972445Sassar	return ret;
97072445Sassar
971178825Sdfr    ret = kadm5_log_set_version (server_context, vno);
97272445Sassar    if (ret)
97372445Sassar	return ret;
97472445Sassar
97572445Sassar    ret = kadm5_log_nop (server_context);
97672445Sassar    if (ret)
97772445Sassar	return ret;
97872445Sassar
97972445Sassar    ret = kadm5_log_end (server_context);
98072445Sassar    if (ret)
98172445Sassar	return ret;
98272445Sassar    return 0;
98372445Sassar
98472445Sassar}
985178825Sdfr
986233294Sstas#ifndef NO_UNIX_SOCKETS
987233294Sstas
988178825Sdfrstatic char *default_signal = NULL;
989178825Sdfrstatic HEIMDAL_MUTEX signal_mutex = HEIMDAL_MUTEX_INITIALIZER;
990178825Sdfr
991178825Sdfrconst char *
992178825Sdfrkadm5_log_signal_socket(krb5_context context)
993178825Sdfr{
994178825Sdfr    HEIMDAL_MUTEX_lock(&signal_mutex);
995178825Sdfr    if (!default_signal)
996178825Sdfr	asprintf(&default_signal, "%s/signal", hdb_db_dir(context));
997178825Sdfr    HEIMDAL_MUTEX_unlock(&signal_mutex);
998178825Sdfr
999178825Sdfr    return krb5_config_get_string_default(context,
1000178825Sdfr					  NULL,
1001178825Sdfr					  default_signal,
1002178825Sdfr					  "kdc",
1003178825Sdfr					  "signal_socket",
1004178825Sdfr					  NULL);
1005178825Sdfr}
1006233294Sstas
1007233294Sstas#else  /* NO_UNIX_SOCKETS */
1008233294Sstas
1009233294Sstas#define SIGNAL_SOCKET_HOST "127.0.0.1"
1010233294Sstas#define SIGNAL_SOCKET_PORT "12701"
1011233294Sstas
1012233294Sstaskadm5_ret_t
1013233294Sstaskadm5_log_signal_socket_info(krb5_context context,
1014233294Sstas			     int server_end,
1015233294Sstas			     struct addrinfo **ret_addrs)
1016233294Sstas{
1017233294Sstas    struct addrinfo hints;
1018233294Sstas    struct addrinfo *addrs = NULL;
1019233294Sstas    kadm5_ret_t ret = KADM5_FAILURE;
1020233294Sstas    int wsret;
1021233294Sstas
1022233294Sstas    memset(&hints, 0, sizeof(hints));
1023233294Sstas
1024233294Sstas    hints.ai_flags = AI_NUMERICHOST;
1025233294Sstas    if (server_end)
1026233294Sstas	hints.ai_flags |= AI_PASSIVE;
1027233294Sstas    hints.ai_family = AF_INET;
1028233294Sstas    hints.ai_socktype = SOCK_STREAM;
1029233294Sstas    hints.ai_protocol = IPPROTO_TCP;
1030233294Sstas
1031233294Sstas    wsret = getaddrinfo(SIGNAL_SOCKET_HOST,
1032233294Sstas			SIGNAL_SOCKET_PORT,
1033233294Sstas			&hints, &addrs);
1034233294Sstas
1035233294Sstas    if (wsret != 0) {
1036233294Sstas	krb5_set_error_message(context, KADM5_FAILURE,
1037233294Sstas			       "%s", gai_strerror(wsret));
1038233294Sstas	goto done;
1039233294Sstas    }
1040233294Sstas
1041233294Sstas    if (addrs == NULL) {
1042233294Sstas	krb5_set_error_message(context, KADM5_FAILURE,
1043233294Sstas			       "getaddrinfo() failed to return address list");
1044233294Sstas	goto done;
1045233294Sstas    }
1046233294Sstas
1047233294Sstas    *ret_addrs = addrs;
1048233294Sstas    addrs = NULL;
1049233294Sstas    ret = 0;
1050233294Sstas
1051233294Sstas done:
1052233294Sstas    if (addrs)
1053233294Sstas	freeaddrinfo(addrs);
1054233294Sstas    return ret;
1055233294Sstas}
1056233294Sstas
1057233294Sstas#endif
1058