Add a ListEntry option for getting more information about an entity.
[invirt/packages/python-afs.git] / afs / _pts.pyx
1 from afs cimport *
2
3 cdef import from "afs/ptuser.h":
4     enum:
5         PR_MAXNAMELEN
6         PRGRP
7         ANONYMOUSID
8
9     ctypedef char prname[PR_MAXNAMELEN]
10
11     struct namelist:
12         unsigned int namelist_len
13         prname *namelist_val
14
15     struct prlist:
16         unsigned int prlist_len
17         afs_int32 *prlist_val
18
19     struct idlist:
20         unsigned int idlist_len
21         afs_int32 *idlist_val
22
23     struct prcheckentry:
24         afs_int32 flags
25         afs_int32 id
26         afs_int32 owner
27         afs_int32 creator
28         afs_int32 ngroups
29         afs_int32 nusers
30         afs_int32 count
31         afs_int32 reserved[5]
32         char name[PR_MAXNAMELEN]
33
34     int ubik_PR_NameToID(ubik_client *, afs_int32, namelist *, idlist *)
35     int ubik_PR_IDToName(ubik_client *, afs_int32, idlist *, namelist *)
36     int ubik_PR_INewEntry(ubik_client *, afs_int32, char *, afs_int32, afs_int32)
37     int ubik_PR_NewEntry(ubik_client *, afs_int32, char *, afs_int32, afs_int32, afs_int32 *)
38     int ubik_PR_Delete(ubik_client *, afs_int32, afs_int32)
39     int ubik_PR_AddToGroup(ubik_client *, afs_int32, afs_int32, afs_int32)
40     int ubik_PR_RemoveFromGroup(ubik_client *, afs_int32, afs_int32, afs_int32)
41     int ubik_PR_ListElements(ubik_client *, afs_int32, afs_int32, prlist *, afs_int32 *)
42     int ubik_PR_ListOwned(ubik_client *, afs_int32, afs_int32, prlist *, afs_int32 *)
43     int ubik_PR_ListEntry(ubik_client *, afs_int32, afs_int32, prcheckentry *)
44
45 cdef import from "afs/pterror.h":
46     enum:
47         PRNOENT
48         PRTOOMANY
49
50     void initialize_PT_error_table()
51
52 cdef class PTEntry:
53     cdef public afs_int32 flags
54     cdef public afs_int32 id
55     cdef public afs_int32 owner
56     cdef public afs_int32 creator
57     cdef public afs_int32 ngroups
58     cdef public afs_int32 nusers
59     cdef public afs_int32 count
60     cdef afs_int32 reserved[5]
61     cdef public char * name
62
63 cdef int _ptentry_from_c(PTEntry p_entry, prcheckentry c_entry) except -1:
64     if p_entry is None:
65         raise TypeError
66         return -1
67
68     p_entry.flags = c_entry.flags
69     p_entry.id = c_entry.id
70     p_entry.owner = c_entry.owner
71     p_entry.creator = c_entry.creator
72     p_entry.ngroups = c_entry.ngroups
73     p_entry.nusers = c_entry.nusers
74     p_entry.count = c_entry.count
75     memcpy(p_entry.reserved, c_entry.reserved, sizeof(p_entry.reserved))
76     p_entry.name = c_entry.name
77     return 0
78
79 cdef int _ptentry_to_c(prcheckentry * c_entry, PTEntry p_entry) except -1:
80     if p_entry is None:
81         raise TypeError
82         return -1
83
84     c_entry.flags = p_entry.flags
85     c_entry.id = p_entry.id
86     c_entry.owner = p_entry.owner
87     c_entry.creator = p_entry.creator
88     c_entry.ngroups = p_entry.ngroups
89     c_entry.nusers = p_entry.nusers
90     c_entry.count = p_entry.count
91     memcpy(c_entry.reserved, p_entry.reserved, sizeof(p_entry.reserved))
92     strncpy(c_entry.name, p_entry.name, sizeof(c_entry.name))
93     return 0
94
95 cdef class PTS:
96     """
97     A PTS object is essentially a handle to talk to the server in a
98     given cell.
99
100     cell defaults to None. If no argument is passed for cell, PTS
101     connects to the home cell.
102
103     sec is the security level, an integer from 0 to 3:
104       - 0: unauthenticated connection
105       - 1: try authenticated, then fall back to unauthenticated
106       - 2: fail if an authenticated connection can't be established
107       - 3: same as 2, plus encrypt all traffic to the protection
108         server
109     """
110     cdef ubik_client * client
111
112     def __cinit__(self, cell=None, sec=1):
113         cdef afs_int32 code
114         cdef afsconf_dir *cdir
115         cdef afsconf_cell info
116         cdef char * c_cell
117         cdef ktc_principal prin
118         cdef ktc_token token
119         cdef rx_securityClass *sc
120         cdef rx_connection *serverconns[MAXSERVERS]
121         cdef int i
122
123         initialize_PT_error_table()
124
125         if cell is None:
126             c_cell = NULL
127         else:
128             c_cell = cell
129
130         self.client = NULL
131
132         code = rx_Init(0)
133         if code != 0:
134             raise Exception(code, "Error initializing Rx")
135
136         cdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH)
137         if cdir is NULL:
138             raise OSError(errno,
139                           "Error opening configuration directory (%s): %s" % \
140                               (AFSDIR_CLIENT_ETC_DIRPATH, strerror(errno)))
141         code = afsconf_GetCellInfo(cdir, c_cell, "afsprot", &info)
142         if code != 0:
143             raise Exception(code, "GetCellInfo: %s" % afs_error_message(code))
144
145         if sec > 0:
146             strncpy(prin.cell, info.name, sizeof(prin.cell))
147             prin.instance[0] = 0
148             strncpy(prin.name, "afs", sizeof(prin.name))
149
150             code = ktc_GetToken(&prin, &token, sizeof(token), NULL);
151             if code != 0:
152                 if sec >= 2:
153                     # No really - we wanted authentication
154                     raise Exception(code, "Failed to get token for service AFS: %s" % afs_error_message(code))
155                 sec = 0
156             else:
157                 if sec == 3:
158                     level = rxkad_crypt
159                 else:
160                     level = rxkad_clear
161                 sc = rxkad_NewClientSecurityObject(level, &token.sessionKey,
162                                                    token.kvno, token.ticketLen,
163                                                    token.ticket)
164
165         if sec == 0:
166             sc = rxnull_NewClientSecurityObject()
167         else:
168             sec = 2
169
170         memset(serverconns, 0, sizeof(serverconns))
171         for 0 <= i < info.numServers:
172             serverconns[i] = rx_NewConnection(info.hostAddr[i].sin_addr.s_addr,
173                                               info.hostAddr[i].sin_port,
174                                               PRSRV,
175                                               sc,
176                                               sec)
177
178         code = ubik_ClientInit(serverconns, &self.client)
179         if code != 0:
180             raise Exception("Failed to initialize ubik connection to Protection server: %s" % afs_error_message(code))
181
182         code = rxs_Release(sc)
183
184     def __dealloc__(self):
185         ubik_ClientDestroy(self.client)
186         rx_Finalize()
187
188     def NameToId(self, name):
189         """
190         Converts a user or group to an AFS ID.
191         """
192         cdef namelist lnames
193         cdef idlist lids
194         cdef afs_int32 code, id
195         name = name.lower()
196
197         lids.idlist_len = 0
198         lids.idlist_val = NULL
199         lnames.namelist_len = 1
200         lnames.namelist_val = <prname *>malloc(PR_MAXNAMELEN)
201         strncpy(lnames.namelist_val[0], name, PR_MAXNAMELEN)
202         code = ubik_PR_NameToID(self.client, 0, &lnames, &lids)
203         if lids.idlist_val is not NULL:
204             id = lids.idlist_val[0]
205             free(lids.idlist_val)
206         if id == ANONYMOUSID:
207             code = PRNOENT
208         if code != 0:
209             raise Exception("Failed to lookup PTS name: %s" % afs_error_message(code))
210         return id
211
212     def IdToName(self, id):
213         """
214         Convert an AFS ID to the name of a user or group.
215         """
216         cdef namelist lnames
217         cdef idlist lids
218         cdef afs_int32 code
219         cdef char name[PR_MAXNAMELEN]
220
221         lids.idlist_len = 1
222         lids.idlist_val = <afs_int32 *>malloc(sizeof(afs_int32))
223         lids.idlist_val[0] = id
224         lnames.namelist_len = 0
225         lnames.namelist_val = NULL
226         code = ubik_PR_IDToName(self.client, 0, &lids, &lnames)
227         if lnames.namelist_val is not NULL:
228             strncpy(name, lnames.namelist_val[0], sizeof(name))
229             free(lnames.namelist_val)
230         if lids.idlist_val is not NULL:
231             free(lids.idlist_val)
232         if name == str(id):
233             code = PRNOENT
234         if code != 0:
235             raise Exception("Failed to lookup PTS ID: %s" % afs_error_message(code))
236         return name
237
238     def CreateUser(self, name, id=None):
239         """
240         Create a new user in the protection database. If an ID is
241         provided, that one will be used.
242         """
243         cdef afs_int32 code
244         cdef afs_int32 cid
245         name = name[:PR_MAXNAMELEN].lower()
246
247         if id is not None:
248             cid = id
249
250         if id is not None:
251             code = ubik_PR_INewEntry(self.client, 0, name, cid, 0)
252         else:
253             code = ubik_PR_NewEntry(self.client, 0, name, 0, 0, &cid)
254
255         if code != 0:
256             raise Exception("Failed to create user: %s" % afs_error_message(code))
257         return cid
258
259     def CreateGroup(self, name, owner, id=None):
260         """
261         Create a new group in the protection database. If an ID is
262         provided, that one will be used.
263         """
264         cdef afs_int32 code, cid
265
266         name = name[:PR_MAXNAMELEN].lower()
267         oid = self.NameToId(owner)
268
269         if id is not None:
270             cid = id
271             code = ubik_PR_INewEntry(self.client, 0, name, cid, oid)
272         else:
273             code = ubik_PR_NewEntry(self.client, 0, name, PRGRP, oid, &cid)
274
275         if code != 0:
276             raise Exception("Failed to create group: %s" % afs_error_message(code))
277         return cid
278
279     def Delete(self, id):
280         """
281         Delete the protection database entry with the provided ID.
282         """
283         cdef afs_int32 code
284
285         code = ubik_PR_Delete(self.client, 0, id)
286         if code != 0:
287             raise Exception("Failed to delete user: %s" % afs_error_message(code))
288
289     def AddToGroup(self, uid, gid):
290         """
291         Add the user with the given ID to the group with the given ID.
292         """
293         cdef afs_int32 code
294
295         code = ubik_PR_AddToGroup(self.client, 0, uid, gid)
296         if code != 0:
297             raise Exception("Failed to add user to group: %s" % afs_error_message(code))
298
299     def RemoveFromGroup(self, uid, gid):
300         """
301         Remove the user with the given ID from the group with the given ID.
302         """
303         cdef afs_int32 code
304
305         code = ubik_PR_RemoveFromGroup(self.client, 0, uid, gid)
306         if code != 0:
307             raise Exception("Failed to remove user from group: %s" % afs_error_message(code))
308
309     def ListMembers(self, id):
310         """
311         Get the membership of an entity.
312
313         If id is a group ID, this returns the users that are in that
314         group.
315
316         If id is a user ID, this returns the list of groups that user
317         is on.
318
319         This returns a list of PTS IDs.
320         """
321         cdef afs_int32 code, over
322         cdef prlist alist
323         cdef int i
324         cdef object members = []
325
326         alist.prlist_len = 0
327         alist.prlist_val = NULL
328
329         code = ubik_PR_ListElements(self.client, 0, id, &alist, &over)
330
331         if alist.prlist_val is not NULL:
332             for i in range(alist.prlist_len):
333                 members.append(alist.prlist_val[i])
334             free(alist.prlist_val)
335
336         if over:
337             code = PRTOOMANY
338         if code != 0:
339             raise Exception("Failed to get group membership: %s" % afs_error_message(code))
340
341         return members
342
343     def ListOwned(self, oid):
344         """
345         Get all groups owned by an entity.
346         """
347         cdef afs_int32 code, over
348         cdef prlist alist
349         cdef int i
350         cdef object owned = []
351
352         alist.prlist_len = 0
353         alist.prlist_val = NULL
354
355         code = ubik_PR_ListOwned(self.client, 0, oid, &alist, &over)
356
357         if alist.prlist_val is not NULL:
358             for i in range(alist.prlist_len):
359                 owned.append(alist.prlist_val[i])
360             free(alist.prlist_val)
361
362         if over:
363             code = PRTOOMANY
364         if code != 0:
365             raise Exception("Failed to get owned entities: %s" % afs_error_message(code))
366
367         return owned
368
369     def ListEntry(self, id):
370         """
371         Load a PTEntry instance with information about the provided
372         ID.
373         """
374         cdef afs_int32 code
375         cdef prcheckentry centry
376         cdef object entry = PTEntry()
377
378         code = ubik_PR_ListEntry(self.client, 0, id, &centry)
379         if code != 0:
380             raise Exception("Error getting entity info: %s" % afs_error_message(code))
381
382         _ptentry_from_c(entry, centry)
383         return entry