155682Smarkm/*
2233294Sstas * Copyright (c) 1997-2006 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 "hprop.h"
3555682Smarkm
3655682Smarkmstatic int inetd_flag = -1;
3755682Smarkmstatic int help_flag;
3855682Smarkmstatic int version_flag;
3955682Smarkmstatic int print_dump;
40178825Sdfrstatic const char *database;
4155682Smarkmstatic int from_stdin;
4290926Snectarstatic char *local_realm;
4372445Sassarstatic char *ktname = NULL;
4455682Smarkm
4555682Smarkmstruct getargs args[] = {
46233294Sstas    { "database", 'd', arg_string, rk_UNCONST(&database), "database", "file" },
47233294Sstas    { "stdin",    'n', arg_flag, &from_stdin, "read from stdin", NULL },
48233294Sstas    { "print",	    0, arg_flag, &print_dump, "print dump to stdout", NULL },
49233294Sstas#ifdef SUPPORT_INETD
5055682Smarkm    { "inetd",	   'i',	arg_negative_flag,	&inetd_flag,
51233294Sstas      "Not started from inetd", NULL },
52233294Sstas#endif
5372445Sassar    { "keytab",   'k',	arg_string, &ktname,	"keytab to use for authentication", "keytab" },
54233294Sstas    { "realm",   'r',	arg_string, &local_realm, "realm to use", NULL },
5555682Smarkm    { "version",    0, arg_flag, &version_flag, NULL, NULL },
5655682Smarkm    { "help",    'h',  arg_flag, &help_flag, NULL, NULL}
5755682Smarkm};
5855682Smarkm
5955682Smarkmstatic int num_args = sizeof(args) / sizeof(args[0]);
60233294Sstasstatic char unparseable_name[] = "unparseable name";
6155682Smarkm
6255682Smarkmstatic void
6355682Smarkmusage(int ret)
6455682Smarkm{
6555682Smarkm    arg_printusage (args, num_args, NULL, "");
6655682Smarkm    exit (ret);
6755682Smarkm}
6855682Smarkm
6955682Smarkmint
7055682Smarkmmain(int argc, char **argv)
7155682Smarkm{
7255682Smarkm    krb5_error_code ret;
7355682Smarkm    krb5_context context;
7455682Smarkm    krb5_auth_context ac = NULL;
7555682Smarkm    krb5_principal c1, c2;
7655682Smarkm    krb5_authenticator authent;
7755682Smarkm    krb5_keytab keytab;
78233294Sstas    krb5_socket_t sock = rk_INVALID_SOCKET;
79233294Sstas    HDB *db = NULL;
80178825Sdfr    int optidx = 0;
8155682Smarkm    char *tmp_db;
8255682Smarkm    krb5_log_facility *fac;
8355682Smarkm    int nprincs;
8455682Smarkm
8578527Sassar    setprogname(argv[0]);
8655682Smarkm
8755682Smarkm    ret = krb5_init_context(&context);
8855682Smarkm    if(ret)
8955682Smarkm	exit(1);
9055682Smarkm
9155682Smarkm    ret = krb5_openlog(context, "hpropd", &fac);
9255682Smarkm    if(ret)
93233294Sstas	errx(1, "krb5_openlog");
9455682Smarkm    krb5_set_warn_dest(context, fac);
95233294Sstas
96178825Sdfr    if(getarg(args, num_args, argc, argv, &optidx))
9755682Smarkm	usage(1);
9855682Smarkm
9990926Snectar    if(local_realm != NULL)
10090926Snectar	krb5_set_default_realm(context, local_realm);
101233294Sstas
10255682Smarkm    if(help_flag)
10355682Smarkm	usage(0);
10455682Smarkm    if(version_flag) {
10555682Smarkm	print_version(NULL);
10655682Smarkm	exit(0);
10755682Smarkm    }
108233294Sstas
109178825Sdfr    argc -= optidx;
110178825Sdfr    argv += optidx;
11155682Smarkm
11255682Smarkm    if (argc != 0)
11355682Smarkm	usage(1);
11455682Smarkm
115178825Sdfr    if (database == NULL)
116178825Sdfr	database = hdb_default_db(context);
117178825Sdfr
118233294Sstas    if(from_stdin) {
119233294Sstas	sock = STDIN_FILENO;
120233294Sstas    } else {
12155682Smarkm	struct sockaddr_storage ss;
12255682Smarkm	struct sockaddr *sa = (struct sockaddr *)&ss;
12372445Sassar	socklen_t sin_len = sizeof(ss);
12455682Smarkm	char addr_name[256];
12572445Sassar	krb5_ticket *ticket;
12672445Sassar	char *server;
12755682Smarkm
128233294Sstas	sock = STDIN_FILENO;
129233294Sstas#ifdef SUPPORT_INETD
13055682Smarkm	if (inetd_flag == -1) {
131233294Sstas	    if (getpeername (sock, sa, &sin_len) < 0) {
13255682Smarkm		inetd_flag = 0;
133233294Sstas	    } else {
13455682Smarkm		inetd_flag = 1;
135233294Sstas	    }
13655682Smarkm	}
137233294Sstas#else
138233294Sstas	inetd_flag = 0;
139233294Sstas#endif
14055682Smarkm	if (!inetd_flag) {
14155682Smarkm	    mini_inetd (krb5_getportbyname (context, "hprop", "tcp",
142233294Sstas					    HPROP_PORT), &sock);
14355682Smarkm	}
14455682Smarkm	sin_len = sizeof(ss);
145233294Sstas	if(getpeername(sock, sa, &sin_len) < 0)
14655682Smarkm	    krb5_err(context, 1, errno, "getpeername");
14755682Smarkm
14855682Smarkm	if (inet_ntop(sa->sa_family,
14955682Smarkm		      socket_get_address (sa),
15055682Smarkm		      addr_name,
15155682Smarkm		      sizeof(addr_name)) == NULL)
15255682Smarkm	    strlcpy (addr_name, "unknown address",
153178825Sdfr		     sizeof(addr_name));
15455682Smarkm
15555682Smarkm	krb5_log(context, fac, 0, "Connection from %s", addr_name);
156233294Sstas
15772445Sassar	ret = krb5_kt_register(context, &hdb_kt_ops);
15855682Smarkm	if(ret)
15972445Sassar	    krb5_err(context, 1, ret, "krb5_kt_register");
16072445Sassar
16172445Sassar	if (ktname != NULL) {
16272445Sassar	    ret = krb5_kt_resolve(context, ktname, &keytab);
16372445Sassar	    if (ret)
16472445Sassar		krb5_err (context, 1, ret, "krb5_kt_resolve %s", ktname);
16572445Sassar	} else {
16672445Sassar	    ret = krb5_kt_default (context, &keytab);
16772445Sassar	    if (ret)
16872445Sassar		krb5_err (context, 1, ret, "krb5_kt_default");
16972445Sassar	}
17072445Sassar
171233294Sstas	ret = krb5_recvauth(context, &ac, &sock, HPROP_VERSION, NULL,
17272445Sassar			    0, keytab, &ticket);
17355682Smarkm	if(ret)
17455682Smarkm	    krb5_err(context, 1, ret, "krb5_recvauth");
175233294Sstas
17672445Sassar	ret = krb5_unparse_name(context, ticket->server, &server);
17772445Sassar	if (ret)
17872445Sassar	    krb5_err(context, 1, ret, "krb5_unparse_name");
17972445Sassar	if (strncmp(server, "hprop/", 5) != 0)
18072445Sassar	    krb5_errx(context, 1, "ticket not for hprop (%s)", server);
18172445Sassar
18272445Sassar	free(server);
18372445Sassar	krb5_free_ticket (context, ticket);
18472445Sassar
18590926Snectar	ret = krb5_auth_con_getauthenticator(context, ac, &authent);
18655682Smarkm	if(ret)
18790926Snectar	    krb5_err(context, 1, ret, "krb5_auth_con_getauthenticator");
188233294Sstas
18955682Smarkm	ret = krb5_make_principal(context, &c1, NULL, "kadmin", "hprop", NULL);
19055682Smarkm	if(ret)
19155682Smarkm	    krb5_err(context, 1, ret, "krb5_make_principal");
192233294Sstas	_krb5_principalname2krb5_principal(context, &c2,
193178825Sdfr					   authent->cname, authent->crealm);
19455682Smarkm	if(!krb5_principal_compare(context, c1, c2)) {
19555682Smarkm	    char *s;
196178825Sdfr	    ret = krb5_unparse_name(context, c2, &s);
197178825Sdfr	    if (ret)
198233294Sstas		s = unparseable_name;
19955682Smarkm	    krb5_errx(context, 1, "Unauthorized connection from %s", s);
20055682Smarkm	}
20155682Smarkm	krb5_free_principal(context, c1);
20255682Smarkm	krb5_free_principal(context, c2);
20355682Smarkm
20455682Smarkm	ret = krb5_kt_close(context, keytab);
20555682Smarkm	if(ret)
20655682Smarkm	    krb5_err(context, 1, ret, "krb5_kt_close");
20755682Smarkm    }
208233294Sstas
20955682Smarkm    if(!print_dump) {
21055682Smarkm	asprintf(&tmp_db, "%s~", database);
21155682Smarkm
212178825Sdfr	ret = hdb_create(context, &db, tmp_db);
213178825Sdfr	if(ret)
214178825Sdfr	    krb5_err(context, 1, ret, "hdb_create(%s)", tmp_db);
215178825Sdfr	ret = db->hdb_open(context, db, O_RDWR | O_CREAT | O_TRUNC, 0600);
216178825Sdfr	if(ret)
217178825Sdfr	    krb5_err(context, 1, ret, "hdb_open(%s)", tmp_db);
21855682Smarkm    }
21955682Smarkm
22055682Smarkm    nprincs = 0;
22155682Smarkm    while(1){
22255682Smarkm	krb5_data data;
223178825Sdfr	hdb_entry_ex entry;
22455682Smarkm
22572445Sassar	if(from_stdin) {
226233294Sstas	    ret = krb5_read_message(context, &sock, &data);
22772445Sassar	    if(ret != 0 && ret != HEIM_ERR_EOF)
22872445Sassar		krb5_err(context, 1, ret, "krb5_read_message");
22972445Sassar	} else {
230233294Sstas	    ret = krb5_read_priv_message(context, ac, &sock, &data);
23155682Smarkm	    if(ret)
23272445Sassar		krb5_err(context, 1, ret, "krb5_read_priv_message");
23355682Smarkm	}
23455682Smarkm
23572445Sassar	if(ret == HEIM_ERR_EOF || data.length == 0) {
23655682Smarkm	    if(!from_stdin) {
23755682Smarkm		data.data = NULL;
23855682Smarkm		data.length = 0;
239233294Sstas		krb5_write_priv_message(context, ac, &sock, &data);
24055682Smarkm	    }
24155682Smarkm	    if(!print_dump) {
242233294Sstas		ret = db->hdb_close(context, db);
243233294Sstas		if(ret)
244233294Sstas		    krb5_err(context, 1, ret, "db_close");
245178825Sdfr		ret = db->hdb_rename(context, db, database);
246178825Sdfr		if(ret)
247178825Sdfr		    krb5_err(context, 1, ret, "db_rename");
24855682Smarkm	    }
24955682Smarkm	    break;
25055682Smarkm	}
251178825Sdfr	memset(&entry, 0, sizeof(entry));
252178825Sdfr	ret = hdb_value2entry(context, &data, &entry.entry);
253178825Sdfr	krb5_data_free(&data);
25455682Smarkm	if(ret)
25555682Smarkm	    krb5_err(context, 1, ret, "hdb_value2entry");
25655682Smarkm	if(print_dump)
25755682Smarkm	    hdb_print_entry(context, db, &entry, stdout);
25855682Smarkm	else {
259178825Sdfr	    ret = db->hdb_store(context, db, 0, &entry);
260178825Sdfr	    if(ret == HDB_ERR_EXISTS) {
261178825Sdfr		char *s;
262178825Sdfr		ret = krb5_unparse_name(context, entry.entry.principal, &s);
263178825Sdfr		if (ret)
264233294Sstas		    s = strdup(unparseable_name);
265178825Sdfr		krb5_warnx(context, "Entry exists: %s", s);
266178825Sdfr		free(s);
267233294Sstas	    } else if(ret)
268178825Sdfr		krb5_err(context, 1, ret, "db_store");
26955682Smarkm	    else
270178825Sdfr		nprincs++;
27155682Smarkm	}
27255682Smarkm	hdb_free_entry(context, &entry);
27355682Smarkm    }
27455682Smarkm    if (!print_dump)
27555682Smarkm	krb5_log(context, fac, 0, "Received %d principals", nprincs);
276233294Sstas
277233294Sstas    if (inetd_flag == 0)
278233294Sstas	rk_closesocket(sock);
279233294Sstas
28055682Smarkm    exit(0);
28155682Smarkm}
282