コード例 #1
0
ファイル: reauthorize.c プロジェクト: BillTheBest/cockpit
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;
}
コード例 #2
0
ファイル: nfsidmap.c プロジェクト: crossbuild/nfs-utils
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);
}
コード例 #3
0
ファイル: key.dns_resolver.c プロジェクト: Bleyda/keyutils
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);
}
コード例 #4
0
ファイル: cifs.idmap.c プロジェクト: Distrotech/cifs-utils
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;
}
コード例 #5
0
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() */
コード例 #6
0
ファイル: cifs.upcall.c プロジェクト: MageSlayer/cifs-utils
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;
}