Ejemplo n.º 1
0
def channels(prefix):
    """
        Show channels.
    """

    mqstate.validate(['host', 'port', 'channel'])

    args = {pymqi.CMQCFC.MQCACH_CHANNEL_NAME: str(prefix)}
    qmgr = pymqi.connect(mqstate.qm_name, mqstate.channel, mqstate.get_host(),
                         mqstate.username, mqstate.password)
    pcf = pymqi.PCFExecute(qmgr)

    try:

        click.secho(
            'Showing channels with prefix: \'{0}\'...\n'.format(prefix),
            dim=True)
        response = pcf.MQCMD_INQUIRE_CHANNEL(args)

    except pymqi.MQMIError as sce:

        if sce.comp == pymqi.CMQC.MQCC_FAILED and sce.reason == pymqi.CMQC.MQRC_UNKNOWN_OBJECT_NAME:
            click.secho('No channels matched prefix [%s]'.format(prefix),
                        fg='red')

        else:
            raise sce

    else:

        t = get_table_handle([
            'Name',
            'Type',
            'MCA UID',
            'Conn Name',
            'Xmit Queue',
            'Description',
            'SSL Cipher',
        ])

        for channel_info in response:
            t.append_row([
                channel_info.get(pymqi.CMQCFC.MQCACH_CHANNEL_NAME, '').strip(),
                channel_type_to_name(
                    channel_info.get(pymqi.CMQCFC.MQIACH_CHANNEL_TYPE)),
                channel_info.get(pymqi.CMQCFC.MQCACH_MCA_USER_ID, ''),
                channel_info.get(pymqi.CMQCFC.MQCACH_CONNECTION_NAME,
                                 '').strip(),
                channel_info.get(pymqi.CMQCFC.MQCACH_XMIT_Q_NAME, '').strip(),
                channel_info.get(pymqi.CMQCFC.MQCACH_DESC, '').strip(),
                # channel_info.get(pymqi.CMQCFC.MQCACH_PASSWORD, '(unknown)').strip(),
                channel_info.get(pymqi.CMQCFC.MQCACH_SSL_CIPHER_SPEC,
                                 '').strip(),
                # channel_info.get(pymqi.CMQCFC.MQCACH_SSL_PEER_NAME, '').strip(),
            ])
        click.secho(t.get_string())

    qmgr.disconnect()
Ejemplo n.º 2
0
def ping():
    """
        Ping a queue manager.
    """

    mqstate.validate(['host', 'port'])

    qmgr = pymqi.connect(mqstate.qm_name, mqstate.channel, mqstate.get_host(),
                         mqstate.username, mqstate.password)

    pcf = pymqi.PCFExecute(qmgr)
    pcf.MQCMD_PING_Q_MGR()
    click.secho('Queue manager command server is responsive.', fg='green')

    # Attempt to determine the MQ command level.
    mq_params = pcf.MQCMD_INQUIRE_Q_MGR(
        {pymqi.CMQCFC.MQCMD_INQUIRE_SYSTEM: '*'})

    # Get the queue manager status
    mq_status = pcf.MQCMD_INQUIRE_Q_MGR_STATUS()[0]

    # A number of these are not in CMQC, so this comment is a reference:
    # MQCA_INSTALLATION_DESC: 2115
    # MQCA_INSTALLATION_NAME: 2116
    # MQCA_INSTALLATION_PATH: 2117
    # MQCACF_LOG_PATH: 3074
    # MQCACF_Q_MGR_START_DATE: 3175
    # MQCACF_Q_MGR_START_TIME: 3176

    click.secho('Queue Manager Status:', bold=True)
    click.secho('---------------------', bold=True)
    click.secho('Command Level:             {0}'.format(
        mq_params[0][pymqi.CMQC.MQIA_COMMAND_LEVEL]),
                bold=True)
    click.secho('Queue Manager Name:        {0}'.format(
        mq_status.get(pymqi.CMQC.MQCA_Q_MGR_NAME, '(unknown)')),
                bold=True)
    click.secho('Installation Name:         {0}'.format(
        mq_status.get(2116, '(unknown)')),
                bold=True)
    click.secho('Installation Path:         {0}'.format(
        mq_status.get(2117, '(unknown)')),
                bold=True)
    click.secho('Installation Description:  {0}'.format(
        mq_status.get(2115, '(unknown)')),
                bold=True)
    click.secho('Log Path:                  {0}'.format(
        mq_status.get(3074, '(unknown)')),
                bold=True)
    click.secho('Queue Manager Start Time:  {0}'.format(' '.join(
        [mq_status.get(3175, '').strip(),
         mq_status.get(3176, '').strip()])),
                bold=True)
    click.secho('\n')

    click.secho('Successfully queried queue manager status.', fg='green')

    qmgr.disconnect()
Ejemplo n.º 3
0
def ping():
    """
        Ping a queue manager.
    """

    mqstate.validate(['host', 'port', 'qm_name', 'channel'])

    qmgr = pymqi.connect(mqstate.qm_name, mqstate.channel, mqstate.get_host(),
                         mqstate.username, mqstate.password)

    pcf = pymqi.PCFExecute(qmgr)
    pcf.MQCMD_PING_Q_MGR()
    click.secho('Queue manager command server is responsive.', fg='green')

    # Attempt to determine the MQ command level.
    mq_params = pcf.MQCMD_INQUIRE_Q_MGR({pymqi.CMQCFC.MQCMD_INQUIRE_SYSTEM: '*'.encode()})

    # Get the queue manager status
    mq_status = pcf.MQCMD_INQUIRE_Q_MGR_STATUS()[0]

    # A number of these are not in CMQC.py, so
    # this comment is a reference from the C headers
    # resolving some of the constants.
    #
    # MQCA_INSTALLATION_DESC: 2115
    # MQCA_INSTALLATION_NAME: 2116
    # MQCA_INSTALLATION_PATH: 2117
    # MQCACF_LOG_PATH: 3074
    # MQCACF_Q_MGR_START_DATE: 3175
    # MQCACF_Q_MGR_START_TIME: 3176

    click.secho('Queue Manager Status:', bold=True)
    click.secho('---------------------', bold=True)
    click.secho(f'Command Level:             {mq_params[0][pymqi.CMQC.MQIA_COMMAND_LEVEL]}', bold=True)
    click.secho('Queue Manager Name:        ' +
                f'{mq_string(mq_status.get(pymqi.CMQC.MQCA_Q_MGR_NAME, "(unknown)"))}', bold=True)
    click.secho(f'Installation Name:         {mq_string(mq_status.get(2116, "(unknown)"))}', bold=True)
    click.secho(f'Installation Path:         {mq_string(mq_status.get(2117, "(unknown)"))}', bold=True)
    click.secho(f'Installation Description:  {mq_string(mq_status.get(2115, "(unknown)"))}', bold=True)
    click.secho(f'Log Path:                  {mq_string(mq_status.get(3074, "(unknown)"))}', bold=True)
    click.secho('Queue Manager Start Time:  ' +
                f'{mq_string(mq_status.get(3175, ""))} {mq_string(mq_status.get(3176, ""))}', bold=True)
    click.secho('\n')

    click.secho('Successfully queried queue manager status.', fg='green')

    qmgr.disconnect()
Ejemplo n.º 4
0
def save(queue, limit, directory):
    """
        Save messages from a queue to a file, non-destructively.
    """

    mqstate.validate(['host', 'port', 'channel'])

    # Automatically generate a directory to save messages to
    if not directory:
        directory = safe_filename(mqstate.host + '_' + safe_filename(queue))
        click.secho(f'Saving messages to \'{directory}\'...', dim=True, fg='green')

    # check that the directory is ready for use
    absolute_path = os.path.abspath(directory)
    if not os.path.exists(absolute_path):
        click.secho(f'Creating {absolute_path} to save messages in...', dim=True)
        os.makedirs(absolute_path, mode=0o755)

    click.secho(f'Saving a maximum of {limit} messages from {queue}...', dim=True)

    qmgr = pymqi.connect(mqstate.qm_name, mqstate.channel, mqstate.get_host(),
                         mqstate.username, mqstate.password)

    # https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.5.0/com.ibm.mq.ref.dev.doc/q096780_.htm
    # https://github.com/dsuch/pymqi/blob/master/code/examples/put_get_correl_id.py
    gmo = pymqi.GMO()
    gmo.Options = pymqi.CMQC.MQGMO_BROWSE_NEXT
    queue = pymqi.Queue(qmgr, str(queue), pymqi.CMQC.MQOO_BROWSE)

    message_count = 0

    while message_count < limit:
        try:

            request_md = pymqi.MD()
            message = queue.get(None, request_md, gmo)

            file_name = filename_from_attributes(
                mq_string(request_md.PutDate),
                mq_string(request_md.PutTime),
                '.' + hashlib.sha1(request_md.MsgId).hexdigest() + '.',
                request_md.MsgType,
                request_md.Expiry,
                mq_string(request_md.UserIdentifier),
                mq_string(request_md.Format),
                mq_string(request_md.PutApplName))

            # try get a safe filename from all of that
            file_name = slugify(file_name)

            with open(os.path.join(absolute_path, file_name), 'wb') as f:
                f.write(message)

            click.secho(f'{message_count}: Wrote message to {file_name}', bold=True, fg='green')

        except pymqi.MQMIError as dme:
            if dme.comp == pymqi.CMQC.MQCC_FAILED and dme.reason == pymqi.CMQC.MQRC_NO_MSG_AVAILABLE:
                click.secho('Dump complete. No more messages on the queue.', fg='yellow')

                break

            # if we are not allowed to GET on this queue, mention that and quit
            if dme.comp == pymqi.CMQ.MQCC_FAILED and dme.reason == pymqi.CMQC.MQRC_GET_INHIBITED:
                click.secho('GET not allowed on queue with current access.', fg='red')

                break

            else:
                raise dme

        message_count += 1

    click.secho(f'Saved {message_count} message(s) in total.', bold=True)

    queue.close()
    qmgr.disconnect()
Ejemplo n.º 5
0
def sniff(queue, store, directory):
    """
        Sniff messages on a queue, non-destructively.

        Sniffs queues messages on a queue by opening the
        queue in a read only mode. Incoming messages will
        be dumped to the screen by default. If the --store
        flag is specified, messages will also be written
        to disk as they arrive.
    """

    mqstate.validate(['host', 'port'])

    # check if a directory was set but store was not
    if directory and not store:
        click.secho('A directory was set to store messages but --store flag was not provided, ignoring...',
                    bold=True, fg='yellow')

    # Prepare the destination directory if messages should also be saved
    if store:
        # Automatically generate a directory to save messages to
        if not directory:
            directory = safe_filename(mqstate.host + '_' + safe_filename(queue))
            click.secho(f'Messages will be saved to directory \'{directory}\'', dim=True, fg='green')

        # check that the directory is ready for use
        absolute_path = os.path.abspath(directory)
        if not os.path.exists(absolute_path):
            click.secho(f'Creating {absolute_path} to save messages in...', dim=True)
            os.makedirs(absolute_path, mode=0o755)

    qmgr = pymqi.connect(mqstate.qm_name, mqstate.channel, mqstate.get_host(),
                         mqstate.username, mqstate.password)

    # https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_7.5.0/com.ibm.mq.ref.dev.doc/q096780_.htm
    # https://github.com/dsuch/pymqi/blob/master/code/examples/put_get_correl_id.py
    # https://github.com/dsuch/pymqi/blob/master/code/examples/get_wait_multiple_messages.py
    gmo = pymqi.GMO()
    gmo.Options = pymqi.CMQC.MQGMO_BROWSE_NEXT | pymqi.CMQC.MQGMO_WAIT | pymqi.CMQC.MQGMO_FAIL_IF_QUIESCING
    gmo.WaitInterval = 2 * 1000  # 5 seconds

    queue = pymqi.Queue(qmgr, str(queue), pymqi.CMQC.MQOO_BROWSE)
    request_md = pymqi.MD()

    # simple counter for statistics
    message_count = 0
    click.secho('Waiting for messages to arrive...', dim=True)

    while True:
        try:
            # grab the message
            message = queue.get(None, request_md, gmo)
            message_count += 1

            # Save the message if we need to we do this early as
            # messages could be reformatted to be printed to screen.
            if store:
                file_name = filename_from_attributes(
                    mq_string(request_md.PutDate),
                    mq_string(request_md.PutTime),
                    '.' + hashlib.sha1(request_md.MsgId).hexdigest() + '.',
                    request_md.MsgType,
                    request_md.Expiry,
                    mq_string(request_md.UserIdentifier),
                    mq_string(request_md.Format),
                    mq_string(request_md.PutApplName))

                # try get a safe filename from all of that
                file_name = slugify(file_name)

                with open(os.path.join(absolute_path, file_name), 'wb') as f:
                    f.write(message)

                click.secho(f'{message_count}: Wrote message to {file_name}', bold=True, fg='green')

            # check if we have a MQSTR message. If we don't, try and filter
            # non-printables.
            if request_md.Format.strip() not in ['MQSTR', '']:
                # remove non-printables and update the Format
                # column with (stripped) so that it is visible
                message = message.decode('ascii', errors='ignore')
                request_md.Format = mq_string(request_md.Format) + ' (stripped)'

            click.secho(f'Message #{message_count}', fg='green')

            table = get_table_handle([
                'Date', 'Time', 'MsgID', 'MsgType', 'Expiry', 'User', 'Format', 'App Name'], markdown=False)

            table.append_row([
                mq_string(request_md.PutDate),
                mq_string(request_md.PutTime),
                request_md.MsgId.decode('ascii', errors='ignore'),
                request_md.MsgType,
                request_md.Expiry,
                mq_string(request_md.UserIdentifier),
                mq_string(request_md.Format),
                mq_string(request_md.PutApplName),
            ])

            # Print a 'header' for the message
            click.secho(table.get_string())

            # Print the message itself
            click.secho('' + '*' * 40 + ' BEGIN MESSAGE DATA ' + '*' * 40, dim=True)
            click.secho(message, bold=True)
            click.secho('*' * 41 + ' END MESSAGE DATA ' + '*' * 41 + '\n', dim=True)

            # reset the request descriptor so we can reuse it for the next message.
            request_md.MsgId = pymqi.CMQC.MQMI_NONE
            request_md.CorrelId = pymqi.CMQC.MQCI_NONE
            request_md.GroupId = pymqi.CMQC.MQGI_NONE
            request_md.Format = pymqi.CMQC.MQGI_NONE

        except pymqi.MQMIError as dme:

            # No messages, that's OK, we can ignore it.
            if dme.comp == pymqi.CMQC.MQCC_FAILED and dme.reason == pymqi.CMQC.MQRC_NO_MSG_AVAILABLE:
                continue

            # if we are not allowed to GET on this queue, mention that and quit
            if dme.comp == pymqi.CMQ.MQCC_FAILED and dme.reason == pymqi.CMQC.MQRC_GET_INHIBITED:
                click.secho('GET not allowed on queue with current credentials.', fg='red')

                break

            else:
                # Some other error condition.
                raise dme

        except KeyboardInterrupt as _:
            click.secho('Stopping...', fg='yellow')
            break

    click.secho(f'\nSniffed {message_count} message(s) in total.', dim=True)

    queue.close()
    qmgr.disconnect()
Ejemplo n.º 6
0
def queues(prefix, min_depth):
    """
        Show queues.
    """

    mqstate.validate(['host', 'port', 'channel'])

    args = {
        pymqi.CMQC.MQCA_Q_NAME: prefix.encode(),
        pymqi.CMQC.MQIA_Q_TYPE: pymqi.CMQC.MQQT_ALL
    }

    qmgr = pymqi.connect(mqstate.qm_name, mqstate.channel, mqstate.get_host(),
                         mqstate.username, mqstate.password)
    pcf = pymqi.PCFExecute(qmgr)

    try:

        click.secho(f'Showing queues with prefix: "{prefix}"...', dim=True)
        if min_depth > 0:
            click.secho(f'Limiting queues to those with at least {min_depth} message(s)...', dim=True)

        response = pcf.MQCMD_INQUIRE_Q(args)

    except pymqi.MQMIError as sqe:

        # no queues found
        if sqe.comp == pymqi.CMQC.MQCC_FAILED and sqe.reason == pymqi.CMQC.MQRC_UNKNOWN_OBJECT_NAME:
            click.secho(f'No queues matched given prefix of {prefix}', fg='red')

        else:
            raise sqe
    else:

        t = get_table_handle([
            'Created', 'Name', 'Type', 'Usage', 'Depth', 'Rmt. QMGR Name', 'Rmt. Queue Name', 'Description',
        ], markdown=True)
        t.set_style(t.STYLE_MARKDOWN)

        for queue_info in response:

            # skip queues that don't have at least the min amount of messages
            if queue_info.get(pymqi.CMQC.MQIA_CURRENT_Q_DEPTH, 0) < min_depth:
                continue

            # try and resolve the transmission queue for remote queue types
            q_type = queue_type_to_name(queue_info.get(pymqi.CMQC.MQIA_Q_TYPE))
            if q_type == 'Remote':
                xmit_q = mq_string(queue_info.get(pymqi.CMQC.MQCA_XMIT_Q_NAME, ''))
                if len(xmit_q) > 0:
                    q_type = q_type + f' (Transmission Q: {xmit_q})'

            t.append_row([
                ' '.join([
                    mq_string(queue_info.get(pymqi.CMQC.MQCA_CREATION_DATE, '')),
                    mq_string(queue_info.get(pymqi.CMQC.MQCA_CREATION_TIME, ''))
                ]),
                mq_string(queue_info.get(pymqi.CMQC.MQCA_Q_NAME, '')),
                q_type,
                queue_usage_to_name(queue_info.get(pymqi.CMQC.MQIA_USAGE)),
                queue_info.get(pymqi.CMQC.MQIA_CURRENT_Q_DEPTH, ''),
                mq_string(queue_info.get(pymqi.CMQC.MQCA_REMOTE_Q_MGR_NAME, '')),
                mq_string(queue_info.get(pymqi.CMQC.MQCA_REMOTE_Q_NAME, '')),
                mq_string(queue_info.get(pymqi.CMQC.MQCA_Q_DESC, '')),
            ])
        click.secho(t.get_string())

    qmgr.disconnect()
Ejemplo n.º 7
0
def channels(wordlist):
    """
        Discover channels.

        This command attempts to enumerate MQ channels using the provided
        configuration options. A list of default channel names is used
        if no word list is provided. Extra permutations will be generated
        if the target host is not an IP address.

        A number of cases exist where a channel does in fact exist
        server-side, but is not picked up by this command. This could
        be primarily because of the channel type not being a Server-connection.
    """

    # Ensure we have at least a host and a port
    mqstate.validate(['host', 'port'])

    if not wordlist:
        wordlist = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'wordlists/', 'mq_channels.txt')

    with open(wordlist, 'r') as f:
        # Don't read empty lines and strip spaces
        wordlist = [x.strip() for x in f.readlines() if len(x.strip()) > 0]

    # Check if the host is an IP address. If it is not, generate
    # permutations based on the hostname to try as channel names.
    if not is_ip_address(mqstate.host):
        click.secho('Destination host does not appear to be an IP address. Generating more permutations...', dim=True)

        # use the first entry as a base channel name
        base_name = mqstate.host.split('.')[0].upper()

        wordlist.append(base_name)
        wordlist.append(base_name + '.CHANNEL')
        wordlist.append(base_name + '.CHL')
        wordlist.append(base_name + '.SVRCONN')
        wordlist.append(base_name + '.ADMIN.SVRCONN')
        wordlist.append(base_name + '.AUTO.SVRCONN')
        wordlist.append(base_name + '.DEF.SVRCONN')
        wordlist.append(base_name + '.ADMIN.CHANNEL')
        wordlist.append(base_name + '.DEV.CHANNEL')

        # 'uniqify' the final list
        wordlist = list(set(wordlist))

    # Loop the wordlist, trying to connect to the target channel.
    # The username & password is taken from the configuration.
    #
    # The existence of a channel is determined based on the response
    # from the target queue manager. Luckily, MQ responds with a clear
    # message if the remote channel does not exist.
    for channel in wordlist:
        channel = channel.strip()

        try:
            qmgr = pymqi.connect(mqstate.qm_name, str(channel), mqstate.get_host(),
                                 mqstate.username, mqstate.password)

            pcf = pymqi.PCFExecute(qmgr)
            pcf.MQCMD_PING_Q_MGR()

            # If no exception is thrown, the channel exists *AND* we have access
            # with the supplied credentials (or lack thereof).
            click.secho(f'"{channel}" exists and was authorised.', fg='green', bold=True)
            qmgr.disconnect()

        except pymqi.MQMIError as ce:

            # Unknown channel. This is ok, just move along.
            if ce.reason == pymqi.CMQC.MQRC_UNKNOWN_CHANNEL_NAME:
                continue

            # The channel could be a sender /receiver type.
            elif ce.reason == pymqi.CMQC.MQRC_CHANNEL_CONFIG_ERROR:
                continue

            # Previous disconnect was not successful. Not sure why this happens tbh.
            elif ce.reason == pymqi.CMQC.MQRC_ALREADY_CONNECTED:
                qmgr.disconnect()
                continue

            # Channel is unavailable
            elif ce.reason == pymqi.CMQC.MQRC_CHANNEL_NOT_AVAILABLE:
                click.secho(f'"{channel}" might exist, but is not available.', bold=True, fg='yellow')
                continue

            # An unauthenticated message means the channel at least exists.
            elif ce.reason == pymqi.CMQC.MQRC_NOT_AUTHORIZED:
                click.secho(f'"{channel}" might exist, but user was not authorised.', bold=True)
                continue

            # Maybe this is an SSL error
            elif ce.reason == pymqi.CMQC.MQRC_SSL_INITIALIZATION_ERROR:
                click.secho(f'"{channel}" might exist, but wants SSL.', bold=True, fg='yellow')
                continue

            # Some other error condition occurred.
            raise ce
Ejemplo n.º 8
0
def queues(prefix, min_depth):
    """
        Show queues.
    """

    mqstate.validate(['host', 'port', 'channel'])

    args = {
        pymqi.CMQC.MQCA_Q_NAME: str(prefix),
        pymqi.CMQC.MQIA_Q_TYPE: pymqi.CMQC.MQQT_ALL
    }

    qmgr = pymqi.connect(mqstate.qm_name, mqstate.channel, mqstate.get_host(),
                         mqstate.username, mqstate.password)
    pcf = pymqi.PCFExecute(qmgr)

    try:

        click.secho('Showing queues with prefix: \'{0}\'...\n'.format(prefix),
                    dim=True)
        response = pcf.MQCMD_INQUIRE_Q(args)

    except pymqi.MQMIError as sqe:

        # no queues found
        if sqe.comp == pymqi.CMQC.MQCC_FAILED and sqe.reason == pymqi.CMQC.MQRC_UNKNOWN_OBJECT_NAME:
            click.secho('No queues matched given prefix of {0}'.format(prefix),
                        fg='red')

        else:
            raise sqe
    else:

        t = get_table_handle([
            'Created',
            'Name',
            'Type',
            'Usage',
            'Depth',
            'Rmt. QMGR Name',
            'Rmt. Queue Name',
            'Description',
        ],
                             markdown=True)
        t.set_style(t.STYLE_MARKDOWN)

        for queue_info in response:

            # skip queues that don't have at least the min amount of messages
            if queue_info.get(pymqi.CMQC.MQIA_CURRENT_Q_DEPTH, 0) < min_depth:
                continue

            t.append_row([
                ' '.join([
                    queue_info.get(pymqi.CMQC.MQCA_CREATION_DATE, '').strip(),
                    queue_info.get(pymqi.CMQC.MQCA_CREATION_TIME, '').strip()
                ]),
                queue_info.get(pymqi.CMQC.MQCA_Q_NAME, '').strip(),
                queue_type_to_name(queue_info.get(pymqi.CMQC.MQIA_Q_TYPE)),
                queue_usage_to_name(queue_info.get(pymqi.CMQC.MQIA_USAGE)),
                queue_info.get(pymqi.CMQC.MQIA_CURRENT_Q_DEPTH, ''),
                queue_info.get(pymqi.CMQC.MQCA_REMOTE_Q_MGR_NAME, '').strip(),
                queue_info.get(pymqi.CMQC.MQCA_REMOTE_Q_NAME, '').strip(),
                queue_info.get(pymqi.CMQC.MQCA_Q_DESC, '').strip(),
            ])
        click.secho(t.get_string())

    qmgr.disconnect()