]>
Commit | Line | Data |
---|---|---|
dba0cf81 | 1 | /* Copyright (C) 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 | #ifndef lint |
9 | static char rcsid[] = "$Header$"; | |
10 | #endif | |
11 | ||
e1f001e5 | 12 | /* |
13 | Sherri Nichols | |
14 | Information Technology Center | |
15 | November, 1988 | |
16 | ||
17 | Modified May, 1989 by Jeff Schiller to keep disk file in | |
18 | network byte order | |
19 | ||
20 | */ | |
21 | ||
dba0cf81 | 22 | #include <afs/param.h> |
23 | #include <sys/types.h> | |
e1f001e5 | 24 | #include <stdio.h> |
e1f001e5 | 25 | #include <lock.h> |
dba0cf81 | 26 | #include <netinet/in.h> |
e1f001e5 | 27 | #include <ubik.h> |
28 | #include <rx/xdr.h> | |
dba0cf81 | 29 | #include <afs/com_err.h> |
30 | #include "ptserver.h" | |
31 | #include "pterror.h" | |
32 | #include <strings.h> | |
e1f001e5 | 33 | |
e1f001e5 | 34 | extern struct ubik_dbase *dbase; |
35 | extern struct afsconf_dir *prdir; | |
dba0cf81 | 36 | extern int pr_noAuth; |
e1f001e5 | 37 | |
dba0cf81 | 38 | static char *whoami = "ptserver"; |
39 | ||
40 | /* CorrectUserName - Check to make sure a user name is OK. It must not include | |
41 | * either a colon (or it would look like a group) or an atsign (or it would | |
42 | * look like a foreign user). The length is checked as well to make sure | |
43 | * that the user name, an atsign, and the local cell name will fit in | |
44 | * PR_MAXNAMELEN. This is so this user can fit in another cells database as | |
45 | * a foreign user with our cell name tacked on. This is a predicate, so it | |
46 | * return one if name is OK and zero if name is bogus. */ | |
47 | ||
48 | static int CorrectUserName (name) | |
49 | char *name; | |
50 | { | |
51 | extern int pr_realmNameLen; | |
52 | ||
53 | if (index (name, ':') || index(name, '@') || index(name, '\n')) return 0; | |
54 | if (strlen (name) >= PR_MAXNAMELEN - pr_realmNameLen - 1) return 0; | |
55 | return 1; | |
56 | } | |
57 | ||
58 | static long CorrectGroupName (ut, aname, cid, oid, cname) | |
59 | struct ubik_trans *ut; | |
60 | char aname[PR_MAXNAMELEN]; /* name for group */ | |
61 | long cid; /* caller id */ | |
62 | long oid; /* owner of group */ | |
63 | char cname[PR_MAXNAMELEN]; /* correct name for group */ | |
64 | { | |
65 | long code; | |
66 | int admin; | |
67 | char *prefix; /* ptr to group owner part */ | |
68 | char *suffix; /* ptr to group name part */ | |
69 | char name[PR_MAXNAMELEN]; /* correct name for group */ | |
70 | struct prentry tentry; | |
71 | ||
72 | if (strlen (aname) >= PR_MAXNAMELEN) return PRBADNAM; | |
73 | admin = pr_noAuth || IsAMemberOf (ut, cid, SYSADMINID); | |
74 | ||
75 | if (oid == 0) oid = cid; | |
76 | ||
77 | /* Determine the correct prefix for the name. */ | |
78 | if (oid == SYSADMINID) prefix = "system"; | |
79 | else { | |
80 | long loc = FindByID (ut, oid); | |
81 | if (loc == 0) { | |
82 | /* let admin create groups owned by non-existent ids (probably | |
83 | * setting a group to own itself). Check that they look like | |
84 | * groups (with a colon) or otherwise are good user names. */ | |
85 | if (admin) { | |
86 | strcpy (cname, aname); | |
87 | goto done; | |
88 | } | |
89 | return PRNOENT; | |
90 | } | |
91 | code = pr_Read (ut, 0, loc, &tentry, sizeof(tentry)); | |
92 | if (code) return code; | |
93 | if (ntohl(tentry.flags) & PRGRP) { | |
94 | if ((tentry.count == 0) && !admin) return PRGROUPEMPTY; | |
95 | /* terminate prefix at colon if there is one */ | |
96 | if (prefix = index(tentry.name, ':')) *prefix = 0; | |
97 | } | |
98 | prefix = tentry.name; | |
99 | } | |
100 | /* only sysadmin allow to use 'system:' prefix */ | |
101 | if ((strcmp (prefix, "system") == 0) && !admin) return PRPERM; | |
102 | ||
103 | strcpy (name, aname); /* in case aname & cname are same */ | |
104 | suffix = index(name, ':'); | |
105 | if (suffix == 0) { | |
106 | /* sysadmin can make groups w/o ':', but they must still look like | |
107 | * legal user names. */ | |
108 | if (!admin) return PRBADNAM; | |
109 | strcpy (cname, name); | |
110 | } | |
111 | else { | |
112 | if (strlen(prefix)+strlen(suffix) >= PR_MAXNAMELEN) return PRBADNAM; | |
113 | strcpy (cname, prefix); | |
114 | strcat (cname, suffix); | |
115 | } | |
116 | done: | |
117 | /* check for legal name with either group rules or user rules */ | |
118 | if (suffix = index(cname, ':')) { | |
119 | /* check for confusing characters */ | |
120 | if (index(cname, '@') || /* avoid confusion w/ foreign users */ | |
121 | index(cname, '\n') || /* restrict so recreate can work */ | |
122 | index(suffix+1, ':')) /* avoid multiple colons */ | |
123 | return PRBADNAM; | |
124 | } else { | |
125 | if (!CorrectUserName (cname)) return PRBADNAM; | |
126 | } | |
127 | return 0; | |
128 | } | |
129 | ||
130 | int AccessOK (ut, cid, tentry, mem, any) | |
131 | struct ubik_trans *ut; | |
132 | long cid; /* caller id */ | |
133 | struct prentry *tentry; /* object being accessed */ | |
134 | int mem; /* check membership in aid, if group */ | |
135 | int any; /* if set return true */ | |
136 | { long flags; | |
137 | long oid; | |
138 | long aid; | |
139 | ||
140 | if (pr_noAuth) return 1; | |
141 | if (tentry) { | |
142 | flags = tentry->flags; | |
143 | oid = tentry->owner; | |
144 | aid = tentry->id; | |
145 | } else { | |
146 | flags = oid = aid = 0; | |
147 | } | |
148 | if (!(flags & PRACCESS)) /* provide default access */ | |
149 | if (flags & PRGRP) | |
150 | flags |= PRP_GROUP_DEFAULT; | |
151 | else | |
152 | flags |= PRP_USER_DEFAULT; | |
153 | ||
154 | if (flags & any) return 1; | |
155 | if (oid) { | |
156 | if ((cid == oid) || | |
157 | IsAMemberOf (ut, cid, oid)) return 1; | |
158 | } | |
159 | if (aid > 0) { /* checking on a user */ | |
160 | if (aid == cid) return 1; | |
161 | } else if (aid < 0) { /* checking on group */ | |
162 | if ((flags & mem) && IsAMemberOf (ut, cid, aid)) return 1; | |
163 | } | |
164 | if (IsAMemberOf (ut, cid, SYSADMINID)) return 1; | |
165 | return 0; /* no access */ | |
166 | } | |
167 | ||
168 | long CreateEntry (at, aname, aid, idflag, flag, oid, creator) | |
169 | register struct ubik_trans *at; | |
170 | char aname[PR_MAXNAMELEN]; | |
171 | long *aid; | |
172 | long idflag; | |
173 | long flag; | |
174 | long oid; | |
175 | long creator; | |
e1f001e5 | 176 | { |
177 | /* get and init a new entry */ | |
178 | register long code; | |
179 | long newEntry; | |
180 | long temp; | |
181 | struct prentry tentry; | |
182 | ||
183 | bzero(&tentry, sizeof(tentry)); | |
dba0cf81 | 184 | |
185 | if ((oid == 0) || (oid == ANONYMOUSID)) oid = creator; | |
186 | ||
187 | if (flag & PRGRP) { | |
188 | code = CorrectGroupName (at, aname, creator, oid, tentry.name); | |
189 | if (code) return code; | |
190 | if (strcmp (aname, tentry.name) != 0) return PRBADNAM; | |
191 | } else { /* non-group must not have colon */ | |
192 | if (!CorrectUserName(aname)) return PRBADNAM; | |
193 | strcpy (tentry.name, aname); | |
194 | } | |
195 | ||
196 | if (FindByName(at,aname)) return PREXIST; | |
197 | ||
e1f001e5 | 198 | newEntry = AllocBlock(at); |
199 | if (!newEntry) return PRDBFAIL; | |
dba0cf81 | 200 | #ifdef PR_REMEMBER_TIMES |
201 | tentry.createTime = time(0); | |
202 | #endif | |
e1f001e5 | 203 | if (flag & PRGRP) { |
204 | tentry.flags |= PRGRP; | |
205 | tentry.owner = oid; | |
206 | } | |
207 | else if (flag & PRFOREIGN) { | |
208 | tentry.flags |= PRFOREIGN; | |
209 | tentry.owner = oid; | |
210 | } | |
211 | else tentry.owner = SYSADMINID; | |
212 | if (idflag) | |
213 | tentry.id = *aid; | |
214 | else { | |
215 | code= AllocID(at,flag,&tentry.id); | |
216 | if (code != PRSUCCESS) return code; | |
217 | } | |
218 | if (flag & PRGRP) { | |
dba0cf81 | 219 | /* group ids are negative */ |
220 | if (tentry.id < (long)ntohl(cheader.maxGroup)) { | |
221 | code = set_header_word (at, maxGroup, htonl(tentry.id)); | |
e1f001e5 | 222 | if (code) return PRDBFAIL; |
223 | } | |
224 | } | |
225 | else if (flag & PRFOREIGN) { | |
dba0cf81 | 226 | if (tentry.id > (long)ntohl(cheader.maxForeign)) { |
227 | code = set_header_word (at, maxForeign, htonl(tentry.id)); | |
e1f001e5 | 228 | if (code) return PRDBFAIL; |
229 | } | |
230 | } | |
231 | else { | |
dba0cf81 | 232 | if (tentry.id > (long)ntohl(cheader.maxID)) { |
233 | code = set_header_word (at, maxID, htonl(tentry.id)); | |
e1f001e5 | 234 | if (code) return PRDBFAIL; |
235 | } | |
236 | } | |
dba0cf81 | 237 | /* PRACCESS is off until set, defaults provided in AccessOK */ |
238 | if (flag == 0) { /* only normal users get quota */ | |
239 | tentry.flags |= PRQUOTA; | |
240 | tentry.ngroups = tentry.nusers = 20; | |
241 | } | |
242 | ||
243 | if (flag & (PRGRP | PRFOREIGN)) { | |
244 | long loc = FindByID (at, creator); | |
245 | struct prentry centry; | |
246 | long *nP; /* ptr to entry to be decremented */ | |
247 | long n; /* quota to check */ | |
248 | ||
249 | if (loc) { /* this should only fail during initialization */ | |
250 | code = pr_Read (at, 0, loc, ¢ry, sizeof(centry)); | |
251 | if (code) return code; | |
252 | ||
253 | if (flag & PRGRP) nP = ¢ry.ngroups; | |
254 | else if (flag & PRFOREIGN) nP = ¢ry.nusers; | |
255 | else nP = 0; | |
256 | ||
257 | if (nP) { | |
258 | if (!(ntohl(centry.flags) & PRQUOTA)) { | |
259 | /* quota uninitialized, so do it now */ | |
260 | centry.flags = htonl (ntohl(centry.flags) | PRQUOTA); | |
261 | centry.ngroups = centry.nusers = htonl(20); | |
262 | } | |
263 | n = ntohl(*nP); | |
264 | if (n <= 0) { | |
265 | if (!pr_noAuth && | |
266 | !IsAMemberOf (at, creator, SYSADMINID)) | |
267 | return PRNOMORE; | |
268 | } | |
269 | else *nP = htonl(n-1); | |
270 | } | |
271 | code = pr_Write (at, 0, loc, ¢ry, sizeof(centry)); | |
272 | if (code) return code; | |
273 | } /* if (loc) */ | |
274 | } /* need to check creation quota */ | |
e1f001e5 | 275 | tentry.creator = creator; |
276 | *aid = tentry.id; | |
e1f001e5 | 277 | code = pr_WriteEntry(at, 0, newEntry, &tentry); |
278 | if (code) return PRDBFAIL; | |
279 | code = AddToIDHash(at,*aid,newEntry); | |
280 | if (code != PRSUCCESS) return code; | |
281 | code = AddToNameHash(at,aname,newEntry); | |
282 | if (code != PRSUCCESS) return code; | |
283 | if (tentry.flags & PRGRP) { | |
284 | code = AddToOwnerChain(at,tentry.id,oid); | |
285 | if (code) return code; | |
286 | } | |
287 | if (tentry.flags & PRGRP) { | |
dba0cf81 | 288 | if (inc_header_word (at, groupcount, 1)) return PRDBFAIL; |
e1f001e5 | 289 | } |
290 | else if (tentry.flags & PRFOREIGN) { | |
dba0cf81 | 291 | if (inc_header_word (at, foreigncount, 1)) return PRDBFAIL; |
e1f001e5 | 292 | } |
293 | else if (tentry.flags & PRINST) { | |
dba0cf81 | 294 | if (inc_header_word (at, instcount, 1)) return PRDBFAIL; |
e1f001e5 | 295 | } |
296 | else { | |
dba0cf81 | 297 | if (inc_header_word (at, usercount, 1)) return PRDBFAIL; |
e1f001e5 | 298 | } |
299 | return PRSUCCESS; | |
300 | } | |
301 | ||
302 | ||
dba0cf81 | 303 | /* RemoveFromEntry - remove aid from bid's entries list, freeing a continuation |
304 | * entry if appropriate */ | |
e1f001e5 | 305 | |
dba0cf81 | 306 | long RemoveFromEntry (at, aid, bid) |
307 | register struct ubik_trans *at; | |
308 | register long aid; | |
309 | register long bid; | |
e1f001e5 | 310 | { |
e1f001e5 | 311 | register long code; |
312 | struct prentry tentry; | |
313 | struct contentry centry; | |
314 | struct contentry hentry; | |
315 | long temp; | |
e1f001e5 | 316 | long i,j; |
317 | long nptr; | |
dba0cf81 | 318 | long hloc; |
e1f001e5 | 319 | |
dba0cf81 | 320 | if (aid == bid) return PRINCONSISTENT; |
e1f001e5 | 321 | bzero(&hentry,sizeof(hentry)); |
322 | temp = FindByID(at,bid); | |
dba0cf81 | 323 | if (temp == 0) return PRNOENT; |
e1f001e5 | 324 | code = pr_ReadEntry(at, 0, temp, &tentry); |
325 | if (code != 0) return code; | |
dba0cf81 | 326 | #ifdef PR_REMEMBER_TIMES |
327 | tentry.removeTime = time(0); | |
328 | #endif | |
e1f001e5 | 329 | for (i=0;i<PRSIZE;i++) { |
330 | if (tentry.entries[i] == aid) { | |
331 | tentry.entries[i] = PRBADID; | |
332 | tentry.count--; | |
333 | code = pr_WriteEntry(at,0,temp,&tentry); | |
334 | if (code != 0) return code; | |
335 | return PRSUCCESS; | |
336 | } | |
337 | if (tentry.entries[i] == 0) /* found end of list */ | |
338 | return PRNOENT; | |
339 | } | |
dba0cf81 | 340 | hloc = 0; |
341 | nptr = tentry.next; | |
342 | while (nptr != NULL) { | |
343 | code = pr_ReadCoEntry(at,0,nptr,¢ry); | |
344 | if (code != 0) return code; | |
345 | if ((centry.id != bid) || !(centry.flags & PRCONT)) return PRDBBAD; | |
346 | for (i=0;i<COSIZE;i++) { | |
347 | if (centry.entries[i] == aid) { | |
348 | centry.entries[i] = PRBADID; | |
349 | for (j=0;j<COSIZE;j++) | |
350 | if (centry.entries[j] != PRBADID && | |
351 | centry.entries[j] != 0) break; | |
352 | if (j == COSIZE) { /* can free this block */ | |
353 | if (hloc == 0) { | |
354 | tentry.next = centry.next; | |
e1f001e5 | 355 | } |
dba0cf81 | 356 | else { |
357 | hentry.next = centry.next; | |
358 | code = pr_WriteCoEntry (at, 0, hloc, &hentry); | |
e1f001e5 | 359 | if (code != 0) return code; |
e1f001e5 | 360 | } |
dba0cf81 | 361 | code = FreeBlock (at, nptr); |
362 | if (code) return code; | |
e1f001e5 | 363 | } |
dba0cf81 | 364 | else { /* can't free it yet */ |
365 | code = pr_WriteCoEntry(at,0,nptr,¢ry); | |
366 | if (code != 0) return code; | |
367 | } | |
368 | tentry.count--; | |
369 | code = pr_WriteEntry(at,0,temp,&tentry); | |
370 | if (code) return PRDBFAIL; | |
371 | return 0; | |
e1f001e5 | 372 | } |
dba0cf81 | 373 | if (centry.entries[i] == 0) return PRNOENT; |
374 | } /* for all coentry slots */ | |
375 | hloc = nptr; | |
376 | nptr = centry.next; | |
377 | bcopy(¢ry,&hentry,sizeof(centry)); | |
378 | } /* while there are coentries */ | |
379 | return PRNOENT; | |
e1f001e5 | 380 | } |
381 | ||
dba0cf81 | 382 | /* DeleteEntry - delete the entry in tentry at loc, removing it from all |
383 | * groups, putting groups owned by it on orphan chain, and freeing the space */ | |
384 | ||
385 | long DeleteEntry (at, tentry, loc) | |
386 | register struct ubik_trans *at; | |
387 | struct prentry *tentry; | |
388 | long loc; | |
e1f001e5 | 389 | { |
e1f001e5 | 390 | register long code; |
e1f001e5 | 391 | long temp1; |
e1f001e5 | 392 | struct contentry centry; |
393 | struct prentry nentry; | |
394 | register long i; | |
395 | long nptr; | |
dba0cf81 | 396 | |
397 | /* First remove the entire membership list */ | |
e1f001e5 | 398 | for (i=0;i<PRSIZE;i++) { |
dba0cf81 | 399 | if (tentry->entries[i] == PRBADID) continue; |
400 | if (tentry->entries[i] == 0) break; | |
401 | code = RemoveFromEntry (at, tentry->id, tentry->entries[i]); | |
402 | if (code) return code; | |
e1f001e5 | 403 | } |
dba0cf81 | 404 | nptr = tentry->next; |
e1f001e5 | 405 | while (nptr != NULL) { |
406 | code = pr_ReadCoEntry(at,0,nptr,¢ry); | |
407 | if (code != 0) return PRDBFAIL; | |
408 | for (i=0;i<COSIZE;i++) { | |
dba0cf81 | 409 | if (centry.entries[i] == PRBADID) continue; |
e1f001e5 | 410 | if (centry.entries[i] == 0) break; |
dba0cf81 | 411 | code = RemoveFromEntry (at, tentry->id, centry.entries[i]); |
412 | if (code) return code; | |
e1f001e5 | 413 | } |
dba0cf81 | 414 | code = FreeBlock (at, nptr); /* free continuation block */ |
415 | if (code) return code; | |
e1f001e5 | 416 | nptr = centry.next; |
417 | } | |
dba0cf81 | 418 | |
419 | /* Remove us from other's owned chain. Note that this will zero our owned | |
420 | * field (on disk) so this step must follow the above step in case we are | |
421 | * on our own owned list. */ | |
422 | if (tentry->flags & PRGRP) { | |
423 | if (tentry->owner) { | |
424 | code = RemoveFromOwnerChain (at, tentry->id, tentry->owner); | |
e1f001e5 | 425 | if (code) return code; |
426 | } | |
427 | else { | |
dba0cf81 | 428 | code = RemoveFromOrphan (at, tentry->id); |
e1f001e5 | 429 | if (code) return code; |
430 | } | |
431 | } | |
dba0cf81 | 432 | |
433 | code = RemoveFromIDHash(at,tentry->id,&loc); | |
e1f001e5 | 434 | if (code != PRSUCCESS) return code; |
dba0cf81 | 435 | code = RemoveFromNameHash(at,tentry->name,&loc); |
e1f001e5 | 436 | if (code != PRSUCCESS) return code; |
dba0cf81 | 437 | |
438 | if (tentry->flags & (PRGRP | PRFOREIGN)) { | |
439 | long loc = FindByID (at, tentry->creator); | |
440 | struct prentry centry; | |
441 | if (loc) { | |
442 | code = pr_Read (at, 0, loc, ¢ry, sizeof(centry)); | |
443 | if (code) return code; | |
444 | if (ntohl(centry.flags) & PRQUOTA) { | |
445 | if (tentry->flags & PRGRP) { | |
446 | centry.ngroups = htonl(ntohl(centry.ngroups) + 1); | |
447 | } else if (tentry->flags & PRFOREIGN) { | |
448 | centry.nusers = htonl(ntohl(centry.nusers) + 1); | |
449 | } | |
450 | } | |
451 | code = pr_Write (at, 0, loc, ¢ry, sizeof(centry)); | |
452 | if (code) return code; | |
453 | } | |
e1f001e5 | 454 | } |
dba0cf81 | 455 | |
456 | if (tentry->flags & PRGRP) { | |
457 | if (inc_header_word (at, groupcount, -1)) return PRDBFAIL; | |
e1f001e5 | 458 | } |
dba0cf81 | 459 | else if (tentry->flags & PRFOREIGN) { |
460 | if (inc_header_word (at, foreigncount, -1)) return PRDBFAIL; | |
461 | } | |
462 | else if (tentry->flags & PRINST) { | |
463 | if (inc_header_word (at, instcount, -1)) return PRDBFAIL; | |
e1f001e5 | 464 | } |
465 | else { | |
dba0cf81 | 466 | if (inc_header_word (at, usercount, -1)) return PRDBFAIL; |
e1f001e5 | 467 | } |
dba0cf81 | 468 | code = FreeBlock(at, loc); |
469 | return code; | |
e1f001e5 | 470 | } |
471 | ||
dba0cf81 | 472 | /* AddToEntry - add aid to entry's entries list, alloc'ing a continuation block |
473 | * if needed. | |
474 | * | |
475 | * Note the entry is written out by this routine. */ | |
e1f001e5 | 476 | |
dba0cf81 | 477 | long AddToEntry (tt, entry, loc, aid) |
478 | struct ubik_trans *tt; | |
479 | struct prentry *entry; | |
480 | long loc; | |
481 | long aid; | |
e1f001e5 | 482 | { |
e1f001e5 | 483 | register long code; |
484 | long i; | |
485 | struct contentry nentry; | |
486 | struct contentry aentry; | |
487 | long nptr; | |
dba0cf81 | 488 | long last; /* addr of last cont. block */ |
e1f001e5 | 489 | long first = 0; |
490 | long cloc; | |
491 | long slot = -1; | |
492 | ||
dba0cf81 | 493 | if (entry->id == aid) return PRINCONSISTENT; |
494 | #ifdef PR_REMEMBER_TIMES | |
495 | entry->addTime = time(0); | |
496 | #endif | |
e1f001e5 | 497 | for (i=0;i<PRSIZE;i++) { |
dba0cf81 | 498 | if (entry->entries[i] == aid) |
e1f001e5 | 499 | return PRIDEXIST; |
dba0cf81 | 500 | if (entry->entries[i] == PRBADID) { /* remember this spot */ |
e1f001e5 | 501 | first = 1; |
502 | slot = i; | |
503 | } | |
dba0cf81 | 504 | else if (entry->entries[i] == 0) { /* end of the line */ |
e1f001e5 | 505 | if (slot == -1) { |
506 | first = 1; | |
507 | slot = i; | |
508 | } | |
509 | break; | |
510 | } | |
511 | } | |
dba0cf81 | 512 | last = 0; |
513 | nptr = entry->next; | |
e1f001e5 | 514 | while (nptr != NULL) { |
dba0cf81 | 515 | code = pr_ReadCoEntry(tt,0,nptr,&nentry); |
e1f001e5 | 516 | if (code != 0) return code; |
dba0cf81 | 517 | last = nptr; |
e1f001e5 | 518 | if (!(nentry.flags & PRCONT)) return PRDBFAIL; |
519 | for (i=0;i<COSIZE;i++) { | |
520 | if (nentry.entries[i] == aid) | |
521 | return PRIDEXIST; | |
522 | if (nentry.entries[i] == PRBADID) { | |
523 | if (slot == -1) { | |
524 | slot = i; | |
525 | cloc = nptr; | |
526 | } | |
527 | } | |
dba0cf81 | 528 | else if (nentry.entries[i] == 0) { |
e1f001e5 | 529 | if (slot == -1) { |
530 | slot = i; | |
531 | cloc = nptr; | |
532 | } | |
533 | break; | |
534 | } | |
535 | } | |
e1f001e5 | 536 | nptr = nentry.next; |
537 | } | |
dba0cf81 | 538 | if (slot != -1) { /* we found a place */ |
539 | entry->count++; | |
e1f001e5 | 540 | if (first) { /* place is in first block */ |
dba0cf81 | 541 | entry->entries[slot] = aid; |
542 | code = pr_WriteEntry (tt, 0, loc, entry); | |
e1f001e5 | 543 | if (code != 0) return code; |
544 | return PRSUCCESS; | |
545 | } | |
dba0cf81 | 546 | code = pr_WriteEntry (tt, 0, loc, entry); |
547 | if (code) return code; | |
e1f001e5 | 548 | code = pr_ReadCoEntry(tt,0,cloc,&aentry); |
549 | if (code != 0) return code; | |
550 | aentry.entries[slot] = aid; | |
551 | code = pr_WriteCoEntry(tt,0,cloc,&aentry); | |
552 | if (code != 0) return code; | |
553 | return PRSUCCESS; | |
554 | } | |
555 | /* have to allocate a continuation block if we got here */ | |
556 | nptr = AllocBlock(tt); | |
dba0cf81 | 557 | if (last) { |
558 | /* then we should tack new block after last block in cont. chain */ | |
e1f001e5 | 559 | nentry.next = nptr; |
560 | code = pr_WriteCoEntry(tt,0,last,&nentry); | |
561 | if (code != 0) return code; | |
562 | } | |
563 | else { | |
dba0cf81 | 564 | entry->next = nptr; |
e1f001e5 | 565 | } |
dba0cf81 | 566 | bzero(&aentry,sizeof(aentry)); |
e1f001e5 | 567 | aentry.flags |= PRCONT; |
dba0cf81 | 568 | aentry.id = entry->id; |
e1f001e5 | 569 | aentry.next = NULL; |
570 | aentry.entries[0] = aid; | |
571 | code = pr_WriteCoEntry(tt,0,nptr,&aentry); | |
572 | if (code != 0) return code; | |
573 | /* don't forget to update count, here! */ | |
dba0cf81 | 574 | entry->count++; |
575 | code = pr_WriteEntry (tt, 0, loc, entry); | |
576 | return code; | |
e1f001e5 | 577 | |
578 | } | |
579 | ||
dba0cf81 | 580 | long AddToPRList (alist, sizeP, id) |
581 | prlist *alist; | |
582 | int *sizeP; | |
583 | long id; | |
584 | { | |
585 | if (alist->prlist_len >= PR_MAXGROUPS) return PRTOOMANY; | |
586 | if (alist->prlist_len >= *sizeP) { | |
587 | *sizeP = *sizeP + 100; | |
588 | if (*sizeP > PR_MAXGROUPS) *sizeP = PR_MAXGROUPS; | |
589 | alist->prlist_val = | |
590 | (long *) ((alist->prlist_val) ? | |
591 | realloc (alist->prlist_val, (*sizeP)*sizeof(long)) : | |
592 | malloc ((*sizeP)*sizeof(long))); | |
593 | } | |
594 | alist->prlist_val[alist->prlist_len++] = id; | |
595 | return 0; | |
596 | } | |
597 | ||
598 | long GetList (at, tentry, alist, add) | |
599 | struct ubik_trans *at; | |
600 | struct prentry *tentry; | |
601 | prlist *alist; | |
602 | long add; | |
e1f001e5 | 603 | { |
604 | register long code; | |
e1f001e5 | 605 | long i; |
e1f001e5 | 606 | struct contentry centry; |
607 | long nptr; | |
dba0cf81 | 608 | int size; |
609 | int count = 0; | |
e1f001e5 | 610 | extern long IDCmp(); |
611 | ||
dba0cf81 | 612 | size = 0; |
613 | alist->prlist_val = 0; | |
e1f001e5 | 614 | alist->prlist_len = 0; |
dba0cf81 | 615 | |
e1f001e5 | 616 | for (i=0;i<PRSIZE;i++) { |
dba0cf81 | 617 | if (tentry->entries[i] == PRBADID) continue; |
618 | if (tentry->entries[i] == 0) break; | |
619 | code = AddToPRList (alist, &size, tentry->entries[i]); | |
620 | if (code) return code; | |
e1f001e5 | 621 | } |
dba0cf81 | 622 | |
623 | nptr = tentry->next; | |
e1f001e5 | 624 | while (nptr != NULL) { |
625 | /* look through cont entries */ | |
626 | code = pr_ReadCoEntry(at,0,nptr,¢ry); | |
627 | if (code != 0) return code; | |
628 | for (i=0;i<COSIZE;i++) { | |
629 | if (centry.entries[i] == PRBADID) continue; | |
630 | if (centry.entries[i] == 0) break; | |
dba0cf81 | 631 | code = AddToPRList (alist, &size, centry.entries[i]); |
632 | if (code) return code; | |
e1f001e5 | 633 | } |
634 | nptr = centry.next; | |
dba0cf81 | 635 | if (count++ > 50) IOMGR_Poll(), count = 0; |
e1f001e5 | 636 | } |
dba0cf81 | 637 | |
e1f001e5 | 638 | if (add) { /* this is for a CPS, so tack on appropriate stuff */ |
dba0cf81 | 639 | if (tentry->id != ANONYMOUSID && tentry->id != ANYUSERID) { |
640 | if ((code = AddToPRList (alist, &size, ANYUSERID)) || | |
641 | (code = AddToPRList (alist, &size, AUTHUSERID)) || | |
642 | (code = AddToPRList (alist, &size, tentry->id))) return code; | |
e1f001e5 | 643 | } |
644 | else { | |
dba0cf81 | 645 | if ((code = AddToPRList (alist, &size, ANYUSERID)) || |
646 | (code = AddToPRList (alist, &size, tentry->id))) return code; | |
e1f001e5 | 647 | } |
648 | } | |
dba0cf81 | 649 | if (alist->prlist_len > 100) IOMGR_Poll(); |
650 | qsort(alist->prlist_val,alist->prlist_len,sizeof(long),IDCmp); | |
651 | return PRSUCCESS; | |
652 | } | |
653 | ||
654 | long GetOwnedChain (ut, next, alist) | |
655 | struct ubik_trans *ut; | |
656 | long next; | |
657 | prlist *alist; | |
658 | { register long code; | |
659 | struct prentry tentry; | |
660 | int size; | |
661 | int count = 0; | |
662 | ||
663 | size = 0; | |
664 | alist->prlist_val = 0; | |
665 | alist->prlist_len = 0; | |
666 | ||
667 | while (next) { | |
668 | code = pr_Read (ut, 0, next, &tentry, sizeof(tentry)); | |
669 | if (code) return code; | |
670 | code = AddToPRList (alist, &size, ntohl(tentry.id)); | |
671 | if (code) return code; | |
672 | next = ntohl(tentry.nextOwned); | |
673 | if (count++ > 50) IOMGR_Poll(), count = 0; | |
674 | } | |
675 | if (alist->prlist_len > 100) IOMGR_Poll(); | |
e1f001e5 | 676 | qsort(alist->prlist_val,alist->prlist_len,sizeof(long),IDCmp); |
677 | return PRSUCCESS; | |
678 | } | |
679 | ||
680 | long GetMax(at,uid,gid) | |
681 | register struct ubik_trans *at; | |
682 | long *uid; | |
683 | long *gid; | |
684 | { | |
685 | *uid = ntohl(cheader.maxID); | |
686 | *gid = ntohl(cheader.maxGroup); | |
687 | return PRSUCCESS; | |
688 | } | |
689 | ||
690 | long SetMax(at,id,flag) | |
691 | register struct ubik_trans *at; | |
692 | long id; | |
693 | long flag; | |
694 | { | |
695 | register long code; | |
696 | if (flag & PRGRP) { | |
697 | cheader.maxGroup = htonl(id); | |
698 | code = pr_Write(at,0,16,(char *)&cheader.maxGroup,sizeof(cheader.maxGroup)); | |
699 | if (code != 0) return code; | |
700 | } | |
701 | else { | |
702 | cheader.maxID = htonl(id); | |
703 | code = pr_Write(at,0,20,(char *)&cheader.maxID,sizeof(cheader.maxID)); | |
704 | if (code != 0) return code; | |
705 | } | |
706 | return PRSUCCESS; | |
707 | } | |
708 | ||
dba0cf81 | 709 | int pr_noAuth; |
710 | ||
711 | long Initdb() | |
e1f001e5 | 712 | { |
713 | long code; | |
714 | struct ubik_trans *tt; | |
715 | long len; | |
e1f001e5 | 716 | static long initd=0; |
dba0cf81 | 717 | #if 0 |
e1f001e5 | 718 | static struct ubik_version curver; |
719 | struct ubik_version newver; | |
dba0cf81 | 720 | #endif |
e1f001e5 | 721 | |
722 | /* init the database. We'll try reading it, but if we're starting from scratch, we'll have to do a write transaction. */ | |
723 | ||
dba0cf81 | 724 | pr_noAuth = afsconf_GetNoAuthFlag(prdir); |
725 | ||
e1f001e5 | 726 | code = ubik_BeginTrans(dbase,UBIK_READTRANS, &tt); |
727 | if (code) return code; | |
728 | code = ubik_SetLock(tt,1,1,LOCKREAD); | |
729 | if (code) { | |
730 | ubik_AbortTrans(tt); | |
731 | return code; | |
732 | } | |
733 | if (!initd) { | |
734 | initd = 1; | |
dba0cf81 | 735 | #if 0 |
e1f001e5 | 736 | bzero(&curver,sizeof(curver)); |
dba0cf81 | 737 | #endif |
738 | } else if (!ubik_CacheUpdate (tt)) { | |
739 | code = ubik_EndTrans(tt); | |
740 | return code; | |
741 | } | |
742 | #if 0 | |
743 | code = ubik_GetVersion(tt,&newver); | |
744 | if (vcmp(curver,newver) == 0) { | |
745 | /* same version */ | |
746 | code = ubik_EndTrans(tt); | |
747 | if (code) return code; | |
748 | return PRSUCCESS; | |
e1f001e5 | 749 | } |
dba0cf81 | 750 | bcopy(&newver,&curver,sizeof(struct ubik_version)); |
751 | #endif | |
752 | ||
e1f001e5 | 753 | len = sizeof(cheader); |
754 | code = pr_Read(tt, 0, 0, (char *) &cheader, len); | |
755 | if (code != 0) { | |
dba0cf81 | 756 | com_err (whoami, code, "couldn't read header"); |
e1f001e5 | 757 | ubik_AbortTrans(tt); |
758 | return code; | |
759 | } | |
dba0cf81 | 760 | if ((ntohl(cheader.version) == PRDBVERSION) && |
761 | ntohl(cheader.headerSize) == sizeof(cheader) && | |
762 | ntohl(cheader.eofPtr) != NULL && | |
763 | FindByID(tt,ANONYMOUSID) != 0){ | |
e1f001e5 | 764 | /* database exists, so we don't have to build it */ |
765 | code = ubik_EndTrans(tt); | |
766 | if (code) return code; | |
767 | return PRSUCCESS; | |
768 | } | |
769 | /* else we need to build a database */ | |
770 | code = ubik_EndTrans(tt); | |
771 | if (code) return code; | |
dba0cf81 | 772 | |
773 | /* Only rebuild database if the db was deleted (the header is zero) and we | |
774 | are running noAuth. */ | |
775 | { char *bp = (char *)&cheader; | |
776 | int i; | |
777 | for (i=0; i<sizeof(cheader); i++) | |
778 | if (bp[i]) { | |
779 | code = PRDBBAD; | |
780 | com_err (whoami, code, | |
781 | "Can't rebuild database because it is not empty"); | |
782 | return code; | |
783 | } | |
784 | } | |
785 | if (!pr_noAuth) { | |
786 | code = PRDBBAD; | |
787 | com_err (whoami, code, | |
788 | "Can't rebuild database because not running NoAuth"); | |
789 | return code; | |
790 | } | |
791 | ||
e1f001e5 | 792 | code = ubik_BeginTrans(dbase,UBIK_WRITETRANS, &tt); |
793 | if (code) return code; | |
794 | code = ubik_SetLock(tt,1,1,LOCKWRITE); | |
795 | if (code) { | |
796 | ubik_AbortTrans(tt); | |
797 | return code; | |
798 | } | |
dba0cf81 | 799 | |
800 | /* Initialize the database header */ | |
801 | ||
802 | if ((code = set_header_word (tt, version, htonl(PRDBVERSION))) || | |
803 | (code = set_header_word (tt, headerSize, htonl(sizeof(cheader)))) || | |
804 | (code = set_header_word (tt, eofPtr, cheader.headerSize))) { | |
805 | com_err (whoami, code, "couldn't write header words"); | |
e1f001e5 | 806 | ubik_AbortTrans(tt); |
807 | return code; | |
808 | } | |
dba0cf81 | 809 | |
810 | #define InitialGroup(id,name) do { \ | |
811 | long temp = (id); \ | |
812 | long flag = (id) < 0 ? PRGRP : 0; \ | |
813 | code = CreateEntry \ | |
814 | (tt, (name), &temp, /*idflag*/1, flag, SYSADMINID, SYSADMINID); \ | |
815 | if (code) { \ | |
816 | com_err (whoami, code, "couldn't create %s with id %di.", \ | |
817 | (name), (id)); \ | |
818 | ubik_AbortTrans(tt); \ | |
819 | return code; \ | |
820 | } \ | |
821 | } while (0) | |
822 | ||
823 | InitialGroup (SYSADMINID, "system:administrators"); | |
824 | InitialGroup (ANYUSERID, "system:anyuser"); | |
825 | InitialGroup (AUTHUSERID, "system:authuser"); | |
826 | InitialGroup (ANONYMOUSID, "anonymous"); | |
827 | ||
828 | /* Well, we don't really want the max id set to anonymousid, so we'll set | |
829 | * it back to 0 */ | |
830 | code = set_header_word (tt, maxID, 0); /* correct in any byte order */ | |
831 | if (code) { | |
832 | com_err (whoami, code, "couldn't reset max id"); | |
e1f001e5 | 833 | ubik_AbortTrans(tt); |
834 | return code; | |
835 | } | |
dba0cf81 | 836 | |
e1f001e5 | 837 | code = ubik_EndTrans(tt); |
838 | if (code) return code; | |
839 | return PRSUCCESS; | |
840 | } | |
841 | ||
dba0cf81 | 842 | long ChangeEntry (at, aid, cid, name, oid, newid) |
843 | struct ubik_trans *at; | |
844 | long aid; | |
845 | long cid; | |
846 | char *name; | |
847 | long oid; | |
848 | long newid; | |
e1f001e5 | 849 | { |
850 | register long code; | |
851 | long pos; | |
852 | struct prentry tentry; | |
853 | long loc; | |
dba0cf81 | 854 | long oldowner; |
e1f001e5 | 855 | char holder[PR_MAXNAMELEN]; |
856 | char temp[PR_MAXNAMELEN]; | |
dba0cf81 | 857 | char oldname[PR_MAXNAMELEN]; |
e1f001e5 | 858 | |
e1f001e5 | 859 | bzero(holder,PR_MAXNAMELEN); |
860 | bzero(temp,PR_MAXNAMELEN); | |
861 | loc = FindByID(at,aid); | |
862 | if (!loc) return PRNOENT; | |
863 | code = pr_ReadEntry(at,0,loc,&tentry); | |
864 | if (code) return PRDBFAIL; | |
dba0cf81 | 865 | if (tentry.owner != cid && |
866 | !IsAMemberOf(at,cid,SYSADMINID) && | |
867 | !IsAMemberOf(at,cid,tentry.owner) && | |
868 | !pr_noAuth) return PRPERM; | |
869 | #ifdef PR_REMEMBER_TIMES | |
870 | tentry.changeTime = time(0); | |
871 | #endif | |
872 | ||
873 | /* we're actually trying to change the id */ | |
874 | if (aid != newid && newid != 0) { | |
875 | if (!IsAMemberOf(at,cid,SYSADMINID) && !pr_noAuth) return PRPERM; | |
e1f001e5 | 876 | pos = FindByID(at,newid); |
877 | if (pos) return PRIDEXIST; /* new id already in use! */ | |
878 | if ((aid < 0 && newid) > 0 || (aid > 0 && newid < 0)) return PRPERM; | |
879 | /* if new id is not in use, rehash things */ | |
880 | code = RemoveFromIDHash(at,aid,&loc); | |
881 | if (code != PRSUCCESS) return code; | |
882 | tentry.id = newid; | |
883 | code = pr_WriteEntry(at,0,loc,&tentry); | |
dba0cf81 | 884 | if (code) return code; |
e1f001e5 | 885 | code = AddToIDHash(at,tentry.id,loc); |
886 | if (code) return code; | |
dba0cf81 | 887 | /* get current data */ |
888 | code = pr_ReadEntry(at,0,loc,&tentry); | |
889 | if (code) return PRDBFAIL; | |
e1f001e5 | 890 | } |
dba0cf81 | 891 | |
892 | /* Change the owner */ | |
e1f001e5 | 893 | if (tentry.owner != oid && oid) { |
dba0cf81 | 894 | /* only groups can have their owner's changed */ |
895 | if (!(tentry.flags & PRGRP)) return PRPERM; | |
896 | oldowner = tentry.owner; | |
897 | tentry.owner = oid; | |
898 | /* The entry must be written through first so Remove and Add routines | |
899 | * can operate on disk data */ | |
900 | code = pr_WriteEntry(at,0,loc,(char *)&tentry); | |
901 | if (code) return PRDBFAIL; | |
e1f001e5 | 902 | if (tentry.flags & PRGRP) { |
dba0cf81 | 903 | /* switch owner chains */ |
904 | if (oldowner) /* if it has an owner */ | |
905 | code = RemoveFromOwnerChain(at,tentry.id,oldowner); | |
906 | else /* must be an orphan */ | |
e1f001e5 | 907 | code = RemoveFromOrphan(at,tentry.id); |
908 | if (code) return code; | |
dba0cf81 | 909 | code = AddToOwnerChain(at,tentry.id,tentry.owner); |
e1f001e5 | 910 | if (code) return code; |
911 | } | |
dba0cf81 | 912 | /* fix up the name */ |
913 | if ((tentry.flags & PRGRP) && (strlen(name) == 0)) name = tentry.name; | |
914 | /* get current data */ | |
915 | code = pr_ReadEntry(at,0,loc,&tentry); | |
e1f001e5 | 916 | if (code) return PRDBFAIL; |
917 | } | |
dba0cf81 | 918 | |
919 | /* Change the name, if name is a ptr to tentry.name then this name change | |
920 | * is due to a chown, otherwise caller has specified a new name */ | |
921 | if ((name == tentry.name) || | |
922 | (*name && (strcmp (tentry.name, name) != 0))) { | |
923 | strncpy (oldname, tentry.name, PR_MAXNAMELEN); | |
e1f001e5 | 924 | if (tentry.flags & PRGRP) { |
dba0cf81 | 925 | code = CorrectGroupName (at, name, cid, tentry.owner, tentry.name); |
926 | if (code) return code; | |
927 | ||
928 | if (name == tentry.name) { /* owner fixup */ | |
929 | if (strcmp (oldname, tentry.name) == 0) goto nameOK; | |
930 | } else { /* new name, caller must be correct */ | |
931 | if (strcmp (name, tentry.name) != 0) return PRBADNAM; | |
932 | } | |
e1f001e5 | 933 | } |
934 | else | |
dba0cf81 | 935 | if (!CorrectUserName(name)) return PRBADNAM; |
936 | ||
e1f001e5 | 937 | pos = FindByName(at,name); |
938 | if (pos) return PREXIST; | |
dba0cf81 | 939 | code = RemoveFromNameHash (at, oldname, &loc); |
e1f001e5 | 940 | if (code != PRSUCCESS) return code; |
dba0cf81 | 941 | strncpy (tentry.name, name, PR_MAXNAMELEN); |
942 | code = pr_WriteEntry(at,0,loc,(char *)&tentry); | |
e1f001e5 | 943 | if (code) return PRDBFAIL; |
944 | code = AddToNameHash(at,tentry.name,loc); | |
945 | if (code != PRSUCCESS) return code; | |
dba0cf81 | 946 | nameOK:; |
e1f001e5 | 947 | } |
948 | return PRSUCCESS; | |
949 | } |