I have a jar that contains a CustomLoginModule to perform JAAS Autherization. This jar is located in ${CATALINA_BASE}/lib . I have an org.apache.juli.logging.Log object that performs logging in the module on different levels. I would like to have a log file e.g. jaas.log where the module's logs be written instead of having them in the Catalina.out or catalina.log. Here's my logging.properties file, with this configuration I am able to create the jaas.log but it stays empty and all log goes to Catalina.out and catalina.log can anybody help with this? Thank you very much.
logging.properties file:
handlers = 1catalina.org.apache.juli.FileHandler,
2localhost.org.apache.juli.FileHandler,
3manager.org.apache.juli.FileHandler, 4host-
manager.org.apache.juli.FileHandler, 5jaasauth.org.apache.juli.FileHandler
#, java.util.logging.ConsoleHandler
.handlers = 1catalina.org.apache.juli.FileHandler,
5jaasauth.org.apache.juli.FileHandler
#.handlers = 1catalina.org.apache.juli.FileHandler,
java.util.logging.ConsoleHandler, 5jaasauth.org.apache.juli.FileHandler
############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################
1catalina.org.apache.juli.FileHandler.level = FINE
1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
1catalina.org.apache.juli.FileHandler.prefix = catalina.
2localhost.org.apache.juli.FileHandler.level = FINE
2localhost.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
2localhost.org.apache.juli.FileHandler.prefix = localhost.
3manager.org.apache.juli.FileHandler.level = FINE
3manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
3manager.org.apache.juli.FileHandler.prefix = manager.
4host-manager.org.apache.juli.FileHandler.level = FINE
4host-manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
4host-manager.org.apache.juli.FileHandler.prefix = host-manager.
5jaasauth.org.apache.juli.FileHandler.level = ALL
5jaasauth.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
5jaasauth.org.apache.juli.FileHandler.prefix =jaas-auth.
############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].handlers =
2localhost.org.apache.juli.FileHandler
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].
[/manager].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].
[/manager].handlers = 3manager.org.apache.juli.FileHandler
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-mana
ger].level = INFO
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-
manager].handlers = 4host-manager.org.apache.juli.FileHandler
com.mymodule.apps.orchestration.CustomLdapLoginModule.level = ALL
com.mymodule.apps.CustomLdapLoginModule.handlers =
5jaasauth.org.apache.juli.FileHandler
Related
This is regarding Terraform on Azure. In my previous project I have used the legacy "azurerm_virtual_machine" resource + ARM Template to provision the "Microsoft.SqlVirtualMachine/SqlVirtualMachines" resource and have the data disks, luns configured.
That works pretty well.
In my current project, we are making use of the newer resource "azurerm_windows_virtual_machine" + "azurerm_mssql_virtual_machine" together to spin up the SQL VMs. However, it's been a dud so far.
Terraform docs example uses the legacy resource "azurerm_windows_virtual_machine".
Problems
Didn't find a way to describe the data disk and lun id in "azurerm_windows_virtual_machine" As a result
When I don't mention the storage_configuration block in the "azurerm_mssql_virtual_machine", Azure portal shows "Drive is not found in the volumes list." under the SQL Virtual Machine resource ( not the Virtual Machine resource) > Configuration section. I have attached a screenshot.
See error below :
If I try to mention data disk and lun in the storage_configuration block of the "azurerm_mssql_virtual_machine" , the provisioning fails with the error
creating Sql Virtual Machine (Sql Virtual Machine Name "ASQLVM" / Resource Group "a-resource-group"):
sqlvirtualmachine.SQLVirtualMachinesClient#CreateOrUpdate: Failure sending request: StatusCode=0 --
Original Error: Code="InvalidDefaultFilePath" Message="Invalid Default File Path"
Is there a good way to provision SQL Virtual Machines using the new "azurerm_windows_virtual_machine" ,+ "azurerm_mssql_virtual_machine" together ?
Check out the following code. I hope it answers your questions if you haven't already succeeded.
resource "azurerm_windows_virtual_machine" "vm" {
count = length(var.instances)
name = upper(element(var.instances, count.index))
location = azurerm_resource_group.resourcegroup[count.index].location
resource_group_name = azurerm_resource_group.resourcegroup[count.index].name
network_interface_ids = [azurerm_network_interface.nic[count.index].id]
size = var.instancesize
zone = var.instancezone
admin_username = var.vmadmin
admin_password = data.azurerm_key_vault_secret.vmadminpwd.value
enable_automatic_updates = "false"
patch_mode = "Manual"
provision_vm_agent = "true"
tags = var.tags
source_image_reference {
publisher = "MicrosoftSQLServer"
offer = "sql2019-ws2019"
sku = "enterprise"
version = "latest"
}
os_disk {
name = "${element(var.instances, count.index)}-osdisk"
caching = "ReadWrite"
storage_account_type = "StandardSSD_LRS"
disk_size_gb = 250
}
}
# add a data disk - we were going to iterate through a collection, but this is easier for now
resource "azurerm_managed_disk" "datadisk" {
count = length(var.instances)
name = "${azurerm_windows_virtual_machine.vm[count.index].name}-data-disk01"
location = azurerm_resource_group.resourcegroup[count.index].location
resource_group_name = azurerm_resource_group.resourcegroup[count.index].name
storage_account_type = "Premium_LRS"
zones = [var.instancezone]
create_option = "Empty"
disk_size_gb = 1000
tags = var.tags
}
resource "azurerm_virtual_machine_data_disk_attachment" "datadisk_attach" {
count = length(var.instances)
managed_disk_id = azurerm_managed_disk.datadisk[count.index].id
virtual_machine_id = azurerm_windows_virtual_machine.vm[count.index].id
lun = 1
caching = "ReadWrite"
}
# add a log disk - we were going to iterate through a collection, but this is easier for now
resource "azurerm_managed_disk" "logdisk" {
count = length(var.instances)
name = "${azurerm_windows_virtual_machine.vm[count.index].name}-log-disk01"
location = azurerm_resource_group.resourcegroup[count.index].location
resource_group_name = azurerm_resource_group.resourcegroup[count.index].name
storage_account_type = "Premium_LRS"
zones = [var.instancezone]
create_option = "Empty"
disk_size_gb = 500
tags = var.tags
}
resource "azurerm_virtual_machine_data_disk_attachment" "logdisk_attach" {
count = length(var.instances)
managed_disk_id = azurerm_managed_disk.logdisk[count.index].id
virtual_machine_id = azurerm_windows_virtual_machine.vm[count.index].id
lun = 2
caching = "ReadWrite"
}
# configure the SQL side of the deployment
resource "azurerm_mssql_virtual_machine" "sqlvm" {
count = length(var.instances)
virtual_machine_id = azurerm_windows_virtual_machine.vm[count.index].id
sql_license_type = "PAYG"
r_services_enabled = true
sql_connectivity_port = 1433
sql_connectivity_type = "PRIVATE"
sql_connectivity_update_username = var.sqladmin
sql_connectivity_update_password = data.azurerm_key_vault_secret.sqladminpwd.value
#The storage_configuration block supports the following:
storage_configuration {
disk_type = "NEW" # (Required) The type of disk configuration to apply to the SQL Server. Valid values include NEW, EXTEND, or ADD.
storage_workload_type = "OLTP" # (Required) The type of storage workload. Valid values include GENERAL, OLTP, or DW.
# The storage_settings block supports the following:
data_settings {
default_file_path = var.sqldatafilepath # (Required) The SQL Server default path
luns = [azurerm_virtual_machine_data_disk_attachment.datadisk_attach[count.index].lun]
}
log_settings {
default_file_path = var.sqllogfilepath # (Required) The SQL Server default path
luns = [azurerm_virtual_machine_data_disk_attachment.logdisk_attach[count.index].lun] # (Required) A list of Logical Unit Numbers for the disks.
}
# temp_db_settings {
# default_file_path = var.sqltempdbfilepath #- (Required) The SQL Server default path
# luns = [3] #- (Required) A list of Logical Unit Numbers for the disks.
# }
}
}
On the contrary to the answer above, the proposed code does not solve the problem.
The problem is:
There´s no clear format on how to pass the default path to the terraform sql resource.
resource "azurerm_mssql_virtual_machine" "sqlserver" {
virtual_machine_id = azurerm_windows_virtual_machine.win.id
sql_license_type = "PAYG"
r_services_enabled = true
auto_patching {
day_of_week = "Sunday"
maintenance_window_duration_in_minutes = 60
maintenance_window_starting_hour = 2
}
storage_configuration {
disk_type = "NEW"
storage_workload_type = "OLTP"
data_settings {
default_file_path = "D:\\Data"
luns = [0]
}
log_settings {
default_file_path = "E:\\log"
luns = [1]
}
temp_db_settings {
default_file_path = "F:\\bin"
luns = [2]
}
}
As you see here, I´m trying to define the correct path setting. But it´s not working.
The target is to attach the disks, and format them so that the SQL resource can take control of the path/disk.
You need use letter of temporary drive D: and omit E: because it's DVD drive.
You need to do it like this:
storage_configuration {
disk_type = "NEW"
storage_workload_type = "OLTP"
data_settings {
default_file_path = "F:\\Data"
luns = [0]
}
log_settings {
default_file_path = "G:\\Log"
luns = [1]
}
temp_db_settings {
default_file_path = "D:\\TempDb"
luns = []
}
I seem to be having an issue with the pro bono tac_plus configuration.
my switch is giving me the following log message
May 4 20:58:52 sv5-c1-r104-ae02 Aaa: %AAA-4-EXEC_AUTHZ_FAILED: User jdambly failed authorization to start a shell
if I look at the tac_plus logs it looks like my group mapping is not configured correctly, here is the log
May 4 14:04:22 neteng tac_plus[14476]: 1/9a920270: Start authorization request
May 4 14:04:22 neteng tac_plus[14476]: 1/9a920270: cfg_get: checking user/group jdambly, tag (NULL)
May 4 14:04:22 neteng tac_plus[14476]: 1/9a920270: cfg_get: checking user/group jdambly, tag (NULL)
May 4 14:04:22 neteng tac_plus[14476]: 1/9a920270: user 'jdambly' found
May 4 14:04:22 neteng tac_plus[14476]: 1/9a920270: cfg_get: checking user/group jdambly, tag (NULL)
May 4 14:04:22 neteng tac_plus[14476]: 1/9a920270: jdambly#192.168.0.19: not found: svcname=shell#world protocol=
May 4 14:04:22 neteng tac_plus[14476]: 1/9a920270: jdambly#192.168.0.19: not found: svcname=shell protocol=
May 4 14:04:22 neteng tac_plus[14476]: 1/9a920270: jdambly#192.168.0.19: svcname=shell protocol= not found, default is <unknown>
May 4 14:04:22 neteng tac_plus[14476]: 1/9a920270: Writing AUTHOR/FAIL size=18
here is my config
id = tac_plus {
debug = PACKET AUTHEN AUTHOR MAVIS
access log = /var/log/tac_plus/access.log
accounting log = /var/log/tac_plus/acct.log
authorization log = /var/log/tac_plus/auth.log
mavis module = external {
setenv LDAP_SERVER_TYPE = "microsoft"
#setenv LDAP_HOSTS = "ldaps://xxxxxx:3268"
setenv LDAP_HOSTS = "xxxxxx:3268"
setenv LDAP_SCOPE = sub
setenv LDAP_BASE = "dc=nskope,dc=net"
setenv LDAP_FILTER = "(&(objectclass=user)(sAMAccountName=%s))"
setenv LDAP_USER = "xxxx#nskope.net"
setenv LDAP_PASSWD = "xxxxxxxx"
#setenv AD_GROUP_PREFIX = devops
# setenv REQUIRE_AD_GROUP_PREFIX = 1
# setenv USE_TLS = 0
exec = /usr/local/lib/mavis/mavis_tacplus_ldap.pl
}
user backend = mavis
login backend = mavis
pap backend = mavis
skip missing groups = yes
host = world {
address = 0.0.0/0
prompt = "Welcome\n"
key = cisco
}
group = devops {
default service = permit
service = shell {
default command = permit
default attribute = permit
set priv-lvl = 15
}
}
}
I'm trying to map the ad group devops to the group in the config but I think that's failing and I don't get why
so LONG story short I got this working using the following config.
#!../../../sbin/tac_plus
id = spawnd {
listen = { port = 49 }
spawn = {
instances min = 1
instances max = 10
}
background = no
}
id = tac_plus {
debug = PACKET AUTHEN AUTHOR MAVIS
access log = /var/log/tac_plus/access.log
accounting log = /var/log/tac_plus/acct.log
authorization log = /var/log/tac_plus/auth.log
mavis module = external {
setenv LDAP_SERVER_TYPE = "microsoft"
#setenv LDAP_HOSTS = "ldaps://xxxxxxxxx:3268"
setenv LDAP_HOSTS = "xxxxxxxxx:3268"
#setenv LDAP_SCOPE = sub
setenv LDAP_BASE = "cn=Users,dc=nskope,dc=net"
setenv LDAP_FILTER = "(&(objectclass=user)(sAMAccountName=%s))"
setenv LDAP_USER = "xxxxxxxx"
setenv LDAP_PASSWD = "xxxxxxxx"
#setenv FLAG_FALLTHROUGH=1
setenv UNLIMIT_AD_GROUP_MEMBERSHIP = "1"
#setenv EXPAND_AD_GROUP_MEMBERSHIP=1
#setenv FLAG_USE_MEMBEROF = 1
setenv AD_GROUP_PREFIX = ""
# setenv REQUIRE_AD_GROUP_PREFIX = 1
# setenv USE_TLS = 0
exec = /usr/local/lib/mavis/mavis_tacplus_ldap.pl
}
user backend = mavis
login backend = mavis
pap backend = mavis
skip missing groups = yes
host = world {
address = 0.0.0/0
#prompt = "Welcome\n"
key = cisco
}
group = devops {
default service = permit
service = shell {
default command = permit
default attribute = permit
set priv-lvl = 15
}
}
}
what really did the trick is adding
setenv UNLIMIT_AD_GROUP_MEMBERSHIP = "1"
setenv AD_GROUP_PREFIX = ""
with these settings it's not looking for a prefix to the all the ad groups. This config allows for a direct mappings of ad group to the group configured in this file, in my case the group is called dev ops. also note that I had to use quotes around the 1. without these quests it does not set the var UNLIMIT_AD_GROUP_MEMBERSHIP to one so watch out for that. hopefully this can help someone else so they do not have to go through all the pain I did ;)
In Waf how can I create multiple custom tasks, that can run parallel (with --jobs=JOBS)?
Sources = ["C:\\src1.c", "C:\\Mod1\src2.c", ... 30pcs] # one per call
Incl_Paths = ["Mod1". "Mod1"] # list all of them in all call
INCL_ST = "-I%s" # how to format an include path in an argument
Ext_out = "_loc" # output file extension
The goal:
C:\\LOC.exe -IMod1 -IMod2 C:\\src1.c > build\\src1.c_loc //or better src1_loc
C:\\LOC.exe -IMod1 -IMod2 C:\\Mod1\src2.c > build\\src2.c_loc //or better src2_loc
...
I couldn't get it work
def build(bld):
for i in Sources:
bld.new_task_gen(
source = i,
rule='C:\\LOC.exe ${INCL_ST:Incl_Paths} ${SRC} > ' + i + Ext_out,
)
Also I couldn't extract the exe
# find_program(self, filename, path_list=[], var=None, environ=None, exts=''):
cfg.find_program("C:\\LOC.exe", var='LOC')
To change from:
rule='C:\\LOC.exe ...'
To:
rule='${LOC} ...'
Something like this should work with waf 1.7:
from waflib.Task import Task
from waflib.TaskGen import extension
Ext_out = "_loc" # output file extension
def configure(conf):
# loc.exe must be in the system path for this to work
conf.find_program(
'loc',
var = "LOC",
)
conf.env.Incl_Paths = ["Mod1", "Mod1"]
conf.env.INCL_ST = "-I%s"
#extension('.c')
def process_loc(self, node):
out_node = node.change_ext(Ext_out)
tsk = self.create_task('loc')
tsk.set_inputs(node)
tsk.set_outputs(out_node)
class loc_task(Task):
ext_in = ['.c']
ext_out = ['_loc']
run_str = "${LOC} ${INCL_ST:Incl_Paths} ${SRC} > ${TGT}"
def build(bld):
bld(source = ["src1.c", "src2.c"])
Well it works for me on linux faking loc ...
I'm trying to synchronize OpenLDAP and Active directory together. To do so I'm using a program called LSC-Project which is specified to do this sort of thing.
I have configured the program the best I can however I can't find a way to shake off the following error:
javax.naming.NameNotFoundException: [LDAP: error code 32 - 0000208D: NameErr: DSID-
031001CD,
problem 2001 (NO_OBJECT), data 0, best match of:
'DC=domname,DC=com'
]; remaining name
'uid=user1,ou=Users'
May 09 15:19:25 - ERROR - Error while synchronizing ID uid=user1,ou=Users:
java.lang.Exception:
Technical problem while applying modifications to directory
dn: uid=user1,ou=Users,dc=domname,dc=com
changetype: add
userPassword: 3+kU2th/WMo/v553A24a3SBw2kU=
objectClass: uid
This is the configuration file that the program runs on:
###############################
Destination LDAP directory #
##############################
dst.java.naming.provider.url = ldap://192.168.1.3:389/dc=Windows,dc=com
dst.java.naming.security.authentication = simple
dst.java.naming.security.principal = cn=Administrator,cn=Users,dc=Windows,dc=com
dst.java.naming.security.credentials = 11111
dst.java.naming.referral = ignore
dst.java.naming.ldap.derefAliases = never
dst.java.naming.factory.initial = com.sun.jndi.ldap.LdapCtxFactory
dst.java.naming.ldap.version = 3
dst.java.naming.ldap.pageSize = 1000
#########################
Source LDAP directory
#########################
src.java.naming.provider.url = ldap://192.168.1.2:389/dc=Linux,dc=com
src.java.naming.security.authentication = simple
src.java.naming.security.principal = uid=root,ou=users,dc=Linux,dc=com
src.java.naming.security.credentials = 11111
src.java.naming.referral = ignore
src.java.naming.ldap.derefAliases = never
src.java.naming.factory.initial = com.sun.jndi.ldap.LdapCtxFactory
src.java.naming.ldap.version = 3
#######################
Tasks configuration
#######################
lsc.tasks = Administrator
lsc.tasks.Administrator.srcService = org.lsc.jndi.SimpleJndiSrcService
lsc.tasks.Administrator.srcService.baseDn = ou=users
lsc.tasks.Administrator.srcService.filterAll = (&(objectClass=person))
lsc.tasks.Administrator.srcService.pivotAttrs = uid
lsc.tasks.Administrator.srcService.filterId = (&(objectClass=person)(uid={uid}))
lsc.tasks.Administrator.srcService.attrs = description uid userPassword
lsc.tasks.Administrator.dstService = org.lsc.jndi.SimpleJndiDstService
lsc.tasks.Administrator.dstService.baseDn = cn=Users
lsc.tasks.Administrator.dstService.filterAll = (&(cn=*)(objectClass=organizationalPerson))
lsc.tasks.Administrator.dstService.pivotAttrs = cn, top, person, user, organizationalPerson
lsc.tasks.Administrator.dstService.filterId = (&(objectClass=user) (sAMAccountName={cn}))
lsc.tasks.Administrator.dstService.attrs = description cn userPassword objectClass
lsc.tasks.Administrator.bean = org.lsc.beans.SimpleBean
lsc.tasks.Administrator.dn = "uid=" + srcBean.getAttributeValueById("uid") + ",ou=Users"
dn.real_root = dc=Domname,dc=com
#############################
Syncoptions configuration
#############################
lsc.syncoptions.Administrator = org.lsc.beans.syncoptions.PropertiesBasedSyncOptions
lsc.syncoptions.Administrator.default.action = M
lsc.syncoptions.Administrator.objectClass.action = M
lsc.syncoptions.Administrator.objectClass.force_value = srcBean.getAttributeValueById("cn").toUpperCase()
lsc.syncoptions.Administrator.userPassword.default_value = SecurityUtils.hash(SecurityUtils.HASH_SHA1, "defaultPassword")
lsc.syncoptions.Administrator.default.delimiter=;
lsc.syncoptions.Administrator.objectClass.force_value = "top";"user";"person";"organizationalPerson"
lsc.syncoptions.Administrator.userPrincipalName.force_value = srcBean.getAttributeValueById("uid") + "#Domname.com"
lsc.syncoptions.Administrator.userAccountControl.create_value = AD.userAccountControlSet ( "0", [AD.UAC_SET_NORMAL_ACCOUNT])
I'm suspecting that it has something to do with the baseDn of the Task configuration in the part of the source configuration.
The OSs is ubuntu 10.04 and Windows2K3
Someone suggested to me to make a manual sync between them but I have not found any guides to do so. And this program is pretty much the only thing that says that is does this kind of job without costs.
The baseDn should be the distinguished name of the base object of the search, for example, ou=users,dc=domname,dc=com.
see also
LDAP: Mastering Search Filters
LDAP: Search best practices
LDAP: Programming practices
The main reason for NameNotFoundException is that the object which you're searching doesn't exist or the container in which you are searching is not correct.
In case of Spring-ldap, we used to get this error when we specify the baseDn in the context file(LdapContextSource bean) and also in createUser code to build userDn.we need not specify the dc again in the buildUserDn()
protected Name buildUserDn(String userName) {
DistinguishedName dn = new DistinguishedName();
//only cn is required as the base dn is already specified in context file
dn.add("cn", userName);
return dn;
}
In Active Directory: Users catalog is container class, not OrganizationalUnit, so you should use: cn=users,dc=domname,dc=com
The waf command waf build shows compiler errors (if there are any) while waf debug or waf release does not and always fails, utilizing the following wscript file (or maybe the wscript file has some other shortcomings I am currently not aware of):
APPNAME = 'waftest'
VERSION = '0.0.1'
def configure(ctx):
ctx.load('compiler_c')
ctx.define('VERSION', VERSION)
ctx.define('GETTEXT_PACKAGE', APPNAME)
ctx.check_cfg(atleast_pkgconfig_version='0.1.1')
ctx.check_cfg(package='glib-2.0', uselib_store='GLIB', args=['--cflags', '--libs'], mandatory=True)
ctx.check_cfg(package='gobject-2.0', uselib_store='GOBJECT', args=['--cflags', '--libs'], mandatory=True)
ctx.check_cfg(package='gtk+-3.0', uselib_store='GTK3', args=['--cflags', '--libs'], mandatory=True)
ctx.check_cfg(package='libxml-2.0', uselib_store='XML', args=['--cflags', '--libs'], mandatory=True)
ctx.check_large_file(mandatory=False)
ctx.check_endianness(mandatory=False)
ctx.check_inline(mandatory=False)
ctx.setenv('debug')
ctx.env.CFLAGS = ['-g', '-Wall']
ctx.define('DEBUG',1)
ctx.setenv('release')
ctx.env.CFLAGS = ['-O2', '-Wall']
ctx.define('RELEASE',1)
def pre(ctx):
print ('Building [[[' + ctx.variant + ']]] ...')
def post(ctx):
print ('Building is complete.')
def build(ctx):
ctx.add_pre_fun(pre)
ctx.add_post_fun(post)
# if not ctx.variant:
# ctx.fatal('Do "waf debug" or "waf release"')
exe = ctx.program(
features = ['c', 'cprogram'],
target = APPNAME+'.bin',
source = ctx.path.ant_glob(['src/*.c']),
includes = ['src/'],
export_includes = ['src/'],
uselib = 'GOBJECT GLIB GTK3 XML'
)
# for item in exe.includes:
# print(item)
from waflib.Build import BuildContext
class release(BuildContext):
cmd = 'release'
variant = 'release'
class debug(BuildContext):
cmd = 'debug'
variant = 'debug'
Error resulting from waf debug :
Build failed
-> task in 'waftest.bin' failed (exit status -1):
{task 46697488: c qqq.c -> qqq.c.1.o}
[useless filepaths]
I had a look at the waf demos, read the wafbook at section 6.2.2 but those did not supply me with valuable information in order to fix this issue.
What's wrong, and how do I fix it?
You need to do at least the following:
def configure(ctx):
...
ctx.setenv('debug')
ctx.load('compiler_c')
...
Since the cfg.setenv function resets whole previous environment. If you want to save previous environment, you can do cfg.setenv('debug', env=cfg.env.derive()).
Also, you don't need to explicitly specify the features = ['c', 'cprogram'], since, it's redundant, when you call bld.program(...).
P.S. Don't forget to reconfigure after modifying wscript file.