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