#!/usr/bin/perl # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # # # Licensed Materials - Property of IBM # # (C) COPYRIGHT International Business Machines Corp. 2005,2019 # All Rights Reserved # # US Government Users Restricted Rights - Use, duplication or # disclosure restricted by GSA ADP Schedule Contract with IBM Corp. # # IBM_PROLOG_END_TAG # sccsid = "@(#)03 1.6 src/rsct/utils/cli/bin/ctadmingroup.perl, common_utils, rsct_rady, rady2035a 9/24/15 07:55:48" ###################################################################### # # # Module: ctadmingroup # # # # Purpose: # # ctadmingroup - define a cluster administrative group # # # # Syntax: # # # # ctadmingroup [-h] # # [-TV] [-u] # # [-TV] [Group_name] # # # # Flags # # # # -h Writes the command's usage statement to standard output. # # # # -T Writes the command's trace messages to standard error. For # # your software service organization's use only. # # # # -V Writes the command's verbose messages to standard output. # # # # -u removes (unsets) the cluster administrative group # # # # Operands: # # # # Group_name: administrative group name. This group must already # # exist in the group database (likely /etc/group) # # # # # # Description: # # # # # # The ctadmingroup command is used to define a cluster # # administrative group. The users belonging to such administrative # # group are given permission, by this command, to examine trace # # files produced by RSCT subsystems. The command has the effect of # # setting trace file group ownership, so that users that belong to # # the given group have appropriate permissions to the trace files. # # Existing trace files are changed by the command to the # # new permissions and group ownership, and trace files created after # # the command is run will contain the new permissions. # # # # Note that the command does not create the given group, nor does it # # add users to that group -- it only allows users of that group # # access to the trace files. # # # # The command can also be invoked to remove (unset) the cluster # # administrative group. After such action is taken ("-u" option), # # users that belong to that group may be unable to examine trace # # files. No output is produced if the "-u" option is used but no # # administrative group was previously defined. # # # # Running the command with a different group name results in the # # new group taking effect as the cluster administrative group, # # replacing the previous group. # # # # When run with no arguments or options, the command will display # # the group name and ID of the administrative group. No output is # # produced if no administrative group is defined. # # # # # # Exit Values: # # 0 The command ran successfully. # # 1 Given group name is not in the group database # # 2 Internal error # # 3 An incorrect flag was entered on the command line # # 4 An incorrect operand was entered on the command line # # # # Man Page: # # For the most current detailed description of this command see # # the mkrpdomain man page in /opt/rsct/man. # # # #--------------------------------------------------------------------# # # # Inputs: # # /opt/rsct/msgmaps/cucli.ctadmingroup.map - # # message mapping # # # # Outputs: # # stdout - none. # # stderr - any error message. # # # # External Ref: # # Commands: ctdspmsg # # Modules: CT_cli_utils.pm, CU_cli_rc.pm, # # CRM_cli_include.pm # # Perl library routines: Getopt::Std # # # # # # Change Activity: # # 050516 FK 118713: Initial design & write. # # 050609 JAC 123591: Change use CRM_cli_include to MC_cli_utils. # # 050705 JAC 125004: Use octal when printing file/directory mode. # # # # # ###################################################################### #--------------------------------------------------------------------# # Included Libraries and Extensions # #--------------------------------------------------------------------# use lib "/opt/rsct/pm"; use locale; use Getopt::Std; use CU_cli_rc qw(CU_CLI_SUCCESS CU_CLI_ERROR CU_CLI_BAD_FLAG CU_CLI_BAD_OPERAND CU_CLI_USER_ERROR); use CT_cli_utils qw(printIMsg printEMsg $TRUE $FALSE $CTBINDIR $CTDIR); #--------------------------------------------------------------------# # Global Variables # #--------------------------------------------------------------------# $Trace = $FALSE; # default - trace off $Verbose = $FALSE; # default - verbose turned off $PROGNAME = "ctadmingroup"; # Program Name for messages $LSMSG = "$CTBINDIR/ctdspmsg"; # list / display message rtn $MSGCAT = "cucli.cat"; # msg catalogue for this cmd $ENV{'MSGMAPPATH'} = "$CTDIR/msgmaps"; # msg maps used by $LSMSG $CACHED_GID_FILENAME = "/var/ct/cfg/ctgroups"; # file with group name and id # This must be kept in sync with # cu_getadmin_group_id() $exit_val = 0; # exit value ($rc, $group_name, $unset_option) = &parse_cmd_line; ($rc == 0) || exit($rc); # # set new admin group # if(!$unset_option && ($group_name ne "") ) { $gid = getgrnam($group_name); if(!defined ($gid)) { # cannot find group $group_name printEMsg("EMsgctadmingroupCannotFindGrp", $group_name); exit (1); } if($Trace) { print STDERR "GID = $gid\n"; } # create file with group name/ID $rc = create_cached_group_file($group_name, $gid); if($rc) { # success ... now change directory and file permissions set_dir_permissions(); set_file_permissions($gid); } else { # a problem ... likely full /var/ filesystem $exit_val = 2; } } # # Unset admin group # if($unset_option) { if($Trace) { print STDERR "Unset Option!\n"; } delete_cached_group_file(); # set file groups to group id 0 set_file_permissions(0); } # # Print current admin group # if(!$unset_option && ($group_name eq "")) { if($Trace) { print STDERR "Print current group\n"; } $rc = print_cached_group_file(); if($rc == 2) { # unexpected error $exit_val = 2; } } exit($exit_val); # # END main program # #--------------------------------------------------------------------# # parse_cmd_line - Parse the command line for options and operands. # # Set appropriate global variables as outlined below, make sure we # # have a valid combination of arguments / options. # # # # Return: # # $rc 0 Command line parsed fine, no problem. # # CU_CLI_BAD_FLAG Command line contained a bad flag. # # CU_CLI_BAD_OPERAND Command line contained some other # # incorrect input # # $group_name Group name provided in the command line # # $unset_option Whether the "unset" option has been set # #--------------------------------------------------------------------# sub parse_cmd_line { my(@original_argv) = @ARGV; my $group_name = ""; # group name my %opts = (); if (!&getopts('huVT', \%opts)) { # Gather options; # if errors print_usage(); # display proper usage return CU_CLI_BAD_FLAG; # return bad rc - bad flag } # process h flag if (defined $opts{h}) { # -h, help request print_usage(); # print usage statement exit(0); # all done with good return! } if (defined $opts{T}) { # -T turn trace on $Trace = 1; } if (defined $opts{V}) { # -V turn verbose mode on $Verbose = 1; } if (defined $opts{u}) { # -u, unset $unset_option = 1; } # Get the arguments...cluster name followed by node names if ($#ARGV >= 0) { # group name $group_name = $ARGV[0]; } # cannot specify -u and also a group name if(($group_name ne "") && $unset_option) { print_usage(); return CU_CLI_BAD_OPERAND; } # only one argument allowed if ($#ARGV >= 1) { print_usage(); return CU_CLI_BAD_OPERAND; } return(0, $group_name, $unset_option); # success } #--------------------------------------------------------------------# # get_file_names - get the set of files that will have their # # permissions/group changed # # # # Parameters: # # # # Return code: # # @filelist: list of files that will have their permissions # # changed # #--------------------------------------------------------------------# sub get_file_names { # list of pathnames that define the files that will have their permissions # and group changed my(@filepathnames) = ( "/var/ct/IW/log/mc/trace*", "/var/ct/IW/log/ctsec/ctcasd/trace*", "/var/ct/*/log/mc/*/trace*" ); my(@filelist) = (); my(@list) = (); my($f); my($ctcasd_file); # add ctcasd trace file name to the list $ctcasd_file = get_ctcasd_filename(); if($ctcasd_file ne "") { push (@filepathnames, $ctcasd_file); } # # files may be visited more than once, because of the symlink in the # dirs # foreach $pattern (@filepathnames) { @list = glob $pattern; push (@filelist, @list); } if($Trace) { foreach $f (@filelist) { print STDERR "File: $f\n"; } } return @filelist; } #--------------------------------------------------------------------# # get_ctcasd_filename - ctcasd's trace file location is # # configurable. This function fetches the # # trace file name from the ctcasd config # # file, which has 2 possible locations # # # # Return code: # # pathname of ctcasd trace file # # # #--------------------------------------------------------------------# sub get_ctcasd_filename { my($SEC_CONFIG1) = "/var/ct/cfg/ctcasd.cfg"; # 1st location of config file my($SEC_CONFIG2) = "/opt/rsct/cfg/ctcasd.cfg"; # 2nd location my($sec_config_file) = ""; my($l); my($trace_file) = ""; if (-e $SEC_CONFIG1 ) { $sec_config_file = $SEC_CONFIG1; } else { if(-e $SEC_CONFIG2) { $sec_config_file = $SEC_CONFIG2; } } if($sec_config_file ne "") { if(open(FD_SEC_CONFIG,"$sec_config_file")) { sec_cfg: while ($l = ) { # typical line in the config file looks like # TRACEFILE= /var/ct/IW/log/ctsec/ctcasd/trace $l =~ s/[ ]+$//; # Remove possible trailing spaces $l =~ s/^[ ]+//; # Remove possible leading spaces if($l =~ "TRACEFILE=([ ]*)(.*)([ ]*)") { $trace_file = $2; if($Trace) { print STDERR "ctcasd: Found $trace_file in $sec_config_file.\n"; } last sec_cfg; } } # while } # open } # if $sec_config_file if($trace_file eq "") { $trace_file = "/var/ct/IW/log/ctsec/ctcasd/trace"; } return $trace_file; } #--------------------------------------------------------------------# # set_file_permissions - set the file permissions and group # # Uses get_file_names() to get a list of files# # that will have their permissions changed # # # # Parameters: # # $gid: group id to which the files should be set # # # # # #--------------------------------------------------------------------# use Fcntl ':mode'; # needed for S_IRUSR, etc sub set_file_permissions { my($gid) = @_; my(@filelist); my($mode); my($newmode); my($f); my($rc); @filelist = get_file_names(); if($Trace) { foreach $f (@filelist) { print STDERR "....File: $f\n"; } } foreach $f (@filelist) { next unless -e $f; next if -d $f; # skip if dir # do a "stat" on the file to get its permissions and prepare new # permissions to set $mode = (stat($f))[2]; $mode &= 07777; $newmode = $mode | (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); if($newmode != $mode) { if($Trace) { # print STDERR "Changing mode for $f from $mode to $newmode.\n"; print STDERR "Changing mode for %s from %04o to %04o.\n", $f, $mode, $newmode; } # set new permissions $rc = chmod $newmode, $f; if($rc <= 0) { printEMsg("EMsgctadmingroupCannotChangeMode", $f); } } else { if($Trace) { # print STDERR "Mode for $f is $mode: no change required.\n"; printf STDERR "Mode for %s is %04o: no change required.\n", $f, $mode; } } # change group of file (keep file owner intact) $rc = chown -1, $gid, $f; if($rc <= 0) { printEMsg("EMsgctadmingroupCannotChangeGroup", $f); } } # foreach } # set_file_permissions() #--------------------------------------------------------------------# # get_dir_names - get the set of directories that will have their # # permissions changed # # # # Parameters: # # # # Return code: # # @dirlist: list of directories that will have their permissions # # changed # #--------------------------------------------------------------------# sub get_dir_names { # list of pathnames that define the dirs that will have their permissions # changed my(@dirpathnames) = ( "/var/ct/IW/log/mc", "/var/ct/IW/log/ctsec", "/var/ct/IW/log/ctsec/ctcasd", "/var/ct/*/log", "/var/ct/*/log/cthats", "/var/ct/*/log/cthags", "/var/ct/*/log/mc/*" ); my(@dirlist) = (); my(@list) = (); my($f); # # dirs may be visited more than once, because of the symlink in the # dirs foreach $pattern (@dirpathnames) { @list = glob $pattern; push (@dirlist, @list); } if($Trace) { foreach $f (@dirlist) { print STDERR "Dir: $f\n"; } } return @dirlist; } # get_dir_names #--------------------------------------------------------------------# # set_dir_permissions - set the directory permissions # # # # Parameters: # # # #--------------------------------------------------------------------# use Fcntl ':mode'; # needed for S_IRUSR, etc sub set_dir_permissions { my($gid) = @_; my(@dirlist); my($mode); my($newmode); my($f); my($rc); @dirlist = get_dir_names(); if($Trace) { foreach $f (@dirlist) { print STDERR "....Dir: $f\n"; } } foreach $f (@dirlist) { next unless -e $f; # skip if dir does not exist next unless -d $f; # skip if not dir $mode = (stat($f))[2]; $mode &= 07777; $newmode = $mode | (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); # 0755 if($newmode != $mode) { if($Trace) { # print STDERR "Changing mode for $f from $mode to $newmode.\n"; print STDERR "Changing mode for %s from %04o to %04o.\n", $f, $mode, $newmode; } $rc = chmod $newmode, $f; if($rc <= 0) { printEMsg("EMsgctadmingroupCannotChangeMode", $f); } } else { if($Trace) { # print STDERR "Mode for $f is $mode: no change required.\n"; printf STDERR "Mode for %s is %04o: no change required.\n", $f, $mode; } } # the following is not needed for now. Enable if the dirs need to have # a specific group ## # change group of file (keep file owner intact) ## $rc = chown -1, $gid, $f; ## if($rc <= 0) { ## printEMsg("EMsgctadmingroupCannotChangeGroup", $f); ## } } # foreach } # set_dir_permissions() #--------------------------------------------------------------------# # create_cached_group_file - write file that contains admin # # group name and id # # # # Parameters: # # $group_name: admin group name # # $gid: group id of the admin group # # # # Return code: # # 1: success # # 0: some error occurred (likely lack of filesystem space) # # # #--------------------------------------------------------------------# sub create_cached_group_file { my($group_name, $gid) = @_; my($rc) = 1; umask 0133; # does not allow group, others to write/execute file if(!open(CACHED_GID_FILE_HANDLE, ">".$CACHED_GID_FILENAME)) { printEMsg("EMsgctadmingroupCannotCreateFile", $CACHED_GID_FILENAME); return 0; } # Format: # #Version # # # group name # group id $rc = $rc && print CACHED_GID_FILE_HANDLE "# Admin Group name and id\n"; $rc = $rc && print CACHED_GID_FILE_HANDLE "#Version 1\n"; $rc = $rc && print CACHED_GID_FILE_HANDLE "#Format: group_name\n"; $rc = $rc && print CACHED_GID_FILE_HANDLE "# group_id\n"; $rc = $rc && print CACHED_GID_FILE_HANDLE "$group_name\n"; $rc = $rc && print CACHED_GID_FILE_HANDLE "$gid\n"; if($rc == 0) { printEMsg("EMsgctadmingroupErrorWriteFile", $CACHED_GID_FILENAME); } if(!close(CACHED_GID_FILE_HANDLE)) { printEMsg("EMsgctadmingroupErrorCloseFile", $CACHED_GID_FILENAME); $rc = 0; } return $rc; # ok } #--------------------------------------------------------------------# # delete_cached_group_file - delete file that contains admin # # group name and id # # # # Parameters: # # # # Return code: # # # #--------------------------------------------------------------------# sub delete_cached_group_file { # just rename the file, to keep a copy rename $CACHED_GID_FILENAME, $CACHED_GID_FILENAME.".last"; } #--------------------------------------------------------------------# # print_cached_group_file - print group name and id info from # # the cached group file. If the file is not present then assume # # that no admin group is defined and produce no output # # # # Parameters: # # # # Return code: # # 1: a group is defined # # 0: cached group file is not present # # 2: some error occurred # # # #--------------------------------------------------------------------# sub print_cached_group_file { my ($l); my ($version) = 1; my (@tmp_l); my ($group_name) = ""; my ($got_group_name) = 0; my ($gid); my ($got_gid) = 0; my ($rc) = 0; if(open(CACHED_GID_FILE_HANDLE, $CACHED_GID_FILENAME)) { while_file: while ($l = ) { if($l =~ /^#Version /) { @tmp_l = split(" ", $l); if(defined(@tmp_l[1])) { $version = @tmp_l[1]; } next while_file; } # ignore other comment lines next while_file if $l =~ /^#/; # if this is not the Version line and it's not a comment line then # it must be a group name (1st line) and the group id (next line) if($group_name eq "") { $group_name = $l; chomp($group_name); $got_group_name = 1; next while_file; } # must be the group id $gid = $l; chomp($gid); # make sure GID looks valid (should have only digits) if($gid =~ /^\d+$/) { $got_gid = 1; } last while_file; } close CACHED_GID_FILE_HANDLE; if(!$got_group_name || !$got_gid) { printEMsg("EMsgctadmingroupCorruptedFile", $CACHED_GID_FILENAME); $rc = 2; } else { print "$group_name ($gid)\n"; $rc = 0; } return $rc; } else { if($Trace) { print STDERR "Cannot open $CACHED_GID_FILENAME for reading.\n"; } return 0; } return 2; } #--------------------------------------------------------------------# # print_usage : print the usage statement (syntax) to stdout. # #--------------------------------------------------------------------# sub print_usage { printIMsg("IMsgctadmingroupUsage"); } # end print_usage