/*
* Copyright 2000, International Business Machines Corporation and others.
* All Rights Reserved.
- *
+ *
* This software has been released under the terms of the IBM Public
* License. For details, see the LICENSE file in the top-level source
* directory or online at http://www.openafs.org/dl/license10.html
*/
-/*
+/*
* (5) Add functions to process supergroups:
* ChangeIDEntry(), RemoveFromSGEntry(),
* AddToSGEntry(), GetListSG2().
#include <afsconfig.h>
#include <afs/param.h>
+#include <afs/stds.h>
-RCSID
- ("$Header$");
+#include <roken.h>
-#include <afs/stds.h>
-#include <sys/types.h>
-#include <stdio.h>
-#ifdef AFS_NT40_ENV
-#include <winsock2.h>
-#else
-#include <netinet/in.h>
-#endif
-#include <string.h>
#include <lock.h>
#include <ubik.h>
#include <rx/xdr.h>
#include <afs/com_err.h>
#include <afs/cellconfig.h>
+
#include "ptserver.h"
#include "pterror.h"
-#include <stdlib.h>
+#include "ptprototypes.h"
/* Foreign cells are represented by the group system:authuser@cell*/
#define AUTHUSER_GROUP "system:authuser"
extern struct ubik_dbase *dbase;
extern struct afsconf_dir *prdir;
extern int pr_noAuth;
-extern int IDCmp();
-extern afs_int32 AddToEntry();
+static int inRange(struct prentry *cellEntry, afs_int32 aid);
+static afs_int32 allocNextId(struct ubik_trans *, struct prentry *);
+static int AddAuthGroup(struct prentry *tentry, prlist *alist, afs_int32 *size);
+
static char *whoami = "ptserver";
int prp_user_default = PRP_USER_DEFAULT;
#include "map.h"
afs_int32 depthsg = 5; /* Maximum iterations used during IsAMemberOF */
-extern int IDCmp();
afs_int32 GetListSG2(struct ubik_trans *at, afs_int32 gid, prlist * alist,
afs_int32 * sizeP, afs_int32 depth);
-afs_int32 allocNextId(struct ubik_trans *, struct prentry *);
struct map *sg_flagged;
struct map *sg_found;
* so we can always tell if we're writing a group record.
*/
-int (*pt_save_dbase_write) ();
+int (*pt_save_dbase_write)(struct ubik_dbase *, afs_int32, void *, afs_int32,
+ afs_int32);
int
-pt_mywrite(struct ubik_dbase *tdb, afs_int32 fno, char *bp, afs_int32 pos, afs_int32 count)
+pt_mywrite(struct ubik_dbase *tdb, afs_int32 fno, void *bp, afs_int32 pos, afs_int32 count)
{
afs_uint32 headersize = ntohl(cheader.headerSize);
* just after ubik_ServerInit.
*/
-void
-pt_hook_write()
+void
+pt_hook_write(void)
{
extern struct ubik_dbase *ubik_dbase;
if (ubik_dbase->write != pt_mywrite) {
#endif /* SUPERGROUPS */
/* CorrectUserName - Check to make sure a user name is OK. It must not include
- * either a colon (or it would look like a group) or an atsign (or it would
- * look like a foreign user). The length is checked as well to make sure
- * that the user name, an atsign, and the local cell name will fit in
- * PR_MAXNAMELEN. This is so this user can fit in another cells database as
- * a foreign user with our cell name tacked on. This is a predicate, so it
- * return one if name is OK and zero if name is bogus. */
+ * either a colon (or it would look like a group) or a newline (which can
+ * confuse some ptdb code, depending on the format we're reading from).
+ * This is a predicate, so it return one if name is OK and zero if name is
+ * bogus. */
static int
CorrectUserName(char *name)
{
- extern int pr_realmNameLen;
-
/* We accept foreign names, so we will deal with '@' later */
if (strchr(name, ':') || strchr(name, '\n'))
return 0;
- if (strlen(name) >= PR_MAXNAMELEN - pr_realmNameLen - 1)
+ if (strlen(name) >= PR_MAXNAMELEN)
return 0;
return 1;
}
CorrectGroupName(struct ubik_trans *ut, char aname[PR_MAXNAMELEN], /* name for group */
afs_int32 cid, /* caller id */
afs_int32 oid, /* owner of group */
+ afs_int32 admin, /* non-zero if admin */
char cname[PR_MAXNAMELEN]) /* correct name for group */
{
afs_int32 code;
- int admin;
char *prefix; /* ptr to group owner part */
char *suffix; /* ptr to group name part */
char name[PR_MAXNAMELEN]; /* correct name for group */
if (strlen(aname) >= PR_MAXNAMELEN)
return PRBADNAM;
- admin = pr_noAuth || IsAMemberOf(ut, cid, SYSADMINID);
-
- if (oid == 0)
- oid = cid;
/* Determine the correct prefix for the name. */
if (oid == SYSADMINID)
strcpy(name, aname); /* in case aname & cname are same */
suffix = strchr(name, ':');
+ /* let e.g. pt_util create groups with "wrong" names (like
+ * an orphan whose parent ID was reused). Check that they look like
+ * groups (with a colon) or otherwise are good user names. */
+ if (pr_noAuth) {
+ strcpy(cname, aname);
+ goto done;
+ }
if (suffix == 0) {
/* sysadmin can make groups w/o ':', but they must still look like
* legal user names. */
return 1;
if (cid == SYSADMINID)
return 1; /* special case fileserver */
- if (restricted && ((mem == PRP_ADD_MEM) || (mem == PRP_REMOVE_MEM)) && (any == 0))
- return 0;
+ if (restricted && !IsAMemberOf(ut, cid, SYSADMINID)) {
+ if (mem == PRP_ADD_MEM || mem == PRP_REMOVE_MEM) {
+ /* operation is for adding/removing members from a group */
+ return 0;
+ }
+ if (mem == 0 && any == 0) {
+ /* operation is for modifying an entry (or some administrative
+ * global operations) */
+ return 0;
+ }
+ }
if (tentry) {
flags = tentry->flags;
oid = tentry->owner;
/* get and init a new entry */
afs_int32 code;
afs_int32 newEntry;
+ afs_int32 admin;
struct prentry tentry, tent;
char *atsign;
memset(&tentry, 0, sizeof(tentry));
- if ((oid == 0) || (oid == ANONYMOUSID))
+ admin = pr_noAuth || IsAMemberOf(at, creator, SYSADMINID);
+
+ if (oid == 0 || oid == ANONYMOUSID) {
+ if (!admin && creator == 0)
+ return PRBADARG;
oid = creator;
+ }
if (flag & PRGRP) {
- code = CorrectGroupName(at, aname, creator, oid, tentry.name);
+ code = CorrectGroupName(at, aname, creator, oid, admin, tentry.name);
if (code)
return code;
if (strcmp(aname, tentry.name) != 0)
newEntry = AllocBlock(at);
if (!newEntry)
return PRDBFAIL;
-#ifdef PR_REMEMBER_TIMES
tentry.createTime = time(0);
-#endif
if (flag & PRGRP) {
tentry.flags = PRGRP;
}
} else {
/* A foreign user: <name>@<cell>. The foreign user is added to
- * its representing group. It is
+ * its representing group. It is
*/
char *cellGroup;
afs_int32 pos, n;
/* To create the user <name>@<cell> the group AUTHUSER_GROUP@<cell>
* must exist.
*/
- cellGroup =
- (char *)malloc(strlen(AUTHUSER_GROUP) + strlen(atsign) + 1);
- strcpy(cellGroup, AUTHUSER_GROUP);
- strcat(cellGroup, atsign);
+ if (asprintf(&cellGroup, "%s%s", AUTHUSER_GROUP, atsign) < 0)
+ return PRNOMEM;
pos = FindByName(at, cellGroup, ¢ry);
free(cellGroup);
if (!pos)
return PRBADARG;
tentry.id = *aid;
} else {
- /* Allocate an ID special for this foreign user. It is based
+ /* Allocate an ID special for this foreign user. It is based
* on the representing group's id and nusers count.
*/
tentry.id = allocNextId(at, ¢ry);
/* write updated entry for group */
code = pr_Write(at, 0, pos, ¢ry, sizeof(centry));
+ if (code)
+ return PRDBFAIL;
/* Now add the new user entry to the database */
- tentry.creator = creator;
+ if (creator == 0)
+ tentry.creator = tentry.id;
+ else
+ tentry.creator = creator;
*aid = tentry.id;
code = pr_WriteEntry(at, 0, newEntry, &tentry);
if (code)
}
/* Admins don't get charged for creating a group.
- * If in noAuth mode, you get changed for it but you
+ * If in noAuth mode, you get changed for it but you
* are still allowed to create as many groups as you want.
*/
admin = ((creator == SYSADMINID)
tentry.ngroups = tentry.nusers = 20;
}
- tentry.creator = creator;
+ if (creator == 0)
+ tentry.creator = tentry.id;
+ else
+ tentry.creator = creator;
*aid = tentry.id;
code = pr_WriteEntry(at, 0, newEntry, &tentry);
if (code)
code = pr_ReadEntry(at, 0, temp, &tentry);
if (code != 0)
return code;
-#ifdef PR_REMEMBER_TIMES
tentry.removeTime = time(0);
-#endif
for (i = 0; i < PRSIZE; i++) {
if (tentry.entries[i] == aid) {
tentry.entries[i] = PRBADID;
* entry if appropriate */
afs_int32
-ChangeIDEntry(register struct ubik_trans *at, register afs_int32 aid, afs_int32 newid, register afs_int32 bid)
+ChangeIDEntry(struct ubik_trans *at, afs_int32 aid, afs_int32 newid, afs_int32 bid)
{
- register afs_int32 code;
+ afs_int32 code;
struct prentry tentry;
struct contentry centry;
afs_int32 temp;
* continuation entry if appropriate */
afs_int32
-RemoveFromSGEntry(register struct ubik_trans *at, register afs_int32 aid, register afs_int32 bid)
+RemoveFromSGEntry(struct ubik_trans *at, afs_int32 aid, afs_int32 bid)
{
- register afs_int32 code;
+ afs_int32 code;
struct prentry tentry;
struct prentryg *tentryg;
struct contentry centry;
code = pr_ReadEntry(at, 0, temp, &tentry);
if (code != 0)
return code;
-#ifdef PR_REMEMBER_TIMES
tentry.removeTime = time(NULL);
-#endif
tentryg = (struct prentryg *)&tentry;
for (i = 0; i < SGSIZE; i++) {
if (tentryg->supergroup[i] == aid) {
} /* for all coentry slots */
hloc = nptr;
nptr = centry.next;
- memcpy((char *)¢ry, (char *)&hentry, sizeof(centry));
+ memcpy(&hentry, ¢ry, sizeof(centry));
} /* while there are coentries */
return PRNOENT;
}
}
#endif /* SUPERGROUPS */
nptr = tentry->next;
- while (nptr != (afs_int32) NULL) {
+ while (nptr != 0) {
code = pr_ReadCoEntry(at, 0, nptr, ¢ry);
if (code != 0)
return PRDBFAIL;
if (entry->id == aid)
return PRINCONSISTENT;
-#ifdef PR_REMEMBER_TIMES
entry->addTime = time(0);
-#endif
for (i = 0; i < PRSIZE; i++) {
if (entry->entries[i] == aid)
return PRIDEXIST;
}
last = 0;
nptr = entry->next;
- while (nptr != (afs_int32) NULL) {
+ while (nptr != 0) {
code = pr_ReadCoEntry(tt, 0, nptr, &nentry);
if (code != 0)
return code;
afs_int32
AddToSGEntry(struct ubik_trans *tt, struct prentry *entry, afs_int32 loc, afs_int32 aid)
{
- register afs_int32 code;
+ afs_int32 code;
afs_int32 i;
struct contentry nentry;
struct contentry aentry;
afs_int32 nptr;
afs_int32 last; /* addr of last cont. block */
afs_int32 first = 0;
- afs_int32 cloc;
+ afs_int32 cloc = 0;
afs_int32 slot = -1;
if (entry->id == aid)
return PRINCONSISTENT;
-#ifdef PR_REMEMBER_TIMES
entry->addTime = time(NULL);
-#endif
entryg = (struct prentryg *)entry;
for (i = 0; i < SGSIZE; i++) {
if (entryg->supergroup[i] == aid)
afs_int32
AddToPRList(prlist *alist, int *sizeP, afs_int32 id)
{
- char *tmp;
+ afs_int32 *tmp;
int count;
if (alist->prlist_len >= *sizeP) {
count = alist->prlist_len + 100;
if (alist->prlist_val) {
- tmp =
- (char *)realloc(alist->prlist_val, count * sizeof(afs_int32));
+ tmp = realloc(alist->prlist_val, count * sizeof(afs_int32));
} else {
- tmp = (char *)malloc(count * sizeof(afs_int32));
+ tmp = malloc(count * sizeof(afs_int32));
}
if (!tmp)
return (PRNOMEM);
- alist->prlist_val = (afs_int32 *) tmp;
+ alist->prlist_val = tmp;
*sizeP = count;
}
alist->prlist_val[alist->prlist_len++] = id;
}
nptr = tentry->next;
- while (nptr != (afs_uint32) NULL) {
+ while (nptr != 0) {
/* look through cont entries */
code = pr_ReadCoEntry(at, 0, nptr, ¢ry);
if (code != 0)
if (!code) {
nptr = tentry2->next;
- while (nptr != (afs_uint32) NULL) {
+ while (nptr != 0) {
/* look through cont entries */
code = pr_ReadCoEntry(at, 0, nptr, ¢ry);
if (code != 0)
afs_int32
GetListSG2(struct ubik_trans *at, afs_int32 gid, prlist *alist, afs_int32 *sizeP, afs_int32 depth)
{
- register afs_int32 code;
+ afs_int32 code;
struct prentry tentry;
struct prentryg *tentryg = (struct prentryg *)&tentry;
afs_int32 i;
didsomething ? "TRUE" : "FALSE");
if (predictflagged && didsomething != predictfound)
fprintf(stderr, "**** for gid=%d, didsomething=%d predictfound=%d\n",
- didsomething, predictfound);
+ gid, didsomething, predictfound);
#endif
if (didsomething)
sg_found = add_map(sg_found, -gid);
afs_int32
GetSGList(struct ubik_trans *at, struct prentry *tentry, prlist *alist)
{
- register afs_int32 code;
+ afs_int32 code;
afs_int32 i;
struct contentry centry;
struct prentryg *tentryg;
return PRSUCCESS;
}
-afs_int32
-read_DbHeader(struct ubik_trans *tt)
+static afs_int32
+UpdateCache(struct ubik_trans *tt, void *rock)
{
afs_int32 code;
- if (!ubik_CacheUpdate(tt))
- return 0;
-
code = pr_Read(tt, 0, 0, (char *)&cheader, sizeof(cheader));
if (code != 0) {
afs_com_err(whoami, code, "Couldn't read header");
return code;
}
+afs_int32
+read_DbHeader(struct ubik_trans *tt)
+{
+ return ubik_CheckCache(tt, UpdateCache, NULL);
+}
+
int pr_noAuth;
-afs_int32 initd = 0;
-afs_int32
-Initdb()
+/**
+ * reads in db cache from ubik.
+ *
+ * @param[in] ut ubik transaction
+ * @param[out] rock opaque pointer to an int*, which on success will be set
+ * to 1 if we need to build the database, or 0 if we do not
+ *
+ * @return operation status
+ * @retval 0 success
+ */
+static afs_int32
+Initdb_check(struct ubik_trans *tt, void *rock)
{
+ int *build_rock = rock;
afs_int32 code;
- struct ubik_trans *tt;
afs_int32 len;
+ len = sizeof(cheader);
+ code = pr_Read(tt, 0, 0, (char *)&cheader, len);
+ if (code != 0) {
+ afs_com_err(whoami, code, "couldn't read header");
+ return code;
+ }
+ if ((ntohl(cheader.version) == PRDBVERSION)
+ && ntohl(cheader.headerSize) == sizeof(cheader)
+ && ntohl(cheader.eofPtr) != 0
+ && FindByID(tt, ANONYMOUSID) != 0) {
+ /* database exists, so we don't have to build it */
+ *build_rock = 0;
+ return 0;
+ }
+
+ /* else we need to build a database */
+ *build_rock = 1;
+ return 0;
+}
+
+afs_int32
+Initdb(void)
+{
+ struct ubik_trans *tt;
+ int build = 0;
+ afs_int32 code;
+
/* init the database. We'll try reading it, but if we're starting
* from scratch, we'll have to do a write transaction. */
ubik_AbortTrans(tt);
return code;
}
- if (!initd) {
- initd = 1;
- } else if (!ubik_CacheUpdate(tt)) {
- code = ubik_EndTrans(tt);
- return code;
- }
- len = sizeof(cheader);
- code = pr_Read(tt, 0, 0, (char *)&cheader, len);
- if (code != 0) {
- afs_com_err(whoami, code, "couldn't read header");
+ code = ubik_CheckCache(tt, Initdb_check, &build);
+ if (code) {
ubik_AbortTrans(tt);
return code;
}
- if ((ntohl(cheader.version) == PRDBVERSION)
- && ntohl(cheader.headerSize) == sizeof(cheader)
- && ntohl(cheader.eofPtr) != (afs_uint32) NULL
- && FindByID(tt, ANONYMOUSID) != 0) {
- /* database exists, so we don't have to build it */
- code = ubik_EndTrans(tt);
- if (code)
- return code;
- return PRSUCCESS;
- }
- /* else we need to build a database */
- code = ubik_EndTrans(tt);
- if (code)
- return code;
- /* Only rebuild database if the db was deleted (the header is zero) and we
- * are running noAuth. */
- {
+ if (build) {
+ /* Only rebuild database if the db was deleted (the header is zero) */
char *bp = (char *)&cheader;
int i;
- for (i = 0; i < sizeof(cheader); i++)
+ for (i = 0; i < sizeof(cheader); i++) {
if (bp[i]) {
code = PRDBBAD;
afs_com_err(whoami, code,
"Can't rebuild database because it is not empty");
- return code;
+ break;
}
+ }
+ }
+
+ if (code) {
+ ubik_EndTrans(tt);
+ } else {
+ code = ubik_EndTrans(tt);
}
- if (!pr_noAuth) {
- code = PRDBBAD;
- afs_com_err(whoami, code,
- "Can't rebuild database because not running NoAuth");
+ if (code || !build) {
+ /* either we encountered an error, or we don't need to build the db */
return code;
}
* actually have been a good database out there. Now that we have a
* real write transaction, make sure things are still bad.
*/
+ code = pr_Read(tt, 0, 0, (char *)&cheader, sizeof(cheader));
+ if (code != 0) {
+ afs_com_err(whoami, code, "couldn't read header");
+ ubik_AbortTrans(tt);
+ return code;
+ }
if ((ntohl(cheader.version) == PRDBVERSION)
&& ntohl(cheader.headerSize) == sizeof(cheader)
- && ntohl(cheader.eofPtr) != (afs_uint32) NULL
+ && ntohl(cheader.eofPtr) != 0
&& FindByID(tt, ANONYMOUSID) != 0) {
/* database exists, so we don't have to build it */
code = ubik_EndTrans(tt);
ChangeEntry(struct ubik_trans *at, afs_int32 aid, afs_int32 cid, char *name, afs_int32 oid, afs_int32 newid)
{
afs_int32 code;
- afs_int32 i, nptr, pos;
+ afs_int32 i, pos;
#if defined(SUPERGROUPS)
afs_int32 nextpos;
-#endif
+#else
+ afs_int32 nptr;
struct contentry centry;
+#endif
struct prentry tentry, tent;
afs_int32 loc;
afs_int32 oldowner;
+ afs_int32 admin;
char holder[PR_MAXNAMELEN];
char temp[PR_MAXNAMELEN];
char oldname[PR_MAXNAMELEN];
code = pr_ReadEntry(at, 0, loc, &tentry);
if (code)
return PRDBFAIL;
- if (restricted && !IsAMemberOf(at, cid, SYSADMINID))
+ if (restricted && !IsAMemberOf(at, cid, SYSADMINID))
return PRPERM;
if (tentry.owner != cid && !IsAMemberOf(at, cid, SYSADMINID)
&& !IsAMemberOf(at, cid, tentry.owner) && !pr_noAuth)
return PRPERM;
-#ifdef PR_REMEMBER_TIMES
tentry.changeTime = time(0);
-#endif
+ admin = pr_noAuth || IsAMemberOf(at, cid, SYSADMINID);
/* we're actually trying to change the id */
if (newid && (newid != aid)) {
- if (!IsAMemberOf(at, cid, SYSADMINID) && !pr_noAuth)
+ if (!admin)
return PRPERM;
pos = FindByID(at, newid);
return code;
}
/* Look through cont entries too. This needs to be broken into
- * seperate transaction so that no one transaction becomes too
+ * seperate transaction so that no one transaction becomes too
* large to complete.
*/
for (nptr = tentry.next; nptr; nptr = centry.next) {
tentry.owner = oid;
/* The entry must be written through first so Remove and Add routines
* can operate on disk data */
- code = pr_WriteEntry(at, 0, loc, (char *)&tentry);
+ code = pr_WriteEntry(at, 0, loc, &tentry);
if (code)
return PRDBFAIL;
/* don't let foreign cell groups change name */
if (atsign != NULL)
return PRPERM;
- code = CorrectGroupName(at, name, cid, tentry.owner, tentry.name);
+
+ if (tentry.owner == 0 || tentry.owner == ANONYMOUSID)
+ tentry.owner = cid;
+
+ code = CorrectGroupName(at, name, cid, tentry.owner, admin, tentry.name);
if (code)
return code;
if (code != PRSUCCESS)
return code;
strncpy(tentry.name, name, PR_MAXNAMELEN);
- code = pr_WriteEntry(at, 0, loc, (char *)&tentry);
+ code = pr_WriteEntry(at, 0, loc, &tentry);
if (code)
return PRDBFAIL;
code = AddToNameHash(at, tentry.name, loc);
}
-afs_int32
+static afs_int32
allocNextId(struct ubik_trans * at, struct prentry * cellEntry)
{
/* Id's for foreign cell entries are constructed as follows:
}
cellEntry->nusers = htonl(id);
- /* use the field nusers to keep
+ /* use the field nusers to keep
* the next available id in that
* foreign cell's group. Note :
* It would seem more appropriate
* to use ngroup for that and nusers
* to enforce the quota, however pts
- * does not have an option to change
+ * does not have an option to change
* foreign users quota yet */
id = (id << 16) | cellid;
return id;
}
-int
+static int
inRange(struct prentry *cellEntry, afs_int32 aid)
{
afs_uint32 id, cellid, groupid;
/*
* The only thing that we want to make sure here is that
* the id is in the legal range of this group. If it is
- * a duplicate we don't care since it will get caught
+ * a duplicate we don't care since it will get caught
* in a different check.
*/
if (cellid != groupid)
return 0; /* not in range */
- /*
+ /*
* if we got here we're ok but we need to update the nusers
- * field in order to get the id correct the next time that
+ * field in order to get the id correct the next time that
* we try to allocate it automatically
*/
}
-int
+static int
AddAuthGroup(struct prentry *tentry, prlist *alist, afs_int32 *size)
{
if (!(strchr(tentry->name, '@')))