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