diff options
-rw-r--r-- | source3/include/client.h | 2 | ||||
-rw-r--r-- | source3/libsmb/cliconnect.c | 138 | ||||
-rw-r--r-- | source3/libsmb/clientgen.c | 4 | ||||
-rw-r--r-- | source3/libsmb/clispnego.c | 3 | ||||
-rw-r--r-- | source3/libsmb/ntlmssp.c | 139 | ||||
-rw-r--r-- | source3/libsmb/smbencrypt.c | 12 | ||||
-rw-r--r-- | source3/param/loadparm.c | 14 |
7 files changed, 200 insertions, 112 deletions
diff --git a/source3/include/client.h b/source3/include/client.h index d9b72d5e0a..ddb1772c26 100644 --- a/source3/include/client.h +++ b/source3/include/client.h @@ -62,7 +62,7 @@ typedef struct smb_sign_info { BOOL negotiated_smb_signing; BOOL temp_smb_signing; size_t mac_key_len; - uint8 mac_key[44]; + uint8 mac_key[64]; uint32 send_seq_num; uint32 reply_seq_num; BOOL allow_smb_signing; diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index ebe19b5143..1c89423b7f 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -2,7 +2,7 @@ Unix SMB/CIFS implementation. client connect/disconnect routines Copyright (C) Andrew Tridgell 1994-1998 - Copyright (C) Andrew Barteltt 2001-2002 + Copyright (C) Andrew Barteltt 2001-2003 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -45,7 +45,7 @@ static const struct { ****************************************************************************/ static BOOL cli_session_setup_lanman2(struct cli_state *cli, const char *user, - const char *pass, int passlen, const char *workgroup) + const char *pass, size_t passlen, const char *workgroup) { fstring pword; char *p; @@ -228,7 +228,7 @@ static BOOL cli_session_setup_plaintext(struct cli_state *cli, const char *user, return True; } -static void set_signing_on_cli (struct cli_state *cli, const char* pass, uint8 response[24]) +static void set_signing_on_cli (struct cli_state *cli, uint8 user_session_key[16], DATA_BLOB response) { uint8 zero_sig[8]; ZERO_STRUCT(zero_sig); @@ -242,7 +242,7 @@ static void set_signing_on_cli (struct cli_state *cli, const char* pass, uint8 r DEBUG(3, ("smb signing enabled!\n")); cli->sign_info.use_smb_signing = True; - cli_calculate_mac_key(cli, pass, response); + cli_calculate_mac_key(cli, user_session_key, response); } else { DEBUG(5, ("smb signing NOT enabled!\n")); } @@ -265,25 +265,90 @@ static void set_temp_signing_on_cli(struct cli_state *cli) ****************************************************************************/ static BOOL cli_session_setup_nt1(struct cli_state *cli, const char *user, - const char *pass, int passlen, - const char *ntpass, int ntpasslen, + const char *pass, size_t passlen, + const char *ntpass, size_t ntpasslen, const char *workgroup) { uint32 capabilities = cli_session_setup_capabilities(cli); - uchar pword[24]; - uchar ntpword[24]; + DATA_BLOB lm_response = data_blob(NULL, 0); + DATA_BLOB nt_response = data_blob(NULL, 0); + uchar user_session_key[16]; char *p; BOOL have_plaintext = False; - if (passlen > sizeof(pword) || ntpasslen > sizeof(ntpword)) - return False; - if (passlen != 24) { - /* non encrypted password supplied. Ignore ntpass. */ - passlen = 24; - ntpasslen = 24; - SMBencrypt(pass,cli->secblob.data,pword); - SMBNTencrypt(pass,cli->secblob.data,ntpword); + uchar nt_hash[16]; + E_md4hash(pass, nt_hash); + + if (lp_client_ntlmv2_auth()) { + uchar ntlm_v2_hash[16]; + uchar ntlmv2_response[16]; + uchar lmv2_response[16]; + DATA_BLOB ntlmv2_client_data; + DATA_BLOB lmv2_client_data; + DATA_BLOB server_chal; + + /* We don't use the NT# directly. Instead we use it mashed up with + the username and domain. + This prevents username swapping during the auth exchange + */ + if (!ntv2_owf_gen(nt_hash, user, workgroup, ntlm_v2_hash)) { + return False; + } + + server_chal = data_blob(cli->secblob.data, MIN(cli->secblob.length, 8)); + + /* NTLMv2 */ + + /* We also get to specify some random data */ + ntlmv2_client_data = data_blob(NULL, 20); + generate_random_buffer(ntlmv2_client_data.data, ntlmv2_client_data.length, False); + memset(ntlmv2_client_data.data, 'A', ntlmv2_client_data.length); + + /* Given that data, and the challenge from the server, generate a response */ + SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, ntlmv2_client_data, ntlmv2_response); + + /* put it into nt_response, for the code below to put into the packet */ + nt_response = data_blob(NULL, ntlmv2_client_data.length + sizeof(ntlmv2_response)); + memcpy(nt_response.data, ntlmv2_response, sizeof(ntlmv2_response)); + /* after the first 16 bytes is the random data we generated above, so the server can verify us with it */ + memcpy(nt_response.data + sizeof(ntlmv2_response), ntlmv2_client_data.data, ntlmv2_client_data.length); + data_blob_free(&ntlmv2_client_data); + + + /* LMv2 */ + + /* We also get to specify some random data, but only 8 bytes (24 byte total response) */ + lmv2_client_data = data_blob(NULL, 8); + generate_random_buffer(lmv2_client_data.data, lmv2_client_data.length, False); + memset(lmv2_client_data.data, 'B', lmv2_client_data.length); + + /* Calculate response */ + SMBOWFencrypt_ntv2(ntlm_v2_hash, server_chal, lmv2_client_data, lmv2_response); + + /* Calculate response */ + lm_response = data_blob(NULL, lmv2_client_data.length + sizeof(lmv2_response)); + memcpy(lm_response.data, lmv2_response, sizeof(lmv2_response)); + /* after the first 16 bytes is the 8 bytes of random data we made above */ + memcpy(lm_response.data + sizeof(lmv2_response), lmv2_client_data.data, lmv2_client_data.length); + data_blob_free(&lmv2_client_data); + + data_blob_free(&server_chal); + + /* The NTLMv2 calculations also provide a session key, for signing etc later */ + SMBsesskeygen_ntv2(ntlm_v2_hash, ntlmv2_response, user_session_key); + + } else { + /* non encrypted password supplied. Ignore ntpass. */ + if (lp_client_lanman_auth()) { + lm_response = data_blob(NULL, 24); + SMBencrypt(pass,cli->secblob.data,lm_response.data); + } + + nt_response = data_blob(NULL, 24); + SMBNTencrypt(pass,cli->secblob.data,nt_response.data); + SMBsesskeygen_ntv1(nt_hash, NULL, user_session_key); + } have_plaintext = True; set_temp_signing_on_cli(cli); @@ -291,11 +356,9 @@ static BOOL cli_session_setup_nt1(struct cli_state *cli, const char *user, /* pre-encrypted password supplied. Only used for security=server, can't do signing becouse we don't have oringial key */ - memcpy(pword, pass, 24); - if (ntpasslen == 24) - memcpy(ntpword, ntpass, 24); - else - ZERO_STRUCT(ntpword); + + lm_response = data_blob(pass, passlen); + nt_response = data_blob(ntpass, ntpasslen); } /* send a session setup command */ @@ -310,28 +373,35 @@ static BOOL cli_session_setup_nt1(struct cli_state *cli, const char *user, SSVAL(cli->outbuf,smb_vwv3,2); SSVAL(cli->outbuf,smb_vwv4,cli->pid); SIVAL(cli->outbuf,smb_vwv5,cli->sesskey); - SSVAL(cli->outbuf,smb_vwv7,passlen); - SSVAL(cli->outbuf,smb_vwv8,ntpasslen); + SSVAL(cli->outbuf,smb_vwv7,lm_response.length); + SSVAL(cli->outbuf,smb_vwv8,nt_response.length); SIVAL(cli->outbuf,smb_vwv11,capabilities); p = smb_buf(cli->outbuf); - memcpy(p,pword,passlen); p += passlen; - memcpy(p,ntpword,ntpasslen); p += ntpasslen; + if (lm_response.length) { + memcpy(p,lm_response.data, lm_response.length); p += lm_response.length; + } + if (nt_response.length) { + memcpy(p,nt_response.data, nt_response.length); p += nt_response.length; + } p += clistr_push(cli, p, user, -1, STR_TERMINATE); p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE); p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE); cli_setup_bcc(cli, p); - if (!cli_send_smb(cli)) - return False; - - if (!cli_receive_smb(cli)) + if (!cli_send_smb(cli) || !cli_receive_smb(cli)) { + data_blob_free(&lm_response); + data_blob_free(&nt_response); return False; + } show_msg(cli->inbuf); - if (cli_is_error(cli)) + if (cli_is_error(cli)) { + data_blob_free(&lm_response); + data_blob_free(&nt_response); return False; + } /* use the returned vuid from now on */ cli->vuid = SVAL(cli->inbuf,smb_uid); @@ -345,9 +415,11 @@ static BOOL cli_session_setup_nt1(struct cli_state *cli, const char *user, if (have_plaintext) { /* Have plaintext orginal */ - set_signing_on_cli(cli, pass, ntpword); + set_signing_on_cli(cli, user_session_key, nt_response); } + data_blob_free(&lm_response); + data_blob_free(&nt_response); return True; } @@ -529,6 +601,10 @@ static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, const char *user, return False; } + if (challenge_blob.length < 8) { + return False; + } + DEBUG(10, ("Challenge:\n")); dump_data(10, challenge_blob.data, 8); diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index ab051426ae..9598f4ac96 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -251,8 +251,8 @@ struct cli_state *cli_initialise(struct cli_state *cli) cli->outbuf = (char *)malloc(cli->bufsize); cli->inbuf = (char *)malloc(cli->bufsize); cli->oplock_handler = cli_oplock_ack; - if (lp_use_spnego()) - cli->use_spnego = True; + + cli->use_spnego = lp_client_use_spnego(); cli->capabilities = CAP_UNICODE | CAP_STATUS32; diff --git a/source3/libsmb/clispnego.c b/source3/libsmb/clispnego.c index 3e28baa417..277bf4765f 100644 --- a/source3/libsmb/clispnego.c +++ b/source3/libsmb/clispnego.c @@ -709,7 +709,8 @@ BOOL msrpc_parse(DATA_BLOB *blob, case 'b': b = (DATA_BLOB *)va_arg(ap, void *); len1 = va_arg(ap, unsigned); - *b = data_blob(blob->data + head_ofs, len1); + *b = data_blob(blob->data + head_ofs, + MIN(len1, blob->length - head_ofs)); head_ofs += len1; break; case 'd': diff --git a/source3/libsmb/ntlmssp.c b/source3/libsmb/ntlmssp.c index 5b608e0a7a..886f872764 100644 --- a/source3/libsmb/ntlmssp.c +++ b/source3/libsmb/ntlmssp.c @@ -37,71 +37,7 @@ static const uint8 *get_challenge(struct ntlmssp_state *ntlmssp_state) return chal; } -NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state) -{ - TALLOC_CTX *mem_ctx; - - mem_ctx = talloc_init("NTLMSSP context"); - - *ntlmssp_state = talloc_zero(mem_ctx, sizeof(**ntlmssp_state)); - if (!*ntlmssp_state) { - DEBUG(0,("ntlmssp_start: talloc failed!\n")); - talloc_destroy(mem_ctx); - return NT_STATUS_NO_MEMORY; - } - - ZERO_STRUCTP(*ntlmssp_state); - - (*ntlmssp_state)->mem_ctx = mem_ctx; - (*ntlmssp_state)->get_challenge = get_challenge; - - (*ntlmssp_state)->get_global_myname = global_myname; - (*ntlmssp_state)->get_domain = lp_workgroup; - (*ntlmssp_state)->server_role = ROLE_DOMAIN_MEMBER; /* a good default */ - - return NT_STATUS_OK; -} - -NTSTATUS ntlmssp_server_end(NTLMSSP_STATE **ntlmssp_state) -{ - TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx; - - data_blob_free(&(*ntlmssp_state)->chal); - data_blob_free(&(*ntlmssp_state)->lm_resp); - data_blob_free(&(*ntlmssp_state)->nt_resp); - - SAFE_FREE((*ntlmssp_state)->user); - SAFE_FREE((*ntlmssp_state)->domain); - SAFE_FREE((*ntlmssp_state)->workstation); - - talloc_destroy(mem_ctx); - *ntlmssp_state = NULL; - return NT_STATUS_OK; -} - -NTSTATUS ntlmssp_server_update(NTLMSSP_STATE *ntlmssp_state, - DATA_BLOB request, DATA_BLOB *reply) -{ - uint32 ntlmssp_command; - *reply = data_blob(NULL, 0); - - if (!msrpc_parse(&request, "Cd", - "NTLMSSP", - &ntlmssp_command)) { - - return NT_STATUS_LOGON_FAILURE; - } - - if (ntlmssp_command == NTLMSSP_NEGOTIATE) { - return ntlmssp_negotiate(ntlmssp_state, request, reply); - } else if (ntlmssp_command == NTLMSSP_AUTH) { - return ntlmssp_auth(ntlmssp_state, request, reply); - } else { - return NT_STATUS_LOGON_FAILURE; - } -} - -static const char *ntlmssp_target_name(NTLMSSP_STATE *ntlmssp_state, +static const char *ntlmssp_target_name(struct ntlmssp_state *ntlmssp_state, uint32 neg_flags, uint32 *chal_flags) { if (neg_flags & NTLMSSP_REQUEST_TARGET) { @@ -119,8 +55,8 @@ static const char *ntlmssp_target_name(NTLMSSP_STATE *ntlmssp_state, } } -NTSTATUS ntlmssp_negotiate(NTLMSSP_STATE *ntlmssp_state, - DATA_BLOB request, DATA_BLOB *reply) +static NTSTATUS ntlmssp_server_negotiate(struct ntlmssp_state *ntlmssp_state, + DATA_BLOB request, DATA_BLOB *reply) { DATA_BLOB struct_blob; fstring dnsname, dnsdomname; @@ -222,8 +158,8 @@ NTSTATUS ntlmssp_negotiate(NTLMSSP_STATE *ntlmssp_state, return NT_STATUS_MORE_PROCESSING_REQUIRED; } -NTSTATUS ntlmssp_auth(NTLMSSP_STATE *ntlmssp_state, - DATA_BLOB request, DATA_BLOB *reply) +static NTSTATUS ntlmssp_server_auth(struct ntlmssp_state *ntlmssp_state, + DATA_BLOB request, DATA_BLOB *reply) { DATA_BLOB sess_key; uint32 ntlmssp_command, neg_flags; @@ -279,3 +215,68 @@ NTSTATUS ntlmssp_auth(NTLMSSP_STATE *ntlmssp_state, return nt_status; } + +NTSTATUS ntlmssp_server_start(NTLMSSP_STATE **ntlmssp_state) +{ + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_init("NTLMSSP context"); + + *ntlmssp_state = talloc_zero(mem_ctx, sizeof(**ntlmssp_state)); + if (!*ntlmssp_state) { + DEBUG(0,("ntlmssp_start: talloc failed!\n")); + talloc_destroy(mem_ctx); + return NT_STATUS_NO_MEMORY; + } + + ZERO_STRUCTP(*ntlmssp_state); + + (*ntlmssp_state)->mem_ctx = mem_ctx; + (*ntlmssp_state)->get_challenge = get_challenge; + + (*ntlmssp_state)->get_global_myname = global_myname; + (*ntlmssp_state)->get_domain = lp_workgroup; + (*ntlmssp_state)->server_role = ROLE_DOMAIN_MEMBER; /* a good default */ + + return NT_STATUS_OK; +} + +NTSTATUS ntlmssp_server_end(NTLMSSP_STATE **ntlmssp_state) +{ + TALLOC_CTX *mem_ctx = (*ntlmssp_state)->mem_ctx; + + data_blob_free(&(*ntlmssp_state)->chal); + data_blob_free(&(*ntlmssp_state)->lm_resp); + data_blob_free(&(*ntlmssp_state)->nt_resp); + + SAFE_FREE((*ntlmssp_state)->user); + SAFE_FREE((*ntlmssp_state)->domain); + SAFE_FREE((*ntlmssp_state)->workstation); + + talloc_destroy(mem_ctx); + *ntlmssp_state = NULL; + return NT_STATUS_OK; +} + +NTSTATUS ntlmssp_server_update(NTLMSSP_STATE *ntlmssp_state, + DATA_BLOB request, DATA_BLOB *reply) +{ + uint32 ntlmssp_command; + *reply = data_blob(NULL, 0); + + if (!msrpc_parse(&request, "Cd", + "NTLMSSP", + &ntlmssp_command)) { + + return NT_STATUS_LOGON_FAILURE; + } + + if (ntlmssp_command == NTLMSSP_NEGOTIATE) { + return ntlmssp_server_negotiate(ntlmssp_state, request, reply); + } else if (ntlmssp_command == NTLMSSP_AUTH) { + return ntlmssp_server_auth(ntlmssp_state, request, reply); + } else { + return NT_STATUS_LOGON_FAILURE; + } +} + diff --git a/source3/libsmb/smbencrypt.c b/source3/libsmb/smbencrypt.c index a30a48a020..34689b502c 100644 --- a/source3/libsmb/smbencrypt.c +++ b/source3/libsmb/smbencrypt.c @@ -363,19 +363,17 @@ BOOL decode_pw_buffer(char in_buffer[516], char *new_pwrd, SMB signing - setup the MAC key. ************************************************************/ -void cli_calculate_mac_key(struct cli_state *cli, const char *plain_passwd, const uchar resp[24]) +void cli_calculate_mac_key(struct cli_state *cli, const uchar user_session_key[16], const DATA_BLOB response) { - uchar nt_hash[16]; - E_md4hash(plain_passwd, nt_hash); - mdfour(&cli->sign_info.mac_key[0], nt_hash, sizeof(nt_hash)); - memcpy(&cli->sign_info.mac_key[16],resp,24); - cli->sign_info.mac_key_len = 40; + memcpy(&cli->sign_info.mac_key[0], user_session_key, 16); + memcpy(&cli->sign_info.mac_key[16],response.data, MIN(response.length, 40 - 16)); + cli->sign_info.mac_key_len = MIN(response.length + 16, 40); cli->sign_info.use_smb_signing = True; /* These calls are INCONPATIBLE with SMB signing */ cli->readbraw_supported = False; - cli->writebraw_supported = False; + cli->writebraw_supported = False; /* Reset the sequence number in case we had a previous (aborted) attempt */ cli->sign_info.send_seq_num = 2; diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index ac366d4ccd..398ae88b97 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -264,6 +264,10 @@ typedef struct BOOL bAllowTrustedDomains; BOOL bLanmanAuth; BOOL bNTLMAuth; + BOOL bUseSpnego; + BOOL bClientLanManAuth; + BOOL bClientNTLMv2Auth; + BOOL bClientUseSpnego; BOOL bDebugHiresTimestamp; BOOL bDebugPid; BOOL bDebugUid; @@ -272,7 +276,6 @@ typedef struct BOOL bUnicode; BOOL bUseMmap; BOOL bHostnameLookups; - BOOL bUseSpnego; BOOL bUnixExtensions; BOOL bDisableNetbios; BOOL bKernelChangeNotify; @@ -772,6 +775,8 @@ static struct parm_struct parm_table[] = { {"restrict anonymous", P_INTEGER, P_GLOBAL, &Globals.restrict_anonymous, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, {"lanman auth", P_BOOL, P_GLOBAL, &Globals.bLanmanAuth, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, {"ntlm auth", P_BOOL, P_GLOBAL, &Globals.bNTLMAuth, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, + {"client NTLMv2 auth", P_BOOL, P_GLOBAL, &Globals.bClientNTLMv2Auth, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, + {"client lanman auth", P_BOOL, P_GLOBAL, &Globals.bClientLanManAuth, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, {"username", P_STRING, P_LOCAL, &sDefault.szUsername, NULL, NULL, FLAG_GLOBAL | FLAG_SHARE}, {"user", P_STRING, P_LOCAL, &sDefault.szUsername, NULL, NULL, FLAG_HIDE}, @@ -864,6 +869,7 @@ static struct parm_struct parm_table[] = { {"unix extensions", P_BOOL, P_GLOBAL, &Globals.bUnixExtensions, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, {"use spnego", P_BOOL, P_GLOBAL, &Globals.bUseSpnego, NULL, NULL, FLAG_DEVELOPER}, {"client signing", P_BOOL, P_GLOBAL, &Globals.client_signing, NULL, NULL, FLAG_ADVANCED | FLAG_DEVELOPER}, + {"client use spnego", P_BOOL, P_GLOBAL, &Globals.bClientUseSpnego, NULL, NULL, FLAG_DEVELOPER}, {"Tuning Options", P_SEP, P_SEPARATOR}, @@ -1375,8 +1381,10 @@ static void init_globals(void) Globals.bNTStatusSupport = True; /* Use NT status by default. */ Globals.bStatCache = True; /* use stat cache by default */ Globals.restrict_anonymous = 0; + Globals.bClientLanManAuth = True; /* Do use the LanMan hash if it is available */ Globals.bLanmanAuth = True; /* Do use the LanMan hash if it is available */ Globals.bNTLMAuth = True; /* Do use NTLMv1 if it is available (otherwise NTLMv2) */ + Globals.map_to_guest = 0; /* By Default, "Never" */ Globals.min_passwd_length = MINPASSWDLENGTH; /* By Default, 5. */ Globals.oplock_break_wait_time = 0; /* By Default, 0 msecs. */ @@ -1453,6 +1461,7 @@ static void init_globals(void) Globals.name_cache_timeout = 660; /* In seconds */ Globals.bUseSpnego = True; + Globals.bClientUseSpnego = True; string_set(&Globals.smb_ports, SMB_PORTS); } @@ -1677,12 +1686,15 @@ FN_GLOBAL_BOOL(lp_allow_trusted_domains, &Globals.bAllowTrustedDomains) FN_GLOBAL_INTEGER(lp_restrict_anonymous, &Globals.restrict_anonymous) FN_GLOBAL_BOOL(lp_lanman_auth, &Globals.bLanmanAuth) FN_GLOBAL_BOOL(lp_ntlm_auth, &Globals.bNTLMAuth) +FN_GLOBAL_BOOL(lp_client_lanman_auth, &Globals.bClientLanManAuth) +FN_GLOBAL_BOOL(lp_client_ntlmv2_auth, &Globals.bClientNTLMv2Auth) FN_GLOBAL_BOOL(lp_host_msdfs, &Globals.bHostMSDfs) FN_GLOBAL_BOOL(lp_kernel_oplocks, &Globals.bKernelOplocks) FN_GLOBAL_BOOL(lp_enhanced_browsing, &Globals.enhanced_browsing) FN_GLOBAL_BOOL(lp_use_mmap, &Globals.bUseMmap) FN_GLOBAL_BOOL(lp_unix_extensions, &Globals.bUnixExtensions) FN_GLOBAL_BOOL(lp_use_spnego, &Globals.bUseSpnego) +FN_GLOBAL_BOOL(lp_client_use_spnego, &Globals.bClientUseSpnego) FN_GLOBAL_BOOL(lp_hostname_lookups, &Globals.bHostnameLookups) FN_GLOBAL_BOOL(lp_kernel_change_notify, &Globals.bKernelChangeNotify) FN_GLOBAL_INTEGER(lp_os_level, &Globals.os_level) |