Initial import
[py-rsbac] / rsbac / um.py
1 # -*- coding:utf-8 -*-
2
3 # py-rsbac - RSBAC Python bindings
4 # Copyright (C) 2006  Frederic Jolliton <pyrsbac@tuxee.net>
5
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20 __all__ = [
21     'User' , 'users' ,
22     'Group' , 'groups' ]
23
24 def export( o ) :
25     if not isinstance( o , basestring ) :
26         name = o.__name__
27     else :
28         name , o = o , None
29     if name in __all__ :
30         raise ImportError , 'duplicate name %r in module %r' % ( name , __name__ )
31     __all__.append( name )
32     return o
33
34 from ctypes import byref
35
36 from rsbac import lib, headers, transaction
37 from rsbac._utils import stringToByteArray, aptr, slowButCorrectStringAssignation
38 from rsbac._utils import fetch, intToTtl, ttlToInt
39 from rsbac.errors import Error, raiseIfError
40
41 g_umModData = headers.rsbac_um_mod_data_t()
42 g_umModDataRef = byref( g_umModData )
43
44 # Duplicated in transaction.py
45 g_NO_USER = -3
46 g_ALL_USERS = -4
47 g_NO_GROUP = -3
48 g_ALL_GROUPS = -4
49
50 @export
51 def auth( user , password ) :
52     """Authenticate.
53
54     user -- username as string
55     password -- password as string
56
57     """
58     if isinstance( user , ( int , long ) ) :
59         raiseIfError( lib.rsbac_um_auth_uid( user , password ) )
60     else :
61         raiseIfError( lib.rsbac_um_auth_name( user , password ) )
62
63 def _makeDefaultUserEntry() :
64     userEntry = headers.rsbac_um_user_entry_t()
65     for field , value in [
66         ( 'name' , '' ) ,
67         ( 'pass' , '' ) ,
68         ( 'fullname' , '' ) ,
69         ( 'homedir' , '/home' ) ,
70         ( 'shell' , '/bin/sh' ) ,
71         ] :
72         slowButCorrectStringAssignation( userEntry , field , value )
73     userEntry.group      =  65534
74     userEntry.lastchange = 100000
75     userEntry.minchange  =      0
76     userEntry.maxchange  =    365
77     userEntry.warnchange =     10
78     userEntry.inactive   =      3
79     userEntry.expire     = 100000
80     return userEntry
81
82 def _makeDefaultGroupEntry() :
83     groupEntry = headers.rsbac_um_group_entry_t()
84     groupEntry.name = ''
85     setattr( groupEntry , 'pass' , '' ) # because 'pass' is a keyword
86     return groupEntry
87
88 @export
89 def addUser( name , uid = None , password = None , ttl = None ) :
90     """Add a user to the UM module.
91
92     name -- username as string
93     uid -- None or a prefered UID as integer
94     password -- None or a default password as string
95     ttl -- None or an integer
96
97     Returns the UID of the newly created user.
98
99     """
100     if uid is None :
101         uid = g_NO_USER
102     ttl = ttlToInt( ttl )
103     userEntry = _makeDefaultUserEntry()
104     slowButCorrectStringAssignation( userEntry , 'name' , name )
105     raiseIfError( lib.rsbac_um_add_user( transaction._t , uid ,
106                                          byref( userEntry ) , password ,
107                                          ttl ) )
108     # Let's hope that there are no race conditions at this point.
109     return getUid( name )
110
111 @export
112 def addGroup( name , gid = None , password = None , ttl = None ) :
113     """Add a group to the UM module.
114
115     name -- group name as string
116     gid -- None or a prefered GID as integer
117     password -- None or a default password as string
118     ttl -- None or an integer
119
120     """
121     if gid is None :
122         gid = g_NO_GROUP
123     ttl = ttlToInt( ttl )
124     groupEntry = _makeDefaultGroupEntry()
125     slowButCorrectStringAssignation( groupEntry , 'name' , name )
126     raiseIfError( lib.rsbac_um_add_group( transaction._t , gid ,
127                                           byref( groupEntry ) , password ,
128                                           ttl ) )
129     # Let's hope that there are no race conditions at this point.
130     return getGid( name )
131
132 @export
133 def addToGroups( uid , gid , ttl = None ) :
134     """Add an UM user to an UM group.
135
136     uid -- UID as integer
137     gid -- GID as integer
138     ttl -- None or an integer
139
140     """
141     ttl = ttlToInt( ttl )
142     raiseIfError( lib.rsbac_um_add_gm( transaction._t , uid , gid , ttl ) )
143
144 @export
145 def removeUser( uid ) :
146     """Remove an UM user.
147
148     uid -- UID as integer
149
150     """
151     raiseIfError( lib.rsbac_um_remove_user( transaction._t , uid ) )
152
153 @export
154 def removeGroup( gid ) :
155     """Remove an UM group.
156
157     gid -- GID as integer
158
159     """
160     raiseIfError( lib.rsbac_um_remove_group( transaction._t , gid ) )
161
162 @export
163 def removeFromGroups( uid , gid ) :
164     """Remove an UM user from an UM group.
165
166     uid -- UID as integer
167     gid -- GID as integer
168
169     """
170     raiseIfError( lib.rsbac_um_remove_gm( transaction._t , uid , gid ) )
171
172 @export
173 def userExists( uid ) :
174     """Test if an UM user exists.
175
176     uid -- UID as integer
177
178     Returns a boolean.
179
180     """
181     return bool( raiseIfError( lib.rsbac_um_user_exists( transaction._t , uid ) ) )
182
183 @export
184 def groupExists( gid ) :
185     """Test if an UM group exists.
186
187     gid -- GID as integer
188
189     Returns a boolean.
190
191     """
192     return bool( raiseIfError( lib.rsbac_um_group_exists( transaction._t , gid ) ) )
193
194 @export
195 def getNextUser( uid = None ) :
196     """Get the user following the one given in argument.
197
198     uid -- None (to get the first user) or an UID as integer
199
200     Returns an UID as integer.
201
202     """
203     if uid is None :
204         uid = g_NO_USER
205     value = headers.rsbac_uid_t()
206     raiseIfError( lib.rsbac_um_get_next_user( transaction._t , uid , byref( value ) ) )
207     return int( value.value )
208
209 @export
210 def getUserList() :
211     """Get the list of all UM users.
212
213     Returns a list of UID.
214
215     """
216     arr = fetch( headers.rsbac_uid_t ,
217                  lambda n , a : lib.rsbac_um_get_user_list( transaction._t , a , n ) )
218     return sorted( map( int , arr ) )
219
220 @export
221 def getGroupsList( uid ) :
222     """Get the extra groups to which an UM user belong.
223
224     uid -- an UID as integer
225
226     Returns a list of GID.
227
228     """
229     arr = fetch( headers.rsbac_gid_t ,
230                  lambda n , a : lib.rsbac_um_get_gm_list( transaction._t , uid , a , n ) )
231     return sorted( map( int , arr ) )
232
233 @export
234 def getGroupsUserList( gid ) :
235     """Get the users which are in an extra group.
236
237     gid -- GID as integer
238
239     Returns a list of UID.
240
241     """
242     arr = fetch( headers.rsbac_uid_t ,
243                  lambda n , a : lib.rsbac_um_get_gm_user_list( transaction._t , gid , a , n ) )
244     return sorted( map( int , arr ) )
245
246 @export
247 def getGroupList() :
248     """Get the list of all UM groups.
249
250     Returns a list of GID.
251
252     """
253     arr = fetch( headers.rsbac_gid_t ,
254                  lambda n , a : lib.rsbac_um_get_group_list( transaction._t , a , n ) )
255     return sorted( map( int , arr ) )
256
257 @export
258 def getUid( name ) :
259     """Get the UID from the username.
260
261     name -- username as string
262
263     Returns the UID as integer.
264
265     """
266     value = headers.rsbac_uid_t()
267     raiseIfError( lib.rsbac_um_get_uid( transaction._t , name , byref( value ) ) )
268     return int( value.value )
269
270 @export
271 def getGid( name ) :
272     """Get the GID from the group name.
273
274     name -- group name as string
275
276     """
277     value = headers.rsbac_gid_t()
278     raiseIfError( lib.rsbac_um_get_gid( transaction._t , name , byref( value ) ) )
279     return int( value.value )
280
281 @export
282 def getUserName( uid ) :
283     """Get the name of an UM user.
284
285     uid -- UID as integer
286
287     Returns the username as string.
288
289     """
290     raiseIfError( lib.rsbac_um_get_user_item( transaction._t , uid ,
291                                               headers.UM_name ,
292                                               g_umModDataRef ) )
293     return g_umModData.string
294
295 @export
296 def setUserName( uid , name ) :
297     """Set the name of an UM user.
298
299     uid -- UID as integer
300     name -- username as string
301
302     """
303     g_umModData.string = name
304     raiseIfError( lib.rsbac_um_mod_user( transaction._t , uid ,
305                                          headers.UM_name ,
306                                          g_umModDataRef ) )
307
308 @export
309 def getUserHashedPassword( uid ) :
310     """Get the user hashed password.
311
312     uid -- UID as integer
313
314     Returns the hashed password.
315
316     """
317     raiseIfError( lib.rsbac_um_get_user_item( transaction._t , uid ,
318                                               headers.UM_pass ,
319                                               g_umModDataRef ) )
320     return g_umModData.string
321
322 @export
323 def setUserHashedPassword( uid , password ) :
324     """Set the user hashed password.
325
326     uid -- UID as integer
327     password -- hashed password as string
328
329     """
330     slowButCorrectStringAssignation( g_umModData , 'string' , password )
331     raiseIfError( lib.rsbac_um_mod_user( transaction._t , uid ,
332                                          headers.UM_cryptpass ,
333                                          g_umModDataRef ) )
334
335 @export
336 def setUserPassword( uid , password ) :
337     """Set the user password.
338
339     uid -- UID as integer
340     password -- password as string
341
342     """
343     slowButCorrectStringAssignation( g_umModData , 'string' , password )
344     raiseIfError( lib.rsbac_um_mod_user( transaction._t , uid ,
345                                          headers.UM_pass ,
346                                          g_umModDataRef ) )
347
348 @export
349 def getUserFullname( uid ) :
350     """Get the full name of an UM user.
351
352     uid -- UID as integer
353
354     Returns the full name as string.
355
356     """
357     data = headers.rsbac_um_mod_data_t()
358     raiseIfError( lib.rsbac_um_get_user_item( transaction._t , uid ,
359                                               headers.UM_fullname ,
360                                               g_umModDataRef ) )
361     return g_umModData.string
362
363 @export
364 def setUserFullname( uid , name ) :
365     """Set the full name of an UM user.
366
367     uid -- UID as integer
368     name -- full name as string
369
370     """
371     slowButCorrectStringAssignation( g_umModData , 'string' , name )
372     raiseIfError( lib.rsbac_um_mod_user( transaction._t , uid ,
373                                          headers.UM_fullname ,
374                                          g_umModDataRef ) )
375
376 @export
377 def getUserHomeDirectory( uid ) :
378     """Get the home directory of an UM user.
379
380     uid -- UID as integer
381
382     Returns the home directory as string.
383
384     """
385     raiseIfError( lib.rsbac_um_get_user_item( transaction._t , uid ,
386                                               headers.UM_homedir ,
387                                               g_umModDataRef ) )
388     return g_umModData.string
389
390 @export
391 def setUserHomeDirectory( uid , directory ) :
392     """Set the home directory of an UM user.
393
394     uid -- UID as integer
395     directory -- directory as string
396
397     """
398     data = headers.rsbac_um_mod_data_t()
399     slowButCorrectStringAssignation( g_umModData , 'string' , directory )
400     raiseIfError( lib.rsbac_um_mod_user( transaction._t , uid ,
401                                          headers.UM_homedir ,
402                                          g_umModDataRef ) )
403
404 @export
405 def getUserShell( uid ) :
406     """Get the shell of an UM user.
407
408     uid -- UID as integer
409
410     Returns the shell path as string.
411
412     """
413     raiseIfError( lib.rsbac_um_get_user_item( transaction._t , uid ,
414                                               headers.UM_shell ,
415                                               g_umModDataRef ) )
416     return g_umModData.string
417
418 @export
419 def setUserShell( uid , shell ) :
420     """Set the shell of an UM user.
421
422     uid -- UID as integer
423     shell -- shell path as string
424
425     """
426     slowButCorrectStringAssignation( g_umModData , 'string' , shell )
427     raiseIfError( lib.rsbac_um_mod_user( transaction._t , uid ,
428                                          headers.UM_shell ,
429                                          g_umModDataRef ) )
430
431 @export
432 def getUserGroup( uid ) :
433     """Get the group of an UM user.
434
435     uid -- UID as integer
436
437     Returns the GID as integer.
438
439     """
440     raiseIfError( lib.rsbac_um_get_user_item( transaction._t , uid ,
441                                               headers.UM_group ,
442                                               g_umModDataRef ) )
443     return int( g_umModData.group )
444
445 @export
446 def setUserGroup( uid , group ) :
447     """Set the group of an UM user.
448
449     uid -- UID as integer
450     group -- GID as integer
451
452     """
453     g_umModData.group = int( group )
454     raiseIfError( lib.rsbac_um_mod_user( transaction._t , uid ,
455                                          headers.UM_group ,
456                                          g_umModDataRef ) )
457
458 @export
459 def getUserTtl( uid ) :
460     """Get the TTL of an UM user.
461
462     uid -- UID as integer
463
464     Returns either None (no TTL) or a non-negative integer.
465
466     """
467     raiseIfError( lib.rsbac_um_get_user_item( transaction._t , uid ,
468                                               headers.UM_ttl ,
469                                               g_umModDataRef ) )
470     return intToTtl( g_umModData.ttl )
471
472 @export
473 def setUserTtl( uid , ttl ) :
474     """Set the TTL of an UM user.
475
476     uid -- UID as integer
477     ttl -- None or an integer.
478
479     """
480     g_umModData.ttl = ttl
481     raiseIfError( lib.rsbac_um_mod_user( transaction._t , uid ,
482                                          headers.UM_ttl ,
483                                          g_umModDataRef ) )
484
485 @export
486 def updateUserPassword( uid , old , new ) :
487     """Update the password of an UM user.
488
489     uid -- UID as integer
490     old -- previous password as string
491     new -- new password as string
492
493     """
494     raiseIfError( lib.rsbac_um_set_pass( uid , old , new ) )
495
496 @export
497 def updateUserPasswordByName( name , old , new ) :
498     """Update the password of an UM user.
499
500     name -- username as string
501     old -- previous password as string
502     new -- new password as string
503
504     """
505     raiseIfError( lib.rsbac_um_set_pass( name , old , new ) )
506
507 @export
508 def checkAccount( uid ) :
509     """Check an UM user account.
510
511     Check if an account password is still valid and have not
512     expired. If not, an exception is thrown.
513
514     uid -- UID as integer
515
516     """
517     raiseIfError( lib.rsbac_um_check_account( uid ) )
518
519 @export
520 def checkAccountByName( name ) :
521     """Check an UM user account.
522
523     Check if an account password is still valid and have not
524     expired. If not, an exception is thrown.
525
526     name -- username as string
527
528     """
529     raiseIfError( lib.rsbac_um_check_account_name( name ) )
530
531 @export
532 def getGroupName( gid ) :
533     """Get the name of an UM group.
534
535     gid -- GID as integer
536
537     Returns the group name as string.
538
539     """
540     raiseIfError( lib.rsbac_um_get_group_item( transaction._t , gid ,
541                                                headers.UM_name ,
542                                                g_umModDataRef ) )
543     return g_umModData.string
544
545 @export
546 def setGroupName( gid , name ) :
547     """Set the name of an UM group.
548
549     gid -- GID as integer
550     name -- group name as string
551
552     """
553     slowButCorrectStringAssignation( g_umModData , 'string' , name )
554     raiseIfError( lib.rsbac_um_mod_group( transaction._t , gid ,
555                                           headers.UM_name ,
556                                           g_umModDataRef ) )
557
558 @export
559 def getGroupHashedPassword( gid ) :
560     """Get the hashed password of an UM group.
561
562     gid -- GID as integer
563
564     Returns the hashed password as string.
565
566     """
567     raiseIfError( lib.rsbac_um_get_group_item( transaction._t , self.id ,
568                                                headers.UM_pass ,
569                                                g_umModDataRef ) )
570     return g_umModData.string
571
572 @export
573 def setGroupHashedPassword( gid , password ) :
574     """Set the hashed password of an UM group.
575
576     gid -- GID as integer
577     password -- hashed password as string
578
579     """
580     slowButCorrectStringAssignation( g_umModData , 'string' , password )
581     raiseIfError( lib.rsbac_um_mod_group( transaction._t , gid ,
582                                           headers.UM_cryptpass ,
583                                           g_umModDataRef ) )
584
585 @export
586 def setGroupPassword( gid , password ) :
587     """Set the password of an UM group.
588
589     gid -- GID as integer
590     passowrd -- password as string
591
592     """
593     raiseIfError( lib.rsbac_um_set_group_pass( gid , password ) )
594
595 @export
596 def setGroupPasswordItem( gid , password ) :
597     """Set the password of an UM group.
598
599     gid -- GID as integer
600     password -- password as string
601
602     """
603     slowButCorrectStringAssignation( g_umModData , 'string' , password )
604     raiseIfError( lib.rsbac_um_mod_group( transaction._t , gid ,
605                                           headers.UM_pass ,
606                                           g_umModDataRef ) )
607
608 @export
609 def getGroupTtl( gid ) :
610     """Get the TTL of an UM group
611
612     gid -- GID as integer
613
614     Returns None or a positive integer.
615
616     """
617     raiseIfError( lib.rsbac_um_get_group_item( transaction._t , gid ,
618                                                headers.UM_ttl ,
619                                                g_umModDataRef ) )
620     return intToTtl( g_umModData.ttl )
621
622 @export
623 def setGroupTtl( gid , ttl ) :
624     """Set the TTL of an UM group
625
626     gid -- GID as integer
627     ttl -- None or an integer.
628
629     """
630     g_umModData.ttl = ttl
631     raiseIfError( lib.rsbac_um_mod_group( transaction._t , gid ,
632                                           headers.UM_ttl ,
633                                           g_umModDataRef ) )
634
635
636 class UserGroups( object ) :
637     def __init__( self , uid ) :
638         self._uid = uid
639     def __iter__( self ) :
640         return iter( getGroupsList( self._uid ) )
641     def __repr__( self ) :
642         return '<Groups for user %d: %s>' % ( self._uid , list( self ) or 'none' )
643     def add( self , gid , ttl = None ) :
644         addToGroups( self._uid , gid , ttl )
645     def discard( self , gid ) :
646         removeFromGroups( self._uid , gid )
647     def clear( self ) :
648         map( self.discard , self )
649
650 class UserBase( object ) :
651     def __init__( self , uid ) :
652         self.id = uid
653         self.groups = UserGroups( self.id )
654     def __int__( self ) :
655         return int( self.id )
656     def __long__( self ) :
657         return long( self.id )
658     def __repr__( self ) :
659         try :
660             name = `self.getName()`
661         except Error , e :
662             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
663                 raise
664             name = 'undefined'
665         try :
666             ttl = self.getTtl()
667             if ttl is not None :
668                 ttl = ' (%ds)' % ttl
669             else :
670                 ttl = ''
671         except Error , e :
672             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
673                 raise
674             ttl = ' (?)'
675         return '<UM User [%d]%s %s>' % ( self.id , ttl , name )
676     #
677     # name
678     #
679     def getName( self ) :
680         return getUserName( self.id )
681     def setName( self , name ) :
682         try :
683             return setUserName( self.id , name )
684         except Error , e :
685             if e[ 0 ] != 1009 :
686                 raise
687             addUser( name , self.id )
688     name = property( getName , setName )
689     #
690     # password (hashed)
691     #
692     # UT: get(UM_pass) == set(UM_pass)?
693     def getHashedPassword( self ) :
694         return getUserHashedPassword( self.id )
695     def setHashedPassword( self , password ) :
696         return setUserHashedPassword( self.id , password )
697     hashedPassword = property( getHashedPassword , setHashedPassword )
698     #
699     # password
700     #
701     def setPassword( self , password ) :
702         return setUserPassword( self.id , password )
703     password = property( fset = setPassword )
704     #
705     # fullname
706     #
707     def getFullname( self ) :
708         return getUserFullname( self.id )
709     def setFullname( self , name ) :
710         return setUserFullname( self.id , name )
711     fullname = property( getFullname , setFullname )
712     #
713     # homedir
714     #
715     def getHomeDirectory( self ) :
716         return getUserHomeDirectory( self.id )
717     def setHomeDirectory( self , directory ) :
718         return setUserHomeDirectory( self.id , directory )
719     homeDirectory = property( getHomeDirectory , setHomeDirectory )
720     #
721     # shell
722     #
723     def getShell( self ) :
724         return getUserShell( self.id )
725     def setShell( self , shell ) :
726         return setUserShell( self.id , shell )
727     shell = property( getShell , setShell )
728     #
729     # group
730     #
731     def getGroup( self ) :
732         return Group( getUserGroup( self.id ) )
733     def setGroup( self , gid ) :
734         return setUserGroup( self.id , int( gid ) )
735     group = property( getGroup , setGroup )
736     #
737     # TTL
738     #
739     def getTtl( self ) :
740         return getUserTtl( self.id )
741     def setTtl( self , ttl ) :
742         return setUserTtl( self.id , ttl )
743     ttl = property( getTtl , setTtl )
744     #
745     # groups
746     #
747     groups = None
748     #
749     # exists
750     #
751     def getExists( self ) :
752         return userExists( self.id )
753     exists = property( getExists )
754     #
755     # misc
756     #
757     def updatePassword( self , old , new ) :
758         updateUserPassword( self.id , old , new )
759     def delete( self ) :
760         removeUser( self.id )
761
762 def buildUserClass() :
763     attrs = {}
764     def addDaysField( name ) :
765         cname = name[ 0 ].upper() + name[ 1 : ]
766         item = getattr( headers , 'UM_' + name.lower() )
767         def get( self ) :
768             raiseIfError( lib.rsbac_um_get_user_item( transaction._t , self.id ,
769                                                       item ,
770                                                       g_umModDataRef ) )
771             return g_umModData.days
772         def set( self , value ) :
773             g_umModData.days = value
774             raiseIfError( lib.rsbac_um_mod_user( transaction._t , self.id ,
775                                                  item ,
776                                                  g_umModDataRef ) )
777         attrs[ 'get' + cname ] = get
778         attrs[ 'set' + cname ] = set
779         attrs[ name ] = property( get , set )
780     for name in 'lastChange' , 'minChange' , 'maxChange' , 'warnChange' , 'inactive' , 'expire' :
781         addDaysField( name )
782     return type( 'User' , ( UserBase , ) , attrs )
783
784 User = buildUserClass()
785
786 class Group( object ) :
787     def __init__( self , gid ) :
788         self.id = gid
789     def __int__( self ) :
790         return int( self.id )
791     def __long__( self ) :
792         return long( self.id )
793     def __repr__( self ) :
794         try :
795             name = `self.getName()`
796         except Error , e :
797             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
798                 raise
799             name = 'undefined'
800         try :
801             ttl = self.getTtl()
802             if ttl is not None :
803                 ttl = ' (%d)' % ttl
804             else :
805                 ttl = ''
806         except Error , e :
807             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
808                 raise
809             ttl = ' (?)'
810         return '<UM Group [%d]%s %s>' % ( self.id , ttl , name )
811     #
812     # name
813     #
814     def getName( self ) :
815         return getGroupName( self.id )
816     def setName( self , name ) :
817         return setGroupName( self.id , name )
818     name = property( getName , setName )
819     #
820     # password (hashed)
821     #
822     def getHashedPassword( self ) :
823         return getGroupHashedPassword( self.id )
824     def setHashedPassword( self , password ) :
825         return setGroupHashedPassword( self.id , password )
826     hashedPassword = property( getHashedPassword , setHashedPassword )
827     #
828     # password
829     #
830     def setPassword( self , password ) :
831         return setGroupPassword( self.id , password )
832     password = property( fset = setPassword )
833     #
834     # TTL
835     #
836     def getTtl( self ) :
837         return getGroupTtl( self.id )
838     def setTtl( self , ttl ) :
839         return setGroupTtl( self.id , ttl )
840     ttl = property( getTtl , setTtl )
841     #
842     # Extra members
843     #
844     def getExtraMembers( self ) :
845         return tuple( map( User , getGroupsUserList( self.id ) ) )
846     extraMembers = property( getExtraMembers )
847     #
848     # Members
849     #
850     def getMembers( self ) :
851         return tuple( [ User( uid ) for uid in getUserList()
852                         if getUserGroup( uid ) == self.id ] )
853     members = property( getMembers )
854     #
855     # exists
856     #
857     def getExists( self ) :
858         return groupExists( self.id )
859     exists = property( getExists )
860     #
861     # misc
862     #
863     def updatePassword( self , password ) :
864         setGroupPassword( self.id , password )
865     def delete( self ) :
866         removeGroup( self.id )
867
868 class UmUserDict( object ) :
869     def __iter__( self ) :
870         return iter( getUserList() )
871     def __delitem__( self , uid ) :
872         removeUser( uid )
873     def __getitem__( self , uid ) :
874         return User( uid )
875     def __repr__( self ) :
876         return '{' + ', '.join( [ ': '.join( map( repr , item ) ) for item in self.items() ] ) + '}'
877     def keys( self ) :
878         return getUserList()
879     def values( self ) :
880         return map( User , self.keys() )
881     def items( self ) :
882         return [ ( uid , User( uid ) ) for uid in self.keys() ]
883     def clear( self ) :
884         map( self.__delitem__ , self )
885
886 users = UmUserDict()
887
888 class UmGroupDict( object ) :
889     def __iter__( self ) :
890         return iter( getGroupList() )
891     def __delitem__( self , gid ) :
892         removeGroup( gid )
893     def __getitem__( self , gid ) :
894         return Group( gid )
895     def __repr__( self ) :
896         return '{' + ', '.join( [ ': '.join( map( repr , item ) ) for item in self.items() ] ) + '}'
897     def keys( self ) :
898         return getGroupList()
899     def values( self ) :
900         return map( Group , self.keys() )
901     def items( self ) :
902         return [ ( gid , Group( gid ) ) for gid in self.keys() ]
903     def clear( self ) :
904         map( self.__delitem__ , self )
905
906 groups = UmGroupDict()
907
908 # Local Variables:
909 # indent-tabs-mode: nil
910 # python-indent: 4
911 # End: