windows-server-config-20040402
[openafs.git] / src / libadmin / pts / afs_ptsAdmin.c
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
13 RCSID
14     ("$Header$");
15
16 #include <stdio.h>
17
18 #ifdef HAVE_STRING_H
19 #include <string.h>
20 #else
21 #ifdef HAVE_STRINGS_H
22 #include <strings.h>
23 #endif
24 #endif
25
26 #include <afs/stds.h>
27 #include "afs_ptsAdmin.h"
28 #include "../adminutil/afs_AdminInternal.h"
29 #include <afs/afs_AdminErrors.h>
30 #include <afs/afs_utilAdmin.h>
31 #include <afs/ptint.h>
32 #include <afs/ptserver.h>
33
34 /*
35  * IsValidCellHandle - validate the cell handle for making pts
36  * requests.
37  *
38  * PARAMETERS
39  *
40  * IN cellHandle - a previously opened cellHandle that is to be validated.
41  *
42  * LOCKS
43  *
44  * No locks are obtained or released by this function
45  *
46  * RETURN CODES
47  *
48  * Returns != 0 upon successful completion.
49  *
50  */
51
52 static int
53 IsValidCellHandle(const afs_cell_handle_p c_handle, afs_status_p st)
54 {
55     int rc = 0;
56     afs_status_t tst = 0;
57
58     if (!CellHandleIsValid((void *)c_handle, &tst)) {
59         goto fail_IsValidCellHandle;
60     }
61
62     if (c_handle->pts_valid == 0) {
63         tst = ADMCLIENTCELLPTSINVALID;
64         goto fail_IsValidCellHandle;
65     }
66
67     if (c_handle->pts == NULL) {
68         tst = ADMCLIENTCELLPTSNULL;
69         goto fail_IsValidCellHandle;
70     }
71     rc = 1;
72
73
74   fail_IsValidCellHandle:
75
76     if (st != NULL) {
77         *st = tst;
78     }
79     return rc;
80 }
81
82
83 /*
84  * TranslatePTSNames - translate character representations of pts names
85  * into their numeric equivalent.
86  *
87  * PARAMETERS
88  *
89  * IN cellHandle - a previously opened cellHandle that corresponds
90  * to the cell where the id's exist.
91  *
92  * IN names - the list of names to be translated.
93  *
94  * OUT ids - the list of translated names
95  *
96  * LOCKS
97  *
98  * No locks are obtained or released by this function
99  *
100  * RETURN CODES
101  *
102  * Returns != 0 upon successful completion.
103  *
104  */
105
106 static int
107 TranslatePTSNames(const afs_cell_handle_p cellHandle, namelist * names,
108                   idlist * ids, afs_status_p st)
109 {
110     int rc = 0;
111     afs_status_t tst = 0;
112     int i;
113     char *p;
114
115     /*
116      * Lowercase the names to translate
117      */
118
119     for (i = 0; i < names->namelist_len; i++) {
120         p = names->namelist_val[i];
121         while (*p) {
122             *p = tolower(*p);
123             p++;
124         }
125     }
126
127     tst = ubik_Call(PR_NameToID, cellHandle->pts, 0, names, ids);
128
129     if (tst) {
130         goto fail_TranslatePTSNames;
131     }
132
133
134     /*
135      * Check to see if the lookup failed
136      */
137
138     for (i = 0; i < ids->idlist_len; i++) {
139         if (ids->idlist_val[i] == ANONYMOUSID) {
140             tst = ADMPTSFAILEDNAMETRANSLATE;
141             goto fail_TranslatePTSNames;
142         }
143     }
144     rc = 1;
145
146   fail_TranslatePTSNames:
147
148     if (st != NULL) {
149         *st = tst;
150     }
151     return rc;
152 }
153
154 /*
155  * TranslateTwoNames - translate two pts names to their pts ids.
156  *
157  * PARAMETERS
158  *
159  * IN cellHandle - a previously opened cellHandle that corresponds
160  * to the cell where the group exists.
161  *
162  * IN id1 - one id to be translated
163  *
164  * IN error1 - the error status to be returned in the event that id1 is
165  * too long.
166  *
167  * IN id2 - one id to be translated
168  *
169  * IN error2 - the error status to be returned in the event that id2 is
170  * too long.
171  *
172  *
173  * OUT idlist - the list of pts id's
174  *
175  * LOCKS
176  *
177  * No locks are obtained or released by this function
178  *
179  * RETURN CODES
180  *
181  * Returns != 0 upon successful completion.
182  *
183  */
184
185 static int
186 TranslateTwoNames(const afs_cell_handle_p c_handle, const char *id1,
187                   afs_status_t error1, const char *id2, afs_status_t error2,
188                   idlist * ids, afs_status_p st)
189 {
190     int rc = 0;
191     afs_status_t tst = 0;
192     namelist names;
193     char tmp_array[2 * PTS_MAX_NAME_LEN];
194
195     /*
196      * Copy the group and user names in order to translate them
197      */
198
199     names.namelist_len = 2;
200     names.namelist_val = (prname *) & tmp_array[0];
201
202     strncpy(names.namelist_val[0], id1, PTS_MAX_NAME_LEN);
203     strncpy(names.namelist_val[1], id2, PTS_MAX_NAME_LEN);
204     ids->idlist_val = 0;
205     ids->idlist_len = 0;
206
207     /*
208      * Check that user and group aren't too long
209      * This is a cheaper check than calling strlen
210      */
211
212     if (names.namelist_val[0][PTS_MAX_NAME_LEN - 1] != 0) {
213         tst = error1;
214         goto fail_TranslateTwoNames;
215     }
216
217     if (names.namelist_val[0][PTS_MAX_NAME_LEN - 1] != 0) {
218         tst = error2;
219         goto fail_TranslateTwoNames;
220     }
221
222     /*
223      * Translate user and group into pts ID's
224      */
225
226     if (TranslatePTSNames(c_handle, &names, ids, &tst) == 0) {
227         goto fail_TranslateTwoNames;
228     }
229     rc = 1;
230
231
232   fail_TranslateTwoNames:
233
234     if (st != NULL) {
235         *st = tst;
236     }
237     return rc;
238 }
239
240 /*
241  * TranslateOneName - translate a pts name to its pts id.
242  *
243  * PARAMETERS
244  *
245  * IN cellHandle - a previously opened cellHandle that corresponds
246  * to the cell where the group exists.
247  *
248  * IN userName - the user to be translated.
249  *
250  * OUT idlist - the user pts id.
251  *
252  * LOCKS
253  *
254  * No locks are obtained or released by this function
255  *
256  * RETURN CODES
257  *
258  * Returns != 0 upon successful completion.
259  *
260  */
261
262 static int
263 TranslateOneName(const afs_cell_handle_p c_handle, const char *ptsName,
264                  afs_status_t tooLongError, afs_int32 * ptsId,
265                  afs_status_p st)
266 {
267     int rc = 0;
268     afs_status_t tst = 0;
269     namelist names[1];
270     char tmp_array[PTS_MAX_NAME_LEN];
271     idlist ids;
272
273     /*
274      * Copy the name in order to translate it
275      */
276
277     names[0].namelist_len = 1;
278     names[0].namelist_val = (prname *) & tmp_array[0];
279
280     strncpy(names[0].namelist_val, ptsName, PTS_MAX_NAME_LEN);
281     ids.idlist_val = 0;
282     ids.idlist_len = 0;
283
284     /*
285      * Check that user isn't too long
286      * This is a cheaper check than calling strlen
287      */
288
289     if (names[0].namelist_val[0][PTS_MAX_NAME_LEN - 1] != 0) {
290         tst = tooLongError;
291         goto fail_TranslateOneName;
292     }
293
294     /*
295      * Translate user into pts ID
296      */
297
298     if (TranslatePTSNames(c_handle, names, &ids, &tst) == 0) {
299         goto fail_TranslateOneName;
300     } else {
301         if (ids.idlist_val != NULL) {
302             *ptsId = *ids.idlist_val;
303             free(ids.idlist_val);
304         }
305     }
306     rc = 1;
307
308
309   fail_TranslateOneName:
310
311     if (st != NULL) {
312         *st = tst;
313     }
314     return rc;
315 }
316
317 /*
318  * TranslatePTSIds - translate numeric representations of pts names
319  * into their character equivalent.
320  *
321  * PARAMETERS
322  *
323  * IN cellHandle - a previously opened cellHandle that corresponds
324  * to the cell where the id's exist.
325  *
326  * IN ids - the list of ids to be translated.
327  *
328  * OUT names - the list of translated names
329  *
330  * LOCKS
331  *
332  * No locks are obtained or released by this function
333  *
334  * RETURN CODES
335  *
336  * Returns != 0 upon successful completion.
337  *
338  */
339
340 static int
341 TranslatePTSIds(const afs_cell_handle_p cellHandle, namelist * names,
342                 idlist * ids, afs_status_p st)
343 {
344     int rc = 0;
345     afs_status_t tst = 0;
346
347     tst = ubik_Call(PR_IDToName, cellHandle->pts, 0, ids, names);
348
349     if (tst) {
350         goto fail_TranslatePTSIds;
351     }
352     rc = 1;
353
354   fail_TranslatePTSIds:
355
356     if (st != NULL) {
357         *st = tst;
358     }
359     return rc;
360 }
361
362 /*
363  * pts_GroupMemberAdd - add one member to a pts group
364  *
365  * PARAMETERS
366  *
367  * IN cellHandle - a previously opened cellHandle that corresponds
368  * to the cell where the group exists.
369  *
370  * IN userName - the name to be added to the group.
371  *
372  * IN groupName - the group to be modified.
373  *
374  * LOCKS
375  *
376  * No locks are obtained or released by this function
377  *
378  * RETURN CODES
379  *
380  * Returns != 0 upon successful completion.
381  *
382  */
383
384 int ADMINAPI
385 pts_GroupMemberAdd(const void *cellHandle, const char *userName,
386                    const char *groupName, afs_status_p st)
387 {
388     int rc = 0;
389     afs_status_t tst = 0;
390     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
391         idlist ids = {0,0};
392
393     /*
394      * Validate arguments
395      */
396
397     if (!IsValidCellHandle(c_handle, &tst)) {
398         goto fail_pts_GroupMemberAdd;
399     }
400
401     if ((userName == NULL) || (*userName == 0)) {
402         tst = ADMPTSUSERNAMENULL;
403         goto fail_pts_GroupMemberAdd;
404     }
405
406     if ((groupName == NULL) || (*groupName == 0)) {
407         tst = ADMPTSGROUPNAMENULL;
408         goto fail_pts_GroupMemberAdd;
409     }
410
411     if (!TranslateTwoNames
412         (c_handle, userName, ADMPTSUSERNAMETOOLONG, groupName,
413          ADMPTSGROUPNAMETOOLONG, &ids, &tst)) {
414         goto fail_pts_GroupMemberAdd;
415     }
416
417     /*
418      * Make the rpc
419      */
420
421     tst =
422         ubik_Call(PR_AddToGroup, c_handle->pts, 0, ids.idlist_val[0],
423                   ids.idlist_val[1]);
424
425     if (tst != 0) {
426         goto fail_pts_GroupMemberAdd;
427     }
428     rc = 1;
429
430   fail_pts_GroupMemberAdd:
431
432     if (ids.idlist_val != 0) {
433         free(ids.idlist_val);
434     }
435
436     if (st != NULL) {
437         *st = tst;
438     }
439     return rc;
440 }
441
442 /*
443  * pts_GroupOwnerChange - change the owner of a group
444  *
445  * PARAMETERS
446  *
447  * IN cellHandle - a previously opened cellHandle that corresponds
448  * to the cell where the group exists.
449  *
450  * IN targetGroup - the group to be modified.
451  *
452  * IN userName - the new owner of the group.
453  *
454  * LOCKS
455  *
456  * No locks are obtained or released by this function
457  *
458  * RETURN CODES
459  *
460  * Returns != 0 upon successful completion.
461  *
462  */
463
464 int ADMINAPI
465 pts_GroupOwnerChange(const void *cellHandle, const char *targetGroup,
466                      const char *newOwner, afs_status_p st)
467 {
468     int rc = 0;
469     afs_status_t tst = 0;
470     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
471     idlist ids;
472
473     /*
474      * Validate arguments
475      */
476
477     if (!IsValidCellHandle(c_handle, &tst)) {
478         goto fail_pts_GroupOwnerChange;
479     }
480
481     if ((newOwner == NULL) || (*newOwner == 0)) {
482         tst = ADMPTSNEWOWNERNULL;
483         goto fail_pts_GroupOwnerChange;
484     }
485
486     if ((targetGroup == NULL) || (*targetGroup == 0)) {
487         tst = ADMPTSTARGETGROUPNULL;
488         goto fail_pts_GroupOwnerChange;
489     }
490
491     if (!TranslateTwoNames
492         (c_handle, newOwner, ADMPTSNEWOWNERTOOLONG, targetGroup,
493          ADMPTSTARGETGROUPTOOLONG, &ids, &tst)) {
494         goto fail_pts_GroupOwnerChange;
495     }
496
497     /*
498      * Make the rpc
499      */
500
501     tst =
502         ubik_Call(PR_ChangeEntry, c_handle->pts, 0, ids.idlist_val[1], "",
503                   ids.idlist_val[0], 0);
504
505     if (tst != 0) {
506         goto fail_pts_GroupOwnerChange;
507     }
508     rc = 1;
509
510   fail_pts_GroupOwnerChange:
511
512     if (ids.idlist_val != 0) {
513         free(ids.idlist_val);
514     }
515
516     if (st != NULL) {
517         *st = tst;
518     }
519     return rc;
520 }
521
522 /*
523  * pts_GroupCreate - create a new group
524  *
525  * PARAMETERS
526  *
527  * IN cellHandle - a previously opened cellHandle that corresponds
528  * to the cell where the group exists.
529  *
530  * IN newGroup - the group to be created.
531  *
532  * IN newOwner - the owner of the group.  Pass NULL if the current user
533  * is to be the new owner, or the character string of the owner otherwise.
534  *
535  * IN/OUT newGroupId - the pts id of the group.  Pass 0 to have ptserver 
536  * generate a value, != 0 to assign a value on your own.  The group id
537  * that is used to create the group is copied into this parameter in the
538  * event you pass in 0.
539  *
540  * LOCKS
541  *
542  * No locks are obtained or released by this function
543  *
544  * RETURN CODES
545  *
546  * Returns != 0 upon successful completion.
547  *
548  */
549
550 int ADMINAPI
551 pts_GroupCreate(const void *cellHandle, const char *newGroup,
552                 const char *newOwner, int *newGroupId, afs_status_p st)
553 {
554     int rc = 0;
555     afs_status_t tst = 0;
556     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
557     afs_int32 newOwnerId = 0;
558
559     /*
560      * Validate arguments
561      */
562
563     if (!IsValidCellHandle(c_handle, &tst)) {
564         goto fail_pts_GroupCreate;
565     }
566
567     if ((newGroup == NULL) || (*newGroup == 0)) {
568         tst = ADMPTSNEWGROUPNULL;
569         goto fail_pts_GroupCreate;
570     }
571
572     if (newGroupId == NULL) {
573         tst = ADMPTSNEWGROUPIDNULL;
574         goto fail_pts_GroupCreate;
575     }
576
577     if (*newGroupId > 0) {
578         tst = ADMPTSNEWGROUPIDPOSITIVE;
579         goto fail_pts_GroupCreate;
580     }
581
582     /*
583      * If a newOwner was specified, validate that it exists
584      */
585
586     if (newOwner != NULL) {
587         if (!TranslateOneName
588             (c_handle, newOwner, ADMPTSNEWOWNERTOOLONG, &newOwnerId, &tst)) {
589             goto fail_pts_GroupCreate;
590         }
591     }
592
593     /*
594      * We make a different rpc based upon the input to this function
595      */
596
597     if (*newGroupId != 0) {
598         tst =
599             ubik_Call(PR_INewEntry, c_handle->pts, 0, newGroup, *newGroupId,
600                       newOwnerId);
601     } else {
602         tst =
603             ubik_Call(PR_NewEntry, c_handle->pts, 0, newGroup, PRGRP,
604                       newOwnerId, newGroupId);
605     }
606
607     if (tst != 0) {
608         goto fail_pts_GroupCreate;
609     }
610     rc = 1;
611
612   fail_pts_GroupCreate:
613
614     if (st != NULL) {
615         *st = tst;
616     }
617     return rc;
618 }
619
620 /*
621  * GetGroupAccess - a small convenience function for setting
622  * permissions.
623  *
624  * PARAMETERS
625  *
626  * IN access - a pointer to a pts_groupAccess_t to be set with the
627  * correct permission.
628  *
629  * IN flag - the current permission flag used to derive the permission.
630  *
631  * LOCKS
632  *
633  * No locks are obtained or released by this function
634  *
635  * RETURN CODES
636  *
637  * Since this function cannot fail, it returns void.
638  *
639  */
640
641 static void
642 GetGroupAccess(pts_groupAccess_p access, afs_int32 flag)
643 {
644
645     *access = PTS_GROUP_OWNER_ACCESS;
646     if (flag == 0) {
647         *access = PTS_GROUP_OWNER_ACCESS;
648     } else if (flag == 1) {
649         *access = PTS_GROUP_ACCESS;
650     } else if (flag == 2) {
651         *access = PTS_GROUP_ANYUSER_ACCESS;
652     }
653 }
654
655
656 /*
657  * pts_GroupGet - retrieve information about a particular group.
658  *
659  * PARAMETERS
660  *
661  * IN cellHandle - a previously opened cellHandle that corresponds
662  * to the cell where the group exists.
663  *
664  * IN groupName - the group to retrieve.
665  *
666  * OUT groupP - a pointer to a pts_GroupEntry_t structure that upon
667  * successful completion is filled with information about groupName.
668  *
669  * LOCKS
670  *
671  * No locks are obtained or released by this function
672  *
673  * RETURN CODES
674  *
675  * Returns != 0 upon successful completion.
676  *
677  */
678
679 int ADMINAPI
680 pts_GroupGet(const void *cellHandle, const char *groupName,
681              pts_GroupEntry_p groupP, afs_status_p st)
682 {
683     int rc = 0;
684     afs_status_t tst = 0;
685     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
686     afs_int32 groupId = 0;
687     afs_int32 flags;
688     afs_int32 twobit;
689     struct prcheckentry groupEntry;
690     idlist ids;
691     afs_int32 ptsids[2];
692     namelist names;
693
694     /*
695      * Validate arguments
696      */
697
698     if (!IsValidCellHandle(c_handle, &tst)) {
699         goto fail_pts_GroupGet;
700     }
701
702     if ((groupName == NULL) || (*groupName == 0)) {
703         tst = ADMPTSGROUPNAMENULL;
704         goto fail_pts_GroupGet;
705     }
706
707     if (groupP == NULL) {
708         tst = ADMPTSGROUPPNULL;
709         goto fail_pts_GroupGet;
710     }
711
712     /*
713      * Translate the group name into an id.
714      */
715
716     if (!TranslateOneName
717         (c_handle, groupName, ADMPTSGROUPNAMETOOLONG, &groupId, &tst)) {
718         goto fail_pts_GroupGet;
719     }
720
721     /*
722      * Retrieve information about the group
723      */
724
725     tst = ubik_Call(PR_ListEntry, c_handle->pts, 0, groupId, &groupEntry);
726
727     if (tst != 0) {
728         goto fail_pts_GroupGet;
729     }
730
731     groupP->membershipCount = groupEntry.count;
732     groupP->nameUid = groupEntry.id;
733     groupP->ownerUid = groupEntry.owner;
734     groupP->creatorUid = groupEntry.creator;
735     strcpy(groupP->name, groupEntry.name);
736     /*
737      * Set the access rights based upon the value of the flags member
738      * of the groupEntry struct.
739      *
740      * To the best of my ability to decypher the pts code, it looks like
741      * the rights are stored in flags as follows:
742      *
743      * I number my bits from least significant to most significant starting
744      * with 0.
745      *
746      * remove - bit 0
747      *     if bit 0 == 0 -> r access is denied
748      *     if bit 0 == 1 -> r access is granted
749      *
750      * add - bits 1 and 2
751      *     if bit 2 == 0 and bit 1 == 0 -> a access is denied
752      *     if bit 2 == 0 and bit 1 == 1 -> a access is granted
753      *     if bit 2 == 1 and bit 1 == 0 -> A access is granted
754      *     if bit 2 == 1 and bit 1 == 1 -> this is an error
755      *
756      * membership - bits 3 and 4
757      *     if bit 4 == 0 and bit 3 == 0 -> m access is denied
758      *     if bit 4 == 0 and bit 3 == 1 -> m access is granted
759      *     if bit 4 == 1 and bit 3 == 0 -> M access is granted
760      *     if bit 4 == 1 and bit 3 == 1 -> this is an error
761      *
762      * owned - bit 5
763      *     if bit 5 == 0 -> O access is denied
764      *     if bit 5 == 1 -> O access is granted
765      *
766      * status - bits 6 and 7
767      *     if bit 7 == 0 and bit 6 == 0 -> s access is denied
768      *     if bit 7 == 0 and bit 6 == 1 -> s access is granted
769      *     if bit 7 == 1 and bit 6 == 0 -> S access is granted
770      *     if bit 7 == 1 and bit 6 == 1 -> this is an error
771      *
772      * For cases where the permission doesn't make sense for the
773      * type of entry, or where an error occurs, we ignore it.
774      * This is the behavior of the pts code.
775      */
776
777     flags = groupEntry.flags;
778     if (flags & 1) {
779         groupP->listDelete = PTS_GROUP_ACCESS;
780     } else {
781         groupP->listDelete = PTS_GROUP_OWNER_ACCESS;
782     }
783
784     flags = flags >> 1;
785     twobit = flags & 3;
786
787     GetGroupAccess(&groupP->listAdd, twobit);
788
789     flags = flags >> 2;
790     twobit = flags & 3;
791
792     GetGroupAccess(&groupP->listMembership, twobit);
793
794     flags = flags >> 2;
795
796     if (flags & 1) {
797         groupP->listGroupsOwned = PTS_GROUP_ANYUSER_ACCESS;
798     } else {
799         groupP->listGroupsOwned = PTS_GROUP_OWNER_ACCESS;
800     }
801
802     flags = flags >> 1;
803     twobit = flags & 3;
804
805     GetGroupAccess(&groupP->listStatus, twobit);
806
807     /* 
808      * Make another rpc and translate the owner and creator ids into
809      * character strings.
810      */
811
812     ids.idlist_len = 2;
813     ids.idlist_val = ptsids;
814     ptsids[0] = groupEntry.owner;
815     ptsids[1] = groupEntry.creator;
816     names.namelist_len = 0;
817     names.namelist_val = 0;
818
819
820     if (!TranslatePTSIds(c_handle, &names, &ids, &tst)) {
821         goto fail_pts_GroupGet;
822     }
823
824     strcpy(groupP->owner, names.namelist_val[0]);
825     strcpy(groupP->creator, names.namelist_val[1]);
826     free(names.namelist_val);
827     rc = 1;
828
829   fail_pts_GroupGet:
830
831     if (st != NULL) {
832         *st = tst;
833     }
834     return rc;
835 }
836
837 /*
838  * EntryDelete - delete a pts entry (group or user).
839  *
840  * PARAMETERS
841  *
842  * IN cellHandle - a previously opened cellHandle that corresponds
843  * to the cell where the group exists.
844  *
845  * IN entryName - the entry to be deleted.
846  *
847  * IN error1 - the error status to be returned in the event that entryName is
848  * null.
849  *
850  * IN error2 - the error status to be returned in the event that entryName is
851  * too long.
852  *
853  * LOCKS
854  *
855  * No locks are obtained or released by this function
856  *
857  * RETURN CODES
858  *
859  * Returns != 0 upon successful completion.
860  *
861  */
862
863 static int
864 EntryDelete(const void *cellHandle, const char *entryName,
865             afs_status_t error1, afs_status_t error2, afs_status_p st)
866 {
867     int rc = 0;
868     afs_status_t tst = 0;
869     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
870     afs_int32 entryId = 0;
871
872     /*
873      * Validate arguments
874      */
875
876     if (!IsValidCellHandle(c_handle, &tst)) {
877         goto fail_EntryDelete;
878     }
879
880     if ((entryName == NULL) || (*entryName == 0)) {
881         tst = error1;
882         goto fail_EntryDelete;
883     }
884
885     /*
886      * Translate the entry name into an id.
887      */
888
889     if (!TranslateOneName(c_handle, entryName, error2, &entryId, &tst)) {
890         goto fail_EntryDelete;
891     }
892
893     /*
894      * Make the rpc
895      */
896
897     tst = ubik_Call(PR_Delete, c_handle->pts, 0, entryId);
898
899     if (tst != 0) {
900         goto fail_EntryDelete;
901     }
902     rc = 1;
903
904   fail_EntryDelete:
905
906     if (st != NULL) {
907         *st = tst;
908     }
909     return rc;
910 }
911
912
913 /*
914  * pts_GroupDelete - delete a group
915  *
916  * PARAMETERS
917  *
918  * IN cellHandle - a previously opened cellHandle that corresponds
919  * to the cell where the group exists.
920  *
921  * IN groupName - the group to be deleted.
922  *
923  * LOCKS
924  *
925  * No locks are obtained or released by this function
926  *
927  * RETURN CODES
928  *
929  * Returns != 0 upon successful completion.
930  *
931  */
932
933 int ADMINAPI
934 pts_GroupDelete(const void *cellHandle, const char *groupName,
935                 afs_status_p st)
936 {
937
938     return EntryDelete(cellHandle, groupName, ADMPTSGROUPNAMENULL,
939                        ADMPTSGROUPNAMETOOLONG, st);
940 }
941
942 /*
943  * pts_GroupMaxGet - get the maximum in use group id.
944  *
945  * PARAMETERS
946  *
947  * IN cellHandle - a previously opened cellHandle that corresponds
948  * to the cell where the group exists.
949  *
950  * OUT maxGroupId - upon successful completion contains the maximum
951  * group Id in use at the server.
952  *
953  * LOCKS
954  *
955  * No locks are obtained or released by this function
956  *
957  * RETURN CODES
958  *
959  * Returns != 0 upon successful completion.
960  *
961  */
962
963 int ADMINAPI
964 pts_GroupMaxGet(const void *cellHandle, int *maxGroupId, afs_status_p st)
965 {
966     int rc = 0;
967     afs_status_t tst = 0;
968     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
969     afs_int32 maxUserId = 0;
970
971     /*
972      * Validate arguments
973      */
974
975     if (!IsValidCellHandle(c_handle, &tst)) {
976         goto fail_pts_GroupMaxGet;
977     }
978
979     if (maxGroupId == NULL) {
980         tst = ADMPTSMAXGROUPIDNULL;
981         goto fail_pts_GroupMaxGet;
982     }
983
984     tst = ubik_Call(PR_ListMax, c_handle->pts, 0, &maxUserId, maxGroupId);
985
986     if (tst != 0) {
987         goto fail_pts_GroupMaxGet;
988     }
989     rc = 1;
990
991   fail_pts_GroupMaxGet:
992
993     if (st != NULL) {
994         *st = tst;
995     }
996     return rc;
997 }
998
999 /*
1000  * pts_GroupMaxSet - set the maximum in use group id.
1001  *
1002  * PARAMETERS
1003  *
1004  * IN cellHandle - a previously opened cellHandle that corresponds
1005  * to the cell where the group exists.
1006  *
1007  * IN maxGroupId - the new maximum group id.
1008  *
1009  * LOCKS
1010  *
1011  * No locks are obtained or released by this function
1012  *
1013  * RETURN CODES
1014  *
1015  * Returns != 0 upon successful completion.
1016  *
1017  */
1018
1019 int ADMINAPI
1020 pts_GroupMaxSet(const void *cellHandle, int maxGroupId, afs_status_p st)
1021 {
1022     int rc = 0;
1023     afs_status_t tst = 0;
1024     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1025
1026     /*
1027      * Validate arguments
1028      */
1029
1030     if (!IsValidCellHandle(c_handle, &tst)) {
1031         goto fail_pts_GroupMaxSet;
1032     }
1033
1034     tst = ubik_Call(PR_SetMax, c_handle->pts, 0, maxGroupId, PRGRP);
1035
1036     if (tst != 0) {
1037         goto fail_pts_GroupMaxSet;
1038     }
1039     rc = 1;
1040
1041   fail_pts_GroupMaxSet:
1042
1043     if (st != NULL) {
1044         *st = tst;
1045     }
1046     return rc;
1047 }
1048
1049 /*
1050  * NOTE
1051  *
1052  * I'm not using the common iterator pattern here since the retrival
1053  * of the member list is actually accomplished in 1 rpc.  There's no
1054  * sense in trying to fit this pts specific behavior into the more
1055  * generic model, so instead the Begin functions actually do all the
1056  * rpc work and the next/done functions just manipulate the retrieved
1057  * data.
1058  */
1059
1060 typedef struct pts_group_member_list_iterator {
1061     int begin_magic;
1062     int is_valid;
1063     pthread_mutex_t mutex;      /* hold to manipulate this structure */
1064     prlist ids;
1065     namelist names;
1066     int index;
1067     int end_magic;
1068 } pts_group_member_list_iterator_t, *pts_group_member_list_iterator_p;
1069
1070 /*
1071  * pts_GroupMemberListBegin - begin iterating over the list of members
1072  * of a particular group.
1073  *
1074  * PARAMETERS
1075  *
1076  * IN iter - an iterator previously returned by pts_GroupMemberListBegin
1077  *
1078  * LOCKS
1079  *
1080  * No locks are obtained or released by this function
1081  *
1082  * RETURN CODES
1083  *
1084  * Returns != 0 upon successful completion.
1085  *
1086  */
1087
1088 static int
1089 IsValidPtsGroupMemberListIterator(pts_group_member_list_iterator_p iter,
1090                                   afs_status_p st)
1091 {
1092     int rc = 0;
1093     afs_status_t tst = 0;
1094
1095     if (iter == NULL) {
1096         tst = ADMITERATORNULL;
1097         goto fail_IsValidPtsGroupMemberListIterator;
1098     }
1099
1100     if ((iter->begin_magic != BEGIN_MAGIC) || (iter->end_magic != END_MAGIC)) {
1101         tst = ADMITERATORBADMAGICNULL;
1102         goto fail_IsValidPtsGroupMemberListIterator;
1103     }
1104
1105     if (iter->is_valid == 0) {
1106         tst = ADMITERATORINVALID;
1107         goto fail_IsValidPtsGroupMemberListIterator;
1108     }
1109     rc = 1;
1110
1111   fail_IsValidPtsGroupMemberListIterator:
1112
1113     if (st != NULL) {
1114         *st = tst;
1115     }
1116     return rc;
1117 }
1118
1119 /*
1120  * MemberListBegin - an internal function which is used to get both
1121  * the list of members in a group and the list of groups a user belongs
1122  * to.
1123  *
1124  * PARAMETERS
1125  *
1126  * IN cellHandle - a previously opened cellHandle that corresponds
1127  * to the cell where the group exists.
1128  *
1129  * IN name - the name whose membership will be retrieved.
1130  *
1131  * OUT iterationIdP - upon successful completion contains a iterator that
1132  * can be passed to pts_GroupMemberListNext or pts_UserMemberListNext
1133  *
1134  * LOCKS
1135  *
1136  * No locks are obtained or released by this function
1137  *
1138  * RETURN CODES
1139  *
1140  * Returns != 0 upon successful completion.
1141  *
1142  */
1143
1144 static int
1145 MemberListBegin(const void *cellHandle, const char *name, afs_status_t error1,
1146                 afs_status_t error2, void **iterationIdP, afs_status_p st)
1147 {
1148     int rc = 0;
1149     afs_status_t tst = 0;
1150     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1151     afs_int32 groupId = 0;
1152     afs_int32 exceeded = 0;
1153     pts_group_member_list_iterator_p iter = (pts_group_member_list_iterator_p)
1154         malloc(sizeof(pts_group_member_list_iterator_t));
1155     int iter_allocated = 0;
1156     int ids_allocated = 0;
1157     int names_allocated = 0;
1158     int mutex_inited = 0;
1159
1160     /*
1161      * Validate arguments
1162      */
1163
1164     if (!IsValidCellHandle(c_handle, &tst)) {
1165         goto fail_MemberListBegin;
1166     }
1167
1168     if ((name == NULL) || (*name == 0)) {
1169         tst = ADMPTSGROUPNAMENULL;
1170         goto fail_MemberListBegin;
1171     }
1172
1173     if (iterationIdP == NULL) {
1174         tst = ADMITERATORNULL;
1175         goto fail_MemberListBegin;
1176     }
1177
1178     if (iter == NULL) {
1179         tst = ADMNOMEM;
1180         goto fail_MemberListBegin;
1181     }
1182
1183     iter_allocated = 1;
1184
1185     /*
1186      * Translate the name into an id.
1187      */
1188
1189     if (!TranslateOneName
1190         (c_handle, name, ADMPTSGROUPNAMETOOLONG, &groupId, &tst)) {
1191         goto fail_MemberListBegin;
1192     }
1193
1194     if (pthread_mutex_init(&iter->mutex, 0)) {
1195         tst = ADMMUTEXINIT;
1196         goto fail_MemberListBegin;
1197     }
1198
1199     mutex_inited = 1;
1200
1201     iter->ids.prlist_len = 0;
1202     iter->ids.prlist_val = 0;
1203
1204     tst =
1205         ubik_Call(PR_ListElements, c_handle->pts, 0, groupId, &iter->ids,
1206                   &exceeded);
1207
1208     if (tst != 0) {
1209         goto fail_MemberListBegin;
1210     }
1211
1212     if (exceeded != 0) {
1213         tst = ADMPTSGROUPMEMEXCEEDED;
1214         goto fail_MemberListBegin;
1215     }
1216
1217     ids_allocated = 1;
1218     iter->names.namelist_len = 0;
1219     iter->names.namelist_val = 0;
1220
1221     if (!TranslatePTSIds
1222         (c_handle, &iter->names, (idlist *) & iter->ids, &tst)) {
1223         goto fail_MemberListBegin;
1224     }
1225
1226     names_allocated = 1;
1227     iter->begin_magic = BEGIN_MAGIC;
1228     iter->end_magic = END_MAGIC;
1229     iter->index = 0;
1230     iter->is_valid = 1;
1231
1232     *iterationIdP = (void *)iter;
1233     rc = 1;
1234
1235   fail_MemberListBegin:
1236
1237     if (ids_allocated) {
1238         free(iter->ids.prlist_val);
1239     }
1240
1241     if (rc == 0) {
1242         if (names_allocated) {
1243             free(iter->names.namelist_val);
1244         }
1245         if (mutex_inited) {
1246             pthread_mutex_destroy(&iter->mutex);
1247         }
1248         if (iter_allocated) {
1249             free(iter);
1250         }
1251     }
1252     if (st != NULL) {
1253         *st = tst;
1254     }
1255     return rc;
1256 }
1257
1258
1259 /*
1260  * pts_GroupMemberListBegin - begin iterating over the list of members
1261  * of a particular group.
1262  *
1263  * PARAMETERS
1264  *
1265  * IN cellHandle - a previously opened cellHandle that corresponds
1266  * to the cell where the group exists.
1267  *
1268  * IN groupName - the group whose members will be returned.
1269  *
1270  * OUT iterationIdP - upon successful completion contains a iterator that
1271  * can be passed to pts_GroupMemberListNext.
1272  *
1273  * LOCKS
1274  *
1275  * No locks are obtained or released by this function
1276  *
1277  * RETURN CODES
1278  *
1279  * Returns != 0 upon successful completion.
1280  *
1281  */
1282
1283 int ADMINAPI
1284 pts_GroupMemberListBegin(const void *cellHandle, const char *groupName,
1285                          void **iterationIdP, afs_status_p st)
1286 {
1287     return MemberListBegin(cellHandle, groupName, ADMPTSGROUPNAMENULL,
1288                            ADMPTSGROUPNAMETOOLONG, iterationIdP, st);
1289 }
1290
1291 /*
1292  * pts_GroupMemberListNext - get the next member of a group
1293  *
1294  * PARAMETERS
1295  *
1296  * IN iterationId - an iterator previously returned by pts_GroupMemberListBegin
1297  *
1298  * OUT memberName - upon successful completion contains the next member of
1299  * a group.
1300  *
1301  * LOCKS
1302  *
1303  * The iterator mutex is held during the retrieval of the next member.
1304  *
1305  * RETURN CODES
1306  *
1307  * Returns != 0 upon successful completion.
1308  *
1309  */
1310
1311 int ADMINAPI
1312 pts_GroupMemberListNext(const void *iterationId, char *memberName,
1313                         afs_status_p st)
1314 {
1315     int rc = 0;
1316     afs_status_t tst = 0;
1317     pts_group_member_list_iterator_p iter =
1318         (pts_group_member_list_iterator_p) iterationId;
1319     int mutex_locked = 0;
1320
1321     /*
1322      * Validate arguments
1323      */
1324
1325     if (iter == NULL) {
1326         tst = ADMITERATORNULL;
1327         goto fail_pts_GroupMemberListNext;
1328     }
1329
1330     if (memberName == NULL) {
1331         tst = ADMPTSMEMBERNAMENULL;
1332         goto fail_pts_GroupMemberListNext;
1333     }
1334
1335     /*
1336      * Lock the mutex and check the validity of the iterator
1337      */
1338
1339     if (pthread_mutex_lock(&iter->mutex)) {
1340         tst = ADMMUTEXLOCK;
1341         goto fail_pts_GroupMemberListNext;
1342     }
1343
1344     mutex_locked = 1;
1345
1346     if (!IsValidPtsGroupMemberListIterator(iter, &tst)) {
1347         goto fail_pts_GroupMemberListNext;
1348     }
1349
1350     /*
1351      * Check to see if we've copied out all the data.  If we haven't,
1352      * copy another item.  If we have, mark the iterator done.
1353      */
1354
1355     if (iter->index >= iter->names.namelist_len) {
1356         tst = ADMITERATORDONE;
1357         goto fail_pts_GroupMemberListNext;
1358     } else {
1359         strcpy(memberName, iter->names.namelist_val[iter->index]);
1360         iter->index++;
1361     }
1362     rc = 1;
1363
1364   fail_pts_GroupMemberListNext:
1365
1366     if (mutex_locked) {
1367         pthread_mutex_unlock(&iter->mutex);
1368     }
1369
1370     if (st != NULL) {
1371         *st = tst;
1372     }
1373     return rc;
1374 }
1375
1376 /*
1377  * pts_GroupMemberListDone - finish using a member list iterator
1378  *
1379  * PARAMETERS
1380  *
1381  * IN iterationId - an iterator previously returned by pts_GroupMemberListBegin
1382  *
1383  * LOCKS
1384  *
1385  * The iterator is locked and then destroyed
1386  *
1387  * RETURN CODES
1388  *
1389  * Returns != 0 upon successful completion.
1390  *
1391  * ASSUMPTIONS
1392  *
1393  * It is the user's responsibility to make sure pts_GroupMemberListDone
1394  * is called only once for each iterator.
1395  */
1396
1397 int ADMINAPI
1398 pts_GroupMemberListDone(const void *iterationId, afs_status_p st)
1399 {
1400     int rc = 0;
1401     afs_status_t tst = 0;
1402     pts_group_member_list_iterator_p iter =
1403         (pts_group_member_list_iterator_p) iterationId;
1404     int mutex_locked = 0;
1405
1406     /*
1407      * Validate arguments
1408      */
1409
1410     if (iter == NULL) {
1411         tst = ADMITERATORNULL;
1412         goto fail_pts_GroupMemberListDone;
1413     }
1414
1415     /*
1416      * Lock the mutex and check the validity of the iterator
1417      */
1418
1419     if (pthread_mutex_lock(&iter->mutex)) {
1420         tst = ADMMUTEXLOCK;
1421         goto fail_pts_GroupMemberListDone;
1422     }
1423
1424     mutex_locked = 1;
1425
1426     if (!IsValidPtsGroupMemberListIterator(iter, &tst)) {
1427         goto fail_pts_GroupMemberListDone;
1428     }
1429
1430     /*
1431      * Free the namelist and the iterator.
1432      */
1433
1434     pthread_mutex_destroy(&iter->mutex);
1435     mutex_locked = 0;
1436     iter->is_valid = 0;
1437     free(iter->names.namelist_val);
1438     free(iter);
1439     rc = 1;
1440
1441   fail_pts_GroupMemberListDone:
1442
1443     if (mutex_locked) {
1444         pthread_mutex_unlock(&iter->mutex);
1445     }
1446
1447     if (st != NULL) {
1448         *st = tst;
1449     }
1450     return rc;
1451 }
1452
1453 /*
1454  * pts_GroupMemberRemove - remove a member from a group.
1455  *
1456  * PARAMETERS
1457  *
1458  * IN cellHandle - a previously opened cellHandle that corresponds
1459  * to the cell where the group exists.
1460  *
1461  * IN userName - the user to remove.
1462  *
1463  * IN groupName - the group to modify
1464  *
1465  * LOCKS
1466  *
1467  * No locks are held by this function
1468  *
1469  * RETURN CODES
1470  *
1471  * Returns != 0 upon successful completion.
1472  *
1473  */
1474
1475 int ADMINAPI
1476 pts_GroupMemberRemove(const void *cellHandle, const char *userName,
1477                       const char *groupName, afs_status_p st)
1478 {
1479     int rc = 0;
1480     afs_status_t tst = 0;
1481     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1482     idlist ids;
1483
1484     /*
1485      * Validate arguments
1486      */
1487
1488     if (!IsValidCellHandle(c_handle, &tst)) {
1489         goto fail_pts_GroupMemberRemove;
1490     }
1491
1492     if ((userName == NULL) || (*userName == 0)) {
1493         tst = ADMPTSUSERNAMENULL;
1494         goto fail_pts_GroupMemberRemove;
1495     }
1496
1497     if ((groupName == NULL) || (*groupName == 0)) {
1498         tst = ADMPTSGROUPNAMENULL;
1499         goto fail_pts_GroupMemberRemove;
1500     }
1501
1502     if (!TranslateTwoNames
1503         (c_handle, userName, ADMPTSUSERNAMETOOLONG, groupName,
1504          ADMPTSGROUPNAMETOOLONG, &ids, &tst)) {
1505         goto fail_pts_GroupMemberRemove;
1506     }
1507
1508     /*
1509      * Make the rpc
1510      */
1511
1512     tst =
1513         ubik_Call(PR_RemoveFromGroup, c_handle->pts, 0, ids.idlist_val[0],
1514                   ids.idlist_val[1]);
1515
1516     if (tst != 0) {
1517         goto fail_pts_GroupMemberRemove;
1518     }
1519     rc = 1;
1520
1521   fail_pts_GroupMemberRemove:
1522
1523     if (ids.idlist_val != 0) {
1524         free(ids.idlist_val);
1525     }
1526
1527     if (st != NULL) {
1528         *st = tst;
1529     }
1530     return rc;
1531 }
1532
1533 /*
1534  * pts_GroupRename - change the name of a group
1535  *
1536  * PARAMETERS
1537  *
1538  * IN cellHandle - a previously opened cellHandle that corresponds
1539  * to the cell where the group exists.
1540  *
1541  * IN oldName - the current group name
1542  *
1543  * IN newName - the new group name
1544  *
1545  * LOCKS
1546  *
1547  * No locks are held by this function
1548  *
1549  * RETURN CODES
1550  *
1551  * Returns != 0 upon successful completion.
1552  *
1553  */
1554
1555 int ADMINAPI
1556 pts_GroupRename(const void *cellHandle, const char *oldName,
1557                 const char *newName, afs_status_p st)
1558 {
1559     int rc = 0;
1560     afs_status_t tst = 0;
1561     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1562     afs_int32 groupId = 0;
1563
1564     /*
1565      * Validate arguments
1566      */
1567
1568     if (!IsValidCellHandle(c_handle, &tst)) {
1569         goto fail_pts_GroupRename;
1570     }
1571
1572     if ((newName == NULL) || (*newName == 0)) {
1573         tst = ADMPTSNEWNAMENULL;
1574         goto fail_pts_GroupRename;
1575     }
1576
1577     if ((oldName == NULL) || (*oldName == 0)) {
1578         tst = ADMPTSOLDNAMENULL;
1579         goto fail_pts_GroupRename;
1580     }
1581
1582     /*
1583      * Translate the group name into an id.
1584      */
1585
1586     if (!TranslateOneName
1587         (c_handle, oldName, ADMPTSOLDNAMETOOLONG, &groupId, &tst)) {
1588         goto fail_pts_GroupRename;
1589     }
1590
1591     /*
1592      * Make the rpc
1593      */
1594
1595     tst = ubik_Call(PR_ChangeEntry, c_handle->pts, 0, groupId, newName, 0, 0);
1596
1597     if (tst != 0) {
1598         goto fail_pts_GroupRename;
1599     }
1600     rc = 1;
1601
1602   fail_pts_GroupRename:
1603
1604     if (st != NULL) {
1605         *st = tst;
1606     }
1607     return rc;
1608 }
1609
1610 /*
1611  * SetGroupAccess - translate our Access notation to pts flags.
1612  *
1613  * PARAMETERS
1614  *
1615  * IN rights - the permissions.
1616  *
1617  * OUT flags - a pointer to an afs_int32 structure that 
1618  * contains the flags to pass to pts.
1619  *
1620  * LOCKS
1621  *
1622  * No locks are held by this function
1623  *
1624  * RETURN CODES
1625  *
1626  * Returns != 0 upon successful completion.
1627  *
1628  */
1629
1630 static int
1631 SetGroupAccess(const pts_GroupUpdateEntry_p rights, afs_int32 * flags,
1632                afs_status_p st)
1633 {
1634     int rc = 0;
1635     afs_status_t tst = 0;
1636
1637     *flags = 0;
1638
1639     if (rights->listDelete == PTS_GROUP_ACCESS) {
1640         *flags |= 1;
1641     } else if (rights->listDelete == PTS_GROUP_ANYUSER_ACCESS) {
1642         tst = ADMPTSINVALIDGROUPDELETEPERM;
1643         goto fail_SetGroupAccess;
1644     }
1645
1646     if (rights->listAdd == PTS_GROUP_ACCESS) {
1647         *flags |= 2;
1648     } else if (rights->listAdd == PTS_GROUP_ANYUSER_ACCESS) {
1649         *flags |= 4;
1650     }
1651
1652     if (rights->listMembership == PTS_GROUP_ACCESS) {
1653         *flags |= 8;
1654     } else if (rights->listMembership == PTS_GROUP_ANYUSER_ACCESS) {
1655         *flags |= 16;
1656     }
1657
1658     if (rights->listGroupsOwned == PTS_GROUP_ANYUSER_ACCESS) {
1659         *flags |= 32;
1660     } else if (rights->listGroupsOwned == PTS_GROUP_ACCESS) {
1661         tst = ADMPTSINVALIDGROUPSOWNEDPERM;
1662         goto fail_SetGroupAccess;
1663     }
1664
1665     if (rights->listStatus == PTS_GROUP_ACCESS) {
1666         *flags |= 64;
1667     } else if (rights->listStatus == PTS_GROUP_ANYUSER_ACCESS) {
1668         *flags |= 128;
1669     }
1670     rc = 1;
1671
1672   fail_SetGroupAccess:
1673
1674     if (st != NULL) {
1675         *st = tst;
1676     }
1677     return rc;
1678 }
1679
1680 /*
1681  * pts_GroupModify - change the contents of a group entry.
1682  *
1683  * PARAMETERS
1684  *
1685  * IN cellHandle - a previously opened cellHandle that corresponds
1686  * to the cell where the group exists.
1687  *
1688  * IN groupName - the group to change
1689  *
1690  * OUT newEntryP - a pointer to a pts_GroupUpdateEntry_t structure that 
1691  * contains the new information for the group.
1692  *
1693  * LOCKS
1694  *
1695  * No locks are held by this function
1696  *
1697  * RETURN CODES
1698  *
1699  * Returns != 0 upon successful completion.
1700  *
1701  */
1702
1703 int ADMINAPI
1704 pts_GroupModify(const void *cellHandle, const char *groupName,
1705                 const pts_GroupUpdateEntry_p newEntryP, afs_status_p st)
1706 {
1707     int rc = 0;
1708     afs_status_t tst = 0;
1709     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1710     afs_int32 groupId = 0;
1711     afs_int32 flags = 0;
1712
1713     /*
1714      * Validate arguments
1715      */
1716
1717     if (!IsValidCellHandle(c_handle, &tst)) {
1718         goto fail_pts_GroupModify;
1719     }
1720
1721     if ((groupName == NULL) || (*groupName == 0)) {
1722         tst = ADMPTSGROUPNAMENULL;
1723         goto fail_pts_GroupModify;
1724     }
1725
1726
1727     if (newEntryP == NULL) {
1728         tst = ADMPTSNEWENTRYPNULL;
1729         goto fail_pts_GroupModify;
1730     }
1731
1732     /*
1733      * Translate the group name into an id.
1734      */
1735
1736     if (!TranslateOneName
1737         (c_handle, groupName, ADMPTSGROUPNAMETOOLONG, &groupId, &tst)) {
1738         goto fail_pts_GroupModify;
1739     }
1740
1741     /*
1742      * Set the flags argument
1743      */
1744
1745     if (!SetGroupAccess(newEntryP, &flags, &tst)) {
1746         goto fail_pts_GroupModify;
1747     }
1748
1749     /*
1750      * Make the rpc
1751      */
1752
1753     tst =
1754         ubik_Call(PR_SetFieldsEntry, c_handle->pts, 0, groupId, PR_SF_ALLBITS,
1755                   flags, 0, 0, 0, 0);
1756
1757     if (tst != 0) {
1758         goto fail_pts_GroupModify;
1759     }
1760     rc = 1;
1761
1762   fail_pts_GroupModify:
1763
1764     if (st != NULL) {
1765         *st = tst;
1766     }
1767     return rc;
1768 }
1769
1770 /*
1771  * pts_UserCreate - create a new user.
1772  *
1773  * PARAMETERS
1774  *
1775  * IN cellHandle - a previously opened cellHandle that corresponds
1776  * to the cell where the group exists.
1777  *
1778  * IN newUser - the name of the new user.
1779  *
1780  * IN newUserId - the id to assign to the new user.  Pass 0 to have the
1781  * id assigned by pts.
1782  *
1783  * LOCKS
1784  *
1785  * No locks are held by this function
1786  *
1787  * RETURN CODES
1788  *
1789  * Returns != 0 upon successful completion.
1790  *
1791  */
1792
1793 int ADMINAPI
1794 pts_UserCreate(const void *cellHandle, const char *userName, int *newUserId,
1795                afs_status_p st)
1796 {
1797     int rc = 0;
1798     afs_status_t tst = 0;
1799     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1800     afs_int32 userId = 0;
1801
1802     /*
1803      * Validate arguments
1804      */
1805
1806     if (!IsValidCellHandle(c_handle, &tst)) {
1807         goto fail_pts_UserCreate;
1808     }
1809
1810     if ((userName == NULL) || (*userName == 0)) {
1811         tst = ADMPTSUSERNAMENULL;
1812         goto fail_pts_UserCreate;
1813     }
1814
1815     if (newUserId == NULL) {
1816         tst = ADMPTSNEWUSERIDNULL;
1817         goto fail_pts_UserCreate;
1818     }
1819
1820     /*
1821      * We make a different rpc based upon the input to this function
1822      */
1823
1824     if (*newUserId != 0) {
1825         tst =
1826             ubik_Call(PR_INewEntry, c_handle->pts, 0, userName, *newUserId,
1827                       0);
1828     } else {
1829         tst =
1830             ubik_Call(PR_NewEntry, c_handle->pts, 0, userName, 0, 0,
1831                       newUserId);
1832     }
1833
1834     if (tst != 0) {
1835         goto fail_pts_UserCreate;
1836     }
1837     rc = 1;
1838
1839   fail_pts_UserCreate:
1840
1841     if (st != NULL) {
1842         *st = tst;
1843     }
1844     return rc;
1845 }
1846
1847 /*
1848  * pts_UserDelete - delete a user.
1849  *
1850  * PARAMETERS
1851  *
1852  * IN cellHandle - a previously opened cellHandle that corresponds
1853  * to the cell where the group exists.
1854  *
1855  * IN user - the name of the user to delete.
1856  *
1857  * LOCKS
1858  *
1859  * No locks are held by this function
1860  *
1861  * RETURN CODES
1862  *
1863  * Returns != 0 upon successful completion.
1864  *
1865  */
1866
1867 int ADMINAPI
1868 pts_UserDelete(const void *cellHandle, const char *userName, afs_status_p st)
1869 {
1870     return EntryDelete(cellHandle, userName, ADMPTSUSERNAMENULL,
1871                        ADMPTSUSERNAMETOOLONG, st);
1872 }
1873
1874
1875 /*
1876  * GetUserAccess - a small convenience function for setting
1877  * permissions.
1878  *
1879  * PARAMETERS
1880  *
1881  * IN access - a pointer to a pts_userAccess_t to be set with the
1882  * correct permission.
1883  *
1884  * IN flag - the current permission flag used to derive the permission.
1885  *
1886  * LOCKS
1887  *
1888  * No locks are obtained or released by this function
1889  *
1890  * RETURN CODES
1891  *
1892  * Since this function cannot fail, it returns void.
1893  *
1894  */
1895
1896 static void
1897 GetUserAccess(pts_userAccess_p access, afs_int32 flag)
1898 {
1899
1900     *access = PTS_USER_OWNER_ACCESS;
1901     if (flag == 2) {
1902         *access = PTS_USER_ANYUSER_ACCESS;
1903     }
1904 }
1905
1906 /*
1907  * IsAdministrator - determine if a user is an administrator.
1908  *
1909  * PARAMETERS
1910  *
1911  * IN cellHandle - a previously opened cellHandle that corresponds
1912  * to the cell where the group exists.
1913  *
1914  * IN userEntry - the user data for the user in question.
1915  *
1916  * OUT admin - set to 1 if the user is an administrator, 0 otherwise.
1917  *
1918  * LOCKS
1919  *
1920  * No locks are held by this function
1921  *
1922  * RETURN CODES
1923  *
1924  * Returns != 0 upon successful completion.
1925  *
1926  */
1927
1928 static int
1929 IsAdministrator(const afs_cell_handle_p c_handle, afs_int32 userId,
1930                 int *admin, afs_status_p st)
1931 {
1932     int rc = 0;
1933     afs_status_t tst = 0;
1934     afs_int32 adminId = 0;
1935     afs_int32 isAdmin = 0;
1936
1937     *admin = 0;
1938
1939     if (userId == SYSADMINID) {
1940         *admin = 1;
1941     } else {
1942         if (!TranslateOneName
1943             (c_handle, "system:administrators", ADMPTSGROUPNAMETOOLONG,
1944              &adminId, &tst)) {
1945             goto fail_IsAdministrator;
1946         }
1947         tst =
1948             ubik_Call(PR_IsAMemberOf, c_handle->pts, 0, userId, adminId,
1949                       &isAdmin);
1950         if (tst != 0) {
1951             goto fail_IsAdministrator;
1952         }
1953         if (isAdmin) {
1954             *admin = 1;
1955         }
1956     }
1957     rc = 1;
1958
1959   fail_IsAdministrator:
1960
1961     if (st != NULL) {
1962         *st = tst;
1963     }
1964     return rc;
1965 }
1966
1967 /*
1968  * pts_UserGet - retrieve information about a particular user.
1969  *
1970  * PARAMETERS
1971  *
1972  * IN cellHandle - a previously opened cellHandle that corresponds
1973  * to the cell where the group exists.
1974  *
1975  * IN userName - the name of the user to retrieve.
1976  *
1977  * OUT userP - a pointer to a pts_UserEntry_t that is filled upon successful
1978  * completion.
1979  *
1980  * LOCKS
1981  *
1982  * No locks are held by this function
1983  *
1984  * RETURN CODES
1985  *
1986  * Returns != 0 upon successful completion.
1987  *
1988  */
1989
1990 int ADMINAPI
1991 pts_UserGet(const void *cellHandle, const char *userName,
1992             pts_UserEntry_p userP, afs_status_p st)
1993 {
1994     int rc = 0;
1995     afs_status_t tst = 0;
1996     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
1997     struct prcheckentry userEntry;
1998     afs_int32 userId = 0;
1999     afs_int32 flags;
2000     afs_int32 twobit;
2001     idlist ids;
2002     afs_int32 ptsids[2];
2003     namelist names;
2004     int admin = 0;
2005
2006
2007     /*
2008      * Validate arguments
2009      */
2010
2011     if (!IsValidCellHandle(c_handle, &tst)) {
2012         goto fail_pts_UserGet;
2013     }
2014
2015     if ((userName == NULL) || (*userName == 0)) {
2016         tst = ADMPTSUSERNAMENULL;
2017         goto fail_pts_UserGet;
2018     }
2019
2020     if (userP == NULL) {
2021         tst = ADMPTSUSERPNULL;
2022         goto fail_pts_UserGet;
2023     }
2024
2025     /*
2026      * Translate the group name into an id.
2027      */
2028
2029     if (!TranslateOneName
2030         (c_handle, userName, ADMPTSUSERNAMETOOLONG, &userId, &tst)) {
2031         goto fail_pts_UserGet;
2032     }
2033
2034     /*
2035      * Retrieve information about the group
2036      */
2037
2038     tst = ubik_Call(PR_ListEntry, c_handle->pts, 0, userId, &userEntry);
2039
2040     if (tst != 0) {
2041         goto fail_pts_UserGet;
2042     }
2043
2044     userP->groupMembershipCount = userEntry.count;
2045     userP->groupCreationQuota = userEntry.ngroups;
2046     /*
2047      * The administrator id, or any member of "system:administrators"
2048      * has unlimited group creation quota.  Denote this by setting
2049      * quota to -1.
2050      */
2051
2052     if (!IsAdministrator(c_handle, userEntry.id, &admin, &tst)) {
2053         goto fail_pts_UserGet;
2054     }
2055
2056     if (admin != 0) {
2057         userP->groupCreationQuota = -1;
2058     }
2059
2060     userP->nameUid = userEntry.id;
2061     userP->ownerUid = userEntry.owner;
2062     userP->creatorUid = userEntry.creator;
2063     strcpy(userP->name, userEntry.name);
2064
2065     /*
2066      * The permission bits are described in the GroupGet function above.
2067      * The user entry only uses 3 of the 5 permissions, so we shift
2068      * past the unused entries.
2069      */
2070
2071     flags = userEntry.flags;
2072     flags = flags >> 3;
2073     twobit = flags & 3;
2074
2075     GetUserAccess(&userP->listMembership, twobit);
2076
2077     flags = flags >> 2;
2078
2079     if (flags & 1) {
2080         userP->listGroupsOwned = PTS_USER_ANYUSER_ACCESS;
2081     } else {
2082         userP->listGroupsOwned = PTS_USER_OWNER_ACCESS;
2083     }
2084
2085     flags = flags >> 1;
2086     twobit = flags & 3;
2087
2088     GetUserAccess(&userP->listStatus, twobit);
2089
2090     /* 
2091      * Make another rpc and translate the owner and creator ids into
2092      * character strings.
2093      */
2094
2095     ids.idlist_len = 2;
2096     ids.idlist_val = ptsids;
2097     ptsids[0] = userEntry.owner;
2098     ptsids[1] = userEntry.creator;
2099     names.namelist_len = 0;
2100     names.namelist_val = 0;
2101
2102
2103     if (!TranslatePTSIds(c_handle, &names, &ids, &tst)) {
2104         goto fail_pts_UserGet;
2105     }
2106
2107     strcpy(userP->owner, names.namelist_val[0]);
2108     strcpy(userP->creator, names.namelist_val[1]);
2109     free(names.namelist_val);
2110     rc = 1;
2111
2112   fail_pts_UserGet:
2113
2114     if (st != NULL) {
2115         *st = tst;
2116     }
2117     return rc;
2118 }
2119
2120 /*
2121  * pts_UserRename - rename a user.
2122  *
2123  * PARAMETERS
2124  *
2125  * IN cellHandle - a previously opened cellHandle that corresponds
2126  * to the cell where the group exists.
2127  *
2128  * IN oldName - the name of the user to rename.
2129  *
2130  * IN newName - the new user name.
2131  *
2132  * LOCKS
2133  *
2134  * No locks are held by this function
2135  *
2136  * RETURN CODES
2137  *
2138  * Returns != 0 upon successful completion.
2139  *
2140  */
2141
2142 int ADMINAPI
2143 pts_UserRename(const void *cellHandle, const char *oldName,
2144                const char *newName, afs_status_p st)
2145 {
2146     int rc = 0;
2147     afs_status_t tst = 0;
2148     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2149     afs_int32 userId = 0;
2150
2151     /*
2152      * Validate arguments
2153      */
2154
2155     if (!IsValidCellHandle(c_handle, &tst)) {
2156         goto fail_pts_UserRename;
2157     }
2158
2159     if ((oldName == NULL) || (*oldName == 0)) {
2160         tst = ADMPTSOLDNAMENULL;
2161         goto fail_pts_UserRename;
2162     }
2163
2164     if ((newName == NULL) || (*newName == 0)) {
2165         tst = ADMPTSNEWNAMENULL;
2166         goto fail_pts_UserRename;
2167     }
2168
2169     /*
2170      * Translate the user name into an id.
2171      */
2172
2173     if (!TranslateOneName
2174         (c_handle, oldName, ADMPTSOLDNAMETOOLONG, &userId, &tst)) {
2175         goto fail_pts_UserRename;
2176     }
2177
2178     /*
2179      * Make the rpc
2180      */
2181
2182     tst = ubik_Call(PR_ChangeEntry, c_handle->pts, 0, userId, newName, 0, 0);
2183
2184     if (tst != 0) {
2185         goto fail_pts_UserRename;
2186     }
2187     rc = 1;
2188
2189   fail_pts_UserRename:
2190
2191     if (st != NULL) {
2192         *st = tst;
2193     }
2194     return rc;
2195 }
2196
2197 /*
2198  * SetUserAccess - translate our Access notation to pts flags.
2199  *
2200  * PARAMETERS
2201  *
2202  * IN userP - the user structure that contains the new permissions.
2203  *
2204  * OUT flags - a pointer to an afs_int32 structure that 
2205  * contains the flags to pass to pts.
2206  *
2207  * LOCKS
2208  *
2209  * No locks are held by this function
2210  *
2211  * RETURN CODES
2212  *
2213  * Returns != 0 upon successful completion.
2214  *
2215  */
2216
2217 static int
2218 SetUserAccess(const pts_UserUpdateEntry_p userP, afs_int32 * flags,
2219               afs_status_p st)
2220 {
2221     int rc = 0;
2222     afs_status_t tst = 0;
2223
2224     *flags = 0;
2225
2226     if (userP->listMembership == PTS_USER_ANYUSER_ACCESS) {
2227         *flags |= 16;
2228     }
2229
2230     if (userP->listGroupsOwned == PTS_USER_ANYUSER_ACCESS) {
2231         *flags |= 32;
2232     }
2233
2234     if (userP->listStatus == PTS_USER_ANYUSER_ACCESS) {
2235         *flags |= 128;
2236     }
2237     rc = 1;
2238
2239     if (st != NULL) {
2240         *st = tst;
2241     }
2242     return rc;
2243 }
2244
2245
2246 /*
2247  * pts_UserModify - update a user entry.
2248  *
2249  * PARAMETERS
2250  *
2251  * IN cellHandle - a previously opened cellHandle that corresponds
2252  * to the cell where the group exists.
2253  *
2254  * IN userName - the name of the user to update.
2255  *
2256  * IN newEntryP - a pointer to a pts_UserUpdateEntry_t that contains the
2257  * new information for user.
2258  *
2259  * LOCKS
2260  *
2261  * No locks are held by this function
2262  *
2263  * RETURN CODES
2264  *
2265  * Returns != 0 upon successful completion.
2266  *
2267  */
2268
2269 int ADMINAPI
2270 pts_UserModify(const void *cellHandle, const char *userName,
2271                const pts_UserUpdateEntry_p newEntryP, afs_status_p st)
2272 {
2273     int rc = 0;
2274     afs_status_t tst = 0;
2275     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2276     afs_int32 userId = 0;
2277     afs_int32 newQuota = 0;
2278     afs_int32 mask = 0;
2279     afs_int32 flags = 0;
2280
2281     /*
2282      * Validate arguments
2283      */
2284
2285     if (!IsValidCellHandle(c_handle, &tst)) {
2286         goto fail_pts_UserModify;
2287     }
2288
2289     if ((userName == NULL) || (*userName == 0)) {
2290         tst = ADMPTSUSERNAMENULL;
2291         goto fail_pts_UserModify;
2292     }
2293
2294     if (newEntryP == NULL) {
2295         tst = ADMPTSNEWENTRYPNULL;
2296         goto fail_pts_UserModify;
2297     }
2298
2299     /*
2300      * Translate the user name into an id.
2301      */
2302
2303     if (!TranslateOneName
2304         (c_handle, userName, ADMPTSUSERNAMETOOLONG, &userId, &tst)) {
2305         goto fail_pts_UserModify;
2306     }
2307
2308
2309     if (newEntryP->flag & PTS_USER_UPDATE_GROUP_CREATE_QUOTA) {
2310         mask |= PR_SF_NGROUPS;
2311         newQuota = newEntryP->groupCreationQuota;
2312     }
2313
2314     if (newEntryP->flag & PTS_USER_UPDATE_PERMISSIONS) {
2315         mask |= PR_SF_ALLBITS;
2316         if (!SetUserAccess(newEntryP, &flags, &tst)) {
2317             goto fail_pts_UserModify;
2318         }
2319     }
2320
2321     /*
2322      * Make the rpc
2323      */
2324
2325     tst =
2326         ubik_Call(PR_SetFieldsEntry, c_handle->pts, 0, userId, mask, flags,
2327                   newQuota, 0, 0, 0);
2328
2329     if (tst != 0) {
2330         goto fail_pts_UserModify;
2331     }
2332     rc = 1;
2333
2334   fail_pts_UserModify:
2335
2336     if (st != NULL) {
2337         *st = tst;
2338     }
2339     return rc;
2340 }
2341
2342 /*
2343  * pts_UserMaxGet - get the maximum in use user id.
2344  *
2345  * PARAMETERS
2346  *
2347  * IN cellHandle - a previously opened cellHandle that corresponds
2348  * to the cell where the group exists.
2349  *
2350  * OUT maxUserId - upon successful completion contains the max in use id.
2351  *
2352  * LOCKS
2353  *
2354  * No locks are held by this function
2355  *
2356  * RETURN CODES
2357  *
2358  * Returns != 0 upon successful completion.
2359  *
2360  */
2361
2362 int ADMINAPI
2363 pts_UserMaxGet(const void *cellHandle, int *maxUserId, afs_status_p st)
2364 {
2365     int rc = 0;
2366     afs_status_t tst = 0;
2367     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2368     afs_int32 maxGroupId = 0;
2369
2370     /*
2371      * Validate arguments
2372      */
2373
2374     if (!IsValidCellHandle(c_handle, &tst)) {
2375         goto fail_pts_UserMaxGet;
2376     }
2377
2378     if (maxUserId == NULL) {
2379         tst = ADMPTSMAXUSERIDNULL;
2380         goto fail_pts_UserMaxGet;
2381     }
2382
2383     tst = ubik_Call(PR_ListMax, c_handle->pts, 0, maxUserId, &maxGroupId);
2384
2385     if (tst != 0) {
2386         goto fail_pts_UserMaxGet;
2387     }
2388     rc = 1;
2389
2390   fail_pts_UserMaxGet:
2391
2392     if (st != NULL) {
2393         *st = tst;
2394     }
2395     return rc;
2396 }
2397
2398 /*
2399  * pts_UserMaxSet - set the maximum user id.
2400  *
2401  * PARAMETERS
2402  *
2403  * IN cellHandle - a previously opened cellHandle that corresponds
2404  * to the cell where the group exists.
2405  *
2406  * IN maxUserId - the new max user id.
2407  *
2408  * LOCKS
2409  *
2410  * No locks are held by this function
2411  *
2412  * RETURN CODES
2413  *
2414  * Returns != 0 upon successful completion.
2415  *
2416  */
2417
2418 int ADMINAPI
2419 pts_UserMaxSet(const void *cellHandle, int maxUserId, afs_status_p st)
2420 {
2421     int rc = 0;
2422     afs_status_t tst = 0;
2423     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2424
2425     /*
2426      * Validate arguments
2427      */
2428
2429     if (!IsValidCellHandle(c_handle, &tst)) {
2430         goto fail_pts_UserMaxSet;
2431     }
2432
2433     tst = ubik_Call(PR_SetMax, c_handle->pts, 0, maxUserId, 0);
2434
2435     if (tst != 0) {
2436         goto fail_pts_UserMaxSet;
2437     }
2438     rc = 1;
2439
2440   fail_pts_UserMaxSet:
2441
2442     if (st != NULL) {
2443         *st = tst;
2444     }
2445     return rc;
2446 }
2447
2448 /*
2449  * pts_UserMemberListBegin - begin iterating over the list of groups
2450  * a particular user belongs to.
2451  *
2452  * PARAMETERS
2453  *
2454  * IN cellHandle - a previously opened cellHandle that corresponds
2455  * to the cell where the group exists.
2456  *
2457  * IN groupName - the group whose members will be returned.
2458  *
2459  * OUT iterationIdP - upon successful completion contains a iterator that
2460  * can be passed to pts_GroupMemberListNext.
2461  *
2462  * LOCKS
2463  *
2464  * No locks are obtained or released by this function
2465  *
2466  * RETURN CODES
2467  *
2468  * Returns != 0 upon successful completion.
2469  *
2470  */
2471
2472 int ADMINAPI
2473 pts_UserMemberListBegin(const void *cellHandle, const char *userName,
2474                         void **iterationIdP, afs_status_p st)
2475 {
2476     return MemberListBegin(cellHandle, userName, ADMPTSUSERNAMENULL,
2477                            ADMPTSUSERNAMETOOLONG, iterationIdP, st);
2478
2479 }
2480
2481 /*
2482  * pts_UserMemberListNext - get the next group a user belongs to
2483  *
2484  * PARAMETERS
2485  *
2486  * IN iterationId - an iterator previously returned by pts_UserMemberListBegin
2487  *
2488  * OUT userName - upon successful completion contains the next group a user
2489  * belongs to.
2490  *
2491  * LOCKS
2492  *
2493  * The iterator mutex is held during the retrieval of the next member.
2494  *
2495  * RETURN CODES
2496  *
2497  * Returns != 0 upon successful completion.
2498  *
2499  */
2500
2501 int ADMINAPI
2502 pts_UserMemberListNext(const void *iterationId, char *userName,
2503                        afs_status_p st)
2504 {
2505     return pts_GroupMemberListNext(iterationId, userName, st);
2506 }
2507
2508 /*
2509  * pts_UserMemberListDone - finish using a user list iterator
2510  *
2511  * PARAMETERS
2512  *
2513  * IN iterationId - an iterator previously returned by pts_UserMemberListBegin
2514  *
2515  * LOCKS
2516  *
2517  * The iterator is locked and then destroyed
2518  *
2519  * RETURN CODES
2520  *
2521  * Returns != 0 upon successful completion.
2522  *
2523  * ASSUMPTIONS
2524  *
2525  * It is the user's responsibility to make sure pts_UserMemberListDone
2526  * is called only once for each iterator.
2527  */
2528
2529 int ADMINAPI
2530 pts_UserMemberListDone(const void *iterationId, afs_status_p st)
2531 {
2532     return pts_GroupMemberListDone(iterationId, st);
2533 }
2534
2535 typedef struct owned_group_list {
2536     namelist owned_names;       /* the list of character names owned by this id */
2537     prlist owned_ids;           /* the list of pts ids owned by this id */
2538     afs_int32 index;            /* the index into owned_names for the next group */
2539     afs_int32 owner;            /* the pts id of the owner */
2540     afs_int32 more;             /* the last parameter to PR_ListOwned */
2541     int finished_retrieving;    /* set when we've processed the last owned_names */
2542     afs_cell_handle_p c_handle; /* ubik client to pts server's from c_handle */
2543     char group[CACHED_ITEMS][PTS_MAX_NAME_LEN]; /* cache of names */
2544 } owned_group_list_t, *owned_group_list_p;
2545
2546 static int
2547 DeleteOwnedGroupSpecificData(void *rpc_specific, afs_status_p st)
2548 {
2549     int rc = 0;
2550     afs_status_t tst = 0;
2551     owned_group_list_p list = (owned_group_list_p) rpc_specific;
2552
2553     if (list->owned_names.namelist_val != NULL) {
2554         free(list->owned_names.namelist_val);
2555     }
2556
2557     if (list->owned_ids.prlist_val != NULL) {
2558         free(list->owned_ids.prlist_val);
2559     }
2560     rc = 1;
2561
2562     if (st != NULL) {
2563         *st = tst;
2564     }
2565     return rc;
2566 }
2567
2568 static int
2569 GetOwnedGroupRPC(void *rpc_specific, int slot, int *last_item,
2570                  int *last_item_contains_data, afs_status_p st)
2571 {
2572     int rc = 0;
2573     afs_status_t tst = 0;
2574     owned_group_list_p list = (owned_group_list_p) rpc_specific;
2575
2576     /*
2577      * We really don't make an rpc for every entry we return here
2578      * since the pts interface allows several members to be returned
2579      * with one rpc, but we fake it to make the iterator happy.
2580      */
2581
2582     /*
2583      * Check to see if we are done retrieving data
2584      */
2585
2586     if ((list->finished_retrieving) && (list->owned_names.namelist_len == 0)) {
2587         *last_item = 1;
2588         *last_item_contains_data = 0;
2589         goto fail_GetOwnedGroupRPC;
2590     }
2591
2592     /*
2593      * Check to see if we really need to make an rpc
2594      */
2595
2596     if ((!list->finished_retrieving) && (list->owned_names.namelist_len == 0)) {
2597         tst =
2598             ubik_Call(PR_ListOwned, list->c_handle->pts, 0, list->owner,
2599                       &list->owned_ids, &list->more);
2600         if (tst != 0) {
2601             goto fail_GetOwnedGroupRPC;
2602         }
2603
2604         if (!TranslatePTSIds
2605             (list->c_handle, &list->owned_names, (idlist *) & list->owned_ids,
2606              &tst)) {
2607             goto fail_GetOwnedGroupRPC;
2608         }
2609         list->index = 0;
2610
2611         if (list->owned_names.namelist_val == NULL) {
2612             *last_item = 1;
2613             *last_item_contains_data = 0;
2614             goto fail_GetOwnedGroupRPC;
2615         }
2616     }
2617
2618     /*
2619      * We can retrieve the next group from data we already received
2620      */
2621
2622     strcpy(list->group[slot], list->owned_names.namelist_val[list->index]);
2623     list->index++;
2624
2625     /*
2626      * Check to see if there is more data to be retrieved
2627      * We need to free up the previously retrieved data here
2628      * and then check to see if the last rpc indicated that there
2629      * were more items to retrieve.
2630      */
2631
2632     if (list->index >= list->owned_names.namelist_len) {
2633         list->owned_names.namelist_len = 0;
2634         free(list->owned_names.namelist_val);
2635         list->owned_names.namelist_val = 0;
2636
2637         list->owned_ids.prlist_len = 0;
2638         free(list->owned_ids.prlist_val);
2639         list->owned_ids.prlist_val = 0;
2640
2641         if (!list->more) {
2642             list->finished_retrieving = 1;
2643         }
2644     }
2645     rc = 1;
2646
2647   fail_GetOwnedGroupRPC:
2648
2649     if (st != NULL) {
2650         *st = tst;
2651     }
2652     return rc;
2653 }
2654
2655 static int
2656 GetOwnedGroupFromCache(void *rpc_specific, int slot, void *dest,
2657                        afs_status_p st)
2658 {
2659     int rc = 0;
2660     afs_status_t tst = 0;
2661     owned_group_list_p list = (owned_group_list_p) rpc_specific;
2662
2663     strcpy((char *)dest, list->group[slot]);
2664     rc = 1;
2665
2666     if (st != NULL) {
2667         *st = tst;
2668     }
2669
2670     return rc;
2671 }
2672
2673 /*
2674  * pts_OwnedGroupListBegin - begin iterating over the list of groups
2675  * a particular user owns.
2676  *
2677  * PARAMETERS
2678  *
2679  * IN cellHandle - a previously opened cellHandle that corresponds
2680  * to the cell where the group exists.
2681  *
2682  * IN ownerName - the owner of the groups of interest.
2683  *
2684  * OUT iterationIdP - upon successful completion contains a iterator that
2685  * can be passed to pts_OwnedGroupListNext.
2686  *
2687  * LOCKS
2688  *
2689  * No locks are held by this function
2690  *
2691  * RETURN CODES
2692  *
2693  * Returns != 0 upon successful completion.
2694  *
2695  */
2696
2697 int ADMINAPI
2698 pts_OwnedGroupListBegin(const void *cellHandle, const char *userName,
2699                         void **iterationIdP, afs_status_p st)
2700 {
2701     int rc = 0;
2702     afs_status_t tst = 0;
2703     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
2704     afs_admin_iterator_p iter =
2705         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
2706     owned_group_list_p list =
2707         (owned_group_list_p) malloc(sizeof(owned_group_list_t));
2708
2709     /*
2710      * Validate arguments
2711      */
2712
2713     if (!IsValidCellHandle(c_handle, &tst)) {
2714         goto fail_pts_OwnedGroupListBegin;
2715     }
2716
2717     if ((userName == NULL) || (*userName == 0)) {
2718         tst = ADMPTSUSERNAMENULL;
2719         goto fail_pts_OwnedGroupListBegin;
2720     }
2721
2722     if (iterationIdP == NULL) {
2723         tst = ADMITERATORNULL;
2724         goto fail_pts_OwnedGroupListBegin;
2725     }
2726
2727     if ((iter == NULL) || (list == NULL)) {
2728         tst = ADMNOMEM;
2729         goto fail_pts_OwnedGroupListBegin;
2730     }
2731
2732     /*
2733      * Initialize the iterator specific data
2734      */
2735
2736     list->index = 0;
2737     list->finished_retrieving = 0;
2738     list->c_handle = c_handle;
2739     list->owned_names.namelist_len = 0;
2740     list->owned_names.namelist_val = 0;
2741     list->owned_ids.prlist_len = 0;
2742     list->owned_ids.prlist_val = 0;
2743
2744     /*
2745      * Translate the user name into an id.
2746      */
2747
2748     if (!TranslateOneName
2749         (c_handle, userName, ADMPTSUSERNAMETOOLONG, &list->owner, &tst)) {
2750         goto fail_pts_OwnedGroupListBegin;
2751     }
2752
2753     if (IteratorInit
2754         (iter, (void *)list, GetOwnedGroupRPC, GetOwnedGroupFromCache, NULL,
2755          DeleteOwnedGroupSpecificData, &tst)) {
2756         *iterationIdP = (void *)iter;
2757         rc = 1;
2758     }
2759
2760   fail_pts_OwnedGroupListBegin:
2761
2762     if (rc == 0) {
2763         if (iter != NULL) {
2764             free(iter);
2765         }
2766         if (list != NULL) {
2767             free(list);
2768         }
2769     }
2770
2771     if (st != NULL) {
2772         *st = tst;
2773     }
2774     return rc;
2775 }
2776
2777 /*
2778  * pts_OwnedGroupListNext - get the next group a user owns.
2779  *
2780  * PARAMETERS
2781  *
2782  * IN iterationId - an iterator previously returned by pts_OwnedGroupListBegin
2783  *
2784  * OUT groupName - upon successful completion contains the next group a user
2785  * owns.
2786  *
2787  * LOCKS
2788  *
2789  * The iterator mutex is held during the retrieval of the next member.
2790  *
2791  * RETURN CODES
2792  *
2793  * Returns != 0 upon successful completion.
2794  *
2795  */
2796
2797 int ADMINAPI
2798 pts_OwnedGroupListNext(const void *iterationId, char *groupName,
2799                        afs_status_p st)
2800 {
2801     int rc = 0;
2802     afs_status_t tst = 0;
2803     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2804
2805     /*
2806      * Validate arguments
2807      */
2808
2809     if (iterationId == NULL) {
2810         tst = ADMITERATORNULL;
2811         goto fail_pts_OwnedGroupListNext;
2812     }
2813
2814     if (groupName == NULL) {
2815         tst = ADMPTSGROUPNAMENULL;
2816         goto fail_pts_OwnedGroupListNext;
2817     }
2818
2819     rc = IteratorNext(iter, (void *)groupName, &tst);
2820
2821   fail_pts_OwnedGroupListNext:
2822
2823     if (st != NULL) {
2824         *st = tst;
2825     }
2826     return rc;
2827 }
2828
2829 /*
2830  * pts_OwnedGroupListDone - finish using a group list iterator
2831  *
2832  * PARAMETERS
2833  *
2834  * IN iterationId - an iterator previously returned by pts_OwnedGroupListBegin
2835  *
2836  * LOCKS
2837  *
2838  * The iterator is locked and then destroyed
2839  *
2840  * RETURN CODES
2841  *
2842  * Returns != 0 upon successful completion.
2843  *
2844  * ASSUMPTIONS
2845  *
2846  * It is the user's responsibility to make sure pts_OwnedGroupListDone
2847  * is called only once for each iterator.
2848  */
2849
2850 int ADMINAPI
2851 pts_OwnedGroupListDone(const void *iterationId, afs_status_p st)
2852 {
2853     int rc = 0;
2854     afs_status_t tst = 0;
2855     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
2856
2857     /*
2858      * Validate arguments
2859      */
2860
2861     if (iterationId == NULL) {
2862         tst = ADMITERATORNULL;
2863         goto fail_pts_OwnedGroupListDone;
2864     }
2865
2866     rc = IteratorDone(iter, &tst);
2867
2868   fail_pts_OwnedGroupListDone:
2869
2870     if (st != NULL) {
2871         *st = tst;
2872     }
2873     return rc;
2874 }
2875
2876 typedef struct pts_list {
2877     prlistentries *names;       /* the current list of pts names in this cell */
2878     prlistentries *currName;    /* the current pts entry */
2879     afs_int32 index;            /* the index into names for the next pts entry */
2880     afs_int32 nextstartindex;   /* the next start index for the RPC */
2881     afs_int32 nentries;         /* the number of entries in names */
2882     afs_int32 flag;             /* the type of the list */
2883     int finished_retrieving;    /* set when we've processed the last owned_names */
2884     afs_cell_handle_p c_handle; /* ubik client to pts server's from c_handle */
2885     char entries[CACHED_ITEMS][PTS_MAX_NAME_LEN];       /* cache of pts names */
2886 } pts_list_t, *pts_list_p;
2887
2888 static int
2889 DeletePTSSpecificData(void *rpc_specific, afs_status_p st)
2890 {
2891     int rc = 0;
2892     afs_status_t tst = 0;
2893     pts_list_p list = (pts_list_p) rpc_specific;
2894
2895     if (list->names) {
2896         free(list->names);
2897     }
2898
2899     rc = 1;
2900
2901     if (st != NULL) {
2902         *st = tst;
2903     }
2904     return rc;
2905 }
2906
2907 static int
2908 GetPTSRPC(void *rpc_specific, int slot, int *last_item,
2909           int *last_item_contains_data, afs_status_p st)
2910 {
2911     int rc = 0;
2912     afs_status_t tst = 0;
2913     pts_list_p list = (pts_list_p) rpc_specific;
2914
2915     /*
2916      * We really don't make an rpc for every entry we return here
2917      * since the pts interface allows several members to be returned
2918      * with one rpc, but we fake it to make the iterator happy.
2919      */
2920
2921     /*
2922      * Check to see if we are done retrieving data
2923      */
2924
2925     if (list->finished_retrieving) {
2926         *last_item = 1;
2927         *last_item_contains_data = 0;
2928         goto fail_GetPTSRPC;
2929     }
2930
2931     /*
2932      * Check to see if we really need to make an rpc
2933      */
2934
2935     if ((!list->finished_retrieving) && (list->index >= list->nentries)) {
2936         afs_int32 start = list->nextstartindex;
2937         prentries bulkentries;
2938         list->nextstartindex = -1;
2939         bulkentries.prentries_val = 0;
2940         bulkentries.prentries_len = 0;
2941
2942         tst =
2943             ubik_Call(PR_ListEntries, list->c_handle->pts, 0, list->flag,
2944                       start, &bulkentries, &(list->nextstartindex));
2945
2946         if (tst != 0) {
2947             goto fail_GetPTSRPC;
2948         }
2949
2950         list->nentries = bulkentries.prentries_len;
2951         list->names = bulkentries.prentries_val;
2952
2953         list->index = 0;
2954         list->currName = list->names;
2955
2956     }
2957
2958     /*
2959      * We can retrieve the next entry from data we already received
2960      */
2961
2962     strcpy(list->entries[slot], list->currName->name);
2963     list->index++;
2964     list->currName++;
2965
2966
2967     /*
2968      * Check to see if there is more data to be retrieved
2969      * We need to free up the previously retrieved data here
2970      * and then check to see if the last rpc indicated that there
2971      * were more items to retrieve.
2972      */
2973
2974     if (list->index >= list->nentries) {
2975         if (list->names) {
2976             free(list->names);
2977         }
2978         list->names = NULL;
2979
2980         if (list->nextstartindex == -1) {
2981             list->finished_retrieving = 1;
2982         }
2983     }
2984     rc = 1;
2985
2986   fail_GetPTSRPC:
2987
2988     if (st != NULL) {
2989         *st = tst;
2990     }
2991
2992     return rc;
2993 }
2994
2995 static int
2996 GetPTSFromCache(void *rpc_specific, int slot, void *dest, afs_status_p st)
2997 {
2998     int rc = 0;
2999     afs_status_t tst = 0;
3000     pts_list_p list = (pts_list_p) rpc_specific;
3001
3002     strcpy((char *)dest, list->entries[slot]);
3003     rc = 1;
3004
3005     if (st != NULL) {
3006         *st = tst;
3007     }
3008
3009     return rc;
3010 }
3011
3012 /*
3013  * pts_UserListBegin - begin iterating over the list of users
3014  * in a particular cell
3015  *
3016  * PARAMETERS
3017  *
3018  * IN cellHandle - a previously opened cellHandle that corresponds
3019  * to the cell where the users exist.
3020  *
3021  * OUT iterationIdP - upon successful completion contains a iterator that
3022  * can be passed to pts_UserListNext.
3023  *
3024  * LOCKS
3025  *
3026  * No locks are held by this function
3027  *
3028  * RETURN CODES
3029  *
3030  * Returns != 0 upon successful completion.
3031  *
3032  */
3033
3034 int ADMINAPI
3035 pts_UserListBegin(const void *cellHandle, void **iterationIdP,
3036                   afs_status_p st)
3037 {
3038     int rc = 0;
3039     afs_status_t tst = 0;
3040     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
3041     afs_admin_iterator_p iter =
3042         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
3043     pts_list_p list = (pts_list_p) malloc(sizeof(pts_list_t));
3044
3045     /*
3046      * Validate arguments
3047      */
3048
3049     if (!IsValidCellHandle(c_handle, &tst)) {
3050         goto fail_pts_UserListBegin;
3051     }
3052
3053     if (iterationIdP == NULL) {
3054         tst = ADMITERATORNULL;
3055         goto fail_pts_UserListBegin;
3056     }
3057
3058     if ((iter == NULL) || (list == NULL)) {
3059         tst = ADMNOMEM;
3060         goto fail_pts_UserListBegin;
3061     }
3062
3063     /*
3064      * Initialize the iterator specific data
3065      */
3066
3067     list->index = 0;
3068     list->finished_retrieving = 0;
3069     list->c_handle = c_handle;
3070     list->names = NULL;
3071     list->nextstartindex = 0;
3072     list->nentries = 0;
3073     list->flag = PRUSERS;
3074
3075     if (IteratorInit
3076         (iter, (void *)list, GetPTSRPC, GetPTSFromCache, NULL,
3077          DeletePTSSpecificData, &tst)) {
3078         *iterationIdP = (void *)iter;
3079         rc = 1;
3080     }
3081
3082   fail_pts_UserListBegin:
3083
3084     if (rc == 0) {
3085         if (iter != NULL) {
3086             free(iter);
3087         }
3088         if (list != NULL) {
3089             free(list);
3090         }
3091     }
3092
3093     if (st != NULL) {
3094         *st = tst;
3095     }
3096     return rc;
3097 }
3098
3099 /*
3100  * pts_UserListNext - get the next user in the cell.
3101  *
3102  * PARAMETERS
3103  *
3104  * IN iterationId - an iterator previously returned by pts_UserListBegin
3105  *
3106  * OUT groupName - upon successful completion contains the next user
3107  *
3108  * LOCKS
3109  *
3110  * The iterator mutex is held during the retrieval of the next member.
3111  *
3112  * RETURN CODES
3113  *
3114  * Returns != 0 upon successful completion.
3115  *
3116  */
3117
3118 int ADMINAPI
3119 pts_UserListNext(const void *iterationId, char *userName, afs_status_p st)
3120 {
3121     int rc = 0;
3122     afs_status_t tst = 0;
3123     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
3124
3125     /*
3126      * Validate arguments
3127      */
3128
3129     if (iterationId == NULL) {
3130         tst = ADMITERATORNULL;
3131         goto fail_pts_UserListNext;
3132     }
3133
3134     if (userName == NULL) {
3135         tst = ADMPTSUSERNAMENULL;
3136         goto fail_pts_UserListNext;
3137     }
3138
3139     rc = IteratorNext(iter, (void *)userName, &tst);
3140
3141   fail_pts_UserListNext:
3142
3143     if (st != NULL) {
3144         *st = tst;
3145     }
3146     return rc;
3147 }
3148
3149 /*
3150  * pts_UserListDone - finish using a user list iterator
3151  *
3152  * PARAMETERS
3153  *
3154  * IN iterationId - an iterator previously returned by pts_UserListBegin
3155  *
3156  * LOCKS
3157  *
3158  * The iterator is locked and then destroyed
3159  *
3160  * RETURN CODES
3161  *
3162  * Returns != 0 upon successful completion.
3163  *
3164  * ASSUMPTIONS
3165  *
3166  * It is the user's responsibility to make sure pts_UserListDone
3167  * is called only once for each iterator.
3168  */
3169
3170 int ADMINAPI
3171 pts_UserListDone(const void *iterationId, afs_status_p st)
3172 {
3173     int rc = 0;
3174     afs_status_t tst = 0;
3175     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
3176
3177     /*
3178      * Validate arguments
3179      */
3180
3181     if (iterationId == NULL) {
3182         tst = ADMITERATORNULL;
3183         goto fail_pts_UserListDone;
3184     }
3185
3186     rc = IteratorDone(iter, &tst);
3187
3188   fail_pts_UserListDone:
3189
3190     if (st != NULL) {
3191         *st = tst;
3192     }
3193     return rc;
3194 }
3195
3196 /*
3197  * pts_GroupListBegin - begin iterating over the list of groups
3198  * in a particular cell.
3199  *
3200  * PARAMETERS
3201  *
3202  * IN cellHandle - a previously opened cellHandle that corresponds
3203  * to the cell where the groups exist.
3204  *
3205  * OUT iterationIdP - upon successful completion contains a iterator that
3206  * can be passed to pts_GroupListNext.
3207  *
3208  * LOCKS
3209  *
3210  * No locks are held by this function
3211  *
3212  * RETURN CODES
3213  *
3214  * Returns != 0 upon successful completion.
3215  *
3216  */
3217
3218 int ADMINAPI
3219 pts_GroupListBegin(const void *cellHandle, void **iterationIdP,
3220                    afs_status_p st)
3221 {
3222     int rc = 0;
3223     afs_status_t tst = 0;
3224     afs_cell_handle_p c_handle = (afs_cell_handle_p) cellHandle;
3225     afs_admin_iterator_p iter =
3226         (afs_admin_iterator_p) malloc(sizeof(afs_admin_iterator_t));
3227     pts_list_p list = (pts_list_p) malloc(sizeof(pts_list_t));
3228
3229     /*
3230      * Validate arguments
3231      */
3232
3233     if (!IsValidCellHandle(c_handle, &tst)) {
3234         goto fail_pts_GroupListBegin;
3235     }
3236
3237     if (iterationIdP == NULL) {
3238         tst = ADMITERATORNULL;
3239         goto fail_pts_GroupListBegin;
3240     }
3241
3242     if ((iter == NULL) || (list == NULL)) {
3243         tst = ADMNOMEM;
3244         goto fail_pts_GroupListBegin;
3245     }
3246
3247     /*
3248      * Initialize the iterator specific data
3249      */
3250
3251     list->index = 0;
3252     list->finished_retrieving = 0;
3253     list->c_handle = c_handle;
3254     list->names = NULL;
3255     list->nextstartindex = 0;
3256     list->nentries = 0;
3257     list->flag = PRGROUPS;
3258
3259     if (IteratorInit
3260         (iter, (void *)list, GetPTSRPC, GetPTSFromCache, NULL,
3261          DeletePTSSpecificData, &tst)) {
3262         *iterationIdP = (void *)iter;
3263         rc = 1;
3264     }
3265
3266   fail_pts_GroupListBegin:
3267
3268     if (rc == 0) {
3269         if (iter != NULL) {
3270             free(iter);
3271         }
3272         if (list != NULL) {
3273             free(list);
3274         }
3275     }
3276
3277     if (st != NULL) {
3278         *st = tst;
3279     }
3280     return rc;
3281 }
3282
3283 /*
3284  * pts_UserListNext - get the next group in a cell.
3285  *
3286  * PARAMETERS
3287  *
3288  * IN iterationId - an iterator previously returned by pts_GroupListBegin
3289  *
3290  * OUT groupName - upon successful completion contains the next group
3291  *
3292  * LOCKS
3293  *
3294  * The iterator mutex is held during the retrieval of the next member.
3295  *
3296  * RETURN CODES
3297  *
3298  * Returns != 0 upon successful completion.
3299  *
3300  */
3301
3302 int ADMINAPI
3303 pts_GroupListNext(const void *iterationId, char *groupName, afs_status_p st)
3304 {
3305     int rc = 0;
3306     afs_status_t tst = 0;
3307     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
3308
3309     /*
3310      * Validate arguments
3311      */
3312
3313     if (iterationId == NULL) {
3314         tst = ADMITERATORNULL;
3315         goto fail_pts_GroupListNext;
3316     }
3317
3318     if (groupName == NULL) {
3319         tst = ADMPTSGROUPNAMENULL;
3320         goto fail_pts_GroupListNext;
3321     }
3322
3323     rc = IteratorNext(iter, (void *)groupName, &tst);
3324
3325   fail_pts_GroupListNext:
3326
3327     if (st != NULL) {
3328         *st = tst;
3329     }
3330     return rc;
3331 }
3332
3333 /*
3334  * pts_GroupListDone - finish using a group list iterator
3335  *
3336  * PARAMETERS
3337  *
3338  * IN iterationId - an iterator previously returned by pts_GroupListBegin
3339  *
3340  * LOCKS
3341  *
3342  * The iterator is locked and then destroyed
3343  *
3344  * RETURN CODES
3345  *
3346  * Returns != 0 upon successful completion.
3347  *
3348  * ASSUMPTIONS
3349  *
3350  * It is the user's responsibility to make sure pts_GroupListDone
3351  * is called only once for each iterator.
3352  */
3353
3354 int ADMINAPI
3355 pts_GroupListDone(const void *iterationId, afs_status_p st)
3356 {
3357     int rc = 0;
3358     afs_status_t tst = 0;
3359     afs_admin_iterator_p iter = (afs_admin_iterator_p) iterationId;
3360
3361     /*
3362      * Validate arguments
3363      */
3364
3365     if (iterationId == NULL) {
3366         tst = ADMITERATORNULL;
3367         goto fail_pts_GroupListDone;
3368     }
3369
3370     rc = IteratorDone(iter, &tst);
3371
3372   fail_pts_GroupListDone:
3373
3374     if (st != NULL) {
3375         *st = tst;
3376     }
3377     return rc;
3378 }