Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 
     27 #include <strings.h>
     28 #include <errno.h>
     29 #include <unistd.h>
     30 #include <sys/stat.h>
     31 #include <stdlib.h>
     32 #include <fcntl.h>
     33 #include <sys/types.h>
     34 #include <ctype.h>
     35 #include <libnvpair.h>
     36 
     37 #include "mms_mgmt.h"
     38 #include "mgmt_util.h"
     39 #include "mms_cfg.h"
     40 #include "net_cfg_service.h"
     41 
     42 static char *_SrcFile = __FILE__;
     43 #define	HERE _SrcFile, __LINE__
     44 #define	MMS_MGMT_PGA	".pga"
     45 
     46 typedef struct {
     47 	char	port[10];
     48 	char	user[256];
     49 	char	bindir[MAXPATHLEN];
     50 	char	path[MAXPATHLEN];
     51 	char	logdir[MAXPATHLEN];
     52 	char	dbname[MAXPATHLEN];
     53 	char	dbhost[MAXHOSTNAMELEN];
     54 	uid_t	dbuid;
     55 	gid_t	dbgid;
     56 } mmsdb_opts_t;
     57 
     58 /* If this path changes, make sure similar changes are made to mmsexplorer */
     59 static char db_cli_env[1024];
     60 
     61 static int get_db_user(char *buf, int buflen, uid_t *uid, gid_t *gid);
     62 static int configure_pgconf(char *port, char *logdir);
     63 static int get_dbver_from_optfile(char *path, int *version);
     64 static int mk_cmds_from_optfile(mmsdb_opts_t *opts, char *path, int vers,
     65 	char cmdtype, int dopd, char **cmdfile);
     66 static int mgmt_db_sql_exec(char *cmdfile, mmsdb_opts_t *opts);
     67 static int set_mm_system_vars_db(nvlist_t *opts, char *cmdfile);
     68 static int mgmt_get_db_opts(mmsdb_opts_t *opts);
     69 static int create_db_dirs(char *dbpath, uid_t uid, gid_t gid, nvlist_t *errs);
     70 static int update_pghba(boolean_t ismd5, mmsdb_opts_t *dbopts, nvlist_t *errs);
     71 
     72 
     73 /*
     74  *  Functions to manage the MMS Database
     75  */
     76 
     77 int
     78 mgmt_set_db_opts(nvlist_t *opts, nvlist_t *errlist)
     79 {
     80 	int			st = 0;
     81 	mmsdb_opts_t		oldopts;
     82 	int			doconf = 0;
     83 	uid_t			uid = 0;
     84 	gid_t			gid = 0;
     85 	char			*val;
     86 	char			*port = NULL;
     87 	char			*logdir = NULL;
     88 
     89 	if (!mgmt_chk_auth("solaris.mms.modify")) {
     90 		return (EACCES);
     91 	}
     92 
     93 	/*
     94 	 * check to see if any options have been set for the DB yet.  Only
     95 	 * a few are user-configurable.   Changing the DB user is handled
     96 	 * by the admin with SMF and chown -R. (i.e., outside of our CLI,
     97 	 * at least for now)
     98 	 */
     99 	(void) memset(&oldopts, 0, sizeof (mmsdb_opts_t));
    100 
    101 	st = mgmt_get_db_opts(&oldopts);
    102 	if (st != 0) {
    103 		return (st);
    104 	}
    105 
    106 	uid = oldopts.dbuid;
    107 	gid = oldopts.dbgid;
    108 
    109 	/* TODO - should we allow change after set?  Need to copy -R if so */
    110 	st = nvlist_lookup_string(opts, O_DBDIR, &val);
    111 	if (st == 0) {
    112 		st = create_db_dirs(val, uid, gid, errlist);
    113 		if (st != 0) {
    114 			return (st);
    115 		}
    116 	}
    117 
    118 	st = nvlist_lookup_string(opts, O_DBPORT, &port);
    119 	if (st == 0) {
    120 		/* update the conf file */
    121 		doconf = 1;
    122 	}
    123 
    124 	st = nvlist_lookup_string(opts, O_DBLOG, &logdir);
    125 	if (st == 0) {
    126 		/* update the conf file */
    127 		doconf = 1;
    128 		/* create dblogdir if it doesn't exist */
    129 		st = create_dir(logdir, 0711, NULL, uid, NULL, gid);
    130 	}
    131 
    132 	if ((st == 0) && (doconf)) {
    133 		st = configure_pgconf(port, logdir);
    134 	}
    135 
    136 	return (st);
    137 }
    138 
    139 static int
    140 create_db_dirs(char *dbpath, uid_t uid, gid_t gid, nvlist_t *errs)
    141 {
    142 	int		st;
    143 	struct stat64	statbuf;
    144 	char		*dbsubdirs[] = {"dump", "log", NULL};
    145 	int		i;
    146 	char		buf[2048];
    147 
    148 	if (!dbpath) {
    149 		return (MMS_MGMT_NOARG);
    150 	}
    151 
    152 	st = stat64(dbpath, &statbuf);
    153 	if ((st != 0) && (errno != ENOENT)) {
    154 		st = errno;
    155 		MGMT_ADD_ERR(errs, dbpath, st);
    156 		return (st);
    157 	}
    158 
    159 	st = create_dir(dbpath, 0711, NULL, uid, NULL, gid);
    160 	if (st != 0) {
    161 		st = errno;
    162 		MGMT_ADD_ERR(errs, dbpath, st);
    163 		return (st);
    164 	}
    165 
    166 	for (i = 0; dbsubdirs[i] != NULL; i++) {
    167 		(void) snprintf(buf, sizeof (buf), "%s/../%s", dbpath,
    168 		    dbsubdirs[i]);
    169 		st = create_dir(buf, 0711, NULL, uid, NULL, gid);
    170 		if (st != 0) {
    171 			st = errno;
    172 			MGMT_ADD_ERR(errs, buf, st);
    173 			break;
    174 		}
    175 	}
    176 
    177 	return (st);
    178 }
    179 
    180 int
    181 mgmt_db_init(void)
    182 {
    183 	int		st;
    184 	pid_t		pid;
    185 	char		buf[2048];
    186 	char		dbbuf[2048];
    187 	mmsdb_opts_t	opts;
    188 	char		*cmd[4];
    189 
    190 	if (!mgmt_chk_auth("solaris.mms.create")) {
    191 		return (EACCES);
    192 	}
    193 
    194 	st = mgmt_get_db_opts(&opts);
    195 	if (st != 0) {
    196 		mms_trace(MMS_DEBUG,
    197 		    "mgmt_get_db_opts(&opts) error");
    198 		return (st);
    199 	}
    200 
    201 	/* see if we've been initialized already, bail if so */
    202 	(void) snprintf(buf, sizeof (buf), "%s/postgresql.conf", opts.path);
    203 	st = access(buf, F_OK);
    204 	if (st == 0) {
    205 		return (0);
    206 	}
    207 
    208 	(void) snprintf(dbbuf, sizeof (dbbuf), "%s/initdb", opts.bindir);
    209 
    210 	cmd[0] = dbbuf;
    211 	cmd[1] = "-D";
    212 	cmd[2] = opts.path;
    213 	cmd[3] = NULL;
    214 
    215 	pid = exec_mgmt_cmd(NULL, NULL, opts.dbuid, opts.dbgid,
    216 	    B_FALSE, cmd);
    217 	mms_trace(MMS_DEBUG, "exec_mgmt_cmd: %s %s %s", cmd[0], cmd[1], cmd[2]);
    218 
    219 	st = check_exit(pid, NULL);
    220 	if (st != 0)
    221 		mms_trace(MMS_DEBUG,
    222 		    "exec_mgmt_cmd error");
    223 
    224 	return (st);
    225 }
    226 
    227 static int
    228 mgmt_get_db_opts(mmsdb_opts_t *opts)
    229 {
    230 	int		st;
    231 	struct passwd	pwd;
    232 	struct passwd	*pwdp;
    233 	char		buf[2048];
    234 
    235 	if (opts == NULL) {
    236 		return (MMS_MGMT_NOARG);
    237 	}
    238 
    239 	st = mms_cfg_getvar(MMS_CFG_DB_DATA, opts->path);
    240 	if (st == 0) {
    241 		st = mms_cfg_getvar(MMS_CFG_MM_DB_USER, opts->user);
    242 	}
    243 	if (st == 0) {
    244 		st = mms_cfg_getvar(MMS_CFG_MM_DB_HOST, opts->dbhost);
    245 	}
    246 	if (st == 0) {
    247 		st = mms_cfg_getvar(MMS_CFG_MM_DB_PORT, opts->port);
    248 	}
    249 	if (st == 0) {
    250 		st = mms_cfg_getvar(MMS_CFG_MM_DB_NAME, opts->dbname);
    251 	}
    252 	if (st == 0) {
    253 		st = mms_cfg_getvar(MMS_CFG_DB_BIN, opts->bindir);
    254 	}
    255 	if (st == 0) {
    256 		(void) snprintf(opts->logdir, sizeof (opts->logdir),
    257 		    "%s/../log", opts->path);
    258 	}
    259 
    260 	if (st != 0) {
    261 		return (st);
    262 	}
    263 
    264 	(void) getpwnam_r(opts->user, &pwd, buf, sizeof (buf), &pwdp);
    265 	if (pwdp == NULL) {
    266 		return (MMS_MGMT_DB_USER_NOTFOUND);
    267 	}
    268 
    269 	opts->dbuid = pwdp->pw_uid;
    270 	opts->dbgid = pwdp->pw_gid;
    271 
    272 	/* set the envvar for PGPASSFILE */
    273 	(void) snprintf(db_cli_env, sizeof (db_cli_env),
    274 	    "PGPASSFILE=%s/../%s", opts->path, MMS_MGMT_PGA);
    275 	st = putenv(db_cli_env);
    276 
    277 	return (st);
    278 }
    279 
    280 static int
    281 get_db_user(char *buf, int buflen, uid_t *uid, gid_t *gid)
    282 {
    283 	int		st;
    284 	struct passwd	pwd;
    285 	struct passwd	*pwdp;
    286 
    287 	if ((buf == NULL) || (uid == NULL)) {
    288 		return (MMS_MGMT_NOARG);
    289 	}
    290 
    291 	st = mms_cfg_getvar(MMS_CFG_MM_DB_USER, buf);
    292 	if (st != 0) {
    293 		return (st);
    294 	}
    295 
    296 	(void) getpwnam_r(buf, &pwd, buf, buflen, &pwdp);
    297 	if (pwdp == NULL) {
    298 		return (MMS_MGMT_DB_USER_NOTFOUND);
    299 	}
    300 
    301 	*uid = pwdp->pw_uid;
    302 	if (gid != NULL) {
    303 		*gid = pwdp->pw_gid;
    304 	}
    305 
    306 	return (0);
    307 }
    308 
    309 int
    310 mgmt_db_create(int initialize, int populate, nvlist_t *optlist)
    311 {
    312 	int		st;
    313 	pid_t		pid;
    314 	mmsdb_opts_t	opts;
    315 	int		oldver = -1;
    316 	int		ver = -1;
    317 	char		buf[MAXPATHLEN];
    318 	char		*pkgfile = MMSETCDIR"/db/mms_db";
    319 	char		*cmd[7];
    320 	char		dbbuf[2048];
    321 
    322 	mms_trace(MMS_DEBUG, "Creating the MMS Database");
    323 
    324 	if (!mgmt_chk_auth("solaris.mms.modify")) {
    325 		mms_trace(MMS_DEBUG,
    326 		    "mgmt_chk_auth(\"solaris.mms.modify\") error");
    327 		return (EACCES);
    328 	}
    329 
    330 	st = mgmt_get_db_opts(&opts);
    331 	if (st != 0) {
    332 		mms_trace(MMS_DEBUG,
    333 		    "mgmt_get_db_opts(&opts) error");
    334 		return (st);
    335 	}
    336 
    337 	(void) snprintf(dbbuf, sizeof (dbbuf), "%s/createdb", opts.bindir);
    338 
    339 	cmd[0] = dbbuf;
    340 	cmd[1] = "-h";
    341 	cmd[2] = opts.dbhost;
    342 	cmd[3] = "-p";
    343 	cmd[4] = opts.port;
    344 	cmd[5] = opts.dbname;
    345 	cmd[6] = NULL;
    346 
    347 	if (initialize) {
    348 		st = mgmt_db_check();
    349 		if (st == 0) {
    350 			mms_trace(MMS_DEBUG,
    351 			    "EALREADY error");
    352 			/* db is alive, already inited */
    353 			return (EALREADY);
    354 		}
    355 
    356 		/* check to see if files exist, even if svc is stopped */
    357 		(void) snprintf(buf, sizeof (buf), "%s/base", opts.path);
    358 		if (access(buf, F_OK) == 0) {
    359 			mms_trace(MMS_DEBUG,
    360 			    "access(buf, F_OK) error");
    361 			return (EALREADY);
    362 		}
    363 
    364 		st = mgmt_db_init();
    365 		if (st != 0)
    366 			mms_trace(MMS_DEBUG,
    367 			    "mgmt_db_init() error");
    368 		if (st == 0) {
    369 			st = configure_pgconf(opts.port, opts.logdir);
    370 		}
    371 
    372 		if (st != 0) {
    373 			mms_trace(MMS_DEBUG,
    374 			    "configure_pgconf error");
    375 			return (st);
    376 		}
    377 
    378 		/* create the dirs we need */
    379 		st = create_db_dirs(opts.path, opts.dbuid, opts.dbgid, NULL);
    380 		if (st != 0) {
    381 			mms_trace(MMS_DEBUG,
    382 			    "create_db_dirs error");
    383 			return (st);
    384 		}
    385 	}
    386 
    387 	/*
    388 	 * some callers may wish to populate the DB themselves, as in
    389 	 * upgrade or downgrade.
    390 	 */
    391 	if (populate) {
    392 		st = get_dbver_from_optfile(pkgfile, &ver);
    393 		if (st != 0) {
    394 			mms_trace(MMS_DEBUG,
    395 			    "get_dbver_from_optfile error");
    396 			return (st);
    397 		}
    398 
    399 		(void) snprintf(buf, sizeof (buf), "%s/../mmsdb", opts.path);
    400 		st = get_dbver_from_optfile(buf, &oldver);
    401 		if (st != 0) {
    402 			if (st != ENOENT) {
    403 				mms_trace(MMS_DEBUG,
    404 				    "get_dbver_from_optfile error");
    405 				return (st);
    406 			}
    407 			st = 0;
    408 		}
    409 
    410 		if (ver > oldver) {
    411 			if (oldver != -1) {
    412 				/* save the old mod file */
    413 				char	newf[MAXPATHLEN];
    414 
    415 				(void) snprintf(newf, sizeof (newf), "%s-%d",
    416 				    buf, oldver);
    417 				(void) rename(buf, newf);
    418 			}
    419 			st = cp_file(pkgfile, buf);
    420 			if (st != 0) {
    421 				return (st);
    422 			}
    423 			(void) chown(buf, opts.dbuid, opts.dbgid);
    424 		}
    425 	}
    426 
    427 	/* make sure the DB is running */
    428 	mms_trace(MMS_DEBUG, "enable db");
    429 	st = mgmt_set_svc_state(DBSVC, ENABLE, NULL);
    430 	if (st != 0) {
    431 		mms_trace(MMS_DEBUG,
    432 		    "mgmt_set_svc_state error");
    433 		return (st);
    434 	}
    435 
    436 	st = mgmt_db_ready();
    437 	if (st != 0) {
    438 		mms_trace(MMS_ERR,
    439 		    "database did not go ready");
    440 		return (st);
    441 	}
    442 
    443 	pid = exec_mgmt_cmd(NULL, NULL, opts.dbuid, opts.dbgid,
    444 	    B_FALSE, cmd);
    445 	mms_trace(MMS_DEBUG,
    446 	    "exec_mgmt_cmd: %s %s %s %s %s %s",
    447 	    cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5]);
    448 
    449 	st = check_exit(pid, NULL);
    450 	if (st != 0) {
    451 		mms_trace(MMS_DEBUG,
    452 		    "exec_mgmt_cmd error: st %d", st);
    453 	}
    454 
    455 	if ((st == 0) && (populate)) {
    456 		/* import all the sql cmds */
    457 		char		*cmdfile = NULL;
    458 
    459 		st = mk_cmds_from_optfile(&opts, buf, ver, 'u', 1, &cmdfile);
    460 		if ((st == 0) && optlist) {
    461 			st = set_mm_system_vars_db(optlist, cmdfile);
    462 		}
    463 		if (st == 0) {
    464 			st = mgmt_db_sql_exec(cmdfile, &opts);
    465 		}
    466 
    467 		if (cmdfile) {
    468 			(void) unlink(cmdfile);
    469 			free(cmdfile);
    470 		}
    471 
    472 		if (st == 0) {
    473 			char	*passp;
    474 
    475 			st = nvlist_lookup_string(optlist, O_MMPASS, &passp);
    476 			if (st == 0) {
    477 				(void) snprintf(buf, sizeof (buf),
    478 				    "%s_dbadmin", passp);
    479 				st = mgmt_set_db_pass(buf, NULL);
    480 			}
    481 		}
    482 	}
    483 
    484 	return (st);
    485 }
    486 
    487 int
    488 mgmt_db_drop(void)
    489 {
    490 	int		st;
    491 	pid_t		pid;
    492 	mmsdb_opts_t	opts;
    493 	char		*cmd[5];
    494 	char		dbbuf[2048];
    495 
    496 	if (!mgmt_chk_auth("solaris.mms.modify")) {
    497 		return (EACCES);
    498 	}
    499 
    500 	st = mgmt_get_db_opts(&opts);
    501 	if (st != 0) {
    502 		return (st);
    503 	}
    504 
    505 	(void) snprintf(dbbuf, sizeof (dbbuf), "%s/dropdb", opts.bindir);
    506 
    507 	cmd[0] = dbbuf;
    508 	cmd[1] = "-p";
    509 	cmd[2] = opts.port;
    510 	cmd[3] = opts.dbname;
    511 	cmd[4] = NULL;
    512 
    513 	pid = exec_mgmt_cmd(NULL, NULL, opts.dbuid, opts.dbgid,
    514 	    B_FALSE, cmd);
    515 	mms_trace(MMS_DEBUG, "exec_mgmt_cmd: %s %s %s %s",
    516 	    cmd[0], cmd[1], cmd[2], cmd[3]);
    517 
    518 
    519 	st = check_exit(pid, NULL);
    520 
    521 	if (st != 0) {
    522 		/* restart the service to force users to disconnect */
    523 
    524 		mms_trace(MMS_DEBUG, "restart db");
    525 		(void) mgmt_set_svc_state(DBSVC, RESTART, NULL);
    526 
    527 		st = mgmt_db_ready();
    528 		if (st != 0) {
    529 			mms_trace(MMS_ERR,
    530 			    "database did not go ready");
    531 		}
    532 
    533 		if (st == 0) {
    534 			pid = exec_mgmt_cmd(NULL, NULL, opts.dbuid, opts.dbgid,
    535 			    B_FALSE, cmd);
    536 			mms_trace(MMS_DEBUG, "exec_mgmt_cmd: %s %s %s %s",
    537 			    cmd[0], cmd[1], cmd[2], cmd[3]);
    538 
    539 			st = check_exit(pid, NULL);
    540 		}
    541 	}
    542 
    543 	return (st);
    544 }
    545 
    546 int
    547 mgmt_db_ready(void)
    548 {
    549 	int		i;
    550 	int		st;
    551 	pid_t		pid;
    552 	FILE		*readf = NULL;
    553 	mmsdb_opts_t	opts;
    554 	char		*cmd[7];
    555 	char		dbbuf[2048];
    556 
    557 	if (!mgmt_chk_auth("solaris.mms.modify")) {
    558 		return (EACCES);
    559 	}
    560 
    561 	st = mgmt_get_db_opts(&opts);
    562 	if (st != 0) {
    563 		return (st);
    564 	}
    565 
    566 	mms_trace(MMS_DEBUG, "check for database ready");
    567 
    568 	(void) snprintf(dbbuf, sizeof (dbbuf), "%s/psql", opts.bindir);
    569 
    570 	/* simple test to list available databases to check for db ready */
    571 	cmd[0] = dbbuf;
    572 	cmd[1] = "-h";
    573 	cmd[2] = opts.dbhost;
    574 	cmd[3] = "-p";
    575 	cmd[4] = opts.port;
    576 	cmd[5] = "-l";
    577 	cmd[6] = NULL;
    578 
    579 	for (i = 0; i < 30; i++) {
    580 
    581 		/* when the simple test is successful the */
    582 		/* database is ready for socket connections */
    583 
    584 		pid = exec_mgmt_cmd(&readf, NULL, opts.dbuid, opts.dbgid,
    585 		    B_FALSE, cmd);
    586 		mms_trace(MMS_DEBUG, "exec_mgmt_cmd: %s %s %s %s %s %s",
    587 		    cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5]);
    588 
    589 		st = check_exit(pid, NULL);
    590 		if (st == 0) {
    591 			break;
    592 		}
    593 		(void) sleep(1);
    594 	}
    595 
    596 	(void) fclose(readf);
    597 
    598 	return (st);
    599 }
    600 
    601 int
    602 mgmt_db_check(void)
    603 {
    604 	int		st;
    605 	pid_t		pid;
    606 	char		buf[1024];
    607 	FILE		*readf = NULL;
    608 	mmsdb_opts_t	opts;
    609 	char		*cmd[9];
    610 	char		dbbuf[2048];
    611 
    612 	if (!mgmt_chk_auth("solaris.mms.modify")) {
    613 		return (EACCES);
    614 	}
    615 
    616 	st = mgmt_get_db_opts(&opts);
    617 	if (st != 0) {
    618 		return (st);
    619 	}
    620 
    621 	/* test to see if the mms database already exists */
    622 
    623 	(void) snprintf(dbbuf, sizeof (dbbuf), "%s/psql", opts.bindir);
    624 
    625 	cmd[0] = dbbuf;
    626 	cmd[1] = "-h";
    627 	cmd[2] = opts.dbhost;
    628 	cmd[3] = "-p";
    629 	cmd[4] = opts.port;
    630 	cmd[5] = "-t";
    631 	cmd[6] = "-c";
    632 	cmd[7] = buf;
    633 	cmd[8] = NULL;
    634 
    635 	(void) snprintf(buf, sizeof (buf),
    636 	    "SELECT datname FROM pg_database where datname = '%s'",
    637 	    opts.dbname);
    638 
    639 	pid = exec_mgmt_cmd(&readf, NULL, opts.dbuid, opts.dbgid,
    640 	    B_FALSE, cmd);
    641 	mms_trace(MMS_DEBUG, "exec_mgmt_cmd: %s %s %s %s %s %s %s %s",
    642 	    cmd[0], cmd[1], cmd[2], cmd[3], cmd[4],
    643 	    cmd[5], cmd[6], cmd[7]);
    644 
    645 	st = check_exit(pid, NULL);
    646 
    647 	if (st == 0) {
    648 		buf[0] = '\0';
    649 		(void) fgets(buf, sizeof (buf), readf);
    650 		if (buf[0] == '\0') {
    651 			st = -1;
    652 		}
    653 	}
    654 
    655 	(void) fclose(readf);
    656 
    657 	return (st);
    658 }
    659 
    660 int
    661 mgmt_db_dump(char *dumpdir, char *dumpfile, int len)
    662 {
    663 	int		st;
    664 	char		datebuf[256];
    665 	char		filbuf[MAXPATHLEN];
    666 	time_t		now = time(NULL);
    667 	struct tm	*tm = NULL;
    668 	pid_t		pid;
    669 	mmsdb_opts_t	opts;
    670 	char		*cmd[11];
    671 	char		dbbuf[2048];
    672 
    673 	if (!dumpdir || !dumpfile) {
    674 		return (MMS_MGMT_NOARG);
    675 	}
    676 
    677 	if (!mgmt_chk_auth("solaris.mms.modify")) {
    678 		return (EACCES);
    679 	}
    680 
    681 	st = mgmt_get_db_opts(&opts);
    682 	if (st != 0) {
    683 		return (st);
    684 	}
    685 
    686 	tm = localtime(&now);
    687 	(void) strftime(datebuf, sizeof (datebuf),
    688 	    "%Y-""%m-""%dT""%H""%M""%S", tm);
    689 
    690 	(void) snprintf(filbuf, sizeof (filbuf), "%s/mmsdb_dump_%s", dumpdir,
    691 	    datebuf);
    692 
    693 	(void) snprintf(dbbuf, sizeof (dbbuf), "%s/pg_dump", opts.bindir);
    694 
    695 	cmd[0] = dbbuf;
    696 	cmd[1] = "-h";
    697 	cmd[2] = opts.dbhost;
    698 	cmd[3] = "-p";
    699 	cmd[4] = opts.port;
    700 	cmd[5] = "-F";
    701 	cmd[6] = "p";
    702 	cmd[7] = "-f";
    703 	cmd[8] = filbuf;
    704 	cmd[9] = opts.dbname;
    705 	cmd[10] = NULL;
    706 
    707 	if (dumpfile != NULL) {
    708 		(void) strlcpy(dumpfile, filbuf, len);
    709 	}
    710 
    711 	st = create_dir(dumpdir, 0711, NULL, opts.dbuid, NULL, 0);
    712 
    713 	if (st != 0) {
    714 		return (st);
    715 	}
    716 
    717 	pid = exec_mgmt_cmd(NULL, NULL, opts.dbuid, opts.dbgid,
    718 	    B_FALSE, cmd);
    719 	mms_trace(MMS_DEBUG, "exec_mgmt_cmd: %s %s %s %s %s %s %s %s %s %s",
    720 	    cmd[0], cmd[1], cmd[2], cmd[3], cmd[4],
    721 	    cmd[5], cmd[6], cmd[7], cmd[8], cmd[9]);
    722 
    723 	st = check_exit(pid, NULL);
    724 
    725 	return (st);
    726 }
    727 
    728 
    729 /*
    730  *  TODO:  Ensure this is done on the MM server host only when client
    731  *  configs are supported.
    732  */
    733 int
    734 mgmt_db_restore(char *dumpfile)
    735 {
    736 	int		st;
    737 	struct stat64	statbuf;
    738 	char		*mmstate = NULL;
    739 	mmsdb_opts_t	opts;
    740 
    741 	if (!mgmt_chk_auth("solaris.mms.modify")) {
    742 		return (EACCES);
    743 	}
    744 
    745 	st = mgmt_get_db_opts(&opts);
    746 	if (st != 0) {
    747 		return (st);
    748 	}
    749 
    750 	st = stat64(dumpfile, &statbuf);
    751 	if (st != 0) {
    752 		return (MMS_MGMT_DBDUMP_MISSING);
    753 	}
    754 	if (!S_ISREG(statbuf.st_mode)) {
    755 		return (MMS_MGMT_NOT_DBFILE);
    756 	}
    757 
    758 	/* shutdown MM */
    759 	mms_trace(MMS_DEBUG, "disable mm");
    760 	st = mgmt_set_svc_state(MMSVC, DISABLE, &mmstate);
    761 	if (st != 0) {
    762 		if (mmstate) {
    763 			free(mmstate);
    764 		}
    765 		return (st);
    766 	}
    767 
    768 	st = mgmt_db_create(1, 0, NULL);
    769 	if (st != 0) {
    770 		free(mmstate);
    771 		return (st);
    772 	}
    773 
    774 	st = mgmt_db_sql_exec(dumpfile, &opts);
    775 
    776 	if ((st == 0) && (strcmp(mmstate, "online") == 0)) {
    777 		mms_trace(MMS_DEBUG, "enable mm");
    778 		st = mgmt_set_svc_state(MMSVC, ENABLE, NULL);
    779 	}
    780 
    781 	free(mmstate);
    782 	return (st);
    783 }
    784 
    785 typedef struct {
    786 	char	*optnam;
    787 	char	*val;
    788 } pgconf_t;
    789 
    790 static pgconf_t pgconf_opts[] = {
    791 	{"port", NULL},
    792 	{"log_directory", NULL},
    793 	{"external_pid_file", "'postgres.pid'"},
    794 	{"log_destination", "'stderr'"},
    795 	{"logging_collector", "on"},
    796 	{"log_filename", "'log.%a'"},
    797 	{"log_rotation_size", "10000"},
    798 	{"log_truncate_on_rotation", "on"},
    799 	{"log_line_prefix", "'%m %p '"},
    800 	{"client_min_messages", "WARNING"},
    801 	{"log_min_messages", "INFO"},
    802 	{"log_disconnections", "on"},
    803 	{"track_counts", "on"},
    804 	{"autovacuum", "on"},
    805 	{"autovacuum_naptime", "1200"}
    806 };
    807 
    808 static int numpgopts = sizeof (pgconf_opts) / sizeof (pgconf_t);
    809 
    810 static int
    811 configure_pgconf(
    812 	char	*port,
    813 	char	*logdir)
    814 {
    815 	int		st = 0;
    816 	struct stat64	statbuf;
    817 	char		nambuf[256];
    818 	char		buf[MAXPATHLEN];
    819 	char		dbpath[MAXPATHLEN];
    820 	char		logpath[MAXPATHLEN];
    821 	uid_t		uid;
    822 	size_t		sz;
    823 	char		*bufp;
    824 	struct tm	usetime;
    825 	int		infd;
    826 	int		outfd;
    827 	FILE		*infp;
    828 	FILE		*outfp;
    829 	static char	datefmt[] = "%y""%m""%d""%H""%M""%S";
    830 	time_t		now;
    831 	char		filbuf[2048];
    832 	int		i;
    833 	char		*cptr;
    834 	int		changed = 0;
    835 	int		matched = 0;
    836 
    837 	if ((port == NULL) || (logdir == NULL)) {
    838 		return (MMS_MGMT_NOARG);
    839 	}
    840 
    841 	pgconf_opts[0].val = port;
    842 
    843 	/* add quotes around the path */
    844 	(void) snprintf(logpath, sizeof (logpath), "'%s'", logdir);
    845 
    846 	pgconf_opts[1].val = logpath;
    847 
    848 	st = get_db_user(nambuf, sizeof (nambuf), &uid, NULL);
    849 	if (st == 0) {
    850 		st = mms_cfg_getvar(MMS_CFG_DB_DATA, dbpath);
    851 	}
    852 
    853 	if (st != 0) {
    854 		return (st);
    855 	}
    856 
    857 	st = stat64(logdir, &statbuf);
    858 	if (st != 0) {
    859 		st = errno;
    860 		if (st == ENOENT) {
    861 			st = create_dir(logdir, 0711, NULL, uid, NULL, 0);
    862 		}
    863 		if (st != 0) {
    864 			return (st);
    865 		}
    866 	} else {
    867 		if (!S_ISDIR(statbuf.st_mode)) {
    868 			return (ENOTDIR);
    869 		}
    870 	}
    871 
    872 	sz = strlcat(dbpath, "/postgresql.conf", sizeof (dbpath));
    873 	if (sz > sizeof (dbpath)) {
    874 		return (ENAMETOOLONG);
    875 	}
    876 
    877 	st = stat64(dbpath, &statbuf);
    878 	if (st != 0) {
    879 		if (errno != ENOENT) {
    880 			return (errno);
    881 		} else {
    882 			/*
    883 			 * DB not initialized yet, bail without
    884 			 * error as this function will be called
    885 			 * later from db_create.
    886 			 */
    887 			return (0);
    888 		}
    889 	}
    890 
    891 	/* construct the name of the new version of this file */
    892 	now = time(NULL);
    893 	(void) localtime_r(&now, &usetime);
    894 	(void) strftime(nambuf, sizeof (nambuf), datefmt, &usetime);
    895 	(void) snprintf(buf, sizeof (buf), "%s_%s", dbpath, nambuf);
    896 
    897 	/* open the original */
    898 	infd = open64(dbpath, O_RDONLY);
    899 	if (infd == -1) {
    900 		st = errno;
    901 		return (st);
    902 	}
    903 
    904 	infp = fdopen(infd, "r");
    905 	if (infp == NULL) {
    906 		st = errno;
    907 		(void) close(infd);
    908 		return (st);
    909 	}
    910 
    911 	/* open the target file */
    912 	outfd = open64(buf, O_CREAT|O_RDWR, statbuf.st_mode);
    913 	if (outfd == -1) {
    914 		st = errno;
    915 		(void) close(infd);
    916 		return (st);
    917 	}
    918 
    919 	outfp = fdopen(outfd, "w");
    920 	if (outfp == NULL) {
    921 		st = errno;
    922 		(void) fclose(infp);
    923 		(void) close(outfd);
    924 		return (st);
    925 	}
    926 
    927 	/* preserve, as much as possible, the existing format of the file */
    928 	while ((bufp = fgets(filbuf, sizeof (filbuf), infp)) != NULL) {
    929 		matched = 0;
    930 		cptr = NULL;
    931 
    932 		for (; *bufp != '\0'; bufp++) {
    933 			/* options are initially commented out */
    934 			if (*bufp == '#') {
    935 				continue;
    936 			}
    937 			if (!isspace(*bufp)) {
    938 				break;
    939 			}
    940 		}
    941 
    942 		if (*bufp == '\0') {
    943 			(void) fprintf(outfp, "%s", filbuf);
    944 			continue;
    945 		}
    946 
    947 		for (i = 0; i < numpgopts; i++) {
    948 			sz = strlen(pgconf_opts[i].optnam);
    949 			if (strncmp(bufp, pgconf_opts[i].optnam, sz) != 0) {
    950 				continue;
    951 			}
    952 			bufp += sz;
    953 			while ((*bufp != '\0') && (isspace(*bufp))) {
    954 				bufp++;
    955 				sz++;
    956 			}
    957 			if (*bufp == '=') {
    958 				/* found a match - update it */
    959 				matched++;
    960 
    961 				/* TODO:  check really needed to change */
    962 				(void) fprintf(outfp, "%s = %s\n",
    963 				    pgconf_opts[i].optnam, pgconf_opts[i].val);
    964 				cptr = strchr(bufp, '#');
    965 				if (cptr) {
    966 					(void) fprintf(outfp, "\t\t\t\t\t%s",
    967 					    cptr);
    968 				}
    969 				changed++;
    970 				break;
    971 			} else {
    972 				/* superstring or substring of another option */
    973 				bufp -= sz;
    974 			}
    975 		}
    976 
    977 		if (!matched) {
    978 			(void) fprintf(outfp, "%s", filbuf);
    979 		}
    980 	}
    981 	(void) fchown(outfd, statbuf.st_uid, statbuf.st_gid);
    982 	(void) fclose(outfp);
    983 	(void) fclose(infp);
    984 
    985 	/* if we didn't change anything, we're done */
    986 	if (!changed) {
    987 		(void) unlink(buf);
    988 		return (0);
    989 	}
    990 
    991 	/* construct the name of the backup copy of this file */
    992 	(void) localtime_r(&(statbuf.st_mtime), &usetime);
    993 	(void) strftime(nambuf, sizeof (nambuf), datefmt, &usetime);
    994 
    995 	(void) snprintf(filbuf, sizeof (filbuf), "%s_%s", dbpath, nambuf);
    996 
    997 	/* finally, swap em */
    998 	st = rename(dbpath, filbuf);
    999 	if (st != 0) {
   1000 		st = errno;
   1001 		(void) unlink(buf);
   1002 	} else {
   1003 		st = rename(buf, dbpath);
   1004 		if (st != 0) {
   1005 			st = errno;
   1006 		}
   1007 	}
   1008 
   1009 	return (st);
   1010 }
   1011 
   1012 static int
   1013 get_dbver_from_optfile(char *path, int *version)
   1014 {
   1015 	int			st = 0;
   1016 	FILE			*fp = NULL;
   1017 	char			buf[1024];
   1018 	char			*bufp;
   1019 	int			vers = -1;
   1020 	int			last = -1;
   1021 
   1022 	if (!path || !version) {
   1023 		return (ENOENT);
   1024 	}
   1025 
   1026 	st = access(path, R_OK);
   1027 	if (st != 0) {
   1028 		st = errno;
   1029 		return (st);
   1030 	}
   1031 
   1032 	fp = fopen(path, "r");
   1033 	if (fp == NULL) {
   1034 		st = errno;
   1035 		return (errno);
   1036 	}
   1037 
   1038 	while ((bufp = fgets(buf, sizeof (buf), fp)) != NULL) {
   1039 		if ((*bufp != '\0') && (!isdigit(*bufp))) {
   1040 			continue;
   1041 		}
   1042 
   1043 		do {
   1044 			bufp++;
   1045 		} while (isdigit(*bufp));
   1046 
   1047 		if (*bufp != 'u') {
   1048 			continue;
   1049 		}
   1050 
   1051 		*bufp = '\0';
   1052 
   1053 		vers = atoi(buf);
   1054 		if (vers > last) {
   1055 			last = vers;
   1056 		}
   1057 	}
   1058 	(void) fclose(fp);
   1059 
   1060 	*version = last;
   1061 
   1062 	return (st);
   1063 }
   1064 
   1065 static int
   1066 mk_cmds_from_optfile(mmsdb_opts_t *opts, char *path, int vers, char cmdtype,
   1067 	int dopd, char **cmdfile)
   1068 {
   1069 	int			st = 0;
   1070 	int			fd = -1;
   1071 	FILE			*fp = NULL;
   1072 	FILE			*ofp = NULL;
   1073 	char			buf[MAXPATHLEN];
   1074 	char			*bufp;
   1075 	int			started = 0;
   1076 	char			*pass;
   1077 
   1078 	if (!opts || !path || !cmdfile) {
   1079 		return (MMS_MGMT_NOARG);
   1080 	}
   1081 
   1082 	st = access(path, R_OK);
   1083 	if (st != 0) {
   1084 		st = errno;
   1085 		return (st);
   1086 	}
   1087 
   1088 	fp = fopen(path, "r");
   1089 	if (fp == NULL) {
   1090 		st = errno;
   1091 		return (errno);
   1092 	}
   1093 
   1094 	/* create our cmdfile */
   1095 	(void) snprintf(buf, sizeof (buf), "%s/../mmsdbcmd-%c-%d",
   1096 	    opts->path, cmdtype, time(NULL));
   1097 
   1098 	fd = open(buf, O_CREAT|O_TRUNC|O_APPEND|O_WRONLY|O_NOFOLLOW|O_NOLINKS,
   1099 	    0600);
   1100 	if (fd == -1) {
   1101 		st = errno;
   1102 		goto done;
   1103 	}
   1104 
   1105 	/* set this so the pguser can read it */
   1106 	(void) fchown(fd, opts->dbuid, opts->dbgid);
   1107 
   1108 	ofp = fdopen(fd, "a");
   1109 	if (ofp == NULL) {
   1110 		st = errno;
   1111 		(void) close(fd);
   1112 		goto done;
   1113 	}
   1114 
   1115 	*cmdfile = strdup(buf);
   1116 
   1117 	(void) fprintf(ofp, "BEGIN;\n");
   1118 
   1119 	while ((bufp = fgets(buf, sizeof (buf), fp)) != NULL) {
   1120 		if (*bufp == '#') {
   1121 			continue;
   1122 		}
   1123 
   1124 		if (!isdigit(*bufp)) {
   1125 			if (started) {
   1126 				(void) fprintf(ofp, "%s", bufp);
   1127 			}
   1128 			continue;
   1129 		}
   1130 
   1131 		while (isdigit(*bufp)) {
   1132 			bufp++;
   1133 		}
   1134 
   1135 		if (*bufp++ == cmdtype) {
   1136 			started = 1;
   1137 			while (isspace(*buf)) {
   1138 				bufp++;
   1139 			}
   1140 			(void) fprintf(ofp, "%s", bufp);
   1141 		} else {
   1142 			started = 0;
   1143 		}
   1144 	}
   1145 
   1146 	if (dopd) {
   1147 		(void) fclose(fp);
   1148 
   1149 		/* override the junk password in the dbopts file */
   1150 		pass = mms_net_cfg_read_pass_file(MMS_NET_CFG_HELLO_FILE);
   1151 		if (pass != NULL) {
   1152 			(void) fprintf(ofp,
   1153 			    "UPDATE \"MMPASSWORD\" SET \"Password\" = '%s' "
   1154 			    "WHERE \"ApplicationName\" = 'MMS';\n",
   1155 			    pass);
   1156 			free(pass);
   1157 		}
   1158 	}
   1159 
   1160 	/* Set the version and add commit statement */
   1161 	(void) fprintf(ofp,
   1162 	    "UPDATE \"MM\" SET \"DBVersion\" = '%d';\nCOMMIT;\n", vers);
   1163 
   1164 done:
   1165 	if (st != 0) {
   1166 		if (*cmdfile) {
   1167 			(void) unlink(*cmdfile);
   1168 			free(cmdfile);
   1169 			*cmdfile = NULL;
   1170 		}
   1171 	}
   1172 	(void) fclose(fp);
   1173 	(void) fclose(ofp);
   1174 
   1175 	return (st);
   1176 }
   1177 
   1178 static int
   1179 mgmt_db_sql_exec(char *cmdfile, mmsdb_opts_t *opts)
   1180 {
   1181 	int	st;
   1182 	pid_t	pid;
   1183 	FILE	*dberr;
   1184 	char	buf[MAXPATHLEN];
   1185 	char	*cmd[10];
   1186 	char	dbbuf[2048];
   1187 
   1188 	if (!cmdfile || !opts) {
   1189 		return (MMS_MGMT_NOARG);
   1190 	}
   1191 
   1192 	(void) snprintf(dbbuf, sizeof (dbbuf), "%s/psql", opts->bindir);
   1193 
   1194 	cmd[0] = dbbuf;
   1195 	cmd[1] = "-a";
   1196 	cmd[2] = "-h";
   1197 	cmd[3] = opts->dbhost;
   1198 	cmd[4] = "-p";
   1199 	cmd[5] = opts->port;
   1200 	cmd[6] = "-f";
   1201 	cmd[7] = cmdfile;
   1202 	cmd[8] = opts->dbname;
   1203 	cmd[9] = NULL;
   1204 
   1205 	pid = exec_mgmt_cmd(NULL, &dberr, opts->dbuid, opts->dbgid,
   1206 	    B_FALSE, cmd);
   1207 	mms_trace(MMS_DEBUG, "exec_mgmt_cmd: %s %s %s %s %s %s %s %s %s",
   1208 	    cmd[0], cmd[1], cmd[2], cmd[3], cmd[4],
   1209 	    cmd[5], cmd[6], cmd[7], cmd[8]);
   1210 
   1211 	st = check_exit(pid, NULL);
   1212 
   1213 	if (st == 0) {
   1214 		while (fgets(buf, sizeof (buf), dberr) != NULL) {
   1215 			if ((strstr(buf, " ERROR: ") != NULL) ||
   1216 			    (strstr(buf, "ROLLBACK") != NULL)) {
   1217 				st = 1;
   1218 				break;
   1219 			}
   1220 		}
   1221 	}
   1222 	(void) fclose(dberr);
   1223 
   1224 	return (st);
   1225 }
   1226 
   1227 /*
   1228  * this should probably move to a header somewhere, but for
   1229  * now, leave it where it's directly mapped
   1230  */
   1231 typedef struct {
   1232 	char	*mm;
   1233 	char	*ui;
   1234 } mgmt_dbopt_map_t;
   1235 
   1236 /*
   1237  * map of MgmtUI-specified opts to MM options.  NULL indicates
   1238  * not exposed by MgmtUI
   1239  */
   1240 static mgmt_dbopt_map_t mm_sys_opts[] = {
   1241 	{"AttendanceMode", O_ATTENDED},
   1242 	{"SystemLogLevel", O_LOGLEVEL},
   1243 	{"SystemLogFile", O_LOGFILE},
   1244 	{"MessageLevel", O_MSGLEVEL},
   1245 	{"TraceLevel", O_TRACELEVEL},
   1246 	{"TraceFileSize", O_TRACESZ},
   1247 	{"SocketFdLimit", O_NUMSOCKET},
   1248 	{"SystemDiskMountTimeout", O_DKTIMEOUT},
   1249 	{"WatcherStartsLimit", O_NUMRESTART},
   1250 	{"SystemAcceptLevel", NULL},
   1251 	{"SystemMessageLimit", NULL},
   1252 	{"SystemMessageCount", NULL},
   1253 	{"SystemRequestLimit", NULL},
   1254 	{"SystemRequestCount", NULL},
   1255 	{"SystemSyncLimit", NULL},
   1256 	{"SystemDCALimit", NULL},
   1257 	{"SystemDCACount", NULL},
   1258 	{"ClearDriveAtLMConfig", NULL},
   1259 	{"AskClearDriveAtLMConfig", NULL},
   1260 	{"PreemptReservation", NULL},
   1261 	{"SystemLogFileSize", NULL},
   1262 	{"SystemName", NULL},
   1263 	{"SystemInstance", NULL},
   1264 	{"UnloadDelayTime", NULL},
   1265 	{"DefaultBlocksize", NULL},
   1266 	{"WatcherTimeLimit", NULL},
   1267 	{"DriveRecordRetention", NULL},
   1268 	{NULL, NULL}
   1269 };
   1270 
   1271 /* add the MM options to the database before creation, if we know them */
   1272 static int
   1273 set_mm_system_vars_db(nvlist_t *opts, char *cmdfile)
   1274 {
   1275 	int		st;
   1276 	char		*val = NULL;
   1277 	int		i;
   1278 	int		fd = -1;
   1279 	FILE		*ofp = NULL;
   1280 	struct stat	sb;
   1281 	int		changed = 0;
   1282 
   1283 	if (!opts) {
   1284 		return (0);
   1285 	}
   1286 
   1287 	if (!cmdfile) {
   1288 		return (MMS_MGMT_NOARG);
   1289 	}
   1290 
   1291 	fd = open(cmdfile, O_RDWR|O_NOFOLLOW|O_NOLINKS);
   1292 	if (fd == -1) {
   1293 		return (errno);
   1294 	}
   1295 	st = fstat(fd, &sb);
   1296 	if (st != 0) {
   1297 		st = errno;
   1298 		(void) close(fd);
   1299 		return (st);
   1300 	}
   1301 
   1302 	ofp = fdopen(fd, "a");
   1303 	if (ofp == NULL) {
   1304 		st = errno;
   1305 		(void) close(fd);
   1306 		return (st);
   1307 	}
   1308 
   1309 	for (i = 0; mm_sys_opts[i].mm != NULL; i++) {
   1310 		if (mm_sys_opts[i].ui == NULL) {
   1311 			continue;
   1312 		}
   1313 		st = nvlist_lookup_string(opts, mm_sys_opts[i].ui, &val);
   1314 		if ((st == 0) && val) {
   1315 			if (!changed) {
   1316 				(void) fprintf(ofp, "BEGIN;\n");
   1317 			}
   1318 			(void) fprintf(ofp,
   1319 			    "UPDATE \"SYSTEM\" SET \"%s\" = '%s';\n",
   1320 			    mm_sys_opts[i].mm, val);
   1321 
   1322 			changed++;
   1323 		}
   1324 	}
   1325 
   1326 	if (changed) {
   1327 		(void) fprintf(ofp, "COMMIT;\n");
   1328 	}
   1329 
   1330 	(void) fclose(ofp);
   1331 
   1332 	return (0);
   1333 }
   1334 
   1335 int
   1336 mgmt_set_db_pass(char *dbpass, nvlist_t *errs)
   1337 {
   1338 	int		st;
   1339 	mmsdb_opts_t	opts;
   1340 	char		buf[2048];
   1341 	boolean_t	ismd5 = B_FALSE;
   1342 	int		fd = -1;
   1343 	int		wr = 0;
   1344 	char		file[MAXPATHLEN];
   1345 
   1346 	/* no provided password means use 'trust' */
   1347 	if (dbpass) {
   1348 		ismd5 = B_TRUE;
   1349 	}
   1350 
   1351 	st = mgmt_get_db_opts(&opts);
   1352 	if (st != 0) {
   1353 		return (st);
   1354 	}
   1355 
   1356 	/* tell Postgres to use the new password */
   1357 	(void) snprintf(file, sizeof (file), "%s/../tsql", opts.path);
   1358 	fd = open64(file, O_CREAT|O_TRUNC|O_WRONLY, 0600);
   1359 	if (fd == -1) {
   1360 		st = errno;
   1361 		MGMT_ADD_ERR(errs, file, st);
   1362 		return (st);
   1363 	}
   1364 
   1365 	(void) fchown(fd, opts.dbuid, opts.dbgid);
   1366 
   1367 	(void) snprintf(buf, sizeof (buf),
   1368 	    "alter user postgres with password '%s' valid until 'infinity';",
   1369 	    dbpass);
   1370 	wr = write_buf(fd, buf, strlen(buf));
   1371 	(void) close(fd);
   1372 
   1373 	if (wr == -1) {
   1374 		MGMT_ADD_ERR(errs, file, EIO);
   1375 		(void) unlink(file);
   1376 		return (EIO);
   1377 	}
   1378 
   1379 	st = mgmt_db_sql_exec(file, &opts);
   1380 	if (st != 0) {
   1381 		MGMT_ADD_ERR(errs, "postgres failure", st);
   1382 		(void) unlink(file);
   1383 		return (st);
   1384 	}
   1385 
   1386 	(void) unlink(file);
   1387 
   1388 	/* next, set up the conf file */
   1389 	st = update_pghba(ismd5, &opts, errs);
   1390 	if (st != 0) {
   1391 		return (st);
   1392 	}
   1393 
   1394 	/* write the PGPASSFILE */
   1395 	(void) snprintf(file, sizeof (file), "%s/../%s",
   1396 	    opts.path, MMS_MGMT_PGA);
   1397 	fd = open64(file, O_CREAT|O_TRUNC|O_WRONLY, 0600);
   1398 	if (fd == -1) {
   1399 		st = errno;
   1400 		MGMT_ADD_ERR(errs, file, st);
   1401 		return (st);
   1402 	}
   1403 	(void) fchown(fd, opts.dbuid, opts.dbgid);
   1404 
   1405 	(void) snprintf(buf, sizeof (buf), "*:*:*:*:%s", dbpass);
   1406 	wr = write_buf(fd, buf, strlen(buf));
   1407 	(void) close(fd);
   1408 
   1409 	if (wr == -1) {
   1410 		MGMT_ADD_ERR(errs, file, EIO);
   1411 		(void) unlink(file);
   1412 		return (EIO);
   1413 	}
   1414 
   1415 	st = mms_net_cfg_write_pass_file(MMS_NET_CFG_DB_FILE, dbpass);
   1416 	if (st != 0) {
   1417 		return (st);
   1418 	}
   1419 
   1420 	/* restart the db */
   1421 	mms_trace(MMS_DEBUG, "restart db");
   1422 	st = mgmt_set_svc_state(DBSVC, RESTART, NULL);
   1423 
   1424 	if (st == 0) {
   1425 		st = mgmt_db_ready();
   1426 		if (st != 0) {
   1427 			mms_trace(MMS_ERR,
   1428 			    "database did not go ready");
   1429 		}
   1430 	}
   1431 
   1432 	return (st);
   1433 }
   1434 
   1435 static int
   1436 update_pghba(boolean_t ismd5, mmsdb_opts_t *dbopts, nvlist_t *errs)
   1437 {
   1438 	int		st;
   1439 	char		buf[2048];
   1440 	char		*bufp;
   1441 	int		infd = -1;
   1442 	int		outfd = -1;
   1443 	FILE		*infp = NULL;
   1444 	FILE		*outfp = NULL;
   1445 	struct stat64	statbuf;
   1446 	char		confpath[2048];
   1447 	char		newconfpath[2048];
   1448 	time_t		now;
   1449 	struct tm	usetime;
   1450 	static char	datefmt[] = "%y""%m""%d""%H""%M""%S";
   1451 	boolean_t	changed = B_FALSE;
   1452 	char		timebuf[256];
   1453 
   1454 	if (!dbopts) {
   1455 		return (MMS_MGMT_NOARG);
   1456 	}
   1457 
   1458 	(void) snprintf(confpath, sizeof (confpath), "%s/pg_hba.conf",
   1459 	    dbopts->path);
   1460 
   1461 	st = stat64(confpath, &statbuf);
   1462 	if (st != 0) {
   1463 		st = errno;
   1464 		MGMT_ADD_ERR(errs, confpath, st);
   1465 		return (st);
   1466 	}
   1467 
   1468 	/* construct the name of the new version of this file */
   1469 	now = time(NULL);
   1470 	(void) localtime_r(&now, &usetime);
   1471 	(void) strftime(timebuf, sizeof (timebuf), datefmt, &usetime);
   1472 	(void) snprintf(newconfpath, sizeof (newconfpath), "%s_%s", confpath,
   1473 	    timebuf);
   1474 
   1475 	/* open the original */
   1476 	infd = open64(confpath, O_RDONLY);
   1477 	if (infd == -1) {
   1478 		st = errno;
   1479 		MGMT_ADD_ERR(errs, confpath, st);
   1480 		return (st);
   1481 	}
   1482 
   1483 	infp = fdopen(infd, "r");
   1484 	if (infp == NULL) {
   1485 		st = errno;
   1486 		MGMT_ADD_ERR(errs, confpath, st);
   1487 		(void) close(infd);
   1488 		return (st);
   1489 	}
   1490 
   1491 	/* open the target file */
   1492 	outfd = open64(newconfpath, O_CREAT|O_RDWR, 0600);
   1493 	if (outfd == -1) {
   1494 		st = errno;
   1495 		(void) close(infd);
   1496 		MGMT_ADD_ERR(errs, newconfpath, st);
   1497 		return (st);
   1498 	}
   1499 
   1500 	outfp = fdopen(outfd, "w");
   1501 	if (outfp == NULL) {
   1502 		st = errno;
   1503 		(void) fclose(infp);
   1504 		(void) close(outfd);
   1505 		MGMT_ADD_ERR(errs, newconfpath, st);
   1506 		return (st);
   1507 	}
   1508 
   1509 	/* preserve, as much as possible, the existing format of the file */
   1510 	while ((bufp = fgets(buf, sizeof (buf), infp)) != NULL) {
   1511 		while (isspace(*bufp)) {
   1512 			bufp++;
   1513 		}
   1514 
   1515 		if ((*bufp == '\0') || (*bufp == '#')) {
   1516 			(void) fprintf(outfp, "%s", buf);
   1517 			continue;
   1518 		}
   1519 
   1520 		/* look for 'trust' or 'md5' */
   1521 		if (ismd5) {
   1522 			/* changing to password-protected */
   1523 			bufp = strstr(buf, "trust");
   1524 			if (bufp) {
   1525 				(void) strlcpy(bufp, "md5\n", 7);
   1526 				changed = B_TRUE;
   1527 			}
   1528 		} else {
   1529 			/* removing password protection */
   1530 			bufp = strstr(buf, "md5");
   1531 			if (bufp) {
   1532 				(void) strlcpy(bufp, "trust\n", 7);
   1533 				changed = B_TRUE;
   1534 			}
   1535 		}
   1536 
   1537 		(void) fprintf(outfp, "%s", buf);
   1538 	}
   1539 
   1540 	(void) fchown(outfd, dbopts->dbuid, dbopts->dbgid);
   1541 	(void) fclose(outfp);
   1542 	(void) fclose(infp);
   1543 
   1544 	/* if we didn't change anything, we're done */
   1545 	if (!changed) {
   1546 		(void) unlink(newconfpath);
   1547 		return (0);
   1548 	}
   1549 
   1550 	/* construct the name of the backup copy of this file */
   1551 	(void) localtime_r(&(statbuf.st_mtime), &usetime);
   1552 	(void) strftime(timebuf, sizeof (timebuf), datefmt, &usetime);
   1553 
   1554 	(void) snprintf(buf, sizeof (buf), "%s_%s", confpath, timebuf);
   1555 
   1556 	/* finally, swap em */
   1557 	st = rename(confpath, buf);
   1558 	if (st != 0) {
   1559 		st = errno;
   1560 		(void) unlink(buf);
   1561 		MGMT_ADD_ERR(errs, confpath, st);
   1562 	} else {
   1563 		st = rename(newconfpath, confpath);
   1564 		if (st != 0) {
   1565 			st = errno;
   1566 			MGMT_ADD_ERR(errs, newconfpath, st);
   1567 		}
   1568 	}
   1569 
   1570 	return (st);
   1571 }
   1572