Class: Keyutils::Key

Inherits:
Object
  • Object
show all
Defined in:
lib/keyutils/key.rb

Direct Known Subclasses

Keyring

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#idFixnum Also known as: to_i, hash

Numeric identifier of the key this object points to.

Returns:

See Also:



9
10
11
# File 'lib/keyutils/key.rb', line 9

def id
  @id
end

Class Method Details

.find(type, description, destination = nil) ⇒ Key?

Find a key by type and description

Searches for a key with the given type and exact description, firstly in the thread, process and session keyrings to which a process is subscribed and secondly in /proc/keys.

If a key is found, and destination is not nil and specifies a keyring, then the found key will be linked into it.

Parameters:

  • type (Symbol)

    key type

  • description (String)

    key description

  • destination (Keyring, nil) (defaults to: nil)

    destination keyring

Returns:

  • (Key, nil)

    the key, if found

Raises:

  • (Errno::EKEYEXPIRED)

    key or keyring have expired.

  • (Errno::EKEYREVOKED)

    the key or keyring have been revoked.

  • (Errno::EACCES)

    the key is not accessible or keyring exists, but is not writable by the calling process.

See Also:



525
526
527
528
529
530
531
532
533
# File 'lib/keyutils/key.rb', line 525

def find type, description, destination = nil
  serial = Lib.find_key_by_type_and_desc \
      type.to_s,
      description,
      destination.to_i
  new_dispatch serial, type.intern, description
rescue Errno::ENOKEY
  nil
end

.renounce_authorityvoid

This method returns an undefined value.

De-assume the currently assumed authority.

See Also:



538
539
540
# File 'lib/keyutils/key.rb', line 538

def renounce_authority
  Lib.keyctl_assume_authority 0
end

Instance Method Details

#==(other) ⇒ Boolean

Key equality

Returns:

  • (Boolean)

    whether the objects point to the same key

See Also:



487
488
489
# File 'lib/keyutils/key.rb', line 487

def == other
  serial == other.serial
end

#assume_authorityKey

Note:

This is a per-thread setting and not a per-process setting so that a multithreaded process can be used to instantiate several keys at once.

Assume the authority to instantiate the key.

Assumes the authority for the calling thread to deal with and instantiate this uninstantiated key.

The calling thread must have the appropriate authorisation key resident in one of its keyrings for this to succeed, and that authority must not have been revoked.

The authorising key is allocated by request_key(2) when it needs to invoke userspace to generate a key for the requesting process. This is then attached to one of the keyrings of the userspace process to which the task of instantiating the key is given:

requester ⟶ request_key() ⟶ instantiator

Calling this function modifies the way request works when called thereafter by the calling (instantiator) thread; once the authority is assumed, the keyrings of the initial process are added to the search path, using the initial process’s UID, GID, groups and security context.

If a thread has multiple instantiations to deal with, it may call this function to change the authorisation key currently in effect.

Returns:

  • (Key)

    self

Raises:

  • (Errno::ENOKEY)

    the key is invalid.

  • (Errno::EKEYREVOKED)

    the key had been revoked, or the authorisation has been revoked.

See Also:



386
387
388
389
# File 'lib/keyutils/key.rb', line 386

def assume_authority
  Lib.keyctl_assume_authority id
  self
end

#chown(uid = nil, gid = nil) ⇒ Key

Change the user and group ownership details of the key.

A setting of -1 or nil on either uid or gid will cause that setting to be ignored.

A process that does not have the SysAdmin capability may not change a key’s UID or set the key’s GID to a value that does not match the process’s GID or one of its group list.

The caller must have setattr permission on a key to be able change its ownership.

Parameters:

  • uid (Fixnum, nil) (defaults to: nil)

    numeric UID of the new owner

  • gid (Fixnum, nil) (defaults to: nil)

    numeric GID of the new owning group

Returns:

  • (Key)

    self

Raises:

  • (Errno::ENOKEY)

    the key does not exist

  • (Errno::EKEYEXPIRED)

    the key has expired

  • (Errno::EKEYREVOKED)

    the key has been revoked

  • (Errno::EDQUOT)

    changing the UID to the one specified would run that UID out of quota

  • (Errno::EACCES)

    the key exists, but does not grant setattr permission to the calling process; or insufficient process permissions

See Also:



123
124
125
126
# File 'lib/keyutils/key.rb', line 123

def chown uid = nil, gid = nil
  Lib.keyctl_chown id, uid || -1, gid || -1
  self
end

#describeHash

Describe the attributes of the key.

The caller must have view permission on a key to be able to get attributes of it.

Attributes are returned as a hash of the following keys:

  • :type [Symbol],

  • :uid [Fixnum],

  • :gid [Fixnum],

  • :perm [Fixnum],

  • :desc [String].

Returns:

  • (Hash)

    key attributes

Raises:

  • (Errno::ENOKEY)

    the key is invalid

  • (Errno::EKEYEXPIRED)

    the key has expired

  • (Errno::EKEYREVOKED)

    the key had been revoked

  • (Errno::EACCES)

    the key is not viewable by the calling process

See Also:



243
244
245
246
247
248
249
250
251
# File 'lib/keyutils/key.rb', line 243

def describe
  buf = FFI::MemoryPointer.new :char, 64
  len = Lib.keyctl_describe id, buf, buf.size
  while len > buf.size
    buf = FFI::MemoryPointer.new :char, len
    len = Lib.keyctl_describe id, buf, buf.size
  end
  Key.send :parse_describe, buf.read_string(len - 1)
end

#descriptionString

Returns the key description.

Returns:

  • (String)

    the key description



194
195
196
# File 'lib/keyutils/key.rb', line 194

def description
  @description ||= describe[:desc]
end

#eql?(other) ⇒ Boolean

Key handle equality

Same as #==, except it doesn’t dereference the special handles such as Keyutils::Keyring::Session. This means #eql? can be false even if the argument points to the same keyring, as long as only one of them is a special handle.

Returns:

  • (Boolean)

    whether the key handles are equal

See Also:



500
501
502
# File 'lib/keyutils/key.rb', line 500

def eql? other
  to_i == other.to_i
end

#exists?Boolean

Check if this key exists in the kernel.

The key may not exist eg. if it has been removed by another process, or if this is a special keyring handle (such as Keyutils::Keyring::Thread) and the keyring has not been instantiated yet.

Returns:

  • (Boolean)

    true if the key exists



43
44
45
46
47
48
49
# File 'lib/keyutils/key.rb', line 43

def exists?
  Lib.keyctl_get_keyring_ID(id, false) && true
rescue Errno::EACCES
  true
rescue Errno::ENOKEY
  false
end

#gidFixnum

Returns the key GID.

Returns:

  • (Fixnum)

    the key GID

See Also:



210
211
212
# File 'lib/keyutils/key.rb', line 210

def gid
  describe[:gid]
end

#instantiate(payload, destination = nil) ⇒ Key

Instantiate a key

Instantiate the payload of an uninstantiated key from the data specified. payload specifies the data for the new payload. payload may be nil if the key type permits that. The key type may reject the data if it’s in the wrong format or in some other way invalid.

Only a key for which authority has been assumed may be instantiated or negatively instantiated, and once instantiated, the authorisation key will be revoked and the requesting process will be able to resume.

The destination keyring, if given, is assumed to belong to the initial requester, and not the instantiating process. Therefore, the special keyring objects (such as Keyutils::Keyring::Session) refer to the requesting process’s keyrings, not the caller’s, and the requester’s UID, etc. will be used to access them.

The destination keyring can be nil if no extra link is desired.

The requester, not the caller, must have write permission on the destination for a link to be made there.

Parameters:

  • payload (String, nil)

    the payload to instantiate the key with

  • destination (Keyring, nil) (defaults to: nil)

    keyring to link the key to

Returns:

  • (Key)

    self

Raises:

  • (Errno::ENOKEY)

    the key or specified keyring is invalid

  • (Errno::EKEYEXPIRED)

    the keyring specified has expired

  • (Errno::EKEYREVOKED)

    the key or keyring specified had been revoked, or the authorisation has been revoked

  • (Errno::EINVAL)

    the payload data was invalid

  • (Errno::ENOMEM)

    insufficient memory to store the new payload or to expand the destination keyring

  • (Errno::EDQUOT)

    the key quota for the key’s user would be exceeded by increasing the size of the key to accommodate the new payload or the key quota for the keyring’s user would be exceeded by expanding the destination keyring

  • (Errno::EACCES)

    the key exists, but is not writable by the requester

See Also:



318
319
320
321
322
323
324
# File 'lib/keyutils/key.rb', line 318

def instantiate payload, destination = nil
  Lib.keyctl_instantiate id,
      payload && payload.to_s,
      payload && payload.to_s.length || 0,
      destination.to_i
  self
end

#invalidateKey

Invalidate the key.

The key is scheduled for immediate removal from all the keyrings that point to it, after which it will be deleted. The key will be ignored by all searches once this function is called even if it is not yet fully dealt with.

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

Returns:

  • (Key)

    self

Raises:

  • (Errno::ENOKEY)

    the key is invalid.

  • (Errno::EKEYEXPIRED)

    the key specified has expired.

  • (Errno::EKEYREVOKED)

    the key specified had been revoked.

  • (Errno::EACCES)

    the key is not searchable by the calling process.

See Also:



478
479
480
481
# File 'lib/keyutils/key.rb', line 478

def invalidate
  Lib.keyctl_invalidate id
  self
end

#permFixnum

Returns the key permission mask.

Returns:

  • (Fixnum)

    the key permission mask

See Also:



217
218
219
# File 'lib/keyutils/key.rb', line 217

def perm
  describe[:perm]
end

#readString Also known as: to_s

Read the key.

Reads the payload of a key if the key type supports it.

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

Returns:

  • (String)

    the key payload

Raises:

  • (Errno::ENOKEY)

    the key is invalid

  • (Errno::EKEYEXPIRED)

    the key has expired

  • (Errno::EKEYREVOKED)

    the key had been revoked

  • (Errno::EACCES)

    the key exists, but is not readable by the calling process

  • (Errno::EOPNOTSUPP)

    the key type does not support reading of the payload data



267
268
269
270
271
272
273
274
275
# File 'lib/keyutils/key.rb', line 267

def read
  buf = FFI::MemoryPointer.new :char, 64
  len = Lib.keyctl_read id, buf, buf.size
  while len > buf.size
    buf = FFI::MemoryPointer.new :char, len
    len = Lib.keyctl_read id, buf, buf.size
  end
  buf.read_string len
end

#reject(timeout_s, error = Errno::ENOKEY, destination = nil) ⇒ Key

Note:

On some kernel versions error setting is not supported. In this case it will fall back to always raising Errno::ENOKEY.

Negatively instantiate a key

Marks a key as negatively instantiated and sets the expiration timer on it. Attempts to access the key will raise the given error.

Only a key for which authority has been assumed may be negatively instantiated, and once instantiated, the authorisation key will be revoked and the requesting process will be able to resume.

The destination keyring, if given, is assumed to belong to the initial requester, and not the instantiating process. Therefore, the special keyring objects (such as Keyutils::Keyring::Session) refer to the requesting process’s keyrings, not the caller’s, and the requester’s UID, etc. will be used to access them.

The destination keyring can be nil if no extra link is desired.

The requester, not the caller, must have write permission on the destination for a link to be made there.

Parameters:

  • timeout_s (Fixnum)

    the lifetime of the key in seconds

  • error (::Errno) (defaults to: Errno::ENOKEY)

    error to be raised when attempting to access the key, typically one of Errno::ENOKEY, Errno::EKEYREJECTED, Errno::EKEYREVOKED or Errno::EKEYEXPIRED

  • destination (Keyring, nil) (defaults to: nil)

    keyring to link the key to

Returns:

  • (Key)

    self

Raises:

  • (Errno::ENOKEY)

    the key or specified keyring is invalid

  • (Errno::EKEYEXPIRED)

    the keyring specified has expired

  • (Errno::EKEYREVOKED)

    the key or keyring specified had been revoked, or the authorisation has been revoked

  • (Errno::ENOMEM)

    insufficient memory to expand the destination keyring

  • (Errno::EDQUOT)

    the key quota for the keyring’s user would be exceeded by expanding the destination keyring

  • (Errno::EACCES)

    the keyring exists, but is not writable by the requester

See Also:



458
459
460
461
# File 'lib/keyutils/key.rb', line 458

def reject timeout_s, error = Errno::ENOKEY, destination = nil
  Lib.keyctl_reject id, timeout_s, error::Errno, keyring.to_i
  self
end

#revokeKey

Mark the key as being revoked.

After this operation has been performed on a key, attempts to access it will meet with error EKEYREVOKED.

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

Returns:

  • (Key)

    self

Raises:

  • (Errno::ENOKEY)

    the key does not exist

  • (Errno::EKEYREVOKED)

    the key has already been revoked

  • (Errno::EACCES)

    the key exists, but is not writable by the calling process

See Also:



93
94
95
96
# File 'lib/keyutils/key.rb', line 93

def revoke
  Lib.keyctl_revoke id
  self
end

#securityString

Retrieve the key’s security context.

This will be rendered in a form appropriate to the LSM in force—for instance, with SELinux, it may look like

unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

The caller must have view permission on a key to be able to get its security context.

Returns:

  • (String)

    key security context

Raises:

  • (Errno::ENOKEY)

    the key is invalid.

  • (Errno::EKEYEXPIRED)

    the key has expired.

  • (Errno::EKEYREVOKED)

    the key had been revoked.

  • (Errno::EACCES)

    the key is not viewable by the calling process.



406
407
408
409
410
411
412
413
414
415
416
# File 'lib/keyutils/key.rb', line 406

def security
  return @security if @security

  buf = FFI::MemoryPointer.new :char, 64
  len = Lib.keyctl_get_security id, buf, buf.size
  while len > buf.size
    buf = FFI::MemoryPointer.new :char, len
    len = Lib.keyctl_get_security id, buf, buf.size
  end
  @security = buf.read_string (len - 1)
end

#serialFixnum

Get the serial number of this key.

For ordinary keys, #serial == #id, and this method always succeeds.

For special key handles (such as Keyutils::Keyring::Session), this method will resolve the actual serial number of the key it points to.

Note if this is a special key handle and the key(ring) is not already instantiated, calling this method will attempt to create it. For this reason it can fail if memory or quota is exhausted.

Returns:

  • (Fixnum)

    serial number of this key

Raises:

  • (Errno::ENOKEY)

    no matching key was found

  • (Errno::ENOMEM)

    insufficient memory to create a key

  • (Errno::EDQUOT)

    the key quota for this user would be exceeded by creating this key or linking it to the keyring

See Also:



31
32
33
34
# File 'lib/keyutils/key.rb', line 31

def serial
  return id unless id < 0
  Lib.keyctl_get_keyring_ID id, true
end

#set_timeout(timeout_s) ⇒ Key

Set the expiration timer on a key

Sets the expiration timer on a key to timeout_s seconds into the future. Setting timeout to zero cancels the expiration, assuming the key hasn’t already expired.

When the key expires, further attempts to access it will be met with error EKEYEXPIRED.

The caller must have setattr permission on a key to be able change its timeout.

Parameters:

  • timeout_s (Fixnum)

    expiration timer, in seconds

Returns:

  • (Key)

    self

Raises:

  • (Errno::ENOKEY)

    the key does not exist.

  • (Errno::EKEYEXPIRED)

    the key has already expired.

  • (Errno::EKEYREVOKED)

    the key has been revoked.

  • (Errno::EACCES)

    the key does not grant setattr permission to the calling process.



345
346
347
348
# File 'lib/keyutils/key.rb', line 345

def set_timeout timeout_s
  Lib.keyctl_set_timeout id, timeout_s
  self
end

#setperm(permissions) ⇒ Key

Change the permissions mask on the key.

A process that does not have the SysAdmin capability may not change the permissions mask on a key that doesn’t have the same UID as the caller.

The caller must have setattr permission on a key to be able change its permissions mask.

The permissions mask is a bitwise-OR of the following flags:

  • KEY_xxx_VIEW Grant permission to view the attributes of a key.

  • KEY_xxx_READ Grant permission to read the payload of a key or to list a keyring.

  • KEY_xxx_WRITE Grant permission to modify the payload of a key or to add or remove links to/from a keyring.

  • KEY_xxx_SEARCH Grant permission to find a key or to search a keyring.

  • KEY_xxx_LINK Grant permission to make links to a key.

  • KEY_xxx_SETATTR Grant permission to change the ownership and permissions attributes of a key.

  • KEY_xxx_ALL Grant all the above.

The ‘xxx’ in the above should be replaced by one of:

  • POS Grant the permission to a process that possesses the key (has it attached searchably to one of the process’s keyrings).

  • USR Grant the permission to a process with the same UID as the key.

  • GRP Grant the permission to a process with the same GID as the key, or with a match for the key’s GID amongst that process’s Groups list.

  • OTH Grant the permission to any other process.

Examples include: Keyutils::KeyPerm::KEY_POS_VIEW, Keyutils::KeyPerm::KEY_USR_READ, Keyutils::KeyPerm::KEY_GRP_SEARCH and Keyutils::KeyPerm::KEY_OTH_ALL.

User, group and other grants are exclusive: if a process qualifies in the ‘user’ category, it will not qualify in the ‘groups’ category; and if a process qualifies in either ‘user’ or ‘groups’ then it will not qualify in the ‘other’ category.

Possessor grants are cumulative with the grants from the ‘user’, ‘groups’ and ‘other’ categories.

Parameters:

  • permissions (Fixnum)

    permission mask; bitwise OR-ed constants from Keyutils::KeyPerm

Returns:

  • (Key)

    self

Raises:

  • (Errno::ENOKEY)

    the key does not exist

  • (Errno::EKEYEXPIRED)

    the key has expired

  • (Errno::EKEYREVOKED)

    the key has been revoked

  • (Errno::EACCES)

    the key exists, but does not grant setattr permission to the calling process

See Also:



183
184
185
186
# File 'lib/keyutils/key.rb', line 183

def setperm permissions
  Lib.keyctl_setperm id, permissions
  self
end

#typeSymbol

Returns the key type name.

Returns:

  • (Symbol)

    the key type name



189
190
191
# File 'lib/keyutils/key.rb', line 189

def type
  @type ||= describe[:type]
end

#uidFixnum

Returns the key UID.

Returns:

  • (Fixnum)

    the key UID

See Also:



202
203
204
# File 'lib/keyutils/key.rb', line 202

def uid
  describe[:uid]
end

#update(payload) ⇒ Key

Update the payload of the key if the key type permits it.

The caller must have write permission on the key to be able to update it.

payload specifies the data for the new payload; it may be nil if the key type permits that. The key type may reject the data if it’s in the wrong format or in some other way invalid.

Parameters:

  • payload (#to_s, nil)

    data for the new key payload

Returns:

  • (Key)

    self

Raises:

  • (Errno::ENOKEY)

    the key is invalid

  • (Errno::EKEYEXPIRED)

    the key has expired

  • (Errno::EKEYREVOKED)

    the key had been revoked

  • (Errno::EINVAL)

    the payload data was invalid

  • (Errno::ENOMEM)

    insufficient memory to store the new payload

  • (Errno::EDQUOT)

    the key quota for this user would be exceeded by increasing the size of the key to accommodate the new payload

  • (Errno::EACCES)

    the key exists, but is not writable by the calling process

  • (Errno::EOPNOTSUPP)

    the key type does not support the update operation on its keys



72
73
74
75
76
77
78
# File 'lib/keyutils/key.rb', line 72

def update payload
  Lib.keyctl_update \
      id,
      payload && payload.to_s,
      payload && payload.to_s.length || 0
  self
end