class Keyutils::Keyring

Constants

Group

GID-specific keyring

Process

process-specific keyring

Session

session-specific keyring @see Keyutils::SessionKeyring

Thread

thread-specific keyring

User

UID-specific keyring

UserSession

UID-session keyring

Public Class Methods

default() click to toggle source

Get the implicit destination keyring

Gets the default destination for implicit key requests for the current thread.

Keys acquired by implicit key requests, such as might be performed by open() on an AFS or NFS filesystem, will be linked by default to that keyring.

Only one of the special keyrings can be returned:

  • {Thread}

  • {Process}

  • {Session}

  • {User}

  • {UserSession}

  • {Group}

If nil is returned, the default behaviour is selected, which is to use the thread-specific keyring if there is one, otherwise the process-specific keyring if there is one, otherwise the session keyring if there is one, otherwise the UID-specific session keyring.

@return [Keyring, nil] the default keyring @see .default=

# File lib/keyutils/keyring.rb, line 394
def default
  [nil, Thread, Process, Session, User, UserSession, Group]\
      [Lib.keyctl_set_reqkey_keyring -1]
end
default=(keyring = nil) click to toggle source

Set the implicit destination keyring

Sets the default destination for implicit key requests for the current thread.

After this operation has been issued, keys acquired by implicit key requests, such as might be performed by open() on an AFS or NFS filesystem, will be linked by default to the specified keyring by this function.

Only one of the special keyrings can be set as default:

  • {Thread}

  • {Process}

  • {Session}

  • {User}

  • {UserSession}

  • {Group}

If keyring is nil, the default behaviour is selected, which is to use the thread-specific keyring if there is one, otherwise the process-specific keyring if there is one, otherwise the session keyring if there is one, otherwise the UID-specific session keyring.

@param keyring [Keyring, nil] the new default keyring @return [Keyring, nil] keyring @see .default

# File lib/keyutils/keyring.rb, line 363
def default= keyring = nil
  id = keyring.to_i
  raise ArgumentError, 'only special keyrings can be default' \
      if id > 0
  Lib.keyctl_set_reqkey_keyring -id
end
persistent(uid = nil, destination = nil) click to toggle source

Get the persistent keyring for a user.

@note Not every system supports persistent keyrings.

Unlike the session and user keyrings, this keyring will persist once all login sessions have been deleted and can thus be used to carry authentication tokens for processes that run without user interaction, such as programs started by cron.

The persistent keyring will be created by the kernel if it does not yet exist. Each time this function is called, the persistent keyring will have its expiration timeout reset to the value in /proc/sys/kernel/keys/persistent_keyring_expiry (by default three days). Should the timeout be reached, the persistent keyring will be removed and everything it pins can then be garbage collected.

If UID is nil then the calling process's real user ID will be used. If UID is not nil then {Errno::EPERM} will be raised if the user ID requested does not match either the caller's real or effective user IDs or if the calling process does not have SetUid capability.

If successful, a link to the persistent keyring will be added into destination.

@param uid [Fixnum, nil] UID of the user for which the persistent

keyring is requested

@param destination [Keyring, nil] keyring to add the persistent keyring

to

@return [Keyring] the persistent keyring @raise [Errno::EPERM] not permitted to access the persistent keyring

for the requested UID.

@raise [Errno::ENOMEM] insufficient memory to create the persistent

keyring or to extend +destination+.

@raise [Errno::ENOKEY] destination does not exist. @raise [Errno::EKEYEXPIRED] destination has expired. @raise [Errno::EKEYREVOKED] destination has been revoked. @raise [Errno::EDQUOT] the user does not have sufficient quota to

extend +destination+.

@raise [Errno::EACCES] destination exists, but does not grant write

permission to the calling process.

@raise [Errno::EOPNOTSUPP] persistent keyrings are not supported by this

system
# File lib/keyutils/keyring.rb, line 441
def persistent uid = nil, destination = nil
  Keyring.send \
      :new,
      Lib.keyctl_get_persistent(uid || -1, destination.to_i),
      nil,
      nil
end

Public Instance Methods

<<(key)
Alias for: link
[](description) click to toggle source

Get a member “user” key

Searches the members of the keyring for a :user type key with the given description

@param description [String] description of the key to find @return [Key, nil] the key, if found

# File lib/keyutils/keyring.rb, line 307
def [] description
  find do |key|
    key.type == :user && key.description == description rescue false
  end
end
[]=(description, payload) click to toggle source

Set a member “user” key

Updates or creates a member key of type “user” and given description

@param description [String] the description of the key to update or

create

@param payload [String] the new key payload @return [String] payload

# File lib/keyutils/keyring.rb, line 321
def []= description, payload
  add :user, description, payload
end
add(type, description, payload) click to toggle source

Add a key to the kernel's key management facility.

Asks the kernel to create or update a key of the given type and description, instantiate it with the payload, and to attach it to this keyring.

The key type may reject the data if it's in the wrong format or in some other way invalid.

Keys of the user-defined key type (“user”) may contain a blob of arbitrary data, and the description may be any valid string, though it is preferred that the description be prefixed with a string representing the service to which the key is of interest and a colon (for instance “afs:mykey”).

If this keyring already contains a key that matches the specified type and description then, if the key type supports it, that key will be updated rather than a new key being created; if not, a new key will be created and it will displace the link to the extant key from the keyring.

@param type [Symbol] key type @param description [String] key description @param payload [#to_s, nil] payload @return [Key] the key created or updated @raise [Errno::ENOKEY] the keyring doesn't exist @raise [Errno::EKEYEXPIRED] the keyring has expired @raise [Errno::EKEYREVOKED] the keyring has been revoked @raise [Errno::EINVAL] the payload data was invalid @raise [Errno::ENODEV] the key type was invalid @raise [Errno::ENOMEM] insufficient memory to create a key @raise [Errno::EDQUOT] the key quota for this user would be exceeded by

creating this key or linking it to the keyring

@raise [Errno::EACCES] the keyring wasn't available for modification by

the user
# File lib/keyutils/keyring.rb, line 233
def add type, description, payload
  serial = Lib.add_key \
      type.to_s,
      description,
      payload && payload.to_s,
      payload && payload.to_s.length || 0,
      to_i
  Key.send :new_dispatch, serial, type.intern, description
end
clear() click to toggle source

Clear the contents of the keyring.

The caller must have write permission on a keyring to be able clear it. @return [Keyring] self @raise [Errno::ENOKEY] the keyring is invalid @raise [Errno::EKEYEXPIRED] the keyring has expired @raise [Errno::EKEYREVOKED] the keyring had been revoked @raise [Errno::EACCES] the keyring is not writable by the calling process

# File lib/keyutils/keyring.rb, line 16
def clear
  Lib.keyctl_clear id
  self
end
each(&b) click to toggle source

Iterate over linked keys

@return [Enumerator, Keyring] self if block given, else an Enumerator @yieldparam key [Key] member of the keyring @see read

# File lib/keyutils/keyring.rb, line 147
def each &b
  read.each &b
end
each_recursive() { |key, parent, attributes, error| ... } click to toggle source

Iterate over keys recursively

Performs a depth-first recursive scan of the keyring tree and yields for every link found in the accessible keyrings in that tree.

Errors are ignored. Inaccessible keyrings are not scanned, but links to them are still yielded. If key attributes (and hence ype) cannot be retrieved, a generic {Key} object is yielded and an error that prevented it is indicated.

This method yields for each link found in all the keyrings in the tree and so may be called multiple times for a particular key if that key has multiple links to it.

@yieldparam key [Key] the key to which the link points @yieldparam parent [Keyring, nil] the keyring containing the link or nil

for the initial key.

@yieldparam attributes [Hash] key attributes, as returned by

{Key#describe}

@yieldparam error [SystemCallError, nil] error that prevented retrieving

key attributes

@return [Enumerator, Keyring] self if block given, else an Enumerator

# File lib/keyutils/keyring.rb, line 174
def each_recursive
  return enum_for __method__ unless block_given?

  Lib.recursive_key_scan serial, ->(parent, key, desc, desc_len, _) do
    parent = parent == 0 ? nil : Keyring.send(:new, parent, nil)
    if desc_len > 0
      attributes = Key.send :parse_describe, desc.read_string(desc_len)
      key = Key.send :new_dispatch, key, attributes[:type], attributes[:desc]
      error = nil
    else
      attributes = nil
      key = Key.send :new, key, nil, nil
      error = SystemCallError.new FFI.errno
    end
    yield key, parent, attributes, error
    0
  end, nil
  self
end
length() click to toggle source

@return [Fixnum] number of keys linked to this keyring

# File lib/keyutils/keyring.rb, line 195
def length
  read.length
end
read() click to toggle source

Read the keyring.

Reads the list of keys in this keyring.

The caller must have read permission on a key to be able to read it.

@return [<Key>] the keyring members @raise [Errno::ENOKEY] the keyring is invalid @raise [Errno::EKEYEXPIRED] the keyring has expired @raise [Errno::EKEYREVOKED] the keyring had been revoked @raise [Errno::EACCES] the keyring is not readable by the calling process @see each

Calls superclass method Keyutils::Key#read
# File lib/keyutils/keyring.rb, line 132
def read
  super.unpack('L*').map do |serial|
    # try to map to the correct class
    key = Key.send :new, serial, nil, nil
    Key.send(:new_dispatch, serial, key.type, key.description) rescue key
  end
end
Also aliased as: to_a
request(type, description, callout_info = '') click to toggle source

Request a key from the kernel's key management facility.

Asks the kernel to find a key of the given type that matches the specified description and, if successful, to attach it this keyring.

{#request} first recursively searches all the keyrings attached to the calling process in the order thread-specific keyring, process-specific keyring and then session keyring for a matching key.

If {#request} is called from a program invoked by request_key(2) on behalf of some other process to generate a key, then the keyrings of that other process will be searched next, using that other process's UID, GID, groups and security context to control access.

The keys in each keyring searched are checked for a match before any child keyrings are recursed into. Only keys that are searchable for the caller may be found, and only searchable keyrings may be searched.

If the key is not found then, if callout_info is not nil, this function will attempt to look further afield. In such a case, the callout_info is passed to a user-space service such as /sbin/request-key to generate the key.

If that is unsuccessful also, then an error will be raised, and a temporary negative key will be installed in the keyring. This will expire after a few seconds, but will cause subsequent calls to {#request} to fail until it does.

If a key is created, no matter whether it's a valid key or a negative key, it will displace any other key of the same type and description from the keyring. @param type [Symbol] key type @param description [String] key description @param callout_info [String, nil] additional parameters for the

request-key(8) facility

@return [Key, nil] the key, if found @raise [Errno::EACCES] the keyring wasn't available for modification by the user @raise [Errno::EINTR] the request was interrupted by a signal @raise [Errno::EDQUOT] the key quota for this user would be exceeded by creating this key or linking it to the keyring @raise [Errno::EKEYEXPIRED] an expired key was found, but no replacement could be obtained @raise [Errno::EKEYREJECTED] the attempt to generate a new key was rejected @raise [Errno::EKEYREVOKED] a revoked key was found, but no replacement could be obtained @raise [Errno::ENOMEM] insufficient memory to create a key @see Keyring#search @see man7.org/linux/man-pages/man2/request_key.2.html request_key(2) @see assume_authority

# File lib/keyutils/keyring.rb, line 289
def request type, description, callout_info = ''
  serial = Lib.request_key \
      type.to_s,
      description,
      callout_info,
      to_i
  new_dispatch serial, type.intern, description
rescue Errno::ENOKEY
  nil
end
to_a()
Alias for: read
to_h() click to toggle source

Return all “user” subkeys

Keys that cannot be read are ommited.

@return [{String => String}] user keys' descriptions and their payloads

# File lib/keyutils/keyring.rb, line 330
def to_h
  keys = find_all { |k| k.type == :user rescue false }
  pairs = keys.map { |k| [k.description, k.to_s] rescue nil }
  Hash[*pairs.compact.flatten]
end