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