1 /*-------------------------------------------------------------------------
2 *
3 * createuser
4 *
5 * Portions Copyright (c) 1996-2021, 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 #include "common.h"
15 #include "common/logging.h"
16 #include "common/string.h"
17 #include "fe_utils/option_utils.h"
18 #include "fe_utils/simple_list.h"
19 #include "fe_utils/string_utils.h"
20
21
22 static void help(const char *progname);
23
24 int
main(int argc,char * argv[])25 main(int argc, char *argv[])
26 {
27 static struct option long_options[] = {
28 {"host", required_argument, NULL, 'h'},
29 {"port", required_argument, NULL, 'p'},
30 {"username", required_argument, NULL, 'U'},
31 {"role", required_argument, NULL, 'g'},
32 {"no-password", no_argument, NULL, 'w'},
33 {"password", no_argument, NULL, 'W'},
34 {"echo", no_argument, NULL, 'e'},
35 {"createdb", no_argument, NULL, 'd'},
36 {"no-createdb", no_argument, NULL, 'D'},
37 {"superuser", no_argument, NULL, 's'},
38 {"no-superuser", no_argument, NULL, 'S'},
39 {"createrole", no_argument, NULL, 'r'},
40 {"no-createrole", no_argument, NULL, 'R'},
41 {"inherit", no_argument, NULL, 'i'},
42 {"no-inherit", no_argument, NULL, 'I'},
43 {"login", no_argument, NULL, 'l'},
44 {"no-login", no_argument, NULL, 'L'},
45 {"replication", no_argument, NULL, 1},
46 {"no-replication", no_argument, NULL, 2},
47 {"interactive", no_argument, NULL, 3},
48 {"connection-limit", required_argument, NULL, 'c'},
49 {"pwprompt", no_argument, NULL, 'P'},
50 {"encrypted", no_argument, NULL, 'E'},
51 {NULL, 0, NULL, 0}
52 };
53
54 const char *progname;
55 int optindex;
56 int c;
57 const char *newuser = NULL;
58 char *host = NULL;
59 char *port = NULL;
60 char *username = NULL;
61 SimpleStringList roles = {NULL, NULL};
62 enum trivalue prompt_password = TRI_DEFAULT;
63 ConnParams cparams;
64 bool echo = false;
65 bool interactive = false;
66 int conn_limit = -2; /* less than minimum valid value */
67 bool pwprompt = false;
68 char *newpassword = NULL;
69
70 /* Tri-valued variables. */
71 enum trivalue createdb = TRI_DEFAULT,
72 superuser = TRI_DEFAULT,
73 createrole = TRI_DEFAULT,
74 inherit = TRI_DEFAULT,
75 login = TRI_DEFAULT,
76 replication = TRI_DEFAULT;
77
78 PQExpBufferData sql;
79
80 PGconn *conn;
81 PGresult *result;
82
83 pg_logging_init(argv[0]);
84 progname = get_progname(argv[0]);
85 set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pgscripts"));
86
87 handle_help_version_opts(argc, argv, "createuser", help);
88
89 while ((c = getopt_long(argc, argv, "h:p:U:g:wWedDsSrRiIlLc:PE",
90 long_options, &optindex)) != -1)
91 {
92 char *endptr;
93
94 switch (c)
95 {
96 case 'h':
97 host = pg_strdup(optarg);
98 break;
99 case 'p':
100 port = pg_strdup(optarg);
101 break;
102 case 'U':
103 username = pg_strdup(optarg);
104 break;
105 case 'g':
106 simple_string_list_append(&roles, optarg);
107 break;
108 case 'w':
109 prompt_password = TRI_NO;
110 break;
111 case 'W':
112 prompt_password = TRI_YES;
113 break;
114 case 'e':
115 echo = true;
116 break;
117 case 'd':
118 createdb = TRI_YES;
119 break;
120 case 'D':
121 createdb = TRI_NO;
122 break;
123 case 's':
124 superuser = TRI_YES;
125 break;
126 case 'S':
127 superuser = TRI_NO;
128 break;
129 case 'r':
130 createrole = TRI_YES;
131 break;
132 case 'R':
133 createrole = TRI_NO;
134 break;
135 case 'i':
136 inherit = TRI_YES;
137 break;
138 case 'I':
139 inherit = TRI_NO;
140 break;
141 case 'l':
142 login = TRI_YES;
143 break;
144 case 'L':
145 login = TRI_NO;
146 break;
147 case 'c':
148 conn_limit = strtol(optarg, &endptr, 10);
149 if (*endptr != '\0' || conn_limit < -1) /* minimum valid value */
150 {
151 pg_log_error("invalid value for --connection-limit: %s",
152 optarg);
153 exit(1);
154 }
155 break;
156 case 'P':
157 pwprompt = true;
158 break;
159 case 'E':
160 /* no-op, accepted for backward compatibility */
161 break;
162 case 1:
163 replication = TRI_YES;
164 break;
165 case 2:
166 replication = TRI_NO;
167 break;
168 case 3:
169 interactive = true;
170 break;
171 default:
172 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
173 exit(1);
174 }
175 }
176
177 switch (argc - optind)
178 {
179 case 0:
180 break;
181 case 1:
182 newuser = argv[optind];
183 break;
184 default:
185 pg_log_error("too many command-line arguments (first is \"%s\")",
186 argv[optind + 1]);
187 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
188 exit(1);
189 }
190
191 if (newuser == NULL)
192 {
193 if (interactive)
194 {
195 newuser = simple_prompt("Enter name of role to add: ", true);
196 }
197 else
198 {
199 if (getenv("PGUSER"))
200 newuser = getenv("PGUSER");
201 else
202 newuser = get_user_name_or_exit(progname);
203 }
204 }
205
206 if (pwprompt)
207 {
208 char *pw2;
209
210 newpassword = simple_prompt("Enter password for new role: ", false);
211 pw2 = simple_prompt("Enter it again: ", false);
212 if (strcmp(newpassword, pw2) != 0)
213 {
214 fprintf(stderr, _("Passwords didn't match.\n"));
215 exit(1);
216 }
217 free(pw2);
218 }
219
220 if (superuser == 0)
221 {
222 if (interactive && yesno_prompt("Shall the new role be a superuser?"))
223 superuser = TRI_YES;
224 else
225 superuser = TRI_NO;
226 }
227
228 if (superuser == TRI_YES)
229 {
230 /* Not much point in trying to restrict a superuser */
231 createdb = TRI_YES;
232 createrole = TRI_YES;
233 }
234
235 if (createdb == 0)
236 {
237 if (interactive && yesno_prompt("Shall the new role be allowed to create databases?"))
238 createdb = TRI_YES;
239 else
240 createdb = TRI_NO;
241 }
242
243 if (createrole == 0)
244 {
245 if (interactive && yesno_prompt("Shall the new role be allowed to create more new roles?"))
246 createrole = TRI_YES;
247 else
248 createrole = TRI_NO;
249 }
250
251 if (inherit == 0)
252 inherit = TRI_YES;
253
254 if (login == 0)
255 login = TRI_YES;
256
257 cparams.dbname = NULL; /* this program lacks any dbname option... */
258 cparams.pghost = host;
259 cparams.pgport = port;
260 cparams.pguser = username;
261 cparams.prompt_password = prompt_password;
262 cparams.override_dbname = NULL;
263
264 conn = connectMaintenanceDatabase(&cparams, progname, echo);
265
266 initPQExpBuffer(&sql);
267
268 printfPQExpBuffer(&sql, "CREATE ROLE %s", fmtId(newuser));
269 if (newpassword)
270 {
271 char *encrypted_password;
272
273 appendPQExpBufferStr(&sql, " PASSWORD ");
274
275 encrypted_password = PQencryptPasswordConn(conn,
276 newpassword,
277 newuser,
278 NULL);
279 if (!encrypted_password)
280 {
281 pg_log_error("password encryption failed: %s",
282 PQerrorMessage(conn));
283 exit(1);
284 }
285 appendStringLiteralConn(&sql, encrypted_password, conn);
286 PQfreemem(encrypted_password);
287 }
288 if (superuser == TRI_YES)
289 appendPQExpBufferStr(&sql, " SUPERUSER");
290 if (superuser == TRI_NO)
291 appendPQExpBufferStr(&sql, " NOSUPERUSER");
292 if (createdb == TRI_YES)
293 appendPQExpBufferStr(&sql, " CREATEDB");
294 if (createdb == TRI_NO)
295 appendPQExpBufferStr(&sql, " NOCREATEDB");
296 if (createrole == TRI_YES)
297 appendPQExpBufferStr(&sql, " CREATEROLE");
298 if (createrole == TRI_NO)
299 appendPQExpBufferStr(&sql, " NOCREATEROLE");
300 if (inherit == TRI_YES)
301 appendPQExpBufferStr(&sql, " INHERIT");
302 if (inherit == TRI_NO)
303 appendPQExpBufferStr(&sql, " NOINHERIT");
304 if (login == TRI_YES)
305 appendPQExpBufferStr(&sql, " LOGIN");
306 if (login == TRI_NO)
307 appendPQExpBufferStr(&sql, " NOLOGIN");
308 if (replication == TRI_YES)
309 appendPQExpBufferStr(&sql, " REPLICATION");
310 if (replication == TRI_NO)
311 appendPQExpBufferStr(&sql, " NOREPLICATION");
312 if (conn_limit >= -1)
313 appendPQExpBuffer(&sql, " CONNECTION LIMIT %d", conn_limit);
314 if (roles.head != NULL)
315 {
316 SimpleStringListCell *cell;
317
318 appendPQExpBufferStr(&sql, " IN ROLE ");
319
320 for (cell = roles.head; cell; cell = cell->next)
321 {
322 if (cell->next)
323 appendPQExpBuffer(&sql, "%s,", fmtId(cell->val));
324 else
325 appendPQExpBufferStr(&sql, fmtId(cell->val));
326 }
327 }
328 appendPQExpBufferChar(&sql, ';');
329
330 if (echo)
331 printf("%s\n", sql.data);
332 result = PQexec(conn, sql.data);
333
334 if (PQresultStatus(result) != PGRES_COMMAND_OK)
335 {
336 pg_log_error("creation of new role failed: %s", PQerrorMessage(conn));
337 PQfinish(conn);
338 exit(1);
339 }
340
341 PQclear(result);
342 PQfinish(conn);
343 exit(0);
344 }
345
346
347 static void
help(const char * progname)348 help(const char *progname)
349 {
350 printf(_("%s creates a new PostgreSQL role.\n\n"), progname);
351 printf(_("Usage:\n"));
352 printf(_(" %s [OPTION]... [ROLENAME]\n"), progname);
353 printf(_("\nOptions:\n"));
354 printf(_(" -c, --connection-limit=N connection limit for role (default: no limit)\n"));
355 printf(_(" -d, --createdb role can create new databases\n"));
356 printf(_(" -D, --no-createdb role cannot create databases (default)\n"));
357 printf(_(" -e, --echo show the commands being sent to the server\n"));
358 printf(_(" -g, --role=ROLE new role will be a member of this role\n"));
359 printf(_(" -i, --inherit role inherits privileges of roles it is a\n"
360 " member of (default)\n"));
361 printf(_(" -I, --no-inherit role does not inherit privileges\n"));
362 printf(_(" -l, --login role can login (default)\n"));
363 printf(_(" -L, --no-login role cannot login\n"));
364 printf(_(" -P, --pwprompt assign a password to new role\n"));
365 printf(_(" -r, --createrole role can create new roles\n"));
366 printf(_(" -R, --no-createrole role cannot create roles (default)\n"));
367 printf(_(" -s, --superuser role will be superuser\n"));
368 printf(_(" -S, --no-superuser role will not be superuser (default)\n"));
369 printf(_(" -V, --version output version information, then exit\n"));
370 printf(_(" --interactive prompt for missing role name and attributes rather\n"
371 " than using defaults\n"));
372 printf(_(" --replication role can initiate replication\n"));
373 printf(_(" --no-replication role cannot initiate replication\n"));
374 printf(_(" -?, --help show this help, then exit\n"));
375 printf(_("\nConnection options:\n"));
376 printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
377 printf(_(" -p, --port=PORT database server port\n"));
378 printf(_(" -U, --username=USERNAME user name to connect as (not the one to create)\n"));
379 printf(_(" -w, --no-password never prompt for password\n"));
380 printf(_(" -W, --password force password prompt\n"));
381 printf(_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
382 printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
383 }
384