OSDN Git Service

Flat file cleanup phase 2: make it work for pg_group. The flat group
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 20 Feb 2005 04:45:59 +0000 (04:45 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 20 Feb 2005 04:45:59 +0000 (04:45 +0000)
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.

src/backend/libpq/crypt.c
src/backend/libpq/hba.c
src/backend/utils/init/flatfiles.c

index fcc7db2..58e8033 100644 (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;
index f96eaec..9a65ee1 100644 (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)
-       {
-               ListCell   *line_item;
+       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 */
-               for_each_cell(line_item, lnext(list_head(*line)))
-               {
-                       if (strcmp(lfirst(line_item), user) == 0)
-                               return true;
-               }
+       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)))
+       {
+               if (strcmp((char *) lfirst(line_item), usesysid) == 0)
+                       return true;
        }
 
        return false;
index c54bade..0cbb878 100644 (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)))
-                       continue;
-
-               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)))
+                               passwd = pstrdup("");
+                       else
+                               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;