xref: /onnv-gate/usr/src/cmd/acctadm/utils.c (revision 13093:48f2dbca79a2)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54891Svk199839  * Common Development and Distribution License (the "License").
64891Svk199839  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21*13093SRoger.Faulkner@Oracle.COM 
220Sstevel@tonic-gate /*
23*13093SRoger.Faulkner@Oracle.COM  * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
267103Sml93401 #include <assert.h>
277103Sml93401 #include <sys/types.h>
287103Sml93401 #include <sys/acctctl.h>
290Sstevel@tonic-gate #include <sys/param.h>
307103Sml93401 #include <sys/stat.h>
310Sstevel@tonic-gate #include <libintl.h>
320Sstevel@tonic-gate #include <string.h>
330Sstevel@tonic-gate #include <stdlib.h>
340Sstevel@tonic-gate #include <stdarg.h>
350Sstevel@tonic-gate #include <stdio.h>
367103Sml93401 #include <strings.h>
377103Sml93401 #include <unistd.h>
380Sstevel@tonic-gate #include <errno.h>
397103Sml93401 #include <exacct.h>
407103Sml93401 #include <fcntl.h>
417103Sml93401 #include <priv.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #include "utils.h"
440Sstevel@tonic-gate 
450Sstevel@tonic-gate static char PNAME_FMT[] = "%s: ";
460Sstevel@tonic-gate static char ERRNO_FMT[] = ": %s\n";
470Sstevel@tonic-gate 
480Sstevel@tonic-gate static char *pname;
490Sstevel@tonic-gate 
500Sstevel@tonic-gate /*PRINTFLIKE1*/
510Sstevel@tonic-gate void
warn(const char * format,...)524891Svk199839 warn(const char *format, ...)
530Sstevel@tonic-gate {
540Sstevel@tonic-gate 	int err = errno;
550Sstevel@tonic-gate 	va_list alist;
560Sstevel@tonic-gate 	if (pname != NULL)
570Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(PNAME_FMT), pname);
580Sstevel@tonic-gate 	va_start(alist, format);
590Sstevel@tonic-gate 	(void) vfprintf(stderr, format, alist);
600Sstevel@tonic-gate 	va_end(alist);
610Sstevel@tonic-gate 	if (strchr(format, '\n') == NULL)
620Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERRNO_FMT), strerror(err));
630Sstevel@tonic-gate }
640Sstevel@tonic-gate 
650Sstevel@tonic-gate /*PRINTFLIKE1*/
660Sstevel@tonic-gate void
die(char * format,...)670Sstevel@tonic-gate die(char *format, ...)
680Sstevel@tonic-gate {
690Sstevel@tonic-gate 	int err = errno;
700Sstevel@tonic-gate 	va_list alist;
710Sstevel@tonic-gate 
720Sstevel@tonic-gate 	if (pname != NULL)
730Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(PNAME_FMT), pname);
740Sstevel@tonic-gate 	va_start(alist, format);
750Sstevel@tonic-gate 	(void) vfprintf(stderr, format, alist);
760Sstevel@tonic-gate 	va_end(alist);
770Sstevel@tonic-gate 	if (strchr(format, '\n') == NULL)
780Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERRNO_FMT), strerror(err));
798453SAnurag.Maskey@Sun.COM 
808453SAnurag.Maskey@Sun.COM 	/* close the libdladm handle if it was opened */
818453SAnurag.Maskey@Sun.COM 	if (dld_handle != NULL)
828453SAnurag.Maskey@Sun.COM 		dladm_close(dld_handle);
838453SAnurag.Maskey@Sun.COM 
840Sstevel@tonic-gate 	exit(E_ERROR);
850Sstevel@tonic-gate }
860Sstevel@tonic-gate 
870Sstevel@tonic-gate char *
setpname(char * arg0)88*13093SRoger.Faulkner@Oracle.COM setpname(char *arg0)
890Sstevel@tonic-gate {
900Sstevel@tonic-gate 	char *p = strrchr(arg0, '/');
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	if (p == NULL)
930Sstevel@tonic-gate 		p = arg0;
940Sstevel@tonic-gate 	else
950Sstevel@tonic-gate 		p++;
960Sstevel@tonic-gate 	pname = p;
970Sstevel@tonic-gate 	return (pname);
980Sstevel@tonic-gate }
990Sstevel@tonic-gate 
1007103Sml93401 /*
1017103Sml93401  * Return the localized name of an accounting type.
1027103Sml93401  */
1037103Sml93401 const char *
ac_type_name(int type)1047103Sml93401 ac_type_name(int type)
1057103Sml93401 {
1067103Sml93401 	switch (type) {
1077103Sml93401 	case AC_PROC:
1087103Sml93401 		return (gettext("process"));
1097103Sml93401 	case AC_FLOW:
1107103Sml93401 		return (gettext("flow"));
1117103Sml93401 	case AC_TASK:
1127103Sml93401 		return (gettext("task"));
1138275SEric Cheng 	case AC_NET:
1148275SEric Cheng 		return (gettext("net"));
1157103Sml93401 	default:
1167103Sml93401 		die(gettext("invalid type %d\n"), type);
1177103Sml93401 	}
1187103Sml93401 	/* NOTREACHED */
1197103Sml93401 	return (NULL);
1207103Sml93401 }
1217103Sml93401 
1227103Sml93401 /*
1237103Sml93401  * Open an accounting file.  The filename specified must be an absolute
1247103Sml93401  * pathname and the existing contents of the file (if any) must be of the
1257103Sml93401  * requested type.  Needs euid 0 to open the root-owned accounting file.
1267103Sml93401  * file_dac_write is required to create a new file in a directory not owned
1277103Sml93401  * by root (/var/adm/exacct is owned by 'adm').  Assumes sys_acct privilege is
1287103Sml93401  * already asserted by caller.
1297103Sml93401  */
1300Sstevel@tonic-gate int
open_exacct_file(const char * file,int type)1317103Sml93401 open_exacct_file(const char *file, int type)
1320Sstevel@tonic-gate {
1337103Sml93401 	int rc;
1347103Sml93401 	int err;
1357103Sml93401 
1367103Sml93401 	if (file[0] != '/') {
1377103Sml93401 		warn(gettext("%s is not an absolute pathname\n"), file);
1387103Sml93401 		return (-1);
1397103Sml93401 	}
1407103Sml93401 	if (!verify_exacct_file(file, type)) {
1417103Sml93401 		warn(gettext("%s is not a %s accounting file\n"), file,
1427103Sml93401 		    ac_type_name(type));
1437103Sml93401 		return (-1);
1447103Sml93401 	}
1457103Sml93401 	if (seteuid(0) == -1 || setegid(0) == -1) {
1467103Sml93401 		warn(gettext("seteuid()/setegid() failed"));
1477103Sml93401 		return (-1);
1487103Sml93401 	}
1497103Sml93401 	assert(priv_ineffect(PRIV_SYS_ACCT));
1507103Sml93401 	(void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE, NULL);
1517103Sml93401 	rc = acctctl(type | AC_FILE_SET, (void *) file, strlen(file) + 1);
1527103Sml93401 	if (rc == -1 && (err = errno) == EBUSY) {
1537103Sml93401 		char name[MAXPATHLEN];
1547103Sml93401 		struct stat cur;
1557103Sml93401 		struct stat new;
1567103Sml93401 
1577103Sml93401 		/*
1587103Sml93401 		 * The file is already open as an accounting file somewhere.
1597103Sml93401 		 * If the file we're trying to open is the same as we have
1607103Sml93401 		 * currently open then we're ok.
1617103Sml93401 		 */
1627103Sml93401 		if (acctctl(type | AC_FILE_GET, name, sizeof (name)) == 0 &&
1637103Sml93401 		    stat(file, &new) != -1 && stat(name, &cur) != -1 &&
1647103Sml93401 		    new.st_dev == cur.st_dev && new.st_ino == cur.st_ino)
1657103Sml93401 			rc = 0;
1660Sstevel@tonic-gate 	}
1677103Sml93401 
1687103Sml93401 	/*
1697103Sml93401 	 * euid 0, egid 0 and the file_dac_write privilege are no longer
1707103Sml93401 	 * required; give them up permanently.
1717103Sml93401 	 */
1727103Sml93401 	(void) priv_set(PRIV_OFF, PRIV_PERMITTED, PRIV_FILE_DAC_WRITE, NULL);
1737103Sml93401 	if (setreuid(getuid(), getuid()) == -1 ||
1747103Sml93401 	    setregid(getgid(), getgid()) == -1)
1757103Sml93401 		die(gettext("setreuid()/setregid() failed"));
1767103Sml93401 	if (rc == 0)
1770Sstevel@tonic-gate 		return (0);
1787103Sml93401 
1797103Sml93401 	warn(gettext("cannot open %s accounting file %s: %s\n"),
1807103Sml93401 	    ac_type_name(type), file, strerror(err));
1817103Sml93401 	return (-1);
1827103Sml93401 }
1837103Sml93401 
1847103Sml93401 /*
1857103Sml93401  * Verify that the file contents (if any) are extended accounting records
1867103Sml93401  * of the desired type.
1877103Sml93401  */
1887103Sml93401 boolean_t
verify_exacct_file(const char * file,int type)1897103Sml93401 verify_exacct_file(const char *file, int type)
1907103Sml93401 {
1917103Sml93401 	ea_file_t ef;
1927103Sml93401 	ea_object_t eo;
1937103Sml93401 	struct stat st;
1947103Sml93401 	int err;
1957103Sml93401 
1967103Sml93401 	if (stat(file, &st) != -1 && st.st_size != 0) {
1977103Sml93401 		if (seteuid(0) == -1)
1987103Sml93401 			return (B_FALSE);
1997103Sml93401 		err = ea_open(&ef, file, "SunOS", EO_TAIL, O_RDONLY, 0);
2007103Sml93401 		if (seteuid(getuid()) == 1)
2017103Sml93401 			die(gettext("seteuid() failed"));
2027103Sml93401 		if (err == -1)
2037103Sml93401 			return (B_FALSE);
2047103Sml93401 
2057103Sml93401 		bzero(&eo, sizeof (eo));
2067103Sml93401 		if (ea_previous_object(&ef, &eo) == EO_ERROR) {
2077103Sml93401 			/*
2087103Sml93401 			 * EXR_EOF indicates there are no non-header objects
2097103Sml93401 			 * in the file.  It can't be determined that this
2107103Sml93401 			 * file is or is not the proper type of extended
2117103Sml93401 			 * accounting file, which isn't necessarily an error.
2127103Sml93401 			 * Since it is a proper (albeit empty) extended
2137103Sml93401 			 * accounting file, it matches any desired type.
2147103Sml93401 			 *
2157103Sml93401 			 * if ea_previous_object() failed for any other reason
2167103Sml93401 			 * than EXR_EOF, the file must be corrupt.
2177103Sml93401 			 */
2187103Sml93401 			if (ea_error() != EXR_EOF) {
2197103Sml93401 				(void) ea_close(&ef);
2207103Sml93401 				return (B_FALSE);
2217103Sml93401 			}
2227103Sml93401 		} else {
2237103Sml93401 			/*
2247103Sml93401 			 * A non-header object exists.  Insist that it be
2258275SEric Cheng 			 * either a process, task, flow  or net accounting
2268275SEric Cheng 			 * record, the same type as is desired.
2278275SEric Cheng 			 * xxx-venu:check 101 merge for EXD_GROUP_NET_*
2287103Sml93401 			 */
2297103Sml93401 			uint_t c = eo.eo_catalog & EXD_DATA_MASK;
2307103Sml93401 
2317103Sml93401 			if (eo.eo_type != EO_GROUP ||
2327103Sml93401 			    (eo.eo_catalog & EXC_CATALOG_MASK) != EXC_NONE ||
2337103Sml93401 			    (!(c == EXD_GROUP_PROC && type == AC_PROC ||
2347103Sml93401 			    c == EXD_GROUP_TASK && type == AC_TASK ||
2358275SEric Cheng 			    c == EXD_GROUP_FLOW && type == AC_FLOW ||
2368275SEric Cheng 			    (c == EXD_GROUP_NET_LINK_DESC ||
2378275SEric Cheng 			    c == EXD_GROUP_NET_FLOW_DESC ||
2388275SEric Cheng 			    c == EXD_GROUP_NET_LINK_STATS ||
2398275SEric Cheng 			    c == EXD_GROUP_NET_FLOW_STATS) &&
2408275SEric Cheng 			    type == AC_NET))) {
2417103Sml93401 				(void) ea_close(&ef);
2427103Sml93401 				return (B_FALSE);
2437103Sml93401 			}
2447103Sml93401 		}
2457103Sml93401 		(void) ea_close(&ef);
2460Sstevel@tonic-gate 	}
2477103Sml93401 	return (B_TRUE);
2480Sstevel@tonic-gate }
249