diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
new file mode 100644
index 0000000000000000000000000000000000000000..b08872856d82cbc7389570179dacdfed53dbe9f8
--- /dev/null
+++ b/src/backend/commands/user.c
@@ -0,0 +1,379 @@
+/*-------------------------------------------------------------------------
+ *
+ * user.c--
+ *	  use pg_eval to create a new user in the catalog
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <stdio.h>				/* for sprintf() */
+#include <string.h>
+
+#include <postgres.h>
+
+#include <miscadmin.h>
+#include <catalog/catname.h>
+#include <catalog/pg_database.h>
+#include <catalog/pg_user.h>
+#include <libpq/crypt.h>
+#include <access/heapam.h>
+#include <access/xact.h>
+#include <storage/bufmgr.h>
+#include <storage/lmgr.h>
+#include <tcop/tcopprot.h>
+#include <utils/acl.h>
+#include <utils/palloc.h>
+#include <utils/rel.h>
+#include <commands/user.h>
+
+/*---------------------------------------------------------------------
+ * UpdatePgPwdFile
+ *
+ * copy the modified contents of pg_user to a file used by the postmaster
+ * for user authentication.  The file is stored as $PGDATA/pg_pwd.
+ *---------------------------------------------------------------------
+ */
+static
+void UpdatePgPwdFile(char* sql) {
+
+  char*     filename;
+
+  filename = crypt_getpwdfilename();
+  sprintf(sql, "copy %s to '%s' using delimiters '#'", UserRelationName, filename);
+  pg_eval(sql, (char**)NULL, (Oid*)NULL, 0);
+}
+
+/*---------------------------------------------------------------------
+ * DefineUser
+ *
+ * Add the user to the pg_user relation, and if specified make sure the
+ * user is specified in the desired groups of defined in pg_group.
+ *---------------------------------------------------------------------
+ */
+void DefineUser(CreateUserStmt *stmt) {
+
+  char*            pg_user;
+  Relation         pg_user_rel;
+  TupleDesc        pg_user_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 (!(inblock = IsTransactionBlock()))
+    BeginTransactionBlock();
+
+  /* Make sure the user attempting to create a user can insert into the pg_user
+   * relation.
+   */
+  pg_user = GetPgUserName();
+  if (pg_aclcheck(UserRelationName, pg_user, ACL_RD | ACL_WR | ACL_AP) != ACLCHECK_OK) {
+    UserAbortTransactionBlock();
+    elog(WARN, "defineUser: user \"%s\" does not have SELECT and INSERT privilege for \"%s\"",
+               pg_user, UserRelationName);
+    return;
+  }
+
+  /* Scan the pg_user relation to be certain the user doesn't already exist.
+   */
+  pg_user_rel = heap_openr(UserRelationName);
+  pg_user_dsc = RelationGetTupleDescriptor(pg_user_rel);
+  /* Secure a write lock on pg_user so we can be sure of what the next usesysid
+   * should be.
+   */
+  RelationSetLockForWrite(pg_user_rel);
+
+  scan = heap_beginscan(pg_user_rel, false, false, 0, NULL);
+  while (HeapTupleIsValid(tuple = heap_getnext(scan, 0, &buffer))) {
+    datum = heap_getattr(tuple, buffer, Anum_pg_user_usename, pg_user_dsc, &n);
+
+    if (!exists && !strncmp((char*)datum, stmt->user, strlen(stmt->user)))
+      exists = true;
+
+    datum = heap_getattr(tuple, buffer, Anum_pg_user_usesysid, pg_user_dsc, &n);
+    if ((int)datum > max_id)
+      max_id = (int)datum;
+
+    ReleaseBuffer(buffer);
+  }
+  heap_endscan(scan);
+
+  if (exists) {
+    RelationUnsetLockForWrite(pg_user_rel);
+    heap_close(pg_user_rel);
+    UserAbortTransactionBlock();
+    elog(WARN, "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", UserRelationName);
+/*  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_eval(sql, (char**)NULL, (Oid*)NULL, 0);
+
+  /* Add the stuff here for groups.
+   */
+
+  RelationUnsetLockForWrite(pg_user_rel);
+  heap_close(pg_user_rel);
+
+  UpdatePgPwdFile(sql);
+
+  if (IsTransactionBlock() && !inblock)
+    EndTransactionBlock();
+}
+
+
+extern void AlterUser(AlterUserStmt *stmt) {
+
+  char*            pg_user;
+  Relation         pg_user_rel;
+  TupleDesc        pg_user_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 (!(inblock = IsTransactionBlock()))
+    BeginTransactionBlock();
+
+  /* Make sure the user attempting to create a user can insert into the pg_user
+   * relation.
+   */
+  pg_user = GetPgUserName();
+  if (pg_aclcheck(UserRelationName, pg_user, ACL_RD | ACL_WR) != ACLCHECK_OK) {
+    UserAbortTransactionBlock();
+    elog(WARN, "alterUser: user \"%s\" does not have SELECT and UPDATE privilege for \"%s\"",
+               pg_user, UserRelationName);
+    return;
+  }
+
+  /* Scan the pg_user relation to be certain the user exists.
+   */
+  pg_user_rel = heap_openr(UserRelationName);
+  pg_user_dsc = RelationGetTupleDescriptor(pg_user_rel);
+
+  scan = heap_beginscan(pg_user_rel, false, false, 0, NULL);
+  while (HeapTupleIsValid(tuple = heap_getnext(scan, 0, &buffer))) {
+    datum = heap_getattr(tuple, buffer, Anum_pg_user_usename, pg_user_dsc, &n);
+
+    if (!strncmp((char*)datum, stmt->user, strlen(stmt->user))) {
+      exists = true;
+      ReleaseBuffer(buffer);
+      break;
+    }
+  }
+  heap_endscan(scan);
+  heap_close(pg_user_rel);
+
+  if (!exists) {
+    UserAbortTransactionBlock();
+    elog(WARN, "alterUser: user \"%s\" does not exist", stmt->user);
+    return;
+  }
+
+  /* Create the update statement to modify the user.
+   */
+  sprintf(sql, "update %s set", UserRelationName);
+  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_eval(sql, (char**)NULL, (Oid*)NULL, 0);
+  }
+
+  /* do the pg_group stuff here */
+
+  UpdatePgPwdFile(sql);
+
+  if (IsTransactionBlock() && !inblock)
+    EndTransactionBlock();
+}
+
+
+extern void RemoveUser(char* user) {
+
+  char*            pg_user;
+  Relation         pg_rel;
+  TupleDesc        pg_dsc;
+  HeapScanDesc     scan;
+  HeapTuple        tuple;
+  Datum            datum;
+  Buffer           buffer;
+  char             sql[256];
+  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_user
+   * relation.
+   */
+  pg_user = GetPgUserName();
+  if (pg_aclcheck(UserRelationName, pg_user, ACL_RD | ACL_WR) != ACLCHECK_OK) {
+    UserAbortTransactionBlock();
+    elog(WARN, "removeUser: user \"%s\" does not have SELECT and DELETE privilege for \"%s\"",
+               pg_user, UserRelationName);
+    return;
+  }
+
+  /* Perform a scan of the pg_user relation to find the usesysid of the user to
+   * be deleted.  If it is not found, then return a warning message.
+   */
+  pg_rel = heap_openr(UserRelationName);
+  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, buffer, Anum_pg_user_usename, pg_dsc, &n);
+
+    if (!strncmp((char*)datum, user, strlen(user))) {
+      usesysid = (int)heap_getattr(tuple, buffer, Anum_pg_user_usesysid, pg_dsc, &n);
+      ReleaseBuffer(buffer);
+      break;
+    }
+    ReleaseBuffer(buffer);
+  }
+  heap_endscan(scan);
+  heap_close(pg_rel);
+
+  if (usesysid == -1) {
+    UserAbortTransactionBlock();
+    elog(WARN, "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, buffer, Anum_pg_database_datdba, pg_dsc, &n);
+
+    if ((int)datum == usesysid) {
+      datum = heap_getattr(tuple, buffer, Anum_pg_database_datname, pg_dsc, &n);
+      if (memcmp((void*)datum, "template1", 9)) {
+        dbase = (char**)repalloc((void*)dbase, sizeof(char*) * (ndbase + 1));
+        dbase[ndbase] = (char*)palloc(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]);
+    pfree((void*)dbase[ndbase]);
+    pg_eval(sql, (char**)NULL, (Oid*)NULL, 0);
+  }
+  if (dbase)
+    pfree((void*)dbase);
+
+  /* Since pg_user is global over all databases, one of two things must be done
+   * to insure complete consistency.  First, pg_user 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_user table
+   */
+  sprintf(sql, "delete from %s where usename = '%s'", UserRelationName, user);
+  pg_eval(sql, (char**)NULL, (Oid*)NULL, 0);
+
+  UpdatePgPwdFile(sql);
+
+  if (IsTransactionBlock() && !inblock)
+    EndTransactionBlock();
+}
diff --git a/src/backend/libpq/crypt.c b/src/backend/libpq/crypt.c
new file mode 100644
index 0000000000000000000000000000000000000000..c75d8ac4590eaba87e6283082567ebdb1ca89626
--- /dev/null
+++ b/src/backend/libpq/crypt.c
@@ -0,0 +1,182 @@
+/*-------------------------------------------------------------------------
+ *
+ * crypt.c--
+ *        Look into pg_user and check the encrypted password with the one
+ *        passed in from the frontend.
+ *
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#include <postgres.h>
+#include <libpq/crypt.h>
+#include <utils/nabstime.h>
+
+char* crypt_getpwdfilename() {
+
+  static char*     filename = NULL;
+
+  if (!filename) {
+    char*     env;
+
+    env = getenv("PGDATA");
+    filename = (char*)malloc(strlen(env) + strlen(CRYPT_PWD_FILE) + 2);
+    sprintf(filename, "%s/%s", env, CRYPT_PWD_FILE);
+  }
+
+  return filename;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static
+FILE* crypt_openpwdfile() {
+
+  char*     filename;
+
+  filename = crypt_getpwdfilename();
+  return (fopen(filename, "r"));
+}
+
+/*-------------------------------------------------------------------------*/
+
+static
+void crypt_parsepwdfile(FILE* datafile, char** login, char** pwd, char** valdate) {
+
+  char     buffer[256];
+  char*    parse;
+  int      count,
+           i;
+
+  fgets(buffer, 256, datafile);
+  parse = buffer;
+
+  /* store a copy of user login to return
+   */
+  count = strcspn(parse, "#");
+  *login = (char*)malloc(count + 1);
+  strncpy(*login, parse, count);
+  (*login)[count] = '\0';
+  parse += (count + 1);
+
+  /* skip to the password field
+   */
+  for (i = 0; i < 5; i++)
+    parse += (strcspn(parse, "#") + 1);
+
+  /* store a copy of user password to return
+   */
+  count = strcspn(parse, "#");
+  *pwd = (char*)malloc(count + 1);
+  strncpy(*pwd, parse, count);
+  (*pwd)[count] = '\0';
+  parse += (count + 1);
+
+  /* store a copy of date login becomes invalid
+   */
+  count = strcspn(parse, "#");
+  *valdate = (char*)malloc(count + 1);
+  strncpy(*valdate, parse, count);
+  (*valdate)[count] = '\0';
+  parse += (count + 1);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static
+void crypt_getloginfo(const char* user, char** passwd, char** valuntil) {
+
+  FILE*     datafile;
+  char*     login;
+  char*     pwd;
+  char*     valdate;
+
+  *passwd = NULL;
+  *valuntil = NULL;
+
+  if (!(datafile = crypt_openpwdfile()))
+    return;
+
+  while (!feof(datafile)) {
+    crypt_parsepwdfile(datafile, &login, &pwd, &valdate);
+    if (!strcmp(login, user)) {
+      free((void*)login);
+      *passwd = pwd;
+      *valuntil = valdate;
+      fclose(datafile);
+      return;
+    }
+    free((void*)login);
+    free((void*)pwd);
+    free((void*)valdate);
+  }
+  fclose(datafile);
+}
+
+/*-------------------------------------------------------------------------*/
+
+MsgType crypt_salt(const char* user) {
+
+  char*     passwd;
+  char*     valuntil;
+
+  crypt_getloginfo(user, &passwd, &valuntil);
+
+  if (passwd == NULL || *passwd == '\0') {
+    if (passwd) free((void*)passwd);
+    if (valuntil) free((void*)valuntil);
+    return STARTUP_UNSALT_MSG;
+  }
+
+  free((void*)passwd);
+  if (valuntil) free((void*)valuntil);
+  return STARTUP_SALT_MSG;
+}
+
+/*-------------------------------------------------------------------------*/
+
+int crypt_verify(Port* port, const char* user, const char* pgpass) {
+
+  char*            passwd;
+  char*            valuntil;
+  char*            crypt_pwd;
+  int              retval = STATUS_ERROR;
+  AbsoluteTime     vuntil,
+                   current;
+
+  crypt_getloginfo(user, &passwd, &valuntil);
+
+  if (passwd == NULL || *passwd == '\0') {
+    if (passwd) free((void*)passwd);
+    if (valuntil) free((void*)valuntil);
+    return STATUS_ERROR;
+  }
+
+  crypt_pwd = crypt(passwd, port->salt);
+  if (!strcmp(pgpass, crypt_pwd)) {
+    /* check here to be sure we are not past valuntil
+     */
+    if (!valuntil)
+      vuntil = INVALID_ABSTIME;
+    else
+      vuntil = nabstimein(valuntil);
+    current = GetCurrentAbsoluteTime();
+    if (vuntil != INVALID_ABSTIME && vuntil < current)
+      retval = STATUS_ERROR;
+    else
+      retval = STATUS_OK;
+  }
+
+  free((void*)passwd);
+  if (valuntil) free((void*)valuntil);
+  
+  return retval;
+}
diff --git a/src/include/commands/user.h b/src/include/commands/user.h
new file mode 100644
index 0000000000000000000000000000000000000000..1994b0bcd12d8309cb076b3bc0346495a5a05670
--- /dev/null
+++ b/src/include/commands/user.h
@@ -0,0 +1,17 @@
+/*-------------------------------------------------------------------------
+ *
+ * user.h--
+ *
+ *
+ *
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef USER_H
+#define USER_H
+
+extern void DefineUser(CreateUserStmt *stmt);
+extern void AlterUser(AlterUserStmt *stmt);
+extern void RemoveUser(char* user);
+
+#endif							/* USER_H */
diff --git a/src/include/libpq/crypt.h b/src/include/libpq/crypt.h
new file mode 100644
index 0000000000000000000000000000000000000000..7c01c8297be6c1fd9a63ace3d02eb99ba65fdf8e
--- /dev/null
+++ b/src/include/libpq/crypt.h
@@ -0,0 +1,20 @@
+/*-------------------------------------------------------------------------
+ *
+ * crypt.h--
+ *	  Interface to hba.c
+ *
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_CRYPT_H
+#define PG_CRYPT_H
+
+#include <libpq/pqcomm.h>
+
+#define CRYPT_PWD_FILE	"pg_pwd"
+
+extern char* crypt_getpwdfilename();
+extern MsgType crypt_salt(const char* user);
+extern int crypt_verify(Port* port, const char* user, const char* pgpass);
+
+#endif