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