17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5d362b749Svk * Common Development and Distribution License (the "License"). 6d362b749Svk * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22074e084fSml * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23d362b749Svk * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 26074e084fSml #include <assert.h> 27074e084fSml #include <sys/types.h> 28074e084fSml #include <sys/acctctl.h> 297c478bd9Sstevel@tonic-gate #include <sys/param.h> 30074e084fSml #include <sys/stat.h> 317c478bd9Sstevel@tonic-gate #include <libintl.h> 327c478bd9Sstevel@tonic-gate #include <string.h> 337c478bd9Sstevel@tonic-gate #include <stdlib.h> 347c478bd9Sstevel@tonic-gate #include <stdarg.h> 357c478bd9Sstevel@tonic-gate #include <stdio.h> 36074e084fSml #include <strings.h> 37074e084fSml #include <unistd.h> 387c478bd9Sstevel@tonic-gate #include <errno.h> 39074e084fSml #include <exacct.h> 40074e084fSml #include <fcntl.h> 41074e084fSml #include <priv.h> 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate #include "utils.h" 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate static char PNAME_FMT[] = "%s: "; 467c478bd9Sstevel@tonic-gate static char ERRNO_FMT[] = ": %s\n"; 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate static char *pname; 497c478bd9Sstevel@tonic-gate 507c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 517c478bd9Sstevel@tonic-gate void 52d362b749Svk warn(const char *format, ...) 537c478bd9Sstevel@tonic-gate { 547c478bd9Sstevel@tonic-gate int err = errno; 557c478bd9Sstevel@tonic-gate va_list alist; 567c478bd9Sstevel@tonic-gate if (pname != NULL) 577c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(PNAME_FMT), pname); 587c478bd9Sstevel@tonic-gate va_start(alist, format); 597c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, format, alist); 607c478bd9Sstevel@tonic-gate va_end(alist); 617c478bd9Sstevel@tonic-gate if (strchr(format, '\n') == NULL) 627c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERRNO_FMT), strerror(err)); 637c478bd9Sstevel@tonic-gate } 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 667c478bd9Sstevel@tonic-gate void 677c478bd9Sstevel@tonic-gate die(char *format, ...) 687c478bd9Sstevel@tonic-gate { 697c478bd9Sstevel@tonic-gate int err = errno; 707c478bd9Sstevel@tonic-gate va_list alist; 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate if (pname != NULL) 737c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(PNAME_FMT), pname); 747c478bd9Sstevel@tonic-gate va_start(alist, format); 757c478bd9Sstevel@tonic-gate (void) vfprintf(stderr, format, alist); 767c478bd9Sstevel@tonic-gate va_end(alist); 777c478bd9Sstevel@tonic-gate if (strchr(format, '\n') == NULL) 787c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(ERRNO_FMT), strerror(err)); 797c478bd9Sstevel@tonic-gate exit(E_ERROR); 807c478bd9Sstevel@tonic-gate } 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate char * 837c478bd9Sstevel@tonic-gate setprogname(char *arg0) 847c478bd9Sstevel@tonic-gate { 857c478bd9Sstevel@tonic-gate char *p = strrchr(arg0, '/'); 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate if (p == NULL) 887c478bd9Sstevel@tonic-gate p = arg0; 897c478bd9Sstevel@tonic-gate else 907c478bd9Sstevel@tonic-gate p++; 917c478bd9Sstevel@tonic-gate pname = p; 927c478bd9Sstevel@tonic-gate return (pname); 937c478bd9Sstevel@tonic-gate } 947c478bd9Sstevel@tonic-gate 95074e084fSml /* 96074e084fSml * Return the localized name of an accounting type. 97074e084fSml */ 98074e084fSml const char * 99074e084fSml ac_type_name(int type) 100074e084fSml { 101074e084fSml switch (type) { 102074e084fSml case AC_PROC: 103074e084fSml return (gettext("process")); 104074e084fSml case AC_FLOW: 105074e084fSml return (gettext("flow")); 106074e084fSml case AC_TASK: 107074e084fSml return (gettext("task")); 108*da14cebeSEric Cheng case AC_NET: 109*da14cebeSEric Cheng return (gettext("net")); 110074e084fSml default: 111074e084fSml die(gettext("invalid type %d\n"), type); 112074e084fSml } 113074e084fSml /* NOTREACHED */ 114074e084fSml return (NULL); 115074e084fSml } 116074e084fSml 117074e084fSml /* 118074e084fSml * Open an accounting file. The filename specified must be an absolute 119074e084fSml * pathname and the existing contents of the file (if any) must be of the 120074e084fSml * requested type. Needs euid 0 to open the root-owned accounting file. 121074e084fSml * file_dac_write is required to create a new file in a directory not owned 122074e084fSml * by root (/var/adm/exacct is owned by 'adm'). Assumes sys_acct privilege is 123074e084fSml * already asserted by caller. 124074e084fSml */ 1257c478bd9Sstevel@tonic-gate int 126074e084fSml open_exacct_file(const char *file, int type) 1277c478bd9Sstevel@tonic-gate { 128074e084fSml int rc; 129074e084fSml int err; 130074e084fSml 131074e084fSml if (file[0] != '/') { 132074e084fSml warn(gettext("%s is not an absolute pathname\n"), file); 133074e084fSml return (-1); 1347c478bd9Sstevel@tonic-gate } 135074e084fSml if (!verify_exacct_file(file, type)) { 136074e084fSml warn(gettext("%s is not a %s accounting file\n"), file, 137074e084fSml ac_type_name(type)); 138074e084fSml return (-1); 139074e084fSml } 140074e084fSml if (seteuid(0) == -1 || setegid(0) == -1) { 141074e084fSml warn(gettext("seteuid()/setegid() failed")); 142074e084fSml return (-1); 143074e084fSml } 144074e084fSml assert(priv_ineffect(PRIV_SYS_ACCT)); 145074e084fSml (void) priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_WRITE, NULL); 146074e084fSml rc = acctctl(type | AC_FILE_SET, (void *) file, strlen(file) + 1); 147074e084fSml if (rc == -1 && (err = errno) == EBUSY) { 148074e084fSml char name[MAXPATHLEN]; 149074e084fSml struct stat cur; 150074e084fSml struct stat new; 151074e084fSml 152074e084fSml /* 153074e084fSml * The file is already open as an accounting file somewhere. 154074e084fSml * If the file we're trying to open is the same as we have 155074e084fSml * currently open then we're ok. 156074e084fSml */ 157074e084fSml if (acctctl(type | AC_FILE_GET, name, sizeof (name)) == 0 && 158074e084fSml stat(file, &new) != -1 && stat(name, &cur) != -1 && 159074e084fSml new.st_dev == cur.st_dev && new.st_ino == cur.st_ino) 160074e084fSml rc = 0; 161074e084fSml } 162074e084fSml 163074e084fSml /* 164074e084fSml * euid 0, egid 0 and the file_dac_write privilege are no longer 165074e084fSml * required; give them up permanently. 166074e084fSml */ 167074e084fSml (void) priv_set(PRIV_OFF, PRIV_PERMITTED, PRIV_FILE_DAC_WRITE, NULL); 168074e084fSml if (setreuid(getuid(), getuid()) == -1 || 169074e084fSml setregid(getgid(), getgid()) == -1) 170074e084fSml die(gettext("setreuid()/setregid() failed")); 171074e084fSml if (rc == 0) 1727c478bd9Sstevel@tonic-gate return (0); 173074e084fSml 174074e084fSml warn(gettext("cannot open %s accounting file %s: %s\n"), 175074e084fSml ac_type_name(type), file, strerror(err)); 176074e084fSml return (-1); 177074e084fSml } 178074e084fSml 179074e084fSml /* 180074e084fSml * Verify that the file contents (if any) are extended accounting records 181074e084fSml * of the desired type. 182074e084fSml */ 183074e084fSml boolean_t 184074e084fSml verify_exacct_file(const char *file, int type) 185074e084fSml { 186074e084fSml ea_file_t ef; 187074e084fSml ea_object_t eo; 188074e084fSml struct stat st; 189074e084fSml int err; 190074e084fSml 191074e084fSml if (stat(file, &st) != -1 && st.st_size != 0) { 192074e084fSml if (seteuid(0) == -1) 193074e084fSml return (B_FALSE); 194074e084fSml err = ea_open(&ef, file, "SunOS", EO_TAIL, O_RDONLY, 0); 195074e084fSml if (seteuid(getuid()) == 1) 196074e084fSml die(gettext("seteuid() failed")); 197074e084fSml if (err == -1) 198074e084fSml return (B_FALSE); 199074e084fSml 200074e084fSml bzero(&eo, sizeof (eo)); 201074e084fSml if (ea_previous_object(&ef, &eo) == EO_ERROR) { 202074e084fSml /* 203074e084fSml * EXR_EOF indicates there are no non-header objects 204074e084fSml * in the file. It can't be determined that this 205074e084fSml * file is or is not the proper type of extended 206074e084fSml * accounting file, which isn't necessarily an error. 207074e084fSml * Since it is a proper (albeit empty) extended 208074e084fSml * accounting file, it matches any desired type. 209074e084fSml * 210074e084fSml * if ea_previous_object() failed for any other reason 211074e084fSml * than EXR_EOF, the file must be corrupt. 212074e084fSml */ 213074e084fSml if (ea_error() != EXR_EOF) { 214074e084fSml (void) ea_close(&ef); 215074e084fSml return (B_FALSE); 216074e084fSml } 217074e084fSml } else { 218074e084fSml /* 219074e084fSml * A non-header object exists. Insist that it be 220*da14cebeSEric Cheng * either a process, task, flow or net accounting 221*da14cebeSEric Cheng * record, the same type as is desired. 222*da14cebeSEric Cheng * xxx-venu:check 101 merge for EXD_GROUP_NET_* 223074e084fSml */ 224074e084fSml uint_t c = eo.eo_catalog & EXD_DATA_MASK; 225074e084fSml 226074e084fSml if (eo.eo_type != EO_GROUP || 227074e084fSml (eo.eo_catalog & EXC_CATALOG_MASK) != EXC_NONE || 228074e084fSml (!(c == EXD_GROUP_PROC && type == AC_PROC || 229074e084fSml c == EXD_GROUP_TASK && type == AC_TASK || 230*da14cebeSEric Cheng c == EXD_GROUP_FLOW && type == AC_FLOW || 231*da14cebeSEric Cheng (c == EXD_GROUP_NET_LINK_DESC || 232*da14cebeSEric Cheng c == EXD_GROUP_NET_FLOW_DESC || 233*da14cebeSEric Cheng c == EXD_GROUP_NET_LINK_STATS || 234*da14cebeSEric Cheng c == EXD_GROUP_NET_FLOW_STATS) && 235*da14cebeSEric Cheng type == AC_NET))) { 236074e084fSml (void) ea_close(&ef); 237074e084fSml return (B_FALSE); 238074e084fSml } 239074e084fSml } 240074e084fSml (void) ea_close(&ef); 2417c478bd9Sstevel@tonic-gate } 242074e084fSml return (B_TRUE); 2437c478bd9Sstevel@tonic-gate } 244