17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
5d362b74vk * Common Development and Distribution License (the "License").
6d362b74vk * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
2123a1cceRoger A. Faulkner
227c478bdstevel@tonic-gate/*
2323a1cceRoger A. Faulkner * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bdstevel@tonic-gate */
257c478bdstevel@tonic-gate
26074e084ml#include <assert.h>
27074e084ml#include <sys/types.h>
28074e084ml#include <sys/acctctl.h>
297c478bdstevel@tonic-gate#include <sys/param.h>
30074e084ml#include <sys/stat.h>
317c478bdstevel@tonic-gate#include <libintl.h>
327c478bdstevel@tonic-gate#include <string.h>
337c478bdstevel@tonic-gate#include <stdlib.h>
347c478bdstevel@tonic-gate#include <stdarg.h>
357c478bdstevel@tonic-gate#include <stdio.h>
36074e084ml#include <strings.h>
37074e084ml#include <unistd.h>
387c478bdstevel@tonic-gate#include <errno.h>
39074e084ml#include <exacct.h>
40074e084ml#include <fcntl.h>
41074e084ml#include <priv.h>
427c478bdstevel@tonic-gate
437c478bdstevel@tonic-gate#include "utils.h"
447c478bdstevel@tonic-gate
457c478bdstevel@tonic-gatestatic char PNAME_FMT[] = "%s: ";
467c478bdstevel@tonic-gatestatic char ERRNO_FMT[] = ": %s\n";
477c478bdstevel@tonic-gate
487c478bdstevel@tonic-gatestatic char *pname;
497c478bdstevel@tonic-gate
507c478bdstevel@tonic-gate/*PRINTFLIKE1*/
517c478bdstevel@tonic-gatevoid
52d362b74vkwarn(const char *format, ...)
537c478bdstevel@tonic-gate{
547c478bdstevel@tonic-gate	int err = errno;
557c478bdstevel@tonic-gate	va_list alist;
567c478bdstevel@tonic-gate	if (pname != NULL)
577c478bdstevel@tonic-gate		(void) fprintf(stderr, gettext(PNAME_FMT), pname);
587c478bdstevel@tonic-gate	va_start(alist, format);
597c478bdstevel@tonic-gate	(void) vfprintf(stderr, format, alist);
607c478bdstevel@tonic-gate	va_end(alist);
617c478bdstevel@tonic-gate	if (strchr(format, '\n') == NULL)
627c478bdstevel@tonic-gate		(void) fprintf(stderr, gettext(ERRNO_FMT), strerror(err));
637c478bdstevel@tonic-gate}
647c478bdstevel@tonic-gate
657c478bdstevel@tonic-gate/*PRINTFLIKE1*/
667c478bdstevel@tonic-gatevoid
677c478bdstevel@tonic-gatedie(char *format, ...)
687c478bdstevel@tonic-gate{
697c478bdstevel@tonic-gate	int err = errno;
707c478bdstevel@tonic-gate	va_list alist;
717c478bdstevel@tonic-gate
727c478bdstevel@tonic-gate	if (pname != NULL)
737c478bdstevel@tonic-gate		(void) fprintf(stderr, gettext(PNAME_FMT), pname);
747c478bdstevel@tonic-gate	va_start(alist, format);
757c478bdstevel@tonic-gate	(void) vfprintf(stderr, format, alist);
767c478bdstevel@tonic-gate	va_end(alist);
777c478bdstevel@tonic-gate	if (strchr(format, '\n') == NULL)
787c478bdstevel@tonic-gate		(void) fprintf(stderr, gettext(ERRNO_FMT), strerror(err));
794ac67f0Anurag S. Maskey
804ac67f0Anurag S. Maskey	/* close the libdladm handle if it was opened */
814ac67f0Anurag S. Maskey	if (dld_handle != NULL)
824ac67f0Anurag S. Maskey		dladm_close(dld_handle);
834ac67f0Anurag S. Maskey
847c478bdstevel@tonic-gate	exit(E_ERROR);
857c478bdstevel@tonic-gate}
867c478bdstevel@tonic-gate
877c478bdstevel@tonic-gatechar *
8823a1cceRoger A. Faulknersetpname(char *arg0)
897c478bdstevel@tonic-gate{
907c478bdstevel@tonic-gate	char *p = strrchr(arg0, '/');
917c478bdstevel@tonic-gate
927c478bdstevel@tonic-gate	if (p == NULL)
937c478bdstevel@tonic-gate		p = arg0;
947c478bdstevel@tonic-gate	else
957c478bdstevel@tonic-gate		p++;
967c478bdstevel@tonic-gate	pname = p;
977c478bdstevel@tonic-gate	return (pname);
987c478bdstevel@tonic-gate}
997c478bdstevel@tonic-gate
100074e084ml/*
101074e084ml * Return the localized name of an accounting type.
102074e084ml */
103074e084mlconst char *
104074e084mlac_type_name(int type)
105074e084ml{
106074e084ml	switch (type) {
107074e084ml	case AC_PROC:
108074e084ml		return (gettext("process"));
109074e084ml	case AC_FLOW:
110074e084ml		return (gettext("flow"));
111074e084ml	case AC_TASK:
112074e084ml		return (gettext("task"));
113da14cebEric Cheng	case AC_NET:
114da14cebEric Cheng		return (gettext("net"));
115074e084ml	default:
116074e084ml		die(gettext("invalid type %d\n"), type);
117074e084ml	}
118074e084ml	/* NOTREACHED */
119074e084ml	return (NULL);
120074e084ml}
121074e084ml
122074e084ml/*
123074e084ml * Open an accounting file.  The filename specified must be an absolute
124074e084ml * pathname and the existing contents of the file (if any) must be of the
125074e084ml * requested type.  Needs euid 0 to open the root-owned accounting file.
126074e084ml * file_dac_write is required to create a new file in a directory not owned
127074e084ml * by root (/var/adm/exacct is owned by 'adm').  Assumes sys_acct privilege is
128074e084ml * already asserted by caller.
129074e084ml */
1307c478bdstevel@tonic-gateint
131074e084mlopen_exacct_file(const char *file, int type)
1327c478bdstevel@tonic-gate{
133074e084ml	int rc;
134074e084ml	int err;
135074e084ml
136074e084ml	if (file[0] != '/') {
137074e084ml		warn(gettext("%s is not an absolute pathname\n"), file);
138074e084ml		return (-1);
1397c478bdstevel@tonic-gate	}
140074e084ml	if (!verify_exacct_file(file, type)) {
141074e084ml		warn(gettext("%s is not a %s accounting file\n"), file,
142074e084ml		    ac_type_name(type));
143074e084ml		return (-1);
144074e084ml	}
145074e084ml	if (seteuid(0) == -1 || setegid(0) == -1) {
146074e084ml		warn(gettext("seteuid()/setegid() failed"));
147074e084ml		return (-1);
148074e084ml	}
149074e084ml	assert(priv_ineffect(PRIV_SYS_ACCT));
150074e084ml	(void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE, NULL);
151074e084ml	rc = acctctl(type | AC_FILE_SET, (void *) file, strlen(file) + 1);
152074e084ml	if (rc == -1 && (err = errno) == EBUSY) {
153074e084ml		char name[MAXPATHLEN];
154074e084ml		struct stat cur;
155074e084ml		struct stat new;
156074e084ml
157074e084ml		/*
158074e084ml		 * The file is already open as an accounting file somewhere.
159074e084ml		 * If the file we're trying to open is the same as we have
160074e084ml		 * currently open then we're ok.
161074e084ml		 */
162074e084ml		if (acctctl(type | AC_FILE_GET, name, sizeof (name)) == 0 &&
163074e084ml		    stat(file, &new) != -1 && stat(name, &cur) != -1 &&
164074e084ml		    new.st_dev == cur.st_dev && new.st_ino == cur.st_ino)
165074e084ml			rc = 0;
166074e084ml	}
167074e084ml
168074e084ml	/*
169074e084ml	 * euid 0, egid 0 and the file_dac_write privilege are no longer
170074e084ml	 * required; give them up permanently.
171074e084ml	 */
172074e084ml	(void) priv_set(PRIV_OFF, PRIV_PERMITTED, PRIV_FILE_DAC_WRITE, NULL);
173074e084ml	if (setreuid(getuid(), getuid()) == -1 ||
174074e084ml	    setregid(getgid(), getgid()) == -1)
175074e084ml		die(gettext("setreuid()/setregid() failed"));
176074e084ml	if (rc == 0)
1777c478bdstevel@tonic-gate		return (0);
178074e084ml
179074e084ml	warn(gettext("cannot open %s accounting file %s: %s\n"),
180074e084ml	    ac_type_name(type), file, strerror(err));
181074e084ml	return (-1);
182074e084ml}
183074e084ml
184074e084ml/*
185074e084ml * Verify that the file contents (if any) are extended accounting records
186074e084ml * of the desired type.
187074e084ml */
188074e084mlboolean_t
189074e084mlverify_exacct_file(const char *file, int type)
190074e084ml{
191074e084ml	ea_file_t ef;
192074e084ml	ea_object_t eo;
193074e084ml	struct stat st;
194074e084ml	int err;
195074e084ml
196074e084ml	if (stat(file, &st) != -1 && st.st_size != 0) {
197074e084ml		if (seteuid(0) == -1)
198074e084ml			return (B_FALSE);
199074e084ml		err = ea_open(&ef, file, "SunOS", EO_TAIL, O_RDONLY, 0);
200074e084ml		if (seteuid(getuid()) == 1)
201074e084ml			die(gettext("seteuid() failed"));
202074e084ml		if (err == -1)
203074e084ml			return (B_FALSE);
204074e084ml
205074e084ml		bzero(&eo, sizeof (eo));
206074e084ml		if (ea_previous_object(&ef, &eo) == EO_ERROR) {
207074e084ml			/*
208074e084ml			 * EXR_EOF indicates there are no non-header objects
209074e084ml			 * in the file.  It can't be determined that this
210074e084ml			 * file is or is not the proper type of extended
211074e084ml			 * accounting file, which isn't necessarily an error.
212074e084ml			 * Since it is a proper (albeit empty) extended
213074e084ml			 * accounting file, it matches any desired type.
214074e084ml			 *
215074e084ml			 * if ea_previous_object() failed for any other reason
216074e084ml			 * than EXR_EOF, the file must be corrupt.
217074e084ml			 */
218074e084ml			if (ea_error() != EXR_EOF) {
219074e084ml				(void) ea_close(&ef);
220074e084ml				return (B_FALSE);
221074e084ml			}
222074e084ml		} else {
223074e084ml			/*
224074e084ml			 * A non-header object exists.  Insist that it be
225da14cebEric Cheng			 * either a process, task, flow  or net accounting
226da14cebEric Cheng			 * record, the same type as is desired.
227da14cebEric Cheng			 * xxx-venu:check 101 merge for EXD_GROUP_NET_*
228074e084ml			 */
229074e084ml			uint_t c = eo.eo_catalog & EXD_DATA_MASK;
230074e084ml
231074e084ml			if (eo.eo_type != EO_GROUP ||
232074e084ml			    (eo.eo_catalog & EXC_CATALOG_MASK) != EXC_NONE ||
233074e084ml			    (!(c == EXD_GROUP_PROC && type == AC_PROC ||
234074e084ml			    c == EXD_GROUP_TASK && type == AC_TASK ||
235da14cebEric Cheng			    c == EXD_GROUP_FLOW && type == AC_FLOW ||
236da14cebEric Cheng			    (c == EXD_GROUP_NET_LINK_DESC ||
237da14cebEric Cheng			    c == EXD_GROUP_NET_FLOW_DESC ||
238da14cebEric Cheng			    c == EXD_GROUP_NET_LINK_STATS ||
239da14cebEric Cheng			    c == EXD_GROUP_NET_FLOW_STATS) &&
240da14cebEric Cheng			    type == AC_NET))) {
241074e084ml				(void) ea_close(&ef);
242074e084ml				return (B_FALSE);
243074e084ml			}
244074e084ml		}
245074e084ml		(void) ea_close(&ef);
2467c478bdstevel@tonic-gate	}
247074e084ml	return (B_TRUE);
2487c478bdstevel@tonic-gate}
249