#!/usr/bin/env python3
# Copyright 2026 SigmaSRC, Inc. All Rights Reserved.

"""Transfer Manager.

This program is invoked by the agent scheduler to transfer data
between the agent and the server.

Usage: %prog [-h] [-r] [ARGS]

If any positional arguments are given, only files whose type matches
one of those arguments are uploaded.

Work flow:

  - if -r given:
      - check matrix
      - check agent home page
      - check global agent configuration
  - upload files

If any step fails, the remaining steps are skipped.

"""

# Python imports
import os
import re
import sys
import glob
import time
import base64
import socket
import logging
import optparse
# M2Crypto.Rand replaced by os.urandom (os already imported above)

# Sigma imports
from sigma.util import avalog, config, cert, xmltime
from sigma.spool import spooling, qmgr
from sigma.sched import remote, tasks, pingpong, scheduling
from sigma.runtime import matrix
from sigma.util.errors import error
from sigma.protocol import xmlproto

# Global variables
options = config.Options()
logger = logging.getLogger("transfer-mgr")
parser = optparse.OptionParser(usage=__doc__.strip())
parser.add_option("-r", "--rfa", dest="rfa", action="store_true",
                  help="Do RFA/ACK handshake first", default=False)

# Functions are ordered top-down; please keep it that way

def main(args=None):
    # Parse the command line
    (opts, args) = parser.parse_args(args)

    # Complain if options.central_server isn't set
    if not options.central_server:
        # Don't use the logger to report this; the logger may not work
        # when this error condition occurs
        return error("The central-server option isn't set")

    # Create the logging environment
    avalog.setupLogging()

    # Complain if we haven't registered yet
    store = cert.CertificateStore(ssl=False, options=options)
    if not os.path.isfile(store.idfile):
        logger.error("Not registered yet")
        return 1

    # A bit of a hack: reusing scheduler code
    schedfile = options.datapath("schedule.xml")
    sched = scheduling.TaskScheduler(schedfile, options=options)
    ppt = pingpong.PingPongThread(sched, None, options)
    if opts.rfa:
        if not ppt.probeVarious():
            return 1
    qm = qmgr.QueueManager(options=options)
    if qm.is_empty():
        logger.info("No uploads")
    else:
        # On AIX 5.2, apply arcane SSL workaround.  Python can't seem to open
        # the character special files /dev/[u]random on 5.2, so use system()
        # to sneak some randomness out and seed the openssl PRNG with it.
        # Agent upgrade process uses transfer-mgr.py to upload a test gather.
        if sys.platform == 'aix5':
            p = os.popen('uname -r', 'r')
            osrel = p.read()
            p.close()
            logger.info('Seeding PRNG from /dev/urandom')
            ddcmd = 'dd if=/dev/urandom of=%s/randpool bs=128 count=1' % \
                    options.agentdata
            p = os.popen(ddcmd, 'r')
            # not interested in dd's chatty output
            p.close()
            # Rand.load_file replaced: Python 3 ssl uses os.urandom internally
            pass
        if not ppt.uploadFiles(qm, args):
            return 1
    return 0

if __name__ == "__main__":
    sys.exit(main())
