def enumerate_tokens(sid=None, session_id=None, privs=None):
    '''
    Enumerate tokens from any existing processes that can be accessed.
    Optionally filter by sid.
    '''
    for p in psutil.process_iter():
        if p.pid == 0:
            continue
        try:
            ph = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, 0, p.pid)
        except win32api.error as exc:
            if exc.winerror == 5:
                log.debug("Unable to OpenProcess pid=%d name=%s", p.pid, p.name())
                continue
            raise exc
        try:
            access = (
                win32security.TOKEN_DUPLICATE |
                win32security.TOKEN_QUERY |
                win32security.TOKEN_IMPERSONATE |
                win32security.TOKEN_ASSIGN_PRIMARY
            )
            th = win32security.OpenProcessToken(ph, access)
        except Exception as exc:
            log.debug("OpenProcessToken failed pid=%d name=%s user%s", p.pid, p.name(), p.username())
            continue
        try:
            process_sid = win32security.GetTokenInformation(th, win32security.TokenUser)[0]
        except Exception as exc:
            log.exception("GetTokenInformation pid=%d name=%s user%s", p.pid, p.name(), p.username())
            continue

        proc_sid = win32security.ConvertSidToStringSid(process_sid)
        if sid and sid != proc_sid:
            log.debug("Token for pid does not match user sid: %s", sid)
            continue

        if session_id and win32security.GetTokenInformation(th, win32security.TokenSessionId) != session_id:
            continue

        def has_priv(tok, priv):
            luid = win32security.LookupPrivilegeValue(None, priv)
            for priv_luid, flags in win32security.GetTokenInformation(tok, win32security.TokenPrivileges):
                if priv_luid == luid:
                    return True
            return False
        if privs:
            has_all = True
            for name in privs:
                if not has_priv(th, name):
                    has_all = False
            if not has_all:
                continue
        yield dup_token(th)
Enumerate tokens from any existing processes that can be accessed.
    Optionally filter by sid.