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