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