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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.