| 1 | from afs._util cimport * |
|---|
| 2 | from afs._util import pyafs_error |
|---|
| 3 | import re |
|---|
| 4 | |
|---|
| 5 | cdef extern from "afs/ptuser.h": |
|---|
| 6 | enum: |
|---|
| 7 | PR_MAXNAMELEN |
|---|
| 8 | PRGRP |
|---|
| 9 | PRUSERS |
|---|
| 10 | PRGROUPS |
|---|
| 11 | ANONYMOUSID |
|---|
| 12 | PR_SF_ALLBITS |
|---|
| 13 | PR_SF_NGROUPS |
|---|
| 14 | PR_SF_NUSERS |
|---|
| 15 | |
|---|
| 16 | ctypedef char prname[PR_MAXNAMELEN] |
|---|
| 17 | |
|---|
| 18 | struct namelist: |
|---|
| 19 | unsigned int namelist_len |
|---|
| 20 | prname *namelist_val |
|---|
| 21 | |
|---|
| 22 | struct prlist: |
|---|
| 23 | unsigned int prlist_len |
|---|
| 24 | afs_int32 *prlist_val |
|---|
| 25 | |
|---|
| 26 | struct idlist: |
|---|
| 27 | unsigned int idlist_len |
|---|
| 28 | afs_int32 *idlist_val |
|---|
| 29 | |
|---|
| 30 | struct prcheckentry: |
|---|
| 31 | afs_int32 flags |
|---|
| 32 | afs_int32 id |
|---|
| 33 | afs_int32 owner |
|---|
| 34 | afs_int32 creator |
|---|
| 35 | afs_int32 ngroups |
|---|
| 36 | afs_int32 nusers |
|---|
| 37 | afs_int32 count |
|---|
| 38 | char name[PR_MAXNAMELEN] |
|---|
| 39 | |
|---|
| 40 | struct prlistentries: |
|---|
| 41 | afs_int32 flags |
|---|
| 42 | afs_int32 id |
|---|
| 43 | afs_int32 owner |
|---|
| 44 | afs_int32 creator |
|---|
| 45 | afs_int32 ngroups |
|---|
| 46 | afs_int32 nusers |
|---|
| 47 | afs_int32 count |
|---|
| 48 | char name[PR_MAXNAMELEN] |
|---|
| 49 | |
|---|
| 50 | struct prentries: |
|---|
| 51 | unsigned int prentries_len |
|---|
| 52 | prlistentries *prentries_val |
|---|
| 53 | |
|---|
| 54 | int ubik_PR_NameToID(ubik_client *, afs_int32, namelist *, idlist *) |
|---|
| 55 | int ubik_PR_IDToName(ubik_client *, afs_int32, idlist *, namelist *) |
|---|
| 56 | int ubik_PR_INewEntry(ubik_client *, afs_int32, char *, afs_int32, afs_int32) |
|---|
| 57 | int ubik_PR_NewEntry(ubik_client *, afs_int32, char *, afs_int32, afs_int32, afs_int32 *) |
|---|
| 58 | int ubik_PR_Delete(ubik_client *, afs_int32, afs_int32) |
|---|
| 59 | int ubik_PR_AddToGroup(ubik_client *, afs_int32, afs_int32, afs_int32) |
|---|
| 60 | int ubik_PR_RemoveFromGroup(ubik_client *, afs_int32, afs_int32, afs_int32) |
|---|
| 61 | int ubik_PR_ListElements(ubik_client *, afs_int32, afs_int32, prlist *, afs_int32 *) |
|---|
| 62 | int ubik_PR_ListOwned(ubik_client *, afs_int32, afs_int32, prlist *, afs_int32 *) |
|---|
| 63 | int ubik_PR_ListEntry(ubik_client *, afs_int32, afs_int32, prcheckentry *) |
|---|
| 64 | int ubik_PR_ChangeEntry(ubik_client *, afs_int32, afs_int32, char *, afs_int32, afs_int32) |
|---|
| 65 | int ubik_PR_IsAMemberOf(ubik_client *, afs_int32, afs_int32, afs_int32, afs_int32 *) |
|---|
| 66 | int ubik_PR_ListMax(ubik_client *, afs_int32, afs_int32 *, afs_int32 *) |
|---|
| 67 | int ubik_PR_SetMax(ubik_client *, afs_int32, afs_int32, afs_int32) |
|---|
| 68 | int ubik_PR_ListEntries(ubik_client *, afs_int32, afs_int32, afs_int32, prentries *, afs_int32 *) |
|---|
| 69 | int ubik_PR_SetFieldsEntry(ubik_client *, afs_int32, afs_int32, afs_int32, afs_int32, afs_int32, afs_int32, afs_int32, afs_int32) |
|---|
| 70 | |
|---|
| 71 | cdef extern from "afs/pterror.h": |
|---|
| 72 | enum: |
|---|
| 73 | PRNOENT |
|---|
| 74 | |
|---|
| 75 | cdef extern from "krb5/krb5.h": |
|---|
| 76 | struct _krb5_context: |
|---|
| 77 | pass |
|---|
| 78 | struct krb5_principal_data: |
|---|
| 79 | pass |
|---|
| 80 | |
|---|
| 81 | ctypedef _krb5_context * krb5_context |
|---|
| 82 | ctypedef krb5_principal_data * krb5_principal |
|---|
| 83 | |
|---|
| 84 | ctypedef long krb5_int32 |
|---|
| 85 | ctypedef krb5_int32 krb5_error_code |
|---|
| 86 | krb5_error_code krb5_init_context(krb5_context *) |
|---|
| 87 | krb5_error_code krb5_parse_name(krb5_context, char *, krb5_principal *) |
|---|
| 88 | krb5_error_code krb5_unparse_name(krb5_context, krb5_principal, char **) |
|---|
| 89 | krb5_error_code krb5_524_conv_principal(krb5_context, krb5_principal, char *, char *, char *) |
|---|
| 90 | krb5_error_code krb5_425_conv_principal(krb5_context, char *, char *, char *, krb5_principal *) |
|---|
| 91 | krb5_error_code krb5_get_host_realm(krb5_context, char *, char ***) |
|---|
| 92 | void krb5_free_host_realm(krb5_context, char **) |
|---|
| 93 | void krb5_free_principal(krb5_context, krb5_principal) |
|---|
| 94 | void krb5_free_context(krb5_context) |
|---|
| 95 | |
|---|
| 96 | cdef class PTEntry: |
|---|
| 97 | cdef public afs_int32 flags |
|---|
| 98 | cdef public afs_int32 id |
|---|
| 99 | cdef public afs_int32 owner |
|---|
| 100 | cdef public afs_int32 creator |
|---|
| 101 | cdef public afs_int32 ngroups |
|---|
| 102 | cdef public afs_int32 nusers |
|---|
| 103 | cdef public afs_int32 count |
|---|
| 104 | cdef public object name |
|---|
| 105 | |
|---|
| 106 | def __repr__(self): |
|---|
| 107 | if self.name != '': |
|---|
| 108 | return '<PTEntry: %s>' % self.name |
|---|
| 109 | else: |
|---|
| 110 | return '<PTEntry: PTS ID %s>' % self.id |
|---|
| 111 | |
|---|
| 112 | cdef int _ptentry_from_c(PTEntry p_entry, prcheckentry * c_entry) except -1: |
|---|
| 113 | if p_entry is None: |
|---|
| 114 | raise TypeError |
|---|
| 115 | return -1 |
|---|
| 116 | |
|---|
| 117 | p_entry.flags = c_entry.flags |
|---|
| 118 | p_entry.id = c_entry.id |
|---|
| 119 | p_entry.owner = c_entry.owner |
|---|
| 120 | p_entry.creator = c_entry.creator |
|---|
| 121 | p_entry.ngroups = c_entry.ngroups |
|---|
| 122 | p_entry.nusers = c_entry.nusers |
|---|
| 123 | p_entry.count = c_entry.count |
|---|
| 124 | p_entry.name = c_entry.name |
|---|
| 125 | return 0 |
|---|
| 126 | |
|---|
| 127 | cdef int _ptentry_to_c(prcheckentry * c_entry, PTEntry p_entry) except -1: |
|---|
| 128 | if p_entry is None: |
|---|
| 129 | raise TypeError |
|---|
| 130 | return -1 |
|---|
| 131 | |
|---|
| 132 | c_entry.flags = p_entry.flags |
|---|
| 133 | c_entry.id = p_entry.id |
|---|
| 134 | c_entry.owner = p_entry.owner |
|---|
| 135 | c_entry.creator = p_entry.creator |
|---|
| 136 | c_entry.ngroups = p_entry.ngroups |
|---|
| 137 | c_entry.nusers = p_entry.nusers |
|---|
| 138 | c_entry.count = p_entry.count |
|---|
| 139 | strncpy(c_entry.name, p_entry.name, sizeof(c_entry.name)) |
|---|
| 140 | return 0 |
|---|
| 141 | |
|---|
| 142 | cdef object kname_re = re.compile(r'^([^.].*?)(?<!\\)(?:\.(.*?))?(?<!\\)@([^@]*)$') |
|---|
| 143 | |
|---|
| 144 | cdef object kname_parse(fullname): |
|---|
| 145 | """Parse a krb4-style principal into a name, instance, and realm.""" |
|---|
| 146 | cdef object re_match = kname_re.match(fullname) |
|---|
| 147 | if not re_match: |
|---|
| 148 | return None |
|---|
| 149 | else: |
|---|
| 150 | princ = re_match.groups() |
|---|
| 151 | return tuple([re.sub(r'\\(.)', r'\1', x) if x else x for x in princ]) |
|---|
| 152 | |
|---|
| 153 | cdef object kname_unparse(name, inst, realm): |
|---|
| 154 | """Unparse a name, instance, and realm into a single krb4 |
|---|
| 155 | principal string.""" |
|---|
| 156 | name = re.sub('r([.\\@])', r'\\\1', name) |
|---|
| 157 | inst = re.sub('r([.\\@])', r'\\\1', inst) |
|---|
| 158 | realm = re.sub(r'([\\@])', r'\\\1', realm) |
|---|
| 159 | if inst: |
|---|
| 160 | return '%s.%s@%s' % (name, inst, realm) |
|---|
| 161 | else: |
|---|
| 162 | return '%s@%s' % (name, realm) |
|---|
| 163 | |
|---|
| 164 | cdef class PTS: |
|---|
| 165 | """ |
|---|
| 166 | A PTS object is essentially a handle to talk to the server in a |
|---|
| 167 | given cell. |
|---|
| 168 | |
|---|
| 169 | cell defaults to None. If no argument is passed for cell, PTS |
|---|
| 170 | connects to the home cell. |
|---|
| 171 | |
|---|
| 172 | sec is the security level, an integer from 0 to 3: |
|---|
| 173 | - 0: unauthenticated connection |
|---|
| 174 | - 1: try authenticated, then fall back to unauthenticated |
|---|
| 175 | - 2: fail if an authenticated connection can't be established |
|---|
| 176 | - 3: same as 2, plus encrypt all traffic to the protection |
|---|
| 177 | server |
|---|
| 178 | |
|---|
| 179 | The realm attribute is the Kerberos realm against which this cell |
|---|
| 180 | authenticates. |
|---|
| 181 | """ |
|---|
| 182 | cdef ubik_client * client |
|---|
| 183 | cdef readonly object cell |
|---|
| 184 | cdef readonly object realm |
|---|
| 185 | |
|---|
| 186 | def __cinit__(self, cell=None, sec=1): |
|---|
| 187 | cdef afs_int32 code |
|---|
| 188 | cdef afsconf_dir *cdir |
|---|
| 189 | cdef afsconf_cell info |
|---|
| 190 | cdef krb5_context context |
|---|
| 191 | cdef char ** hrealms = NULL |
|---|
| 192 | cdef char * c_cell |
|---|
| 193 | cdef ktc_principal prin |
|---|
| 194 | cdef ktc_token token |
|---|
| 195 | cdef rx_securityClass *sc |
|---|
| 196 | cdef rx_connection *serverconns[MAXSERVERS] |
|---|
| 197 | cdef int i |
|---|
| 198 | |
|---|
| 199 | initialize_PT_error_table() |
|---|
| 200 | |
|---|
| 201 | if cell is None: |
|---|
| 202 | c_cell = NULL |
|---|
| 203 | else: |
|---|
| 204 | c_cell = cell |
|---|
| 205 | |
|---|
| 206 | self.client = NULL |
|---|
| 207 | |
|---|
| 208 | code = rx_Init(0) |
|---|
| 209 | if code != 0: |
|---|
| 210 | raise Exception(code, "Error initializing Rx") |
|---|
| 211 | |
|---|
| 212 | cdir = afsconf_Open(AFSDIR_CLIENT_ETC_DIRPATH) |
|---|
| 213 | if cdir is NULL: |
|---|
| 214 | raise OSError(errno, |
|---|
| 215 | "Error opening configuration directory (%s): %s" % \ |
|---|
| 216 | (AFSDIR_CLIENT_ETC_DIRPATH, strerror(errno))) |
|---|
| 217 | code = afsconf_GetCellInfo(cdir, c_cell, "afsprot", &info) |
|---|
| 218 | pyafs_error(code) |
|---|
| 219 | |
|---|
| 220 | code = krb5_init_context(&context) |
|---|
| 221 | pyafs_error(code) |
|---|
| 222 | code = krb5_get_host_realm(context, info.hostName[0], &hrealms) |
|---|
| 223 | pyafs_error(code) |
|---|
| 224 | self.realm = hrealms[0] |
|---|
| 225 | krb5_free_host_realm(context, hrealms) |
|---|
| 226 | krb5_free_context(context) |
|---|
| 227 | |
|---|
| 228 | self.cell = info.name |
|---|
| 229 | |
|---|
| 230 | if sec > 0: |
|---|
| 231 | strncpy(prin.cell, info.name, sizeof(prin.cell)) |
|---|
| 232 | prin.instance[0] = 0 |
|---|
| 233 | strncpy(prin.name, "afs", sizeof(prin.name)) |
|---|
| 234 | |
|---|
| 235 | code = ktc_GetToken(&prin, &token, sizeof(token), NULL); |
|---|
| 236 | if code != 0: |
|---|
| 237 | if sec >= 2: |
|---|
| 238 | # No really - we wanted authentication |
|---|
| 239 | pyafs_error(code) |
|---|
| 240 | sec = 0 |
|---|
| 241 | else: |
|---|
| 242 | if sec == 3: |
|---|
| 243 | level = rxkad_crypt |
|---|
| 244 | else: |
|---|
| 245 | level = rxkad_clear |
|---|
| 246 | sc = rxkad_NewClientSecurityObject(level, &token.sessionKey, |
|---|
| 247 | token.kvno, token.ticketLen, |
|---|
| 248 | token.ticket) |
|---|
| 249 | |
|---|
| 250 | if sec == 0: |
|---|
| 251 | sc = rxnull_NewClientSecurityObject() |
|---|
| 252 | else: |
|---|
| 253 | sec = 2 |
|---|
| 254 | |
|---|
| 255 | memset(serverconns, 0, sizeof(serverconns)) |
|---|
| 256 | for 0 <= i < info.numServers: |
|---|
| 257 | serverconns[i] = rx_NewConnection(info.hostAddr[i].sin_addr.s_addr, |
|---|
| 258 | info.hostAddr[i].sin_port, |
|---|
| 259 | PRSRV, |
|---|
| 260 | sc, |
|---|
| 261 | sec) |
|---|
| 262 | |
|---|
| 263 | code = ubik_ClientInit(serverconns, &self.client) |
|---|
| 264 | pyafs_error(code) |
|---|
| 265 | |
|---|
| 266 | code = rxs_Release(sc) |
|---|
| 267 | |
|---|
| 268 | def __dealloc__(self): |
|---|
| 269 | ubik_ClientDestroy(self.client) |
|---|
| 270 | rx_Finalize() |
|---|
| 271 | |
|---|
| 272 | def _NameOrId(self, ident): |
|---|
| 273 | """ |
|---|
| 274 | Given an identifier, convert it to a PTS ID by looking up the |
|---|
| 275 | name if it's a string, or otherwise just converting it to an |
|---|
| 276 | integer. |
|---|
| 277 | """ |
|---|
| 278 | if isinstance(ident, basestring): |
|---|
| 279 | return self._NameToId(ident) |
|---|
| 280 | else: |
|---|
| 281 | return int(ident) |
|---|
| 282 | |
|---|
| 283 | def _NameToId(self, name): |
|---|
| 284 | """ |
|---|
| 285 | Converts a user or group to an AFS ID. |
|---|
| 286 | """ |
|---|
| 287 | cdef namelist lnames |
|---|
| 288 | cdef idlist lids |
|---|
| 289 | cdef afs_int32 code, id = ANONYMOUSID |
|---|
| 290 | name = name.lower() |
|---|
| 291 | |
|---|
| 292 | lids.idlist_len = 0 |
|---|
| 293 | lids.idlist_val = NULL |
|---|
| 294 | lnames.namelist_len = 1 |
|---|
| 295 | lnames.namelist_val = <prname *>malloc(PR_MAXNAMELEN) |
|---|
| 296 | strncpy(lnames.namelist_val[0], name, PR_MAXNAMELEN) |
|---|
| 297 | code = ubik_PR_NameToID(self.client, 0, &lnames, &lids) |
|---|
| 298 | if lids.idlist_val is not NULL: |
|---|
| 299 | id = lids.idlist_val[0] |
|---|
| 300 | free(lids.idlist_val) |
|---|
| 301 | if id == ANONYMOUSID: |
|---|
| 302 | code = PRNOENT |
|---|
| 303 | pyafs_error(code) |
|---|
| 304 | return id |
|---|
| 305 | |
|---|
| 306 | def _IdToName(self, id): |
|---|
| 307 | """ |
|---|
| 308 | Convert an AFS ID to the name of a user or group. |
|---|
| 309 | """ |
|---|
| 310 | cdef namelist lnames |
|---|
| 311 | cdef idlist lids |
|---|
| 312 | cdef afs_int32 code |
|---|
| 313 | cdef char name[PR_MAXNAMELEN] |
|---|
| 314 | |
|---|
| 315 | lids.idlist_len = 1 |
|---|
| 316 | lids.idlist_val = <afs_int32 *>malloc(sizeof(afs_int32)) |
|---|
| 317 | lids.idlist_val[0] = id |
|---|
| 318 | lnames.namelist_len = 0 |
|---|
| 319 | lnames.namelist_val = NULL |
|---|
| 320 | code = ubik_PR_IDToName(self.client, 0, &lids, &lnames) |
|---|
| 321 | if lnames.namelist_val is not NULL: |
|---|
| 322 | strncpy(name, lnames.namelist_val[0], sizeof(name)) |
|---|
| 323 | free(lnames.namelist_val) |
|---|
| 324 | if lids.idlist_val is not NULL: |
|---|
| 325 | free(lids.idlist_val) |
|---|
| 326 | if name == str(id): |
|---|
| 327 | code = PRNOENT |
|---|
| 328 | pyafs_error(code) |
|---|
| 329 | return name |
|---|
| 330 | |
|---|
| 331 | def _CreateUser(self, name, id=None): |
|---|
| 332 | """ |
|---|
| 333 | Create a new user in the protection database. If an ID is |
|---|
| 334 | provided, that one will be used. |
|---|
| 335 | """ |
|---|
| 336 | cdef afs_int32 code |
|---|
| 337 | cdef afs_int32 cid |
|---|
| 338 | name = name[:PR_MAXNAMELEN].lower() |
|---|
| 339 | |
|---|
| 340 | if id is not None: |
|---|
| 341 | cid = id |
|---|
| 342 | |
|---|
| 343 | if id is not None: |
|---|
| 344 | code = ubik_PR_INewEntry(self.client, 0, name, cid, 0) |
|---|
| 345 | else: |
|---|
| 346 | code = ubik_PR_NewEntry(self.client, 0, name, 0, 0, &cid) |
|---|
| 347 | |
|---|
| 348 | pyafs_error(code) |
|---|
| 349 | return cid |
|---|
| 350 | |
|---|
| 351 | def _CreateGroup(self, name, owner, id=None): |
|---|
| 352 | """ |
|---|
| 353 | Create a new group in the protection database. If an ID is |
|---|
| 354 | provided, that one will be used. |
|---|
| 355 | """ |
|---|
| 356 | cdef afs_int32 code, cid |
|---|
| 357 | |
|---|
| 358 | name = name[:PR_MAXNAMELEN].lower() |
|---|
| 359 | oid = self._NameOrId(owner) |
|---|
| 360 | |
|---|
| 361 | if id is not None: |
|---|
| 362 | cid = id |
|---|
| 363 | code = ubik_PR_INewEntry(self.client, 0, name, cid, oid) |
|---|
| 364 | else: |
|---|
| 365 | code = ubik_PR_NewEntry(self.client, 0, name, PRGRP, oid, &cid) |
|---|
| 366 | |
|---|
| 367 | pyafs_error(code) |
|---|
| 368 | return cid |
|---|
| 369 | |
|---|
| 370 | def _Delete(self, ident): |
|---|
| 371 | """ |
|---|
| 372 | Delete the protection database entry with the provided |
|---|
| 373 | identifier. |
|---|
| 374 | """ |
|---|
| 375 | cdef afs_int32 code |
|---|
| 376 | cdef afs_int32 id = self._NameOrId(ident) |
|---|
| 377 | |
|---|
| 378 | code = ubik_PR_Delete(self.client, 0, id) |
|---|
| 379 | pyafs_error(code) |
|---|
| 380 | |
|---|
| 381 | def _AddToGroup(self, user, group): |
|---|
| 382 | """ |
|---|
| 383 | Add the given user to the given group. |
|---|
| 384 | """ |
|---|
| 385 | cdef afs_int32 code |
|---|
| 386 | cdef afs_int32 uid = self._NameOrId(user), gid = self._NameOrId(group) |
|---|
| 387 | |
|---|
| 388 | code = ubik_PR_AddToGroup(self.client, 0, uid, gid) |
|---|
| 389 | pyafs_error(code) |
|---|
| 390 | |
|---|
| 391 | def _RemoveFromGroup(self, user, group): |
|---|
| 392 | """ |
|---|
| 393 | Remove the given user from the given group. |
|---|
| 394 | """ |
|---|
| 395 | cdef afs_int32 code |
|---|
| 396 | cdef afs_int32 uid = self._NameOrId(user), gid = self._NameOrId(group) |
|---|
| 397 | |
|---|
| 398 | code = ubik_PR_RemoveFromGroup(self.client, 0, uid, gid) |
|---|
| 399 | pyafs_error(code) |
|---|
| 400 | |
|---|
| 401 | def _ListMembers(self, ident): |
|---|
| 402 | """ |
|---|
| 403 | Get the membership of an entity. |
|---|
| 404 | |
|---|
| 405 | If id is a group, this returns the users that are in that |
|---|
| 406 | group. |
|---|
| 407 | |
|---|
| 408 | If id is a user, this returns the list of groups that user is |
|---|
| 409 | on. |
|---|
| 410 | |
|---|
| 411 | This returns a list of PTS IDs. |
|---|
| 412 | """ |
|---|
| 413 | cdef afs_int32 code, over |
|---|
| 414 | cdef prlist alist |
|---|
| 415 | cdef int i |
|---|
| 416 | cdef object members = [] |
|---|
| 417 | |
|---|
| 418 | cdef afs_int32 id = self._NameOrId(ident) |
|---|
| 419 | |
|---|
| 420 | alist.prlist_len = 0 |
|---|
| 421 | alist.prlist_val = NULL |
|---|
| 422 | |
|---|
| 423 | code = ubik_PR_ListElements(self.client, 0, id, &alist, &over) |
|---|
| 424 | |
|---|
| 425 | if alist.prlist_val is not NULL: |
|---|
| 426 | for i in range(alist.prlist_len): |
|---|
| 427 | members.append(alist.prlist_val[i]) |
|---|
| 428 | free(alist.prlist_val) |
|---|
| 429 | |
|---|
| 430 | pyafs_error(code) |
|---|
| 431 | |
|---|
| 432 | return members |
|---|
| 433 | |
|---|
| 434 | def _ListOwned(self, owner): |
|---|
| 435 | """ |
|---|
| 436 | Get all groups owned by an entity. |
|---|
| 437 | """ |
|---|
| 438 | cdef afs_int32 code, over |
|---|
| 439 | cdef prlist alist |
|---|
| 440 | cdef int i |
|---|
| 441 | cdef object owned = [] |
|---|
| 442 | |
|---|
| 443 | cdef afs_int32 oid = self._NameOrId(owner) |
|---|
| 444 | |
|---|
| 445 | alist.prlist_len = 0 |
|---|
| 446 | alist.prlist_val = NULL |
|---|
| 447 | |
|---|
| 448 | code = ubik_PR_ListOwned(self.client, 0, oid, &alist, &over) |
|---|
| 449 | |
|---|
| 450 | if alist.prlist_val is not NULL: |
|---|
| 451 | for i in range(alist.prlist_len): |
|---|
| 452 | owned.append(alist.prlist_val[i]) |
|---|
| 453 | free(alist.prlist_val) |
|---|
| 454 | |
|---|
| 455 | pyafs_error(code) |
|---|
| 456 | |
|---|
| 457 | return owned |
|---|
| 458 | |
|---|
| 459 | def _ListEntry(self, ident): |
|---|
| 460 | """ |
|---|
| 461 | Load a PTEntry instance with information about the provided |
|---|
| 462 | entity. |
|---|
| 463 | """ |
|---|
| 464 | cdef afs_int32 code |
|---|
| 465 | cdef prcheckentry centry |
|---|
| 466 | cdef object entry = PTEntry() |
|---|
| 467 | |
|---|
| 468 | cdef afs_int32 id = self._NameOrId(ident) |
|---|
| 469 | |
|---|
| 470 | code = ubik_PR_ListEntry(self.client, 0, id, ¢ry) |
|---|
| 471 | pyafs_error(code) |
|---|
| 472 | |
|---|
| 473 | _ptentry_from_c(entry, ¢ry) |
|---|
| 474 | return entry |
|---|
| 475 | |
|---|
| 476 | def _ChangeEntry(self, ident, newname=None, newid=None, newoid=None): |
|---|
| 477 | """ |
|---|
| 478 | Change the name, ID, and/or owner of a PTS entity. |
|---|
| 479 | |
|---|
| 480 | For any of newname, newid, and newoid which aren't specified |
|---|
| 481 | or ar None, the value isn't changed. |
|---|
| 482 | """ |
|---|
| 483 | cdef afs_int32 code |
|---|
| 484 | cdef afs_int32 c_newid = 0, c_newoid = 0 |
|---|
| 485 | cdef char * c_newname |
|---|
| 486 | |
|---|
| 487 | cdef afs_int32 id = self._NameOrId(ident) |
|---|
| 488 | |
|---|
| 489 | if newname is None: |
|---|
| 490 | newname = self._IdToName(id) |
|---|
| 491 | c_newname = newname |
|---|
| 492 | if newid is not None: |
|---|
| 493 | c_newid = newid |
|---|
| 494 | if newoid is not None: |
|---|
| 495 | c_newoid = newoid |
|---|
| 496 | |
|---|
| 497 | code = ubik_PR_ChangeEntry(self.client, 0, id, c_newname, c_newoid, c_newid) |
|---|
| 498 | pyafs_error(code) |
|---|
| 499 | |
|---|
| 500 | def _IsAMemberOf(self, user, group): |
|---|
| 501 | """ |
|---|
| 502 | Return True if the given user is a member of the given group. |
|---|
| 503 | """ |
|---|
| 504 | cdef afs_int32 code |
|---|
| 505 | cdef afs_int32 flag |
|---|
| 506 | |
|---|
| 507 | cdef afs_int32 uid = self._NameOrId(user), gid = self._NameOrId(group) |
|---|
| 508 | |
|---|
| 509 | code = ubik_PR_IsAMemberOf(self.client, 0, uid, gid, &flag) |
|---|
| 510 | pyafs_error(code) |
|---|
| 511 | |
|---|
| 512 | return bool(flag) |
|---|
| 513 | |
|---|
| 514 | def _ListMax(self): |
|---|
| 515 | """ |
|---|
| 516 | Return a tuple of the maximum user ID and the maximum group |
|---|
| 517 | ID currently assigned. |
|---|
| 518 | """ |
|---|
| 519 | cdef afs_int32 code, uid, gid |
|---|
| 520 | |
|---|
| 521 | code = ubik_PR_ListMax(self.client, 0, &uid, &gid) |
|---|
| 522 | pyafs_error(code) |
|---|
| 523 | |
|---|
| 524 | return (uid, gid) |
|---|
| 525 | |
|---|
| 526 | def _SetMaxUserId(self, id): |
|---|
| 527 | """ |
|---|
| 528 | Set the maximum currently assigned user ID (the next |
|---|
| 529 | automatically assigned UID will be id + 1) |
|---|
| 530 | """ |
|---|
| 531 | cdef afs_int32 code |
|---|
| 532 | |
|---|
| 533 | code = ubik_PR_SetMax(self.client, 0, id, 0) |
|---|
| 534 | pyafs_error(code) |
|---|
| 535 | |
|---|
| 536 | def _SetMaxGroupId(self, id): |
|---|
| 537 | """ |
|---|
| 538 | Set the maximum currently assigned user ID (the next |
|---|
| 539 | automatically assigned UID will be id + 1) |
|---|
| 540 | """ |
|---|
| 541 | cdef afs_int32 code |
|---|
| 542 | |
|---|
| 543 | code = ubik_PR_SetMax(self.client, 0, id, PRGRP) |
|---|
| 544 | pyafs_error(code) |
|---|
| 545 | |
|---|
| 546 | def _ListEntries(self, users=None, groups=None): |
|---|
| 547 | """ |
|---|
| 548 | Return a list of PTEntry instances representing all entries in |
|---|
| 549 | the PRDB. |
|---|
| 550 | |
|---|
| 551 | Returns just users by default, but can return just users, just |
|---|
| 552 | groups, or both. |
|---|
| 553 | """ |
|---|
| 554 | cdef afs_int32 code |
|---|
| 555 | cdef afs_int32 flag = 0, startindex = 0, nentries, nextstartindex |
|---|
| 556 | cdef prentries centries |
|---|
| 557 | cdef unsigned int i |
|---|
| 558 | |
|---|
| 559 | cdef object entries = [] |
|---|
| 560 | |
|---|
| 561 | if groups is None or users is True: |
|---|
| 562 | flag |= PRUSERS |
|---|
| 563 | if groups: |
|---|
| 564 | flag |= PRGROUPS |
|---|
| 565 | |
|---|
| 566 | while startindex != -1: |
|---|
| 567 | centries.prentries_val = NULL |
|---|
| 568 | centries.prentries_len = 0 |
|---|
| 569 | nextstartindex = -1 |
|---|
| 570 | |
|---|
| 571 | code = ubik_PR_ListEntries(self.client, 0, flag, startindex, ¢ries, &nextstartindex) |
|---|
| 572 | if centries.prentries_val is not NULL: |
|---|
| 573 | for i in range(centries.prentries_len): |
|---|
| 574 | e = PTEntry() |
|---|
| 575 | _ptentry_from_c(e, <prcheckentry *>¢ries.prentries_val[i]) |
|---|
| 576 | entries.append(e) |
|---|
| 577 | free(centries.prentries_val) |
|---|
| 578 | pyafs_error(code) |
|---|
| 579 | |
|---|
| 580 | startindex = nextstartindex |
|---|
| 581 | |
|---|
| 582 | return entries |
|---|
| 583 | |
|---|
| 584 | def _SetFields(self, ident, access=None, groups=None, users=None): |
|---|
| 585 | """ |
|---|
| 586 | Update the fields for an entry. |
|---|
| 587 | |
|---|
| 588 | Valid fields are the privacy flags (access), the group quota |
|---|
| 589 | (groups), or the "foreign user quota" (users), which doesn't |
|---|
| 590 | actually seem to do anything, but is included for |
|---|
| 591 | completeness. |
|---|
| 592 | """ |
|---|
| 593 | cdef afs_int32 code |
|---|
| 594 | cdef afs_int32 mask = 0, flags = 0, nusers = 0, ngroups = 0 |
|---|
| 595 | |
|---|
| 596 | cdef afs_int32 id = self._NameOrId(ident) |
|---|
| 597 | |
|---|
| 598 | if access is not None: |
|---|
| 599 | flags = access |
|---|
| 600 | mask |= PR_SF_ALLBITS |
|---|
| 601 | if groups is not None: |
|---|
| 602 | ngroups = groups |
|---|
| 603 | mask |= PR_SF_NGROUPS |
|---|
| 604 | if users is not None: |
|---|
| 605 | nusers = users |
|---|
| 606 | mask |= PR_SF_NGROUPS |
|---|
| 607 | |
|---|
| 608 | code = ubik_PR_SetFieldsEntry(self.client, 0, id, mask, flags, ngroups, nusers, 0, 0) |
|---|
| 609 | pyafs_error(code) |
|---|
| 610 | |
|---|
| 611 | def _AfsToKrb5(self, afs_name): |
|---|
| 612 | """Convert an AFS principal to a Kerberos v5 one.""" |
|---|
| 613 | cdef krb5_context ctx = NULL |
|---|
| 614 | cdef krb5_principal princ = NULL |
|---|
| 615 | cdef krb5_error_code code = 0 |
|---|
| 616 | cdef char * krb5_princ = NULL |
|---|
| 617 | cdef char *name = NULL, *inst = NULL, *realm = NULL |
|---|
| 618 | cdef object pname, pinst, prealm |
|---|
| 619 | |
|---|
| 620 | if '@' in afs_name: |
|---|
| 621 | pname, prealm = afs_name.rsplit('@', 1) |
|---|
| 622 | prealm = prealm.upper() |
|---|
| 623 | krb4_name = '%s@%s' % (pname, prealm) |
|---|
| 624 | else: |
|---|
| 625 | krb4_name = '%s@%s' % (afs_name, self.realm) |
|---|
| 626 | |
|---|
| 627 | pname, pinst, prealm = kname_parse(krb4_name) |
|---|
| 628 | if pname: |
|---|
| 629 | name = pname |
|---|
| 630 | if pinst: |
|---|
| 631 | inst = pinst |
|---|
| 632 | if prealm: |
|---|
| 633 | realm = prealm |
|---|
| 634 | |
|---|
| 635 | code = krb5_init_context(&ctx) |
|---|
| 636 | try: |
|---|
| 637 | pyafs_error(code) |
|---|
| 638 | |
|---|
| 639 | code = krb5_425_conv_principal(ctx, name, inst, realm, &princ) |
|---|
| 640 | try: |
|---|
| 641 | pyafs_error(code) |
|---|
| 642 | |
|---|
| 643 | code = krb5_unparse_name(ctx, princ, &krb5_princ) |
|---|
| 644 | try: |
|---|
| 645 | pyafs_error(code) |
|---|
| 646 | |
|---|
| 647 | return krb5_princ |
|---|
| 648 | finally: |
|---|
| 649 | if krb5_princ is not NULL: |
|---|
| 650 | free(krb5_princ) |
|---|
| 651 | finally: |
|---|
| 652 | if princ is not NULL: |
|---|
| 653 | krb5_free_principal(ctx, princ) |
|---|
| 654 | finally: |
|---|
| 655 | if ctx is not NULL: |
|---|
| 656 | krb5_free_context(ctx) |
|---|
| 657 | |
|---|
| 658 | def _Krb5ToAfs(self, krb5_name): |
|---|
| 659 | """Convert a Kerberos v5 principal to an AFS one.""" |
|---|
| 660 | cdef krb5_context ctx = NULL |
|---|
| 661 | cdef krb5_principal k5_princ = NULL |
|---|
| 662 | cdef char *k4_name, *k4_inst, *k4_realm |
|---|
| 663 | cdef object afs_princ |
|---|
| 664 | cdef object afs_name, afs_realm |
|---|
| 665 | |
|---|
| 666 | k4_name = <char *>malloc(40) |
|---|
| 667 | k4_name[0] = '\0' |
|---|
| 668 | k4_inst = <char *>malloc(40) |
|---|
| 669 | k4_inst[0] = '\0' |
|---|
| 670 | k4_realm = <char *>malloc(40) |
|---|
| 671 | k4_realm[0] = '\0' |
|---|
| 672 | |
|---|
| 673 | code = krb5_init_context(&ctx) |
|---|
| 674 | try: |
|---|
| 675 | pyafs_error(code) |
|---|
| 676 | |
|---|
| 677 | code = krb5_parse_name(ctx, krb5_name, &k5_princ) |
|---|
| 678 | try: |
|---|
| 679 | pyafs_error(code) |
|---|
| 680 | |
|---|
| 681 | code = krb5_524_conv_principal(ctx, k5_princ, k4_name, k4_inst, k4_realm) |
|---|
| 682 | pyafs_error(code) |
|---|
| 683 | |
|---|
| 684 | afs_princ = kname_unparse(k4_name, k4_inst, k4_realm) |
|---|
| 685 | afs_name, afs_realm = afs_princ.rsplit('@', 1) |
|---|
| 686 | |
|---|
| 687 | if k4_realm == self.realm: |
|---|
| 688 | return afs_name |
|---|
| 689 | else: |
|---|
| 690 | return '%s@%s' % (afs_name, afs_realm.lower()) |
|---|
| 691 | finally: |
|---|
| 692 | if k5_princ is not NULL: |
|---|
| 693 | krb5_free_principal(ctx, k5_princ) |
|---|
| 694 | finally: |
|---|
| 695 | if ctx is not NULL: |
|---|
| 696 | krb5_free_context(ctx) |
|---|