1 /*-------------------------------------------------------------------------
5 * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
8 * src/bin/scripts/createuser.c
10 *-------------------------------------------------------------------------
13 #include "postgres_fe.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"
25 static void help(const char *progname
);
28 main(int argc
, char *argv
[])
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},
66 const char *newuser
= 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
;
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
;
82 /* Tri-valued variables. */
83 enum trivalue createdb
= TRI_DEFAULT
,
84 superuser
= TRI_DEFAULT
,
85 createrole
= TRI_DEFAULT
,
86 inherit
= TRI_DEFAULT
,
88 replication
= TRI_DEFAULT
,
89 bypassrls
= TRI_DEFAULT
;
96 pg_logging_init(argv
[0]);
97 progname
= get_progname(argv
[0]);
98 set_pglocale_pgservice(argv
[0], PG_TEXTDOMAIN("pgscripts"));
100 handle_help_version_opts(argc
, argv
, "createuser", help
);
102 while ((c
= getopt_long(argc
, argv
, "a:c:dDeEg:h:iIlLm:p:PrRsSU:v:wW",
103 long_options
, &optindex
)) != -1)
108 simple_string_list_append(&admins
, optarg
);
111 if (!option_parse_int(optarg
, "-c/--connection-limit",
112 -1, INT_MAX
, &conn_limit
))
125 /* no-op, accepted for backward compatibility */
128 simple_string_list_append(&roles
, optarg
);
131 host
= pg_strdup(optarg
);
146 simple_string_list_append(&members
, optarg
);
149 port
= pg_strdup(optarg
);
155 createrole
= TRI_YES
;
167 username
= pg_strdup(optarg
);
170 pwexpiry
= pg_strdup(optarg
);
173 prompt_password
= TRI_NO
;
176 prompt_password
= TRI_YES
;
179 replication
= TRI_YES
;
182 replication
= TRI_NO
;
194 /* getopt_long already emitted a complaint */
195 pg_log_error_hint("Try \"%s --help\" for more information.", progname
);
200 switch (argc
- optind
)
205 newuser
= argv
[optind
];
208 pg_log_error("too many command-line arguments (first is \"%s\")",
210 pg_log_error_hint("Try \"%s --help\" for more information.", progname
);
218 newuser
= simple_prompt("Enter name of role to add: ", true);
222 if (getenv("PGUSER"))
223 newuser
= getenv("PGUSER");
225 newuser
= get_user_name_or_exit(progname
);
233 newpassword
= simple_prompt("Enter password for new role: ", false);
234 pw2
= simple_prompt("Enter it again: ", false);
235 if (strcmp(newpassword
, pw2
) != 0)
237 fprintf(stderr
, _("Passwords didn't match.\n"));
243 if (superuser
== TRI_DEFAULT
)
245 if (interactive
&& yesno_prompt("Shall the new role be a superuser?"))
251 if (superuser
== TRI_YES
)
253 /* Not much point in trying to restrict a superuser */
255 createrole
= TRI_YES
;
258 if (createdb
== TRI_DEFAULT
)
260 if (interactive
&& yesno_prompt("Shall the new role be allowed to create databases?"))
266 if (createrole
== TRI_DEFAULT
)
268 if (interactive
&& yesno_prompt("Shall the new role be allowed to create more new roles?"))
269 createrole
= TRI_YES
;
274 if (bypassrls
== TRI_DEFAULT
)
277 if (replication
== TRI_DEFAULT
)
278 replication
= TRI_NO
;
280 if (inherit
== TRI_DEFAULT
)
283 if (login
== TRI_DEFAULT
)
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
;
293 conn
= connectMaintenanceDatabase(&cparams
, progname
, echo
);
295 initPQExpBuffer(&sql
);
297 printfPQExpBuffer(&sql
, "CREATE ROLE %s", fmtId(newuser
));
300 char *encrypted_password
;
302 appendPQExpBufferStr(&sql
, " PASSWORD ");
304 encrypted_password
= PQencryptPasswordConn(conn
,
308 if (!encrypted_password
)
309 pg_fatal("password encryption failed: %s",
310 PQerrorMessage(conn
));
311 appendStringLiteralConn(&sql
, encrypted_password
, conn
);
312 PQfreemem(encrypted_password
);
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");
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
)
346 appendPQExpBufferStr(&sql
, " VALID UNTIL ");
347 appendStringLiteralConn(&sql
, pwexpiry
, conn
);
349 if (roles
.head
!= NULL
)
351 SimpleStringListCell
*cell
;
353 appendPQExpBufferStr(&sql
, " IN ROLE ");
355 for (cell
= roles
.head
; cell
; cell
= cell
->next
)
358 appendPQExpBuffer(&sql
, "%s,", fmtId(cell
->val
));
360 appendPQExpBufferStr(&sql
, fmtId(cell
->val
));
363 if (members
.head
!= NULL
)
365 SimpleStringListCell
*cell
;
367 appendPQExpBufferStr(&sql
, " ROLE ");
369 for (cell
= members
.head
; cell
; cell
= cell
->next
)
372 appendPQExpBuffer(&sql
, "%s,", fmtId(cell
->val
));
374 appendPQExpBufferStr(&sql
, fmtId(cell
->val
));
377 if (admins
.head
!= NULL
)
379 SimpleStringListCell
*cell
;
381 appendPQExpBufferStr(&sql
, " ADMIN ");
383 for (cell
= admins
.head
; cell
; cell
= cell
->next
)
386 appendPQExpBuffer(&sql
, "%s,", fmtId(cell
->val
));
388 appendPQExpBufferStr(&sql
, fmtId(cell
->val
));
392 appendPQExpBufferChar(&sql
, ';');
395 printf("%s\n", sql
.data
);
396 result
= PQexec(conn
, sql
.data
);
398 if (PQresultStatus(result
) != PGRES_COMMAND_OK
)
400 pg_log_error("creation of new role failed: %s", PQerrorMessage(conn
));
412 help(const char *progname
)
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"
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"
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
);