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