From: Steve Dickson <SteveD@redhat.com>
To: andros@netapp.com
Cc: linux-nfs@vger.kernel.org, Weston Andros Adamson <dros@netapp.com>
Subject: Re: [PATCH Version 2 2/3] WIP: Add gsskeyd
Date: Wed, 23 Oct 2013 10:30:15 -0400 [thread overview]
Message-ID: <5267DD77.2090904@RedHat.com> (raw)
In-Reply-To: <1382451757-3032-3-git-send-email-andros@netapp.com>
Hello.
After read this these recent threads about this, we may or may not end up with this
type of daemon, personally I hope we don't... ;-) But if we do...
On 22/10/13 10:22, andros@netapp.com wrote:
> From: Weston Andros Adamson <dros@netapp.com>
>
> this is an experimental daemon that watches for krb credential cache files
> being created and deleted and creates or removes the mapping in the user
> keyring.
>
> this replaces the wrappers for kinit and kdestroy as they are no longer needed -
> users can go ahead using kinit/kdestroy and existing pam modules.
>
> if this is the way we want to go, this should probably end up as a processes
> forked from gssd and not its own daemon.
>
> Signed-off-by: Weston Andros Adamson <dros@netapp.com>
> ---
> configure.ac | 1 +
> utils/Makefile.am | 2 +-
> utils/gsskeyd/gsskeyd.c | 328 ++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 330 insertions(+), 1 deletion(-)
> create mode 100644 utils/gsskeyd/gsskeyd.c
>
> diff --git a/configure.ac b/configure.ac
> index d3ad854..a8e75ac 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -497,6 +497,7 @@ AC_CONFIG_FILES([
> utils/nfsdcltrack/Makefile
> utils/exportfs/Makefile
> utils/gssd/Makefile
> + utils/gsskeyd/Makefile
> utils/idmapd/Makefile
> utils/mount/Makefile
> utils/mountd/Makefile
> diff --git a/utils/Makefile.am b/utils/Makefile.am
> index b892dc8..943ae2d 100644
> --- a/utils/Makefile.am
> +++ b/utils/Makefile.am
> @@ -14,7 +14,7 @@ OPTDIRS += blkmapd
> endif
>
> if CONFIG_GSS
> -OPTDIRS += gssd
> +OPTDIRS += gssd gsskeyd
> endif
>
> if CONFIG_MOUNT
> diff --git a/utils/gsskeyd/gsskeyd.c b/utils/gsskeyd/gsskeyd.c
> new file mode 100644
> index 0000000..6d598fa
> --- /dev/null
> +++ b/utils/gsskeyd/gsskeyd.c
> @@ -0,0 +1,328 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <limits.h>
> +#include <assert.h>
> +#include <keyutils.h>
> +#include <err.h>
> +#include <errno.h>
> +#include <string.h>
> +
> +#include <sys/inotify.h>
> +#include <sys/errno.h>
> +#include <sys/select.h>
> +#include <sys/param.h>
> +#include <sys/time.h>
> +#include <sys/types.h>
> +#include <sys/wait.h>
> +#include <sys/queue.h>
> +#include <sys/uio.h>
> +#include <unistd.h>
> +
> +#define MAX_EVENT_SIZE (sizeof(struct inotify_event) + NAME_MAX + 1)
> +
> +//#define DEBUG_TRACE
> +
> +#ifdef DEBUG_TRACE
> +#define TRACE(X...) do { fprintf(stderr, "_trace_: " X); } while (0)
> +#else
> +#define TRACE(X...)
> +#endif
Please do not make debugging a compile decision. Go ahead and
use a '-d' or '-vvvv' (which each 'v' add more logging) flags to
make it a run time decision... Having to recompile to debug is
something that never made much sense to me...
Secondly, you please use the existing xlog() interface to do your
error/warning/debugging logging... Having all logging going through
on interface is a good thing... IMHO...
steved.
> +
> +/* .25 second timeouts to select */
> +#define SELECT_INTERVAL_TV { 0, 250000 }
> +
> +/* .5 seconds to collect list of unique file names that had events */
> +#define COLLECT_INTERVAL_TV { 0, 500000 }
> +
> +struct watchdir {
> + char dir[MAXPATHLEN];
> + int wd;
> + LIST_ENTRY(watchdir) entry;
> +};
> +
> +LIST_HEAD(watchdir_list, watchdir);
> +
> +struct update {
> + char dir[MAXPATHLEN];
> + char name[MAXPATHLEN];
> + int is_remove;
> + LIST_ENTRY(update) entry;
> +};
> +
> +LIST_HEAD(update_list, update);
> +
> +struct updates {
> + struct update_list list;
> + struct timeval first;
> +};
> +
> +void
> +watchdir_add(struct watchdir_list *watchdirs, int notify, char *dir)
> +{
> + struct watchdir *w;
> +
> + w = calloc(1, sizeof(struct watchdir));
> + assert(w != NULL);
> +
> + strncpy(w->dir, dir, MAXPATHLEN);
> +
> + w->wd = inotify_add_watch(notify, dir,
> + IN_CREATE | IN_DELETE | IN_MOVED_FROM | IN_MOVED_TO );
> + //| IN_MODIFY
> +
> + if (w->wd < 0)
> + perror("inotify_add_watch");
> +
> + LIST_INSERT_HEAD(watchdirs, w, entry);
> +
> + TRACE("WATCH(%d): %s\n", w->wd, w->dir);
> +}
> +
> +/*
> + * XXX maybe use hash when there is more than one watchdir?
> + */
> +struct watchdir *
> +watchdir_lookup(struct watchdir_list *watchdirs, int wd)
> +{
> + struct watchdir *w;
> +
> + LIST_FOREACH(w, watchdirs, entry) {
> + if (wd == w->wd)
> + return w;
> + }
> +
> + return NULL;
> +}
> +
> +static void
> +update_set_type(struct update *u, struct inotify_event *e)
> +{
> + if (e->mask & (IN_DELETE | IN_MOVED_FROM))
> + u->is_remove = 1;
> + else
> + u->is_remove = 0;
> +}
> +
> +void
> +updates_add(struct updates *updates, struct watchdir_list *watchdirs, struct inotify_event *e)
> +{
> + struct update *u;
> + struct watchdir *w;
> +
> +
> + w = watchdir_lookup(watchdirs, e->wd);
> + assert(w != NULL);
> +
> + TRACE("updates_add: %s/%s\n", w->dir, e->name);
> +
> + LIST_FOREACH(u, &updates->list, entry) {
> + if (strncmp(w->dir, u->dir, MAXPATHLEN) == 0 &&
> + strncmp(e->name, u->name, MAXPATHLEN) == 0) {
> + update_set_type(u, e);
> + return;
> + }
> + }
> +
> + u = calloc(1, sizeof(struct update));
> + strncpy(u->dir, w->dir, MAXPATHLEN);
> + strncpy(u->name, e->name, MAXPATHLEN);
> + update_set_type(u, e);
> +
> + LIST_INSERT_HEAD(&updates->list, u, entry);
> +
> + if (!timerisset(&updates->first)) {
> + if (gettimeofday(&updates->first, NULL) < 0)
> + perror("gettimeofday");
> + }
> +}
> +
> +void
> +print_event_mask(FILE *fp, uint32_t mask)
> +{
> +#define _print_if_found(X, S) do { \
> + if (mask & (X)) { \
> + fprintf(fp, S); \
> + } \
> + } while(0)
> +
> + _print_if_found(IN_ACCESS, "access");
> + _print_if_found(IN_ATTRIB, "attrib");
> + _print_if_found(IN_CLOSE_WRITE, "close write");
> + _print_if_found(IN_CLOSE_NOWRITE, "close nowrite");
> + _print_if_found(IN_CREATE, "create");
> + _print_if_found(IN_DELETE, "delete");
> + _print_if_found(IN_DELETE_SELF, "delete self");
> + _print_if_found(IN_MODIFY, "modify");
> + _print_if_found(IN_MOVE_SELF, "move self");
> + _print_if_found(IN_MOVED_FROM, "moved from");
> + _print_if_found(IN_MOVED_TO, "moved to");
> + _print_if_found(IN_OPEN, "open");
> +}
> +
> +static int
> +manage_gss_ctx_keyring_mapping(struct update *u)
> +{
> + char buf[MAXPATHLEN];
> + int status;
> + uid_t uid;
> + pid_t pid;
> + key_serial_t key;
> + long res;
> +
> + snprintf(buf, MAXPATHLEN, "%s/%s", u->dir, u->name);
> +
> + if (sscanf(u->name, "krb5cc_%u", &uid) <= 0)
> + perror("parsing krb5cc uid");
> +
> + if ((pid = fork()) < 0)
> + perror("fork");
> +
> + if (pid == 0) {
> + if (setuid(uid) < 0)
> + perror("setuid");
> +
> + if (u->is_remove) {
> + fprintf(stderr, "remove gss ctx mapping for uid %u\n",
> + uid);
> + key = request_key("gss-ctx", "_nfstgt_", NULL,
> + KEY_SPEC_USER_KEYRING);
> + if (key > 0) {
> + res = keyctl_unlink(key, KEY_SPEC_USER_KEYRING);
> + if (res < 0)
> + warn("keyctl_unlink failed");
> + } else
> + warn("request_key failed");
> + } else {
> + fprintf(stderr, "add gss ctx mapping for uid=%u\n",
> + uid);
> + snprintf(buf, MAXPATHLEN, "FILE:%s/%s",
> + u->dir, u->name);
> + key = add_key("gss-ctx", "_nfstgt_", buf,
> + MAXPATHLEN, KEY_SPEC_USER_KEYRING);
> +
> + if (key < 0)
> + warn("add_key failed");
> + }
> +
> + exit(0);
> + } else {
> + waitpid(pid, &status, 0);
> +
> + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
> + return WEXITSTATUS(status);
> + }
> + }
> +
> + return 0;
> +}
> +
> +void
> +parse_events(int notify, struct watchdir_list *watchdirs, struct updates *updates)
> +{
> + ssize_t nread, pos;
> + unsigned char buf[MAX_EVENT_SIZE * 100];
> + struct inotify_event *e;
> +
> + for (;;) {
> + nread = read(notify, buf, sizeof(buf));
> +
> + if (nread <= 0) {
> + TRACE("read returns %d, errno %u\n", nread, errno);
> + break;
> + }
> +
> + TRACE("Read %d bytes\n", nread);
> +
> + pos = 0;
> + while (pos < nread) {
> + assert((nread - pos) >=
> + (ssize_t)sizeof(struct inotify_event));
> + e = (struct inotify_event *)(buf + pos);
> + pos += sizeof(struct inotify_event) + e->len;
> +
> +#ifdef DEBUG_TRACE
> + TRACE("EVENT on %s: ", e->name);
> + print_event_mask(stderr, e->mask);
> + fprintf(stderr, "\n");
> +#endif
> +
> + if (strlen(e->name) >= strlen("krb5cc_") &&
> + strncmp("krb5cc_", e->name, strlen("krb5cc_")) != 0)
> + TRACE("skip file: %s\n", e->name);
> + else
> + updates_add(updates, watchdirs, e);
> + }
> + assert(pos == nread);
> + }
> +}
> +
> +void
> +handle_events(struct updates *updates)
> +{
> + struct update *u;
> + struct timeval now, diff, collection_interval = COLLECT_INTERVAL_TV;
> +
> + if (!timerisset(&updates->first))
> + return;
> +
> + if (gettimeofday(&now, NULL) < 0)
> + perror("gettimeofday");
> +
> + timersub(&now, &updates->first, &diff);
> +
> + if (!(diff.tv_sec >= collection_interval.tv_sec &&
> + diff.tv_usec >= collection_interval.tv_usec)) {
> + TRACE("it's been %u s %u ms - waiting longer...\n",
> + diff.tv_sec, diff.tv_usec);
> + return;
> + }
> +
> + while (!LIST_EMPTY(&updates->list)) {
> + u = updates->list.lh_first;
> +
> + TRACE("handle krb5 cc file: %s\n", u->name);
> + manage_gss_ctx_keyring_mapping(u);
> + LIST_REMOVE(u, entry);
> + }
> +
> + timerclear(&updates->first);
> +}
> +
> +
> +int
> +main(int argc, char **argv)
> +{
> + fd_set readfds;
> + int notify;
> + int res;
> + struct timeval timeo, select_interval = SELECT_INTERVAL_TV;
> + struct watchdir_list watchdirs;
> + struct updates updates;
> +
> + LIST_INIT(&watchdirs);
> +
> + notify = inotify_init1(IN_NONBLOCK);
> + if (notify < 0)
> + perror("inotify_init1");
> +
> + watchdir_add(&watchdirs, notify, "/tmp");
> +
> + LIST_INIT(&updates.list);
> + timerclear(&updates.first);
> +
> + for (;;) {
> + FD_ZERO(&readfds);
> + FD_SET(notify, &readfds);
> + memcpy(&timeo, &select_interval, sizeof(struct timeval));
> +
> + res = select(notify + 1, &readfds, NULL, NULL, &timeo);
> +
> + if (res < 0)
> + perror("error calling select");
> +
> + if (FD_ISSET(notify, &readfds))
> + parse_events(notify, &watchdirs, &updates);
> +
> + handle_events(&updates);
> + }
> +}
>
next prev parent reply other threads:[~2013-10-23 14:29 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-10-22 14:22 [PATCH Version 2 0/3] GSSD: Use gss-ctx keys and gsskeyd to sync Kerberos credentials and kernel gss_contexts andros
2013-10-22 14:22 ` [PATCH Version 2 1/3] GSSD add cc_name to upcall andros
2013-10-22 15:07 ` Simo Sorce
2013-10-22 14:22 ` [PATCH Version 2 2/3] WIP: Add gsskeyd andros
2013-10-23 14:30 ` Steve Dickson [this message]
2013-10-23 14:40 ` Weston Andros Adamson
2013-10-23 15:02 ` Adamson, Andy
2013-10-22 14:22 ` [PATCH Version 2 3/3] ANDROS: update gsskeyd to use new /run/user/UID/krb5cc/tgt cache file andros
2013-10-22 15:02 ` [PATCH Version 2 0/3] GSSD: Use gss-ctx keys and gsskeyd to sync Kerberos credentials and kernel gss_contexts Simo Sorce
2013-10-22 15:32 ` Adamson, Andy
2013-10-22 16:09 ` Simo Sorce
2013-10-22 17:00 ` Adamson, Andy
2013-10-22 17:25 ` Simo Sorce
2013-11-20 20:35 ` Adamson, Andy
2013-11-20 20:49 ` Simo Sorce
2013-11-20 21:21 ` Adamson, Andy
2013-11-20 21:24 ` Adamson, Andy
2013-11-22 19:09 ` Simo Sorce
2013-11-22 20:44 ` Adamson, Andy
2013-11-21 13:37 ` Steve Dickson
2013-11-22 19:11 ` Simo Sorce
2013-11-22 21:28 ` Trond Myklebust
2013-11-22 21:39 ` Simo Sorce
2013-10-22 15:46 ` Weston Andros Adamson
2013-10-22 16:11 ` Simo Sorce
2013-10-22 16:14 ` Weston Andros Adamson
2013-10-22 16:39 ` Adamson, Andy
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=5267DD77.2090904@RedHat.com \
--to=steved@redhat.com \
--cc=andros@netapp.com \
--cc=dros@netapp.com \
--cc=linux-nfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).