diff options
Diffstat (limited to 'src/backend/commands/user.c')
-rw-r--r-- | src/backend/commands/user.c | 803 |
1 files changed, 432 insertions, 371 deletions
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 05506fd93fc..9ef2613a4f4 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -43,34 +43,39 @@ static void CheckPgUserAclNotNull(void); *--------------------------------------------------------------------- */ static -void UpdatePgPwdFile(char* sql) { - - char* filename; - char* tempname; - - /* Create a temporary filename to be renamed later. This prevents the - * backend from clobbering the pg_pwd file while the postmaster might be - * reading from it. - */ - filename = crypt_getpwdfilename(); - tempname = (char*)malloc(strlen(filename) + 12); - sprintf(tempname, "%s.%d", filename, MyProcPid); - - /* Copy the contents of pg_shadow to the pg_pwd ASCII file using a the SEPCHAR - * character as the delimiter between fields. Then rename the file to its - * final name. - */ - sprintf(sql, "copy %s to '%s' using delimiters %s", ShadowRelationName, tempname, CRYPT_PWD_FILE_SEPCHAR); - pg_exec_query(sql, (char**)NULL, (Oid*)NULL, 0); - rename(tempname, filename); - free((void*)tempname); - - /* Create a flag file the postmaster will detect the next time it tries to - * authenticate a user. The postmaster will know to reload the pg_pwd file - * contents. - */ - filename = crypt_getpwdreloadfilename(); - creat(filename, S_IRUSR | S_IWUSR); +void +UpdatePgPwdFile(char *sql) +{ + + char *filename; + char *tempname; + + /* + * Create a temporary filename to be renamed later. This prevents the + * backend from clobbering the pg_pwd file while the postmaster might + * be reading from it. + */ + filename = crypt_getpwdfilename(); + tempname = (char *) malloc(strlen(filename) + 12); + sprintf(tempname, "%s.%d", filename, MyProcPid); + + /* + * Copy the contents of pg_shadow to the pg_pwd ASCII file using a the + * SEPCHAR character as the delimiter between fields. Then rename the + * file to its final name. + */ + sprintf(sql, "copy %s to '%s' using delimiters %s", ShadowRelationName, tempname, CRYPT_PWD_FILE_SEPCHAR); + pg_exec_query(sql, (char **) NULL, (Oid *) NULL, 0); + rename(tempname, filename); + free((void *) tempname); + + /* + * Create a flag file the postmaster will detect the next time it + * tries to authenticate a user. The postmaster will know to reload + * the pg_pwd file contents. + */ + filename = crypt_getpwdreloadfilename(); + creat(filename, S_IRUSR | S_IWUSR); } /*--------------------------------------------------------------------- @@ -80,352 +85,407 @@ void UpdatePgPwdFile(char* sql) { * user is specified in the desired groups of defined in pg_group. *--------------------------------------------------------------------- */ -void DefineUser(CreateUserStmt *stmt) { - - char* pg_user; - Relation pg_shadow_rel; - TupleDesc pg_shadow_dsc; - HeapScanDesc scan; - HeapTuple tuple; - Datum datum; - Buffer buffer; - char sql[512]; - char* sql_end; - bool exists = false, - n, - inblock; - int max_id = -1; - - if (stmt->password) - CheckPgUserAclNotNull(); - if (!(inblock = IsTransactionBlock())) - BeginTransactionBlock(); - - /* Make sure the user attempting to create a user can insert into the pg_shadow - * relation. - */ - pg_user = GetPgUserName(); - if (pg_aclcheck(ShadowRelationName, pg_user, ACL_RD | ACL_WR | ACL_AP) != ACLCHECK_OK) { - UserAbortTransactionBlock(); - elog(ERROR, "defineUser: user \"%s\" does not have SELECT and INSERT privilege for \"%s\"", - pg_user, ShadowRelationName); - return; - } - - /* Scan the pg_shadow relation to be certain the user doesn't already exist. - */ - pg_shadow_rel = heap_openr(ShadowRelationName); - pg_shadow_dsc = RelationGetTupleDescriptor(pg_shadow_rel); - /* Secure a write lock on pg_shadow so we can be sure of what the next usesysid - * should be. - */ - RelationSetLockForWrite(pg_shadow_rel); - - scan = heap_beginscan(pg_shadow_rel, false, false, 0, NULL); - while (HeapTupleIsValid(tuple = heap_getnext(scan, 0, &buffer))) { - datum = heap_getattr(tuple, Anum_pg_shadow_usename, pg_shadow_dsc, &n); - - if (!exists && !strncmp((char*)datum, stmt->user, strlen(stmt->user))) - exists = true; - - datum = heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_shadow_dsc, &n); - if ((int)datum > max_id) - max_id = (int)datum; - - ReleaseBuffer(buffer); - } - heap_endscan(scan); - - if (exists) { - RelationUnsetLockForWrite(pg_shadow_rel); - heap_close(pg_shadow_rel); - UserAbortTransactionBlock(); - elog(ERROR, "defineUser: user \"%s\" has already been created", stmt->user); - return; - } - - /* Build the insert statment to be executed. - */ - sprintf(sql, "insert into %s(usename,usesysid,usecreatedb,usetrace,usesuper,usecatupd,passwd", ShadowRelationName); -/* if (stmt->password) - strcat(sql, ",passwd"); -- removed so that insert empty string when no password */ - if (stmt->validUntil) - strcat(sql, ",valuntil"); - - sql_end = sql + strlen(sql); - sprintf(sql_end, ") values('%s',%d", stmt->user, max_id + 1); - if (stmt->createdb && *stmt->createdb) - strcat(sql_end, ",'t','t'"); - else - strcat(sql_end, ",'f','t'"); - if (stmt->createuser && *stmt->createuser) - strcat(sql_end, ",'t','t'"); - else - strcat(sql_end, ",'f','t'"); - sql_end += strlen(sql_end); - if (stmt->password) { - sprintf(sql_end, ",'%s'", stmt->password); - sql_end += strlen(sql_end); - } else { - strcpy(sql_end, ",''"); - sql_end += strlen(sql_end); - } - if (stmt->validUntil) { - sprintf(sql_end, ",'%s'", stmt->validUntil); - sql_end += strlen(sql_end); - } - strcat(sql_end, ")"); - - pg_exec_query(sql, (char**)NULL, (Oid*)NULL, 0); - - /* Add the stuff here for groups. - */ - - UpdatePgPwdFile(sql); - - /* This goes after the UpdatePgPwdFile to be certain that two backends to not - * attempt to write to the pg_pwd file at the same time. - */ - RelationUnsetLockForWrite(pg_shadow_rel); - heap_close(pg_shadow_rel); - - if (IsTransactionBlock() && !inblock) - EndTransactionBlock(); +void +DefineUser(CreateUserStmt *stmt) +{ + + char *pg_user; + Relation pg_shadow_rel; + TupleDesc pg_shadow_dsc; + HeapScanDesc scan; + HeapTuple tuple; + Datum datum; + Buffer buffer; + char sql[512]; + char *sql_end; + bool exists = false, + n, + inblock; + int max_id = -1; + + if (stmt->password) + CheckPgUserAclNotNull(); + if (!(inblock = IsTransactionBlock())) + BeginTransactionBlock(); + + /* + * Make sure the user attempting to create a user can insert into the + * pg_shadow relation. + */ + pg_user = GetPgUserName(); + if (pg_aclcheck(ShadowRelationName, pg_user, ACL_RD | ACL_WR | ACL_AP) != ACLCHECK_OK) + { + UserAbortTransactionBlock(); + elog(ERROR, "defineUser: user \"%s\" does not have SELECT and INSERT privilege for \"%s\"", + pg_user, ShadowRelationName); + return; + } + + /* + * Scan the pg_shadow relation to be certain the user doesn't already + * exist. + */ + pg_shadow_rel = heap_openr(ShadowRelationName); + pg_shadow_dsc = RelationGetTupleDescriptor(pg_shadow_rel); + + /* + * Secure a write lock on pg_shadow so we can be sure of what the next + * usesysid should be. + */ + RelationSetLockForWrite(pg_shadow_rel); + + scan = heap_beginscan(pg_shadow_rel, false, false, 0, NULL); + while (HeapTupleIsValid(tuple = heap_getnext(scan, 0, &buffer))) + { + datum = heap_getattr(tuple, Anum_pg_shadow_usename, pg_shadow_dsc, &n); + + if (!exists && !strncmp((char *) datum, stmt->user, strlen(stmt->user))) + exists = true; + + datum = heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_shadow_dsc, &n); + if ((int) datum > max_id) + max_id = (int) datum; + + ReleaseBuffer(buffer); + } + heap_endscan(scan); + + if (exists) + { + RelationUnsetLockForWrite(pg_shadow_rel); + heap_close(pg_shadow_rel); + UserAbortTransactionBlock(); + elog(ERROR, "defineUser: user \"%s\" has already been created", stmt->user); + return; + } + + /* + * Build the insert statment to be executed. + */ + sprintf(sql, "insert into %s(usename,usesysid,usecreatedb,usetrace,usesuper,usecatupd,passwd", ShadowRelationName); +/* if (stmt->password) + strcat(sql, ",passwd"); -- removed so that insert empty string when no password */ + if (stmt->validUntil) + strcat(sql, ",valuntil"); + + sql_end = sql + strlen(sql); + sprintf(sql_end, ") values('%s',%d", stmt->user, max_id + 1); + if (stmt->createdb && *stmt->createdb) + strcat(sql_end, ",'t','t'"); + else + strcat(sql_end, ",'f','t'"); + if (stmt->createuser && *stmt->createuser) + strcat(sql_end, ",'t','t'"); + else + strcat(sql_end, ",'f','t'"); + sql_end += strlen(sql_end); + if (stmt->password) + { + sprintf(sql_end, ",'%s'", stmt->password); + sql_end += strlen(sql_end); + } + else + { + strcpy(sql_end, ",''"); + sql_end += strlen(sql_end); + } + if (stmt->validUntil) + { + sprintf(sql_end, ",'%s'", stmt->validUntil); + sql_end += strlen(sql_end); + } + strcat(sql_end, ")"); + + pg_exec_query(sql, (char **) NULL, (Oid *) NULL, 0); + + /* + * Add the stuff here for groups. + */ + + UpdatePgPwdFile(sql); + + /* + * This goes after the UpdatePgPwdFile to be certain that two backends + * to not attempt to write to the pg_pwd file at the same time. + */ + RelationUnsetLockForWrite(pg_shadow_rel); + heap_close(pg_shadow_rel); + + if (IsTransactionBlock() && !inblock) + EndTransactionBlock(); } -extern void AlterUser(AlterUserStmt *stmt) { - - char* pg_user; - Relation pg_shadow_rel; - TupleDesc pg_shadow_dsc; - HeapScanDesc scan; - HeapTuple tuple; - Datum datum; - Buffer buffer; - char sql[512]; - char* sql_end; - bool exists = false, - n, - inblock; - - if (stmt->password) - CheckPgUserAclNotNull(); - if (!(inblock = IsTransactionBlock())) - BeginTransactionBlock(); - - /* Make sure the user attempting to create a user can insert into the pg_shadow - * relation. - */ - pg_user = GetPgUserName(); - if (pg_aclcheck(ShadowRelationName, pg_user, ACL_RD | ACL_WR) != ACLCHECK_OK) { - UserAbortTransactionBlock(); - elog(ERROR, "alterUser: user \"%s\" does not have SELECT and UPDATE privilege for \"%s\"", - pg_user, ShadowRelationName); - return; - } - - /* Scan the pg_shadow relation to be certain the user exists. - */ - pg_shadow_rel = heap_openr(ShadowRelationName); - pg_shadow_dsc = RelationGetTupleDescriptor(pg_shadow_rel); - /* Secure a write lock on pg_shadow so we can be sure that when the dump of - * the pg_pwd file is done, there is not another backend doing the same. - */ - RelationSetLockForWrite(pg_shadow_rel); - - scan = heap_beginscan(pg_shadow_rel, false, false, 0, NULL); - while (HeapTupleIsValid(tuple = heap_getnext(scan, 0, &buffer))) { - datum = heap_getattr(tuple, Anum_pg_shadow_usename, pg_shadow_dsc, &n); - - if (!strncmp((char*)datum, stmt->user, strlen(stmt->user))) { - exists = true; - ReleaseBuffer(buffer); - break; - } - } - heap_endscan(scan); - - if (!exists) { - RelationUnsetLockForWrite(pg_shadow_rel); - heap_close(pg_shadow_rel); - UserAbortTransactionBlock(); - elog(ERROR, "alterUser: user \"%s\" does not exist", stmt->user); - return; - } - - /* Create the update statement to modify the user. - */ - sprintf(sql, "update %s set", ShadowRelationName); - sql_end = sql; - if (stmt->password) { - sql_end += strlen(sql_end); - sprintf(sql_end, " passwd = '%s'", stmt->password); - } - if (stmt->createdb) { - if (sql_end != sql) - strcat(sql_end, ","); - sql_end += strlen(sql_end); - if (*stmt->createdb) - strcat(sql_end, " usecreatedb = 't'"); - else - strcat(sql_end, " usecreatedb = 'f'"); - } - if (stmt->createuser) { - if (sql_end != sql) - strcat(sql_end, ","); - sql_end += strlen(sql_end); - if (*stmt->createuser) - strcat(sql_end, " usesuper = 't'"); - else - strcat(sql_end, " usesuper = 'f'"); - } - if (stmt->validUntil) { - if (sql_end != sql) - strcat(sql_end, ","); - sql_end += strlen(sql_end); - sprintf(sql_end, " valuntil = '%s'", stmt->validUntil); - } - if (sql_end != sql) { - sql_end += strlen(sql_end); - sprintf(sql_end, " where usename = '%s'", stmt->user); - pg_exec_query(sql, (char**)NULL, (Oid*)NULL, 0); - } - - /* do the pg_group stuff here */ - - UpdatePgPwdFile(sql); - - RelationUnsetLockForWrite(pg_shadow_rel); - heap_close(pg_shadow_rel); - - if (IsTransactionBlock() && !inblock) - EndTransactionBlock(); +extern void +AlterUser(AlterUserStmt *stmt) +{ + + char *pg_user; + Relation pg_shadow_rel; + TupleDesc pg_shadow_dsc; + HeapScanDesc scan; + HeapTuple tuple; + Datum datum; + Buffer buffer; + char sql[512]; + char *sql_end; + bool exists = false, + n, + inblock; + + if (stmt->password) + CheckPgUserAclNotNull(); + if (!(inblock = IsTransactionBlock())) + BeginTransactionBlock(); + + /* + * Make sure the user attempting to create a user can insert into the + * pg_shadow relation. + */ + pg_user = GetPgUserName(); + if (pg_aclcheck(ShadowRelationName, pg_user, ACL_RD | ACL_WR) != ACLCHECK_OK) + { + UserAbortTransactionBlock(); + elog(ERROR, "alterUser: user \"%s\" does not have SELECT and UPDATE privilege for \"%s\"", + pg_user, ShadowRelationName); + return; + } + + /* + * Scan the pg_shadow relation to be certain the user exists. + */ + pg_shadow_rel = heap_openr(ShadowRelationName); + pg_shadow_dsc = RelationGetTupleDescriptor(pg_shadow_rel); + + /* + * Secure a write lock on pg_shadow so we can be sure that when the + * dump of the pg_pwd file is done, there is not another backend doing + * the same. + */ + RelationSetLockForWrite(pg_shadow_rel); + + scan = heap_beginscan(pg_shadow_rel, false, false, 0, NULL); + while (HeapTupleIsValid(tuple = heap_getnext(scan, 0, &buffer))) + { + datum = heap_getattr(tuple, Anum_pg_shadow_usename, pg_shadow_dsc, &n); + + if (!strncmp((char *) datum, stmt->user, strlen(stmt->user))) + { + exists = true; + ReleaseBuffer(buffer); + break; + } + } + heap_endscan(scan); + + if (!exists) + { + RelationUnsetLockForWrite(pg_shadow_rel); + heap_close(pg_shadow_rel); + UserAbortTransactionBlock(); + elog(ERROR, "alterUser: user \"%s\" does not exist", stmt->user); + return; + } + + /* + * Create the update statement to modify the user. + */ + sprintf(sql, "update %s set", ShadowRelationName); + sql_end = sql; + if (stmt->password) + { + sql_end += strlen(sql_end); + sprintf(sql_end, " passwd = '%s'", stmt->password); + } + if (stmt->createdb) + { + if (sql_end != sql) + strcat(sql_end, ","); + sql_end += strlen(sql_end); + if (*stmt->createdb) + strcat(sql_end, " usecreatedb = 't'"); + else + strcat(sql_end, " usecreatedb = 'f'"); + } + if (stmt->createuser) + { + if (sql_end != sql) + strcat(sql_end, ","); + sql_end += strlen(sql_end); + if (*stmt->createuser) + strcat(sql_end, " usesuper = 't'"); + else + strcat(sql_end, " usesuper = 'f'"); + } + if (stmt->validUntil) + { + if (sql_end != sql) + strcat(sql_end, ","); + sql_end += strlen(sql_end); + sprintf(sql_end, " valuntil = '%s'", stmt->validUntil); + } + if (sql_end != sql) + { + sql_end += strlen(sql_end); + sprintf(sql_end, " where usename = '%s'", stmt->user); + pg_exec_query(sql, (char **) NULL, (Oid *) NULL, 0); + } + + /* do the pg_group stuff here */ + + UpdatePgPwdFile(sql); + + RelationUnsetLockForWrite(pg_shadow_rel); + heap_close(pg_shadow_rel); + + if (IsTransactionBlock() && !inblock) + EndTransactionBlock(); } -extern void RemoveUser(char* user) { - - char* pg_user; - Relation pg_shadow_rel, - pg_rel; - TupleDesc pg_dsc; - HeapScanDesc scan; - HeapTuple tuple; - Datum datum; - Buffer buffer; - char sql[512]; - bool n, - inblock; - int usesysid = -1, - ndbase = 0; - char** dbase = NULL; - - if (!(inblock = IsTransactionBlock())) - BeginTransactionBlock(); - - /* Make sure the user attempting to create a user can delete from the pg_shadow - * relation. - */ - pg_user = GetPgUserName(); - if (pg_aclcheck(ShadowRelationName, pg_user, ACL_RD | ACL_WR) != ACLCHECK_OK) { - UserAbortTransactionBlock(); - elog(ERROR, "removeUser: user \"%s\" does not have SELECT and DELETE privilege for \"%s\"", - pg_user, ShadowRelationName); - return; - } - - /* Perform a scan of the pg_shadow relation to find the usesysid of the user to - * be deleted. If it is not found, then return a warning message. - */ - pg_shadow_rel = heap_openr(ShadowRelationName); - pg_dsc = RelationGetTupleDescriptor(pg_shadow_rel); - /* Secure a write lock on pg_shadow so we can be sure that when the dump of - * the pg_pwd file is done, there is not another backend doing the same. - */ - RelationSetLockForWrite(pg_shadow_rel); - - scan = heap_beginscan(pg_shadow_rel, false, false, 0, NULL); - while (HeapTupleIsValid(tuple = heap_getnext(scan, 0, &buffer))) { - datum = heap_getattr(tuple, Anum_pg_shadow_usename, pg_dsc, &n); - - if (!strncmp((char*)datum, user, strlen(user))) { - usesysid = (int)heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_dsc, &n); - ReleaseBuffer(buffer); - break; - } - ReleaseBuffer(buffer); - } - heap_endscan(scan); - - if (usesysid == -1) { - RelationUnsetLockForWrite(pg_shadow_rel); - heap_close(pg_shadow_rel); - UserAbortTransactionBlock(); - elog(ERROR, "removeUser: user \"%s\" does not exist", user); - return; - } - - /* Perform a scan of the pg_database relation to find the databases owned by - * usesysid. Then drop them. - */ - pg_rel = heap_openr(DatabaseRelationName); - pg_dsc = RelationGetTupleDescriptor(pg_rel); - - scan = heap_beginscan(pg_rel, false, false, 0, NULL); - while (HeapTupleIsValid(tuple = heap_getnext(scan, 0, &buffer))) { - datum = heap_getattr(tuple, Anum_pg_database_datdba, pg_dsc, &n); - - if ((int)datum == usesysid) { - datum = heap_getattr(tuple, Anum_pg_database_datname, pg_dsc, &n); - if (memcmp((void*)datum, "template1", 9)) { - dbase = (char**)realloc((void*)dbase, sizeof(char*) * (ndbase + 1)); - dbase[ndbase] = (char*)malloc(NAMEDATALEN + 1); - memcpy((void*)dbase[ndbase], (void*)datum, NAMEDATALEN); - dbase[ndbase++][NAMEDATALEN] = '\0'; - } - } - ReleaseBuffer(buffer); - } - heap_endscan(scan); - heap_close(pg_rel); - - while (ndbase--) { - elog(NOTICE, "Dropping database %s", dbase[ndbase]); - sprintf(sql, "drop database %s", dbase[ndbase]); - free((void*)dbase[ndbase]); - pg_exec_query(sql, (char**)NULL, (Oid*)NULL, 0); - } - if (dbase) - free((void*)dbase); - - /* Since pg_shadow is global over all databases, one of two things must be done - * to insure complete consistency. First, pg_shadow could be made non-global. - * This would elminate the code above for deleting database and would require - * the addition of code to delete tables, views, etc owned by the user. - * - * The second option would be to create a means of deleting tables, view, - * etc. owned by the user from other databases. Pg_user is global and so - * this must be done at some point. - * - * Let us not forget that the user should be removed from the pg_groups also. - * - * Todd A. Brandys 11/18/1997 - * - */ - - /* Remove the user from the pg_shadow table - */ - sprintf(sql, "delete from %s where usename = '%s'", ShadowRelationName, user); - pg_exec_query(sql, (char**)NULL, (Oid*)NULL, 0); - - UpdatePgPwdFile(sql); - - RelationUnsetLockForWrite(pg_shadow_rel); - heap_close(pg_shadow_rel); - - if (IsTransactionBlock() && !inblock) - EndTransactionBlock(); +extern void +RemoveUser(char *user) +{ + + char *pg_user; + Relation pg_shadow_rel, + pg_rel; + TupleDesc pg_dsc; + HeapScanDesc scan; + HeapTuple tuple; + Datum datum; + Buffer buffer; + char sql[512]; + bool n, + inblock; + int usesysid = -1, + ndbase = 0; + char **dbase = NULL; + + if (!(inblock = IsTransactionBlock())) + BeginTransactionBlock(); + + /* + * Make sure the user attempting to create a user can delete from the + * pg_shadow relation. + */ + pg_user = GetPgUserName(); + if (pg_aclcheck(ShadowRelationName, pg_user, ACL_RD | ACL_WR) != ACLCHECK_OK) + { + UserAbortTransactionBlock(); + elog(ERROR, "removeUser: user \"%s\" does not have SELECT and DELETE privilege for \"%s\"", + pg_user, ShadowRelationName); + return; + } + + /* + * Perform a scan of the pg_shadow relation to find the usesysid of + * the user to be deleted. If it is not found, then return a warning + * message. + */ + pg_shadow_rel = heap_openr(ShadowRelationName); + pg_dsc = RelationGetTupleDescriptor(pg_shadow_rel); + + /* + * Secure a write lock on pg_shadow so we can be sure that when the + * dump of the pg_pwd file is done, there is not another backend doing + * the same. + */ + RelationSetLockForWrite(pg_shadow_rel); + + scan = heap_beginscan(pg_shadow_rel, false, false, 0, NULL); + while (HeapTupleIsValid(tuple = heap_getnext(scan, 0, &buffer))) + { + datum = heap_getattr(tuple, Anum_pg_shadow_usename, pg_dsc, &n); + + if (!strncmp((char *) datum, user, strlen(user))) + { + usesysid = (int) heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_dsc, &n); + ReleaseBuffer(buffer); + break; + } + ReleaseBuffer(buffer); + } + heap_endscan(scan); + + if (usesysid == -1) + { + RelationUnsetLockForWrite(pg_shadow_rel); + heap_close(pg_shadow_rel); + UserAbortTransactionBlock(); + elog(ERROR, "removeUser: user \"%s\" does not exist", user); + return; + } + + /* + * Perform a scan of the pg_database relation to find the databases + * owned by usesysid. Then drop them. + */ + pg_rel = heap_openr(DatabaseRelationName); + pg_dsc = RelationGetTupleDescriptor(pg_rel); + + scan = heap_beginscan(pg_rel, false, false, 0, NULL); + while (HeapTupleIsValid(tuple = heap_getnext(scan, 0, &buffer))) + { + datum = heap_getattr(tuple, Anum_pg_database_datdba, pg_dsc, &n); + + if ((int) datum == usesysid) + { + datum = heap_getattr(tuple, Anum_pg_database_datname, pg_dsc, &n); + if (memcmp((void *) datum, "template1", 9)) + { + dbase = (char **) realloc((void *) dbase, sizeof(char *) * (ndbase + 1)); + dbase[ndbase] = (char *) malloc(NAMEDATALEN + 1); + memcpy((void *) dbase[ndbase], (void *) datum, NAMEDATALEN); + dbase[ndbase++][NAMEDATALEN] = '\0'; + } + } + ReleaseBuffer(buffer); + } + heap_endscan(scan); + heap_close(pg_rel); + + while (ndbase--) + { + elog(NOTICE, "Dropping database %s", dbase[ndbase]); + sprintf(sql, "drop database %s", dbase[ndbase]); + free((void *) dbase[ndbase]); + pg_exec_query(sql, (char **) NULL, (Oid *) NULL, 0); + } + if (dbase) + free((void *) dbase); + + /* + * Since pg_shadow is global over all databases, one of two things + * must be done to insure complete consistency. First, pg_shadow + * could be made non-global. This would elminate the code above for + * deleting database and would require the addition of code to delete + * tables, views, etc owned by the user. + * + * The second option would be to create a means of deleting tables, view, + * etc. owned by the user from other databases. Pg_user is global and + * so this must be done at some point. + * + * Let us not forget that the user should be removed from the pg_groups + * also. + * + * Todd A. Brandys 11/18/1997 + * + */ + + /* + * Remove the user from the pg_shadow table + */ + sprintf(sql, "delete from %s where usename = '%s'", ShadowRelationName, user); + pg_exec_query(sql, (char **) NULL, (Oid *) NULL, 0); + + UpdatePgPwdFile(sql); + + RelationUnsetLockForWrite(pg_shadow_rel); + heap_close(pg_shadow_rel); + + if (IsTransactionBlock() && !inblock) + EndTransactionBlock(); } /* @@ -433,9 +493,10 @@ extern void RemoveUser(char* user) { * * check to see if there is an ACL on pg_shadow */ -static void CheckPgUserAclNotNull() +static void +CheckPgUserAclNotNull() { -HeapTuple htp; + HeapTuple htp; htp = SearchSysCacheTuple(RELNAME, PointerGetDatum(ShadowRelationName), 0, 0, 0); @@ -451,6 +512,6 @@ HeapTuple htp; elog(NOTICE, "so normal users can not read the passwords."); elog(ERROR, "Try 'REVOKE ALL ON pg_shadow FROM PUBLIC'"); } - + return; } |