static int lookup_reauthorize_secret (const char *user, char **secret) { char *buffer = NULL; char *name = NULL; key_serial_t key; int ret; if (asprintf (&name, "reauthorize/secret/%s", user) < 0) { message ("failed to allocate secret name"); ret = -ENOMEM; goto out; } key = keyctl_search (KEY_SPEC_SESSION_KEYRING, "user", name, 0); if (key < 0) { /* missing key is not an error */ if (errno == ENOKEY) { ret = 0; *secret = NULL; goto out; } ret = -errno; message ("failed to lookup reauthorize secret key: %s: %m", name); goto out; } if (keyctl_describe_alloc (key, &buffer) < 0) { ret = -errno; message ("couldn't describe reauthorize secret key: %s: %m", name); goto out; } if (strncmp (buffer, "user;0;0;001f0000;", 18) != 0) { ret = -EPERM; message ("kernel reauthorize secret key has invalid permissions: %s: %s", name, buffer); goto out; } /* null-terminates */ if (keyctl_read_alloc (key, (void **)secret) < 0) { ret = -errno; message ("couldn't read kernel reauthorize secret key: %s: %m", name); goto out; } ret = 0; out: free (buffer); free (name); return ret; }
static void list_key(key_serial_t key) { char *buffer, *c; int rc; rc = keyctl_describe_alloc(key, &buffer); if (rc < 0) { switch (errno) { case EKEYEXPIRED: printf("Expired key not displayed\n"); break; default: xlog_err("Failed to describe key: %m"); } return; } c = strrchr(buffer, ';'); if (!c) { xlog_err("Unparsable key not displayed\n"); goto out_free; } printf(" %s\n", ++c); out_free: free(buffer); }
int main(int argc, char *argv[]) { int ktlen, qtlen, ret; char *keyend, *p; char *callout_info = NULL; char *buf = NULL, *name; openlog(prog, 0, LOG_DAEMON); while ((ret = getopt_long(argc, argv, "vD", long_options, NULL)) != -1) { switch (ret) { case 'D': debug_mode = 1; continue; case 'V': printf("version: %s from %s (%s)\n", DNS_PARSE_VERSION, keyutils_version_string, keyutils_build_string); exit(0); case 'v': verbose++; continue; default: if (!isatty(2)) syslog(LOG_ERR, "unknown option: %c", ret); usage(); } } argc -= optind; argv += optind; if (!debug_mode) { if (argc != 1) usage(); /* get the key ID */ errno = 0; key = strtol(*argv, NULL, 10); if (errno != 0) error("Invalid key ID format: %m"); /* get the key description (of the form "x;x;x;x;<query_type>:<name>") */ if (!buf) { ret = keyctl_describe_alloc(key, &buf); if (ret == -1) error("keyctl_describe_alloc failed: %m"); } /* get the callout_info (which can supply options) */ if (!callout_info) { ret = keyctl_read_alloc(KEY_SPEC_REQKEY_AUTH_KEY, (void **)&callout_info); if (ret == -1) error("Invalid key callout_info read: %m"); } } else { if (argc != 2) usage(); ret = asprintf(&buf, "%s;-1;-1;0;%s", key_type, argv[0]); if (ret < 0) error("Error %m"); callout_info = argv[1]; } ret = 1; info("Key description: '%s'", buf); info("Callout info: '%s'", callout_info); p = strchr(buf, ';'); if (!p) error("Badly formatted key description '%s'", buf); ktlen = p - buf; /* make sure it's the type we are expecting */ if (ktlen != sizeof(key_type) - 1 || memcmp(buf, key_type, ktlen) != 0) error("Key type is not supported: '%*.*s'", ktlen, ktlen, buf); keyend = buf + ktlen + 1; /* the actual key description follows the last semicolon */ keyend = rindex(keyend, ';'); if (!keyend) error("Invalid key description: %s", buf); keyend++; name = index(keyend, ':'); if (!name) dns_query_a_or_aaaa(key, keyend, callout_info); qtlen = name - keyend; name++; if ((qtlen == sizeof(a_query_type) - 1 && memcmp(keyend, a_query_type, sizeof(a_query_type) - 1) == 0) || (qtlen == sizeof(aaaa_query_type) - 1 && memcmp(keyend, aaaa_query_type, sizeof(aaaa_query_type) - 1) == 0) ) { info("Do DNS query of A/AAAA type for:'%s' mask:'%s'", name, callout_info); dns_query_a_or_aaaa(key, name, callout_info); } if (qtlen == sizeof(afsdb_query_type) - 1 && memcmp(keyend, afsdb_query_type, sizeof(afsdb_query_type) - 1) == 0 ) { info("Do DNS query of AFSDB type for:'%s' mask:'%s'", name, callout_info); dns_query_afsdb(key, name, callout_info); } error("Query type: \"%*.*s\" is not supported", qtlen, qtlen, keyend); }
int main(const int argc, char *const argv[]) { int c; long rc; key_serial_t key = 0; char *buf; unsigned int timeout = 600; /* default idmap cache timeout */ openlog(prog, 0, LOG_DAEMON); while ((c = getopt_long(argc, argv, "ht:v", long_options, NULL)) != -1) { switch (c) { case 'h': rc = 0; usage(); goto out; case 't': rc = str_to_uint(optarg, &timeout); if (rc) { syslog(LOG_ERR, "bad timeout value %s: %s", optarg, strerror(rc)); goto out; } break; case 'v': rc = 0; printf("version: %s\n", VERSION); goto out; default: rc = EINVAL; syslog(LOG_ERR, "unknown option: %c", c); goto out; } } rc = 1; /* is there a key? */ if (argc <= optind) { usage(); goto out; } /* get key and keyring values */ errno = 0; key = strtol(argv[optind], NULL, 10); if (errno != 0) { key = 0; syslog(LOG_ERR, "Invalid key format: %s", strerror(errno)); goto out; } if (init_plugin(&plugin_handle)) { plugin_handle = NULL; syslog(LOG_ERR, "Unable to initialize ID mapping plugin: %s", plugin_errmsg); goto out; } /* set timeout on key */ rc = keyctl_set_timeout(key, timeout); if (rc == -1) { syslog(LOG_ERR, "unable to set key timeout: %s", strerror(errno)); goto out_exit_plugin; } rc = keyctl_describe_alloc(key, &buf); if (rc == -1) { syslog(LOG_ERR, "keyctl_describe_alloc failed: %s", strerror(errno)); goto out_exit_plugin; } syslog(LOG_DEBUG, "key description: %s", buf); rc = cifs_idmap(key, buf); out_exit_plugin: exit_plugin(plugin_handle); out: return rc; }
int main(int argc, char *argv[]) { key_serial_t key; char *ktype, *kdesc, *buf, *callout_info; int ret, ntype, dpos, n, fd; signal(SIGSEGV, oops); signal(SIGBUS, oops); signal(SIGPIPE, SIG_IGN); for (;;) { if (argc > 1 && strcmp(argv[1], "-d") == 0) { xdebug++; argv++; argc--; } else if (argc > 1 && strcmp(argv[1], "-n") == 0) { xnolog = 1; argv++; argc--; } else break; } if (argc != 8 && argc != 9) error("Unexpected argument count: %d\n", argc); fd = open("/dev/null", O_RDWR); if (fd < 0) error("open"); if (fd > 2) { close(fd); } else if (fd < 2) { ret = dup(fd); if (ret < 0) error("dup failed: %m\n"); if (ret < 2 && dup(fd) < 0) error("dup failed: %m\n"); } xkey = argv[2]; xuid = argv[3]; xgid = argv[4]; xthread_keyring = argv[5]; xprocess_keyring = argv[6]; xsession_keyring = argv[7]; key = atoi(xkey); /* assume authority over the key * - older kernel doesn't support this function */ ret = keyctl_assume_authority(key); if (ret < 0 && !(argc == 9 || errno == EOPNOTSUPP)) error("Failed to assume authority over key %d (%m)\n", key); /* ask the kernel to describe the key to us */ if (xdebug < 2) { ret = keyctl_describe_alloc(key, &buf); if (ret < 0) goto inaccessible; } else { buf = strdup("user;0;0;1f0000;debug:1234"); } /* extract the type and description from the key */ debug("Key descriptor: \"%s\"\n", buf); ntype = -1; dpos = -1; n = sscanf(buf, "%*[^;]%n;%*d;%*d;%x;%n", &ntype, &n, &dpos); if (n != 1) error("Failed to parse key description\n"); ktype = buf; ktype[ntype] = 0; kdesc = buf + dpos; debug("Key type: %s\n", ktype); debug("Key desc: %s\n", kdesc); /* get hold of the callout info */ callout_info = argv[8]; if (!callout_info) { void *tmp; if (keyctl_read_alloc(KEY_SPEC_REQKEY_AUTH_KEY, &tmp) < 0) error("Failed to retrieve callout info (%m)\n"); callout_info = tmp; } debug("CALLOUT: '%s'\n", callout_info); /* determine the action to perform */ lookup_action(argv[1], /* op */ key, /* ID of key under construction */ ktype, /* key type */ kdesc, /* key description */ callout_info /* call out information */ ); inaccessible: error("Key %d is inaccessible (%m)\n", key); } /* end main() */
int main(const int argc, char *const argv[]) { struct cifs_spnego_msg *keydata = NULL; DATA_BLOB secblob = data_blob_null; DATA_BLOB sess_key = data_blob_null; key_serial_t key = 0; size_t datalen; unsigned int have; long rc = 1; int c, try_dns = 0, legacy_uid = 0; char *buf, *ccdir = NULL, *ccname = NULL, *best_cache = NULL; char hostbuf[NI_MAXHOST], *host; struct decoded_args arg; const char *oid; uid_t uid; char *keytab_name = CIFS_DEFAULT_KRB5_KEYTAB; time_t best_time = 0; hostbuf[0] = '\0'; memset(&arg, 0, sizeof(arg)); openlog(prog, 0, LOG_DAEMON); while ((c = getopt_long(argc, argv, "ck:ltv", long_options, NULL)) != -1) { switch (c) { case 'c': /* legacy option -- skip it */ break; case 't': try_dns++; break; case 'k': if (setenv("KRB5_CONFIG", optarg, 1) != 0) { syslog(LOG_ERR, "unable to set $KRB5_CONFIG: %d", errno); goto out; } break; case 'l': legacy_uid++; break; case 'v': printf("version: %s\n", VERSION); goto out; default: syslog(LOG_ERR, "unknown option: %c", c); goto out; } } /* is there a key? */ if (argc <= optind) { usage(); goto out; } /* get key and keyring values */ errno = 0; key = strtol(argv[optind], NULL, 10); if (errno != 0) { key = 0; syslog(LOG_ERR, "Invalid key format: %s", strerror(errno)); goto out; } rc = keyctl_describe_alloc(key, &buf); if (rc == -1) { syslog(LOG_ERR, "keyctl_describe_alloc failed: %s", strerror(errno)); rc = 1; goto out; } syslog(LOG_DEBUG, "key description: %s", buf); if ((strncmp(buf, "cifs.resolver", sizeof("cifs.resolver") - 1) == 0) || (strncmp(buf, "dns_resolver", sizeof("dns_resolver") - 1) == 0)) { rc = cifs_resolver(key, buf); goto out; } have = decode_key_description(buf, &arg); SAFE_FREE(buf); if ((have & DKD_MUSTHAVE_SET) != DKD_MUSTHAVE_SET) { syslog(LOG_ERR, "unable to get necessary params from key " "description (0x%x)", have); rc = 1; goto out; } if (arg.ver > CIFS_SPNEGO_UPCALL_VERSION) { syslog(LOG_ERR, "incompatible kernel upcall version: 0x%x", arg.ver); rc = 1; goto out; } if (strlen(arg.hostname) >= NI_MAXHOST) { syslog(LOG_ERR, "hostname provided by kernel is too long"); rc = 1; goto out; } if (!legacy_uid && (have & DKD_HAVE_CREDUID)) uid = arg.creduid; else if (have & DKD_HAVE_UID) uid = arg.uid; else { /* no uid= or creduid= parm -- something is wrong */ syslog(LOG_ERR, "No uid= or creduid= parm specified"); rc = 1; goto out; } rc = setuid(uid); if (rc == -1) { syslog(LOG_ERR, "setuid: %s", strerror(errno)); goto out; } ccdir = resolve_krb5_dir(CIFS_DEFAULT_KRB5_USER_DIR, uid); if (ccdir != NULL) find_krb5_cc(ccdir, uid, &best_cache, &best_time); ccname = find_krb5_cc(CIFS_DEFAULT_KRB5_DIR, uid, &best_cache, &best_time); SAFE_FREE(ccdir); /* Couldn't find credcache? Try to use keytab */ if (ccname == NULL && arg.username != NULL) ccname = init_cc_from_keytab(keytab_name, arg.username); host = arg.hostname; // do mech specific authorization switch (arg.sec) { case MS_KRB5: case KRB5: /* * Andrew Bartlett's suggested scheme for picking a principal * name, based on a supplied hostname. * * INPUT: fooo * TRY in order: * cifs/fooo@REALM * cifs/fooo.<guessed domain ?>@REALM * * INPUT: bar.example.com * TRY only: * cifs/bar.example.com@REALM */ if (arg.sec == MS_KRB5) oid = OID_KERBEROS5_OLD; else oid = OID_KERBEROS5; retry_new_hostname: lowercase_string(host); rc = handle_krb5_mech(oid, host, &secblob, &sess_key, ccname); if (!rc) break; /* * If hostname has a '.', assume it's a FQDN, otherwise we * want to guess the domainname. */ if (!strchr(host, '.')) { struct addrinfo hints; struct addrinfo *ai; char *domainname; char fqdn[NI_MAXHOST]; /* * use getaddrinfo() to resolve the hostname of the * server and set ai_canonname. */ memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_flags = AI_CANONNAME; rc = getaddrinfo(host, NULL, &hints, &ai); if (rc) { syslog(LOG_ERR, "Unable to resolve host address: %s [%s]", host, gai_strerror(rc)); break; } /* scan forward to first '.' in ai_canonnname */ domainname = strchr(ai->ai_canonname, '.'); if (!domainname) { rc = -EINVAL; freeaddrinfo(ai); break; } lowercase_string(domainname); rc = snprintf(fqdn, sizeof(fqdn), "%s%s", host, domainname); freeaddrinfo(ai); if (rc < 0 || (size_t)rc >= sizeof(fqdn)) { syslog(LOG_ERR, "Problem setting hostname in string: %ld", rc); rc = -EINVAL; break; } rc = handle_krb5_mech(oid, fqdn, &secblob, &sess_key, ccname); if (!rc) break; } if (!try_dns || !(have & DKD_HAVE_IP)) break; rc = ip_to_fqdn(arg.ip, hostbuf, sizeof(hostbuf)); if (rc) break; try_dns = 0; host = hostbuf; goto retry_new_hostname; default: syslog(LOG_ERR, "sectype: %d is not implemented", arg.sec); rc = 1; break; } if (rc) { syslog(LOG_DEBUG, "Unable to obtain service ticket"); goto out; } /* pack SecurityBlob and SessionKey into downcall packet */ datalen = sizeof(struct cifs_spnego_msg) + secblob.length + sess_key.length; keydata = (struct cifs_spnego_msg *)calloc(sizeof(char), datalen); if (!keydata) { rc = 1; goto out; } keydata->version = arg.ver; keydata->flags = 0; keydata->sesskey_len = sess_key.length; keydata->secblob_len = secblob.length; memcpy(&(keydata->data), sess_key.data, sess_key.length); memcpy(&(keydata->data) + keydata->sesskey_len, secblob.data, secblob.length); /* setup key */ rc = keyctl_instantiate(key, keydata, datalen, 0); if (rc == -1) { syslog(LOG_ERR, "keyctl_instantiate: %s", strerror(errno)); goto out; } /* BB: maybe we need use timeout for key: for example no more then * ticket lifietime? */ /* keyctl_set_timeout( key, 60); */ out: /* * on error, negatively instantiate the key ourselves so that we can * make sure the kernel doesn't hang it off of a searchable keyring * and interfere with the next attempt to instantiate the key. */ if (rc != 0 && key == 0) { syslog(LOG_DEBUG, "Negating key"); keyctl_negate(key, 1, KEY_REQKEY_DEFL_DEFAULT); } data_blob_free(&secblob); data_blob_free(&sess_key); SAFE_FREE(ccname); SAFE_FREE(arg.hostname); SAFE_FREE(arg.ip); SAFE_FREE(arg.username); SAFE_FREE(keydata); syslog(LOG_DEBUG, "Exit status %ld", rc); return rc; }