keyutils 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,49 @@
1
+ module Keyutils
2
+ # Key permission constants.
3
+ # @see Key#setperm
4
+ module KeyPerm
5
+ KEY_POS_VIEW = 0x01000000 # possessor can view a key's attributes
6
+ KEY_POS_READ = 0x02000000 # possessor can read key payload / view keyring
7
+ KEY_POS_WRITE = 0x04000000 # possessor can update key payload / add link to keyring
8
+ KEY_POS_SEARCH = 0x08000000 # possessor can find a key in search / search a keyring
9
+ KEY_POS_LINK = 0x10000000 # possessor can create a link to a key/keyring
10
+ KEY_POS_SETATTR = 0x20000000 # possessor can set key attributes
11
+ KEY_POS_ALL = 0x3f000000
12
+
13
+ #
14
+ # user permissions...
15
+ #
16
+
17
+ KEY_USR_VIEW = 0x00010000
18
+ KEY_USR_READ = 0x00020000
19
+ KEY_USR_WRITE = 0x00040000
20
+ KEY_USR_SEARCH = 0x00080000
21
+ KEY_USR_LINK = 0x00100000
22
+ KEY_USR_SETATTR = 0x00200000
23
+ KEY_USR_ALL = 0x003f0000
24
+
25
+ #
26
+ # group permissions...
27
+ #
28
+
29
+ KEY_GRP_VIEW = 0x00000100
30
+ KEY_GRP_READ = 0x00000200
31
+ KEY_GRP_WRITE = 0x00000400
32
+ KEY_GRP_SEARCH = 0x00000800
33
+ KEY_GRP_LINK = 0x00001000
34
+ KEY_GRP_SETATTR = 0x00002000
35
+ KEY_GRP_ALL = 0x00003f00
36
+
37
+ #
38
+ # third party permissions...
39
+ #
40
+
41
+ KEY_OTH_VIEW = 0x00000001
42
+ KEY_OTH_READ = 0x00000002
43
+ KEY_OTH_WRITE = 0x00000004
44
+ KEY_OTH_SEARCH = 0x00000008
45
+ KEY_OTH_LINK = 0x00000010
46
+ KEY_OTH_SETATTR = 0x00000020
47
+ KEY_OTH_ALL = 0x0000003f
48
+ end
49
+ end
@@ -0,0 +1,24 @@
1
+ module Keyutils
2
+ module KeyTypes
3
+ class << self
4
+ def classes
5
+ @classes ||= {}
6
+ end
7
+
8
+ def [] type
9
+ classes[type]
10
+ end
11
+
12
+ def []= type, klass
13
+ klass.send :define_method, :initialize, ->(id, description) do
14
+ @id = id
15
+ @description = description
16
+ end
17
+ klass.send :define_method, :type, ->() do
18
+ type
19
+ end
20
+ classes[type] = klass
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,527 @@
1
+ require 'keyutils/key'
2
+ require 'keyutils/key_types'
3
+
4
+ module Keyutils
5
+ class Keyring < Key
6
+ include Enumerable
7
+
8
+ # Clear the contents of the keyring.
9
+ #
10
+ # The caller must have write permission on a keyring to be able clear it.
11
+ # @return [Keyring] self
12
+ # @raise [Errno::ENOKEY] the keyring is invalid
13
+ # @raise [Errno::EKEYEXPIRED] the keyring has expired
14
+ # @raise [Errno::EKEYREVOKED] the keyring had been revoked
15
+ # @raise [Errno::EACCES] the keyring is not writable by the calling process
16
+ def clear
17
+ Lib.keyctl_clear id
18
+ self
19
+ end
20
+
21
+ # Link a key to the keyring.
22
+ #
23
+ # Creates a link from this keyring to +key+, displacing any link to another
24
+ # key of the same type and description in this keyring if one exists.
25
+ #
26
+ # The caller must have write permission on a keyring to be able to create
27
+ # links in it.
28
+ #
29
+ # The caller must have link permission on a key to be able to create a
30
+ # link to it.
31
+ #
32
+ # @param key [Key] the key to link to this keyring
33
+ # @return [Keyring] self
34
+ # @raise [Errno::ENOKEY] the key or the keyring specified are invalid
35
+ # @raise [Errno::EKEYEXPIRED] the key or the keyring specified have expired
36
+ # @raise [Errno::EKEYREVOKED] the key or the keyring specified have been
37
+ # revoked
38
+ # @raise [Errno::EACCES] the keyring exists, but is not writable by the
39
+ # calling process
40
+ # @raise [Errno::ENOMEM] insufficient memory to expand the keyring
41
+ # @raise [Errno::EDQUOT] expanding the keyring would exceed the keyring
42
+ # owner's quota
43
+ # @raise [Errno::EACCES] the key exists, but is not linkable by the
44
+ # calling process
45
+ # @see #unlink
46
+ def link key
47
+ Lib.keyctl_link key.id, id
48
+ self
49
+ end
50
+
51
+ alias << link
52
+
53
+ # Unlink a key from the keyring.
54
+ #
55
+ # Removes a link from this keyring to +key+ if it exists.
56
+ #
57
+ # The caller must have write permission on a keyring to be able to remove
58
+ # links in it.
59
+ # @param key [Key] the key to unlink from this keyring
60
+ # @return [Keyring] self
61
+ # @raise [Errno::ENOKEY] the key or the keyring specified are invalid
62
+ # @raise [Errno::EKEYEXPIRED] the key or the keyring specified have expired
63
+ # @raise [Errno::EKEYREVOKED] the key or the keyring specified have been
64
+ # revoked
65
+ # @raise [Errno::EACCES] the keyring exists, but is not writable by the
66
+ # calling process
67
+ # @see #link
68
+ def unlink key
69
+ Lib.keyctl_unlink key.id, id
70
+ self
71
+ rescue Errno::ENOENT
72
+ # there was no link
73
+ self
74
+ end
75
+
76
+ # Search the keyring for a key
77
+ #
78
+ # Recursively searches the keyring for a key of the specified +type+ and
79
+ # +description+.
80
+ #
81
+ # If found, the key will be attached to the +destination+ keyring (if
82
+ # given), and returned.
83
+ #
84
+ # The source keyring must grant search permission to the caller, and for a
85
+ # key to be found, it must also grant search permission to the caller.
86
+ # Child keyrings will be only be recursively searched if they grant search
87
+ # permission to the caller as well.
88
+ #
89
+ # If the +destination+ keyring is given, then the link may only be formed
90
+ # if the found key grants the caller link permission and the destination
91
+ # keyring grants the caller write permission.
92
+ #
93
+ # If the search is successful, and if the destination keyring already
94
+ # contains a link to a key that matches the specified type and description,
95
+ # then that link will be replaced by a link to the found key.
96
+ #
97
+ # @param type [Symbol] the type of the key to find
98
+ # @param description [String] the description of the key to find
99
+ # @param destination [Keyring, nil] the keyring to attach the key if found
100
+ # @return [Key, nil] the key, if found
101
+ # @raise [Errno::EKEYEXPIRED] one of the keyrings has expired, or the only
102
+ # key found was expired
103
+ # @raise [Errno::EKEYREVOKED] one of the keyrings has been revoked, or the
104
+ # only key found was revoked
105
+ # @raise [Errno::ENOMEM] insufficient memory to expand the destination
106
+ # keyring
107
+ # @raise [Errno::EDQUOT] the key quota for this user would be exceeded by
108
+ # creating a link to the found key in the destination keyring
109
+ # @raise [Errno::EACCES] the source keyring didn't grant search permission,
110
+ # the destination keyring didn't grant write permission or the found key
111
+ # didn't grant link permission to the caller
112
+ # @see #request
113
+ def search type, description, destination = nil
114
+ serial = Lib.keyctl_search id, type.to_s, description, destination.to_i
115
+ Key.send :new_dispatch, serial, type.intern, description
116
+ rescue Errno::ENOKEY
117
+ nil
118
+ end
119
+
120
+ # Read the keyring.
121
+ #
122
+ # Reads the list of keys in this keyring.
123
+ #
124
+ # The caller must have read permission on a key to be able to read it.
125
+ #
126
+ # @return [<Key>] the keyring members
127
+ # @raise [Errno::ENOKEY] the keyring is invalid
128
+ # @raise [Errno::EKEYEXPIRED] the keyring has expired
129
+ # @raise [Errno::EKEYREVOKED] the keyring had been revoked
130
+ # @raise [Errno::EACCES] the keyring is not readable by the calling process
131
+ # @see #each
132
+ def read
133
+ super.unpack('L*').map do |serial|
134
+ # try to map to the correct class
135
+ key = Key.send :new, serial, nil, nil
136
+ Key.send(:new_dispatch, serial, key.type, key.description) rescue key
137
+ end
138
+ end
139
+ alias to_a read
140
+ undef to_s rescue nil
141
+
142
+ # Iterate over linked keys
143
+ #
144
+ # @return [Enumerator, Keyring] self if block given, else an Enumerator
145
+ # @yieldparam key [Key] member of the keyring
146
+ # @see #read
147
+ def each &b
148
+ read.each &b
149
+ end
150
+
151
+ # Iterate over keys recursively
152
+ #
153
+ # Performs a depth-first recursive scan of the keyring tree and yields for
154
+ # every link found in the accessible keyrings in that tree.
155
+ #
156
+ # Errors are ignored. Inaccessible keyrings are not scanned, but links to
157
+ # them are still yielded. If key attributes (and hence ype) cannot be
158
+ # retrieved, a generic {Key} object is yielded and an error that prevented
159
+ # it is indicated.
160
+ #
161
+ # This method yields for each link found in all the keyrings in the tree
162
+ # and so may be called multiple times for a particular key if that key has
163
+ # multiple links to it.
164
+ #
165
+ # @yieldparam key [Key] the key to which the link points
166
+ # @yieldparam parent [Keyring, nil] the keyring containing the link or nil
167
+ # for the initial key.
168
+ # @yieldparam attributes [Hash] key attributes, as returned by
169
+ # {Key#describe}
170
+ # @yieldparam error [SystemCallError, nil] error that prevented retrieving
171
+ # key attributes
172
+ #
173
+ # @return [Enumerator, Keyring] self if block given, else an Enumerator
174
+ def each_recursive
175
+ return enum_for __method__ unless block_given?
176
+
177
+ Lib.recursive_key_scan serial, ->(parent, key, desc, desc_len, _) do
178
+ parent = parent == 0 ? nil : Keyring.send(:new, parent, nil)
179
+ if desc_len > 0
180
+ attributes = Key.send :parse_describe, desc.read_string(desc_len)
181
+ key = Key.send :new_dispatch, key, attributes[:type], attributes[:desc]
182
+ error = nil
183
+ else
184
+ attributes = nil
185
+ key = Key.send :new, key, nil, nil
186
+ error = SystemCallError.new FFI.errno
187
+ end
188
+ yield key, parent, attributes, error
189
+ 0
190
+ end, nil
191
+ self
192
+ end
193
+
194
+ # @return [Fixnum] number of keys linked to this keyring
195
+ def length
196
+ read.length
197
+ end
198
+
199
+ # Add a key to the kernel's key management facility.
200
+ #
201
+ # Asks the kernel to create or update a key of the given +type+ and
202
+ # +description+, instantiate it with the +payload+, and to attach it to
203
+ # this keyring.
204
+ #
205
+ # The key type may reject the data if it's in the wrong format or in
206
+ # some other way invalid.
207
+ #
208
+ # Keys of the user-defined key type ("user") may contain a blob of
209
+ # arbitrary data, and the description may be any valid string, though it
210
+ # is preferred that the description be prefixed with a string
211
+ # representing the service to which the key is of interest and a colon
212
+ # (for instance "afs:mykey").
213
+ #
214
+ # If this keyring already contains a key that matches the specified type
215
+ # and description then, if the key type supports it, that key will be
216
+ # updated rather than a new key being created; if not, a new key will be
217
+ # created and it will displace the link to the extant key from the keyring.
218
+ #
219
+ # @param type [Symbol] key type
220
+ # @param description [String] key description
221
+ # @param payload [#to_s, nil] payload
222
+ # @return [Key] the key created or updated
223
+ # @raise [Errno::ENOKEY] the keyring doesn't exist
224
+ # @raise [Errno::EKEYEXPIRED] the keyring has expired
225
+ # @raise [Errno::EKEYREVOKED] the keyring has been revoked
226
+ # @raise [Errno::EINVAL] the payload data was invalid
227
+ # @raise [Errno::ENODEV] the key type was invalid
228
+ # @raise [Errno::ENOMEM] insufficient memory to create a key
229
+ # @raise [Errno::EDQUOT] the key quota for this user would be exceeded by
230
+ # creating this key or linking it to the keyring
231
+ # @raise [Errno::EACCES] the keyring wasn't available for modification by
232
+ # the user
233
+ def add type, description, payload
234
+ serial = Lib.add_key \
235
+ type.to_s,
236
+ description,
237
+ payload && payload.to_s,
238
+ payload && payload.to_s.length || 0,
239
+ to_i
240
+ Key.send :new_dispatch, serial, type.intern, description
241
+ end
242
+
243
+ # Request a key from the kernel's key management facility.
244
+ #
245
+ # Asks the kernel to find a key of the given +type+ that matches the
246
+ # specified +description+ and, if successful, to attach it this keyring.
247
+ #
248
+ # {#request} first recursively searches all the keyrings attached to the
249
+ # calling process in the order thread-specific keyring, process-specific
250
+ # keyring and then session keyring for a matching key.
251
+ #
252
+ # If {#request} is called from a program invoked by request_key(2) on
253
+ # behalf of some other process to generate a key, then the keyrings of
254
+ # that other process will be searched next, using that other process's
255
+ # UID, GID, groups and security context to control access.
256
+ #
257
+ # The keys in each keyring searched are checked for a match before any
258
+ # child keyrings are recursed into. Only keys that are searchable for
259
+ # the caller may be found, and only searchable keyrings may be searched.
260
+ #
261
+ # If the key is not found then, if +callout_info+ is not nil, this
262
+ # function will attempt to look further afield. In such a case, the
263
+ # +callout_info+ is passed to a user-space service such as
264
+ # +/sbin/request-key+ to generate the key.
265
+ #
266
+ # If that is unsuccessful also, then an error will be raised, and a
267
+ # temporary negative key will be installed in the keyring. This
268
+ # will expire after a few seconds, but will cause subsequent calls to
269
+ # {#request} to fail until it does.
270
+ #
271
+ # If a key is created, no matter whether it's a valid key or a negative
272
+ # key, it will displace any other key of the same type and description
273
+ # from the keyring.
274
+ # @param type [Symbol] key type
275
+ # @param description [String] key description
276
+ # @param callout_info [String, nil] additional parameters for the
277
+ # request-key(8) facility
278
+ # @return [Key, nil] the key, if found
279
+ # @raise [Errno::EACCES] the keyring wasn't available for modification by the user
280
+ # @raise [Errno::EINTR] the request was interrupted by a signal
281
+ # @raise [Errno::EDQUOT] the key quota for this user would be exceeded by creating this key or linking it to the keyring
282
+ # @raise [Errno::EKEYEXPIRED] an expired key was found, but no replacement could be obtained
283
+ # @raise [Errno::EKEYREJECTED] the attempt to generate a new key was rejected
284
+ # @raise [Errno::EKEYREVOKED] a revoked key was found, but no replacement could be obtained
285
+ # @raise [Errno::ENOMEM] insufficient memory to create a key
286
+ # @see Keyring#search
287
+ # @see http://man7.org/linux/man-pages/man2/request_key.2.html request_key(2)
288
+ # @see #assume_authority
289
+ def request type, description, callout_info = ''
290
+ serial = Lib.request_key \
291
+ type.to_s,
292
+ description,
293
+ callout_info,
294
+ to_i
295
+ new_dispatch serial, type.intern, description
296
+ rescue Errno::ENOKEY
297
+ nil
298
+ end
299
+
300
+ # Get a member "user" key
301
+ #
302
+ # Searches the members of the keyring for a :user type key with the
303
+ # given +description+
304
+ #
305
+ # @param description [String] description of the key to find
306
+ # @return [Key, nil] the key, if found
307
+ def [] description
308
+ find do |key|
309
+ key.type == :user && key.description == description rescue false
310
+ end
311
+ end
312
+
313
+ # Set a member "user" key
314
+ #
315
+ # Updates or creates a member key of type "user" and given description
316
+ #
317
+ # @param description [String] the description of the key to update or
318
+ # create
319
+ # @param payload [String] the new key payload
320
+ # @return [String] +payload+
321
+ def []= description, payload
322
+ add :user, description, payload
323
+ end
324
+
325
+ # Return all "user" subkeys
326
+ #
327
+ # Keys that cannot be read are ommited.
328
+ #
329
+ # @return [{String => String}] user keys' descriptions and their payloads
330
+ def to_h
331
+ keys = find_all { |k| k.type == :user rescue false }
332
+ pairs = keys.map { |k| [k.description, k.to_s] rescue nil }
333
+ Hash[*pairs.compact.flatten]
334
+ end
335
+
336
+ class << self
337
+ # Set the implicit destination keyring
338
+ #
339
+ # Sets the default destination for implicit key requests for the current
340
+ # thread.
341
+ #
342
+ # After this operation has been issued, keys acquired by implicit key
343
+ # requests, such as might be performed by open() on an AFS or NFS
344
+ # filesystem, will be linked by default to the specified keyring by this
345
+ # function.
346
+ #
347
+ # Only one of the special keyrings can be set as default:
348
+ # - {Thread}
349
+ # - {Process}
350
+ # - {Session}
351
+ # - {User}
352
+ # - {UserSession}
353
+ # - {Group}
354
+ #
355
+ # If +keyring+ is nil, the default behaviour is selected, which is to
356
+ # use the thread-specific keyring if there is one, otherwise the
357
+ # process-specific keyring if there is one, otherwise the session
358
+ # keyring if there is one, otherwise the UID-specific session keyring.
359
+ #
360
+ # @param keyring [Keyring, nil] the new default keyring
361
+ # @return [Keyring, nil] +keyring+
362
+ # @see .default
363
+ def default= keyring = nil
364
+ id = keyring.to_i
365
+ raise ArgumentError, 'only special keyrings can be default' \
366
+ if id > 0
367
+ Lib.keyctl_set_reqkey_keyring -id
368
+ end
369
+
370
+ # Get the implicit destination keyring
371
+ #
372
+ # Gets the default destination for implicit key requests for the current
373
+ # thread.
374
+ #
375
+ # Keys acquired by implicit key requests, such as might be performed
376
+ # by open() on an AFS or NFS filesystem, will be linked by default to
377
+ # that keyring.
378
+ #
379
+ # Only one of the special keyrings can be returned:
380
+ # - {Thread}
381
+ # - {Process}
382
+ # - {Session}
383
+ # - {User}
384
+ # - {UserSession}
385
+ # - {Group}
386
+ #
387
+ # If nil is returned, the default behaviour is selected, which is to
388
+ # use the thread-specific keyring if there is one, otherwise the
389
+ # process-specific keyring if there is one, otherwise the session
390
+ # keyring if there is one, otherwise the UID-specific session keyring.
391
+ #
392
+ # @return [Keyring, nil] the default keyring
393
+ # @see .default=
394
+ def default
395
+ [nil, Thread, Process, Session, User, UserSession, Group]\
396
+ [Lib.keyctl_set_reqkey_keyring -1]
397
+ end
398
+
399
+ # Get the persistent keyring for a user.
400
+ #
401
+ # @note Not every system supports persistent keyrings.
402
+ #
403
+ # Unlike the session and user keyrings, this keyring will persist once
404
+ # all login sessions have been deleted and can thus be used to carry
405
+ # authentication tokens for processes that run without user interaction,
406
+ # such as programs started by cron.
407
+ #
408
+ # The persistent keyring will be created by the kernel if it does not
409
+ # yet exist. Each time this function is called, the persistent keyring
410
+ # will have its expiration timeout reset to the value in
411
+ # +/proc/sys/kernel/keys/persistent_keyring_expiry+ (by default three
412
+ # days). Should the timeout be reached, the persistent keyring will be
413
+ # removed and everything it pins can then be garbage collected.
414
+ #
415
+ # If UID is nil then the calling process's real user ID will be used. If
416
+ # UID is not nil then {Errno::EPERM} will be raised if the user ID
417
+ # requested does not match either the caller's real or effective user
418
+ # IDs or if the calling process does not have _SetUid_ capability.
419
+ #
420
+ # If successful, a link to the persistent keyring will be added into
421
+ # +destination+.
422
+ #
423
+ # @param uid [Fixnum, nil] UID of the user for which the persistent
424
+ # keyring is requested
425
+ # @param destination [Keyring, nil] keyring to add the persistent keyring
426
+ # to
427
+ # @return [Keyring] the persistent keyring
428
+ # @raise [Errno::EPERM] not permitted to access the persistent keyring
429
+ # for the requested UID.
430
+ # @raise [Errno::ENOMEM] insufficient memory to create the persistent
431
+ # keyring or to extend +destination+.
432
+ # @raise [Errno::ENOKEY] +destination+ does not exist.
433
+ # @raise [Errno::EKEYEXPIRED] +destination+ has expired.
434
+ # @raise [Errno::EKEYREVOKED] +destination+ has been revoked.
435
+ # @raise [Errno::EDQUOT] the user does not have sufficient quota to
436
+ # extend +destination+.
437
+ # @raise [Errno::EACCES] +destination+ exists, but does not grant write
438
+ # permission to the calling process.
439
+ # @raise [Errno::EOPNOTSUPP] persistent keyrings are not supported by this
440
+ # system
441
+ def persistent uid = nil, destination = nil
442
+ Keyring.send \
443
+ :new,
444
+ Lib.keyctl_get_persistent(uid || -1, destination.to_i),
445
+ nil,
446
+ nil
447
+ end
448
+ end
449
+ end
450
+
451
+ # This module contains the additional methods included in {Keyutils::Keyring::Session}.
452
+ module SessionKeyring
453
+ # Join a different session keyring
454
+ #
455
+ # Change the session keyring to which a process is subscribed.
456
+ #
457
+ # If +name+ is nil then a new anonymous keyring will be created, and the
458
+ # process will be subscribed to that.
459
+ #
460
+ # If +name+ is provided, then if a keyring of that name is available,
461
+ # the process will attempt to subscribe to that keyring, raising an
462
+ # error if that is not permitted; otherwise a new keyring of that name
463
+ # is created and attached as the session keyring.
464
+ #
465
+ # To attach to an extant named keyring, the keyring must have search
466
+ # permission available to the calling process.
467
+ # @param name [String, nil] name of the keyring to join
468
+ # @return [Keyring] the keyring found or created
469
+ # @raise [Errno::ENOMEM] insufficient memory to create a key
470
+ # @raise [Errno::EDQUOT] the key quota for this user would be exceeded
471
+ # by creating this key or linking it to the keyring
472
+ # @raise [Errno::EACCES] the named keyring exists, but is not searchable
473
+ # by the calling process
474
+ def join name = nil
475
+ Keyring.send :new, Lib.keyctl_join_session_keyring(name), name
476
+ end
477
+
478
+ # Set the parent process's session keyring.
479
+ #
480
+ # Changes the session keyring to which the calling process's parent
481
+ # subscribes to be the that of the calling process.
482
+ #
483
+ # The keyring must have link permission available to the calling process,
484
+ # the parent process must have the same UIDs/GIDs as the calling process,
485
+ # and the LSM must not reject the replacement. Furthermore, this may not
486
+ # be used to affect init or a kernel thread.
487
+ #
488
+ # Note that the replacement will not take immediate effect upon the parent
489
+ # process, but will rather be deferred to the next time it returns to
490
+ # userspace from kernel space.
491
+ #
492
+ # @return [Keyring] self
493
+ # @raise [Errno::ENOMEM] insufficient memory to create a key.
494
+ # @raise [Errno::EPERM] the credentials of the parent don't match those of
495
+ # the caller.
496
+ # @raise [Errno::EACCES] the named keyring exists, but is not linkable by
497
+ # the calling process.
498
+ def to_parent
499
+ Lib.keyctl_session_to_parent
500
+ self
501
+ end
502
+ end
503
+
504
+ KeyTypes[:keyring] = Keyring
505
+
506
+ class Keyring
507
+ # thread-specific keyring
508
+ Thread = Keyring.new Lib::KEY_SPEC[:THREAD_KEYRING], nil
509
+
510
+ # process-specific keyring
511
+ Process = Keyring.new Lib::KEY_SPEC[:PROCESS_KEYRING], nil
512
+
513
+ # session-specific keyring
514
+ # @see Keyutils::SessionKeyring
515
+ Session = Keyring.new(Lib::KEY_SPEC[:SESSION_KEYRING], nil).
516
+ extend SessionKeyring
517
+
518
+ # UID-specific keyring
519
+ User = Keyring.new Lib::KEY_SPEC[:USER_KEYRING], nil
520
+
521
+ # UID-session keyring
522
+ UserSession = Keyring.new Lib::KEY_SPEC[:USER_SESSION_KEYRING], nil
523
+
524
+ # GID-specific keyring
525
+ Group = Keyring.new Lib::KEY_SPEC[:GROUP_KEYRING], nil
526
+ end
527
+ end