Add empty placeholder LINGUAS file for pg_combinebackup.
[pgsql.git] / src / bin / scripts / createuser.c
blob0709491185c39eb6d7e474ee7e7c39134ace62fe
1 /*-------------------------------------------------------------------------
3 * createuser
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"
15 #include <limits.h>
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"
25 static void help(const char *progname);
27 int
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},
60 {NULL, 0, NULL, 0}
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;
82 /* Tri-valued variables. */
83 enum trivalue createdb = TRI_DEFAULT,
84 superuser = TRI_DEFAULT,
85 createrole = TRI_DEFAULT,
86 inherit = TRI_DEFAULT,
87 login = TRI_DEFAULT,
88 replication = TRI_DEFAULT,
89 bypassrls = TRI_DEFAULT;
91 PQExpBufferData sql;
93 PGconn *conn;
94 PGresult *result;
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)
105 switch (c)
107 case 'a':
108 simple_string_list_append(&admins, optarg);
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':
128 simple_string_list_append(&roles, optarg);
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':
146 simple_string_list_append(&members, optarg);
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':
167 username = pg_strdup(optarg);
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);
200 switch (argc - optind)
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);
214 if (newuser == NULL)
216 if (interactive)
218 newuser = simple_prompt("Enter name of role to add: ", true);
220 else
222 if (getenv("PGUSER"))
223 newuser = getenv("PGUSER");
224 else
225 newuser = get_user_name_or_exit(progname);
229 if (pwprompt)
231 char *pw2;
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"));
238 exit(1);
240 free(pw2);
243 if (superuser == TRI_DEFAULT)
245 if (interactive && yesno_prompt("Shall the new role be a superuser?"))
246 superuser = TRI_YES;
247 else
248 superuser = TRI_NO;
251 if (superuser == TRI_YES)
253 /* Not much point in trying to restrict a superuser */
254 createdb = TRI_YES;
255 createrole = TRI_YES;
258 if (createdb == TRI_DEFAULT)
260 if (interactive && yesno_prompt("Shall the new role be allowed to create databases?"))
261 createdb = TRI_YES;
262 else
263 createdb = TRI_NO;
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;
270 else
271 createrole = TRI_NO;
274 if (bypassrls == TRI_DEFAULT)
275 bypassrls = TRI_NO;
277 if (replication == TRI_DEFAULT)
278 replication = TRI_NO;
280 if (inherit == TRI_DEFAULT)
281 inherit = TRI_YES;
283 if (login == TRI_DEFAULT)
284 login = TRI_YES;
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));
298 if (newpassword)
300 char *encrypted_password;
302 appendPQExpBufferStr(&sql, " PASSWORD ");
304 encrypted_password = PQencryptPasswordConn(conn,
305 newpassword,
306 newuser,
307 NULL);
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");
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)
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)
357 if (cell->next)
358 appendPQExpBuffer(&sql, "%s,", fmtId(cell->val));
359 else
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)
371 if (cell->next)
372 appendPQExpBuffer(&sql, "%s,", fmtId(cell->val));
373 else
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)
385 if (cell->next)
386 appendPQExpBuffer(&sql, "%s,", fmtId(cell->val));
387 else
388 appendPQExpBufferStr(&sql, fmtId(cell->val));
392 appendPQExpBufferChar(&sql, ';');
394 if (echo)
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));
401 PQfinish(conn);
402 exit(1);
405 PQclear(result);
406 PQfinish(conn);
407 exit(0);
411 static void
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"
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);