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