PostgreSQL Source Code  git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
createuser.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * createuser
4  *
5  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
6  * Portions Copyright (c) 1994, Regents of the University of California
7  *
8  * src/bin/scripts/createuser.c
9  *
10  *-------------------------------------------------------------------------
11  */
12 
13 #include "postgres_fe.h"
14 
15 #include <limits.h>
16 
17 #include "common.h"
18 #include "common/logging.h"
19 #include "common/string.h"
20 #include "fe_utils/option_utils.h"
21 #include "fe_utils/simple_list.h"
22 #include "fe_utils/string_utils.h"
23 
24 
25 static void help(const char *progname);
26 
27 int
28 main(int argc, char *argv[])
29 {
30  static struct option long_options[] = {
31  {"with-admin", required_argument, NULL, 'a'},
32  {"connection-limit", required_argument, NULL, 'c'},
33  {"createdb", no_argument, NULL, 'd'},
34  {"no-createdb", no_argument, NULL, 'D'},
35  {"echo", no_argument, NULL, 'e'},
36  {"encrypted", no_argument, NULL, 'E'},
37  {"role", required_argument, NULL, 'g'},
38  {"member-of", required_argument, NULL, 'g'},
39  {"host", required_argument, NULL, 'h'},
40  {"inherit", no_argument, NULL, 'i'},
41  {"no-inherit", no_argument, NULL, 'I'},
42  {"login", no_argument, NULL, 'l'},
43  {"no-login", no_argument, NULL, 'L'},
44  {"with-member", required_argument, NULL, 'm'},
45  {"port", required_argument, NULL, 'p'},
46  {"pwprompt", no_argument, NULL, 'P'},
47  {"createrole", no_argument, NULL, 'r'},
48  {"no-createrole", no_argument, NULL, 'R'},
49  {"superuser", no_argument, NULL, 's'},
50  {"no-superuser", no_argument, NULL, 'S'},
51  {"username", required_argument, NULL, 'U'},
52  {"valid-until", required_argument, NULL, 'v'},
53  {"no-password", no_argument, NULL, 'w'},
54  {"password", no_argument, NULL, 'W'},
55  {"replication", no_argument, NULL, 1},
56  {"no-replication", no_argument, NULL, 2},
57  {"interactive", no_argument, NULL, 3},
58  {"bypassrls", no_argument, NULL, 4},
59  {"no-bypassrls", no_argument, NULL, 5},
60  {NULL, 0, NULL, 0}
61  };
62 
63  const char *progname;
64  int optindex;
65  int c;
66  const char *newuser = NULL;
67  char *host = NULL;
68  char *port = NULL;
69  char *username = NULL;
70  SimpleStringList roles = {NULL, NULL};
71  SimpleStringList members = {NULL, NULL};
72  SimpleStringList admins = {NULL, NULL};
73  enum trivalue prompt_password = TRI_DEFAULT;
74  ConnParams cparams;
75  bool echo = false;
76  bool interactive = false;
77  int conn_limit = -2; /* less than minimum valid value */
78  bool pwprompt = false;
79  char *newpassword = NULL;
80  char *pwexpiry = NULL;
81 
82  /* Tri-valued variables. */
85  createrole = TRI_DEFAULT,
86  inherit = TRI_DEFAULT,
87  login = TRI_DEFAULT,
88  replication = TRI_DEFAULT,
89  bypassrls = TRI_DEFAULT;
90 
91  PQExpBufferData sql;
92 
93  PGconn *conn;
94  PGresult *result;
95 
96  pg_logging_init(argv[0]);
97  progname = get_progname(argv[0]);
98  set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
99 
100  handle_help_version_opts(argc, argv, "createuser", help);
101 
102  while ((c = getopt_long(argc, argv, "a:c:dDeEg:h:iIlLm:p:PrRsSU:v:wW",
103  long_options, &optindex)) != -1)
104  {
105  switch (c)
106  {
107  case 'a':
109  break;
110  case 'c':
111  if (!option_parse_int(optarg, "-c/--connection-limit",
112  -1, INT_MAX, &conn_limit))
113  exit(1);
114  break;
115  case 'd':
116  createdb = TRI_YES;
117  break;
118  case 'D':
119  createdb = TRI_NO;
120  break;
121  case 'e':
122  echo = true;
123  break;
124  case 'E':
125  /* no-op, accepted for backward compatibility */
126  break;
127  case 'g':
129  break;
130  case 'h':
131  host = pg_strdup(optarg);
132  break;
133  case 'i':
134  inherit = TRI_YES;
135  break;
136  case 'I':
137  inherit = TRI_NO;
138  break;
139  case 'l':
140  login = TRI_YES;
141  break;
142  case 'L':
143  login = TRI_NO;
144  break;
145  case 'm':
147  break;
148  case 'p':
149  port = pg_strdup(optarg);
150  break;
151  case 'P':
152  pwprompt = true;
153  break;
154  case 'r':
155  createrole = TRI_YES;
156  break;
157  case 'R':
158  createrole = TRI_NO;
159  break;
160  case 's':
161  superuser = TRI_YES;
162  break;
163  case 'S':
164  superuser = TRI_NO;
165  break;
166  case 'U':
168  break;
169  case 'v':
170  pwexpiry = pg_strdup(optarg);
171  break;
172  case 'w':
173  prompt_password = TRI_NO;
174  break;
175  case 'W':
176  prompt_password = TRI_YES;
177  break;
178  case 1:
179  replication = TRI_YES;
180  break;
181  case 2:
182  replication = TRI_NO;
183  break;
184  case 3:
185  interactive = true;
186  break;
187  case 4:
188  bypassrls = TRI_YES;
189  break;
190  case 5:
191  bypassrls = TRI_NO;
192  break;
193  default:
194  /* getopt_long already emitted a complaint */
195  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
196  exit(1);
197  }
198  }
199 
200  switch (argc - optind)
201  {
202  case 0:
203  break;
204  case 1:
205  newuser = argv[optind];
206  break;
207  default:
208  pg_log_error("too many command-line arguments (first is \"%s\")",
209  argv[optind + 1]);
210  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
211  exit(1);
212  }
213 
214  if (newuser == NULL)
215  {
216  if (interactive)
217  {
218  newuser = simple_prompt("Enter name of role to add: ", true);
219  }
220  else
221  {
222  if (getenv("PGUSER"))
223  newuser = getenv("PGUSER");
224  else
225  newuser = get_user_name_or_exit(progname);
226  }
227  }
228 
229  if (pwprompt)
230  {
231  char *pw2;
232 
233  newpassword = simple_prompt("Enter password for new role: ", false);
234  pw2 = simple_prompt("Enter it again: ", false);
235  if (strcmp(newpassword, pw2) != 0)
236  {
237  fprintf(stderr, _("Passwords didn't match.\n"));
238  exit(1);
239  }
240  free(pw2);
241  }
242 
243  if (superuser == TRI_DEFAULT)
244  {
245  if (interactive && yesno_prompt("Shall the new role be a superuser?"))
246  superuser = TRI_YES;
247  else
248  superuser = TRI_NO;
249  }
250 
251  if (superuser == TRI_YES)
252  {
253  /* Not much point in trying to restrict a superuser */
254  createdb = TRI_YES;
255  createrole = TRI_YES;
256  }
257 
258  if (createdb == TRI_DEFAULT)
259  {
260  if (interactive && yesno_prompt("Shall the new role be allowed to create databases?"))
261  createdb = TRI_YES;
262  else
263  createdb = TRI_NO;
264  }
265 
266  if (createrole == TRI_DEFAULT)
267  {
268  if (interactive && yesno_prompt("Shall the new role be allowed to create more new roles?"))
269  createrole = TRI_YES;
270  else
271  createrole = TRI_NO;
272  }
273 
274  if (bypassrls == TRI_DEFAULT)
275  bypassrls = TRI_NO;
276 
277  if (replication == TRI_DEFAULT)
278  replication = TRI_NO;
279 
280  if (inherit == TRI_DEFAULT)
281  inherit = TRI_YES;
282 
283  if (login == TRI_DEFAULT)
284  login = TRI_YES;
285 
286  cparams.dbname = NULL; /* this program lacks any dbname option... */
287  cparams.pghost = host;
288  cparams.pgport = port;
289  cparams.pguser = username;
290  cparams.prompt_password = prompt_password;
291  cparams.override_dbname = NULL;
292 
293  conn = connectMaintenanceDatabase(&cparams, progname, echo);
294 
295  initPQExpBuffer(&sql);
296 
297  printfPQExpBuffer(&sql, "CREATE ROLE %s", fmtId(newuser));
298  if (newpassword)
299  {
300  char *encrypted_password;
301 
302  appendPQExpBufferStr(&sql, " PASSWORD ");
303 
304  encrypted_password = PQencryptPasswordConn(conn,
305  newpassword,
306  newuser,
307  NULL);
308  if (!encrypted_password)
309  pg_fatal("password encryption failed: %s",
311  appendStringLiteralConn(&sql, encrypted_password, conn);
312  PQfreemem(encrypted_password);
313  }
314  if (superuser == TRI_YES)
315  appendPQExpBufferStr(&sql, " SUPERUSER");
316  if (superuser == TRI_NO)
317  appendPQExpBufferStr(&sql, " NOSUPERUSER");
318  if (createdb == TRI_YES)
319  appendPQExpBufferStr(&sql, " CREATEDB");
320  if (createdb == TRI_NO)
321  appendPQExpBufferStr(&sql, " NOCREATEDB");
322  if (createrole == TRI_YES)
323  appendPQExpBufferStr(&sql, " CREATEROLE");
324  if (createrole == TRI_NO)
325  appendPQExpBufferStr(&sql, " NOCREATEROLE");
326  if (inherit == TRI_YES)
327  appendPQExpBufferStr(&sql, " INHERIT");
328  if (inherit == TRI_NO)
329  appendPQExpBufferStr(&sql, " NOINHERIT");
330  if (login == TRI_YES)
331  appendPQExpBufferStr(&sql, " LOGIN");
332  if (login == TRI_NO)
333  appendPQExpBufferStr(&sql, " NOLOGIN");
334  if (replication == TRI_YES)
335  appendPQExpBufferStr(&sql, " REPLICATION");
336  if (replication == TRI_NO)
337  appendPQExpBufferStr(&sql, " NOREPLICATION");
338  if (bypassrls == TRI_YES)
339  appendPQExpBufferStr(&sql, " BYPASSRLS");
340  if (bypassrls == TRI_NO)
341  appendPQExpBufferStr(&sql, " NOBYPASSRLS");
342  if (conn_limit >= -1)
343  appendPQExpBuffer(&sql, " CONNECTION LIMIT %d", conn_limit);
344  if (pwexpiry != NULL)
345  {
346  appendPQExpBufferStr(&sql, " VALID UNTIL ");
347  appendStringLiteralConn(&sql, pwexpiry, conn);
348  }
349  if (roles.head != NULL)
350  {
351  SimpleStringListCell *cell;
352 
353  appendPQExpBufferStr(&sql, " IN ROLE ");
354 
355  for (cell = roles.head; cell; cell = cell->next)
356  {
357  if (cell->next)
358  appendPQExpBuffer(&sql, "%s,", fmtId(cell->val));
359  else
360  appendPQExpBufferStr(&sql, fmtId(cell->val));
361  }
362  }
363  if (members.head != NULL)
364  {
365  SimpleStringListCell *cell;
366 
367  appendPQExpBufferStr(&sql, " ROLE ");
368 
369  for (cell = members.head; cell; cell = cell->next)
370  {
371  if (cell->next)
372  appendPQExpBuffer(&sql, "%s,", fmtId(cell->val));
373  else
374  appendPQExpBufferStr(&sql, fmtId(cell->val));
375  }
376  }
377  if (admins.head != NULL)
378  {
379  SimpleStringListCell *cell;
380 
381  appendPQExpBufferStr(&sql, " ADMIN ");
382 
383  for (cell = admins.head; cell; cell = cell->next)
384  {
385  if (cell->next)
386  appendPQExpBuffer(&sql, "%s,", fmtId(cell->val));
387  else
388  appendPQExpBufferStr(&sql, fmtId(cell->val));
389  }
390  }
391 
392  appendPQExpBufferChar(&sql, ';');
393 
394  if (echo)
395  printf("%s\n", sql.data);
396  result = PQexec(conn, sql.data);
397 
398  if (PQresultStatus(result) != PGRES_COMMAND_OK)
399  {
400  pg_log_error("creation of new role failed: %s", PQerrorMessage(conn));
401  PQfinish(conn);
402  exit(1);
403  }
404 
405  PQclear(result);
406  PQfinish(conn);
407  exit(0);
408 }
409 
410 
411 static void
412 help(const char *progname)
413 {
414  printf(_("%s creates a new PostgreSQL role.\n\n"), progname);
415  printf(_("Usage:\n"));
416  printf(_(" %s [OPTION]... [ROLENAME]\n"), progname);
417  printf(_("\nOptions:\n"));
418  printf(_(" -a, --with-admin=ROLE ROLE will be a member of new role with admin\n"
419  " option\n"));
420  printf(_(" -c, --connection-limit=N connection limit for role (default: no limit)\n"));
421  printf(_(" -d, --createdb role can create new databases\n"));
422  printf(_(" -D, --no-createdb role cannot create databases (default)\n"));
423  printf(_(" -e, --echo show the commands being sent to the server\n"));
424  printf(_(" -g, --member-of=ROLE new role will be a member of ROLE\n"));
425  printf(_(" --role=ROLE (same as --member-of, deprecated)\n"));
426  printf(_(" -i, --inherit role inherits privileges of roles it is a\n"
427  " member of (default)\n"));
428  printf(_(" -I, --no-inherit role does not inherit privileges\n"));
429  printf(_(" -l, --login role can login (default)\n"));
430  printf(_(" -L, --no-login role cannot login\n"));
431  printf(_(" -m, --with-member=ROLE ROLE will be a member of new role\n"));
432  printf(_(" -P, --pwprompt assign a password to new role\n"));
433  printf(_(" -r, --createrole role can create new roles\n"));
434  printf(_(" -R, --no-createrole role cannot create roles (default)\n"));
435  printf(_(" -s, --superuser role will be superuser\n"));
436  printf(_(" -S, --no-superuser role will not be superuser (default)\n"));
437  printf(_(" -v, --valid-until=TIMESTAMP\n"
438  " password expiration date and time for role\n"));
439  printf(_(" -V, --version output version information, then exit\n"));
440  printf(_(" --interactive prompt for missing role name and attributes rather\n"
441  " than using defaults\n"));
442  printf(_(" --bypassrls role can bypass row-level security (RLS) policy\n"));
443  printf(_(" --no-bypassrls role cannot bypass row-level security (RLS) policy\n"
444  " (default)\n"));
445  printf(_(" --replication role can initiate replication\n"));
446  printf(_(" --no-replication role cannot initiate replication (default)\n"));
447  printf(_(" -?, --help show this help, then exit\n"));
448  printf(_("\nConnection options:\n"));
449  printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
450  printf(_(" -p, --port=PORT database server port\n"));
451  printf(_(" -U, --username=USERNAME user name to connect as (not the one to create)\n"));
452  printf(_(" -w, --no-password never prompt for password\n"));
453  printf(_(" -W, --password force password prompt\n"));
454  printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
455  printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
456 }
bool yesno_prompt(const char *question)
Definition: common.c:135
#define PG_TEXTDOMAIN(domain)
Definition: c.h:1193
void set_pglocale_pgservice(const char *argv0, const char *app)
Definition: exec.c:429
PGconn * connectMaintenanceDatabase(ConnParams *cparams, const char *progname, bool echo)
int main(int argc, char *argv[])
Definition: createuser.c:28
static void help(const char *progname)
Definition: createuser.c:412
Oid createdb(ParseState *pstate, const CreatedbStmt *stmt)
Definition: dbcommands.c:683
#define _(x)
Definition: elog.c:90
char * PQencryptPasswordConn(PGconn *conn, const char *passwd, const char *user, const char *algorithm)
Definition: fe-auth.c:1317
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:7200
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4879
void PQfreemem(void *ptr)
Definition: fe-exec.c:4032
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:3411
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2262
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:60
#define no_argument
Definition: getopt_long.h:24
#define required_argument
Definition: getopt_long.h:25
#define free(a)
Definition: header.h:65
static char * username
Definition: initdb.c:153
static bool pwprompt
Definition: initdb.c:154
@ PGRES_COMMAND_OK
Definition: libpq-fe.h:120
exit(1)
void pg_logging_init(const char *argv0)
Definition: logging.c:83
#define pg_log_error(...)
Definition: logging.h:106
#define pg_log_error_hint(...)
Definition: logging.h:112
const char * progname
Definition: main.c:43
bool option_parse_int(const char *optarg, const char *optname, int min_range, int max_range, int *result)
Definition: option_utils.c:50
void handle_help_version_opts(int argc, char *argv[], const char *fixed_progname, help_handler hlp)
Definition: option_utils.c:24
#define pg_fatal(...)
PGDLLIMPORT int optind
Definition: getopt.c:51
PGDLLIMPORT char * optarg
Definition: getopt.c:53
static int port
Definition: pg_regress.c:115
const char * get_progname(const char *argv0)
Definition: path.c:575
#define fprintf
Definition: port.h:242
#define printf(...)
Definition: port.h:244
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:235
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:90
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:265
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:378
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367
char * c
void simple_string_list_append(SimpleStringList *list, const char *val)
Definition: simple_list.c:63
char * simple_prompt(const char *prompt, bool echo)
Definition: sprompt.c:38
PGconn * conn
Definition: streamutil.c:53
void appendStringLiteralConn(PQExpBuffer buf, const char *str, PGconn *conn)
Definition: string_utils.c:293
const char * fmtId(const char *rawid)
Definition: string_utils.c:64
char val[FLEXIBLE_ARRAY_MEMBER]
Definition: simple_list.h:37
struct SimpleStringListCell * next
Definition: simple_list.h:34
SimpleStringListCell * head
Definition: simple_list.h:42
const char * pguser
Definition: connect_utils.h:31
char * override_dbname
Definition: pg_backup.h:92
char * pgport
Definition: pg_backup.h:86
char * pghost
Definition: pg_backup.h:87
char * dbname
Definition: pg_backup.h:85
enum trivalue prompt_password
Definition: connect_utils.h:32
bool superuser(void)
Definition: superuser.c:46
const char * get_user_name_or_exit(const char *progname)
Definition: username.c:74
trivalue
Definition: vacuumlo.c:35
@ TRI_YES
Definition: vacuumlo.c:38
@ TRI_DEFAULT
Definition: vacuumlo.c:36
@ TRI_NO
Definition: vacuumlo.c:37