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 static char *_SrcFile = __FILE__; /* Using __FILE__ makes duplicate strings */
     27 
     28 /*
     29  * various utility functions
     30  */
     31 
     32 #include <stdlib.h>
     33 #include <stdio.h>
     34 #include <errno.h>
     35 #include <sys/stat.h>
     36 #include <sys/types.h>
     37 #include <sys/param.h>
     38 #include <sys/wait.h>
     39 #include <unistd.h>
     40 #include <string.h>
     41 #include <stdarg.h>
     42 #include <time.h>
     43 #include <sys/mnttab.h>
     44 #include <libgen.h>
     45 #include <pwd.h>
     46 #include <grp.h>
     47 #include <ctype.h>
     48 #include <fcntl.h>
     49 #include <unistd.h>
     50 #include <procfs.h>
     51 #include <dirent.h>
     52 #include <auth_attr.h>
     53 #include <secdb.h>
     54 
     55 #include "mgmt_util.h"
     56 #include "mmp_defs.h"
     57 #include "mms_cfg.h"
     58 
     59 /* forward declarations */
     60 static int file_chown(char *file, struct stat64 *statbuf, char *user,
     61 	char *group);
     62 static int file_chown_id(char *file, struct stat64 *statbuf, uid_t uid,
     63 	gid_t gid);
     64 static void
     65 filter_on_var(char *varname, char **varray, int count, nvlist_t *nvl);
     66 
     67 /* error messages */
     68 static mms_sym_t	mms_mgmt_errs[] = {
     69 	"Internal error; missing argument",
     70 	MMS_MGMT_NOARG,
     71 	"Could not exec ACSLS ssi daemon",
     72 	MMS_MGMT_ERR_EXEC_SSI,
     73 	"Could not communicate with ACSLS server",
     74 	MMS_MGMT_ERR_ACSLS_COMM,
     75 	"Received invalid response from ACSLS server",
     76 	MMS_MGMT_ERR_ACSLS_RSP,
     77 	"Could not parse response from ACSLS server",
     78 	MMS_MGMT_ERR_ACSLS_PARSE,
     79 	"Missing required option",
     80 	MMS_MGMT_ERR_REQUIRED,
     81 	"Could not determine MM host",
     82 	MMS_MGMT_NO_MMHOST,
     83 	"Volume in use",
     84 	MMS_MGMT_CARTRIDGE_INUSE,
     85 	"Could not access database backup",
     86 	MMS_MGMT_DBDUMP_MISSING,
     87 	"Unknown response type",
     88 	MMS_MGMT_RSP_UNKNOWN,
     89 	"Request cancelled",
     90 	MMS_MGMT_RSP_CANCELLED,
     91 	"Request not accepted",
     92 	MMS_MGMT_REQ_NOT_ACCEPTED,
     93 	"Could not determine group",
     94 	MMS_MGMT_ERR_GROUP,
     95 	"Could not determine user",
     96 	MMS_MGMT_ERR_USER,
     97 	"Option applies to MM server host only",
     98 	MMS_MGMT_ERR_SVRONLY,
     99 	"Volume not unique",
    100 	MMS_MGMT_ERR_CART_NOT_UNIQUE,
    101 	"Partition not unique",
    102 	MMS_MGMT_ERR_PARTITION_NOT_UNIQUE,
    103 	"Volume not labeled",
    104 	MMS_MGMT_VOL_NOT_INIT,
    105 	"No usable volume found",
    106 	MMS_MGMT_NO_USABLE_VOL,
    107 	"Could not find ACSLS client libraries",
    108 	MMS_MGMT_ACSLS_NOT_FOUND,
    109 	"MMS is not initialized or not running",
    110 	MMS_MGMT_MMS_NOT_INIT,
    111 	"Drives on remote systems cannot be configured at this time",
    112 	MMS_MGMT_REMOTE_NOT_SUPP,
    113 	"Operation requires a password",
    114 	MMS_MGMT_PASSWORD_REQUIRED,
    115 	"Volume not mounted",
    116 	MMS_MGMT_VOL_NOT_MOUNTED,
    117 	"Not authorized.  Use the correct application/password combination.",
    118 	MMS_MGMT_NOT_AUTHORIZED,
    119 	"Password validation failed",
    120 	MMS_MGMT_PASSWD_MISMATCH,
    121 	"Failed to get the password",
    122 	MMS_MGMT_GETPASS_FAILED,
    123 	"Password must be 8 characters or longer.",
    124 	MMS_MGMT_PASSTOOSHORT,
    125 	"Internal error:  MMP parsing failed",
    126 	MMS_MGMT_MMP_PARSE_ERR,
    127 	"Application is still using one or more volumes.",
    128 	MMS_MGMT_APP_VOLS_EXIST,
    129 	"Not a valid MMS database backup file",
    130 	MMS_MGMT_NOT_DBFILE,
    131 	"Database Administrator user account not found",
    132 	MMS_MGMT_DB_USER_NOTFOUND,
    133 	"Default DISK lib path invalid",
    134 	MMS_MGMT_INVALID_PATH,
    135 	"Invalid hostpath format. Must be hostname@path",
    136 	MMS_MGMT_INV_HOSTPATH,
    137 	"Library already exists",
    138 	MMS_MGMT_LIB_EXISTS,
    139 	"Library does not exist",
    140 	MMS_MGMT_LIB_NOT_EXIST,
    141 	"Must specify hardware type",
    142 	MMS_MGMT_NO_HWTYPE,
    143 	"Must specify volume type",
    144 	MMS_MGMT_NO_VOLTYPE,
    145 	"Cannot get library DefaultPath",
    146 	MMS_MGMT_DFLTPATH_ERR,
    147 	"dpool does not exist. Create it first.",
    148 	MMS_MGMT_DG_NOT_EXIST,
    149 	"mpool does not exist. Create it first.",
    150 	MMS_MGMT_CG_NOT_EXIST,
    151 	"voltype does not exist. Create it first.",
    152 	MMS_MGMT_SHOW_CT_ERR,
    153 	"show voltype error",
    154 	MMS_MGMT_CT_NOT_EXIST,
    155 	"voltype does not exist. Create it first",
    156 	MMS_MGMT_SN_ERR,
    157 	"missing required arguement",
    158 	MMS_MGMT_REQ_ARG,
    159 	"create PARTITION error",
    160 	MMS_MGMT_CREATE_PART_ERR,
    161 	"create CARTRIDGE error",
    162 	MMS_MGMT_CREATE_CART_ERR,
    163 	"invalid readonly value",
    164 	MMS_MGMT_INVALID_READONLY,
    165 };
    166 
    167 /*
    168  * mms_gen_taskid()
    169  *
    170  * Parameters:
    171  *      - tid           unique task identifier.
    172  *
    173  * This function returns a task identifier (TID). All responses to an MMP
    174  * command will include the TID of the initiating command. The TID will be
    175  * unique in the context of a session so that the client can determine which
    176  * responses go with which command.
    177  */
    178 int
    179 mms_gen_taskid(char *tid)
    180 {
    181 	if (!tid) {
    182 		return (MMS_MGMT_NOARG);
    183 	}
    184 
    185 	(void) sprintf(tid, "%d-%ld", (int)getpid(), time(NULL));
    186 
    187 	return (0);
    188 }
    189 
    190 /*
    191  * create the directory dir. This function will not fail if the directory
    192  * already exists.
    193  */
    194 int
    195 create_dir(char *dir, mode_t perms, char *user, uid_t uid, char *group,
    196 	gid_t gid)
    197 {
    198 
    199 	struct stat64	dir_stat;
    200 	int		st = 0;
    201 
    202 	if (!dir) {
    203 		return (MMS_MGMT_NOARG);
    204 	}
    205 
    206 	if (perms == 0) {
    207 		/* make the dir rwx by owner, and rx by other and group */
    208 		perms = 0 | S_IRWXU | S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP;
    209 	}
    210 
    211 	mms_trace(MMS_INFO, "creating directory %s", dir);
    212 	errno = 0;
    213 	if (stat64(dir, &dir_stat) == 0) {
    214 		if (!S_ISDIR(dir_stat.st_mode)) {
    215 
    216 			/* TBD: set errno and errmsg */
    217 			return (ENOTDIR);
    218 		}
    219 	} else if (errno == ENOENT) {
    220 		errno = 0;
    221 		st = mkdirp(dir, perms);
    222 		if (st != 0) {
    223 			return (errno);
    224 		}
    225 		(void) stat64(dir, &dir_stat);
    226 	}
    227 
    228 	if (uid == 0) {
    229 		st = file_chown(dir, &dir_stat, user, group);
    230 	} else {
    231 		st = file_chown_id(dir, &dir_stat, uid, gid);
    232 	}
    233 
    234 	return (st);
    235 }
    236 
    237 static int
    238 file_chown(char *file, struct stat64 *statbuf, char *user, char *group)
    239 {
    240 	struct passwd	pwd;
    241 	struct passwd	*pwdp;
    242 	struct group	gr;
    243 	struct group	*grp;
    244 	char		buf[1024];
    245 	uid_t		uid = 0;
    246 	gid_t		gid = 0;
    247 	int		st;
    248 
    249 	if ((file == NULL) || (statbuf == NULL)) {
    250 		return (MMS_MGMT_NOARG);
    251 	}
    252 
    253 	if (user == NULL) {
    254 		/* nothing to do */
    255 		return (0);
    256 	}
    257 
    258 	(void) getpwnam_r(user, &pwd, buf, sizeof (buf), &pwdp);
    259 	if (pwdp == NULL) {
    260 		return (MMS_MGMT_ERR_USER);
    261 	}
    262 	uid = pwdp->pw_uid;
    263 	gid = pwdp->pw_gid;	/* default to user's default group */
    264 
    265 	if (group != NULL) {
    266 		(void) getgrnam_r(group, &gr, buf, sizeof (buf), &grp);
    267 		if (grp == NULL) {
    268 			return (MMS_MGMT_ERR_GROUP);
    269 		}
    270 		gid = grp->gr_gid;
    271 	}
    272 
    273 	st = file_chown_id(file, statbuf, uid, gid);
    274 
    275 	return (st);
    276 }
    277 
    278 static int
    279 file_chown_id(char *file, struct stat64 *statbuf, uid_t uid, gid_t gid)
    280 {
    281 	int	st;
    282 
    283 	if ((file == NULL) || (statbuf == NULL)) {
    284 		return (MMS_MGMT_NOARG);
    285 	}
    286 
    287 	if ((uid == 0) && (gid == 0)) {
    288 		/* nothing to do */
    289 		return (0);
    290 	}
    291 
    292 	if ((statbuf->st_uid == uid) && (statbuf->st_gid == gid)) {
    293 		/* nothing to do */
    294 		return (0);
    295 	}
    296 
    297 	st = chown(file, uid, gid);
    298 
    299 	return (st);
    300 }
    301 
    302 int cp_file(
    303 	const char *old,
    304 	const char *new)
    305 {
    306 	int		oldfd = -1;
    307 	int		newfd = -1;
    308 	struct stat	oldstatbuf;
    309 	struct stat	newstatbuf;
    310 	int		res;
    311 	int		saverr = 0;
    312 	struct timeval	oldtimes[2];
    313 	char		buf[8192];
    314 	int		wlen;
    315 	ssize_t		oldlen;
    316 
    317 	mms_trace(MMS_DEBUG, "copying file %s to %s", old, new);
    318 
    319 	/* make sure old exists */
    320 	res = stat(old, &oldstatbuf);
    321 	if (res != 0) {
    322 		return (errno);
    323 	}
    324 
    325 	/* if the target exists, remove it */
    326 	res = stat(new, &newstatbuf);
    327 	if (res == 0) {
    328 		mms_trace(MMS_DEBUG, "cp_file: removing %s", new);
    329 		(void) unlink(new);
    330 	}
    331 
    332 	/* save the access & mod times so they can be reset */
    333 	oldtimes[0].tv_sec = oldstatbuf.st_atim.tv_sec;
    334 	oldtimes[0].tv_usec = oldstatbuf.st_atim.tv_nsec / 1000;
    335 	oldtimes[1].tv_sec = oldstatbuf.st_mtim.tv_sec;
    336 	oldtimes[1].tv_usec = oldstatbuf.st_mtim.tv_nsec / 1000;
    337 
    338 	oldfd = open(old, O_RDONLY, oldstatbuf.st_mode);
    339 	if (oldfd == -1) {
    340 		res = errno;
    341 		mms_trace(MMS_ERR, "Error opening %s, %d", old, res);
    342 		return (res);
    343 	}
    344 	newfd = open(new, O_WRONLY|O_CREAT|O_EXCL, oldstatbuf.st_mode);
    345 	if (newfd == -1) {
    346 		res = errno;
    347 		(void) close(oldfd);
    348 		mms_trace(MMS_ERR, "Error opening %s, %d", new, res);
    349 		return (res);
    350 	}
    351 
    352 	/* finally, copy the file */
    353 	res = 0;
    354 	oldlen = oldstatbuf.st_size;
    355 
    356 	while (oldlen > 0) {
    357 		if (oldlen < 8192) {
    358 			wlen = oldlen;
    359 		} else {
    360 			wlen = 8192;
    361 		}
    362 
    363 		res = readbuf(oldfd, buf, wlen);
    364 		if (res == -1) {
    365 			saverr = errno;
    366 			mms_trace(MMS_ERR, "Error reading file %s, %d",
    367 			    old, saverr);
    368 			break;
    369 		}
    370 
    371 		res = write_buf(newfd, buf, wlen);
    372 		if (res == -1) {
    373 			saverr = errno;
    374 			mms_trace(MMS_ERR, "Error writing file %s, %d",
    375 			    new, saverr);
    376 			break;
    377 		}
    378 
    379 		oldlen -= wlen;
    380 	}
    381 
    382 	(void) close(newfd);
    383 	(void) close(oldfd);
    384 
    385 	/* set acccess & modify times to match original file */
    386 	if (saverr == 0) {
    387 		(void) utimes(new, oldtimes);
    388 		(void) utimes(old, oldtimes);
    389 		res = 0;
    390 	} else {
    391 		res = saverr;
    392 	}
    393 
    394 	return (res);
    395 }
    396 
    397 /* helper function to use read() correctly */
    398 int
    399 readbuf(int fd, void* buffer, int len)
    400 {
    401 	int	numread = 0;
    402 	int	ret;
    403 	char	*bufp;
    404 
    405 	if ((buffer == NULL) || (len < 1) || (fd == -1)) {
    406 		return (-1);
    407 	}
    408 
    409 	bufp = buffer;
    410 
    411 	while (numread < len) {
    412 		ret = read(fd, bufp, (len - numread));
    413 
    414 		if (ret == 0) {
    415 			/* reached EOF */
    416 			break;
    417 		} else if (ret == -1) {
    418 			if (errno == EAGAIN) {
    419 				continue;
    420 			}
    421 			numread = -1;
    422 			break;
    423 		}
    424 
    425 		numread += ret;
    426 		bufp += ret;
    427 	}
    428 
    429 	return (numread);
    430 }
    431 
    432 /* helper function to use write() correctly */
    433 int
    434 write_buf(int fd, void* buffer, int len)
    435 {
    436 	int	written = 0;
    437 	int	ret;
    438 	char	*bufp;
    439 
    440 	if ((buffer == NULL) || (fd == -1)) {
    441 		return (-1);
    442 	}
    443 
    444 	bufp = buffer;
    445 
    446 	while (written < len) {
    447 		ret = write(fd, bufp, (len - written));
    448 
    449 		if (ret == -1) {
    450 			if (errno == EAGAIN) {
    451 				continue;
    452 			}
    453 			written = -1;
    454 			break;
    455 		}
    456 
    457 		written += ret;
    458 		bufp += written;
    459 	}
    460 
    461 	return (written);
    462 }
    463 
    464 /*
    465  * mk_wc_path()
    466  *
    467  * Function to generate a path name for working copies of
    468  * files and creates the file.
    469  */
    470 int
    471 mk_wc_path(
    472 	char *original, 	/* IN - path to original file */
    473 	char *tmppath, 		/* IN/OUT - buffer to hold new file path */
    474 	size_t buflen)		/* IN - length of buffer */
    475 {
    476 	char		*copypath;
    477 	char		template[MAXPATHLEN+1];
    478 	char		buf[MAXPATHLEN+1];
    479 	char		*fname;
    480 	int		ret;
    481 	struct stat64	statbuf;
    482 
    483 	if (!original || !tmppath) {
    484 		return (MMS_MGMT_NOARG);
    485 	}
    486 
    487 	/* make sure target directory exists */
    488 	ret = create_dir(default_tmpfile_dir, 0, NULL, geteuid(),
    489 	    NULL, getegid());
    490 	if (ret != 0) {
    491 		return (ret);
    492 	}
    493 
    494 	ret = stat64(original, &statbuf);
    495 
    496 	/*
    497 	 * not an error if the original doesn't exist.  In this
    498 	 * case, dummy up a mode to be used for the later mknod.
    499 	 */
    500 	if (ret != 0) {
    501 		statbuf.st_mode = S_IFREG;
    502 		statbuf.st_mode |= S_IRWXU|S_IRGRP|S_IROTH;
    503 	}
    504 
    505 	/* create the template name */
    506 	(void) strlcpy(buf, original, MAXPATHLEN+1);
    507 	fname = basename(buf);
    508 	(void) snprintf(template, MAXPATHLEN+1, "%s/%s_XXXXXX",
    509 	    default_tmpfile_dir, fname);
    510 
    511 	copypath = mktemp(template);
    512 
    513 	if (copypath == NULL) {
    514 		return (-1);
    515 	} else {
    516 		(void) strlcpy(tmppath, copypath, buflen);
    517 	}
    518 
    519 	/* make sure an old version isn't hanging around */
    520 	(void) unlink(tmppath);
    521 
    522 	/* create the target file */
    523 	ret = mknod(tmppath, statbuf.st_mode, 0);
    524 
    525 	return (ret);
    526 }
    527 
    528 /*
    529  * make_working_copy()
    530  *
    531  * Copies a file to the default temporary location and returns
    532  * the pathname of the copy.
    533  *
    534  */
    535 int
    536 make_working_copy(char *path, char *wc_path, int pathlen)
    537 {
    538 	int		ret;
    539 
    540 	if (!path || !wc_path) {
    541 		return (-1);
    542 	}
    543 
    544 	ret = mk_wc_path(path, wc_path, pathlen);
    545 	if (ret != 0) {
    546 		return (ret);
    547 	}
    548 
    549 	ret = cp_file(path, wc_path);
    550 
    551 	return (ret);
    552 }
    553 
    554 
    555 typedef struct proclist proclist_t;
    556 struct proclist {
    557 	mms_list_node_t	next_proc;
    558 	psinfo_t	*proc;
    559 };
    560 
    561 /*
    562  * The find_process() function reads through /proc and finds all processes with
    563  * the specified executable name.
    564  *
    565  * PARAM
    566  * exename	- INPUT - 	name of executable
    567  * procs	- OUTPUT - 	list of psinfo_t structs
    568  *
    569  * ERRORS
    570  */
    571 int
    572 find_process(char *exename, mms_list_t *procs)
    573 {
    574 	DIR		*dirp;
    575 	dirent64_t	*dent;
    576 	dirent64_t	*dentp;
    577 	char		pname[MAXPATHLEN];
    578 	char		*ptr;
    579 	int		procfd;	/* filedescriptor for /proc/nnnnn/psinfo */
    580 	psinfo_t 	info;	/* process information from /proc */
    581 	int		ret = 0;
    582 	int		len = sizeof (info);
    583 
    584 	if (!exename || !procs) {
    585 		return (MMS_MGMT_NOARG);
    586 	}
    587 
    588 	mms_trace(MMS_INFO, "finding all %s processes", exename);
    589 
    590 	if ((dirp = opendir(PROCDIR)) == NULL) {
    591 		ret = errno;
    592 		mms_trace(MMS_ERR, "Could not open %s, %d", PROCDIR, ret);
    593 		return (ret);
    594 	}
    595 
    596 	mms_list_create(procs, sizeof (proclist_t),
    597 	    offsetof(proclist_t, next_proc));
    598 
    599 	/* allocate the dirent structure */
    600 	dent = malloc(MAXPATHLEN + sizeof (dirent64_t));
    601 	if (dent == NULL) {
    602 		(void) closedir(dirp);
    603 		mms_list_destroy(procs);
    604 		return (ENOMEM);
    605 	}
    606 
    607 	/* find each active process --- */
    608 	while ((ret = readdir64_r(dirp, dent, &dentp)) == 0) {
    609 
    610 		if (dentp == NULL) {
    611 			break;
    612 		}
    613 
    614 		/* skip . and .. */
    615 		if (dentp->d_name[0] == '.') {
    616 			continue;
    617 		}
    618 
    619 		(void) snprintf(pname, MAXPATHLEN, "%s/%s/%s", PROCDIR,
    620 		    dentp->d_name, "psinfo");
    621 
    622 		procfd = open64(pname, O_RDONLY);
    623 		if (procfd == -1) {
    624 			/* process may have ended while we were processing */
    625 			continue;
    626 		}
    627 
    628 		/*
    629 		 * Get the info structure for the process and close quickly.
    630 		 */
    631 		ret = readbuf(procfd, &info, len);
    632 
    633 		(void) close(procfd);
    634 
    635 		if (ret == -1) {
    636 			break;
    637 		}
    638 
    639 		if (info.pr_lwp.pr_state == 0)		/* can't happen? */
    640 			continue;
    641 
    642 		/* ensure cmd buffers properly terminated */
    643 		info.pr_psargs[PRARGSZ-1] = '\0';
    644 		info.pr_fname[PRFNSZ-1] = '\0';
    645 
    646 		/* is it the proc we're looking for? */
    647 		if (strncmp(info.pr_psargs, exename, strlen(exename)) != 0) {
    648 			continue;
    649 		}
    650 
    651 		ptr = malloc(len);
    652 		if (ptr == NULL) {
    653 			ret = ENOMEM;
    654 			break;
    655 		}
    656 		(void) memcpy(ptr, &info, len);
    657 		mms_list_insert_tail(procs, ptr);
    658 	}
    659 
    660 	(void) closedir(dirp);
    661 	free(dent);
    662 	return (ret);
    663 }
    664 
    665 /*
    666  * exec_mgmt_cmd()
    667  *
    668  * Helper functino to exec an external program, optionally returning
    669  * messages written to stdout/stderr and exec()ing as a different UID.
    670  *
    671  * The 'cmd' array must have the executable as the first entry, and *must*
    672  * have a NULL as the last entry.
    673  */
    674 int
    675 exec_mgmt_cmd(
    676 	FILE		**outstr,
    677 	FILE		**errstr,
    678 	uid_t		euid,
    679 	gid_t		egid,
    680 	boolean_t	daemon,
    681 	char		*cmd[])
    682 {
    683 	int		fdo[2] = {-1, -1}; /* pipe for reading stdout */
    684 	int		fde[2] = {-1, -1}; /* pipe for reading stderr */
    685 	pid_t		pid;
    686 
    687 	/* The path to the executable must be fully-qualified */
    688 	if ((cmd == NULL) || (cmd[0] == NULL) || (cmd[0][0] != '/')) {
    689 		mms_trace(MMS_DEBUG,
    690 		    "validate error");
    691 		return (-1);
    692 	}
    693 
    694 	if (outstr != NULL) {
    695 		if (pipe(fdo) < 0) {
    696 			mms_trace(MMS_DEBUG,
    697 			    "pipe(fdo) error");
    698 			return (-1);
    699 		}
    700 	}
    701 
    702 	if (errstr != NULL) {
    703 		if (pipe(fde) < 0) {
    704 			mms_trace(MMS_DEBUG,
    705 			    "pipe(fde) error");
    706 			(void) close(fdo[0]);
    707 			(void) close(fdo[1]);
    708 			return (-1);
    709 		}
    710 	}
    711 
    712 	if ((pid = fork()) < 0) {
    713 		mms_trace(MMS_DEBUG,
    714 		    "fork() error");
    715 		(void) close(fdo[0]);
    716 		(void) close(fdo[1]);
    717 		(void) close(fde[0]);
    718 		(void) close(fde[1]);
    719 		return (-1);
    720 	}
    721 
    722 	if (pid == 0) {		/* child */
    723 		/* redirect stdout and stderr */
    724 		int	ret;
    725 
    726 		if (!outstr) {
    727 			fdo[1] = open("/dev/null", O_WRONLY);
    728 		}
    729 
    730 		if (!errstr) {
    731 			fde[1] = open("/dev/null", O_WRONLY);
    732 		}
    733 
    734 		if ((fde[1] == -1) || (fdo[1] == -1)) {
    735 			mms_trace(MMS_DEBUG,
    736 			    "(fde[1] == -1) || (fdo[1] == -1) error");
    737 			exit(9);
    738 		}
    739 
    740 		(void) dup2(fdo[1], STDOUT_FILENO);
    741 		(void) dup2(fde[1], STDERR_FILENO);
    742 
    743 		(void) close(fdo[0]);
    744 		(void) close(fde[0]);
    745 
    746 		(void) close(STDIN_FILENO);
    747 
    748 		(void) closefrom(3);
    749 
    750 		/* set UID if requested */
    751 		if (euid != 0) {
    752 			(void) setuid(euid);
    753 		}
    754 
    755 		if (egid != 0) {
    756 			(void) setgid(egid);
    757 		}
    758 
    759 		if (daemon) {
    760 			(void) setsid();	 /* become session leader */
    761 			pid = fork();
    762 			if (pid < 0) {
    763 				exit(1);
    764 			} else if (pid > 0) {
    765 				/* parent */
    766 				exit(0);
    767 			}
    768 		}
    769 
    770 		ret = execv(cmd[0], cmd);
    771 
    772 		if (0 != ret) {
    773 			mms_trace(MMS_DEBUG,
    774 			    "execv(cmd[0], cmd) error");
    775 			return (ret);
    776 		}
    777 	}
    778 
    779 	/* parent */
    780 	if (outstr) {
    781 		(void) close(fdo[1]);
    782 		*outstr = fdopen(fdo[0], "r");
    783 	}
    784 
    785 	if (errstr) {
    786 		(void) close(fde[1]);
    787 		*errstr = fdopen(fde[0], "r");
    788 	}
    789 
    790 	return (pid);
    791 }
    792 
    793 /* configuration functions */
    794 void
    795 mgmt_unsetall_cfgvar(void)
    796 {
    797 	(void) mms_cfg_unsetvar(MMS_CFG_CONFIG_TYPE);
    798 	(void) mms_cfg_unsetvar(MMS_CFG_MGR_HOST);
    799 	(void) mms_cfg_unsetvar(MMS_CFG_MGR_PORT);
    800 	(void) mms_cfg_unsetvar(MMS_CFG_SSL_ENABLED);
    801 	(void) mms_cfg_unsetvar(MMS_CFG_SSL_CERT_FILE);
    802 	(void) mms_cfg_unsetvar(MMS_CFG_SSL_PASS_FILE);
    803 	(void) mms_cfg_unsetvar(MMS_CFG_SSL_DH_FILE);
    804 	(void) mms_cfg_unsetvar(MMS_CFG_SSL_CRL_FILE);
    805 	(void) mms_cfg_unsetvar(MMS_CFG_SSL_PEER_FILE);
    806 	(void) mms_cfg_unsetvar(MMS_CFG_SSL_CIPHER);
    807 	(void) mms_cfg_unsetvar(MMS_CFG_SSL_VERIFY);
    808 	(void) mms_cfg_unsetvar(MMS_CFG_DB_DATA);
    809 	(void) mms_cfg_unsetvar(MMS_CFG_DB_LOG);
    810 	(void) mms_cfg_unsetvar(MMS_CFG_MM_DB_HOST);
    811 	(void) mms_cfg_unsetvar(MMS_CFG_MM_DB_PORT);
    812 	(void) mms_cfg_unsetvar(MMS_CFG_MM_DB_NAME);
    813 	(void) mms_cfg_unsetvar(MMS_CFG_MM_DB_USER);
    814 	(void) mms_cfg_unsetvar(MMS_CFG_SSI_PATH);
    815 }
    816 
    817 int
    818 mgmt_set_svc_state(
    819 	char		*fmri,
    820 	mms_svcstate_t	targetState,
    821 	char		**original)
    822 {
    823 	char		*startState = NULL;
    824 	char		*endState = NULL;
    825 	int		st = 0;
    826 	const char	*cmpState;
    827 	int		i;
    828 
    829 	if (fmri == NULL) {
    830 		mms_trace(MMS_ERR, "fmri is null");
    831 		return (MMS_MGMT_NOARG);
    832 	}
    833 
    834 	startState = smf_get_state(fmri);
    835 	if (startState == NULL) {
    836 		st = scf_error();
    837 		mms_trace(MMS_ERR, "get state %s - %s", fmri, scf_strerror(st));
    838 		/*
    839 		 * Not an error if request to disable or degrade a
    840 		 * non-existent svc
    841 		 */
    842 		if ((targetState == DISABLE) || (targetState == DEGRADE)) {
    843 			if (st == SCF_ERROR_NOT_FOUND) {
    844 				st = 0;
    845 			}
    846 		}
    847 		return (st);
    848 	}
    849 
    850 	if (original != NULL) {
    851 		*original = startState;
    852 	}
    853 
    854 	switch (targetState) {
    855 		case ENABLE:
    856 			cmpState = SCF_STATE_STRING_ONLINE;
    857 			if (strcmp(startState, cmpState) != 0) {
    858 				st = smf_enable_instance(fmri, 0);
    859 			}
    860 			break;
    861 		case DISABLE:
    862 			cmpState = SCF_STATE_STRING_DISABLED;
    863 			/*
    864 			 * can't go directly from maintenance to disabled,
    865 			 * though I can't see why.
    866 			 */
    867 			if (strcmp(startState, SCF_STATE_STRING_MAINT) == 0) {
    868 				mms_trace(MMS_DEBUG,
    869 				    "restore before disable %s",
    870 				    fmri);
    871 				st = mgmt_set_svc_state(fmri, RESTORE, NULL);
    872 				if (st != 0) {
    873 					mms_trace(MMS_ERR,
    874 					    "failed to restore %s",
    875 					    fmri);
    876 				}
    877 				st = smf_disable_instance(fmri, 0);
    878 			}
    879 			if (strcmp(startState, cmpState) != 0) {
    880 				st = smf_disable_instance(fmri, 0);
    881 			}
    882 			break;
    883 		case REFRESH:
    884 			/* refresh shouldn't change the current state */
    885 			cmpState = startState;
    886 			st = smf_refresh_instance(fmri);
    887 			break;
    888 		case RESTART:
    889 			cmpState = SCF_STATE_STRING_ONLINE;
    890 			st = smf_restart_instance(fmri);
    891 			break;
    892 		case MAINTAIN:
    893 			cmpState = SCF_STATE_STRING_MAINT;
    894 			st = smf_maintain_instance(fmri, SMF_IMMEDIATE);
    895 			break;
    896 		case DEGRADE:
    897 			/* only available if 'online' */
    898 			if (strcmp(startState, SCF_STATE_STRING_ONLINE) == 0) {
    899 				cmpState = SCF_STATE_STRING_DEGRADED;
    900 				st = smf_degrade_instance(fmri, 0);
    901 			} else {
    902 				cmpState = startState;
    903 			}
    904 			break;
    905 		case RESTORE:
    906 			/*
    907 			 * if disabled, returns to online.  If maintenance,
    908 			 * returns to disabled.
    909 			 */
    910 			if (strcmp(startState, SCF_STATE_STRING_DISABLED)
    911 			    == 0) {
    912 				cmpState = SCF_STATE_STRING_ONLINE;
    913 			} else if (strcmp(startState, SCF_STATE_STRING_MAINT)
    914 			    == 0) {
    915 				cmpState = SCF_STATE_STRING_DISABLED;
    916 			} else {
    917 				/* invalid operation */
    918 				st = EINVAL;
    919 				break;
    920 			}
    921 			st = smf_restore_instance(fmri);
    922 			break;
    923 		default:
    924 			st = -1;
    925 			mms_trace(MMS_ERR, "%s unknown action %d",
    926 			    fmri, targetState);
    927 			break;
    928 	}
    929 
    930 	if (st == 0) {
    931 		/*
    932 		 * Changing state sometimes takes a while and
    933 		 * the scf service state functions do not wait.
    934 		 * Check to see if the action was successul.
    935 		 */
    936 		st = 1;
    937 		for (i = 0; i < 10; i++) {
    938 			endState = smf_get_state(fmri);
    939 			if (endState == NULL) {
    940 				st = scf_error();
    941 				mms_trace(MMS_ERR,
    942 				    "wait for state change %s - %s",
    943 				    fmri, scf_strerror(st));
    944 				break;
    945 			} else if (strcmp(endState, cmpState) == 0) {
    946 				st = 0;
    947 				break;
    948 			}
    949 			free(endState);
    950 			endState = NULL;
    951 			(void) sleep(1);
    952 		}
    953 	} else if (st != -1) {
    954 		st = scf_error();
    955 		mms_trace(MMS_ERR, "state change %s - %s",
    956 		    fmri, scf_strerror(st));
    957 	}
    958 
    959 	if ((startState != NULL) && (original == NULL)) {
    960 		free(startState);
    961 	}
    962 	if (endState != NULL) {
    963 		free(endState);
    964 	}
    965 
    966 	return (st);
    967 }
    968 
    969 int
    970 check_exit(pid_t pid, int *signo)
    971 {
    972 	pid_t	wpid;
    973 	int	pst;
    974 	int	st = EINVAL;
    975 
    976 	if (pid == (pid_t)-1) {
    977 		return (st);
    978 	}
    979 
    980 	wpid = waitpid(pid, &pst, 0);
    981 
    982 	if (wpid != pid) {
    983 		st = errno;
    984 	} else {
    985 		if (WIFEXITED(pst)) {
    986 			st = WEXITSTATUS(pst);
    987 		} else if (WIFSIGNALED(pst)) {
    988 			st = EINTR;
    989 			if (signo) {
    990 				*signo = WTERMSIG(pst);
    991 			}
    992 		} else if (WCOREDUMP(pst)) {
    993 			st = EINTR;
    994 			if (signo) {
    995 				*signo = SIGSEGV;
    996 			}
    997 		}
    998 	}
    999 	return (st);
   1000 }
   1001 
   1002 /* Helper function for MMS lists */
   1003 void
   1004 mms_list_free_and_destroy(mms_list_t *list, void (*free_func)(void *))
   1005 {
   1006 	mms_list_node_t	*node;
   1007 
   1008 	if (!list || !free_func || (list->list_size == 0)) {
   1009 		return;
   1010 	}
   1011 
   1012 	while (! mms_list_empty(list)) {
   1013 		node = mms_list_head(list);
   1014 
   1015 		mms_list_remove(list, node);
   1016 		free_func(node);
   1017 	}
   1018 
   1019 	mms_list_destroy(list);
   1020 }
   1021 
   1022 /* helper functions to validate option values */
   1023 int
   1024 val_numonly(char *val)
   1025 {
   1026 	int	st = 0;
   1027 	char	*bufp;
   1028 
   1029 	if (!val) {
   1030 		return (MMS_MGMT_NOARG);
   1031 	}
   1032 
   1033 	for (bufp = val; *bufp != '\0'; bufp++) {
   1034 		if (*bufp == '-') {
   1035 			/* negative number */
   1036 			continue;
   1037 		}
   1038 		if (!isdigit(*bufp)) {
   1039 			st = EINVAL;
   1040 			break;
   1041 		}
   1042 	}
   1043 
   1044 	return (st);
   1045 }
   1046 
   1047 int
   1048 val_passwd(char *val)
   1049 {
   1050 	if (!val) {
   1051 		return (MMS_MGMT_NOARG);
   1052 	} else if (strlen(val) < 8) {
   1053 		return (EINVAL);
   1054 	} else {
   1055 		return (0);
   1056 	}
   1057 }
   1058 
   1059 int
   1060 val_objtype(char *val)
   1061 {
   1062 	if (!val) {
   1063 		return (MMS_MGMT_NOARG);
   1064 	}
   1065 
   1066 	if ((strcmp(val, "client") == 0) ||
   1067 	    (strcmp(val, "server") == 0) ||
   1068 	    (strcmp(val, "library") == 0) ||
   1069 	    (strcmp(val, "drive") == 0) ||
   1070 	    (strcmp(val, "dpool") == 0) ||
   1071 	    (strcmp(val, "mpool") == 0) ||
   1072 	    (strcmp(val, "app") == 0) ||
   1073 	    (strcmp(val, "alarm") == 0) ||
   1074 	    (strcmp(val, "vol") == 0) ||
   1075 	    (strcmp(val, "voltype") == 0)) {
   1076 		return (0);
   1077 	} else {
   1078 		return (EINVAL);
   1079 	}
   1080 }
   1081 
   1082 int
   1083 val_path(char *val)
   1084 {
   1085 	if (!val) {
   1086 		return (MMS_MGMT_NOARG);
   1087 	}
   1088 
   1089 	if (*val != '/') {
   1090 		return (EINVAL);
   1091 	}
   1092 
   1093 	return (0);
   1094 }
   1095 
   1096 int
   1097 val_level(char *val)
   1098 {
   1099 	if (!val) {
   1100 		return (MMS_MGMT_NOARG);
   1101 	}
   1102 
   1103 	if ((strcmp(val, "emergency") == 0) ||
   1104 	    (strcmp(val, "alert") == 0) ||
   1105 	    (strcmp(val, "critical") == 0) ||
   1106 	    (strcmp(val, "error") == 0) ||
   1107 	    (strcmp(val, "warning") == 0) ||
   1108 	    (strcmp(val, "notice") == 0) ||
   1109 	    (strcmp(val, "information") == 0) ||
   1110 	    (strcmp(val, "debug") == 0)) {
   1111 		return (0);
   1112 	} else {
   1113 		return (EINVAL);
   1114 	}
   1115 }
   1116 
   1117 int
   1118 val_yesno(char *val)
   1119 {
   1120 	if (!val) {
   1121 		return (MMS_MGMT_NOARG);
   1122 	}
   1123 
   1124 	if (*val == 'y' || *val == 'Y' || *val == 'n' || *val == 'N') {
   1125 		return (0);
   1126 	} else {
   1127 		return (EINVAL);
   1128 	}
   1129 }
   1130 
   1131 int
   1132 val_truefalse(char *val)
   1133 {
   1134 	if (!val) {
   1135 		return (MMS_MGMT_NOARG);
   1136 	}
   1137 
   1138 	if ((strcmp(val, "true") == 0) || (strcmp(val, "false") == 0)) {
   1139 		return (0);
   1140 	} else {
   1141 		return (EINVAL);
   1142 	}
   1143 }
   1144 
   1145 int
   1146 val_mms_size(char *val)
   1147 {
   1148 	return (do_val_mms_size(val, NULL));
   1149 }
   1150 
   1151 int
   1152 do_val_mms_size(char *val, uint64_t *bytes)
   1153 {
   1154 	uint64_t	sz = 0;
   1155 	char		*unit = NULL;
   1156 	uint64_t	mult = 1;
   1157 
   1158 	if (!val) {
   1159 		return (MMS_MGMT_NOARG);
   1160 	}
   1161 
   1162 	sz = strtoll(val, &unit, 10);
   1163 	if ((sz == LONG_MAX) || (sz == LONG_MIN)) {
   1164 		return (EINVAL);
   1165 	}
   1166 
   1167 	if (unit) {
   1168 		switch (*unit) {
   1169 			case 'b':
   1170 			case 'B':
   1171 				mult = 1;
   1172 				break;
   1173 			case 'k':
   1174 			case 'K':
   1175 				mult = KILO;
   1176 				break;
   1177 			case 'm':
   1178 			case 'M':
   1179 				mult = MEGA;
   1180 				break;
   1181 			case 'g':
   1182 			case 'G':
   1183 				mult = GIGA;
   1184 				break;
   1185 			case 't':
   1186 			case 'T':
   1187 				mult = TERA;
   1188 				break;
   1189 			case 'p':
   1190 			case 'P':
   1191 				mult = PETA;
   1192 				break;
   1193 			default:
   1194 				return (EINVAL);
   1195 				break;
   1196 		}
   1197 	}
   1198 
   1199 	if (bytes) {
   1200 		*bytes = sz * mult;
   1201 	}
   1202 
   1203 	return (0);
   1204 }
   1205 
   1206 int
   1207 val_density(char *val)
   1208 {
   1209 	if (!val) {
   1210 		return (MMS_MGMT_NOARG);
   1211 	}
   1212 
   1213 	if ((strcmp(val, "den_9840C") == 0) ||
   1214 	    (strcmp(val, "den_9840") == 0) ||
   1215 	    (strcmp(val, "den_LTO4") == 0) ||
   1216 	    (strcmp(val, "den_LTO3") == 0) ||
   1217 	    (strcmp(val, "den_LTO2") == 0) ||
   1218 	    (strcmp(val, "den_LTO1") == 0)) {
   1219 		return (0);
   1220 	}
   1221 
   1222 	return (EINVAL);
   1223 }
   1224 
   1225 int
   1226 mms_mgmt_get_pwd(char *pwfile, char *key, char *phrase[2], nvlist_t *nvl,
   1227     nvlist_t *errs)
   1228 {
   1229 	int		st = 0;
   1230 	char		*mpwp;
   1231 	char		*chkpw;
   1232 	char		buf[512];
   1233 	int		fd;
   1234 	size_t		sz;
   1235 
   1236 	if (!key || !nvl) {
   1237 		return (MMS_MGMT_NOARG);
   1238 	}
   1239 
   1240 	if (pwfile != NULL) {
   1241 		fd = open(pwfile, O_RDONLY);
   1242 		if (fd == -1) {
   1243 			st = errno;
   1244 			if (errs) {
   1245 				(void) nvlist_add_int32(errs, pwfile, st);
   1246 			}
   1247 			return (st);
   1248 		}
   1249 
   1250 		sz = readbuf(fd, buf, sizeof (buf));
   1251 		(void) close(fd);
   1252 
   1253 		buf[sz] = '\0';
   1254 
   1255 		while ((sz > 1) && (isspace(buf[sz - 1]))) {
   1256 			buf[sz -1] = '\0';
   1257 			sz--;
   1258 		}
   1259 
   1260 		mpwp = buf;
   1261 		if (strlen(mpwp) < 8) {
   1262 			return (MMS_MGMT_PASSTOOSHORT);
   1263 		}
   1264 	} else {
   1265 		if ((!phrase) || (!phrase[0])) {
   1266 			return (MMS_MGMT_NOARG);
   1267 		}
   1268 
   1269 		mpwp = getpassphrase(phrase[0]);
   1270 		if (mpwp == NULL) {
   1271 			return (MMS_MGMT_GETPASS_FAILED);
   1272 		} else if (strlen(mpwp) < 8) {
   1273 			return (MMS_MGMT_PASSTOOSHORT);
   1274 		}
   1275 
   1276 		/* getpassphrase overwrites previous result, so save first */
   1277 		(void) strlcpy(buf, mpwp, sizeof (buf));
   1278 		mpwp = buf;
   1279 
   1280 		/* verify entered password if required */
   1281 		if (phrase[1]) {
   1282 			chkpw = getpassphrase(phrase[1]);
   1283 			if ((chkpw == NULL) || (strcmp(mpwp, chkpw) != 0)) {
   1284 				return (MMS_MGMT_PASSWD_MISMATCH);
   1285 			}
   1286 		}
   1287 	}
   1288 
   1289 	st = nvlist_add_string(nvl, key, mpwp);
   1290 	return (0);
   1291 }
   1292 
   1293 /*
   1294  *  Helper function to generate the MMP 'create' clause for the specified
   1295  *  object.
   1296  */
   1297 int
   1298 create_mmp_clause(char *objtype, mms_mgmt_setopt_t *opts, nvlist_t *inopts,
   1299     nvlist_t *errs, char *cmd, size_t cmdlen)
   1300 {
   1301 	int		st = 0;
   1302 	int		ost = 0;
   1303 	char		tid[64];
   1304 	char		buf[1024];
   1305 	char		*val;
   1306 	int		i;
   1307 
   1308 	if (!objtype || !opts || !buf || !inopts) {
   1309 		return (MMS_MGMT_NOARG);
   1310 	}
   1311 
   1312 	(void) mms_gen_taskid(tid);
   1313 
   1314 	(void) snprintf(cmd, cmdlen, "create task['%s'] type[%s]", tid,
   1315 	    objtype);
   1316 
   1317 	for (i = 0; opts[i].name != NULL; i++) {
   1318 		if (opts[i].mmpopt == NULL) {
   1319 			continue;
   1320 		}
   1321 		ost = nvlist_lookup_string(inopts, opts[i].name, &val);
   1322 		if (ost == ENOENT) {
   1323 			if (opts[i].required) {
   1324 				if (opts[i].defval) {
   1325 					val = opts[i].defval;
   1326 					ost = 0;
   1327 				}
   1328 			} else {
   1329 				ost = 0;
   1330 				continue;
   1331 			}
   1332 		}
   1333 		if (ost != 0) {
   1334 			MGMT_ADD_OPTERR(errs, opts[i].name, ost);
   1335 			if (st == 0) {
   1336 				st = ost;
   1337 			}
   1338 			continue;
   1339 		}
   1340 		(void) snprintf(buf, sizeof (buf), " set[%s.'%s' '%s']",
   1341 		    objtype, opts[i].mmpopt, val);
   1342 		(void) strlcat(cmd, buf, cmdlen);
   1343 	}
   1344 
   1345 	(void) strlcat(cmd, ";\n", cmdlen);
   1346 
   1347 	return (st);
   1348 }
   1349 
   1350 int
   1351 mms_add_object(void *session, char *objtype, mms_mgmt_setopt_t *objopts,
   1352     nvlist_t *nvl, nvlist_t *errs)
   1353 {
   1354 	void	*response = NULL;
   1355 	int	st;
   1356 	char	tid[64];
   1357 	char	cmd[8192];
   1358 	void	*sess = NULL;
   1359 	void	*sessp = session;
   1360 
   1361 	if (!objtype || !objopts || !nvl) {
   1362 		return (MMS_MGMT_NOARG);
   1363 	}
   1364 
   1365 	if (session == NULL) {
   1366 		st = create_mm_clnt(NULL, NULL, NULL, NULL, &sess);
   1367 		if (st != 0) {
   1368 			return (st);
   1369 		}
   1370 		sessp = sess;
   1371 	}
   1372 
   1373 	st = create_mmp_clause(objtype, objopts, nvl, errs, cmd, sizeof (cmd));
   1374 	if (st == 0) {
   1375 		st = mms_mgmt_send_cmd(sessp, tid, cmd, "mms_add_object()",
   1376 		    &response);
   1377 
   1378 		mms_free_rsp(response);
   1379 	}
   1380 
   1381 	if (sess) {
   1382 		(void) mms_goodbye(sess, 0);
   1383 	}
   1384 
   1385 	return (st);
   1386 }
   1387 
   1388 int
   1389 mms_mgmt_send_cmd(void *sess, char *tid, char *cmd, char *pfx, void **response)
   1390 {
   1391 	int		st = 0;
   1392 
   1393 	if (!sess || !tid || !cmd || !pfx || !response) {
   1394 		return (MMS_MGMT_NOARG);
   1395 	}
   1396 
   1397 	mms_trace(MMS_DEBUG, "%s request command: %s", pfx, cmd);
   1398 
   1399 	if ((st = mms_send_cmd(sess, cmd, response)) != 0) {
   1400 		st = MMS_MGMT_MMP_PARSE_ERR;
   1401 		mms_trace(MMS_ERR, "%s send command failed with %d", pfx,
   1402 		    st);
   1403 	} else {
   1404 		mms_trace(MMS_DEBUG, "Response[%s]: %s",
   1405 		    tid, ((mms_rsp_ele_t *)(*response))->mms_rsp_str);
   1406 
   1407 		if ((st = mms_client_handle_rsp(*response)) != MMS_API_OK) {
   1408 			mms_trace(MMS_ERR, "%s response failed", pfx);
   1409 		}
   1410 	}
   1411 
   1412 	return (st);
   1413 }
   1414 
   1415 int
   1416 mgmt_find_changed_attrs(char *objtype, mms_mgmt_setopt_t *opts,
   1417     nvlist_t *nvl, char **carray, int *count, nvlist_t *errs)
   1418 {
   1419 	int		st = 0;
   1420 	int		ost = 0;
   1421 	int		i;
   1422 
   1423 	if (!objtype || !opts || !nvl || !carray || !count) {
   1424 		return (MMS_MGMT_NOARG);
   1425 	}
   1426 
   1427 	*count = 0;
   1428 
   1429 	for (i = 0; opts[i].name != NULL; i++) {
   1430 		if (strcmp(opts[i].name, "name") == 0) {
   1431 			continue;
   1432 		}
   1433 		ost = nvlist_lookup_string(nvl, opts[i].name, &carray[i]);
   1434 		if (ost == 0) {
   1435 			if (opts[i].validate_func) {
   1436 				ost = (opts[i].validate_func)(carray[i]);
   1437 				if (ost != 0) {
   1438 					if (st == 0) {
   1439 						st = ost;
   1440 					}
   1441 					MGMT_ADD_OPTERR(errs, opts[i].name,
   1442 					    ost);
   1443 					carray[i] = NULL;
   1444 					continue;
   1445 				}
   1446 			}
   1447 			(*count)++;
   1448 		}
   1449 	}
   1450 
   1451 	return (st);
   1452 }
   1453 
   1454 void
   1455 cmp_mmp_opts(mms_mgmt_setopt_t *opts, char **carray, nvlist_t *nva, int *count)
   1456 {
   1457 	int	i;
   1458 	int	ost;
   1459 	char	*val;
   1460 
   1461 	if (!opts || !carray || !nva || !count) {
   1462 		return;
   1463 	}
   1464 
   1465 	for (i = 0; opts[i].name != NULL; i++) {
   1466 		if (carray[i] == NULL) {
   1467 			continue;
   1468 		}
   1469 		ost = nvlist_lookup_string(nva, opts[i].mmpopt, &val);
   1470 		if (ost != 0) {
   1471 			continue;
   1472 		}
   1473 		if (strcmp(val, carray[i]) == 0) {
   1474 			/* value identical */
   1475 			carray[i] = NULL;
   1476 			(*count)--;
   1477 		}
   1478 	}
   1479 }
   1480 
   1481 void
   1482 mk_set_clause(char *objtype, mms_mgmt_setopt_t *opts, char **carray,
   1483     char *buf, int buflen)
   1484 {
   1485 	int	i;
   1486 	char	phrase[1024];
   1487 
   1488 	if (!objtype || !opts || !carray || !buf) {
   1489 		return;
   1490 	}
   1491 
   1492 	for (i = 0; opts[i].name != NULL; i++) {
   1493 		if (carray[i] == NULL) {
   1494 			continue;
   1495 		}
   1496 		(void) snprintf(phrase, sizeof (phrase),
   1497 		    " set[%s.'%s' '%s']",
   1498 		    objtype, opts[i].mmpopt, carray[i]);
   1499 		(void) strlcat(buf, phrase, buflen);
   1500 	}
   1501 }
   1502 
   1503 char **
   1504 mgmt_var_to_array(nvlist_t *nvl, char *optname, int *count)
   1505 {
   1506 	int		st;
   1507 	data_type_t	nvt;
   1508 	nvpair_t	*nvp = NULL;
   1509 	char		**arr = NULL;
   1510 	char		*val = NULL;
   1511 	char		**aval = NULL;
   1512 	int		i;
   1513 
   1514 	if (!nvl || !optname || !count) {
   1515 		return (NULL);
   1516 	}
   1517 
   1518 	*count = 0;
   1519 
   1520 	st = nvlist_lookup_nvpair(nvl, optname, &nvp);
   1521 	if (nvp == NULL) {
   1522 		return (NULL);
   1523 	}
   1524 
   1525 	nvt = nvpair_type(nvp);
   1526 
   1527 	if (nvt == DATA_TYPE_STRING) {
   1528 		st = nvpair_value_string(nvp, &val);
   1529 		if (st == 0) {
   1530 			*count = 1;
   1531 			arr = malloc(sizeof (char *));
   1532 			if (arr != NULL) {
   1533 				arr[0] = strdup(val);
   1534 			}
   1535 		}
   1536 	} else if (nvt == DATA_TYPE_STRING_ARRAY) {
   1537 		st = nvpair_value_string_array(nvp, &aval, (uint_t *)count);
   1538 		if ((st == 0) && (*count > 0)) {
   1539 			arr = malloc(sizeof (char *) * *count);
   1540 			if (arr != NULL) {
   1541 				for (i = 0; i < *count; i++) {
   1542 					arr[i] = strdup(aval[i]);
   1543 				}
   1544 			}
   1545 		}
   1546 	}
   1547 
   1548 	return (arr);
   1549 }
   1550 
   1551 void
   1552 mgmt_free_str_arr(char **inarr, int count)
   1553 {
   1554 	int	i;
   1555 
   1556 	if (!inarr) {
   1557 		return;
   1558 	}
   1559 
   1560 	for (i = 0; i < count; i++) {
   1561 		if (inarr[i]) {
   1562 			free(inarr[i]);
   1563 		}
   1564 	}
   1565 
   1566 	free(inarr);
   1567 }
   1568 
   1569 int
   1570 mgmt_opt_to_var(char *in_str, boolean_t allow_empty, nvlist_t *nvl)
   1571 {
   1572 	int	st;
   1573 	char	*bufp;
   1574 	char	*wstr;
   1575 
   1576 	if (!in_str || !nvl) {
   1577 		return (MMS_MGMT_NOARG);
   1578 	}
   1579 
   1580 	wstr = strdup(in_str);
   1581 	if (!wstr) {
   1582 		return (ENOMEM);
   1583 	}
   1584 
   1585 	bufp = strchr(wstr, '=');
   1586 	if (!bufp) {
   1587 		return (MMS_MGMT_NOARG);
   1588 	}
   1589 	*bufp++ = '\0';
   1590 
   1591 	st = mgmt_set_str_or_arr(bufp, wstr, nvl);
   1592 	if (st != 0) {
   1593 		if (st == ENOENT) {
   1594 			if (allow_empty) {
   1595 				/* common for 'list' options */
   1596 				st = 0;
   1597 				(void) nvlist_add_string(nvl, wstr, "");
   1598 			}
   1599 		}
   1600 	}
   1601 
   1602 	free(wstr);
   1603 
   1604 	return (st);
   1605 }
   1606 
   1607 int
   1608 mgmt_set_str_or_arr(char *inargs, char *key, nvlist_t *nvl)
   1609 {
   1610 	int		st;
   1611 	char		*bufp;
   1612 	int		count;
   1613 	char		**tmparr;
   1614 
   1615 	if (!inargs || !key || !nvl) {
   1616 		return (MMS_MGMT_NOARG);
   1617 	}
   1618 
   1619 	bufp = inargs;
   1620 	count = 1;
   1621 
   1622 	for (;;) {
   1623 		bufp = strchr(bufp, ',');
   1624 		if (bufp == NULL) {
   1625 			break;
   1626 		}
   1627 		bufp++;
   1628 		count++;
   1629 	}
   1630 
   1631 	if (count == 1) {
   1632 		st = nvlist_add_string(nvl, key, inargs);
   1633 	} else {
   1634 		tmparr = calloc(count, sizeof (char *));
   1635 		if (tmparr == NULL) {
   1636 			return (ENOMEM);
   1637 		}
   1638 		bufp = inargs;
   1639 		/* set delimiter to comma */
   1640 		(void) bufsplit(",", 0, NULL);
   1641 
   1642 		(void) bufsplit(bufp, count, tmparr);
   1643 		st = nvlist_add_string_array(nvl, key, tmparr, count);
   1644 		free(tmparr);
   1645 	}
   1646 
   1647 	return (st);
   1648 }
   1649 
   1650 int
   1651 mgmt_xlate_cfgerr(scf_error_t in_err)
   1652 {
   1653 	int		st;
   1654 
   1655 	switch (in_err) {
   1656 		case SCF_ERROR_NOT_SET:
   1657 		case SCF_ERROR_NOT_FOUND:
   1658 		case SCF_ERROR_DELETED:
   1659 			st = ENOENT;
   1660 			break;
   1661 		case SCF_ERROR_NO_MEMORY:
   1662 			st = ENOMEM;
   1663 			break;
   1664 		case SCF_ERROR_TYPE_MISMATCH:
   1665 			st = EINVAL;
   1666 			break;
   1667 		default:
   1668 			st = in_err;
   1669 			break;
   1670 	}
   1671 
   1672 	return (st);
   1673 }
   1674 
   1675 int
   1676 mgmt_compare_hosts(char *host1, char *host2)
   1677 {
   1678 	int			st;
   1679 	struct addrinfo		*res1 = NULL;
   1680 	struct addrinfo		*res2 = NULL;
   1681 	struct addrinfo		*p1 = NULL;
   1682 	struct addrinfo		*p2 = NULL;
   1683 	boolean_t		match = B_FALSE;
   1684 	int			a;
   1685 
   1686 	if (!host1 || !host2) {
   1687 		return (MMS_MGMT_NOARG);
   1688 	}
   1689 
   1690 	st = getaddrinfo(host1, NULL, NULL, &res1);
   1691 	if (st != 0) {
   1692 		return (st);
   1693 	}
   1694 
   1695 	st = getaddrinfo(host2, NULL, NULL, &res2);
   1696 	if (st != 0) {
   1697 		freeaddrinfo(res1);
   1698 		return (st);
   1699 	}
   1700 
   1701 	for (p1 = res1; p1 != NULL; p1 = p1->ai_next) {
   1702 		for (p2 = res2; p2 != NULL; p2 = p2->ai_next) {
   1703 			a = memcmp(p1->ai_addr, p2->ai_addr,
   1704 			    sizeof (struct sockaddr));
   1705 			if (a == 0) {
   1706 				match = B_TRUE;
   1707 				break;
   1708 			}
   1709 			if (memcmp(p1->ai_addr, p2->ai_addr,
   1710 			    sizeof (struct sockaddr)) == 0) {
   1711 				match = B_TRUE;
   1712 				break;
   1713 			}
   1714 		}
   1715 	}
   1716 
   1717 	if (res1) {
   1718 		freeaddrinfo(res1);
   1719 	}
   1720 	if (res2) {
   1721 		freeaddrinfo(res2);
   1722 	}
   1723 
   1724 	if (match) {
   1725 		return (0);
   1726 	}
   1727 
   1728 	return (1);
   1729 }
   1730 
   1731 const char *
   1732 mms_mgmt_get_errstr(int errcode)
   1733 {
   1734 	int		i;
   1735 	int max_err = sizeof (mms_mgmt_errs) / sizeof (mms_sym_t);
   1736 	static	char	msg[1024];
   1737 
   1738 	/* standard errors */
   1739 	if (errcode < 256) {
   1740 		return (strerror(errcode));
   1741 	}
   1742 
   1743 	/* SCF errors */
   1744 	if ((errcode >= 1000) && (errcode < 1020)) {
   1745 		return (scf_strerror(errcode));
   1746 	}
   1747 
   1748 	if ((errcode > MMS_MGMT_ERR_OFFSET) &&
   1749 	    (errcode < MMS_MGMT_LAST_ERR_CODE)) {
   1750 		for (i = 0; i < max_err; i++) {
   1751 			if (mms_mgmt_errs[i].sym_code == errcode) {
   1752 				return (mms_mgmt_errs[i].sym_token);
   1753 			}
   1754 		}
   1755 		(void) snprintf(msg, sizeof (msg), "Unknown err code %d",
   1756 		    errcode);
   1757 		return (msg);
   1758 	}
   1759 
   1760 	if (errcode >= MMS_ERR_BIAS) {
   1761 		return (mms_sym_code_to_str(errcode));
   1762 	}
   1763 
   1764 	return (NULL);
   1765 }
   1766 
   1767 int
   1768 mgmt_chk_auth(char *authname)
   1769 {
   1770 	int		st;
   1771 	struct passwd	pwd;
   1772 	struct passwd	*pwdp;
   1773 	char		buf[1024];
   1774 
   1775 	if (!authname) {
   1776 		return (1);
   1777 	}
   1778 
   1779 	st = getpwuid_r(getuid(), &pwd, buf, sizeof (buf), &pwdp);
   1780 
   1781 	if (st != 0) {
   1782 		/* fail if we can't determine the username */
   1783 		return (0);
   1784 	}
   1785 
   1786 	st = chkauthattr(authname, pwdp->pw_name);
   1787 
   1788 	return (st);
   1789 }
   1790 
   1791 void
   1792 mgmt_filter_results(nvlist_t *filter, nvlist_t *nvl)
   1793 {
   1794 	int		st;
   1795 	int		count;
   1796 	char		**varray;
   1797 	nvpair_t	*nvp;
   1798 	char		*key;
   1799 	data_type_t	nvt;
   1800 	boolean_t	do_filter = B_FALSE;
   1801 
   1802 	if (!filter || !nvl) {
   1803 		/* not a failure if nothing to do */
   1804 		return;
   1805 	}
   1806 
   1807 	st = nvlist_lookup_boolean_value(filter, "filter", &do_filter);
   1808 	if ((st != 0) || !do_filter) {
   1809 		return;
   1810 	}
   1811 
   1812 	nvp = NULL;
   1813 	while ((nvp = nvlist_next_nvpair(filter, nvp)) != NULL) {
   1814 		key = nvpair_name(nvp);
   1815 
   1816 		if ((strcmp(key, "printopts") == 0) ||
   1817 		    (strcmp(key, "name") == 0) ||
   1818 		    (strcmp(key, "objtype") == 0)) {
   1819 			continue;
   1820 		}
   1821 
   1822 		nvt = nvpair_type(nvp);
   1823 		if ((nvt != DATA_TYPE_STRING_ARRAY) &&
   1824 		    (nvt != DATA_TYPE_STRING)) {
   1825 			continue;
   1826 		}
   1827 
   1828 		varray = mgmt_var_to_array(filter, key, &count);
   1829 		filter_on_var(key, varray, count, nvl);
   1830 		mgmt_free_str_arr(varray, count);
   1831 	}
   1832 }
   1833 
   1834 static void
   1835 filter_on_var(char *varname, char **varray, int count, nvlist_t *nvl)
   1836 {
   1837 	int		st;
   1838 	uint_t		vcount;
   1839 	char		**arr;
   1840 	nvpair_t	*nvp = NULL;
   1841 	nvlist_t	*attrs;
   1842 	char		*val;
   1843 	data_type_t	nvt;
   1844 	int		i;
   1845 	int		j;
   1846 	nvpair_t	*fnvp;
   1847 	char		*attrname;
   1848 	nvpair_t	*lastnvp = NULL;
   1849 	boolean_t	keep;
   1850 
   1851 	if (!varname || (count == 0) || !nvl) {
   1852 		return;
   1853 	}
   1854 
   1855 
   1856 	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
   1857 		st = nvpair_value_nvlist(nvp, &attrs);
   1858 		if (st != 0) {
   1859 			continue;
   1860 		}
   1861 
   1862 		attrname = nvpair_name(nvp);
   1863 
   1864 		st = nvlist_lookup_nvpair(attrs, varname, &fnvp);
   1865 		if (st != 0) {
   1866 			/* no match, remove it */
   1867 			(void) nvlist_remove_all(nvl, attrname);
   1868 			nvp = lastnvp;
   1869 			continue;
   1870 		}
   1871 
   1872 		keep = B_FALSE;
   1873 
   1874 		nvt = nvpair_type(fnvp);
   1875 
   1876 		val = NULL;
   1877 		if (nvt == DATA_TYPE_STRING) {
   1878 			(void) nvpair_value_string(fnvp, &val);
   1879 			if (val) {
   1880 				for (i = 0; i < count; i++) {
   1881 					if (strcmp(val, varray[i]) == 0) {
   1882 						/* a keeper */
   1883 						keep = B_TRUE;
   1884 						break;
   1885 					}
   1886 				}
   1887 			}
   1888 		} else if (nvt == DATA_TYPE_STRING_ARRAY) {
   1889 			st = nvpair_value_string_array(fnvp, &arr, &vcount);
   1890 			if (st == 0) {
   1891 				for (j = 0; j < vcount; j++) {
   1892 					for (i = 0; i < count; i++) {
   1893 						if (strcmp(val, varray[i])
   1894 						    == 0) {
   1895 							/* a keeper */
   1896 							keep = B_TRUE;
   1897 							break;
   1898 						}
   1899 					}
   1900 					if (keep) {
   1901 						break;
   1902 					}
   1903 				}
   1904 			}
   1905 		}
   1906 
   1907 		if (keep) {
   1908 			lastnvp = nvp;
   1909 		} else {
   1910 			(void) nvlist_remove_all(nvl, attrname);
   1911 			nvp = lastnvp;
   1912 		}
   1913 	}
   1914 }
   1915