]> andersk Git - moira.git/blame - afssync/ptutils.c
Initial revision
[moira.git] / afssync / ptutils.c
CommitLineData
da0b4fd5 1/* Copyright (C) 1990, 1989 Transarc Corporation - All rights reserved */
e1f001e5 2/*
3 * P_R_P_Q_# (C) COPYRIGHT IBM CORPORATION 1988
4 * LICENSED MATERIALS - PROPERTY OF IBM
5 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
6 */
7
dba0cf81 8
e1f001e5 9/*
10 Sherri Nichols
11 Information Technology Center
12 November, 1988
13
14 Modified May, 1989 by Jeff Schiller to keep disk file in
15 network byte order
16
17*/
18
dba0cf81 19#include <afs/param.h>
da0b4fd5 20#include <afs/stds.h>
dba0cf81 21#include <sys/types.h>
e1f001e5 22#include <stdio.h>
da0b4fd5 23#ifdef AFS_HPUX_ENV
24#include <string.h>
25#else
26#include <strings.h>
27#endif
e1f001e5 28#include <lock.h>
dba0cf81 29#include <netinet/in.h>
e1f001e5 30#include <ubik.h>
31#include <rx/xdr.h>
dba0cf81 32#include <afs/com_err.h>
33#include "ptserver.h"
34#include "pterror.h"
da0b4fd5 35
36RCSID ("$Header$")
e1f001e5 37
e1f001e5 38extern struct ubik_dbase *dbase;
39extern struct afsconf_dir *prdir;
dba0cf81 40extern int pr_noAuth;
e1f001e5 41
dba0cf81 42static char *whoami = "ptserver";
43
44/* CorrectUserName - Check to make sure a user name is OK. It must not include
45 * either a colon (or it would look like a group) or an atsign (or it would
46 * look like a foreign user). The length is checked as well to make sure
47 * that the user name, an atsign, and the local cell name will fit in
48 * PR_MAXNAMELEN. This is so this user can fit in another cells database as
49 * a foreign user with our cell name tacked on. This is a predicate, so it
50 * return one if name is OK and zero if name is bogus. */
51
52static int CorrectUserName (name)
53 char *name;
54{
55 extern int pr_realmNameLen;
56
da0b4fd5 57#ifdef CROSS_CELL
58 if (index (name, ':') || index(name, '\n')) return 0;
59#else
dba0cf81 60 if (index (name, ':') || index(name, '@') || index(name, '\n')) return 0;
da0b4fd5 61#endif
dba0cf81 62 if (strlen (name) >= PR_MAXNAMELEN - pr_realmNameLen - 1) return 0;
63 return 1;
64}
65
da0b4fd5 66/* CorrectGroupName - Like the above but handles more complicated cases caused
67 * by including the ownership in the name. The interface works by calculating
68 * the correct name based on a given name and owner. This allows easy use by
69 * rename, which then compares the correct name with the requested new name. */
70
dba0cf81 71static long CorrectGroupName (ut, aname, cid, oid, cname)
72 struct ubik_trans *ut;
73 char aname[PR_MAXNAMELEN]; /* name for group */
74 long cid; /* caller id */
75 long oid; /* owner of group */
76 char cname[PR_MAXNAMELEN]; /* correct name for group */
77{
78 long code;
79 int admin;
80 char *prefix; /* ptr to group owner part */
81 char *suffix; /* ptr to group name part */
82 char name[PR_MAXNAMELEN]; /* correct name for group */
83 struct prentry tentry;
84
85 if (strlen (aname) >= PR_MAXNAMELEN) return PRBADNAM;
2ba81a31 86 admin = pr_noAuth || (cid==SYSADMINID) || IsAMemberOf(ut, cid, SYSADMINID);
dba0cf81 87
88 if (oid == 0) oid = cid;
89
90 /* Determine the correct prefix for the name. */
91 if (oid == SYSADMINID) prefix = "system";
92 else {
93 long loc = FindByID (ut, oid);
94 if (loc == 0) {
95 /* let admin create groups owned by non-existent ids (probably
96 * setting a group to own itself). Check that they look like
97 * groups (with a colon) or otherwise are good user names. */
98 if (admin) {
99 strcpy (cname, aname);
100 goto done;
101 }
102 return PRNOENT;
103 }
104 code = pr_Read (ut, 0, loc, &tentry, sizeof(tentry));
105 if (code) return code;
106 if (ntohl(tentry.flags) & PRGRP) {
107 if ((tentry.count == 0) && !admin) return PRGROUPEMPTY;
108 /* terminate prefix at colon if there is one */
109 if (prefix = index(tentry.name, ':')) *prefix = 0;
110 }
111 prefix = tentry.name;
112 }
113 /* only sysadmin allow to use 'system:' prefix */
114 if ((strcmp (prefix, "system") == 0) && !admin) return PRPERM;
115
116 strcpy (name, aname); /* in case aname & cname are same */
117 suffix = index(name, ':');
118 if (suffix == 0) {
119 /* sysadmin can make groups w/o ':', but they must still look like
120 * legal user names. */
121 if (!admin) return PRBADNAM;
122 strcpy (cname, name);
123 }
124 else {
125 if (strlen(prefix)+strlen(suffix) >= PR_MAXNAMELEN) return PRBADNAM;
126 strcpy (cname, prefix);
127 strcat (cname, suffix);
128 }
129 done:
130 /* check for legal name with either group rules or user rules */
131 if (suffix = index(cname, ':')) {
132 /* check for confusing characters */
da0b4fd5 133#ifdef CROSS_CELL
134 if (index(cname, '\n') || /* restrict so recreate can work */
135 index(suffix+1, ':')) /* avoid multiple colons */
136 return PRBADNAM;
137#else
dba0cf81 138 if (index(cname, '@') || /* avoid confusion w/ foreign users */
139 index(cname, '\n') || /* restrict so recreate can work */
140 index(suffix+1, ':')) /* avoid multiple colons */
141 return PRBADNAM;
da0b4fd5 142#endif
dba0cf81 143 } else {
144 if (!CorrectUserName (cname)) return PRBADNAM;
145 }
146 return 0;
147}
148
149int AccessOK (ut, cid, tentry, mem, any)
150 struct ubik_trans *ut;
151 long cid; /* caller id */
152 struct prentry *tentry; /* object being accessed */
153 int mem; /* check membership in aid, if group */
154 int any; /* if set return true */
155{ long flags;
156 long oid;
157 long aid;
158
159 if (pr_noAuth) return 1;
da0b4fd5 160 if (cid == SYSADMINID) return 1; /* special case fileserver */
dba0cf81 161 if (tentry) {
162 flags = tentry->flags;
163 oid = tentry->owner;
164 aid = tentry->id;
165 } else {
166 flags = oid = aid = 0;
167 }
168 if (!(flags & PRACCESS)) /* provide default access */
169 if (flags & PRGRP)
170 flags |= PRP_GROUP_DEFAULT;
171 else
172 flags |= PRP_USER_DEFAULT;
173
174 if (flags & any) return 1;
175 if (oid) {
176 if ((cid == oid) ||
177 IsAMemberOf (ut, cid, oid)) return 1;
178 }
179 if (aid > 0) { /* checking on a user */
180 if (aid == cid) return 1;
181 } else if (aid < 0) { /* checking on group */
182 if ((flags & mem) && IsAMemberOf (ut, cid, aid)) return 1;
183 }
184 if (IsAMemberOf (ut, cid, SYSADMINID)) return 1;
185 return 0; /* no access */
186}
187
188long CreateEntry (at, aname, aid, idflag, flag, oid, creator)
189 register struct ubik_trans *at;
190 char aname[PR_MAXNAMELEN];
191 long *aid;
192 long idflag;
193 long flag;
194 long oid;
195 long creator;
e1f001e5 196{
197 /* get and init a new entry */
198 register long code;
199 long newEntry;
e1f001e5 200 struct prentry tentry;
201
202 bzero(&tentry, sizeof(tentry));
dba0cf81 203
204 if ((oid == 0) || (oid == ANONYMOUSID)) oid = creator;
205
206 if (flag & PRGRP) {
207 code = CorrectGroupName (at, aname, creator, oid, tentry.name);
208 if (code) return code;
209 if (strcmp (aname, tentry.name) != 0) return PRBADNAM;
210 } else { /* non-group must not have colon */
211 if (!CorrectUserName(aname)) return PRBADNAM;
212 strcpy (tentry.name, aname);
213 }
214
215 if (FindByName(at,aname)) return PREXIST;
216
e1f001e5 217 newEntry = AllocBlock(at);
218 if (!newEntry) return PRDBFAIL;
dba0cf81 219#ifdef PR_REMEMBER_TIMES
220 tentry.createTime = time(0);
221#endif
e1f001e5 222 if (flag & PRGRP) {
223 tentry.flags |= PRGRP;
224 tentry.owner = oid;
225 }
226 else if (flag & PRFOREIGN) {
227 tentry.flags |= PRFOREIGN;
228 tentry.owner = oid;
229 }
230 else tentry.owner = SYSADMINID;
da0b4fd5 231
232#ifdef CROSS_CELL
233#define ADD_TO_AUTHUSER_GROUP 1
234#define AUTHUSER_GROUP "system:authuser"
235 {
236 char * atsign;
237
238 if (!(atsign= index(aname,'@'))) { /* No @ so local cell*/
239 if (idflag)
240 tentry.id = *aid;
241 else {
242 code= AllocID(at,flag,&tentry.id);
243 if (code != PRSUCCESS) return code;
244 }
245 } else {
246 /*foreign cells are represented by the group system:authuser@cell*/
247 if (flag & PRGRP) {
248 /* it's a new foreign cell so the format
249 * must be AUTHUSER_GROUP@cellname */
250 int badFormat;
251
252 *atsign = '\0';
253 badFormat = strcmp(AUTHUSER_GROUP, aname);
254 *atsign = '@';
255 if (badFormat) return PRBADNAM;
256 if (idflag)
257 tentry.id = *aid;
258 else {
259 code= AllocID(at,flag,&tentry.id);
260 if (code != PRSUCCESS) return code;
261 }
262 } else {
263 /* it's a foreign cell entry */
264 char *cellGroup;
265 long pos;
266 struct prentry centry;
267 extern long allocNextId();
268 extern long AddToEntry();
269
270 cellGroup = (char *) malloc (strlen(AUTHUSER_GROUP) +
271 strlen(atsign) +1);
272 strcpy(cellGroup, AUTHUSER_GROUP);
273 strcat(cellGroup, atsign);
274 pos = FindByName(at,cellGroup);
275
276 /* if the group doesn't exist don't allow user creation */
277 if (!pos) return PRBADNAM;
278
279 code = pr_Read (at, 0, pos, &centry, sizeof(centry));
280 if (code) return code;
281 tentry.cellid = ntohl(centry.id);
282 /* cellid is the id of the group representing the cell */
283
284 if (idflag) {
285 if (!inRange(&centry,*aid))
286 return PRBADARG; /* the id specified is not in
287 * the id space of the group */
288 tentry.id = *aid;
289 } else
290 /* allocNextID() will allocate the next id
291 * in that cell's space */
292 tentry.id = allocNextId(&centry);
293
294 /* charge the cell group for the new user and test quota */
295 if (!(ntohl(centry.flags) & PRQUOTA)) {
296 /* quota uninitialized, so initialize it now */
297 centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
298 centry.ngroups = htonl(30);
299 }
300
301 centry.ngroups = htonl(ntohl(centry.ngroups) - 1);
9d08cc98 302 if (ntohl(centry.ngroups) < 0)
da0b4fd5 303 if (!pr_noAuth) return PRNOMORE;
304
305#if !ADD_TO_AUTHUSER_GROUP
306 centry.count = htonl(ntohl(centry.ngroups) +1);
307 /* keep count of how many people are in the group. */
308#endif
309
310 code = pr_Write (at, 0, pos, &centry, sizeof(centry));
311 /* write updated entry for group */
312
313 /* Now add the new user entry to the database */
314
315 tentry.creator = creator;
316 *aid = tentry.id;
317 code = pr_WriteEntry(at, 0, newEntry, &tentry);
318 if (code) return PRDBFAIL;
319 code = AddToIDHash(at,*aid,newEntry);
320 if (code != PRSUCCESS) return code;
321 code = AddToNameHash(at,aname,newEntry);
322 if (code != PRSUCCESS) return code;
323 if (inc_header_word (at, foreigncount, 1)) return PRDBFAIL;
324
325#if ADD_TO_AUTHUSER_GROUP
326
327 /* Now add the entry to the authuser group for this cell.
328 * We will reread the entries for the user and the group
329 * instead of modifying them before writing them in the
330 * previous steps. Although not very efficient, much simpler */
331
332 /* First update the group entry */
333 pos = FindByID(at,tentry.cellid);
334 if (!pos) return PRBADNAM;
335 code = pr_ReadEntry (at, 0, pos, &centry);
336 if (code) return code;
337 code = AddToEntry(at, &centry,pos,*aid);
338 if (code) return code;
339 /* and now the user entry */
340 pos = FindByID(at,*aid);
341 if (!pos) return PRBADNAM;
342 code = pr_ReadEntry(at, 0, pos, &tentry);
343 if (code) return code;
344 code = AddToEntry(at, &tentry,pos,tentry.cellid);
345 if (code) return code;
346
347#endif
348
349 /* Ok we're done */
350 return PRSUCCESS;
351 }
352 }
353 }
354
355#else /* !CROSS_CELL */
356
e1f001e5 357 if (idflag)
358 tentry.id = *aid;
359 else {
360 code= AllocID(at,flag,&tentry.id);
361 if (code != PRSUCCESS) return code;
362 }
da0b4fd5 363#endif /* !CROSS_CELL */
364
e1f001e5 365 if (flag & PRGRP) {
dba0cf81 366 /* group ids are negative */
367 if (tentry.id < (long)ntohl(cheader.maxGroup)) {
368 code = set_header_word (at, maxGroup, htonl(tentry.id));
e1f001e5 369 if (code) return PRDBFAIL;
370 }
371 }
372 else if (flag & PRFOREIGN) {
dba0cf81 373 if (tentry.id > (long)ntohl(cheader.maxForeign)) {
374 code = set_header_word (at, maxForeign, htonl(tentry.id));
e1f001e5 375 if (code) return PRDBFAIL;
376 }
377 }
378 else {
dba0cf81 379 if (tentry.id > (long)ntohl(cheader.maxID)) {
380 code = set_header_word (at, maxID, htonl(tentry.id));
e1f001e5 381 if (code) return PRDBFAIL;
382 }
383 }
dba0cf81 384 /* PRACCESS is off until set, defaults provided in AccessOK */
385 if (flag == 0) { /* only normal users get quota */
386 tentry.flags |= PRQUOTA;
387 tentry.ngroups = tentry.nusers = 20;
388 }
389
390 if (flag & (PRGRP | PRFOREIGN)) {
391 long loc = FindByID (at, creator);
392 struct prentry centry;
393 long *nP; /* ptr to entry to be decremented */
394 long n; /* quota to check */
395
396 if (loc) { /* this should only fail during initialization */
397 code = pr_Read (at, 0, loc, &centry, sizeof(centry));
398 if (code) return code;
399
400 if (flag & PRGRP) nP = &centry.ngroups;
401 else if (flag & PRFOREIGN) nP = &centry.nusers;
402 else nP = 0;
403
404 if (nP) {
405 if (!(ntohl(centry.flags) & PRQUOTA)) {
406 /* quota uninitialized, so do it now */
407 centry.flags = htonl (ntohl(centry.flags) | PRQUOTA);
408 centry.ngroups = centry.nusers = htonl(20);
409 }
410 n = ntohl(*nP);
411 if (n <= 0) {
412 if (!pr_noAuth &&
413 !IsAMemberOf (at, creator, SYSADMINID))
414 return PRNOMORE;
415 }
da0b4fd5 416 else { /* don't use up admin user's quota */
417 int admin = ((creator == SYSADMINID) ||
418 IsAMemberOf (at, creator, SYSADMINID));
419 if (!admin) *nP = htonl(n-1);
420 }
dba0cf81 421 }
422 code = pr_Write (at, 0, loc, &centry, sizeof(centry));
423 if (code) return code;
424 } /* if (loc) */
425 } /* need to check creation quota */
e1f001e5 426 tentry.creator = creator;
427 *aid = tentry.id;
e1f001e5 428 code = pr_WriteEntry(at, 0, newEntry, &tentry);
429 if (code) return PRDBFAIL;
430 code = AddToIDHash(at,*aid,newEntry);
431 if (code != PRSUCCESS) return code;
432 code = AddToNameHash(at,aname,newEntry);
433 if (code != PRSUCCESS) return code;
434 if (tentry.flags & PRGRP) {
435 code = AddToOwnerChain(at,tentry.id,oid);
436 if (code) return code;
437 }
438 if (tentry.flags & PRGRP) {
dba0cf81 439 if (inc_header_word (at, groupcount, 1)) return PRDBFAIL;
e1f001e5 440 }
441 else if (tentry.flags & PRFOREIGN) {
dba0cf81 442 if (inc_header_word (at, foreigncount, 1)) return PRDBFAIL;
e1f001e5 443 }
444 else if (tentry.flags & PRINST) {
dba0cf81 445 if (inc_header_word (at, instcount, 1)) return PRDBFAIL;
e1f001e5 446 }
447 else {
dba0cf81 448 if (inc_header_word (at, usercount, 1)) return PRDBFAIL;
e1f001e5 449 }
450 return PRSUCCESS;
451}
452
453
dba0cf81 454/* RemoveFromEntry - remove aid from bid's entries list, freeing a continuation
455 * entry if appropriate */
e1f001e5 456
dba0cf81 457long RemoveFromEntry (at, aid, bid)
458 register struct ubik_trans *at;
459 register long aid;
460 register long bid;
e1f001e5 461{
e1f001e5 462 register long code;
463 struct prentry tentry;
464 struct contentry centry;
465 struct contentry hentry;
466 long temp;
e1f001e5 467 long i,j;
468 long nptr;
dba0cf81 469 long hloc;
e1f001e5 470
dba0cf81 471 if (aid == bid) return PRINCONSISTENT;
e1f001e5 472 bzero(&hentry,sizeof(hentry));
473 temp = FindByID(at,bid);
dba0cf81 474 if (temp == 0) return PRNOENT;
e1f001e5 475 code = pr_ReadEntry(at, 0, temp, &tentry);
476 if (code != 0) return code;
dba0cf81 477#ifdef PR_REMEMBER_TIMES
478 tentry.removeTime = time(0);
479#endif
e1f001e5 480 for (i=0;i<PRSIZE;i++) {
481 if (tentry.entries[i] == aid) {
482 tentry.entries[i] = PRBADID;
483 tentry.count--;
484 code = pr_WriteEntry(at,0,temp,&tentry);
485 if (code != 0) return code;
486 return PRSUCCESS;
487 }
488 if (tentry.entries[i] == 0) /* found end of list */
489 return PRNOENT;
490 }
dba0cf81 491 hloc = 0;
492 nptr = tentry.next;
493 while (nptr != NULL) {
494 code = pr_ReadCoEntry(at,0,nptr,&centry);
495 if (code != 0) return code;
496 if ((centry.id != bid) || !(centry.flags & PRCONT)) return PRDBBAD;
497 for (i=0;i<COSIZE;i++) {
498 if (centry.entries[i] == aid) {
499 centry.entries[i] = PRBADID;
500 for (j=0;j<COSIZE;j++)
501 if (centry.entries[j] != PRBADID &&
502 centry.entries[j] != 0) break;
503 if (j == COSIZE) { /* can free this block */
504 if (hloc == 0) {
505 tentry.next = centry.next;
e1f001e5 506 }
dba0cf81 507 else {
508 hentry.next = centry.next;
509 code = pr_WriteCoEntry (at, 0, hloc, &hentry);
e1f001e5 510 if (code != 0) return code;
e1f001e5 511 }
dba0cf81 512 code = FreeBlock (at, nptr);
513 if (code) return code;
e1f001e5 514 }
dba0cf81 515 else { /* can't free it yet */
516 code = pr_WriteCoEntry(at,0,nptr,&centry);
517 if (code != 0) return code;
518 }
519 tentry.count--;
520 code = pr_WriteEntry(at,0,temp,&tentry);
521 if (code) return PRDBFAIL;
522 return 0;
e1f001e5 523 }
dba0cf81 524 if (centry.entries[i] == 0) return PRNOENT;
525 } /* for all coentry slots */
526 hloc = nptr;
527 nptr = centry.next;
528 bcopy(&centry,&hentry,sizeof(centry));
529 } /* while there are coentries */
530 return PRNOENT;
e1f001e5 531}
532
dba0cf81 533/* DeleteEntry - delete the entry in tentry at loc, removing it from all
534 * groups, putting groups owned by it on orphan chain, and freeing the space */
535
536long DeleteEntry (at, tentry, loc)
537 register struct ubik_trans *at;
538 struct prentry *tentry;
539 long loc;
e1f001e5 540{
e1f001e5 541 register long code;
e1f001e5 542 struct contentry centry;
e1f001e5 543 register long i;
544 long nptr;
dba0cf81 545
da0b4fd5 546#ifdef CROSS_CELL
547 if (index(tentry->name,'@')) {
548 if (tentry->flags & PRGRP) {
549 /* If there are still foreign user accounts from that cell
550 * don't delete the group */
551 if (tentry->count) return PRBADARG;
552 } else {
553 /* It's a user adjust the group quota upwards */
554 long loc = FindByID (at, tentry->cellid);
555 struct prentry centry;
556 if (loc) {
557 code = pr_Read (at, 0, loc, &centry, sizeof(centry));
558 if (code) return code;
559 if (ntohl(centry.flags) & PRQUOTA) {
560 centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
561 }
562#if !ADD_TO_AUTHUSER_GROUP
563 /* if this is a foreign cell entry then decrement the number of
564 * existing users in the prentry of the authuser group for that
565 * cell
566 */
567 centry.count = htonl(ntohl(centry.count) - 1);
568#endif
569 code = pr_Write (at, 0, loc, &centry, sizeof(centry));
570 if (code) return code;
571 }
572 }
573 }
574#endif /* CROSS_CELL */
575
dba0cf81 576 /* First remove the entire membership list */
e1f001e5 577 for (i=0;i<PRSIZE;i++) {
dba0cf81 578 if (tentry->entries[i] == PRBADID) continue;
579 if (tentry->entries[i] == 0) break;
580 code = RemoveFromEntry (at, tentry->id, tentry->entries[i]);
581 if (code) return code;
e1f001e5 582 }
dba0cf81 583 nptr = tentry->next;
e1f001e5 584 while (nptr != NULL) {
585 code = pr_ReadCoEntry(at,0,nptr,&centry);
586 if (code != 0) return PRDBFAIL;
587 for (i=0;i<COSIZE;i++) {
dba0cf81 588 if (centry.entries[i] == PRBADID) continue;
e1f001e5 589 if (centry.entries[i] == 0) break;
dba0cf81 590 code = RemoveFromEntry (at, tentry->id, centry.entries[i]);
591 if (code) return code;
e1f001e5 592 }
dba0cf81 593 code = FreeBlock (at, nptr); /* free continuation block */
594 if (code) return code;
e1f001e5 595 nptr = centry.next;
596 }
dba0cf81 597
598 /* Remove us from other's owned chain. Note that this will zero our owned
599 * field (on disk) so this step must follow the above step in case we are
600 * on our own owned list. */
601 if (tentry->flags & PRGRP) {
602 if (tentry->owner) {
603 code = RemoveFromOwnerChain (at, tentry->id, tentry->owner);
e1f001e5 604 if (code) return code;
605 }
606 else {
dba0cf81 607 code = RemoveFromOrphan (at, tentry->id);
e1f001e5 608 if (code) return code;
609 }
610 }
dba0cf81 611
612 code = RemoveFromIDHash(at,tentry->id,&loc);
e1f001e5 613 if (code != PRSUCCESS) return code;
dba0cf81 614 code = RemoveFromNameHash(at,tentry->name,&loc);
e1f001e5 615 if (code != PRSUCCESS) return code;
dba0cf81 616
617 if (tentry->flags & (PRGRP | PRFOREIGN)) {
618 long loc = FindByID (at, tentry->creator);
619 struct prentry centry;
da0b4fd5 620 int admin;
dba0cf81 621 if (loc) {
622 code = pr_Read (at, 0, loc, &centry, sizeof(centry));
623 if (code) return code;
da0b4fd5 624 admin = ((tentry->creator == SYSADMINID) ||
625 IsAMemberOf (at, tentry->creator, SYSADMINID));
dba0cf81 626 if (ntohl(centry.flags) & PRQUOTA) {
da0b4fd5 627 if ((tentry->flags & PRGRP) &&
628 !(admin && (ntohl(centry.ngroups) >= 20))) {
dba0cf81 629 centry.ngroups = htonl(ntohl(centry.ngroups) + 1);
da0b4fd5 630 } else if ((tentry->flags & PRFOREIGN) &&
631 !(admin && (ntohl(centry.nusers) >= 20))) {
dba0cf81 632 centry.nusers = htonl(ntohl(centry.nusers) + 1);
633 }
634 }
635 code = pr_Write (at, 0, loc, &centry, sizeof(centry));
636 if (code) return code;
637 }
e1f001e5 638 }
dba0cf81 639
640 if (tentry->flags & PRGRP) {
641 if (inc_header_word (at, groupcount, -1)) return PRDBFAIL;
e1f001e5 642 }
dba0cf81 643 else if (tentry->flags & PRFOREIGN) {
644 if (inc_header_word (at, foreigncount, -1)) return PRDBFAIL;
645 }
646 else if (tentry->flags & PRINST) {
647 if (inc_header_word (at, instcount, -1)) return PRDBFAIL;
e1f001e5 648 }
649 else {
dba0cf81 650 if (inc_header_word (at, usercount, -1)) return PRDBFAIL;
e1f001e5 651 }
dba0cf81 652 code = FreeBlock(at, loc);
653 return code;
e1f001e5 654}
655
dba0cf81 656/* AddToEntry - add aid to entry's entries list, alloc'ing a continuation block
657 * if needed.
658 *
659 * Note the entry is written out by this routine. */
e1f001e5 660
dba0cf81 661long AddToEntry (tt, entry, loc, aid)
662 struct ubik_trans *tt;
663 struct prentry *entry;
664 long loc;
665 long aid;
e1f001e5 666{
e1f001e5 667 register long code;
668 long i;
669 struct contentry nentry;
670 struct contentry aentry;
671 long nptr;
dba0cf81 672 long last; /* addr of last cont. block */
e1f001e5 673 long first = 0;
674 long cloc;
675 long slot = -1;
676
dba0cf81 677 if (entry->id == aid) return PRINCONSISTENT;
678#ifdef PR_REMEMBER_TIMES
679 entry->addTime = time(0);
680#endif
e1f001e5 681 for (i=0;i<PRSIZE;i++) {
dba0cf81 682 if (entry->entries[i] == aid)
e1f001e5 683 return PRIDEXIST;
dba0cf81 684 if (entry->entries[i] == PRBADID) { /* remember this spot */
e1f001e5 685 first = 1;
686 slot = i;
687 }
dba0cf81 688 else if (entry->entries[i] == 0) { /* end of the line */
e1f001e5 689 if (slot == -1) {
690 first = 1;
691 slot = i;
692 }
693 break;
694 }
695 }
dba0cf81 696 last = 0;
697 nptr = entry->next;
e1f001e5 698 while (nptr != NULL) {
dba0cf81 699 code = pr_ReadCoEntry(tt,0,nptr,&nentry);
e1f001e5 700 if (code != 0) return code;
dba0cf81 701 last = nptr;
e1f001e5 702 if (!(nentry.flags & PRCONT)) return PRDBFAIL;
703 for (i=0;i<COSIZE;i++) {
704 if (nentry.entries[i] == aid)
705 return PRIDEXIST;
706 if (nentry.entries[i] == PRBADID) {
707 if (slot == -1) {
708 slot = i;
709 cloc = nptr;
710 }
711 }
dba0cf81 712 else if (nentry.entries[i] == 0) {
e1f001e5 713 if (slot == -1) {
714 slot = i;
715 cloc = nptr;
716 }
717 break;
718 }
719 }
e1f001e5 720 nptr = nentry.next;
721 }
dba0cf81 722 if (slot != -1) { /* we found a place */
723 entry->count++;
e1f001e5 724 if (first) { /* place is in first block */
dba0cf81 725 entry->entries[slot] = aid;
726 code = pr_WriteEntry (tt, 0, loc, entry);
e1f001e5 727 if (code != 0) return code;
728 return PRSUCCESS;
729 }
dba0cf81 730 code = pr_WriteEntry (tt, 0, loc, entry);
731 if (code) return code;
e1f001e5 732 code = pr_ReadCoEntry(tt,0,cloc,&aentry);
733 if (code != 0) return code;
734 aentry.entries[slot] = aid;
735 code = pr_WriteCoEntry(tt,0,cloc,&aentry);
736 if (code != 0) return code;
737 return PRSUCCESS;
738 }
739 /* have to allocate a continuation block if we got here */
740 nptr = AllocBlock(tt);
dba0cf81 741 if (last) {
742 /* then we should tack new block after last block in cont. chain */
e1f001e5 743 nentry.next = nptr;
744 code = pr_WriteCoEntry(tt,0,last,&nentry);
745 if (code != 0) return code;
746 }
747 else {
dba0cf81 748 entry->next = nptr;
e1f001e5 749 }
dba0cf81 750 bzero(&aentry,sizeof(aentry));
e1f001e5 751 aentry.flags |= PRCONT;
dba0cf81 752 aentry.id = entry->id;
e1f001e5 753 aentry.next = NULL;
754 aentry.entries[0] = aid;
755 code = pr_WriteCoEntry(tt,0,nptr,&aentry);
756 if (code != 0) return code;
757 /* don't forget to update count, here! */
dba0cf81 758 entry->count++;
759 code = pr_WriteEntry (tt, 0, loc, entry);
760 return code;
e1f001e5 761
762}
763
dba0cf81 764long AddToPRList (alist, sizeP, id)
765 prlist *alist;
766 int *sizeP;
767 long id;
768{
769 if (alist->prlist_len >= PR_MAXGROUPS) return PRTOOMANY;
770 if (alist->prlist_len >= *sizeP) {
771 *sizeP = *sizeP + 100;
772 if (*sizeP > PR_MAXGROUPS) *sizeP = PR_MAXGROUPS;
773 alist->prlist_val =
774 (long *) ((alist->prlist_val) ?
775 realloc (alist->prlist_val, (*sizeP)*sizeof(long)) :
776 malloc ((*sizeP)*sizeof(long)));
777 }
778 alist->prlist_val[alist->prlist_len++] = id;
779 return 0;
780}
781
782long GetList (at, tentry, alist, add)
783 struct ubik_trans *at;
784 struct prentry *tentry;
785 prlist *alist;
786 long add;
e1f001e5 787{
788 register long code;
e1f001e5 789 long i;
e1f001e5 790 struct contentry centry;
791 long nptr;
dba0cf81 792 int size;
793 int count = 0;
e1f001e5 794 extern long IDCmp();
795
dba0cf81 796 size = 0;
797 alist->prlist_val = 0;
e1f001e5 798 alist->prlist_len = 0;
dba0cf81 799
e1f001e5 800 for (i=0;i<PRSIZE;i++) {
dba0cf81 801 if (tentry->entries[i] == PRBADID) continue;
802 if (tentry->entries[i] == 0) break;
803 code = AddToPRList (alist, &size, tentry->entries[i]);
804 if (code) return code;
e1f001e5 805 }
dba0cf81 806
807 nptr = tentry->next;
e1f001e5 808 while (nptr != NULL) {
809 /* look through cont entries */
810 code = pr_ReadCoEntry(at,0,nptr,&centry);
811 if (code != 0) return code;
812 for (i=0;i<COSIZE;i++) {
813 if (centry.entries[i] == PRBADID) continue;
814 if (centry.entries[i] == 0) break;
dba0cf81 815 code = AddToPRList (alist, &size, centry.entries[i]);
816 if (code) return code;
e1f001e5 817 }
818 nptr = centry.next;
dba0cf81 819 if (count++ > 50) IOMGR_Poll(), count = 0;
e1f001e5 820 }
dba0cf81 821
e1f001e5 822 if (add) { /* this is for a CPS, so tack on appropriate stuff */
dba0cf81 823 if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) {
da0b4fd5 824#ifdef CROSS_CELL
825 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
826 (code = AddAuthGroup(tentry, alist, &size)) ||
827 (code = AddToPRList (alist, &size, tentry->id))) return code;
828#else
dba0cf81 829 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
830 (code = AddToPRList (alist, &size, AUTHUSERID)) ||
831 (code = AddToPRList (alist, &size, tentry->id))) return code;
da0b4fd5 832#endif
e1f001e5 833 }
834 else {
dba0cf81 835 if ((code = AddToPRList (alist, &size, ANYUSERID)) ||
836 (code = AddToPRList (alist, &size, tentry->id))) return code;
e1f001e5 837 }
838 }
dba0cf81 839 if (alist->prlist_len > 100) IOMGR_Poll();
840 qsort(alist->prlist_val,alist->prlist_len,sizeof(long),IDCmp);
841 return PRSUCCESS;
842}
843
844long GetOwnedChain (ut, next, alist)
845 struct ubik_trans *ut;
846 long next;
847 prlist *alist;
848{ register long code;
849 struct prentry tentry;
850 int size;
851 int count = 0;
da0b4fd5 852 extern long IDCmp();
dba0cf81 853
854 size = 0;
855 alist->prlist_val = 0;
856 alist->prlist_len = 0;
857
858 while (next) {
859 code = pr_Read (ut, 0, next, &tentry, sizeof(tentry));
860 if (code) return code;
861 code = AddToPRList (alist, &size, ntohl(tentry.id));
862 if (code) return code;
863 next = ntohl(tentry.nextOwned);
864 if (count++ > 50) IOMGR_Poll(), count = 0;
865 }
866 if (alist->prlist_len > 100) IOMGR_Poll();
e1f001e5 867 qsort(alist->prlist_val,alist->prlist_len,sizeof(long),IDCmp);
868 return PRSUCCESS;
869}
870
871long GetMax(at,uid,gid)
872register struct ubik_trans *at;
873long *uid;
874long *gid;
875{
876 *uid = ntohl(cheader.maxID);
877 *gid = ntohl(cheader.maxGroup);
878 return PRSUCCESS;
879}
880
881long SetMax(at,id,flag)
882register struct ubik_trans *at;
883long id;
884long flag;
885{
886 register long code;
887 if (flag & PRGRP) {
888 cheader.maxGroup = htonl(id);
889 code = pr_Write(at,0,16,(char *)&cheader.maxGroup,sizeof(cheader.maxGroup));
890 if (code != 0) return code;
891 }
892 else {
893 cheader.maxID = htonl(id);
894 code = pr_Write(at,0,20,(char *)&cheader.maxID,sizeof(cheader.maxID));
895 if (code != 0) return code;
896 }
897 return PRSUCCESS;
898}
899
dba0cf81 900int pr_noAuth;
901
902long Initdb()
e1f001e5 903{
904 long code;
905 struct ubik_trans *tt;
906 long len;
e1f001e5 907 static long initd=0;
dba0cf81 908#if 0
e1f001e5 909 static struct ubik_version curver;
910 struct ubik_version newver;
dba0cf81 911#endif
e1f001e5 912
913 /* init the database. We'll try reading it, but if we're starting from scratch, we'll have to do a write transaction. */
914
dba0cf81 915 pr_noAuth = afsconf_GetNoAuthFlag(prdir);
916
da0b4fd5 917 code = ubik_BeginTransReadAny(dbase,UBIK_READTRANS, &tt);
e1f001e5 918 if (code) return code;
919 code = ubik_SetLock(tt,1,1,LOCKREAD);
920 if (code) {
921 ubik_AbortTrans(tt);
922 return code;
923 }
924 if (!initd) {
925 initd = 1;
dba0cf81 926#if 0
e1f001e5 927 bzero(&curver,sizeof(curver));
dba0cf81 928#endif
929 } else if (!ubik_CacheUpdate (tt)) {
930 code = ubik_EndTrans(tt);
931 return code;
932 }
933#if 0
934 code = ubik_GetVersion(tt,&newver);
935 if (vcmp(curver,newver) == 0) {
936 /* same version */
937 code = ubik_EndTrans(tt);
938 if (code) return code;
939 return PRSUCCESS;
e1f001e5 940 }
dba0cf81 941 bcopy(&newver,&curver,sizeof(struct ubik_version));
942#endif
943
e1f001e5 944 len = sizeof(cheader);
945 code = pr_Read(tt, 0, 0, (char *) &cheader, len);
946 if (code != 0) {
dba0cf81 947 com_err (whoami, code, "couldn't read header");
e1f001e5 948 ubik_AbortTrans(tt);
949 return code;
950 }
dba0cf81 951 if ((ntohl(cheader.version) == PRDBVERSION) &&
952 ntohl(cheader.headerSize) == sizeof(cheader) &&
953 ntohl(cheader.eofPtr) != NULL &&
954 FindByID(tt,ANONYMOUSID) != 0){
e1f001e5 955 /* database exists, so we don't have to build it */
956 code = ubik_EndTrans(tt);
957 if (code) return code;
958 return PRSUCCESS;
959 }
960 /* else we need to build a database */
961 code = ubik_EndTrans(tt);
962 if (code) return code;
dba0cf81 963
964 /* Only rebuild database if the db was deleted (the header is zero) and we
965 are running noAuth. */
966 { char *bp = (char *)&cheader;
967 int i;
968 for (i=0; i<sizeof(cheader); i++)
969 if (bp[i]) {
970 code = PRDBBAD;
971 com_err (whoami, code,
972 "Can't rebuild database because it is not empty");
973 return code;
974 }
975 }
976 if (!pr_noAuth) {
977 code = PRDBBAD;
978 com_err (whoami, code,
979 "Can't rebuild database because not running NoAuth");
980 return code;
981 }
982
e1f001e5 983 code = ubik_BeginTrans(dbase,UBIK_WRITETRANS, &tt);
984 if (code) return code;
da0b4fd5 985
e1f001e5 986 code = ubik_SetLock(tt,1,1,LOCKWRITE);
987 if (code) {
988 ubik_AbortTrans(tt);
989 return code;
990 }
dba0cf81 991
da0b4fd5 992 /* before doing a rebuild, check again that the dbase looks bad, because
993 * the previous check was only under a ReadAny transaction, and there could
994 * actually have been a good database out there. Now that we have a
995 * real write transaction, make sure things are still bad.
996 */
997 if ((ntohl(cheader.version) == PRDBVERSION) &&
998 ntohl(cheader.headerSize) == sizeof(cheader) &&
999 ntohl(cheader.eofPtr) != NULL &&
1000 FindByID(tt,ANONYMOUSID) != 0){
1001 /* database exists, so we don't have to build it */
1002 code = ubik_EndTrans(tt);
1003 if (code) return code;
1004 return PRSUCCESS;
1005 }
dba0cf81 1006
da0b4fd5 1007 /* Initialize the database header */
dba0cf81 1008 if ((code = set_header_word (tt, version, htonl(PRDBVERSION))) ||
1009 (code = set_header_word (tt, headerSize, htonl(sizeof(cheader)))) ||
1010 (code = set_header_word (tt, eofPtr, cheader.headerSize))) {
1011 com_err (whoami, code, "couldn't write header words");
e1f001e5 1012 ubik_AbortTrans(tt);
1013 return code;
1014 }
dba0cf81 1015
1016#define InitialGroup(id,name) do { \
1017 long temp = (id); \
1018 long flag = (id) < 0 ? PRGRP : 0; \
1019 code = CreateEntry \
1020 (tt, (name), &temp, /*idflag*/1, flag, SYSADMINID, SYSADMINID); \
1021 if (code) { \
1022 com_err (whoami, code, "couldn't create %s with id %di.", \
1023 (name), (id)); \
1024 ubik_AbortTrans(tt); \
1025 return code; \
1026 } \
1027} while (0)
1028
1029 InitialGroup (SYSADMINID, "system:administrators");
1030 InitialGroup (ANYUSERID, "system:anyuser");
1031 InitialGroup (AUTHUSERID, "system:authuser");
1032 InitialGroup (ANONYMOUSID, "anonymous");
1033
1034 /* Well, we don't really want the max id set to anonymousid, so we'll set
1035 * it back to 0 */
1036 code = set_header_word (tt, maxID, 0); /* correct in any byte order */
1037 if (code) {
1038 com_err (whoami, code, "couldn't reset max id");
e1f001e5 1039 ubik_AbortTrans(tt);
1040 return code;
1041 }
dba0cf81 1042
e1f001e5 1043 code = ubik_EndTrans(tt);
1044 if (code) return code;
1045 return PRSUCCESS;
1046}
1047
2ba81a31 1048/*
1049 * FUNCTION
1050 * fixOwnerChain
1051 *
1052 * DESCRIPTION
1053 * This function follows the "owned" and "nextOwned" chains and verifies
1054 * that the data is consistent. The chain is only traversed as far as is
1055 * necessary for efficiency reasons:
1056 * o Follow the "nextOwned" chain only if we had to adjust ourself
1057 * (either renaming ourself or adjusting the owner id)
1058 * o Follow the "owned" chain if we had to adjust ourself (see above), or
1059 * we are the parent that started this mess (tentry->id == oldid/newid)
1060 */
1061
1062long fixOwnerChain(at,loc,tentry,oldid,newid)
1063 struct ubik_trans *at;
1064 struct prentry *tentry;
1065 long loc, oldid, newid;
1066{
1067 char name[PR_MAXNAMELEN];
1068 struct prentry nentry;
1069 long pos;
1070 register long code;
1071 int nextOwn = 0;
1072
1073 if (newid && oldid != newid) {
1074 if (tentry->owner == oldid) tentry->owner = newid;
1075 if (tentry->creator == oldid) tentry->creator = newid;
1076
1077 /* If our owner has changed, continue along the nextOwned chain */
1078 if (tentry->owner == newid) nextOwn=1;
1079 }
1080
1081 strcpy(name, tentry->name);
1082 code=CorrectGroupName(at,name,tentry->creator,tentry->owner,tentry->name);
1083 if (code) return code;
1084 if (strcmp(name, tentry->name)) {
1085
1086 /* If we had to rename ourself, there are probably others
1087 * along the nextOwned chain that have to do the same. */
1088 nextOwn = 1;
1089
1090 pos = FindByName(at,tentry->name);
1091 if (pos) return PREXIST;
1092
1093 code = RemoveFromNameHash (at, name, &loc);
1094 if (code) return code;
1095 code = AddToNameHash(at,tentry->name,loc);
1096 if (code) return code;
1097 }
1098
1099 code = pr_WriteEntry(at, 0, loc, tentry);
1100 if (code) return code;
1101
1102 if ((loc = tentry->owned) &&
1103 (nextOwn || (newid && tentry->id == newid) || (tentry->id == oldid))) {
1104
1105 code = pr_ReadEntry(at,0,loc,&nentry);
1106 if (code) return code;
1107 code = fixOwnerChain(at, loc, &nentry, oldid, newid);
1108 if (code) return code;
1109 }
1110
1111 if (nextOwn && (loc = tentry->nextOwned)) {
1112
1113 code = pr_ReadEntry(at,0,loc,&nentry);
1114 if (code) return code;
1115 code = fixOwnerChain(at, loc, &nentry, oldid, newid);
1116 if (code) return code;
1117 }
1118 return PRSUCCESS;
1119}
1120
dba0cf81 1121long ChangeEntry (at, aid, cid, name, oid, newid)
1122 struct ubik_trans *at;
1123 long aid;
1124 long cid;
1125 char *name;
1126 long oid;
1127 long newid;
e1f001e5 1128{
2ba81a31 1129 register long code, nptr, i;
e1f001e5 1130 long pos;
2ba81a31 1131 struct prentry tentry, gentry;
1132 struct contentry centry;
e1f001e5 1133 long loc;
dba0cf81 1134 long oldowner;
e1f001e5 1135 char holder[PR_MAXNAMELEN];
1136 char temp[PR_MAXNAMELEN];
dba0cf81 1137 char oldname[PR_MAXNAMELEN];
da0b4fd5 1138#if CROSS_CELL
1139 char *atsign;
1140#endif
e1f001e5 1141
e1f001e5 1142 bzero(holder,PR_MAXNAMELEN);
1143 bzero(temp,PR_MAXNAMELEN);
1144 loc = FindByID(at,aid);
1145 if (!loc) return PRNOENT;
1146 code = pr_ReadEntry(at,0,loc,&tentry);
1147 if (code) return PRDBFAIL;
dba0cf81 1148 if (tentry.owner != cid &&
1149 !IsAMemberOf(at,cid,SYSADMINID) &&
1150 !IsAMemberOf(at,cid,tentry.owner) &&
1151 !pr_noAuth) return PRPERM;
1152#ifdef PR_REMEMBER_TIMES
1153 tentry.changeTime = time(0);
1154#endif
1155
1156 /* we're actually trying to change the id */
1157 if (aid != newid && newid != 0) {
1158 if (!IsAMemberOf(at,cid,SYSADMINID) && !pr_noAuth) return PRPERM;
e1f001e5 1159 pos = FindByID(at,newid);
1160 if (pos) return PRIDEXIST; /* new id already in use! */
da0b4fd5 1161 if ((aid < 0 && newid > 0) || (aid > 0 && newid < 0)) return PRPERM;
e1f001e5 1162 /* if new id is not in use, rehash things */
1163 code = RemoveFromIDHash(at,aid,&loc);
1164 if (code != PRSUCCESS) return code;
1165 tentry.id = newid;
1166 code = pr_WriteEntry(at,0,loc,&tentry);
dba0cf81 1167 if (code) return code;
e1f001e5 1168 code = AddToIDHash(at,tentry.id,loc);
1169 if (code) return code;
dba0cf81 1170 /* get current data */
1171 code = pr_ReadEntry(at,0,loc,&tentry);
1172 if (code) return PRDBFAIL;
2ba81a31 1173
1174 for (i=0;i<PRSIZE;i++) {
1175 if (tentry.entries[i] == PRBADID) continue;
1176 if (tentry.entries[i] == 0) break;
1177 if (pos = FindByID(at, tentry.entries[i])) {
1178 code = pr_ReadEntry(at,0,pos,&gentry);
1179 if (code) return PRDBFAIL;
1180 code = AddToEntry(at,&gentry,pos,newid);
1181 if (code) return PRDBFAIL;
1182 code = RemoveFromEntry(at,aid,tentry.entries[i]);
1183 if (code) return PRDBFAIL;
1184 } else {
1185 fprintf(stderr, "ChangeEntry: %d: Couldn't locate group %d\n",
1186 newid, tentry.entries[i]);
1187 return PRDBFAIL;
1188 }
1189 }
1190 nptr = tentry.next;
1191 while (nptr) {
1192 /* look through cont entries */
1193 code = pr_ReadCoEntry(at,0,nptr,&centry);
1194 if (code != 0) return code;
1195 for (i=0;i<COSIZE;i++) {
1196 if (centry.entries[i] == PRBADID) continue;
1197 if (centry.entries[i] == 0) break;
1198 if (pos = FindByID(at, centry.entries[i])) {
1199 code = pr_ReadEntry(at,0,pos,&gentry);
1200 if (code) return PRDBFAIL;
1201 code = AddToEntry(at,&gentry,pos,newid);
1202 if (code) return PRDBFAIL;
1203 code = RemoveFromEntry(at,aid,centry.entries[i]);
1204 if (code) return PRDBFAIL;
1205 } else
1206 return PRDBFAIL;
1207 }
1208 nptr = centry.next;
1209 }
e1f001e5 1210 }
dba0cf81 1211
da0b4fd5 1212#ifdef CROSS_CELL
1213 atsign = index(tentry.name, '@'); /* check for foreign entry */
1214#endif
1215
dba0cf81 1216 /* Change the owner */
e1f001e5 1217 if (tentry.owner != oid && oid) {
dba0cf81 1218 /* only groups can have their owner's changed */
1219 if (!(tentry.flags & PRGRP)) return PRPERM;
da0b4fd5 1220#ifdef CROSS_CELL
1221 /* don't allow modifications to foreign cell group owners */
1222 if (atsign) return PRPERM;
1223#endif
dba0cf81 1224 oldowner = tentry.owner;
1225 tentry.owner = oid;
1226 /* The entry must be written through first so Remove and Add routines
1227 * can operate on disk data */
1228 code = pr_WriteEntry(at,0,loc,(char *)&tentry);
1229 if (code) return PRDBFAIL;
e1f001e5 1230 if (tentry.flags & PRGRP) {
dba0cf81 1231 /* switch owner chains */
1232 if (oldowner) /* if it has an owner */
1233 code = RemoveFromOwnerChain(at,tentry.id,oldowner);
1234 else /* must be an orphan */
e1f001e5 1235 code = RemoveFromOrphan(at,tentry.id);
1236 if (code) return code;
dba0cf81 1237 code = AddToOwnerChain(at,tentry.id,tentry.owner);
e1f001e5 1238 if (code) return code;
1239 }
dba0cf81 1240 /* fix up the name */
1241 if ((tentry.flags & PRGRP) && (strlen(name) == 0)) name = tentry.name;
1242 /* get current data */
1243 code = pr_ReadEntry(at,0,loc,&tentry);
e1f001e5 1244 if (code) return PRDBFAIL;
1245 }
dba0cf81 1246
1247 /* Change the name, if name is a ptr to tentry.name then this name change
1248 * is due to a chown, otherwise caller has specified a new name */
1249 if ((name == tentry.name) ||
1250 (*name && (strcmp (tentry.name, name) != 0))) {
1251 strncpy (oldname, tentry.name, PR_MAXNAMELEN);
e1f001e5 1252 if (tentry.flags & PRGRP) {
da0b4fd5 1253#ifdef CROSS_CELL
1254 if (atsign) return PRPERM;
1255#endif
dba0cf81 1256 code = CorrectGroupName (at, name, cid, tentry.owner, tentry.name);
1257 if (code) return code;
1258
1259 if (name == tentry.name) { /* owner fixup */
1260 if (strcmp (oldname, tentry.name) == 0) goto nameOK;
1261 } else { /* new name, caller must be correct */
1262 if (strcmp (name, tentry.name) != 0) return PRBADNAM;
1263 }
da0b4fd5 1264 } else {
1265#ifdef CROSS_CELL
1266 /* Allow a foreign name change only if the cellname part is
1267 * the same */
1268 char *newatsign;
1269
1270 newatsign = index (name, '@');
1271 if (newatsign != atsign){ /* if they are the same no problem*/
1272 /* if the pointers are not equal the strings better be */
1273 if ((atsign == 0) || (newatsign == 0) ||
1274 strcmp (atsign,newatsign)) return PRPERM;
1275 }
1276#endif
1277 if (!CorrectUserName(name)) return PRBADNAM;
1278 }
dba0cf81 1279
e1f001e5 1280 pos = FindByName(at,name);
1281 if (pos) return PREXIST;
dba0cf81 1282 code = RemoveFromNameHash (at, oldname, &loc);
e1f001e5 1283 if (code != PRSUCCESS) return code;
dba0cf81 1284 strncpy (tentry.name, name, PR_MAXNAMELEN);
1285 code = pr_WriteEntry(at,0,loc,(char *)&tentry);
e1f001e5 1286 if (code) return PRDBFAIL;
1287 code = AddToNameHash(at,tentry.name,loc);
1288 if (code != PRSUCCESS) return code;
dba0cf81 1289nameOK:;
e1f001e5 1290 }
2ba81a31 1291 return (fixOwnerChain(at, loc, &tentry, aid, newid));
e1f001e5 1292}
da0b4fd5 1293
1294#ifdef CROSS_CELL
1295long allocNextId(cellEntry)
1296struct prentry *cellEntry;
1297{
1298 /* Id's for foreign cell entries are constructed as follows:
1299 * The 16 low order bits are the group id of the cell and the
1300 * top 16 bits identify the particular users in that cell */
1301
1302 long id;
1303
1304 id = (ntohl(cellEntry -> nusers) +1);
1305 cellEntry -> nusers = htonl(id);
1306 /* use the field nusers to keep the last used id in that
1307 * foreign cell's group.
1308 *
1309 * Note: It would seem more appropriate to use ngroup for
1310 * that and nusers to enforce the quota, however pts does not
1311 * have an option to change foreign users quota yet. */
1312 id = (id << 16) | ((ntohl(cellEntry-> id)) & 0x0000ffff);
1313 return id;
1314}
1315
1316int inRange(cellEntry,aid)
1317struct prentry *cellEntry;
1318long aid;
1319{
1320 unsigned long id,cellid,groupid;
1321
1322 /* The only thing that we want to make sure here is that the id
1323 * is in the legal range of this group. If it is a duplicate we
1324 * don't care since it will get in a different check. */
1325 cellid = aid & 0x0000ffff;
1326 groupid = (ntohl(cellEntry-> id)) & 0x0000ffff;
1327 if (cellid != groupid) return 0; /* not in range */
1328
1329 /* if we got here we're ok but we need to update the nusers field
1330 * in order to get the id correct the next time that we try to
1331 * allocate it automatically. */
1332 id = aid >> 16;
1333 if (id > ntohl(cellEntry -> nusers))
1334 cellEntry -> nusers = htonl(id);
1335 return 1;
1336}
1337
1338AddAuthGroup(tentry, alist, size)
1339 struct prentry *tentry;
1340 prlist *alist;
1341 long *size;
1342{
1343 if (!(index(tentry->name, '@')))
1344 return (AddToPRList (alist, size, AUTHUSERID));
1345#if ADD_TO_AUTHUSER_GROUP
1346 return PRSUCCESS;
1347#else
1348 return (AddToPRList (alist, size, tentry->cellid));
1349#endif
1350}
1351#endif /* CROSS_CELL */
This page took 5.92883 seconds and 5 git commands to generate.