summaryrefslogtreecommitdiffstats
path: root/ipa-server/ipa-keytab-util/ipa-keytab-util.c
diff options
context:
space:
mode:
authorKarl MacMillan <kmacmill@redhat.com>2007-11-21 23:28:25 -0500
committerKarl MacMillan <kmacmill@redhat.com>2007-11-21 23:28:25 -0500
commitedc7af1446af451ea5ed44420cceb05059a7b973 (patch)
treec8ef012239d7ed5f9cce0190d7f071b871e3d070 /ipa-server/ipa-keytab-util/ipa-keytab-util.c
parent9038bf71dd76d845746e0ea3e94bca9f52f60c03 (diff)
downloadfreeipa-edc7af1446af451ea5ed44420cceb05059a7b973.tar.gz
freeipa-edc7af1446af451ea5ed44420cceb05059a7b973.tar.xz
freeipa-edc7af1446af451ea5ed44420cceb05059a7b973.zip
Add xml-rpc interface for getting keytabs.
Warning: this lacks any sort of authorization.
Diffstat (limited to 'ipa-server/ipa-keytab-util/ipa-keytab-util.c')
-rw-r--r--ipa-server/ipa-keytab-util/ipa-keytab-util.c304
1 files changed, 304 insertions, 0 deletions
diff --git a/ipa-server/ipa-keytab-util/ipa-keytab-util.c b/ipa-server/ipa-keytab-util/ipa-keytab-util.c
new file mode 100644
index 000000000..d080d0cd5
--- /dev/null
+++ b/ipa-server/ipa-keytab-util/ipa-keytab-util.c
@@ -0,0 +1,304 @@
+/*
+ * Authors:
+ * Karl MacMillan <kmacmill@redhat.com>
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE /* for asprintf */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#define KADMIN_PATH "/usr/kerberos/sbin/kadmin.local"
+
+struct options
+{
+ char *princ_name;
+ char *realm;
+ int kstdin, kstdout, kstderr;
+};
+
+void *xmalloc(size_t size)
+{
+ void *foo = malloc(size);
+ if (!foo) {
+ fprintf(stderr, "malloc error of size %jd\n", size);
+ exit(1);
+ }
+ memset(foo, 0, size);
+
+ return foo;
+}
+
+void usage(void)
+{
+ printf("ipa-keytab-util princ-name realm-name\n");
+}
+
+struct options *process_args(int argc, char **argv)
+{
+ struct options* opts;
+
+ opts = xmalloc(sizeof(struct options));
+
+ if (argc != 3) {
+ usage();
+ exit(1);
+ }
+
+ opts->princ_name = argv[1];
+ opts->realm = argv[2];
+
+ return opts;
+}
+
+void drop_caps(void)
+{
+ cap_t caps;
+ int ret;
+
+ if (geteuid() != 0)
+ return;
+ if (getuid() != 0)
+ return;
+
+ caps = cap_init();
+ if (!caps) {
+ perror("error initializing caps");
+ exit(1);
+ }
+ ret = cap_clear(caps);
+ if (ret != 0) {
+ perror("could not clear capps");
+ exit(1);
+ }
+
+ ret = cap_set_proc(caps);
+ if (ret != 0) {
+ perror("could not drop caps");
+ exit(1);
+ }
+
+ cap_free(caps);
+}
+
+pid_t exec_kadmin_local(struct options *opts)
+{
+ int stdin_pipes[2];
+ int stdout_pipes[2];
+ int stderr_pipes[2];
+ int ret;
+ pid_t chpid;
+ char *princ;
+
+ /* create a pair of pipes for stdin / stdout
+ of the child process.
+ */
+
+ if (pipe(stdin_pipes) == -1) {
+ perror("creating stdin");
+ exit(1);
+ }
+
+ if (pipe(stdout_pipes) == -1) {
+ perror("creating stdin");
+ exit(1);
+ }
+
+ if (pipe(stderr_pipes) == -1) {
+ perror("creating stdin");
+ exit(1);
+ }
+
+ chpid = fork();
+ if (chpid == -1) {
+ perror("fork");
+ exit(1);
+ }
+
+ /* CHILD */
+ if (chpid == 0) {
+ /* stdin */
+ close(stdin_pipes[1]);
+ dup2(stdin_pipes[0], 0);
+
+ /* stdout */
+ close(stdout_pipes[0]);
+ dup2(stdout_pipes[1], 1);
+
+ /* stderr */
+ close(stderr_pipes[0]);
+ dup2(stdout_pipes[1], 2);
+
+ /* now exec kadmin.local */
+
+ ret = asprintf(&princ, "admin@%s", opts->realm);
+ if (!princ) {
+ perror("creating bind princ");
+ exit(1);
+ }
+ ret = execl(KADMIN_PATH, "kadmin.local", "-p", princ, NULL);
+ free(princ);
+ if (ret == -1) {
+ perror("exec");
+ exit(1);
+ }
+ } else {
+ close(stdin_pipes[0]);
+ close(stdout_pipes[1]);
+ close(stderr_pipes[1]);
+
+ opts->kstdin = stdin_pipes[1];
+ opts->kstdout = stdout_pipes[0];
+ opts->kstderr = stdout_pipes[0];
+ }
+
+ return chpid;
+}
+
+void write_to_kadmin(struct options *opts, char *buf, int len)
+{
+ int ret;
+
+ ret = write(opts->kstdin, buf, len);
+ if (ret != len) {
+ perror("write");
+ fprintf(stderr, "write is short %d:%d\n", len, ret);
+ exit(1);
+ }
+ fsync(opts->kstdin);
+}
+
+char *get_temp_filename(void)
+{
+ char *fname;
+ /* ok - we have to use mktemp here even w/ the race
+ * because kadmin.local barfs if the file exists. The
+ * risk is pretty low and we will try to protect the files
+ * with selinux.
+ *
+ * TODO: generate these files in a safer place than /tmp
+ */
+ fname = strdup("/tmp/ipa-keytab-util-XXXXXX");
+ if (!fname) {
+ fprintf(stderr, "could not allocate temporary file name");
+ exit(1);
+ }
+ fname = mktemp(fname);
+
+ return fname;
+}
+
+char *create_keytab(struct options *opts)
+{
+ char *buf, *fname;
+ int ret;
+
+ fname = get_temp_filename();
+
+ ret = asprintf(&buf, "ktadd -k %s %s\n", fname, opts->princ_name);
+ if (ret == -1) {
+ perror("asprintf");
+ exit(1);
+ }
+
+ write_to_kadmin(opts, buf, ret);
+
+ free(buf);
+
+ write_to_kadmin(opts, "quit\n", sizeof("quit\n"));
+
+ return fname;
+}
+
+void read_keytab(char *fname)
+{
+ FILE *fd;
+ char *data;
+ long flen, ret;
+
+ fd = fopen(fname, "r");
+ if (!fd) {
+ fprintf(stderr, "could not open file %s: ", fname);
+ perror(NULL);
+ exit(1);
+ }
+
+ fseek(fd, 0, SEEK_END);
+ flen = ftell(fd);
+ rewind(fd);
+
+ data = xmalloc(flen);
+
+ /* TODO: handle short reads */
+ ret = fread(data, 1, flen, fd);
+ if (ret != flen) {
+ fprintf(stderr, "short read");
+ exit(1);
+ }
+
+ fclose(fd);
+
+ /* write to stdout */
+ ret = fwrite(data, 1, flen, stdout);
+ if (ret != flen) {
+ fprintf(stderr, "short write");
+ exit(1);
+ }
+}
+
+void remove_keytab(char *filename)
+{
+ unlink(filename);
+}
+
+/* TODO: add significantly better authorization */
+int main(int argc, char **argv)
+{
+ struct options *opts;
+ pid_t chpid;
+ int status, ret;
+ char *fname;
+
+ opts = process_args(argc, argv);
+
+ /* must really be root */
+ setuid(0);
+
+ drop_caps();
+
+
+ chpid = exec_kadmin_local(opts);
+ fname = create_keytab(opts);
+
+ ret = waitpid(-1, &status, 0);
+ if (WEXITSTATUS(status)) {
+ fprintf(stderr, "error creating keytab\n");
+ exit(1);
+ }
+
+ read_keytab(fname);
+ remove_keytab(fname);
+
+ return 0;
+}