More explicit warning about versions mismatch.
[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, unlimitedTtl
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 = unlimitedTtl ) :
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 -- TTL
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 User( getUid( name ) )
110
111 @export
112 def addGroup( name , gid = None , password = None , ttl = unlimitedTtl ) :
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 -- TTL
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 Group( getGid( name ) )
131
132 @export
133 def addToGroups( uid , gid , ttl = unlimitedTtl ) :
134     """Add an UM user to an UM group.
135
136     uid -- UID as integer
137     gid -- GID as integer
138     ttl -- TTL
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 TTL.
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 -- TTL
478
479     """
480     g_umModData.ttl = ttlToInt( 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 TTL.
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 -- TTL
628
629     """
630     g_umModData.ttl = ttlToInt( 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     __slots__ = ( '_uid' , )
638     def __init__( self , uid ) :
639         self._uid = uid
640     def __iter__( self ) :
641         return iter( getGroupsList( self._uid ) )
642     def __repr__( self ) :
643         return '<Groups for user %d: %s>' % ( self._uid , list( self ) or 'none' )
644     def add( self , gid , ttl = unlimitedTtl ) :
645         addToGroups( self._uid , int( gid ) , ttl )
646     def discard( self , gid ) :
647         removeFromGroups( self._uid , int( gid ) )
648     def clear( self ) :
649         map( self.discard , self )
650
651 class UserBase( object ) :
652     __slots__ = ( 'id' , 'groups' )
653     def __init__( self , uid ) :
654         self.id = uid
655         self.groups = UserGroups( self.id )
656     def __int__( self ) :
657         return int( self.id )
658     def __long__( self ) :
659         return long( self.id )
660     def __repr__( self ) :
661         try :
662             name = `self.getName()`
663         except Error , e :
664             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
665                 raise
666             name = 'undefined'
667         try :
668             ttl = self.getTtl()
669             if ttl is True :
670                 ttl = ''
671             else :
672                 ttl = ' (%ds)' % ttl
673         except Error , e :
674             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
675                 raise
676             ttl = ' (?)'
677         return '<UM User [%d]%s %s>' % ( self.id , ttl , name )
678     #
679     # name
680     #
681     def getName( self ) :
682         return getUserName( self.id )
683     def setName( self , name ) :
684         try :
685             return setUserName( self.id , name )
686         except Error , e :
687             if e[ 0 ] != 1009 :
688                 raise
689             addUser( name , self.id )
690     name = property( getName , setName )
691     #
692     # password (hashed)
693     #
694     # UT: get(UM_pass) == set(UM_pass)?
695     def getHashedPassword( self ) :
696         return getUserHashedPassword( self.id )
697     def setHashedPassword( self , password ) :
698         return setUserHashedPassword( self.id , password )
699     hashedPassword = property( getHashedPassword , setHashedPassword )
700     #
701     # password
702     #
703     def setPassword( self , password ) :
704         return setUserPassword( self.id , password )
705     password = property( fset = setPassword )
706     #
707     # fullname
708     #
709     def getFullname( self ) :
710         return getUserFullname( self.id )
711     def setFullname( self , name ) :
712         return setUserFullname( self.id , name )
713     fullname = property( getFullname , setFullname )
714     #
715     # homedir
716     #
717     def getHomeDirectory( self ) :
718         return getUserHomeDirectory( self.id )
719     def setHomeDirectory( self , directory ) :
720         return setUserHomeDirectory( self.id , directory )
721     homeDirectory = property( getHomeDirectory , setHomeDirectory )
722     #
723     # shell
724     #
725     def getShell( self ) :
726         return getUserShell( self.id )
727     def setShell( self , shell ) :
728         return setUserShell( self.id , shell )
729     shell = property( getShell , setShell )
730     #
731     # group
732     #
733     def getGroup( self ) :
734         return Group( getUserGroup( self.id ) )
735     def setGroup( self , gid ) :
736         return setUserGroup( self.id , int( gid ) )
737     group = property( getGroup , setGroup )
738     #
739     # TTL
740     #
741     def getTtl( self ) :
742         return getUserTtl( self.id )
743     def setTtl( self , ttl ) :
744         return setUserTtl( self.id , ttl )
745     ttl = property( getTtl , setTtl )
746     #
747     # exists
748     #
749     def getExists( self ) :
750         return userExists( self.id )
751     exists = property( getExists )
752     #
753     # misc
754     #
755     def updatePassword( self , old , new ) :
756         updateUserPassword( self.id , old , new )
757     def delete( self ) :
758         removeUser( self.id )
759
760 def buildUserClass() :
761     attrs = { '__slots__' : () }
762     def addDaysField( name ) :
763         cname = name[ 0 ].upper() + name[ 1 : ]
764         item = getattr( headers , 'UM_' + name.lower() )
765         def get( self ) :
766             raiseIfError( lib.rsbac_um_get_user_item( transaction._t , self.id ,
767                                                       item ,
768                                                       g_umModDataRef ) )
769             return g_umModData.days
770         def set( self , value ) :
771             g_umModData.days = value
772             raiseIfError( lib.rsbac_um_mod_user( transaction._t , self.id ,
773                                                  item ,
774                                                  g_umModDataRef ) )
775         attrs[ 'get' + cname ] = get
776         attrs[ 'set' + cname ] = set
777         attrs[ name ] = property( get , set )
778     for name in 'lastChange' , 'minChange' , 'maxChange' , 'warnChange' , 'inactive' , 'expire' :
779         addDaysField( name )
780     return type( 'User' , ( UserBase , ) , attrs )
781
782 User = buildUserClass()
783
784 class Group( object ) :
785     __slots__ = ( 'id' , )
786     def __init__( self , gid ) :
787         self.id = gid
788     def __int__( self ) :
789         return int( self.id )
790     def __long__( self ) :
791         return long( self.id )
792     def __repr__( self ) :
793         try :
794             name = `self.getName()`
795         except Error , e :
796             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
797                 raise
798             name = 'undefined'
799         try :
800             ttl = self.getTtl()
801             if ttl is True :
802                 ttl = ''
803             else :
804                 ttl = ' (%d)' % ttl
805         except Error , e :
806             if e[ 0 ] != headers.RSBAC_ENOTFOUND :
807                 raise
808             ttl = ' (?)'
809         return '<UM Group [%d]%s %s>' % ( self.id , ttl , name )
810     #
811     # name
812     #
813     def getName( self ) :
814         return getGroupName( self.id )
815     def setName( self , name ) :
816         return setGroupName( self.id , name )
817     name = property( getName , setName )
818     #
819     # password (hashed)
820     #
821     def getHashedPassword( self ) :
822         return getGroupHashedPassword( self.id )
823     def setHashedPassword( self , password ) :
824         return setGroupHashedPassword( self.id , password )
825     hashedPassword = property( getHashedPassword , setHashedPassword )
826     #
827     # password
828     #
829     def setPassword( self , password ) :
830         return setGroupPassword( self.id , password )
831     password = property( fset = setPassword )
832     #
833     # TTL
834     #
835     def getTtl( self ) :
836         return intToTtl( getGroupTtl( self.id ) )
837     def setTtl( self , ttl ) :
838         return setGroupTtl( self.id , ttlToInt( ttl ) )
839     ttl = property( getTtl , setTtl )
840     #
841     # Members
842     #
843     def getMembers( self ) :
844         return tuple( [ User( uid ) for uid in getUserList()
845                         if getUserGroup( uid ) == self.id ] )
846     members = property( getMembers )
847     #
848     # Extra members
849     #
850     def getExtraMembers( self ) :
851         return tuple( map( User , getGroupsUserList( self.id ) ) )
852     extraMembers = property( getExtraMembers )
853     #
854     # exists
855     #
856     def getExists( self ) :
857         return groupExists( self.id )
858     exists = property( getExists )
859     #
860     # misc
861     #
862     def updatePassword( self , password ) :
863         setGroupPassword( self.id , password )
864     def delete( self ) :
865         removeGroup( self.id )
866
867 class UmUserDict( object ) :
868     __slots__ = ()
869     def __len__( self ) :
870         return len( self.keys() )
871     def __contains__( self , uid ) :
872         return self.has_key( uid )
873     def __iter__( self ) :
874         return iter( getUserList() )
875     def __delitem__( self , uid ) :
876         removeUser( uid )
877     def __getitem__( self , uid ) :
878         return User( uid )
879     def __repr__( self ) :
880         return '{' + ', '.join( [ ': '.join( map( repr , item ) ) for item in self.items() ] ) + '}'
881     def has_key( self , uid ) :
882         # fixme: return User( uid ).exists instead?
883         return uid in self.keys()
884     def keys( self ) :
885         return getUserList()
886     def values( self ) :
887         return map( User , self.keys() )
888     def items( self ) :
889         return [ ( uid , User( uid ) ) for uid in self.keys() ]
890     def clear( self ) :
891         map( self.__delitem__ , self )
892
893 users = UmUserDict()
894
895 class UmGroupDict( object ) :
896     __slots__ = ()
897     def __len__( self ) :
898         return len( self.keys() )
899     def __iter__( self ) :
900         return iter( getGroupList() )
901     def __delitem__( self , gid ) :
902         removeGroup( gid )
903     def __getitem__( self , gid ) :
904         return Group( gid )
905     def __repr__( self ) :
906         return '{' + ', '.join( [ ': '.join( map( repr , item ) ) for item in self.items() ] ) + '}'
907     def has_key( self , gid ) :
908         return gid in self.keys()
909     def keys( self ) :
910         return getGroupList()
911     def values( self ) :
912         return map( Group , self.keys() )
913     def items( self ) :
914         return [ ( gid , Group( gid ) ) for gid in self.keys() ]
915     def clear( self ) :
916         map( self.__delitem__ , self )
917
918 groups = UmGroupDict()
919
920 # Local Variables:
921 # indent-tabs-mode: nil
922 # python-indent: 4
923 # End: