Commit | Line | Data |
---|---|---|
805e021f CE |
1 | /* |
2 | * Copyright 2000, International Business Machines Corporation and others. | |
3 | * All Rights Reserved. | |
4 | * | |
5 | * This software has been released under the terms of the IBM Public | |
6 | * License. For details, see the LICENSE file in the top-level source | |
7 | * directory or online at http://www.openafs.org/dl/license10.html | |
8 | */ | |
9 | ||
10 | #include <afsconfig.h> | |
11 | #include <afs/param.h> | |
12 | #include <afs/stds.h> | |
13 | ||
14 | #include <roken.h> | |
15 | #include <afs/opr.h> | |
16 | ||
17 | #include <rx/rx.h> | |
18 | #include <rx/xdr.h> | |
19 | #include <afs/auth.h> | |
20 | #include <afs/cellconfig.h> | |
21 | #include <afs/afsutil.h> | |
22 | #include <afs/com_err.h> | |
23 | ||
24 | #include "ptclient.h" | |
25 | #include "ptuser.h" | |
26 | #include "pterror.h" | |
27 | ||
28 | struct ubik_client *pruclient = 0; | |
29 | static afs_int32 lastLevel; /* security level pruclient, if any */ | |
30 | ||
31 | static char *whoami = "libprot"; | |
32 | ||
33 | ||
34 | #define ID_HASH_SIZE 1024 | |
35 | #define ID_STACK_SIZE 1024 | |
36 | ||
37 | /** | |
38 | * Hash table chain of user and group ids. | |
39 | */ | |
40 | struct idchain { | |
41 | struct idchain *next; | |
42 | afs_int32 id; | |
43 | }; | |
44 | ||
45 | /** | |
46 | * Hash table of user and group ids. | |
47 | */ | |
48 | struct idhash { | |
49 | afs_uint32 userEntries; /**< number of user id entries hashed */ | |
50 | afs_uint32 groupEntries; /**< number of group id entries hashed */ | |
51 | struct idchain *hash[ID_HASH_SIZE]; | |
52 | }; | |
53 | ||
54 | /** | |
55 | * Allocate a new id hash table. | |
56 | */ | |
57 | static afs_int32 | |
58 | AllocateIdHash(struct idhash **aidhash) | |
59 | { | |
60 | struct idhash *idhash; | |
61 | ||
62 | idhash = calloc(1, sizeof(struct idhash)); | |
63 | if (!idhash) { | |
64 | return ENOMEM; | |
65 | } | |
66 | *aidhash = idhash; | |
67 | return 0; | |
68 | } | |
69 | ||
70 | /** | |
71 | * Free the id hash. | |
72 | */ | |
73 | static void | |
74 | FreeIdHash(struct idhash *idhash) | |
75 | { | |
76 | int index; | |
77 | struct idchain *chain; | |
78 | struct idchain *next; | |
79 | ||
80 | for (index = 0; index < ID_HASH_SIZE; index++) { | |
81 | for (chain = idhash->hash[index]; chain; chain = next) { | |
82 | next = chain->next; | |
83 | free(chain); | |
84 | } | |
85 | } | |
86 | free(idhash); | |
87 | } | |
88 | ||
89 | /** | |
90 | * Indicate if group/user id is already hashed, and | |
91 | * if not insert it. | |
92 | * | |
93 | * @returns whether id is present | |
94 | * @retval >0 id is already present in the hash | |
95 | * @retval 0 id was not found and was inserted into the hash | |
96 | * @retval <0 error encountered | |
97 | */ | |
98 | static afs_int32 | |
99 | FindId(struct idhash *idhash, afs_int32 id) | |
100 | { | |
101 | afs_int32 index; | |
102 | struct idchain *chain; | |
103 | struct idchain *newChain; | |
104 | ||
105 | index = abs(id) % ID_HASH_SIZE; | |
106 | for (chain = idhash->hash[index]; chain; chain = chain->next) { | |
107 | if (chain->id == id) { | |
108 | return 1; | |
109 | } | |
110 | } | |
111 | ||
112 | /* Insert this id but return not found. */ | |
113 | newChain = malloc(sizeof(struct idchain)); | |
114 | if (!newChain) { | |
115 | return ENOMEM; | |
116 | } else { | |
117 | newChain->id = id; | |
118 | newChain->next = idhash->hash[index]; | |
119 | idhash->hash[index] = newChain; | |
120 | if (id < 0) { | |
121 | idhash->groupEntries++; | |
122 | } else { | |
123 | idhash->userEntries++; | |
124 | } | |
125 | } | |
126 | return 0; | |
127 | } | |
128 | ||
129 | /** | |
130 | * Create an idlist from the ids in the hash. | |
131 | */ | |
132 | static afs_int32 | |
133 | CreateIdList(struct idhash *idhash, idlist * alist, afs_int32 select) | |
134 | { | |
135 | struct idchain *chain; | |
136 | afs_int32 entries = 0; | |
137 | int index; | |
138 | int i; | |
139 | ||
140 | if (select & PRGROUPS) { | |
141 | entries += idhash->groupEntries; | |
142 | } | |
143 | if (select & PRUSERS) { | |
144 | entries += idhash->userEntries; | |
145 | } | |
146 | if (entries == 0) { | |
147 | alist->idlist_len = 0; | |
148 | alist->idlist_val = NULL; | |
149 | return 0; | |
150 | } | |
151 | ||
152 | alist->idlist_len = entries; | |
153 | alist->idlist_val = malloc(sizeof(afs_int32) * entries); | |
154 | if (!alist->idlist_val) { | |
155 | return ENOMEM; | |
156 | } | |
157 | ||
158 | for (i = 0, index = 0; index < ID_HASH_SIZE; index++) { | |
159 | for (chain = idhash->hash[index]; chain; chain = chain->next) { | |
160 | if (chain->id < 0) { | |
161 | if (select & PRGROUPS) { | |
162 | alist->idlist_val[i++] = chain->id; | |
163 | } | |
164 | } else { | |
165 | if (select & PRUSERS) { | |
166 | alist->idlist_val[i++] = chain->id; | |
167 | } | |
168 | } | |
169 | } | |
170 | } | |
171 | return 0; | |
172 | } | |
173 | ||
174 | afs_int32 | |
175 | pr_Initialize(IN afs_int32 secLevel, IN const char *confDir, IN char *cell) | |
176 | { | |
177 | afs_int32 code; | |
178 | struct rx_connection *serverconns[MAXSERVERS]; | |
179 | struct rx_securityClass *sc = NULL; | |
180 | static struct afsconf_dir *tdir = NULL; /* only do this once */ | |
181 | static char tconfDir[100] = ""; | |
182 | static char tcell[64] = ""; | |
183 | afs_int32 scIndex; | |
184 | afs_int32 secFlags; | |
185 | static struct afsconf_cell info; | |
186 | afs_int32 i; | |
187 | char cellstr[64]; | |
188 | afs_int32 gottdir = 0; | |
189 | afs_int32 refresh = 0; | |
190 | ||
191 | initialize_PT_error_table(); | |
192 | initialize_RXK_error_table(); | |
193 | initialize_ACFG_error_table(); | |
194 | initialize_KTC_error_table(); | |
195 | ||
196 | if (!cell) { | |
197 | if (!tdir) | |
198 | tdir = afsconf_Open(confDir); | |
199 | if (!tdir) { | |
200 | if (confDir && strcmp(confDir, "")) | |
201 | fprintf(stderr, | |
202 | "%s: Could not open configuration directory: %s.\n", | |
203 | whoami, confDir); | |
204 | else | |
205 | fprintf(stderr, | |
206 | "%s: No configuration directory specified.\n", | |
207 | whoami); | |
208 | return -1; | |
209 | } | |
210 | gottdir = 1; | |
211 | ||
212 | code = afsconf_GetLocalCell(tdir, cellstr, sizeof(cellstr)); | |
213 | if (code) { | |
214 | fprintf(stderr, | |
215 | "libprot: Could not get local cell. [%d]\n", code); | |
216 | return code; | |
217 | } | |
218 | cell = cellstr; | |
219 | } | |
220 | ||
221 | if (tdir == NULL || strcmp(confDir, tconfDir) || strcmp(cell, tcell)) { | |
222 | /* | |
223 | * force re-evaluation. we either don't have an afsconf_dir, | |
224 | * the directory has changed or the cell has changed. | |
225 | */ | |
226 | if (tdir && !gottdir) { | |
227 | afsconf_Close(tdir); | |
228 | tdir = NULL; | |
229 | } | |
230 | pruclient = NULL; | |
231 | refresh = 1; | |
232 | } | |
233 | ||
234 | if (refresh) { | |
235 | strncpy(tconfDir, confDir, sizeof(tconfDir)); | |
236 | strncpy(tcell, cell, sizeof(tcell)); | |
237 | ||
238 | if (!gottdir) | |
239 | tdir = afsconf_Open(confDir); | |
240 | if (!tdir) { | |
241 | if (confDir && strcmp(confDir, "")) | |
242 | fprintf(stderr, | |
243 | "libprot: Could not open configuration directory: %s.\n", | |
244 | confDir); | |
245 | else | |
246 | fprintf(stderr, | |
247 | "libprot: No configuration directory specified.\n"); | |
248 | return -1; | |
249 | } | |
250 | ||
251 | code = afsconf_GetCellInfo(tdir, cell, "afsprot", &info); | |
252 | if (code) { | |
253 | fprintf(stderr, "libprot: Could not locate cell %s in %s/%s\n", | |
254 | cell, confDir, AFSDIR_CELLSERVDB_FILE); | |
255 | return code; | |
256 | } | |
257 | } | |
258 | ||
259 | /* If we already have a client and it is at the security level we | |
260 | * want, don't get a new one. Unless the security level is 2 in | |
261 | * which case we will get one (and re-read the key file). | |
262 | */ | |
263 | if (pruclient && (lastLevel == secLevel) && (secLevel != 2)) { | |
264 | return 0; | |
265 | } | |
266 | ||
267 | code = rx_Init(0); | |
268 | if (code) { | |
269 | fprintf(stderr, "libprot: Could not initialize rx.\n"); | |
270 | return code; | |
271 | } | |
272 | ||
273 | /* Most callers use secLevel==1, however, the fileserver uses secLevel==2 | |
274 | * to force use of the KeyFile. secLevel == 0 implies -noauth was | |
275 | * specified. */ | |
276 | if (secLevel == 2) { | |
277 | /* If secLevel is two assume we're on a file server and use | |
278 | * ClientAuthSecure if possible. */ | |
279 | code = afsconf_ClientAuthSecure(tdir, &sc, &scIndex); | |
280 | if (code) | |
281 | afs_com_err(whoami, code, "(calling client secure)\n"); | |
282 | } else if (secLevel > 0) { | |
283 | secFlags = 0; | |
284 | if (secLevel > 1) | |
285 | secFlags |= AFSCONF_SECOPTS_ALWAYSENCRYPT; | |
286 | ||
287 | code = afsconf_ClientAuthToken(&info, secFlags, &sc, &scIndex, NULL); | |
288 | if (code) { | |
289 | afs_com_err(whoami, code, "(getting token)"); | |
290 | if (secLevel > 1) | |
291 | return code; | |
292 | } | |
293 | } | |
294 | ||
295 | if (sc == NULL) { | |
296 | sc = rxnull_NewClientSecurityObject(); | |
297 | scIndex = RX_SECIDX_NULL; | |
298 | } | |
299 | ||
300 | if ((scIndex == RX_SECIDX_NULL) && (secLevel != 0)) | |
301 | fprintf(stderr, | |
302 | "%s: Could not get afs tokens, running unauthenticated\n", | |
303 | whoami); | |
304 | ||
305 | memset(serverconns, 0, sizeof(serverconns)); /* terminate list!!! */ | |
306 | for (i = 0; i < info.numServers; i++) | |
307 | serverconns[i] = | |
308 | rx_NewConnection(info.hostAddr[i].sin_addr.s_addr, | |
309 | info.hostAddr[i].sin_port, PRSRV, sc, | |
310 | scIndex); | |
311 | ||
312 | code = ubik_ClientInit(serverconns, &pruclient); | |
313 | if (code) { | |
314 | afs_com_err(whoami, code, "ubik client init failed."); | |
315 | return code; | |
316 | } | |
317 | lastLevel = scIndex; | |
318 | ||
319 | code = rxs_Release(sc); | |
320 | return code; | |
321 | } | |
322 | ||
323 | int | |
324 | pr_End(void) | |
325 | { | |
326 | int code = 0; | |
327 | ||
328 | if (pruclient) { | |
329 | code = ubik_ClientDestroy(pruclient); | |
330 | pruclient = 0; | |
331 | } | |
332 | return code; | |
333 | } | |
334 | ||
335 | /* | |
336 | * Make sure that arg is a proper C string that fits in a prname. | |
337 | * If strnlen(arg, PR_MAXNAMELEN) == PR_MAXNAMELEN, then arg either | |
338 | * doesn't have a terminating NUL or is too long, and we can't tell | |
339 | * which one in the current API. This code has always assumed that | |
340 | * the names presented to it are valid C strings, but for robustness | |
341 | * we can't depend on the server side guaranteeing that. Unfortunately, | |
342 | * the wire protocol uses a vector[PR_MAXNAMELEN] of char, so XDR will | |
343 | * not automatically fix up strings generated by the server. | |
344 | * | |
345 | * The inequality is just belt-and-suspenders and should be impossible. | |
346 | */ | |
347 | static_inline int check_length(prname arg) | |
348 | { | |
349 | if (strnlen(arg, PR_MAXNAMELEN) >= PR_MAXNAMELEN) | |
350 | return PRNAMETOOLONG; | |
351 | return 0; | |
352 | } | |
353 | ||
354 | int | |
355 | pr_CreateUser(prname name, afs_int32 *id) | |
356 | { | |
357 | afs_int32 code; | |
358 | ||
359 | code = check_length(name); | |
360 | if (code) | |
361 | return code; | |
362 | stolower(name); | |
363 | if (*id) { | |
364 | code = ubik_PR_INewEntry(pruclient, 0, name, *id, 0); | |
365 | } else { | |
366 | code = ubik_PR_NewEntry(pruclient, 0, name, 0, 0, id); | |
367 | } | |
368 | return code; | |
369 | } | |
370 | ||
371 | int | |
372 | pr_CreateGroup(prname name, prname owner, afs_int32 *id) | |
373 | { | |
374 | afs_int32 code; | |
375 | afs_int32 oid = 0; | |
376 | afs_int32 flags = 0; | |
377 | ||
378 | code = check_length(name); | |
379 | if (code) | |
380 | return code; | |
381 | /* pr_SNameToId will check owner's length. */ | |
382 | stolower(name); | |
383 | if (owner) { | |
384 | code = pr_SNameToId(owner, &oid); | |
385 | if (code) | |
386 | return code; | |
387 | if (oid == ANONYMOUSID) | |
388 | return PRNOENT; | |
389 | } | |
390 | flags |= PRGRP; | |
391 | if (*id) { | |
392 | code = ubik_PR_INewEntry(pruclient, 0, name, *id, oid); | |
393 | } else { | |
394 | code = ubik_PR_NewEntry(pruclient, 0, name, flags, oid, id); | |
395 | } | |
396 | return code; | |
397 | } | |
398 | ||
399 | int | |
400 | pr_Delete(prname name) | |
401 | { | |
402 | afs_int32 code; | |
403 | afs_int32 id; | |
404 | ||
405 | /* pr_SNameToId both checks the length of name and lowercases it. */ | |
406 | code = pr_SNameToId(name, &id); | |
407 | if (code) | |
408 | return code; | |
409 | if (id == ANONYMOUSID) | |
410 | return PRNOENT; | |
411 | code = ubik_PR_Delete(pruclient, 0, id); | |
412 | return code; | |
413 | } | |
414 | ||
415 | int | |
416 | pr_DeleteByID(afs_int32 id) | |
417 | { | |
418 | afs_int32 code; | |
419 | ||
420 | code = ubik_PR_Delete(pruclient, 0, id); | |
421 | return code; | |
422 | } | |
423 | ||
424 | int | |
425 | pr_AddToGroup(prname user, prname group) | |
426 | { | |
427 | afs_int32 code; | |
428 | namelist lnames; | |
429 | idlist lids; | |
430 | ||
431 | code = check_length(user); | |
432 | if (code) | |
433 | return code; | |
434 | code = check_length(group); | |
435 | if (code) | |
436 | return code; | |
437 | lnames.namelist_len = 2; | |
438 | lnames.namelist_val = malloc(2 * PR_MAXNAMELEN); | |
439 | strncpy(lnames.namelist_val[0], user, PR_MAXNAMELEN); | |
440 | strncpy(lnames.namelist_val[1], group, PR_MAXNAMELEN); | |
441 | lids.idlist_val = 0; | |
442 | lids.idlist_len = 0; | |
443 | code = pr_NameToId(&lnames, &lids); | |
444 | if (code) | |
445 | goto done; | |
446 | /* if here, still could be missing an entry */ | |
447 | if (lids.idlist_len != 2) { | |
448 | code = PRINTERNAL; | |
449 | goto done; | |
450 | } | |
451 | if (lids.idlist_val[0] == ANONYMOUSID | |
452 | || lids.idlist_val[1] == ANONYMOUSID) { | |
453 | code = PRNOENT; | |
454 | goto done; | |
455 | } | |
456 | code = | |
457 | ubik_PR_AddToGroup(pruclient, 0, lids.idlist_val[0], | |
458 | lids.idlist_val[1]); | |
459 | done: | |
460 | if (lnames.namelist_val) | |
461 | free(lnames.namelist_val); | |
462 | ||
463 | xdr_free((xdrproc_t) xdr_idlist, &lids); | |
464 | return code; | |
465 | } | |
466 | ||
467 | int | |
468 | pr_RemoveUserFromGroup(prname user, prname group) | |
469 | { | |
470 | afs_int32 code; | |
471 | namelist lnames; | |
472 | idlist lids; | |
473 | ||
474 | code = check_length(user); | |
475 | if (code) | |
476 | return code; | |
477 | code = check_length(group); | |
478 | if (code) | |
479 | return code; | |
480 | lnames.namelist_len = 2; | |
481 | lnames.namelist_val = malloc(2 * PR_MAXNAMELEN); | |
482 | strncpy(lnames.namelist_val[0], user, PR_MAXNAMELEN); | |
483 | strncpy(lnames.namelist_val[1], group, PR_MAXNAMELEN); | |
484 | lids.idlist_val = 0; | |
485 | lids.idlist_len = 0; | |
486 | code = pr_NameToId(&lnames, &lids); | |
487 | if (code) | |
488 | goto done; | |
489 | ||
490 | if (lids.idlist_len != 2) { | |
491 | code = PRINTERNAL; | |
492 | goto done; | |
493 | } | |
494 | if (lids.idlist_val[0] == ANONYMOUSID | |
495 | || lids.idlist_val[1] == ANONYMOUSID) { | |
496 | code = PRNOENT; | |
497 | goto done; | |
498 | } | |
499 | code = | |
500 | ubik_PR_RemoveFromGroup(pruclient, 0, lids.idlist_val[0], | |
501 | lids.idlist_val[1]); | |
502 | done: | |
503 | if (lnames.namelist_val) | |
504 | free(lnames.namelist_val); | |
505 | ||
506 | xdr_free((xdrproc_t) xdr_idlist, &lids); | |
507 | ||
508 | return code; | |
509 | } | |
510 | ||
511 | int | |
512 | pr_NameToId(namelist *names, idlist *ids) | |
513 | { | |
514 | afs_int32 code; | |
515 | afs_int32 i; | |
516 | ||
517 | for (i = 0; i < names->namelist_len; i++) { | |
518 | code = check_length(names->namelist_val[i]); | |
519 | if (code) | |
520 | return code; | |
521 | stolower(names->namelist_val[i]); | |
522 | } | |
523 | code = ubik_PR_NameToID(pruclient, 0, names, ids); | |
524 | return code; | |
525 | } | |
526 | ||
527 | int | |
528 | pr_SNameToId(prname name, afs_int32 *id) | |
529 | { | |
530 | namelist lnames; | |
531 | idlist lids; | |
532 | afs_int32 code; | |
533 | ||
534 | code = check_length(name); | |
535 | if (code) | |
536 | return code; | |
537 | lids.idlist_len = 0; | |
538 | lids.idlist_val = 0; | |
539 | lnames.namelist_len = 1; | |
540 | lnames.namelist_val = malloc(PR_MAXNAMELEN); | |
541 | stolower(name); | |
542 | strncpy(lnames.namelist_val[0], name, PR_MAXNAMELEN); | |
543 | code = ubik_PR_NameToID(pruclient, 0, &lnames, &lids); | |
544 | if (lids.idlist_val) { | |
545 | *id = *lids.idlist_val; | |
546 | xdr_free((xdrproc_t) xdr_idlist, &lids); | |
547 | } else if (code == 0) { | |
548 | code = PRINTERNAL; | |
549 | } | |
550 | if (lnames.namelist_val) | |
551 | free(lnames.namelist_val); | |
552 | return code; | |
553 | } | |
554 | ||
555 | /* | |
556 | * Like ubik_PR_IDToName, but enforces that the output prnames are | |
557 | * interpretable as C strings (i.e., NUL-terminated). | |
558 | */ | |
559 | int | |
560 | string_PR_IDToName(struct ubik_client *client, afs_int32 flags, | |
561 | idlist *ids, namelist *names) | |
562 | { | |
563 | afs_int32 code; | |
564 | int i; | |
565 | ||
566 | code = ubik_PR_IDToName(client, flags, ids, names); | |
567 | if (code) | |
568 | return code; | |
569 | for (i = 0; i < names->namelist_len; i++) { | |
570 | code = check_length(names->namelist_val[i]); | |
571 | if (code) | |
572 | return code; | |
573 | } | |
574 | return code; | |
575 | } | |
576 | ||
577 | ||
578 | int | |
579 | pr_IdToName(idlist *ids, namelist *names) | |
580 | { | |
581 | return string_PR_IDToName(pruclient, 0, ids, names); | |
582 | } | |
583 | ||
584 | int | |
585 | pr_SIdToName(afs_int32 id, prname name) | |
586 | { | |
587 | namelist lnames; | |
588 | idlist lids; | |
589 | afs_int32 code; | |
590 | ||
591 | lids.idlist_len = 1; | |
592 | lids.idlist_val = malloc(sizeof(afs_int32)); | |
593 | *lids.idlist_val = id; | |
594 | lnames.namelist_len = 0; | |
595 | lnames.namelist_val = 0; | |
596 | code = pr_IdToName(&lids, &lnames); | |
597 | if (lnames.namelist_val) | |
598 | strncpy(name, lnames.namelist_val[0], PR_MAXNAMELEN); | |
599 | else if (code == 0) | |
600 | code = PRINTERNAL; | |
601 | ||
602 | if (lids.idlist_val) | |
603 | free(lids.idlist_val); | |
604 | ||
605 | xdr_free((xdrproc_t) xdr_namelist, &lnames); | |
606 | ||
607 | return code; | |
608 | } | |
609 | ||
610 | int | |
611 | pr_GetCPS(afs_int32 id, prlist *CPS) | |
612 | { | |
613 | afs_int32 code; | |
614 | afs_int32 over; | |
615 | ||
616 | over = 0; | |
617 | code = ubik_PR_GetCPS(pruclient, 0, id, CPS, &over); | |
618 | if (code != PRSUCCESS) | |
619 | return code; | |
620 | if (over) { | |
621 | /* do something about this, probably make a new call */ | |
622 | /* don't forget there's a hard limit in the interface */ | |
623 | fprintf(stderr, "membership list for id %d exceeds display limit\n", | |
624 | id); | |
625 | } | |
626 | return 0; | |
627 | } | |
628 | ||
629 | int | |
630 | pr_GetCPS2(afs_int32 id, afs_uint32 host, prlist *CPS) | |
631 | { | |
632 | afs_int32 code; | |
633 | afs_int32 over; | |
634 | ||
635 | over = 0; | |
636 | code = ubik_PR_GetCPS2(pruclient, 0, id, host, CPS, &over); | |
637 | if (code != PRSUCCESS) | |
638 | return code; | |
639 | if (over) { | |
640 | /* do something about this, probably make a new call */ | |
641 | /* don't forget there's a hard limit in the interface */ | |
642 | fprintf(stderr, "membership list for id %d exceeds display limit\n", | |
643 | id); | |
644 | } | |
645 | return 0; | |
646 | } | |
647 | ||
648 | int | |
649 | pr_GetHostCPS(afs_uint32 host, prlist *CPS) | |
650 | { | |
651 | afs_int32 code; | |
652 | afs_int32 over; | |
653 | ||
654 | over = 0; | |
655 | code = ubik_PR_GetHostCPS(pruclient, 0, host, CPS, &over); | |
656 | if (code != PRSUCCESS) | |
657 | return code; | |
658 | if (over) { | |
659 | /* do something about this, probably make a new call */ | |
660 | /* don't forget there's a hard limit in the interface */ | |
661 | fprintf(stderr, | |
662 | "membership list for host id %d exceeds display limit\n", | |
663 | host); | |
664 | } | |
665 | return 0; | |
666 | } | |
667 | ||
668 | int | |
669 | pr_ListMembers(prname group, namelist *lnames) | |
670 | { | |
671 | afs_int32 code; | |
672 | afs_int32 gid; | |
673 | int i; | |
674 | ||
675 | memset(lnames, 0, sizeof(namelist)); | |
676 | ||
677 | /* pr_SNameToId checks the length of group. */ | |
678 | code = pr_SNameToId(group, &gid); | |
679 | if (code) | |
680 | return code; | |
681 | if (gid == ANONYMOUSID) | |
682 | return PRNOENT; | |
683 | code = pr_IDListMembers(gid, lnames); | |
684 | if (code) | |
685 | return code; | |
686 | for (i = 0; i < lnames->namelist_len; i++) { | |
687 | code = check_length(lnames->namelist_val[i]); | |
688 | if (code) | |
689 | return code; | |
690 | } | |
691 | return code; | |
692 | } | |
693 | ||
694 | int | |
695 | pr_ListOwned(afs_int32 oid, namelist *lnames, afs_int32 *moreP) | |
696 | { | |
697 | afs_int32 code; | |
698 | prlist alist; | |
699 | idlist *lids; | |
700 | ||
701 | alist.prlist_len = 0; | |
702 | alist.prlist_val = 0; | |
703 | code = ubik_PR_ListOwned(pruclient, 0, oid, &alist, moreP); | |
704 | if (code) | |
705 | return code; | |
706 | if (*moreP == 1) { | |
707 | /* Remain backwards compatible when moreP was a T/F bit */ | |
708 | fprintf(stderr, "membership list for id %d exceeds display limit\n", | |
709 | oid); | |
710 | *moreP = 0; | |
711 | } | |
712 | lids = (idlist *) &alist; | |
713 | code = pr_IdToName(lids, lnames); | |
714 | ||
715 | xdr_free((xdrproc_t) xdr_prlist, &alist); | |
716 | ||
717 | if (code) | |
718 | return code; | |
719 | ||
720 | return PRSUCCESS; | |
721 | } | |
722 | ||
723 | int | |
724 | pr_IDListMembers(afs_int32 gid, namelist *lnames) | |
725 | { | |
726 | afs_int32 code; | |
727 | prlist alist; | |
728 | idlist *lids; | |
729 | afs_int32 over; | |
730 | ||
731 | alist.prlist_len = 0; | |
732 | alist.prlist_val = 0; | |
733 | code = ubik_PR_ListElements(pruclient, 0, gid, &alist, &over); | |
734 | if (code) | |
735 | return code; | |
736 | if (over) { | |
737 | fprintf(stderr, "membership list for id %d exceeds display limit\n", | |
738 | gid); | |
739 | } | |
740 | lids = (idlist *) &alist; | |
741 | code = pr_IdToName(lids, lnames); | |
742 | ||
743 | xdr_free((xdrproc_t) xdr_prlist, &alist); | |
744 | ||
745 | if (code) | |
746 | return code; | |
747 | return PRSUCCESS; | |
748 | } | |
749 | ||
750 | int | |
751 | pr_IDListExpandedMembers(afs_int32 aid, namelist * lnames) | |
752 | { | |
753 | afs_int32 code; | |
754 | afs_int32 gid; | |
755 | idlist lids; | |
756 | prlist alist; | |
757 | afs_int32 over; | |
758 | struct idhash *members = NULL; | |
759 | afs_int32 *stack = NULL; | |
760 | afs_int32 maxstack = ID_STACK_SIZE; | |
761 | int n = 0; /* number of ids stacked */ | |
762 | int i; | |
763 | int firstpass = 1; | |
764 | ||
765 | code = AllocateIdHash(&members); | |
766 | if (code) { | |
767 | return code; | |
768 | } | |
769 | stack = malloc(sizeof(afs_int32) * maxstack); | |
770 | if (!stack) { | |
771 | code = ENOMEM; | |
772 | goto done; | |
773 | } | |
774 | ||
775 | stack[n++] = aid; | |
776 | while (n) { | |
777 | gid = stack[--n]; /* pop next group id */ | |
778 | alist.prlist_len = 0; | |
779 | alist.prlist_val = NULL; | |
780 | if (firstpass || aid < 0) { | |
781 | firstpass = 0; | |
782 | code = ubik_PR_ListElements(pruclient, 0, gid, &alist, &over); | |
783 | } else { | |
784 | code = ubik_PR_ListSuperGroups(pruclient, 0, gid, &alist, &over); | |
785 | if (code == RXGEN_OPCODE) { | |
786 | alist.prlist_len = 0; | |
787 | alist.prlist_val = NULL; | |
788 | code = 0; /* server does not support supergroups. */ | |
789 | } | |
790 | } | |
791 | if (code) | |
792 | goto done; | |
793 | if (over) { | |
794 | fprintf(stderr, | |
795 | "membership list for id %d exceeds display limit\n", gid); | |
796 | } | |
797 | for (i = 0; i < alist.prlist_len; i++) { | |
798 | afs_int32 found; | |
799 | afs_int32 id; | |
800 | ||
801 | id = alist.prlist_val[i]; | |
802 | found = FindId(members, id); | |
803 | if (found < 0) { | |
804 | code = found; | |
805 | xdr_free((xdrproc_t) xdr_prlist, &alist); | |
806 | goto done; | |
807 | } | |
808 | if (found == 0 && id < 0) { | |
809 | if (n == maxstack) { /* need more stack space */ | |
810 | afs_int32 *tmp; | |
811 | maxstack += n; | |
812 | tmp = realloc(stack, maxstack * sizeof(afs_int32)); | |
813 | if (!tmp) { | |
814 | code = ENOMEM; | |
815 | xdr_free((xdrproc_t) xdr_prlist, &alist); | |
816 | goto done; | |
817 | } | |
818 | stack = tmp; | |
819 | } | |
820 | stack[n++] = id; /* push group id */ | |
821 | } | |
822 | } | |
823 | xdr_free((xdrproc_t) xdr_prlist, &alist); | |
824 | } | |
825 | ||
826 | code = CreateIdList(members, &lids, (aid < 0 ? PRUSERS : PRGROUPS)); | |
827 | if (code) { | |
828 | goto done; | |
829 | } else if (lids.idlist_len == 0) { | |
830 | /* Avoid the RPC when there's nothing to look up. */ | |
831 | lnames->namelist_len = 0; | |
832 | lnames->namelist_val = NULL; | |
833 | goto done; | |
834 | } | |
835 | code = pr_IdToName(&lids, lnames); | |
836 | free(lids.idlist_val); | |
837 | ||
838 | done: | |
839 | if (stack) | |
840 | free(stack); | |
841 | if (members) | |
842 | FreeIdHash(members); | |
843 | return code; | |
844 | } | |
845 | ||
846 | int | |
847 | pr_ListEntry(afs_int32 id, struct prcheckentry *aentry) | |
848 | { | |
849 | afs_int32 code; | |
850 | ||
851 | code = ubik_PR_ListEntry(pruclient, 0, id, aentry); | |
852 | if (code) | |
853 | return code; | |
854 | return check_length(aentry->name); | |
855 | } | |
856 | ||
857 | afs_int32 | |
858 | pr_ListEntries(int flag, afs_int32 startindex, afs_int32 *nentries, struct prlistentries **entries, afs_int32 *nextstartindex) | |
859 | { | |
860 | afs_int32 code; | |
861 | int i; | |
862 | prentries bulkentries; | |
863 | ||
864 | *nentries = 0; | |
865 | *entries = NULL; | |
866 | *nextstartindex = -1; | |
867 | bulkentries.prentries_val = 0; | |
868 | bulkentries.prentries_len = 0; | |
869 | ||
870 | code = | |
871 | ubik_PR_ListEntries(pruclient, 0, flag, startindex, | |
872 | &bulkentries, nextstartindex); | |
873 | if (code) | |
874 | return code; | |
875 | for (i = 0; i < bulkentries.prentries_len; i++) { | |
876 | /* XXX should we try to return all the other entries? */ | |
877 | code = check_length(bulkentries.prentries_val[i].name); | |
878 | if (code) | |
879 | goto out; | |
880 | } | |
881 | ||
882 | out: | |
883 | if (code != 0) { | |
884 | xdr_free((xdrproc_t)xdr_prentries, &bulkentries); | |
885 | } else { | |
886 | *nentries = bulkentries.prentries_len; | |
887 | *entries = bulkentries.prentries_val; | |
888 | } | |
889 | return code; | |
890 | } | |
891 | ||
892 | int | |
893 | pr_CheckEntryByName(prname name, afs_int32 *id, prname owner, prname creator) | |
894 | { | |
895 | /* struct prcheckentry returns other things, which aren't useful to show at this time. */ | |
896 | afs_int32 code; | |
897 | struct prcheckentry aentry; | |
898 | ||
899 | /* pr_SNameToId will check name's length. */ | |
900 | code = pr_SNameToId(name, id); | |
901 | if (code) | |
902 | return code; | |
903 | if (*id == ANONYMOUSID) | |
904 | return PRNOENT; | |
905 | code = ubik_PR_ListEntry(pruclient, 0, *id, &aentry); | |
906 | if (code) | |
907 | return code; | |
908 | /* this should be done in one RPC, but I'm lazy. */ | |
909 | code = pr_SIdToName(aentry.owner, owner); | |
910 | if (code) | |
911 | return code; | |
912 | code = pr_SIdToName(aentry.creator, creator); | |
913 | if (code) | |
914 | return code; | |
915 | return PRSUCCESS; | |
916 | } | |
917 | ||
918 | int | |
919 | pr_CheckEntryById(prname name, afs_int32 id, prname owner, prname creator) | |
920 | { | |
921 | /* struct prcheckentry returns other things, which aren't useful to show at this time. */ | |
922 | afs_int32 code; | |
923 | struct prcheckentry aentry; | |
924 | ||
925 | /* XXX ListEntry RPC gives us the name back so should avoid extra RPC */ | |
926 | code = pr_SIdToName(id, name); | |
927 | if (code) | |
928 | return code; | |
929 | if (id == ANONYMOUSID) | |
930 | return PRNOENT; | |
931 | code = ubik_PR_ListEntry(pruclient, 0, id, &aentry); | |
932 | if (code) | |
933 | return code; | |
934 | /* this should be done in one RPC, but I'm lazy. */ | |
935 | code = pr_SIdToName(aentry.owner, owner); | |
936 | if (code) | |
937 | return code; | |
938 | code = pr_SIdToName(aentry.creator, creator); | |
939 | if (code) | |
940 | return code; | |
941 | return PRSUCCESS; | |
942 | } | |
943 | ||
944 | int | |
945 | pr_ChangeEntry(prname oldname, prname newname, afs_int32 *newid, prname newowner) | |
946 | { | |
947 | afs_int32 code; | |
948 | afs_int32 id; | |
949 | afs_int32 oid = 0; | |
950 | ||
951 | /* pr_SNameToId takes care of length checks for us. */ | |
952 | code = pr_SNameToId(oldname, &id); | |
953 | if (code) | |
954 | return code; | |
955 | if (id == ANONYMOUSID) | |
956 | return PRNOENT; | |
957 | if (newowner && *newowner) { | |
958 | code = pr_SNameToId(newowner, &oid); | |
959 | if (code) | |
960 | return code; | |
961 | if (oid == ANONYMOUSID) | |
962 | return PRNOENT; | |
963 | } | |
964 | if (newid) | |
965 | code = ubik_PR_ChangeEntry(pruclient, 0, id, newname, oid, *newid); | |
966 | else | |
967 | code = ubik_PR_ChangeEntry(pruclient, 0, id, newname, oid, 0); | |
968 | return code; | |
969 | } | |
970 | ||
971 | int | |
972 | pr_IsAMemberOf(prname uname, prname gname, afs_int32 *flag) | |
973 | { | |
974 | afs_int32 code; | |
975 | namelist lnames; | |
976 | idlist lids; | |
977 | ||
978 | code = check_length(uname); | |
979 | if (code) | |
980 | return code; | |
981 | code = check_length(gname); | |
982 | if (code) | |
983 | return code; | |
984 | stolower(uname); | |
985 | stolower(gname); | |
986 | lnames.namelist_len = 2; | |
987 | lnames.namelist_val = malloc(2 * PR_MAXNAMELEN); | |
988 | strncpy(lnames.namelist_val[0], uname, PR_MAXNAMELEN); | |
989 | strncpy(lnames.namelist_val[1], gname, PR_MAXNAMELEN); | |
990 | lids.idlist_val = 0; | |
991 | lids.idlist_len = 0; | |
992 | code = pr_NameToId(&lnames, &lids); | |
993 | if (code) { | |
994 | if (lnames.namelist_val) | |
995 | free(lnames.namelist_val); | |
996 | xdr_free((xdrproc_t) xdr_idlist, &lids); | |
997 | return code; | |
998 | } | |
999 | if (lids.idlist_len != 2) { | |
1000 | free(lnames.namelist_val); | |
1001 | xdr_free((xdrproc_t) xdr_idlist, &lids); | |
1002 | return PRINTERNAL; | |
1003 | } | |
1004 | code = | |
1005 | ubik_PR_IsAMemberOf(pruclient, 0, lids.idlist_val[0], | |
1006 | lids.idlist_val[1], flag); | |
1007 | if (lnames.namelist_val) | |
1008 | free(lnames.namelist_val); | |
1009 | xdr_free((xdrproc_t) xdr_idlist, &lids); | |
1010 | return code; | |
1011 | } | |
1012 | ||
1013 | int | |
1014 | pr_ListMaxUserId(afs_int32 *mid) | |
1015 | { | |
1016 | afs_int32 code; | |
1017 | afs_int32 gid; | |
1018 | code = ubik_PR_ListMax(pruclient, 0, mid, &gid); | |
1019 | return code; | |
1020 | } | |
1021 | ||
1022 | int | |
1023 | pr_SetMaxUserId(afs_int32 mid) | |
1024 | { | |
1025 | afs_int32 code; | |
1026 | afs_int32 flag = 0; | |
1027 | code = ubik_PR_SetMax(pruclient, 0, mid, flag); | |
1028 | return code; | |
1029 | } | |
1030 | ||
1031 | int | |
1032 | pr_ListMaxGroupId(afs_int32 *mid) | |
1033 | { | |
1034 | afs_int32 code; | |
1035 | afs_int32 id; | |
1036 | code = ubik_PR_ListMax(pruclient, 0, &id, mid); | |
1037 | return code; | |
1038 | } | |
1039 | ||
1040 | int | |
1041 | pr_SetMaxGroupId(afs_int32 mid) | |
1042 | { | |
1043 | afs_int32 code; | |
1044 | afs_int32 flag = 0; | |
1045 | ||
1046 | flag |= PRGRP; | |
1047 | code = ubik_PR_SetMax(pruclient, 0, mid, flag); | |
1048 | return code; | |
1049 | } | |
1050 | ||
1051 | afs_int32 | |
1052 | pr_SetFieldsEntry(afs_int32 id, afs_int32 mask, afs_int32 flags, afs_int32 ngroups, afs_int32 nusers) | |
1053 | { | |
1054 | afs_int32 code; | |
1055 | ||
1056 | code = | |
1057 | ubik_PR_SetFieldsEntry(pruclient, 0, id, mask, flags, ngroups, | |
1058 | nusers, 0, 0); | |
1059 | return code; | |
1060 | } | |
1061 | ||
1062 | int | |
1063 | pr_ListSuperGroups(afs_int32 gid, namelist * lnames) | |
1064 | { | |
1065 | afs_int32 code; | |
1066 | prlist alist; | |
1067 | idlist *lids; | |
1068 | afs_int32 over; | |
1069 | ||
1070 | alist.prlist_len = 0; | |
1071 | alist.prlist_val = 0; | |
1072 | code = ubik_PR_ListSuperGroups(pruclient, 0, gid, &alist, &over); | |
1073 | if (code) | |
1074 | return code; | |
1075 | if (over) { | |
1076 | fprintf(stderr, "supergroup list for id %d exceeds display limit\n", | |
1077 | gid); | |
1078 | } | |
1079 | lids = (idlist *) & alist; | |
1080 | code = pr_IdToName(lids, lnames); | |
1081 | ||
1082 | xdr_free((xdrproc_t) xdr_prlist, &alist); | |
1083 | return code; | |
1084 | } |