#!/bin/ksh93
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# 61haes_r721 src/43haes/lib/ksh93/hacmp/KLIB_HACMP_add_group.sh 1.6 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 2011 
# 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 
# @(#)48	1.6  src/43haes/lib/ksh93/hacmp/KLIB_HACMP_add_group.sh, hacmp.assist, 61haes_r721, 1618A_hacmp721 4/29/16 05:30:52

#================================================
# The following, commented line enforces coding
# standards when this file is edited via vim.
#================================================
# vim:tabstop=4:shiftwidth=4:expandtab:smarttab
#================================================

# Start of POD-formatted documentation. Viewing suggestions:
#      perldoc <FILENAME>
#      pod2text -c <FILENAME>
#      pod2text -c --code <FILENAME>
#      pod2html <FILENAME>
function devDoc {
    : <<'=cut' >/dev/null 2>&1

=head1 NAME

 KLIB_HACMP_add_group

=head1 VERSION

 Version Number:  1.6
 Last Extracted:  5/3/16 18:54:15
 Last Changed:    4/29/16 05:30:52

 Path, Component, Release(, Level):
 src/43haes/lib/ksh93/hacmp/KLIB_HACMP_add_group.sh, hacmp.assist, 61haes_r721, 1618A_hacmp721

=head1 SYNOPSIS

 clmgr add group <group_name> \
             [ RESOURCE_GROUP=<resource_group> ] \
             [ ID=### ] \
             [ ADMINISTRATIVE={false|true} ] \
             [ USERS=<user#1>[,<user#2>,...] ] \
             [ ADMINS=<admin#1>[,<admin#2>,...] ] \
             [ PROJECTS=<project#1>[,<project#2>,...] ] \
             [ KEYSTORE_MODE={admin|guard} ] \
             [ KEYSTORE_ENCRYPTION={RSA_1024|RSA_2048|RSA_4096} ] \
             [ KEYSTORE_ACCESS={file|none} ] \
             [ REGISTRY={ldap|local(files)} ]

 NOTE: the alias for "group" is "gp".

=head1 DESCRIPTION

Attempts to add a new AIX group to either all the nodes in the cluster,
or to just those nodes within the specified resource group.

=head1 ARGUMENTS

 1. properties [REQUIRED] [hash ref]
    An associative array within which data about the
    created object can be returned to the caller.

 2. group [REQUIRED] [string]
    The label that is to be applied to this group. A group represents
    one or more system users who can access and work with protected
    resources.
                                                                     
    The system uses groups to control access to files and resources
    by users who do not own them. When a user starts a process, the
    system associates the process with the user's ID and the group
    IDs of the groups the user belongs to. If the user owns the
    resource or is a member of a group that can access it, the
    system grants read write, or execute access to it according to
    the access control list of the resource or file.

    A group name is specified as a string.  The maximum length
    depends on the configuration of the individual nodes, and can
    be queried using the lsattr command to view the max_logname
    attribute of the sys0 device, but all AIX systems will accept
    a length of up to 8 characters.  See the documentation on the
    AIX mkuser command for more information.

    You can use letters, numbers, and some special characters in
    the name. The string cannot start with a hyphen (-), plus (+),
    tilde (~), or at sign (@). The string cannot contain any spaces
    or any of the following characters: colon (:), double quote ("),
    pound sign, comma (,), asterisk (*), single quote ('), equal
    sign (=), newline (\n), tab (\t), backslash (\), forward slash
    (/), question mark (?), back quote (`), or the key words "ALL"
    or "default".

 3. rg [OPTIONAL] [string]
    A resource group within the cluster. If specified, the new group
    will only be added to the nodes that this resource group is able
    to run on. If no resource group is specified, the new groups will
    be added to all nodes within the cluster.

 4. id [OPTIONAL] [posint]
    A unique ID number associated with this group. If an ID number
    is not specified, AIX will automatically assign one for you.

 5. administrative [OPTIONAL] [boolean]
    Indicates if the group is an administrative group. Only the root
    user can modify the attributes of an administrative group.
                                                                
    This field is displayed with False or True as its value. True
    indicates that group is an administrative group. False indicates
    that it is a nonadministrative group (its attributes can be
    modified by the group's specified administrators and the root
    user).

 6. users [OPTIONAL] [string]
    Specifies the names of the users that belong to this group. The
    members of a group can access (that is, read, write, or execute)
    a resource or file owned by another member of the group as
    specified by the resource's access control list.

    To enter the user members of this group, type in their names
    (separated by commas), or use the List box and select the users
    from the choices displayed (the users are displayed in the field
    in the correct format.

    Note: A user cannot be removed from the user's primary group
    unless you first redefine the user's primary group.

 7. admins [OPTIONAL] [string]
    Specifies the members that can modify this group (for example,
    add new members to the group, or remove members from it) if
    the group is a non-administrative group.

    Note: The group attributes of an administrative group can be
    modified by only the root user; so if the group is an
    administrative group (specified in the ADMINISTRATIVE group
    attribute), no administrators can be defined in this field.

 8. projects [OPTIONAL] [string]

 9. keystore_mode [OPTIONAL] [set]
    The efs_initalks_mode of admin allows for root or other
    security privileged system users to reset the user's key
    store password. Otherwise, if the user forgets their key
    store password, they will not be able to access their
    Encrypted File System files.

    If the guard mode is selected, then root cannot reset the
    user's key store password.

    Allowed values: admin, guard

 10. keystore_encryption [OPTIONAL] [set]
    This option specifies the algorithm for the user's key within
    the key store. This key will protect the encrypting key of
    files the user creates within the Encrypted File System.

    Allowed values: RSA_1024, RSA_2048, RSA_4096

    RSA_1024 = 1024 bit RSA key
    RSA_2048 = 2048 bit RSA key
    RSA_4096 = 4096 bit RSA key

 11. keystore_access [OPTIONAL] [set]
    The key store will allow the user to utilize files in Encrypted    
    File System. The selection of file will create a key store file
    associated with this user. It is recommended that file is
    selected.  Select none for no key store to be created. All
    other EFS (efs_*) attributes will not have any effect.

    Allowed values: file, node

 12. registry [OPTIONAL] [set]
    Indicates where the new group's information is to be stored.
    If the group is being defined locally, within AIX, than the
    value "LOCAL" should be used. If the group is being defined
    remotely, on the LDAP server, then "LDAP" should be used.

=head1 RETURN

 0: no errors were detected; the operation appears to have been successful
 1: a general error has occurred
 2: a specified resource does not exist, or could not be found
 3: some required input was missing
 4: some detected input was incorrect in some way
 5: a required dependency does not exist
 6: a specified search failed to match any data

=head1 COPYRIGHT

COPYRIGHT International Business Machines Corp. 2005,2010
All Rights Reserved

=cut
} # End of POD-formatted documentation.


function KLIB_HACMP_add_group {
    LINENO=2 . $HALIBROOT/log_entry "$0()" "$CL"
    : version=1.6, src/43haes/lib/ksh93/hacmp/KLIB_HACMP_add_group.sh, hacmp.assist, 61haes_r721, 1618A_hacmp721
    : INPUTS: $*

    typeset -n properties=$1
    typeset group=${2//\"/}
    typeset rg=${3//\"/}
    typeset id=${4//\"/}
    typeset -l administrative=${5//\"/}
    typeset users=${6//\"/}
            users=${users//,/ }
    typeset admins=${7//\"/}
            admins=${admins//,/ }
    typeset projects=${8//\"/}
            projects=${projects//,/ }
    typeset -l keystore_mode=${9//\"/}
    typeset -u keystore_encryption=${10//\"/}
    typeset keystore_access=${11//\"/}
    typeset registry=${12//\"/}

    [[ $CLMGR_LOGGING == 'med' ]] && set +x  # Only trace param values

    #===================================
    : Declare and initialize variables
    #===================================
    typeset -i rc=$RC_UNKNOWN
    typeset -u registryUC=$registry

    typeset existing
    CL=$LINENO KLIB_HACMP_list_groups existing 2>>$CLMGR_TMPLOG

    if [[ $registryUC != *([[:space:]]) ]]; then
      case $registryUC in
          LD*) registry="LDAP"  ;;
          LO*) registry="files" ;;
           F*) registry="files" ;;
            *) /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 '\nERROR: invalid value specified for "%1$s":  "%2$s".\n' REGISTRY "$registry" 1>&2
               /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "files, LDAP" 1>&2
               rc=$RC_INCORRECT_INPUT
            ;;
      esac
    fi

    #=================
    : Validate input
    #=================
    if [[ -z $group ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 100 "\nERROR: a name/label must be provided.\n\n" 1>&2
        rc=$RC_MISSING_INPUT

    elif [[ " ${existing[*]} " == *\ $group\ * ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 229 "\nERROR: the specified object already exists: \"%1\$s\"\n\n" "$group" 1>&2
        rc=$RC_INCORRECT_INPUT
    fi

    if [[ -n $group && $group == [\-\+\~\@]* ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 103 "\nERROR: one or more invalid characters were detected in \"%1\$s\":  \"%2\$s\".\n\n" NAME "[-+~@]" 1>&2
        rc=$RC_INCORRECT_INPUT
    fi

    if [[ $rg != *([[:space:]]) ]]; then
        CL=$LINENO KLIB_HACMP_is_known_rg $rg
        if (( $? != RC_SUCCESS )); then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 "\nERROR: \"%1\$s\" does not appear to exist!\n\n" "$rg" 1>&2
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 154 "Available Resource Groups:\n\n" 1>&2

            typeset available
            CL=$LINENO KLIB_HACMP_list_resourcegroups available
            for (( i=0; i<${#available[*]}; i++ )); do
                if [[ ${available[$i]} != *([[:space:]]) ]]; then
                    print -u2 "\t${available[$i]}"
                fi
            done
            print -u2 ""

            rc=$RC_NOT_FOUND
        fi
    fi

    if [[ $id != *([[:space:]]) && $id != +([[:digit:]]) ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 111 "\nERROR: \"%1\$s\" requires a positive, integer value.\n\n" ID 1>&2
        rc=$RC_INCORRECT_INPUT
    fi

    if [[ -n $administrative && $administrative != @(y|t|n|f)* ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\":  \"%2\$s\".\n" ADMINISTRATIVE "$administrative" 1>&2
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "true, false" 1>&2
        rc=$RC_INCORRECT_INPUT
    fi

    CL=$LINENO KLIB_HACMP_is_known_efs >>$CLMGR_TMPLOG 2>&1
    typeset -i EFS_ENABLED=$?

    if [[ $keystore_mode != *([[:space:]]) ]] && \
       (( EFS_ENABLED == RC_ERROR ))
    then
        CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 9999 '\nERROR: EFS is not enabled on this system, so no attributes related to EFS may be used: %1$s\n\n' KEYSTORE_MODE 1>&2
        rc=$RC_INCORRECT_INPUT

    elif [[ $keystore_mode != *([[:space:]]) ]]; then
        case $keystore_mode in
            a*) keystore_mode="admin" ;;
            g*) keystore_mode="guard" ;;
             *) /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\":  \"%2\$s\".\n" KEYSTORE_MODE "$keystore_mode" 1>&2
                /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "admin, guard" 1>&2
                rc=$RC_INCORRECT_INPUT
            ;;
        esac
    fi

    if [[ $keystore_encryption != *([[:space:]]) ]] && \
       (( EFS_ENABLED == RC_ERROR ))
    then
        CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 9999 '\nERROR: EFS is not enabled on this system, so no attributes related to EFS may be used: %1$s\n\n' KEYSTORE_ENCRYPTION 1>&2
        rc=$RC_INCORRECT_INPUT

    elif [[ $keystore_encryption != *([[:space:]]) ]]; then
        case $keystore_encryption in
            *24*) keystore_encryption="RSA_1024" ;;
            *48*) keystore_encryption="RSA_2048" ;;
            *96*) keystore_encryption="RSA_4096" ;;
               *) /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\":  \"%2\$s\".\n" KEYSTORE_ENCRYPTION "$keystore_encryption" 1>&2
                  /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "RSA_1024, RSA_2048, RSA_4096" 1>&2
                  rc=$RC_INCORRECT_INPUT
              ;;
        esac
    fi

    if [[ $keystore_access != *([[:space:]]) ]] && \
       (( EFS_ENABLED == RC_ERROR ))
    then
        CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 9999 '\nERROR: EFS is not enabled on this system, so no attributes related to EFS may be used: %1$s\n\n' KEYSTORE_ACCESS 1>&2
        rc=$RC_INCORRECT_INPUT

    elif [[ $keystore_access != *([[:space:]]) ]]; then
        typeset -u kaUC=$keystore_access
        case $kaUC in
            L*) keystore_access="LDAP" ;;
            F*) keystore_access="file" ;;
            N*) keystore_access="none" ;;
             *) /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\":  \"%2\$s\".\n" KEYSTORE_ACCESS "$keystore_access" 1>&2
                /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "file, none" 1>&2
                rc=$RC_INCORRECT_INPUT
        esac

        if [[ $registry == "LDAP" && $keystore_access != "LDAP" ]]; then
            CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 36 '\nERROR: conflicting options were provided, "%1$s" versus "%2$s".\n\n' "REGISTRY=$registry" "KEYSTORE_ACCESS=$keystore_access" 1>&2
            rc=$RC_INCORRECT_INPUT

        elif [[ $registry != "LDAP" && $keystore_access == "LDAP" ]]; then
            CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 36 '\nERROR: conflicting options were provided, "%1$s" versus "%2$s".\n\n' "REGISTRY=$registry" "KEYSTORE_ACCESS=$keystore_access" 1>&2
            rc=$RC_INCORRECT_INPUT

        elif [[ $registry == "LDAP" && $keystore_access == "LDAP" ]]; then
            unset keystore_access  # LDAP is implied
        fi
    fi

    if [[ -n $users ]]; then
        for user in $users; do
            CL=$LINENO KLIB_HACMP_is_known_user $user
            if (( $? != RC_SUCCESS )); then
                /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 "\nERROR: \"%1\$s\" does not appear to exist!\n\n" "$user" 1>&2
                /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 162 "Available Users:\n\n" 1>&2

                typeset available
                CL=$LINENO KLIB_HACMP_list_users available
                for (( i=0; i<${#available[*]}; i++ )); do
                    if [[ ${available[$i]} != *([[:space:]]) ]]; then
                        print -u2 "\t${available[$i]}"
                    fi
                done
                print -u2 ""

                rc=$RC_NOT_FOUND
            fi
        done
    fi

    if [[ -n $admins ]]; then
        for admin in $admins; do
            CL=$LINENO KLIB_HACMP_is_known_user $admin
            if (( $? != RC_SUCCESS )); then
                /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 "\nERROR: \"%1\$s\" does not appear to exist!\n\n" "$admin" 1>&2
                /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 162 "Available Users:\n\n" 1>&2

                typeset available
                CL=$LINENO KLIB_HACMP_list_users available
                for (( i=0; i<${#available[*]}; i++ )); do
                    if [[ ${available[$i]} != *([[:space:]]) ]]; then
                        print -u2 "\t${available[$i]}"
                    fi
                done
                print -u2 ""

                rc=$RC_NOT_FOUND
            fi
        done
    fi

    #========================================================
    : Create the group if no input errors have been detected
    #========================================================
    if (( $rc == RC_UNKNOWN )); then
        typeset rgOpt= adminOpt=" -A" idOpt= usersOpt= adminsOpt= ksMode=
        typeset ksEnc= ksAcc= regOpt=
        [[ $rg != *([[:space:]]) ]] && rgOpt=" -cspoc-g $rg"
        [[ $administrative == @(y|t)* ]] && adminOpt=" -a"
        [[ $id != *([[:space:]]) ]] && idOpt=" id=$id"
        [[ $users != *([[:space:]]) ]] && usersOpt=" users=${users//+([[:space:]])/,}"
        [[ $admins != *([[:space:]]) ]] && adminsOpt=" adms=${admins//+([[:space:]])/,}"
        [[ $keystore_mode != *([[:space:]]) ]] && ksMode=" efs_initialks_mode=$keystore_mode"
        [[ $keystore_encryption != *([[:space:]]) ]] && ksEnc=" efs_keystore_algo=$keystore_encryption"
        [[ $keystore_access != *([[:space:]]) ]] && ksAcc=" efs_keystore_access=$keystore_access"
        [[ $registry != *([[:space:]]) ]] && regOpt=" registry=$registry"

        if [[ $registry == "LDAP" ]]; then
            print -- "$0()[$LINENO]($SECONDS): mode=LDAP $HACSPOC/fix_args nop cl_mkgroup$rgOpt$adminOpt$idOpt$usersOpt$adminsOpt$ksMode$ksEnc$ksAcc$regOpt $group" >>$CLMGR_TMPLOG  # Always log commands
            mode=LDAP $HACSPOC/fix_args nop cl_mkgroup$rgOpt$adminOpt$idOpt$usersOpt$adminsOpt$ksMode$ksEnc$ksAcc$regOpt $group
        else
            print -- "$0()[$LINENO]($SECONDS): $HACSPOC/fix_args nop cl_mkgroup$rgOpt$adminOpt$idOpt$usersOpt$adminsOpt$ksMode$ksEnc$ksAcc$rgOpt $group" >>$CLMGR_TMPLOG  # Always log commands
            $HACSPOC/fix_args nop cl_mkgroup$rgOpt$adminOpt$idOpt$usersOpt$adminsOpt$ksMode$ksEnc$ksAcc$rgOpt $group
        fi
        rc=$?
        print "$0()[$LINENO]($SECONDS): cl_mkgroup RC: $rc" >>$CLMGR_TMPLOG  # Always log command result

        if (( $rc != RC_SUCCESS )); then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 201 "\nERROR: failed to create \"%1\$s\".\n\n" "$group" 1>&2
            rc=$RC_ERROR
        fi

        #===========================================================
        : If output from this operation was requested, retrieve it
        #===========================================================
        if (( $rc == RC_SUCCESS )); then
            if (( CLMGR_VERBOSE )) || [[ -n $CLMGR_ATTRS ]]; then
                CL=$LINENO KLIB_HACMP_get_group_attributes "$group" properties
            fi
        fi
    fi

    #=======================================================================
    : If a user input error was detected, provide some helpful suggestions
    #=======================================================================
    if (( $rc == RC_MISSING_INPUT || $rc == RC_INCORRECT_INPUT )) && \
       [[ $CLMGR_GUI == *([[:space:]]) ]]
    then
        CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 104 "For more information about available options and syntax, try\n\"$HAUTILS/clmgr %1\$s\". As an\nalternative, if the PowerHA SystemMirror man pages have been installed, invoke\n\"$HAUTILS/clmgr -hv\" (or \"/usr/bin/man clmgr\"),\nsearching for \"%2\$s\" in the displayed text.\n\n" \
        "add group -h" "GROUP:" "$CLMGR_PROGNAME" 1>&2
    fi

    log_return_msg "$rc" "$0()" "$LINENO"
    return $?
} # End of "KLIB_HACMP_add_group()"
