user.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:12k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * user.c
  4.  *   use pg_exec_query to create a new user in the catalog
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  * $Id: user.c,v 1.28.2.1 1999/08/02 05:56:59 scrappy Exp $
  9.  *
  10.  *-------------------------------------------------------------------------
  11.  */
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #include <fcntl.h>
  15. #include <unistd.h>
  16. #include "postgres.h"
  17. #include "access/heapam.h"
  18. #include "catalog/catname.h"
  19. #include "catalog/pg_database.h"
  20. #include "catalog/pg_shadow.h"
  21. #include "commands/user.h"
  22. #include "libpq/crypt.h"
  23. #include "miscadmin.h"
  24. #include "tcop/tcopprot.h"
  25. #include "utils/acl.h"
  26. #include "utils/syscache.h"
  27. static void CheckPgUserAclNotNull(void);
  28. #define SQL_LENGTH 512
  29. /*---------------------------------------------------------------------
  30.  * UpdatePgPwdFile
  31.  *
  32.  * copy the modified contents of pg_shadow to a file used by the postmaster
  33.  * for user authentication.  The file is stored as $PGDATA/pg_pwd.
  34.  *---------------------------------------------------------------------
  35.  */
  36. static
  37. void
  38. UpdatePgPwdFile(char *sql, CommandDest dest)
  39. {
  40. char    *filename,
  41.    *tempname;
  42. int bufsize;
  43. /*
  44.  * Create a temporary filename to be renamed later.  This prevents the
  45.  * backend from clobbering the pg_pwd file while the postmaster might
  46.  * be reading from it.
  47.  */
  48. filename = crypt_getpwdfilename();
  49. bufsize = strlen(filename) + 12;
  50. tempname = (char *) palloc(bufsize);
  51. snprintf(tempname, bufsize, "%s.%d", filename, MyProcPid);
  52. /*
  53.  * Copy the contents of pg_shadow to the pg_pwd ASCII file using a the
  54.  * SEPCHAR character as the delimiter between fields.  Then rename the
  55.  * file to its final name.
  56.  */
  57. snprintf(sql, SQL_LENGTH,
  58.  "copy %s to '%s' using delimiters %s",
  59.  ShadowRelationName, tempname, CRYPT_PWD_FILE_SEPCHAR);
  60. pg_exec_query_dest(sql, dest, false);
  61. rename(tempname, filename);
  62. pfree((void *) tempname);
  63. /*
  64.  * Create a flag file the postmaster will detect the next time it
  65.  * tries to authenticate a user.  The postmaster will know to reload
  66.  * the pg_pwd file contents.
  67.  */
  68. filename = crypt_getpwdreloadfilename();
  69. creat(filename, S_IRUSR | S_IWUSR);
  70. }
  71. /*---------------------------------------------------------------------
  72.  * DefineUser
  73.  *
  74.  * Add the user to the pg_shadow relation, and if specified make sure the
  75.  * user is specified in the desired groups of defined in pg_group.
  76.  *---------------------------------------------------------------------
  77.  */
  78. void
  79. DefineUser(CreateUserStmt *stmt, CommandDest dest)
  80. {
  81. char    *pg_shadow,
  82. sql[SQL_LENGTH];
  83. Relation pg_shadow_rel;
  84. TupleDesc pg_shadow_dsc;
  85. HeapScanDesc scan;
  86. HeapTuple tuple;
  87. Datum datum;
  88. bool exists = false,
  89. n,
  90. inblock,
  91. havepassword,
  92. havevaluntil;
  93. int max_id = -1;
  94. havepassword = stmt->password && stmt->password[0];
  95. havevaluntil = stmt->validUntil && stmt->validUntil[0];
  96. if (havepassword)
  97. CheckPgUserAclNotNull();
  98. if (!(inblock = IsTransactionBlock()))
  99. BeginTransactionBlock();
  100. /*
  101.  * Make sure the user attempting to create a user can insert into the
  102.  * pg_shadow relation.
  103.  */
  104. pg_shadow = GetPgUserName();
  105. if (pg_aclcheck(ShadowRelationName, pg_shadow, ACL_RD | ACL_WR | ACL_AP) != ACLCHECK_OK)
  106. {
  107. UserAbortTransactionBlock();
  108. elog(ERROR, "defineUser: user "%s" does not have SELECT and INSERT privilege for "%s"",
  109.  pg_shadow, ShadowRelationName);
  110. return;
  111. }
  112. /*
  113.  * Scan the pg_shadow relation to be certain the user doesn't already
  114.  * exist.
  115.  */
  116. pg_shadow_rel = heap_openr(ShadowRelationName);
  117. pg_shadow_dsc = RelationGetDescr(pg_shadow_rel);
  118. /*
  119.  * Secure a write lock on pg_shadow so we can be sure of what the next
  120.  * usesysid should be.
  121.  */
  122. LockRelation(pg_shadow_rel, AccessExclusiveLock);
  123. scan = heap_beginscan(pg_shadow_rel, false, SnapshotNow, 0, NULL);
  124. while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
  125. {
  126. datum = heap_getattr(tuple, Anum_pg_shadow_usename, pg_shadow_dsc, &n);
  127. if (!exists && !strncmp((char *) datum, stmt->user, strlen(stmt->user)))
  128. exists = true;
  129. datum = heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_shadow_dsc, &n);
  130. if ((int) datum > max_id)
  131. max_id = (int) datum;
  132. }
  133. heap_endscan(scan);
  134. if (exists)
  135. {
  136. UnlockRelation(pg_shadow_rel, AccessExclusiveLock);
  137. heap_close(pg_shadow_rel);
  138. UserAbortTransactionBlock();
  139. elog(ERROR,
  140.  "defineUser: user "%s" has already been created", stmt->user);
  141. return;
  142. }
  143. /*
  144.  * Build the insert statement to be executed.
  145.  *
  146.  * XXX Ugly as this code is, it still fails to cope with ' or  in any of
  147.  * the provided strings.
  148.  */
  149. snprintf(sql, SQL_LENGTH,
  150.  "insert into %s (usename,usesysid,usecreatedb,usetrace,"
  151.  "usesuper,usecatupd,passwd,valuntil) "
  152.  "values('%s',%d,'%c','t','%c','t',%s%s%s,%s%s%s)",
  153.  ShadowRelationName,
  154.  stmt->user,
  155.  max_id + 1,
  156.  (stmt->createdb && *stmt->createdb) ? 't' : 'f',
  157.  (stmt->createuser && *stmt->createuser) ? 't' : 'f',
  158.  havepassword ? "'" : "",
  159.  havepassword ? stmt->password : "NULL",
  160.  havepassword ? "'" : "",
  161.  havevaluntil ? "'" : "",
  162.  havevaluntil ? stmt->validUntil : "NULL",
  163.  havevaluntil ? "'" : "");
  164. /*
  165.  * XXX If insert fails, say because a bogus valuntil date is given,
  166.  * need to catch the resulting error and undo our transaction.
  167.  */
  168. pg_exec_query_dest(sql, dest, false);
  169. /*
  170.  * Add the stuff here for groups.
  171.  */
  172. UpdatePgPwdFile(sql, dest);
  173. /*
  174.  * This goes after the UpdatePgPwdFile to be certain that two backends
  175.  * to not attempt to write to the pg_pwd file at the same time.
  176.  */
  177. UnlockRelation(pg_shadow_rel, AccessExclusiveLock);
  178. heap_close(pg_shadow_rel);
  179. if (IsTransactionBlock() && !inblock)
  180. EndTransactionBlock();
  181. }
  182. extern void
  183. AlterUser(AlterUserStmt *stmt, CommandDest dest)
  184. {
  185. char    *pg_shadow,
  186. sql[SQL_LENGTH];
  187. Relation pg_shadow_rel;
  188. TupleDesc pg_shadow_dsc;
  189. HeapTuple tuple;
  190. bool inblock;
  191. if (stmt->password)
  192. CheckPgUserAclNotNull();
  193. if (!(inblock = IsTransactionBlock()))
  194. BeginTransactionBlock();
  195. /*
  196.  * Make sure the user attempting to create a user can insert into the
  197.  * pg_shadow relation.
  198.  */
  199. pg_shadow = GetPgUserName();
  200. if (pg_aclcheck(ShadowRelationName, pg_shadow, ACL_RD | ACL_WR) != ACLCHECK_OK)
  201. {
  202. UserAbortTransactionBlock();
  203. elog(ERROR, "alterUser: user "%s" does not have SELECT and UPDATE privilege for "%s"",
  204.  pg_shadow, ShadowRelationName);
  205. return;
  206. }
  207. /*
  208.  * Scan the pg_shadow relation to be certain the user exists.
  209.  */
  210. pg_shadow_rel = heap_openr(ShadowRelationName);
  211. pg_shadow_dsc = RelationGetDescr(pg_shadow_rel);
  212. /*
  213.  * Secure a write lock on pg_shadow so we can be sure that when the
  214.  * dump of the pg_pwd file is done, there is not another backend doing
  215.  * the same.
  216.  */
  217. LockRelation(pg_shadow_rel, AccessExclusiveLock);
  218. tuple = SearchSysCacheTuple(USENAME,
  219. PointerGetDatum(stmt->user),
  220. 0, 0, 0);
  221. if (!HeapTupleIsValid(tuple))
  222. {
  223. UnlockRelation(pg_shadow_rel, AccessExclusiveLock);
  224. heap_close(pg_shadow_rel);
  225. UserAbortTransactionBlock(); /* needed? */
  226. elog(ERROR, "alterUser: user "%s" does not exist", stmt->user);
  227. return;
  228. }
  229. /*
  230.  * Create the update statement to modify the user.
  231.  */
  232. snprintf(sql, SQL_LENGTH, "update %s set", ShadowRelationName);
  233. if (stmt->password)
  234. snprintf(sql, SQL_LENGTH, "%s passwd = '%s'", pstrdup(sql), stmt->password);
  235. if (stmt->createdb)
  236. {
  237. snprintf(sql, SQL_LENGTH, "%s %susecreatedb='%s'",
  238.  pstrdup(sql), stmt->password ? "," : "",
  239.  *stmt->createdb ? "t" : "f");
  240. }
  241. if (stmt->createuser)
  242. {
  243. snprintf(sql, SQL_LENGTH, "%s %susesuper='%s'",
  244.  pstrdup(sql), (stmt->password || stmt->createdb) ? "," : "",
  245.  *stmt->createuser ? "t" : "f");
  246. }
  247. if (stmt->validUntil)
  248. {
  249. snprintf(sql, SQL_LENGTH, "%s %svaluntil='%s'",
  250.  pstrdup(sql),
  251. (stmt->password || stmt->createdb || stmt->createuser) ? "," : "",
  252.  stmt->validUntil);
  253. }
  254. snprintf(sql, SQL_LENGTH, "%s where usename = '%s'",
  255.  pstrdup(sql), stmt->user);
  256. pg_exec_query_dest(sql, dest, false);
  257. /* do the pg_group stuff here */
  258. UpdatePgPwdFile(sql, dest);
  259. UnlockRelation(pg_shadow_rel, AccessExclusiveLock);
  260. heap_close(pg_shadow_rel);
  261. if (IsTransactionBlock() && !inblock)
  262. EndTransactionBlock();
  263. }
  264. extern void
  265. RemoveUser(char *user, CommandDest dest)
  266. {
  267. char    *pg_shadow;
  268. Relation pg_shadow_rel,
  269. pg_rel;
  270. TupleDesc pg_dsc;
  271. HeapScanDesc scan;
  272. HeapTuple tuple;
  273. Datum datum;
  274. char sql[512];
  275. bool n,
  276. inblock;
  277. int32 usesysid;
  278. int ndbase = 0;
  279. char   **dbase = NULL;
  280. if (!(inblock = IsTransactionBlock()))
  281. BeginTransactionBlock();
  282. /*
  283.  * Make sure the user attempting to create a user can delete from the
  284.  * pg_shadow relation.
  285.  */
  286. pg_shadow = GetPgUserName();
  287. if (pg_aclcheck(ShadowRelationName, pg_shadow, ACL_RD | ACL_WR) != ACLCHECK_OK)
  288. {
  289. UserAbortTransactionBlock();
  290. elog(ERROR, "removeUser: user "%s" does not have SELECT and DELETE privilege for "%s"",
  291.  pg_shadow, ShadowRelationName);
  292. }
  293. /*
  294.  * Perform a scan of the pg_shadow relation to find the usesysid of
  295.  * the user to be deleted. If it is not found, then return a warning
  296.  * message.
  297.  */
  298. pg_shadow_rel = heap_openr(ShadowRelationName);
  299. pg_dsc = RelationGetDescr(pg_shadow_rel);
  300. /*
  301.  * Secure a write lock on pg_shadow so we can be sure that when the
  302.  * dump of the pg_pwd file is done, there is not another backend doing
  303.  * the same.
  304.  */
  305. LockRelation(pg_shadow_rel, AccessExclusiveLock);
  306. tuple = SearchSysCacheTuple(USENAME,
  307. PointerGetDatum(user),
  308. 0, 0, 0);
  309. if (!HeapTupleIsValid(tuple))
  310. {
  311. UnlockRelation(pg_shadow_rel, AccessExclusiveLock);
  312. heap_close(pg_shadow_rel);
  313. UserAbortTransactionBlock();
  314. elog(ERROR, "removeUser: user "%s" does not exist", user);
  315. }
  316. usesysid = (int32) heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_dsc, &n);
  317. /*
  318.  * Perform a scan of the pg_database relation to find the databases
  319.  * owned by usesysid.  Then drop them.
  320.  */
  321. pg_rel = heap_openr(DatabaseRelationName);
  322. pg_dsc = RelationGetDescr(pg_rel);
  323. scan = heap_beginscan(pg_rel, false, SnapshotNow, 0, NULL);
  324. while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
  325. {
  326. datum = heap_getattr(tuple, Anum_pg_database_datdba, pg_dsc, &n);
  327. if ((int) datum == usesysid)
  328. {
  329. datum = heap_getattr(tuple, Anum_pg_database_datname, pg_dsc, &n);
  330. if (memcmp((void *) datum, "template1", 9))
  331. {
  332. dbase =
  333. (char **) repalloc((void *) dbase, sizeof(char *) * (ndbase + 1));
  334. dbase[ndbase] = (char *) palloc(NAMEDATALEN + 1);
  335. memcpy((void *) dbase[ndbase], (void *) datum, NAMEDATALEN);
  336. dbase[ndbase++][NAMEDATALEN] = '';
  337. }
  338. }
  339. }
  340. heap_endscan(scan);
  341. heap_close(pg_rel);
  342. while (ndbase--)
  343. {
  344. elog(NOTICE, "Dropping database %s", dbase[ndbase]);
  345. snprintf(sql, SQL_LENGTH, "drop database %s", dbase[ndbase]);
  346. pfree((void *) dbase[ndbase]);
  347. pg_exec_query_dest(sql, dest, false);
  348. }
  349. if (dbase)
  350. pfree((void *) dbase);
  351. /*
  352.  * Since pg_shadow is global over all databases, one of two things
  353.  * must be done to insure complete consistency.  First, pg_shadow
  354.  * could be made non-global. This would elminate the code above for
  355.  * deleting database and would require the addition of code to delete
  356.  * tables, views, etc owned by the user.
  357.  *
  358.  * The second option would be to create a means of deleting tables, view,
  359.  * etc. owned by the user from other databases.  pg_shadow is global
  360.  * and so this must be done at some point.
  361.  *
  362.  * Let us not forget that the user should be removed from the pg_groups
  363.  * also.
  364.  *
  365.  * Todd A. Brandys 11/18/1997
  366.  *
  367.  */
  368. /*
  369.  * Remove the user from the pg_shadow table
  370.  */
  371. snprintf(sql, SQL_LENGTH,
  372. "delete from %s where usename = '%s'", ShadowRelationName, user);
  373. pg_exec_query_dest(sql, dest, false);
  374. UpdatePgPwdFile(sql, dest);
  375. UnlockRelation(pg_shadow_rel, AccessExclusiveLock);
  376. heap_close(pg_shadow_rel);
  377. if (IsTransactionBlock() && !inblock)
  378. EndTransactionBlock();
  379. }
  380. /*
  381.  * CheckPgUserAclNotNull
  382.  *
  383.  * check to see if there is an ACL on pg_shadow
  384.  */
  385. static void
  386. CheckPgUserAclNotNull()
  387. {
  388. HeapTuple htup;
  389. htup = SearchSysCacheTuple(RELNAME,
  390.    PointerGetDatum(ShadowRelationName),
  391.    0, 0, 0);
  392. if (!HeapTupleIsValid(htup))
  393. {
  394. elog(ERROR, "IsPgUserAclNull: class "%s" not found",
  395.  ShadowRelationName);
  396. }
  397. if (heap_attisnull(htup, Anum_pg_class_relacl))
  398. {
  399. elog(NOTICE, "To use passwords, you have to revoke permissions on pg_shadow");
  400. elog(NOTICE, "so normal users can not read the passwords.");
  401. elog(ERROR, "Try 'REVOKE ALL ON pg_shadow FROM PUBLIC'");
  402. }
  403. return;
  404. }