Flat file cleanup phase 2: make it work for pg_group. The flat group

file now identifies group members by usesysid not name; this avoids
needing to depend on SearchSysCache which we can't use during startup.
(The old representation was entirely broken anyway, since we did not
regenerate the file following RENAME USER.)  It's only a 95% solution
because if the group membership list is big enough to be toasted out
of line, we cannot read it during startup.  I think this will do for
the moment, until we have time to implement the planned pg_role
replacement for pg_group.
This commit is contained in:
Tom Lane 2005-02-20 04:45:59 +00:00
parent 60b2444cc3
commit 3f9aec50e7
3 changed files with 104 additions and 110 deletions

View File

@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/backend/libpq/crypt.c,v 1.61 2004/12/31 21:59:50 pgsql Exp $
* $PostgreSQL: pgsql/src/backend/libpq/crypt.c,v 1.62 2005/02/20 04:45:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -42,14 +42,18 @@ md5_crypt_verify(const Port *port, const char *user, char *client_pass)
if ((line = get_user_line(user)) == NULL)
return STATUS_ERROR;
/* Skip over username */
token = lnext(list_head(*line));
/* Skip over username and usesysid */
token = list_head(*line);
if (token)
token = lnext(token);
if (token)
token = lnext(token);
if (token)
{
shadow_pass = lfirst(token);
shadow_pass = (char *) lfirst(token);
token = lnext(token);
if (token)
valuntil = lfirst(token);
valuntil = (char *) lfirst(token);
}
if (shadow_pass == NULL || *shadow_pass == '\0')
@ -142,16 +146,14 @@ md5_crypt_verify(const Port *port, const char *user, char *client_pass)
/*
* Password OK, now check to be sure we are not past valuntil
*/
AbsoluteTime vuntil,
current;
AbsoluteTime vuntil;
if (!valuntil)
if (valuntil == NULL || *valuntil == '\0')
vuntil = INVALID_ABSTIME;
else
vuntil = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
CStringGetDatum(valuntil)));
current = GetCurrentAbsoluteTime();
if (vuntil != INVALID_ABSTIME && vuntil < current)
if (vuntil != INVALID_ABSTIME && vuntil < GetCurrentAbsoluteTime())
retval = STATUS_ERROR;
else
retval = STATUS_OK;

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.138 2005/02/20 02:21:40 tgl Exp $
* $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.139 2005/02/20 04:45:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -498,23 +498,28 @@ get_user_line(const char *user)
/*
* Check group for a specific user.
* Does user belong to group?
*/
static bool
check_group(char *group, char *user)
{
List **line;
ListCell *line_item;
char *usesysid;
if ((line = get_group_line(group)) != NULL)
if ((line = get_user_line(user)) == NULL)
return false; /* if user not exist, say "no" */
/* Skip over username to get usesysid */
usesysid = (char *) lsecond(*line);
if ((line = get_group_line(group)) == NULL)
return false; /* if group not exist, say "no" */
/* skip over the group name, examine all the member usesysid's */
for_each_cell(line_item, lnext(list_head(*line)))
{
ListCell *line_item;
/* skip over the group name */
for_each_cell(line_item, lnext(list_head(*line)))
{
if (strcmp(lfirst(line_item), user) == 0)
return true;
}
if (strcmp((char *) lfirst(line_item), usesysid) == 0)
return true;
}
return false;

View File

@ -22,7 +22,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.1 2005/02/20 02:22:00 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.2 2005/02/20 04:45:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -278,7 +278,7 @@ write_database_file(Relation drel)
}
/*
* File format is: "dbname" oid frozenxid
* The file format is: "dbname" oid frozenxid
*
* The xid is not needed for backend startup, but may be of use
* for forensic purposes.
@ -317,13 +317,6 @@ write_database_file(Relation drel)
/*
* write_group_file: update the flat group file
*
* XXX this will never be able to work during system bootstrap: we don't
* have either TOAST support or SysCache support. Need to redefine both
* the catalog and file contents to fix this completely. In the short term
* we can handle everything except an out-of-line-toasted grolist, if we
* change the flat file definition to store numeric sysids instead of
* user names.
*/
static void
write_group_file(Relation grel)
@ -335,7 +328,6 @@ write_group_file(Relation grel)
mode_t oumask;
HeapScanDesc scan;
HeapTuple tuple;
TupleDesc dsc = RelationGetDescr(grel);
/*
* Create a temporary filename to be renamed later. This prevents the
@ -364,22 +356,19 @@ write_group_file(Relation grel)
scan = heap_beginscan(grel, SnapshotSelf, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
Datum datum,
grolist_datum;
bool isnull;
Form_pg_group grpform = (Form_pg_group) GETSTRUCT(tuple);
HeapTupleHeader tup = tuple->t_data;
char *tp; /* ptr to tuple data */
long off; /* offset in tuple data */
bits8 *bp = tup->t_bits; /* ptr to null bitmask in tuple */
Datum datum;
char *groname;
IdList *grolist_p;
AclId *aidp;
int i,
num;
char *usename;
bool first_user = true;
datum = heap_getattr(tuple, Anum_pg_group_groname, dsc, &isnull);
/* ignore NULL groupnames --- shouldn't happen */
if (isnull)
continue;
groname = NameStr(*DatumGetName(datum));
groname = NameStr(grpform->groname);
/*
* Check for illegal characters in the group name.
@ -391,57 +380,58 @@ write_group_file(Relation grel)
continue;
}
grolist_datum = heap_getattr(tuple, Anum_pg_group_grolist, dsc, &isnull);
/* Ignore NULL group lists */
if (isnull)
/*
* We can't use heap_getattr() here because during startup we will
* not have any tupdesc for pg_group. Fortunately it's not too
* hard to work around this. grolist is the first possibly-null
* field so we can compute its offset directly.
*/
tp = (char *) tup + tup->t_hoff;
off = offsetof(FormData_pg_group, grolist);
if (HeapTupleHasNulls(tuple) &&
att_isnull(Anum_pg_group_grolist - 1, bp))
{
/* grolist is null, so we can ignore this group */
continue;
}
/* assume grolist is pass-by-ref */
datum = PointerGetDatum(tp + off);
/*
* We can't currently support out-of-line toasted group lists in
* startup mode (the tuptoaster won't work). This sucks, but it
* should be something of a corner case. Live with it until we
* can redesign pg_group.
*
* Detect startup mode by noting whether we got a tupdesc.
*/
if (VARATT_IS_EXTERNAL(DatumGetPointer(datum)) &&
RelationGetDescr(grel) == NULL)
continue;
/* be sure the IdList is not toasted */
grolist_p = DatumGetIdListP(grolist_datum);
grolist_p = DatumGetIdListP(datum);
/* scan grolist */
num = IDLIST_NUM(grolist_p);
/*
* The file format is: "groupname" usesysid1 usesysid2 ...
*
* We ignore groups that have no members.
*/
aidp = IDLIST_DAT(grolist_p);
for (i = 0; i < num; ++i)
num = IDLIST_NUM(grolist_p);
if (num > 0)
{
tuple = SearchSysCache(SHADOWSYSID,
PointerGetDatum(aidp[i]),
0, 0, 0);
if (HeapTupleIsValid(tuple))
{
usename = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename);
/*
* Check for illegal characters in the user name.
*/
if (!name_okay(usename))
{
ereport(LOG,
(errmsg("invalid user name \"%s\"", usename)));
continue;
}
/*
* File format is: "groupname" "user1" "user2" "user3"
*/
if (first_user)
{
fputs_quote(groname, fp);
fputs("\t", fp);
first_user = false;
}
else
fputs(" ", fp);
fputs_quote(usename, fp);
ReleaseSysCache(tuple);
}
}
if (!first_user)
fputs_quote(groname, fp);
fprintf(fp, "\t%u", aidp[0]);
for (i = 1; i < num; ++i)
fprintf(fp, " %u", aidp[i]);
fputs("\n", fp);
}
/* if IdList was toasted, free detoasted copy */
if ((Pointer) grolist_p != DatumGetPointer(grolist_datum))
if ((Pointer) grolist_p != DatumGetPointer(datum))
pfree(grolist_p);
}
heap_endscan(scan);
@ -517,8 +507,10 @@ write_user_file(Relation urel)
char *usename,
*passwd,
*valuntil;
AclId usesysid;
usename = NameStr(pwform->usename);
usesysid = pwform->usesysid;
/*
* We can't use heap_getattr() here because during startup we will
@ -532,30 +524,26 @@ write_user_file(Relation urel)
if (HeapTupleHasNulls(tuple) &&
att_isnull(Anum_pg_shadow_passwd - 1, bp))
{
/*
* It can be argued that people having a null password shouldn't
* be allowed to connect under password authentication, because
* they need to have a password set up first. If you think
* assuming an empty password in that case is better, change this
* logic to look something like the code for valuntil.
*/
continue;
/* passwd is null, emit as an empty string */
passwd = pstrdup("");
}
else
{
/* assume passwd is pass-by-ref */
datum = PointerGetDatum(tp + off);
/* assume passwd is pass-by-ref */
datum = PointerGetDatum(tp + off);
/*
* The password probably shouldn't ever be out-of-line toasted;
* if it is, ignore it, since we can't handle that in startup mode.
*/
if (VARATT_IS_EXTERNAL(DatumGetPointer(datum)))
passwd = pstrdup("");
else
passwd = DatumGetCString(DirectFunctionCall1(textout, datum));
/*
* The password probably shouldn't ever be out-of-line toasted;
* if it is, ignore it, since we can't handle that in startup mode.
*/
if (VARATT_IS_EXTERNAL(DatumGetPointer(datum)))
continue;
passwd = DatumGetCString(DirectFunctionCall1(textout, datum));
/* assume passwd has attlen -1 */
off = att_addlength(off, -1, tp + off);
/* assume passwd has attlen -1 */
off = att_addlength(off, -1, tp + off);
}
if (HeapTupleHasNulls(tuple) &&
att_isnull(Anum_pg_shadow_valuntil - 1, bp))
@ -588,8 +576,11 @@ write_user_file(Relation urel)
continue;
}
/*
* The file format is: "usename" usesysid "passwd" "valuntil"
*/
fputs_quote(usename, fp);
fputs(" ", fp);
fprintf(fp, " %u ", usesysid);
fputs_quote(passwd, fp);
fputs(" ", fp);
fputs_quote(valuntil, fp);
@ -664,9 +655,6 @@ BuildFlatFiles(bool database_only)
if (!database_only)
{
#ifdef NOT_YET
/* XXX doesn't work yet for reasons stated above */
/* hard-wired path to pg_group */
rnode.spcNode = GLOBALTABLESPACE_OID;
rnode.dbNode = 0;
@ -674,7 +662,6 @@ BuildFlatFiles(bool database_only)
rel = XLogOpenRelation(true, 0, rnode);
write_group_file(rel);
#endif
/* hard-wired path to pg_shadow */
rnode.spcNode = GLOBALTABLESPACE_OID;