keyutils 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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