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
36 RCSID("$Id: hpropd.c,v 1.36 2003/04/16 15:46:32 lha Exp $");
39 static des_cblock mkey4
;
40 static des_key_schedule msched4
;
46 strftime(buf
, sizeof(buf
), "%Y%m%d%H%M", gmtime(&t
));
51 dump_krb4(krb5_context context
, hdb_entry
*ent
, int fd
)
54 char instance
[INST_SZ
];
65 ret
= krb5_524_conv_principal(context
, ent
->principal
,
66 name
, instance
, realm
);
68 krb5_unparse_name(context
, ent
->principal
, &princ_name
);
69 krb5_warn(context
, ret
, "%s", princ_name
);
74 ret
= krb5_get_default_realms (context
, &realms
);
76 krb5_warn(context
, ret
, "krb5_get_default_realms");
80 cmp
= strcmp (realms
[0], ent
->principal
->realm
);
81 krb5_free_host_realm (context
, realms
);
85 snprintf (buf
, sizeof(buf
), "%s %s ", name
,
86 (strlen(instance
) != 0) ? instance
: "*");
89 asprintf(&p
, "%d", krb_time_to_life(0, *ent
->max_life
));
90 strlcat(buf
, p
, sizeof(buf
));
93 strlcat(buf
, "255", sizeof(buf
));
94 strlcat(buf
, " ", sizeof(buf
));
97 while (i
< ent
->keys
.len
&&
98 ent
->keys
.val
[i
].key
.keytype
!= KEYTYPE_DES
)
101 if (i
== ent
->keys
.len
) {
102 krb5_warnx(context
, "No DES key for %s.%s", name
, instance
);
106 if (ent
->keys
.val
[i
].mkvno
)
107 asprintf(&p
, "%d ", *ent
->keys
.val
[i
].mkvno
);
109 asprintf(&p
, "%d ", 1);
110 strlcat(buf
, p
, sizeof(buf
));
113 asprintf(&p
, "%d ", ent
->kvno
);
114 strlcat(buf
, p
, sizeof(buf
));
117 asprintf(&p
, "%d ", 0); /* Attributes are always 0*/
118 strlcat(buf
, p
, sizeof(buf
));
122 u_int32_t
*key
= ent
->keys
.val
[i
].key
.keyvalue
.data
;
123 kdb_encrypt_key((des_cblock
*)key
, (des_cblock
*)key
,
124 &mkey4
, msched4
, DES_ENCRYPT
);
125 asprintf(&p
, "%x %x ", (int)htonl(*key
), (int)htonl(*(key
+1)));
126 strlcat(buf
, p
, sizeof(buf
));
130 if (ent
->valid_end
== NULL
)
131 strlcat(buf
, time2str(60*60*24*365*50), sizeof(buf
)); /*no expiration*/
133 strlcat(buf
, time2str(*ent
->valid_end
), sizeof(buf
));
134 strlcat(buf
, " ", sizeof(buf
));
136 if (ent
->modified_by
== NULL
)
137 modifier
= &ent
->created_by
;
139 modifier
= ent
->modified_by
;
141 ret
= krb5_524_conv_principal(context
, modifier
->principal
,
142 name
, instance
, realm
);
144 krb5_unparse_name(context
, modifier
->principal
, &princ_name
);
145 krb5_warn(context
, ret
, "%s", princ_name
);
149 asprintf(&p
, "%s %s %s\n", time2str(modifier
->time
),
150 (strlen(name
) != 0) ? name
: "*",
151 (strlen(instance
) != 0) ? instance
: "*");
152 strlcat(buf
, p
, sizeof(buf
));
155 ret
= write(fd
, buf
, strlen(buf
));
157 krb5_warnx(context
, "write");
162 static int inetd_flag
= -1;
163 static int help_flag
;
164 static int version_flag
;
165 static int print_dump
;
166 static const char *database
= HDB_DEFAULT_DB
;
167 static int from_stdin
;
168 static char *local_realm
;
172 static char *ktname
= NULL
;
174 struct getargs args
[] = {
175 { "database", 'd', arg_string
, &database
, "database", "file" },
176 { "stdin", 'n', arg_flag
, &from_stdin
, "read from stdin" },
177 { "print", 0, arg_flag
, &print_dump
, "print dump to stdout" },
178 { "inetd", 'i', arg_negative_flag
, &inetd_flag
,
179 "Not started from inetd" },
180 { "keytab", 'k', arg_string
, &ktname
, "keytab to use for authentication", "keytab" },
181 { "realm", 'r', arg_string
, &local_realm
, "realm to use" },
183 { "v4dump", '4', arg_flag
, &v4dump
, "create v4 type DB" },
185 { "version", 0, arg_flag
, &version_flag
, NULL
, NULL
},
186 { "help", 'h', arg_flag
, &help_flag
, NULL
, NULL
}
189 static int num_args
= sizeof(args
) / sizeof(args
[0]);
194 arg_printusage (args
, num_args
, NULL
, "");
199 main(int argc
, char **argv
)
202 krb5_context context
;
203 krb5_auth_context ac
= NULL
;
204 krb5_principal c1
, c2
;
205 krb5_authenticator authent
;
211 krb5_log_facility
*fac
;
218 setprogname(argv
[0]);
220 ret
= krb5_init_context(&context
);
224 ret
= krb5_openlog(context
, "hpropd", &fac
);
227 krb5_set_warn_dest(context
, fac
);
229 if(getarg(args
, num_args
, argc
, argv
, &optind
))
233 if (v4dump
&& database
== HDB_DEFAULT_DB
)
234 database
= "/var/kerberos/524_dump";
237 if(local_realm
!= NULL
)
238 krb5_set_default_realm(context
, local_realm
);
256 struct sockaddr_storage ss
;
257 struct sockaddr
*sa
= (struct sockaddr
*)&ss
;
258 socklen_t sin_len
= sizeof(ss
);
264 if (inetd_flag
== -1) {
265 if (getpeername (fd
, sa
, &sin_len
) < 0)
271 mini_inetd (krb5_getportbyname (context
, "hprop", "tcp",
274 sin_len
= sizeof(ss
);
275 if(getpeername(fd
, sa
, &sin_len
) < 0)
276 krb5_err(context
, 1, errno
, "getpeername");
278 if (inet_ntop(sa
->sa_family
,
279 socket_get_address (sa
),
281 sizeof(addr_name
)) == NULL
)
282 strlcpy (addr_name
, "unknown address",
285 krb5_log(context
, fac
, 0, "Connection from %s", addr_name
);
287 ret
= krb5_kt_register(context
, &hdb_kt_ops
);
289 krb5_err(context
, 1, ret
, "krb5_kt_register");
291 if (ktname
!= NULL
) {
292 ret
= krb5_kt_resolve(context
, ktname
, &keytab
);
294 krb5_err (context
, 1, ret
, "krb5_kt_resolve %s", ktname
);
296 ret
= krb5_kt_default (context
, &keytab
);
298 krb5_err (context
, 1, ret
, "krb5_kt_default");
301 ret
= krb5_recvauth(context
, &ac
, &fd
, HPROP_VERSION
, NULL
,
304 krb5_err(context
, 1, ret
, "krb5_recvauth");
306 ret
= krb5_unparse_name(context
, ticket
->server
, &server
);
308 krb5_err(context
, 1, ret
, "krb5_unparse_name");
309 if (strncmp(server
, "hprop/", 5) != 0)
310 krb5_errx(context
, 1, "ticket not for hprop (%s)", server
);
313 krb5_free_ticket (context
, ticket
);
315 ret
= krb5_auth_con_getauthenticator(context
, ac
, &authent
);
317 krb5_err(context
, 1, ret
, "krb5_auth_con_getauthenticator");
319 ret
= krb5_make_principal(context
, &c1
, NULL
, "kadmin", "hprop", NULL
);
321 krb5_err(context
, 1, ret
, "krb5_make_principal");
322 principalname2krb5_principal(&c2
, authent
->cname
, authent
->crealm
);
323 if(!krb5_principal_compare(context
, c1
, c2
)) {
325 krb5_unparse_name(context
, c2
, &s
);
326 krb5_errx(context
, 1, "Unauthorized connection from %s", s
);
328 krb5_free_principal(context
, c1
);
329 krb5_free_principal(context
, c2
);
331 ret
= krb5_kt_close(context
, keytab
);
333 krb5_err(context
, 1, ret
, "krb5_kt_close");
337 asprintf(&tmp_db
, "%s~", database
);
340 fd_out
= open(tmp_db
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0600);
342 krb5_errx(context
, 1, "%s", strerror(errno
));
347 ret
= hdb_create(context
, &db
, tmp_db
);
349 krb5_err(context
, 1, ret
, "hdb_create(%s)", tmp_db
);
350 ret
= db
->open(context
, db
, O_RDWR
| O_CREAT
| O_TRUNC
, 0600);
352 krb5_err(context
, 1, ret
, "hdb_open(%s)", tmp_db
);
358 e
= kdb_get_master_key(0, &mkey4
, msched4
);
360 krb5_errx(context
, 1, "kdb_get_master_key: %s",
361 krb_get_err_text(e
));
371 ret
= krb5_read_message(context
, &fd
, &data
);
372 if(ret
!= 0 && ret
!= HEIM_ERR_EOF
)
373 krb5_err(context
, 1, ret
, "krb5_read_message");
375 ret
= krb5_read_priv_message(context
, ac
, &fd
, &data
);
377 krb5_err(context
, 1, ret
, "krb5_read_priv_message");
380 if(ret
== HEIM_ERR_EOF
|| data
.length
== 0) {
384 krb5_write_priv_message(context
, ac
, &fd
, &data
);
389 ret
= rename(tmp_db
, database
);
391 krb5_errx(context
, 1, "rename");
394 krb5_errx(context
, 1, "close");
398 ret
= db
->rename(context
, db
, database
);
400 krb5_err(context
, 1, ret
, "db_rename");
401 ret
= db
->close(context
, db
);
403 krb5_err(context
, 1, ret
, "db_close");
408 ret
= hdb_value2entry(context
, &data
, &entry
);
410 krb5_err(context
, 1, ret
, "hdb_value2entry");
412 hdb_print_entry(context
, db
, &entry
, stdout
);
416 ret
= dump_krb4(context
, &entry
, fd_out
);
422 ret
= db
->store(context
, db
, 0, &entry
);
423 if(ret
== HDB_ERR_EXISTS
) {
425 krb5_unparse_name(context
, entry
.principal
, &s
);
426 krb5_warnx(context
, "Entry exists: %s", s
);
429 krb5_err(context
, 1, ret
, "db_store");
434 hdb_free_entry(context
, &entry
);
437 krb5_log(context
, fac
, 0, "Received %d principals", nprincs
);