| |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <errno.h> |
| |
| #include <pwd.h> |
| #include <grp.h> |
| #include <keyutils.h> |
| #include <nfsidmap.h> |
| |
| #include <unistd.h> |
| #include "xlog.h" |
| #include "conffile.h" |
| |
| int verbose = 0; |
| char *usage="Usage: %s [-v] [-c || [-u|-g|-r key] || [-t timeout] key desc]"; |
| |
| #define MAX_ID_LEN 11 |
| #define IDMAP_NAMESZ 128 |
| #define USER 1 |
| #define GROUP 0 |
| |
| #define PROCKEYS "/proc/keys" |
| #ifndef DEFAULT_KEYRING |
| #define DEFAULT_KEYRING "id_resolver" |
| #endif |
| |
| #ifndef PATH_IDMAPDCONF |
| #define PATH_IDMAPDCONF "/etc/idmapd.conf" |
| #endif |
| |
| static int keyring_clear(char *keyring); |
| |
| #define UIDKEYS 0x1 |
| #define GIDKEYS 0x2 |
| |
| /* |
| * Find either a user or group id based on the name@domain string |
| */ |
| int id_lookup(char *name_at_domain, key_serial_t key, int type) |
| { |
| char id[MAX_ID_LEN]; |
| uid_t uid = 0; |
| gid_t gid = 0; |
| int rc; |
| |
| if (type == USER) { |
| rc = nfs4_owner_to_uid(name_at_domain, &uid); |
| sprintf(id, "%u", uid); |
| } else { |
| rc = nfs4_group_owner_to_gid(name_at_domain, &gid); |
| sprintf(id, "%u", gid); |
| } |
| if (rc < 0) |
| xlog_errno(rc, "id_lookup: %s: failed: %m", |
| (type == USER ? "nfs4_owner_to_uid" : "nfs4_group_owner_to_gid")); |
| |
| if (rc == 0) { |
| rc = keyctl_instantiate(key, id, strlen(id) + 1, 0); |
| if (rc < 0) { |
| switch(rc) { |
| case -EDQUOT: |
| case -ENFILE: |
| case -ENOMEM: |
| /* |
| * The keyring is full. Clear the keyring and try again |
| */ |
| rc = keyring_clear(DEFAULT_KEYRING); |
| if (rc == 0) |
| rc = keyctl_instantiate(key, id, strlen(id) + 1, 0); |
| break; |
| default: |
| break; |
| } |
| } |
| if (rc < 0) |
| xlog_err("id_lookup: keyctl_instantiate failed: %m"); |
| } |
| |
| return rc; |
| } |
| |
| /* |
| * Find the name@domain string from either a user or group id |
| */ |
| int name_lookup(char *id, key_serial_t key, int type) |
| { |
| char name[IDMAP_NAMESZ]; |
| char domain[NFS4_MAX_DOMAIN_LEN]; |
| uid_t uid; |
| gid_t gid; |
| int rc; |
| |
| rc = nfs4_get_default_domain(NULL, domain, NFS4_MAX_DOMAIN_LEN); |
| if (rc != 0) { |
| xlog_errno(rc, |
| "name_lookup: nfs4_get_default_domain failed: %m"); |
| rc = -1; |
| goto out; |
| } |
| |
| if (type == USER) { |
| uid = atoi(id); |
| rc = nfs4_uid_to_name(uid, domain, name, IDMAP_NAMESZ); |
| } else { |
| gid = atoi(id); |
| rc = nfs4_gid_to_name(gid, domain, name, IDMAP_NAMESZ); |
| } |
| if (rc < 0) |
| xlog_errno(rc, "name_lookup: %s: failed: %m", |
| (type == USER ? "nfs4_uid_to_name" : "nfs4_gid_to_name")); |
| |
| if (rc == 0) { |
| rc = keyctl_instantiate(key, &name, strlen(name), 0); |
| if (rc < 0) |
| xlog_err("name_lookup: keyctl_instantiate failed: %m"); |
| } |
| out: |
| return rc; |
| } |
| /* |
| * Clear all the keys on the given keyring |
| */ |
| static int keyring_clear(char *keyring) |
| { |
| FILE *fp; |
| char buf[BUFSIZ]; |
| key_serial_t key; |
| |
| if (keyring == NULL) |
| keyring = DEFAULT_KEYRING; |
| |
| if ((fp = fopen(PROCKEYS, "r")) == NULL) { |
| xlog_err("fopen(%s) failed: %m", PROCKEYS); |
| return 1; |
| } |
| |
| while(fgets(buf, BUFSIZ, fp) != NULL) { |
| if (strstr(buf, "keyring") == NULL) |
| continue; |
| if (strstr(buf, keyring) == NULL) |
| continue; |
| if (verbose) { |
| *(strchr(buf, '\n')) = '\0'; |
| xlog_warn("clearing '%s'", buf); |
| } |
| /* |
| * The key is the first arugment in the string |
| */ |
| *(strchr(buf, ' ')) = '\0'; |
| sscanf(buf, "%x", &key); |
| if (keyctl_clear(key) < 0) { |
| xlog_err("keyctl_clear(0x%x) failed: %m", key); |
| fclose(fp); |
| return 1; |
| } |
| fclose(fp); |
| return 0; |
| } |
| xlog_err("'%s' keyring was not found.", keyring); |
| fclose(fp); |
| return 1; |
| } |
| /* |
| * Revoke a key |
| */ |
| static int key_invalidate(char *keystr, int keymask) |
| { |
| FILE *fp; |
| char buf[BUFSIZ], *ptr; |
| key_serial_t key; |
| int mask; |
| |
| xlog_syslog(0); |
| |
| if ((fp = fopen(PROCKEYS, "r")) == NULL) { |
| xlog_err("fopen(%s) failed: %m", PROCKEYS); |
| return 1; |
| } |
| |
| while(fgets(buf, BUFSIZ, fp) != NULL) { |
| if (strstr(buf, "keyring") != NULL) |
| continue; |
| |
| mask = 0; |
| if ((ptr = strstr(buf, "uid:")) != NULL) |
| mask = UIDKEYS; |
| else if ((ptr = strstr(buf, "gid:")) != NULL) |
| mask = GIDKEYS; |
| else |
| continue; |
| |
| if ((keymask & mask) == 0) |
| continue; |
| |
| if (strncmp(ptr+4, keystr, strlen(keystr)) != 0) |
| continue; |
| |
| if (verbose) { |
| *(strchr(buf, '\n')) = '\0'; |
| xlog_warn("invalidating '%s'", buf); |
| } |
| /* |
| * The key is the first arugment in the string |
| */ |
| *(strchr(buf, ' ')) = '\0'; |
| sscanf(buf, "%x", &key); |
| |
| if (keyctl_invalidate(key) < 0) { |
| xlog_err("keyctl_invalidate(0x%x) failed: %m", key); |
| fclose(fp); |
| return 1; |
| } |
| |
| keymask &= ~mask; |
| if (keymask == 0) { |
| fclose(fp); |
| return 0; |
| } |
| } |
| xlog_err("'%s' key was not found.", keystr); |
| fclose(fp); |
| return 1; |
| } |
| |
| int main(int argc, char **argv) |
| { |
| char *arg; |
| char *value; |
| char *type; |
| int rc = 1, opt; |
| int timeout = 600; |
| key_serial_t key; |
| char *progname, *keystr = NULL; |
| int clearing = 0, keymask = 0; |
| |
| /* Set the basename */ |
| if ((progname = strrchr(argv[0], '/')) != NULL) |
| progname++; |
| else |
| progname = argv[0]; |
| |
| xlog_open(progname); |
| |
| while ((opt = getopt(argc, argv, "u:g:r:ct:v")) != -1) { |
| switch (opt) { |
| case 'u': |
| keymask = UIDKEYS; |
| keystr = strdup(optarg); |
| break; |
| case 'g': |
| keymask = GIDKEYS; |
| keystr = strdup(optarg); |
| break; |
| case 'r': |
| keymask = GIDKEYS|UIDKEYS; |
| keystr = strdup(optarg); |
| break; |
| case 'c': |
| clearing++; |
| break; |
| case 'v': |
| verbose++; |
| break; |
| case 't': |
| timeout = atoi(optarg); |
| break; |
| default: |
| xlog_warn(usage, progname); |
| break; |
| } |
| } |
| |
| if ((rc = nfs4_init_name_mapping(PATH_IDMAPDCONF))) { |
| xlog_errno(rc, "Unable to create name to user id mappings."); |
| return 1; |
| } |
| if (!verbose) |
| verbose = conf_get_num("General", "Verbosity", 0); |
| |
| if (keystr) { |
| rc = key_invalidate(keystr, keymask); |
| return rc; |
| } |
| if (clearing) { |
| xlog_syslog(0); |
| rc = keyring_clear(DEFAULT_KEYRING); |
| return rc; |
| } |
| |
| xlog_stderr(0); |
| if ((argc - optind) != 2) { |
| xlog_err("Bad arg count. Check /etc/request-key.conf"); |
| xlog_warn(usage, progname); |
| return 1; |
| } |
| |
| if (verbose) |
| nfs4_set_debug(verbose, NULL); |
| |
| key = strtol(argv[optind++], NULL, 10); |
| |
| arg = strdup(argv[optind]); |
| if (arg == NULL) { |
| xlog_err("strdup failed: %m"); |
| return 1; |
| } |
| type = strtok(arg, ":"); |
| value = strtok(NULL, ":"); |
| |
| if (verbose) { |
| xlog_warn("key: 0x%lx type: %s value: %s timeout %ld", |
| key, type, value, timeout); |
| } |
| |
| if (strcmp(type, "uid") == 0) |
| rc = id_lookup(value, key, USER); |
| else if (strcmp(type, "gid") == 0) |
| rc = id_lookup(value, key, GROUP); |
| else if (strcmp(type, "user") == 0) |
| rc = name_lookup(value, key, USER); |
| else if (strcmp(type, "group") == 0) |
| rc = name_lookup(value, key, GROUP); |
| |
| /* Set timeout to 10 (600 seconds) minutes */ |
| if (rc == 0) |
| keyctl_set_timeout(key, timeout); |
| |
| free(arg); |
| return rc; |
| } |