Commit 3f9aec50 authored by Tom Lane's avatar Tom Lane

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.
parent 60b2444c
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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) ...@@ -42,14 +42,18 @@ md5_crypt_verify(const Port *port, const char *user, char *client_pass)
if ((line = get_user_line(user)) == NULL) if ((line = get_user_line(user)) == NULL)
return STATUS_ERROR; return STATUS_ERROR;
/* Skip over username */ /* Skip over username and usesysid */
token = lnext(list_head(*line)); token = list_head(*line);
if (token)
token = lnext(token);
if (token)
token = lnext(token);
if (token) if (token)
{ {
shadow_pass = lfirst(token); shadow_pass = (char *) lfirst(token);
token = lnext(token); token = lnext(token);
if (token) if (token)
valuntil = lfirst(token); valuntil = (char *) lfirst(token);
} }
if (shadow_pass == NULL || *shadow_pass == '\0') if (shadow_pass == NULL || *shadow_pass == '\0')
...@@ -142,16 +146,14 @@ md5_crypt_verify(const Port *port, const char *user, char *client_pass) ...@@ -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 * Password OK, now check to be sure we are not past valuntil
*/ */
AbsoluteTime vuntil, AbsoluteTime vuntil;
current;
if (!valuntil) if (valuntil == NULL || *valuntil == '\0')
vuntil = INVALID_ABSTIME; vuntil = INVALID_ABSTIME;
else else
vuntil = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein, vuntil = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein,
CStringGetDatum(valuntil))); CStringGetDatum(valuntil)));
current = GetCurrentAbsoluteTime(); if (vuntil != INVALID_ABSTIME && vuntil < GetCurrentAbsoluteTime())
if (vuntil != INVALID_ABSTIME && vuntil < current)
retval = STATUS_ERROR; retval = STATUS_ERROR;
else else
retval = STATUS_OK; retval = STATUS_OK;
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * 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,24 +498,29 @@ get_user_line(const char *user) ...@@ -498,24 +498,29 @@ get_user_line(const char *user)
/* /*
* Check group for a specific user. * Does user belong to group?
*/ */
static bool static bool
check_group(char *group, char *user) check_group(char *group, char *user)
{ {
List **line; List **line;
if ((line = get_group_line(group)) != NULL)
{
ListCell *line_item; ListCell *line_item;
char *usesysid;
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);
/* skip over the group name */ 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))) for_each_cell(line_item, lnext(list_head(*line)))
{ {
if (strcmp(lfirst(line_item), user) == 0) if (strcmp((char *) lfirst(line_item), usesysid) == 0)
return true; return true;
} }
}
return false; return false;
} }
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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) ...@@ -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 * The xid is not needed for backend startup, but may be of use
* for forensic purposes. * for forensic purposes.
...@@ -317,13 +317,6 @@ write_database_file(Relation drel) ...@@ -317,13 +317,6 @@ write_database_file(Relation drel)
/* /*
* write_group_file: update the flat group file * 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 static void
write_group_file(Relation grel) write_group_file(Relation grel)
...@@ -335,7 +328,6 @@ write_group_file(Relation grel) ...@@ -335,7 +328,6 @@ write_group_file(Relation grel)
mode_t oumask; mode_t oumask;
HeapScanDesc scan; HeapScanDesc scan;
HeapTuple tuple; HeapTuple tuple;
TupleDesc dsc = RelationGetDescr(grel);
/* /*
* Create a temporary filename to be renamed later. This prevents the * Create a temporary filename to be renamed later. This prevents the
...@@ -364,22 +356,19 @@ write_group_file(Relation grel) ...@@ -364,22 +356,19 @@ write_group_file(Relation grel)
scan = heap_beginscan(grel, SnapshotSelf, 0, NULL); scan = heap_beginscan(grel, SnapshotSelf, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{ {
Datum datum, Form_pg_group grpform = (Form_pg_group) GETSTRUCT(tuple);
grolist_datum; HeapTupleHeader tup = tuple->t_data;
bool isnull; 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; char *groname;
IdList *grolist_p; IdList *grolist_p;
AclId *aidp; AclId *aidp;
int i, int i,
num; num;
char *usename;
bool first_user = true;
datum = heap_getattr(tuple, Anum_pg_group_groname, dsc, &isnull); groname = NameStr(grpform->groname);
/* ignore NULL groupnames --- shouldn't happen */
if (isnull)
continue;
groname = NameStr(*DatumGetName(datum));
/* /*
* Check for illegal characters in the group name. * Check for illegal characters in the group name.
...@@ -391,57 +380,58 @@ write_group_file(Relation grel) ...@@ -391,57 +380,58 @@ write_group_file(Relation grel)
continue; continue;
} }
grolist_datum = heap_getattr(tuple, Anum_pg_group_grolist, dsc, &isnull); /*
/* Ignore NULL group lists */ * We can't use heap_getattr() here because during startup we will
if (isnull) * not have any tupdesc for pg_group. Fortunately it's not too
continue; * hard to work around this. grolist is the first possibly-null
* field so we can compute its offset directly.
/* be sure the IdList is not toasted */ */
grolist_p = DatumGetIdListP(grolist_datum); tp = (char *) tup + tup->t_hoff;
off = offsetof(FormData_pg_group, grolist);
/* scan grolist */ if (HeapTupleHasNulls(tuple) &&
num = IDLIST_NUM(grolist_p); att_isnull(Anum_pg_group_grolist - 1, bp))
aidp = IDLIST_DAT(grolist_p);
for (i = 0; i < num; ++i)
{
tuple = SearchSysCache(SHADOWSYSID,
PointerGetDatum(aidp[i]),
0, 0, 0);
if (HeapTupleIsValid(tuple))
{ {
usename = NameStr(((Form_pg_shadow) GETSTRUCT(tuple))->usename); /* grolist is null, so we can ignore this group */
continue;
}
/* assume grolist is pass-by-ref */
datum = PointerGetDatum(tp + off);
/* /*
* Check for illegal characters in the user name. * 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 (!name_okay(usename)) if (VARATT_IS_EXTERNAL(DatumGetPointer(datum)) &&
{ RelationGetDescr(grel) == NULL)
ereport(LOG,
(errmsg("invalid user name \"%s\"", usename)));
continue; continue;
}
/* be sure the IdList is not toasted */
grolist_p = DatumGetIdListP(datum);
/* /*
* File format is: "groupname" "user1" "user2" "user3" * The file format is: "groupname" usesysid1 usesysid2 ...
*
* We ignore groups that have no members.
*/ */
if (first_user) aidp = IDLIST_DAT(grolist_p);
num = IDLIST_NUM(grolist_p);
if (num > 0)
{ {
fputs_quote(groname, fp); fputs_quote(groname, fp);
fputs("\t", fp); fprintf(fp, "\t%u", aidp[0]);
first_user = false; for (i = 1; i < num; ++i)
fprintf(fp, " %u", aidp[i]);
fputs("\n", fp);
} }
else
fputs(" ", fp);
fputs_quote(usename, fp);
ReleaseSysCache(tuple);
}
}
if (!first_user)
fputs("\n", fp);
/* if IdList was toasted, free detoasted copy */ /* if IdList was toasted, free detoasted copy */
if ((Pointer) grolist_p != DatumGetPointer(grolist_datum)) if ((Pointer) grolist_p != DatumGetPointer(datum))
pfree(grolist_p); pfree(grolist_p);
} }
heap_endscan(scan); heap_endscan(scan);
...@@ -517,8 +507,10 @@ write_user_file(Relation urel) ...@@ -517,8 +507,10 @@ write_user_file(Relation urel)
char *usename, char *usename,
*passwd, *passwd,
*valuntil; *valuntil;
AclId usesysid;
usename = NameStr(pwform->usename); usename = NameStr(pwform->usename);
usesysid = pwform->usesysid;
/* /*
* We can't use heap_getattr() here because during startup we will * We can't use heap_getattr() here because during startup we will
...@@ -532,16 +524,11 @@ write_user_file(Relation urel) ...@@ -532,16 +524,11 @@ write_user_file(Relation urel)
if (HeapTupleHasNulls(tuple) && if (HeapTupleHasNulls(tuple) &&
att_isnull(Anum_pg_shadow_passwd - 1, bp)) att_isnull(Anum_pg_shadow_passwd - 1, bp))
{ {
/* /* passwd is null, emit as an empty string */
* It can be argued that people having a null password shouldn't passwd = pstrdup("");
* 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;
} }
else
{
/* assume passwd is pass-by-ref */ /* assume passwd is pass-by-ref */
datum = PointerGetDatum(tp + off); datum = PointerGetDatum(tp + off);
...@@ -550,12 +537,13 @@ write_user_file(Relation urel) ...@@ -550,12 +537,13 @@ write_user_file(Relation urel)
* if it is, ignore it, since we can't handle that in startup mode. * if it is, ignore it, since we can't handle that in startup mode.
*/ */
if (VARATT_IS_EXTERNAL(DatumGetPointer(datum))) if (VARATT_IS_EXTERNAL(DatumGetPointer(datum)))
continue; passwd = pstrdup("");
else
passwd = DatumGetCString(DirectFunctionCall1(textout, datum)); passwd = DatumGetCString(DirectFunctionCall1(textout, datum));
/* assume passwd has attlen -1 */ /* assume passwd has attlen -1 */
off = att_addlength(off, -1, tp + off); off = att_addlength(off, -1, tp + off);
}
if (HeapTupleHasNulls(tuple) && if (HeapTupleHasNulls(tuple) &&
att_isnull(Anum_pg_shadow_valuntil - 1, bp)) att_isnull(Anum_pg_shadow_valuntil - 1, bp))
...@@ -588,8 +576,11 @@ write_user_file(Relation urel) ...@@ -588,8 +576,11 @@ write_user_file(Relation urel)
continue; continue;
} }
/*
* The file format is: "usename" usesysid "passwd" "valuntil"
*/
fputs_quote(usename, fp); fputs_quote(usename, fp);
fputs(" ", fp); fprintf(fp, " %u ", usesysid);
fputs_quote(passwd, fp); fputs_quote(passwd, fp);
fputs(" ", fp); fputs(" ", fp);
fputs_quote(valuntil, fp); fputs_quote(valuntil, fp);
...@@ -664,9 +655,6 @@ BuildFlatFiles(bool database_only) ...@@ -664,9 +655,6 @@ BuildFlatFiles(bool database_only)
if (!database_only) if (!database_only)
{ {
#ifdef NOT_YET
/* XXX doesn't work yet for reasons stated above */
/* hard-wired path to pg_group */ /* hard-wired path to pg_group */
rnode.spcNode = GLOBALTABLESPACE_OID; rnode.spcNode = GLOBALTABLESPACE_OID;
rnode.dbNode = 0; rnode.dbNode = 0;
...@@ -674,7 +662,6 @@ BuildFlatFiles(bool database_only) ...@@ -674,7 +662,6 @@ BuildFlatFiles(bool database_only)
rel = XLogOpenRelation(true, 0, rnode); rel = XLogOpenRelation(true, 0, rnode);
write_group_file(rel); write_group_file(rel);
#endif
/* hard-wired path to pg_shadow */ /* hard-wired path to pg_shadow */
rnode.spcNode = GLOBALTABLESPACE_OID; rnode.spcNode = GLOBALTABLESPACE_OID;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment