2929#include <sys/resource.h>
3030#endif
3131
32+ #include "common/username.h"
3233#include "getopt_long.h"
3334#include "libpq/pqcomm.h" /* needed for UNIXSOCK_PATH() */
3435#include "pg_config_paths.h"
@@ -104,6 +105,7 @@ static char *dlpath = PKGLIBDIR;
104105static char * user = NULL ;
105106static _stringlist * extraroles = NULL ;
106107static _stringlist * extra_install = NULL ;
108+ static char * config_auth_datadir = NULL ;
107109
108110/* internal variables */
109111static const char * progname ;
@@ -965,6 +967,150 @@ initialize_environment(void)
965967 load_resultmap ();
966968}
967969
970+ #ifdef ENABLE_SSPI
971+ /*
972+ * Get account and domain/realm names for the current user. This is based on
973+ * pg_SSPI_recvauth(). The returned strings use static storage.
974+ */
975+ static void
976+ current_windows_user (const char * * acct , const char * * dom )
977+ {
978+ static char accountname [MAXPGPATH ];
979+ static char domainname [MAXPGPATH ];
980+ HANDLE token ;
981+ TOKEN_USER * tokenuser ;
982+ DWORD retlen ;
983+ DWORD accountnamesize = sizeof (accountname );
984+ DWORD domainnamesize = sizeof (domainname );
985+ SID_NAME_USE accountnameuse ;
986+
987+ if (!OpenProcessToken (GetCurrentProcess (), TOKEN_READ , & token ))
988+ {
989+ fprintf (stderr ,
990+ _ ("%s: could not open process token: error code %lu\n" ),
991+ progname , GetLastError ());
992+ exit (2 );
993+ }
994+
995+ if (!GetTokenInformation (token , TokenUser , NULL , 0 , & retlen ) && GetLastError () != 122 )
996+ {
997+ fprintf (stderr ,
998+ _ ("%s: could not get token user size: error code %lu\n" ),
999+ progname , GetLastError ());
1000+ exit (2 );
1001+ }
1002+ tokenuser = malloc (retlen );
1003+ if (!GetTokenInformation (token , TokenUser , tokenuser , retlen , & retlen ))
1004+ {
1005+ fprintf (stderr ,
1006+ _ ("%s: could not get token user: error code %lu\n" ),
1007+ progname , GetLastError ());
1008+ exit (2 );
1009+ }
1010+
1011+ if (!LookupAccountSid (NULL , tokenuser -> User .Sid , accountname , & accountnamesize ,
1012+ domainname , & domainnamesize , & accountnameuse ))
1013+ {
1014+ fprintf (stderr ,
1015+ _ ("%s: could not look up account SID: error code %lu\n" ),
1016+ progname , GetLastError ());
1017+ exit (2 );
1018+ }
1019+
1020+ free (tokenuser );
1021+
1022+ * acct = accountname ;
1023+ * dom = domainname ;
1024+ }
1025+
1026+ /*
1027+ * Rewrite pg_hba.conf and pg_ident.conf to use SSPI authentication. Permit
1028+ * the current OS user to authenticate as the bootstrap superuser and as any
1029+ * user named in a --create-role option.
1030+ */
1031+ static void
1032+ config_sspi_auth (const char * pgdata )
1033+ {
1034+ const char * accountname ,
1035+ * domainname ;
1036+ const char * username ;
1037+ char * errstr ;
1038+ char fname [MAXPGPATH ];
1039+ int res ;
1040+ FILE * hba ,
1041+ * ident ;
1042+ _stringlist * sl ;
1043+
1044+ /*
1045+ * "username", the initdb-chosen bootstrap superuser name, may always
1046+ * match "accountname", the value SSPI authentication discovers. The
1047+ * underlying system functions do not clearly guarantee that.
1048+ */
1049+ current_windows_user (& accountname , & domainname );
1050+ username = get_user_name (& errstr );
1051+ if (username == NULL )
1052+ {
1053+ fprintf (stderr , "%s: %s\n" , progname , errstr );
1054+ exit (2 );
1055+ }
1056+
1057+ /* Check a Write outcome and report any error. */
1058+ #define CW (cond ) \
1059+ do { \
1060+ if (!(cond)) \
1061+ { \
1062+ fprintf(stderr, _("%s: could not write to file \"%s\": %s\n"), \
1063+ progname, fname, strerror(errno)); \
1064+ exit(2); \
1065+ } \
1066+ } while (0)
1067+
1068+ res = snprintf (fname , sizeof (fname ), "%s/pg_hba.conf" , pgdata );
1069+ if (res < 0 || res >= sizeof (fname ) - 1 )
1070+ {
1071+ /*
1072+ * Truncating this name is a fatal error, because we must not fail to
1073+ * overwrite an original trust-authentication pg_hba.conf.
1074+ */
1075+ fprintf (stderr , _ ("%s: directory name too long\n" ), progname );
1076+ exit (2 );
1077+ }
1078+ hba = fopen (fname , "w" );
1079+ if (hba == NULL )
1080+ {
1081+ fprintf (stderr , _ ("%s: could not open file \"%s\" for writing: %s\n" ),
1082+ progname , fname , strerror (errno ));
1083+ exit (2 );
1084+ }
1085+ CW (fputs ("# Configuration written by config_sspi_auth()\n" , hba ) >= 0 );
1086+ CW (fputs ("host all all 127.0.0.1/32 sspi include_realm=1 map=regress\n" ,
1087+ hba ) >= 0 );
1088+ CW (fclose (hba ) == 0 );
1089+
1090+ snprintf (fname , sizeof (fname ), "%s/pg_ident.conf" , pgdata );
1091+ ident = fopen (fname , "w" );
1092+ if (ident == NULL )
1093+ {
1094+ fprintf (stderr , _ ("%s: could not open file \"%s\" for writing: %s\n" ),
1095+ progname , fname , strerror (errno ));
1096+ exit (2 );
1097+ }
1098+ CW (fputs ("# Configuration written by config_sspi_auth()\n" , ident ) >= 0 );
1099+
1100+ /*
1101+ * Double-quote for the benefit of account names containing whitespace or
1102+ * '#'. Windows forbids the double-quote character itself, so don't
1103+ * bother escaping embedded double-quote characters.
1104+ */
1105+ CW (fprintf (ident , "regress \"%s@%s\" \"%s\"\n" ,
1106+ accountname , domainname , username ) >= 0 );
1107+ for (sl = extraroles ; sl ; sl = sl -> next )
1108+ CW (fprintf (ident , "regress \"%s@%s\" \"%s\"\n" ,
1109+ accountname , domainname , sl -> str ) >= 0 );
1110+ CW (fclose (ident ) == 0 );
1111+ }
1112+ #endif
1113+
9681114/*
9691115 * Issue a command via psql, connecting to the specified database
9701116 *
@@ -1957,6 +2103,7 @@ help(void)
19572103 printf (_ ("Usage:\n %s [OPTION]... [EXTRA-TEST]...\n" ), progname );
19582104 printf (_ ("\n" ));
19592105 printf (_ ("Options:\n" ));
2106+ printf (_ (" --config-auth=DATADIR update authentication settings for DATADIR\n" ));
19602107 printf (_ (" --create-role=ROLE create the specified role before testing\n" ));
19612108 printf (_ (" --dbname=DB use database DB (default \"regression\")\n" ));
19622109 printf (_ (" --debug turn on debug mode in programs that are run\n" ));
@@ -2023,6 +2170,7 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
20232170 {"launcher" , required_argument , NULL , 21 },
20242171 {"load-extension" , required_argument , NULL , 22 },
20252172 {"extra-install" , required_argument , NULL , 23 },
2173+ {"config-auth" , required_argument , NULL , 24 },
20262174 {NULL , 0 , NULL , 0 }
20272175 };
20282176
@@ -2137,6 +2285,9 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
21372285 case 23 :
21382286 add_stringlist_item (& extra_install , optarg );
21392287 break ;
2288+ case 24 :
2289+ config_auth_datadir = pstrdup (optarg );
2290+ break ;
21402291 default :
21412292 /* getopt_long already emitted a complaint */
21422293 fprintf (stderr , _ ("\nTry \"%s -h\" for more information.\n" ),
@@ -2154,6 +2305,14 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
21542305 optind ++ ;
21552306 }
21562307
2308+ if (config_auth_datadir )
2309+ {
2310+ #ifdef ENABLE_SSPI
2311+ config_sspi_auth (config_auth_datadir );
2312+ #endif
2313+ exit (0 );
2314+ }
2315+
21572316 if (temp_install && !port_specified_by_user )
21582317
21592318 /*
@@ -2298,6 +2457,18 @@ regression_main(int argc, char *argv[], init_function ifunc, test_function tfunc
22982457
22992458 fclose (pg_conf );
23002459
2460+ #ifdef ENABLE_SSPI
2461+
2462+ /*
2463+ * Since we successfully used the same buffer for the much-longer
2464+ * "initdb" command, this can't truncate.
2465+ */
2466+ snprintf (buf , sizeof (buf ), "%s/data" , temp_install );
2467+ config_sspi_auth (buf );
2468+ #elif !defined(HAVE_UNIX_SOCKETS )
2469+ #error Platform has no means to secure the test installation.
2470+ #endif
2471+
23012472 /*
23022473 * Check if there is a postmaster running already.
23032474 */
0 commit comments