LCOV - differential code coverage report
Current view: top level - src/bin/scripts - createuser.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 70.9 % 278 197 21 22 10 28 11 50 65 71 23 93 19 11
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 2 2 1 1 1
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a