mirror of
https://github.com/samba-team/samba.git
synced 2025-11-02 20:23:50 +03:00
first public release of samba4 code
This commit is contained in:
1
source/utils/.cvsignore
Normal file
1
source/utils/.cvsignore
Normal file
@@ -0,0 +1 @@
|
||||
net_proto.h
|
||||
253
source/utils/debug2html.c
Normal file
253
source/utils/debug2html.c
Normal file
@@ -0,0 +1,253 @@
|
||||
/* ========================================================================== **
|
||||
* debug2html.c
|
||||
*
|
||||
* Copyright (C) 1998 by Christopher R. Hertel
|
||||
*
|
||||
* Email: crh@ubiqx.mn.org
|
||||
*
|
||||
* -------------------------------------------------------------------------- **
|
||||
* Parse Samba debug logs (2.0 & greater) and output the results as HTML.
|
||||
* -------------------------------------------------------------------------- **
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* -------------------------------------------------------------------------- **
|
||||
* This program provides an example of the use of debugparse.c, and also
|
||||
* does a decent job of converting Samba logs into HTML.
|
||||
* -------------------------------------------------------------------------- **
|
||||
*
|
||||
* Revision 1.4 1998/11/13 03:37:01 tridge
|
||||
* fixes for OSF1 compilation
|
||||
*
|
||||
* Revision 1.3 1998/10/28 20:33:35 crh
|
||||
* I've moved the debugparse module files into the ubiqx directory because I
|
||||
* know that 'make proto' will ignore them there. The debugparse.h header
|
||||
* file is included in includes.h, and includes.h is included in debugparse.c,
|
||||
* so all of the pieces "see" each other. I've compiled and tested this,
|
||||
* and it does seem to work. It's the same compromise model I used when
|
||||
* adding the ubiqx modules into the system, which is why I put it all into
|
||||
* the same directory.
|
||||
*
|
||||
* Chris -)-----
|
||||
*
|
||||
* Revision 1.1 1998/10/26 23:21:37 crh
|
||||
* Here is the simple debug parser and the debug2html converter. Still to do:
|
||||
*
|
||||
* * Debug message filtering.
|
||||
* * I need to add all this to Makefile.in
|
||||
* (If it looks at all strange I'll ask for help.)
|
||||
*
|
||||
* If you want to compile debug2html, you'll need to do it by hand until I
|
||||
* make the changes to Makefile.in. Sorry.
|
||||
*
|
||||
* Chris -)-----
|
||||
*
|
||||
* ========================================================================== **
|
||||
*/
|
||||
|
||||
#include "debugparse.h"
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
* The size of the read buffer.
|
||||
*/
|
||||
|
||||
#define DBG_BSIZE 1024
|
||||
|
||||
/* -------------------------------------------------------------------------- **
|
||||
* Functions...
|
||||
*/
|
||||
|
||||
static dbg_Token modechange( dbg_Token new, dbg_Token mode )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Handle a switch between header and message printing.
|
||||
*
|
||||
* Input: new - The token value of the current token. This indicates
|
||||
* the lexical item currently being recognized.
|
||||
* mode - The current mode. This is either dbg_null or
|
||||
* dbg_message. It could really be any toggle
|
||||
* (true/false, etc.)
|
||||
*
|
||||
* Output: The new mode. This will be the same as the input mode unless
|
||||
* there was a transition in or out of message processing.
|
||||
*
|
||||
* Notes: The purpose of the mode value is to mark the beginning and end
|
||||
* of the message text block. In order to show the text in its
|
||||
* correct format, it must be included within a <PRE></PRE> block.
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
switch( new )
|
||||
{
|
||||
case dbg_null:
|
||||
case dbg_ignore:
|
||||
return( mode );
|
||||
case dbg_message:
|
||||
if( dbg_message != mode )
|
||||
{
|
||||
/* Switching to message mode. */
|
||||
(void)printf( "<PRE>\n" );
|
||||
return( dbg_message );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if( dbg_message == mode )
|
||||
{
|
||||
/* Switching out of message mode. */
|
||||
(void)printf( "</PRE>\n\n" );
|
||||
return( dbg_null );
|
||||
}
|
||||
}
|
||||
|
||||
return( mode );
|
||||
} /* modechange */
|
||||
|
||||
static void newblock( dbg_Token old, dbg_Token new )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Handle the transition between tokens.
|
||||
*
|
||||
* Input: old - The previous token.
|
||||
* new - The current token.
|
||||
*
|
||||
* Output: none.
|
||||
*
|
||||
* Notes: This is called whenever there is a transition from one token
|
||||
* type to another. It first prints the markup tags that close
|
||||
* the previous token, and then the markup tags for the new
|
||||
* token.
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
switch( old )
|
||||
{
|
||||
case dbg_timestamp:
|
||||
(void)printf( ",</B>" );
|
||||
break;
|
||||
case dbg_level:
|
||||
(void)printf( "</FONT>]</B>\n " );
|
||||
break;
|
||||
case dbg_sourcefile:
|
||||
(void)printf( ":" );
|
||||
break;
|
||||
case dbg_lineno:
|
||||
(void)printf( ")" );
|
||||
break;
|
||||
}
|
||||
|
||||
switch( new )
|
||||
{
|
||||
case dbg_timestamp:
|
||||
(void)printf( "<B>[" );
|
||||
break;
|
||||
case dbg_level:
|
||||
(void)printf( " <B><FONT COLOR=MAROON>" );
|
||||
break;
|
||||
case dbg_lineno:
|
||||
(void)printf( "(" );
|
||||
break;
|
||||
}
|
||||
} /* newblock */
|
||||
|
||||
static void charprint( dbg_Token tok, int c )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* Filter the input characters to determine what goes to output.
|
||||
*
|
||||
* Input: tok - The token value of the current character.
|
||||
* c - The current character.
|
||||
*
|
||||
* Output: none.
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
switch( tok )
|
||||
{
|
||||
case dbg_ignore:
|
||||
case dbg_header:
|
||||
break;
|
||||
case dbg_null:
|
||||
case dbg_eof:
|
||||
(void)putchar( '\n' );
|
||||
break;
|
||||
default:
|
||||
switch( c )
|
||||
{
|
||||
case '<':
|
||||
(void)printf( "<" );
|
||||
break;
|
||||
case '>':
|
||||
(void)printf( ">" );
|
||||
break;
|
||||
case '&':
|
||||
(void)printf( "&" );
|
||||
break;
|
||||
case '\"':
|
||||
(void)printf( """ );
|
||||
break;
|
||||
default:
|
||||
(void)putchar( c );
|
||||
break;
|
||||
}
|
||||
}
|
||||
} /* charprint */
|
||||
|
||||
int main( int argc, char *argv[] )
|
||||
/* ------------------------------------------------------------------------ **
|
||||
* This simple program scans and parses Samba debug logs, and produces HTML
|
||||
* output.
|
||||
*
|
||||
* Input: argc - Currently ignored.
|
||||
* argv - Currently ignored.
|
||||
*
|
||||
* Output: Always zero.
|
||||
*
|
||||
* Notes: The HTML output is sent to stdout.
|
||||
*
|
||||
* ------------------------------------------------------------------------ **
|
||||
*/
|
||||
{
|
||||
int i;
|
||||
int len;
|
||||
char bufr[DBG_BSIZE];
|
||||
dbg_Token old = dbg_null,
|
||||
new = dbg_null,
|
||||
state = dbg_null,
|
||||
mode = dbg_null;
|
||||
|
||||
(void)printf( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2//EN\">\n" );
|
||||
(void)printf( "<HTML>\n<HEAD>\n" );
|
||||
(void)printf( " <TITLE>Samba Debug Output</TITLE>\n</HEAD>\n\n<BODY>\n" );
|
||||
|
||||
while( (!feof( stdin ))
|
||||
&& ((len = fread( bufr, 1, DBG_BSIZE, stdin )) > 0) )
|
||||
{
|
||||
for( i = 0; i < len; i++ )
|
||||
{
|
||||
old = new;
|
||||
new = dbg_char2token( &state, bufr[i] );
|
||||
if( new != old )
|
||||
{
|
||||
mode = modechange( new, mode );
|
||||
newblock( old, new );
|
||||
}
|
||||
charprint( new, bufr[i] );
|
||||
}
|
||||
}
|
||||
(void)modechange( dbg_eof, mode );
|
||||
|
||||
(void)printf( "</BODY>\n</HTML>\n" );
|
||||
return( 0 );
|
||||
} /* main */
|
||||
2069
source/utils/editreg.c
Normal file
2069
source/utils/editreg.c
Normal file
File diff suppressed because it is too large
Load Diff
642
source/utils/net.c
Normal file
642
source/utils/net.c
Normal file
@@ -0,0 +1,642 @@
|
||||
/*
|
||||
Samba Unix/Linux SMB client library
|
||||
Distributed SMB/CIFS Server Management Utility
|
||||
Copyright (C) 2001 Steve French (sfrench@us.ibm.com)
|
||||
Copyright (C) 2001 Jim McDonough (jmcd@us.ibm.com)
|
||||
Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
|
||||
Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org)
|
||||
|
||||
Originally written by Steve and Jim. Largely rewritten by tridge in
|
||||
November 2001.
|
||||
|
||||
Reworked again by abartlet in December 2001
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/*****************************************************/
|
||||
/* */
|
||||
/* Distributed SMB/CIFS Server Management Utility */
|
||||
/* */
|
||||
/* The intent was to make the syntax similar */
|
||||
/* to the NET utility (first developed in DOS */
|
||||
/* with additional interesting & useful functions */
|
||||
/* added in later SMB server network operating */
|
||||
/* systems). */
|
||||
/* */
|
||||
/*****************************************************/
|
||||
|
||||
#include "includes.h"
|
||||
#include "../utils/net.h"
|
||||
|
||||
/***********************************************************************/
|
||||
/* Beginning of internationalization section. Translatable constants */
|
||||
/* should be kept in this area and referenced in the rest of the code. */
|
||||
/* */
|
||||
/* No functions, outside of Samba or LSB (Linux Standards Base) should */
|
||||
/* be used (if possible). */
|
||||
/***********************************************************************/
|
||||
|
||||
#define YES_STRING "Yes"
|
||||
#define NO_STRING "No"
|
||||
|
||||
/************************************************************************************/
|
||||
/* end of internationalization section */
|
||||
/************************************************************************************/
|
||||
|
||||
/* Yes, these buggers are globals.... */
|
||||
const char *opt_requester_name = NULL;
|
||||
const char *opt_host = NULL;
|
||||
const char *opt_password = NULL;
|
||||
const char *opt_user_name = NULL;
|
||||
BOOL opt_user_specified = False;
|
||||
const char *opt_workgroup = NULL;
|
||||
int opt_long_list_entries = 0;
|
||||
int opt_reboot = 0;
|
||||
int opt_force = 0;
|
||||
int opt_port = 0;
|
||||
int opt_maxusers = -1;
|
||||
const char *opt_comment = "";
|
||||
char *opt_container = "cn=Users";
|
||||
int opt_flags = -1;
|
||||
int opt_jobid = 0;
|
||||
int opt_timeout = 0;
|
||||
const char *opt_target_workgroup = NULL;
|
||||
static int opt_machine_pass = 0;
|
||||
|
||||
BOOL opt_have_ip = False;
|
||||
struct in_addr opt_dest_ip;
|
||||
|
||||
extern BOOL AllowDebugChange;
|
||||
|
||||
/*
|
||||
run a function from a function table. If not found then
|
||||
call the specified usage function
|
||||
*/
|
||||
int net_run_function(int argc, const char **argv, struct functable *table,
|
||||
int (*usage_fn)(int argc, const char **argv))
|
||||
{
|
||||
int i;
|
||||
|
||||
if (argc < 1) {
|
||||
d_printf("\nUsage: \n");
|
||||
return usage_fn(argc, argv);
|
||||
}
|
||||
for (i=0; table[i].funcname; i++) {
|
||||
if (StrCaseCmp(argv[0], table[i].funcname) == 0)
|
||||
return table[i].fn(argc-1, argv+1);
|
||||
}
|
||||
d_printf("No command: %s\n", argv[0]);
|
||||
return usage_fn(argc, argv);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
connect to \\server\ipc$
|
||||
****************************************************************************/
|
||||
NTSTATUS connect_to_ipc(struct cli_state **c, struct in_addr *server_ip,
|
||||
const char *server_name)
|
||||
{
|
||||
NTSTATUS nt_status;
|
||||
|
||||
if (!opt_password) {
|
||||
char *pass = getpass("Password:");
|
||||
if (pass) {
|
||||
opt_password = strdup(pass);
|
||||
}
|
||||
}
|
||||
|
||||
nt_status = cli_full_connection(c, opt_requester_name, server_name,
|
||||
server_ip, opt_port,
|
||||
"IPC$", "IPC",
|
||||
opt_user_name, opt_workgroup,
|
||||
opt_password, 0, NULL);
|
||||
|
||||
if (NT_STATUS_IS_OK(nt_status)) {
|
||||
return nt_status;
|
||||
} else {
|
||||
DEBUG(1,("Cannot connect to server. Error was %s\n",
|
||||
nt_errstr(nt_status)));
|
||||
|
||||
/* Display a nicer message depending on the result */
|
||||
|
||||
if (NT_STATUS_V(nt_status) ==
|
||||
NT_STATUS_V(NT_STATUS_LOGON_FAILURE))
|
||||
d_printf("The username or password was not correct.\n");
|
||||
|
||||
return nt_status;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
connect to \\server\ipc$ anonymously
|
||||
****************************************************************************/
|
||||
NTSTATUS connect_to_ipc_anonymous(struct cli_state **c,
|
||||
struct in_addr *server_ip, const char *server_name)
|
||||
{
|
||||
NTSTATUS nt_status;
|
||||
|
||||
nt_status = cli_full_connection(c, opt_requester_name, server_name,
|
||||
server_ip, opt_port,
|
||||
"IPC$", "IPC",
|
||||
"", "",
|
||||
"", 0, NULL);
|
||||
|
||||
if (NT_STATUS_IS_OK(nt_status)) {
|
||||
return nt_status;
|
||||
} else {
|
||||
DEBUG(1,("Cannot connect to server (anonymously). Error was %s\n", nt_errstr(nt_status)));
|
||||
return nt_status;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL net_find_server(unsigned flags, struct in_addr *server_ip, char **server_name)
|
||||
{
|
||||
|
||||
if (opt_host) {
|
||||
*server_name = strdup(opt_host);
|
||||
}
|
||||
|
||||
if (opt_have_ip) {
|
||||
*server_ip = opt_dest_ip;
|
||||
if (!*server_name) {
|
||||
*server_name = strdup(inet_ntoa(opt_dest_ip));
|
||||
}
|
||||
} else if (*server_name) {
|
||||
/* resolve the IP address */
|
||||
if (!resolve_name(*server_name, server_ip, 0x20)) {
|
||||
DEBUG(1,("Unable to resolve server name\n"));
|
||||
return False;
|
||||
}
|
||||
} else if (flags & NET_FLAGS_PDC) {
|
||||
struct in_addr pdc_ip;
|
||||
|
||||
if (get_pdc_ip(opt_target_workgroup, &pdc_ip)) {
|
||||
fstring dc_name;
|
||||
|
||||
if (is_zero_ip(pdc_ip))
|
||||
return False;
|
||||
|
||||
if (!lookup_dc_name(lp_netbios_name(), opt_target_workgroup, &pdc_ip, dc_name))
|
||||
return False;
|
||||
|
||||
*server_name = strdup(dc_name);
|
||||
*server_ip = pdc_ip;
|
||||
}
|
||||
|
||||
} else if (flags & NET_FLAGS_DMB) {
|
||||
struct in_addr msbrow_ip;
|
||||
/* if (!resolve_name(MSBROWSE, &msbrow_ip, 1)) */
|
||||
if (!resolve_name(opt_target_workgroup, &msbrow_ip, 0x1B)) {
|
||||
DEBUG(1,("Unable to resolve domain browser via name lookup\n"));
|
||||
return False;
|
||||
} else {
|
||||
*server_ip = msbrow_ip;
|
||||
}
|
||||
*server_name = strdup(inet_ntoa(opt_dest_ip));
|
||||
} else if (flags & NET_FLAGS_MASTER) {
|
||||
struct in_addr brow_ips;
|
||||
if (!resolve_name(opt_target_workgroup, &brow_ips, 0x1D)) {
|
||||
/* go looking for workgroups */
|
||||
DEBUG(1,("Unable to resolve master browser via name lookup\n"));
|
||||
return False;
|
||||
} else {
|
||||
*server_ip = brow_ips;
|
||||
}
|
||||
*server_name = strdup(inet_ntoa(opt_dest_ip));
|
||||
} else if (!(flags & NET_FLAGS_LOCALHOST_DEFAULT_INSANE)) {
|
||||
extern struct in_addr loopback_ip;
|
||||
*server_ip = loopback_ip;
|
||||
*server_name = strdup("127.0.0.1");
|
||||
}
|
||||
|
||||
if (!server_name || !*server_name) {
|
||||
DEBUG(1,("no server to connect to\n"));
|
||||
return False;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
BOOL net_find_dc(struct in_addr *server_ip, fstring server_name, const char *domain_name)
|
||||
{
|
||||
if (get_pdc_ip(domain_name, server_ip)) {
|
||||
fstring dc_name;
|
||||
|
||||
if (is_zero_ip(*server_ip))
|
||||
return False;
|
||||
|
||||
if (!lookup_dc_name(lp_netbios_name(), domain_name, server_ip, dc_name))
|
||||
return False;
|
||||
|
||||
safe_strcpy(server_name, dc_name, FSTRING_LEN);
|
||||
return True;
|
||||
} else
|
||||
return False;
|
||||
}
|
||||
|
||||
|
||||
struct cli_state *net_make_ipc_connection(unsigned flags)
|
||||
{
|
||||
char *server_name = NULL;
|
||||
struct in_addr server_ip;
|
||||
struct cli_state *cli = NULL;
|
||||
NTSTATUS nt_status;
|
||||
|
||||
if (!net_find_server(flags, &server_ip, &server_name)) {
|
||||
d_printf("\nUnable to find a suitable server\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (flags & NET_FLAGS_ANONYMOUS) {
|
||||
nt_status = connect_to_ipc_anonymous(&cli, &server_ip, server_name);
|
||||
} else {
|
||||
nt_status = connect_to_ipc(&cli, &server_ip, server_name);
|
||||
}
|
||||
|
||||
SAFE_FREE(server_name);
|
||||
if (NT_STATUS_IS_OK(nt_status)) {
|
||||
return cli;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int net_user(int argc, const char **argv)
|
||||
{
|
||||
if (net_ads_check() == 0)
|
||||
return net_ads_user(argc, argv);
|
||||
|
||||
/* if server is not specified, default to PDC? */
|
||||
if (net_rpc_check(NET_FLAGS_PDC))
|
||||
return net_rpc_user(argc, argv);
|
||||
|
||||
return net_rap_user(argc, argv);
|
||||
}
|
||||
|
||||
static int net_group(int argc, const char **argv)
|
||||
{
|
||||
if (net_ads_check() == 0)
|
||||
return net_ads_group(argc, argv);
|
||||
|
||||
if (argc == 0 && net_rpc_check(NET_FLAGS_PDC))
|
||||
return net_rpc_group(argc, argv);
|
||||
|
||||
return net_rap_group(argc, argv);
|
||||
}
|
||||
|
||||
static int net_join(int argc, const char **argv)
|
||||
{
|
||||
if (net_ads_check() == 0) {
|
||||
if (net_ads_join(argc, argv) == 0)
|
||||
return 0;
|
||||
else
|
||||
d_printf("ADS join did not work, trying RPC...\n");
|
||||
}
|
||||
return net_rpc_join(argc, argv);
|
||||
}
|
||||
|
||||
static int net_share(int argc, const char **argv)
|
||||
{
|
||||
if (net_rpc_check(0))
|
||||
return net_rpc_share(argc, argv);
|
||||
return net_rap_share(argc, argv);
|
||||
}
|
||||
|
||||
static int net_file(int argc, const char **argv)
|
||||
{
|
||||
if (net_rpc_check(0))
|
||||
return net_rpc_file(argc, argv);
|
||||
return net_rap_file(argc, argv);
|
||||
}
|
||||
|
||||
/*
|
||||
Retrieve our local SID or the SID for the specified name
|
||||
*/
|
||||
static int net_getlocalsid(int argc, const char **argv)
|
||||
{
|
||||
DOM_SID sid;
|
||||
const char *name;
|
||||
fstring sid_str;
|
||||
|
||||
if (argc >= 1) {
|
||||
name = argv[0];
|
||||
}
|
||||
else {
|
||||
name = lp_netbios_name();
|
||||
}
|
||||
|
||||
if (!secrets_fetch_domain_sid(name, &sid)) {
|
||||
DEBUG(0, ("Can't fetch domain SID for name: %s\n", name));
|
||||
return 1;
|
||||
}
|
||||
sid_to_string(sid_str, &sid);
|
||||
d_printf("SID for domain %s is: %s\n", name, sid_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int net_setlocalsid(int argc, const char **argv)
|
||||
{
|
||||
DOM_SID sid;
|
||||
|
||||
if ( (argc != 1)
|
||||
|| (strncmp(argv[0], "S-1-5-21-", strlen("S-1-5-21-")) != 0)
|
||||
|| (!string_to_sid(&sid, argv[0]))
|
||||
|| (sid.num_auths != 4)) {
|
||||
d_printf("usage: net setlocalsid S-1-5-21-x-y-z\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!secrets_store_domain_sid(lp_netbios_name(), &sid)) {
|
||||
DEBUG(0,("Can't store domain SID as a pdc/bdc.\n"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int net_getdomainsid(int argc, const char **argv)
|
||||
{
|
||||
DOM_SID domain_sid;
|
||||
fstring sid_str;
|
||||
|
||||
if (!secrets_fetch_domain_sid(lp_netbios_name(), &domain_sid)) {
|
||||
d_printf("Could not fetch local SID\n");
|
||||
return 1;
|
||||
}
|
||||
sid_to_string(sid_str, &domain_sid);
|
||||
d_printf("SID for domain %s is: %s\n", lp_netbios_name(), sid_str);
|
||||
|
||||
if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) {
|
||||
d_printf("Could not fetch domain SID\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sid_to_string(sid_str, &domain_sid);
|
||||
d_printf("SID for domain %s is: %s\n", lp_workgroup(), sid_str);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32 get_maxrid(void)
|
||||
{
|
||||
SAM_ACCOUNT *pwd = NULL;
|
||||
uint32 max_rid = 0;
|
||||
GROUP_MAP *map = NULL;
|
||||
int num_entries = 0;
|
||||
int i;
|
||||
|
||||
if (!pdb_setsampwent(False)) {
|
||||
DEBUG(0, ("load_sampwd_entries: Unable to open passdb.\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (; (NT_STATUS_IS_OK(pdb_init_sam(&pwd)))
|
||||
&& pdb_getsampwent(pwd) == True; pwd=NULL) {
|
||||
uint32 rid;
|
||||
|
||||
if (!sid_peek_rid(pdb_get_user_sid(pwd), &rid)) {
|
||||
DEBUG(0, ("can't get RID for user '%s'\n",
|
||||
pdb_get_username(pwd)));
|
||||
pdb_free_sam(&pwd);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rid > max_rid)
|
||||
max_rid = rid;
|
||||
|
||||
DEBUG(1,("%d is user '%s'\n", rid, pdb_get_username(pwd)));
|
||||
pdb_free_sam(&pwd);
|
||||
}
|
||||
|
||||
pdb_endsampwent();
|
||||
pdb_free_sam(&pwd);
|
||||
|
||||
if (!pdb_enum_group_mapping(SID_NAME_UNKNOWN, &map, &num_entries,
|
||||
ENUM_ONLY_MAPPED, MAPPING_WITHOUT_PRIV))
|
||||
return max_rid;
|
||||
|
||||
for (i = 0; i < num_entries; i++) {
|
||||
uint32 rid;
|
||||
|
||||
if (!sid_peek_check_rid(get_global_sam_sid(), &map[i].sid,
|
||||
&rid)) {
|
||||
DEBUG(3, ("skipping map for group '%s', SID %s\n",
|
||||
map[i].nt_name,
|
||||
sid_string_static(&map[i].sid)));
|
||||
continue;
|
||||
}
|
||||
DEBUG(1,("%d is group '%s'\n", rid, map[i].nt_name));
|
||||
|
||||
if (rid > max_rid)
|
||||
max_rid = rid;
|
||||
}
|
||||
|
||||
SAFE_FREE(map);
|
||||
|
||||
return max_rid;
|
||||
}
|
||||
|
||||
static int net_maxrid(int argc, const char **argv)
|
||||
{
|
||||
uint32 rid;
|
||||
|
||||
if (argc != 0) {
|
||||
DEBUG(0, ("usage: net initrid\n"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((rid = get_maxrid()) == 0) {
|
||||
DEBUG(0, ("can't get current maximum rid\n"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
d_printf("Currently used maximum rid: %d\n", rid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* main function table */
|
||||
static struct functable net_func[] = {
|
||||
{"RPC", net_rpc},
|
||||
{"RAP", net_rap},
|
||||
{"ADS", net_ads},
|
||||
|
||||
/* eventually these should auto-choose the transport ... */
|
||||
{"FILE", net_file},
|
||||
{"SHARE", net_share},
|
||||
{"SESSION", net_rap_session},
|
||||
{"SERVER", net_rap_server},
|
||||
{"DOMAIN", net_rap_domain},
|
||||
{"PRINTQ", net_rap_printq},
|
||||
{"USER", net_user},
|
||||
{"GROUP", net_group},
|
||||
{"VALIDATE", net_rap_validate},
|
||||
{"GROUPMEMBER", net_rap_groupmember},
|
||||
{"ADMIN", net_rap_admin},
|
||||
{"SERVICE", net_rap_service},
|
||||
{"PASSWORD", net_rap_password},
|
||||
{"TIME", net_time},
|
||||
{"LOOKUP", net_lookup},
|
||||
{"JOIN", net_join},
|
||||
{"CACHE", net_cache},
|
||||
{"GETLOCALSID", net_getlocalsid},
|
||||
{"SETLOCALSID", net_setlocalsid},
|
||||
{"GETDOMAINSID", net_getdomainsid},
|
||||
{"MAXRID", net_maxrid},
|
||||
|
||||
{"HELP", net_help},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
main program
|
||||
****************************************************************************/
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
int opt,i;
|
||||
char *p;
|
||||
int rc = 0;
|
||||
int argc_new = 0;
|
||||
const char ** argv_new;
|
||||
poptContext pc;
|
||||
static char *servicesf = dyn_CONFIGFILE;
|
||||
static char *debuglevel = NULL;
|
||||
|
||||
struct poptOption long_options[] = {
|
||||
{"help", 'h', POPT_ARG_NONE, 0, 'h'},
|
||||
{"workgroup", 'w', POPT_ARG_STRING, &opt_target_workgroup},
|
||||
{"myworkgroup", 'W', POPT_ARG_STRING, &opt_workgroup},
|
||||
{"user", 'U', POPT_ARG_STRING, &opt_user_name, 'U'},
|
||||
{"ipaddress", 'I', POPT_ARG_STRING, 0,'I'},
|
||||
{"port", 'p', POPT_ARG_INT, &opt_port},
|
||||
{"myname", 'n', POPT_ARG_STRING, &opt_requester_name},
|
||||
{"conf", 's', POPT_ARG_STRING, &servicesf},
|
||||
{"server", 'S', POPT_ARG_STRING, &opt_host},
|
||||
{"container", 'c', POPT_ARG_STRING, &opt_container},
|
||||
{"comment", 'C', POPT_ARG_STRING, &opt_comment},
|
||||
{"maxusers", 'M', POPT_ARG_INT, &opt_maxusers},
|
||||
{"flags", 'F', POPT_ARG_INT, &opt_flags},
|
||||
{"jobid", 'j', POPT_ARG_INT, &opt_jobid},
|
||||
{"long", 'l', POPT_ARG_NONE, &opt_long_list_entries},
|
||||
{"reboot", 'r', POPT_ARG_NONE, &opt_reboot},
|
||||
{"force", 'f', POPT_ARG_NONE, &opt_force},
|
||||
{"timeout", 't', POPT_ARG_INT, &opt_timeout},
|
||||
{"machine-pass",'P', POPT_ARG_NONE, &opt_machine_pass},
|
||||
{"debuglevel", 'd', POPT_ARG_STRING, &debuglevel},
|
||||
{NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_version},
|
||||
{ 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
zero_ip(&opt_dest_ip);
|
||||
|
||||
dbf = x_stderr;
|
||||
|
||||
pc = poptGetContext(NULL, argc, (const char **) argv, long_options,
|
||||
POPT_CONTEXT_KEEP_FIRST);
|
||||
|
||||
while((opt = poptGetNextOpt(pc)) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
net_help(argc, argv);
|
||||
exit(0);
|
||||
break;
|
||||
case 'I':
|
||||
opt_dest_ip = *interpret_addr2(poptGetOptArg(pc));
|
||||
if (is_zero_ip(opt_dest_ip))
|
||||
d_printf("\nInvalid ip address specified\n");
|
||||
else
|
||||
opt_have_ip = True;
|
||||
break;
|
||||
case 'U':
|
||||
opt_user_specified = True;
|
||||
opt_user_name = strdup(opt_user_name);
|
||||
p = strchr(opt_user_name,'%');
|
||||
if (p) {
|
||||
*p = 0;
|
||||
opt_password = p+1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
d_printf("\nInvalid option %s: %s\n",
|
||||
poptBadOption(pc, 0), poptStrerror(opt));
|
||||
net_help(argc, argv);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (debuglevel) {
|
||||
debug_parse_levels(debuglevel);
|
||||
AllowDebugChange = False;
|
||||
}
|
||||
|
||||
lp_load(servicesf,True,False,False);
|
||||
|
||||
argv_new = (const char **)poptGetArgs(pc);
|
||||
|
||||
argc_new = argc;
|
||||
for (i=0; i<argc; i++) {
|
||||
if (argv_new[i] == NULL) {
|
||||
argc_new = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!opt_requester_name) {
|
||||
opt_requester_name = get_myname();
|
||||
}
|
||||
|
||||
if (!opt_user_name && getenv("LOGNAME")) {
|
||||
opt_user_name = getenv("LOGNAME");
|
||||
}
|
||||
|
||||
if (!opt_workgroup) {
|
||||
opt_workgroup = lp_workgroup();
|
||||
}
|
||||
|
||||
if (!opt_target_workgroup) {
|
||||
opt_target_workgroup = strdup(lp_workgroup());
|
||||
}
|
||||
|
||||
if (!init_names())
|
||||
exit(1);
|
||||
|
||||
load_interfaces();
|
||||
|
||||
if (opt_machine_pass) {
|
||||
char *user;
|
||||
/* it is very useful to be able to make ads queries as the
|
||||
machine account for testing purposes and for domain leave */
|
||||
|
||||
if (!secrets_init()) {
|
||||
d_printf("ERROR: Unable to open secrets database\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
asprintf(&user,"%s$", lp_netbios_name());
|
||||
opt_user_name = user;
|
||||
opt_password = secrets_fetch_machine_password();
|
||||
if (!opt_password) {
|
||||
d_printf("ERROR: Unable to fetch machine password\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
rc = net_run_function(argc_new-1, argv_new+1, net_func, net_help);
|
||||
|
||||
DEBUG(2,("return code = %d\n", rc));
|
||||
return rc;
|
||||
}
|
||||
61
source/utils/net.h
Normal file
61
source/utils/net.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
Samba Unix/Linux SMB client library
|
||||
Distributed SMB/CIFS Server Management Utility
|
||||
Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org)
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include "../utils/net_proto.h"
|
||||
|
||||
#define NET_FLAGS_MASTER 1
|
||||
#define NET_FLAGS_DMB 2
|
||||
|
||||
/* Would it be insane to set 'localhost' as the default
|
||||
remote host for this operation?
|
||||
|
||||
For example, localhost is insane for a 'join' operation.
|
||||
*/
|
||||
#define NET_FLAGS_LOCALHOST_DEFAULT_INSANE 4
|
||||
|
||||
/* We want to find the PDC only */
|
||||
#define NET_FLAGS_PDC 8
|
||||
|
||||
/* We want an anonymous connection */
|
||||
#define NET_FLAGS_ANONYMOUS 16
|
||||
|
||||
|
||||
extern int opt_maxusers;
|
||||
extern const char *opt_comment;
|
||||
extern char *opt_container;
|
||||
extern int opt_flags;
|
||||
|
||||
extern const char *opt_comment;
|
||||
|
||||
extern const char *opt_target_workgroup;
|
||||
extern const char *opt_workgroup;
|
||||
extern int opt_long_list_entries;
|
||||
extern int opt_reboot;
|
||||
extern int opt_force;
|
||||
extern int opt_timeout;
|
||||
extern const char *opt_host;
|
||||
extern const char *opt_user_name;
|
||||
extern const char *opt_password;
|
||||
extern BOOL opt_user_specified;
|
||||
|
||||
extern BOOL opt_have_ip;
|
||||
extern struct in_addr opt_dest_ip;
|
||||
|
||||
extern const char *share_type[];
|
||||
|
||||
1176
source/utils/net_ads.c
Normal file
1176
source/utils/net_ads.c
Normal file
File diff suppressed because it is too large
Load Diff
354
source/utils/net_ads_cldap.c
Normal file
354
source/utils/net_ads_cldap.c
Normal file
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
Samba Unix/Linux SMB client library
|
||||
net ads cldap functions
|
||||
Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
|
||||
Copyright (C) 2003 Jim McDonough (jmcd@us.ibm.com)
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "../utils/net.h"
|
||||
|
||||
#ifdef HAVE_ADS
|
||||
|
||||
struct netlogon_string {
|
||||
uint32 comp_len;
|
||||
char **component;
|
||||
uint8 extra_flag;
|
||||
};
|
||||
|
||||
struct cldap_netlogon_reply {
|
||||
uint32 type;
|
||||
uint32 flags;
|
||||
GUID guid;
|
||||
|
||||
struct netlogon_string forest;
|
||||
struct netlogon_string domain;
|
||||
struct netlogon_string hostname;
|
||||
|
||||
struct netlogon_string netbios_domain;
|
||||
struct netlogon_string netbios_hostname;
|
||||
|
||||
struct netlogon_string user_name;
|
||||
struct netlogon_string site_name;
|
||||
|
||||
struct netlogon_string unk0;
|
||||
|
||||
uint32 version;
|
||||
uint16 lmnt_token;
|
||||
uint16 lm20_token;
|
||||
};
|
||||
|
||||
/*
|
||||
These strings are rather interesting... They are composed of a series of
|
||||
length encoded strings, terminated by either 1) a zero length string or 2)
|
||||
a 0xc0 byte with what appears to be a one byte flags immediately following.
|
||||
*/
|
||||
static unsigned pull_netlogon_string(struct netlogon_string *ret,const char *d)
|
||||
{
|
||||
char *p = (char *)d;
|
||||
|
||||
ZERO_STRUCTP(ret);
|
||||
|
||||
do {
|
||||
unsigned len = (unsigned char)*p;
|
||||
p++;
|
||||
|
||||
if (len > 0 && len != 0xc0) {
|
||||
ret->component = realloc(ret->component,
|
||||
++ret->comp_len *
|
||||
sizeof(char *));
|
||||
|
||||
ret->component[ret->comp_len - 1] =
|
||||
smb_xstrndup(p, len);
|
||||
p += len;
|
||||
} else {
|
||||
if (len == 0xc0) {
|
||||
ret->extra_flag = *p;
|
||||
p++;
|
||||
};
|
||||
break;
|
||||
}
|
||||
} while (1);
|
||||
|
||||
return (p - d);
|
||||
}
|
||||
|
||||
/*
|
||||
do a cldap netlogon query
|
||||
*/
|
||||
static int send_cldap_netlogon(int sock, const char *domain,
|
||||
const char *hostname, unsigned ntversion)
|
||||
{
|
||||
ASN1_DATA data;
|
||||
char ntver[4];
|
||||
|
||||
SIVAL(ntver, 0, ntversion);
|
||||
|
||||
memset(&data, 0, sizeof(data));
|
||||
|
||||
asn1_push_tag(&data,ASN1_SEQUENCE(0));
|
||||
asn1_write_Integer(&data, 4);
|
||||
asn1_push_tag(&data, ASN1_APPLICATION(3));
|
||||
asn1_write_OctetString(&data, NULL, 0);
|
||||
asn1_write_enumerated(&data, 0);
|
||||
asn1_write_enumerated(&data, 0);
|
||||
asn1_write_Integer(&data, 0);
|
||||
asn1_write_Integer(&data, 0);
|
||||
asn1_write_BOOLEAN2(&data, False);
|
||||
asn1_push_tag(&data, ASN1_CONTEXT(0));
|
||||
|
||||
asn1_push_tag(&data, ASN1_CONTEXT(3));
|
||||
asn1_write_OctetString(&data, "DnsDomain", 9);
|
||||
asn1_write_OctetString(&data, domain, strlen(domain));
|
||||
asn1_pop_tag(&data);
|
||||
|
||||
asn1_push_tag(&data, ASN1_CONTEXT(3));
|
||||
asn1_write_OctetString(&data, "Host", 4);
|
||||
asn1_write_OctetString(&data, hostname, strlen(hostname));
|
||||
asn1_pop_tag(&data);
|
||||
|
||||
asn1_push_tag(&data, ASN1_CONTEXT(3));
|
||||
asn1_write_OctetString(&data, "NtVer", 5);
|
||||
asn1_write_OctetString(&data, ntver, 4);
|
||||
asn1_pop_tag(&data);
|
||||
|
||||
asn1_pop_tag(&data);
|
||||
|
||||
asn1_push_tag(&data,ASN1_SEQUENCE(0));
|
||||
asn1_write_OctetString(&data, "NetLogon", 8);
|
||||
asn1_pop_tag(&data);
|
||||
asn1_pop_tag(&data);
|
||||
asn1_pop_tag(&data);
|
||||
|
||||
if (data.has_error) {
|
||||
d_printf("Failed to build cldap netlogon at offset %d\n", (int)data.ofs);
|
||||
asn1_free(&data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (write(sock, data.data, data.length) != data.length) {
|
||||
d_printf("failed to send cldap query (%s)\n", strerror(errno));
|
||||
}
|
||||
|
||||
file_save("cldap_query.dat", data.data, data.length);
|
||||
asn1_free(&data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
receive a cldap netlogon reply
|
||||
*/
|
||||
static int recv_cldap_netlogon(int sock, struct cldap_netlogon_reply *reply)
|
||||
{
|
||||
int ret;
|
||||
ASN1_DATA data;
|
||||
DATA_BLOB blob;
|
||||
DATA_BLOB os1, os2, os3;
|
||||
uint32 i1;
|
||||
char *p;
|
||||
|
||||
blob = data_blob(NULL, 8192);
|
||||
|
||||
ret = read(sock, blob.data, blob.length);
|
||||
|
||||
if (ret <= 0) {
|
||||
d_printf("no reply received to cldap netlogon\n");
|
||||
return -1;
|
||||
}
|
||||
blob.length = ret;
|
||||
|
||||
file_save("cldap_reply.dat", blob.data, blob.length);
|
||||
|
||||
asn1_load(&data, blob);
|
||||
asn1_start_tag(&data, ASN1_SEQUENCE(0));
|
||||
asn1_read_Integer(&data, &i1);
|
||||
asn1_start_tag(&data, ASN1_APPLICATION(4));
|
||||
asn1_read_OctetString(&data, &os1);
|
||||
asn1_start_tag(&data, ASN1_SEQUENCE(0));
|
||||
asn1_start_tag(&data, ASN1_SEQUENCE(0));
|
||||
asn1_read_OctetString(&data, &os2);
|
||||
asn1_start_tag(&data, ASN1_SET);
|
||||
asn1_read_OctetString(&data, &os3);
|
||||
asn1_end_tag(&data);
|
||||
asn1_end_tag(&data);
|
||||
asn1_end_tag(&data);
|
||||
asn1_end_tag(&data);
|
||||
asn1_end_tag(&data);
|
||||
|
||||
if (data.has_error) {
|
||||
d_printf("Failed to parse cldap reply\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
file_save("cldap_reply_core.dat", os3.data, os3.length);
|
||||
|
||||
p = os3.data;
|
||||
|
||||
reply->type = IVAL(p, 0); p += 4;
|
||||
reply->flags = IVAL(p, 0); p += 4;
|
||||
|
||||
memcpy(&reply->guid.info, p, GUID_SIZE);
|
||||
p += GUID_SIZE;
|
||||
|
||||
p += pull_netlogon_string(&reply->forest, p);
|
||||
p += pull_netlogon_string(&reply->domain, p);
|
||||
p += pull_netlogon_string(&reply->hostname, p);
|
||||
p += pull_netlogon_string(&reply->netbios_domain, p);
|
||||
p += pull_netlogon_string(&reply->netbios_hostname, p);
|
||||
p += pull_netlogon_string(&reply->user_name, p);
|
||||
p += pull_netlogon_string(&reply->site_name, p);
|
||||
|
||||
p += pull_netlogon_string(&reply->unk0, p);
|
||||
|
||||
reply->version = IVAL(p, 0);
|
||||
reply->lmnt_token = SVAL(p, 4);
|
||||
reply->lm20_token = SVAL(p, 6);
|
||||
|
||||
data_blob_free(&os1);
|
||||
data_blob_free(&os2);
|
||||
data_blob_free(&os3);
|
||||
data_blob_free(&blob);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
free a netlogon string
|
||||
*/
|
||||
static void netlogon_string_free(struct netlogon_string *str)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < str->comp_len; ++i) {
|
||||
SAFE_FREE(str->component[i]);
|
||||
}
|
||||
SAFE_FREE(str->component);
|
||||
}
|
||||
|
||||
/*
|
||||
free a cldap reply packet
|
||||
*/
|
||||
static void cldap_reply_free(struct cldap_netlogon_reply *reply)
|
||||
{
|
||||
netlogon_string_free(&reply->forest);
|
||||
netlogon_string_free(&reply->domain);
|
||||
netlogon_string_free(&reply->hostname);
|
||||
netlogon_string_free(&reply->netbios_domain);
|
||||
netlogon_string_free(&reply->netbios_hostname);
|
||||
netlogon_string_free(&reply->user_name);
|
||||
netlogon_string_free(&reply->site_name);
|
||||
netlogon_string_free(&reply->unk0);
|
||||
}
|
||||
|
||||
static void d_print_netlogon_string(const char *label,
|
||||
struct netlogon_string *str)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (str->comp_len) {
|
||||
d_printf("%s", label);
|
||||
if (str->extra_flag) {
|
||||
d_printf("[%d]", str->extra_flag);
|
||||
}
|
||||
d_printf(": ");
|
||||
for (i = 0; i < str->comp_len; ++i) {
|
||||
d_printf("%s%s", (i ? "." : ""), str->component[i]);
|
||||
}
|
||||
d_printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
do a cldap netlogon query
|
||||
*/
|
||||
int ads_cldap_netlogon(ADS_STRUCT *ads)
|
||||
{
|
||||
int sock;
|
||||
int ret;
|
||||
struct cldap_netlogon_reply reply;
|
||||
|
||||
sock = open_udp_socket(inet_ntoa(ads->ldap_ip), ads->ldap_port);
|
||||
if (sock == -1) {
|
||||
d_printf("Failed to open udp socket to %s:%u\n",
|
||||
inet_ntoa(ads->ldap_ip),
|
||||
ads->ldap_port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = send_cldap_netlogon(sock, ads->config.realm, lp_netbios_name(), 6);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = recv_cldap_netlogon(sock, &reply);
|
||||
close(sock);
|
||||
|
||||
if (ret == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
d_printf("Information for Domain Controller: %s\n\n",
|
||||
ads->config.ldap_server_name);
|
||||
|
||||
d_printf("Response Type: 0x%x\n", reply.type);
|
||||
d_printf("GUID: ");
|
||||
print_guid(&reply.guid);
|
||||
d_printf("Flags:\n"
|
||||
"\tIs a PDC: %s\n"
|
||||
"\tIs a GC of the forest: %s\n"
|
||||
"\tIs an LDAP server: %s\n"
|
||||
"\tSupports DS: %s\n"
|
||||
"\tIs running a KDC: %s\n"
|
||||
"\tIs running time services: %s\n"
|
||||
"\tIs the closest DC: %s\n"
|
||||
"\tIs writable: %s\n"
|
||||
"\tHas a hardware clock: %s\n"
|
||||
"\tIs a non-domain NC serviced by LDAP server: %s\n",
|
||||
(reply.flags & ADS_PDC) ? "yes" : "no",
|
||||
(reply.flags & ADS_GC) ? "yes" : "no",
|
||||
(reply.flags & ADS_LDAP) ? "yes" : "no",
|
||||
(reply.flags & ADS_DS) ? "yes" : "no",
|
||||
(reply.flags & ADS_KDC) ? "yes" : "no",
|
||||
(reply.flags & ADS_TIMESERV) ? "yes" : "no",
|
||||
(reply.flags & ADS_CLOSEST) ? "yes" : "no",
|
||||
(reply.flags & ADS_WRITABLE) ? "yes" : "no",
|
||||
(reply.flags & ADS_GOOD_TIMESERV) ? "yes" : "no",
|
||||
(reply.flags & ADS_NDNC) ? "yes" : "no");
|
||||
|
||||
d_print_netlogon_string("Forest", &reply.forest);
|
||||
d_print_netlogon_string("Domain", &reply.domain);
|
||||
d_print_netlogon_string("Hostname", &reply.hostname);
|
||||
|
||||
d_print_netlogon_string("Pre-Win2k Domain", &reply.netbios_domain);
|
||||
d_print_netlogon_string("Pre-Win2k Hostname", &reply.netbios_hostname);
|
||||
|
||||
d_print_netlogon_string("User name", &reply.user_name);
|
||||
d_print_netlogon_string("Site Name", &reply.site_name);
|
||||
d_print_netlogon_string("Unknown Field", &reply.unk0);
|
||||
|
||||
d_printf("NT Version: %d\n", reply.version);
|
||||
d_printf("LMNT Token: %.2x\n", reply.lmnt_token);
|
||||
d_printf("LM20 Token: %.2x\n", reply.lm20_token);
|
||||
|
||||
cldap_reply_free(&reply);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
348
source/utils/net_cache.c
Normal file
348
source/utils/net_cache.c
Normal file
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
Samba Unix/Linux SMB client library
|
||||
Distributed SMB/CIFS Server Management Utility
|
||||
Copyright (C) Rafal Szczesniak 2002
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
|
||||
#include "includes.h"
|
||||
#include "net.h"
|
||||
|
||||
/**
|
||||
* @file net_cache.c
|
||||
* @brief This is part of the net tool which is basically command
|
||||
* line wrapper for gencache.c functions (mainly for testing)
|
||||
*
|
||||
**/
|
||||
|
||||
|
||||
/*
|
||||
* These routines are used via gencache_iterate() to display the cache's contents
|
||||
* (print_cache_entry) and to flush it (delete_cache_entry).
|
||||
* Both of them are defined by first arg of gencache_iterate() routine.
|
||||
*/
|
||||
static void print_cache_entry(const char* keystr, const char* datastr,
|
||||
const time_t timeout, void* dptr)
|
||||
{
|
||||
char* timeout_str;
|
||||
time_t now_t = time(NULL);
|
||||
struct tm timeout_tm, *now_tm;
|
||||
/* localtime returns statically allocated pointer, so timeout_tm
|
||||
has to be copied somewhere else */
|
||||
memcpy(&timeout_tm, localtime(&timeout), sizeof(struct tm));
|
||||
now_tm = localtime(&now_t);
|
||||
|
||||
/* form up timeout string depending whether it's today's date or not */
|
||||
if (timeout_tm.tm_year != now_tm->tm_year ||
|
||||
timeout_tm.tm_mon != now_tm->tm_mon ||
|
||||
timeout_tm.tm_mday != now_tm->tm_mday) {
|
||||
|
||||
timeout_str = asctime(&timeout_tm);
|
||||
timeout_str[strlen(timeout_str) - 1] = '\0'; /* remove tailing CR */
|
||||
} else
|
||||
asprintf(&timeout_str, "%.2d:%.2d:%.2d", timeout_tm.tm_hour,
|
||||
timeout_tm.tm_min, timeout_tm.tm_sec);
|
||||
|
||||
d_printf("Key: %s\t Timeout: %s\t Value: %s %s\n", keystr,
|
||||
timeout_str, datastr, timeout > now_t ? "": "(expired)");
|
||||
}
|
||||
|
||||
static void delete_cache_entry(const char* keystr, const char* datastr,
|
||||
const time_t timeout, void* dptr)
|
||||
{
|
||||
if (!gencache_del(keystr))
|
||||
d_printf("Couldn't delete entry! key = %s", keystr);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse text representation of timeout value
|
||||
*
|
||||
* @param timeout_str string containing text representation of the timeout
|
||||
* @return numeric timeout of time_t type
|
||||
**/
|
||||
static time_t parse_timeout(const char* timeout_str)
|
||||
{
|
||||
char sign = '\0', *number = NULL, unit = '\0';
|
||||
int len, number_begin, number_end;
|
||||
time_t timeout;
|
||||
|
||||
/* sign detection */
|
||||
if (timeout_str[0] == '!' || timeout_str[0] == '+') {
|
||||
sign = timeout_str[0];
|
||||
number_begin = 1;
|
||||
} else {
|
||||
number_begin = 0;
|
||||
}
|
||||
|
||||
/* unit detection */
|
||||
len = strlen(timeout_str);
|
||||
switch (timeout_str[len - 1]) {
|
||||
case 's':
|
||||
case 'm':
|
||||
case 'h':
|
||||
case 'd':
|
||||
case 'w': unit = timeout_str[len - 1];
|
||||
}
|
||||
|
||||
/* number detection */
|
||||
len = (sign) ? strlen(&timeout_str[number_begin]) : len;
|
||||
number_end = (unit) ? len - 1 : len;
|
||||
number = strndup(&timeout_str[number_begin], number_end);
|
||||
|
||||
/* calculate actual timeout value */
|
||||
timeout = (time_t)atoi(number);
|
||||
|
||||
switch (unit) {
|
||||
case 'm': timeout *= 60; break;
|
||||
case 'h': timeout *= 60*60; break;
|
||||
case 'd': timeout *= 60*60*24; break;
|
||||
case 'w': timeout *= 60*60*24*7; break; /* that's fair enough, I think :) */
|
||||
}
|
||||
|
||||
switch (sign) {
|
||||
case '!': timeout = time(NULL) - timeout; break;
|
||||
case '+':
|
||||
default: timeout += time(NULL); break;
|
||||
}
|
||||
|
||||
if (number) SAFE_FREE(number);
|
||||
return timeout;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add an entry to the cache. If it does exist, then set it.
|
||||
*
|
||||
* @param argv key, value and timeout are passed in command line
|
||||
* @return 0 on success, otherwise failure
|
||||
**/
|
||||
static int net_cache_add(int argc, const char **argv)
|
||||
{
|
||||
const char *keystr, *datastr, *timeout_str;
|
||||
time_t timeout;
|
||||
|
||||
if (argc < 3) {
|
||||
d_printf("\nUsage: net cache add <key string> <data string> <timeout>\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
keystr = argv[0];
|
||||
datastr = argv[1];
|
||||
timeout_str = argv[2];
|
||||
|
||||
/* parse timeout given in command line */
|
||||
timeout = parse_timeout(timeout_str);
|
||||
if (!timeout) {
|
||||
d_printf("Invalid timeout argument.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (gencache_set(keystr, datastr, timeout)) {
|
||||
d_printf("New cache entry stored successfully.\n");
|
||||
gencache_shutdown();
|
||||
return 0;
|
||||
}
|
||||
|
||||
d_printf("Entry couldn't be added. Perhaps there's already such a key.\n");
|
||||
gencache_shutdown();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set new value of an existing entry in the cache. Fail If the entry doesn't
|
||||
* exist.
|
||||
*
|
||||
* @param argv key being searched and new value and timeout to set in the entry
|
||||
* @return 0 on success, otherwise failure
|
||||
**/
|
||||
static int net_cache_set(int argc, const char **argv)
|
||||
{
|
||||
const char *keystr, *datastr, *timeout_str;
|
||||
time_t timeout;
|
||||
|
||||
if (argc < 3) {
|
||||
d_printf("\nUsage: net cache set <key string> <data string> <timeout>\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
keystr = argv[0];
|
||||
datastr = argv[1];
|
||||
timeout_str = argv[2];
|
||||
|
||||
/* parse timeout given in command line */
|
||||
timeout = parse_timeout(timeout_str);
|
||||
if (!timeout) {
|
||||
d_printf("Invalid timeout argument.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (gencache_set_only(keystr, datastr, timeout)) {
|
||||
d_printf("Cache entry set successfully.\n");
|
||||
gencache_shutdown();
|
||||
return 0;
|
||||
}
|
||||
|
||||
d_printf("Entry couldn't be set. Perhaps there's no such a key.\n");
|
||||
gencache_shutdown();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete an entry in the cache
|
||||
*
|
||||
* @param argv key to delete an entry of
|
||||
* @return 0 on success, otherwise failure
|
||||
**/
|
||||
static int net_cache_del(int argc, const char **argv)
|
||||
{
|
||||
const char *keystr = argv[0];
|
||||
|
||||
if (argc < 1) {
|
||||
d_printf("\nUsage: net cache add <key string>\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(gencache_del(keystr)) {
|
||||
d_printf("Entry deleted.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
d_printf("Couldn't delete specified entry\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get and display an entry from the cache
|
||||
*
|
||||
* @param argv key to search an entry of
|
||||
* @return 0 on success, otherwise failure
|
||||
**/
|
||||
static int net_cache_get(int argc, const char **argv)
|
||||
{
|
||||
const char* keystr = argv[0];
|
||||
char* valuestr;
|
||||
time_t timeout;
|
||||
|
||||
if (argc < 1) {
|
||||
d_printf("\nUsage: net cache get <key>\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (gencache_get(keystr, &valuestr, &timeout)) {
|
||||
print_cache_entry(keystr, valuestr, timeout, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
d_printf("Failed to find entry\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Search an entry/entries in the cache
|
||||
*
|
||||
* @param argv key pattern to match the entries to
|
||||
* @return 0 on success, otherwise failure
|
||||
**/
|
||||
static int net_cache_search(int argc, const char **argv)
|
||||
{
|
||||
const char* pattern;
|
||||
|
||||
if (argc < 1) {
|
||||
d_printf("Usage: net cache search <pattern>\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pattern = argv[0];
|
||||
gencache_iterate(print_cache_entry, NULL, pattern);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* List the contents of the cache
|
||||
*
|
||||
* @param argv ignored in this functionailty
|
||||
* @return always returns 0
|
||||
**/
|
||||
static int net_cache_list(int argc, const char **argv)
|
||||
{
|
||||
const char* pattern = "*";
|
||||
gencache_iterate(print_cache_entry, NULL, pattern);
|
||||
gencache_shutdown();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Flush the whole cache
|
||||
*
|
||||
* @param argv ignored in this functionality
|
||||
* @return always returns 0
|
||||
**/
|
||||
static int net_cache_flush(int argc, const char **argv)
|
||||
{
|
||||
const char* pattern = "*";
|
||||
gencache_iterate(delete_cache_entry, NULL, pattern);
|
||||
gencache_shutdown();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Short help
|
||||
*
|
||||
* @param argv ignored in this functionality
|
||||
* @return always returns -1
|
||||
**/
|
||||
static int net_cache_usage(int argc, const char **argv)
|
||||
{
|
||||
d_printf(" net cache add \t add add new cache entry\n");
|
||||
d_printf(" net cache set \t set new value for existing cache entry\n");
|
||||
d_printf(" net cache del \t delete existing cache entry by key\n");
|
||||
d_printf(" net cache flush \t delete all entries existing in the cache\n");
|
||||
d_printf(" net cache get \t get cache entry by key\n");
|
||||
d_printf(" net cache search \t search for entries in the cache, by given pattern\n");
|
||||
d_printf(" net cache list \t list all cache entries (just like search for \"*\")\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Entry point to 'net cache' subfunctionality
|
||||
*
|
||||
* @param argv arguments passed to further called functions
|
||||
* @return whatever further functions return
|
||||
**/
|
||||
int net_cache(int argc, const char **argv)
|
||||
{
|
||||
struct functable func[] = {
|
||||
{"add", net_cache_add},
|
||||
{"set", net_cache_set},
|
||||
{"del", net_cache_del},
|
||||
{"get", net_cache_get},
|
||||
{"search", net_cache_search},
|
||||
{"list", net_cache_list},
|
||||
{"flush", net_cache_flush},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
return net_run_function(argc, argv, func, net_cache_usage);
|
||||
}
|
||||
199
source/utils/net_help.c
Normal file
199
source/utils/net_help.c
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
Samba Unix/Linux SMB client library
|
||||
net help commands
|
||||
Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "../utils/net.h"
|
||||
|
||||
int net_common_methods_usage(int argc, const char**argv)
|
||||
{
|
||||
d_printf("Valid methods: (auto-detected if not specified)\n");
|
||||
d_printf("\tads\t\t\t\tActive Directory (LDAP/Kerberos)\n");
|
||||
d_printf("\trpc\t\t\t\tDCE-RPC\n");
|
||||
d_printf("\trap\t\t\t\tRAP (older systems)\n");
|
||||
d_printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int net_common_flags_usage(int argc, const char **argv)
|
||||
{
|
||||
d_printf("Valid targets: choose one (none defaults to localhost)\n");
|
||||
d_printf("\t-S or --server=<server>\t\tserver name\n");
|
||||
d_printf("\t-I or --ipaddress=<ipaddr>\taddress of target server\n");
|
||||
d_printf("\t-w or --workgroup=<wg>\t\ttarget workgroup or domain\n");
|
||||
|
||||
d_printf("\n");
|
||||
d_printf("Valid miscellaneous options are:\n"); /* misc options */
|
||||
d_printf("\t-p or --port=<port>\t\tconnection port on target\n");
|
||||
d_printf("\t-W or --myworkgroup=<wg>\tclient workgroup\n");
|
||||
d_printf("\t-d or --debug=<level>\t\tdebug level (0-10)\n");
|
||||
d_printf("\t-n or --myname=<name>\t\tclient name\n");
|
||||
d_printf("\t-U or --user=<name>\t\tuser name\n");
|
||||
d_printf("\t-s or --conf=<path>\t\tpathname of smb.conf file\n");
|
||||
d_printf("\t-l or --long\t\t\tDisplay full information\n");
|
||||
d_printf("\t-P or --machine-pass\t\tAuthenticate as machine account\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int help_usage(int argc, const char **argv)
|
||||
{
|
||||
d_printf(
|
||||
"\n"\
|
||||
"Usage: net help <function>\n"\
|
||||
"\n"\
|
||||
"Valid functions are:\n"\
|
||||
" RPC RAP ADS FILE SHARE SESSION SERVER DOMAIN PRINTQ USER GROUP VALIDATE\n"\
|
||||
" GROUPMEMBER ADMIN SERVICE PASSWORD TIME LOOKUP GETLOCALSID SETLOCALSID\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int net_help_user(int argc, const char **argv)
|
||||
{
|
||||
d_printf("\nnet [<method>] user [misc. options] [targets]"\
|
||||
"\n\tList users\n\n");
|
||||
d_printf("net [<method>] user DELETE <name> [misc. options] [targets]"\
|
||||
"\n\tDelete specified user\n");
|
||||
d_printf("\nnet [<method>] user INFO <name> [misc. options] [targets]"\
|
||||
"\n\tList the domain groups of the specified user\n");
|
||||
d_printf("\nnet [<method>] user ADD <name> [password] [-c container] "\
|
||||
"[-F user flags] [misc. options]"\
|
||||
" [targets]\n\tAdd specified user\n");
|
||||
|
||||
net_common_methods_usage(argc, argv);
|
||||
net_common_flags_usage(argc, argv);
|
||||
d_printf("\t-C or --comment=<comment>\tdescriptive comment (for add only)\n");
|
||||
d_printf("\t-c or --container=<container>\tLDAP container, defaults to cn=Users (for add in ADS only)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int net_help_group(int argc, const char **argv)
|
||||
{
|
||||
d_printf("net [<method>] group [misc. options] [targets]"\
|
||||
"\n\tList user groups\n\n");
|
||||
d_printf("net [<method>] group DELETE <name> "\
|
||||
"[misc. options] [targets]"\
|
||||
"\n\tDelete specified group\n");
|
||||
d_printf("\nnet [<method>] group ADD <name> [-C comment] [-c container]"\
|
||||
" [misc. options] [targets]\n\tCreate specified group\n");
|
||||
net_common_methods_usage(argc, argv);
|
||||
net_common_flags_usage(argc, argv);
|
||||
d_printf("\t-C or --comment=<comment>\tdescriptive comment (for add only)\n");
|
||||
d_printf("\t-c or --container=<container>\tLDAP container, defaults to cn=Users (for add in ADS only)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int net_help_join(int argc, const char **argv)
|
||||
{
|
||||
d_printf("\nnet [<method>] join [misc. options]\n"
|
||||
"\tjoins this server to a domain\n");
|
||||
d_printf("Valid methods: (auto-detected if not specified)\n");
|
||||
d_printf("\tads\t\t\t\tActive Directory (LDAP/Kerberos)\n");
|
||||
d_printf("\trpc\t\t\t\tDCE-RPC\n");
|
||||
net_common_flags_usage(argc, argv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int net_help_share(int argc, const char **argv)
|
||||
{
|
||||
d_printf(
|
||||
"\nnet [<method>] share [misc. options] [targets] \n"
|
||||
"\tenumerates all exported resources (network shares) "
|
||||
"on target server\n\n"
|
||||
"net [<method>] share ADD <name=serverpath> [misc. options] [targets]"
|
||||
"\n\tAdds a share from a server (makes the export active)\n\n"
|
||||
"net [<method>] share DELETE <sharename> [misc. options] [targets]\n"
|
||||
"\n\tDeletes a share from a server (makes the export inactive)\n");
|
||||
net_common_methods_usage(argc, argv);
|
||||
net_common_flags_usage(argc, argv);
|
||||
d_printf(
|
||||
"\t-C or --comment=<comment>\tdescriptive comment (for add only)\n"
|
||||
"\t-M or --maxusers=<num>\t\tmax users allowed for share\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int net_help_file(int argc, const char **argv)
|
||||
{
|
||||
d_printf("net [<method>] file [misc. options] [targets]\n"\
|
||||
"\tlists all open files on file server\n\n");
|
||||
d_printf("net [<method>] file USER <username> "\
|
||||
"[misc. options] [targets]"\
|
||||
"\n\tlists all files opened by username on file server\n\n");
|
||||
d_printf("net [<method>] file CLOSE <id> [misc. options] [targets]\n"\
|
||||
"\tcloses specified file on target server\n\n");
|
||||
d_printf("net [rap] file INFO <id> [misc. options] [targets]\n"\
|
||||
"\tdisplays information about the specified open file\n");
|
||||
|
||||
net_common_methods_usage(argc, argv);
|
||||
net_common_flags_usage(argc, argv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int net_usage(int argc, const char **argv)
|
||||
{
|
||||
d_printf(" net time\t\tto view or set time information\n"\
|
||||
" net lookup\t\tto lookup host name or ip address\n"\
|
||||
" net user\t\tto manage users\n"\
|
||||
" net group\t\tto manage groups\n"\
|
||||
" net join\t\tto join a domain\n"\
|
||||
" net cache\t\tto operate on cache tdb file\n"\
|
||||
" net getlocalsid [NAME]\tto get the SID for local name\n"\
|
||||
" net setlocalsid SID\tto set the local domain SID\n"\
|
||||
"\n"\
|
||||
" net ads <command>\tto run ADS commands\n"\
|
||||
" net rap <command>\tto run RAP (pre-RPC) commands\n"\
|
||||
" net rpc <command>\tto run RPC commands\n"\
|
||||
"\n"\
|
||||
"Type \"net help <option>\" to get more information on that option\n");
|
||||
net_common_flags_usage(argc, argv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
handle "net help *" subcommands
|
||||
*/
|
||||
int net_help(int argc, const char **argv)
|
||||
{
|
||||
struct functable func[] = {
|
||||
{"ADS", net_ads_help},
|
||||
{"RAP", net_rap_help},
|
||||
{"RPC", net_rpc_help},
|
||||
|
||||
{"FILE", net_help_file},
|
||||
{"SHARE", net_help_share},
|
||||
{"SESSION", net_rap_session_usage},
|
||||
{"SERVER", net_rap_server_usage},
|
||||
{"DOMAIN", net_rap_domain_usage},
|
||||
{"PRINTQ", net_rap_printq_usage},
|
||||
{"USER", net_help_user},
|
||||
{"GROUP", net_help_group},
|
||||
{"JOIN", net_help_join},
|
||||
{"VALIDATE", net_rap_validate_usage},
|
||||
{"GROUPMEMBER", net_rap_groupmember_usage},
|
||||
{"ADMIN", net_rap_admin_usage},
|
||||
{"SERVICE", net_rap_service_usage},
|
||||
{"PASSWORD", net_rap_password_usage},
|
||||
{"TIME", net_time_usage},
|
||||
{"LOOKUP", net_lookup_usage},
|
||||
|
||||
{"HELP", help_usage},
|
||||
{NULL, NULL}};
|
||||
|
||||
return net_run_function(argc, argv, func, net_usage);
|
||||
}
|
||||
234
source/utils/net_lookup.c
Normal file
234
source/utils/net_lookup.c
Normal file
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
Samba Unix/Linux SMB client library
|
||||
net lookup command
|
||||
Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "../utils/net.h"
|
||||
|
||||
int net_lookup_usage(int argc, const char **argv)
|
||||
{
|
||||
d_printf(
|
||||
" net lookup host HOSTNAME <type>\n\tgives IP for a hostname\n\n"
|
||||
" net lookup ldap [domain]\n\tgives IP of domain's ldap server\n\n"
|
||||
" net lookup kdc [realm]\n\tgives IP of realm's kerberos KDC\n\n"
|
||||
" net lookup dc [domain]\n\tgives IP of domains Domain Controllers\n\n"
|
||||
" net lookup master [domain|wg]\n\tgive IP of master browser\n\n"
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* lookup a hostname giving an IP */
|
||||
static int net_lookup_host(int argc, const char **argv)
|
||||
{
|
||||
struct in_addr ip;
|
||||
int name_type = 0x20;
|
||||
|
||||
if (argc == 0) return net_lookup_usage(argc, argv);
|
||||
if (argc > 1) name_type = strtol(argv[1], NULL, 0);
|
||||
|
||||
if (!resolve_name(argv[0], &ip, name_type)) {
|
||||
/* we deliberately use DEBUG() here to send it to stderr
|
||||
so scripts aren't mucked up */
|
||||
DEBUG(0,("Didn't find %s#%02x\n", argv[0], name_type));
|
||||
return -1;
|
||||
}
|
||||
|
||||
d_printf("%s\n", inet_ntoa(ip));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_ldap_srvlist(char *srvlist)
|
||||
{
|
||||
char *cur, *next;
|
||||
struct in_addr ip;
|
||||
BOOL printit;
|
||||
|
||||
cur = srvlist;
|
||||
do {
|
||||
next = strchr(cur,':');
|
||||
if (next) *next++='\0';
|
||||
printit = resolve_name(cur, &ip, 0x20);
|
||||
cur=next;
|
||||
next=cur ? strchr(cur,' ') :NULL;
|
||||
if (next)
|
||||
*next++='\0';
|
||||
if (printit)
|
||||
d_printf("%s:%s\n", inet_ntoa(ip), cur?cur:"");
|
||||
cur = next;
|
||||
} while (next);
|
||||
}
|
||||
|
||||
|
||||
static int net_lookup_ldap(int argc, const char **argv)
|
||||
{
|
||||
#ifdef HAVE_LDAP
|
||||
char *srvlist;
|
||||
const char *domain;
|
||||
int rc;
|
||||
struct in_addr addr;
|
||||
struct hostent *hostent;
|
||||
|
||||
if (argc > 0)
|
||||
domain = argv[0];
|
||||
else
|
||||
domain = opt_target_workgroup;
|
||||
|
||||
DEBUG(9, ("Lookup up ldap for domain %s\n", domain));
|
||||
rc = ldap_domain2hostlist(domain, &srvlist);
|
||||
if ((rc == LDAP_SUCCESS) && srvlist) {
|
||||
print_ldap_srvlist(srvlist);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG(9, ("Looking up DC for domain %s\n", domain));
|
||||
if (!get_pdc_ip(domain, &addr))
|
||||
return -1;
|
||||
|
||||
hostent = gethostbyaddr((char *) &addr.s_addr, sizeof(addr.s_addr),
|
||||
AF_INET);
|
||||
if (!hostent)
|
||||
return -1;
|
||||
|
||||
DEBUG(9, ("Found DC with DNS name %s\n", hostent->h_name));
|
||||
domain = strchr(hostent->h_name, '.');
|
||||
if (!domain)
|
||||
return -1;
|
||||
domain++;
|
||||
|
||||
DEBUG(9, ("Looking up ldap for domain %s\n", domain));
|
||||
rc = ldap_domain2hostlist(domain, &srvlist);
|
||||
if ((rc == LDAP_SUCCESS) && srvlist) {
|
||||
print_ldap_srvlist(srvlist);
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
#endif
|
||||
DEBUG(1,("No LDAP support\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int net_lookup_dc(int argc, const char **argv)
|
||||
{
|
||||
struct in_addr *ip_list, addr;
|
||||
char *pdc_str = NULL;
|
||||
const char *domain=opt_target_workgroup;
|
||||
int count, i;
|
||||
BOOL list_ordered;
|
||||
|
||||
if (argc > 0)
|
||||
domain=argv[0];
|
||||
|
||||
/* first get PDC */
|
||||
if (!get_pdc_ip(domain, &addr))
|
||||
return -1;
|
||||
|
||||
asprintf(&pdc_str, "%s", inet_ntoa(addr));
|
||||
d_printf("%s\n", pdc_str);
|
||||
|
||||
if (!get_dc_list(domain, &ip_list, &count, &list_ordered)) {
|
||||
SAFE_FREE(pdc_str);
|
||||
return 0;
|
||||
}
|
||||
for (i=0;i<count;i++) {
|
||||
char *dc_str = inet_ntoa(ip_list[i]);
|
||||
if (!strequal(pdc_str, dc_str))
|
||||
d_printf("%s\n", dc_str);
|
||||
}
|
||||
SAFE_FREE(pdc_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int net_lookup_master(int argc, const char **argv)
|
||||
{
|
||||
struct in_addr master_ip;
|
||||
const char *domain=opt_target_workgroup;
|
||||
|
||||
if (argc > 0)
|
||||
domain=argv[0];
|
||||
|
||||
if (!find_master_ip(domain, &master_ip))
|
||||
return -1;
|
||||
d_printf("%s\n", inet_ntoa(master_ip));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int net_lookup_kdc(int argc, const char **argv)
|
||||
{
|
||||
#ifdef HAVE_KRB5
|
||||
krb5_error_code rc;
|
||||
krb5_context ctx;
|
||||
struct sockaddr_in *addrs;
|
||||
int num_kdcs,i;
|
||||
krb5_data realm;
|
||||
char **realms;
|
||||
|
||||
rc = krb5_init_context(&ctx);
|
||||
if (rc) {
|
||||
DEBUG(1,("krb5_init_context failed (%s)\n",
|
||||
error_message(rc)));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (argc>0) {
|
||||
realm.data = (krb5_pointer) argv[0];
|
||||
realm.length = strlen(argv[0]);
|
||||
} else if (lp_realm() && *lp_realm()) {
|
||||
realm.data = (krb5_pointer) lp_realm();
|
||||
realm.length = strlen(realm.data);
|
||||
} else {
|
||||
rc = krb5_get_host_realm(ctx, NULL, &realms);
|
||||
if (rc) {
|
||||
DEBUG(1,("krb5_gethost_realm failed (%s)\n",
|
||||
error_message(rc)));
|
||||
return -1;
|
||||
}
|
||||
realm.data = (krb5_pointer) *realms;
|
||||
realm.length = strlen(realm.data);
|
||||
}
|
||||
|
||||
rc = krb5_locate_kdc(ctx, &realm, &addrs, &num_kdcs, 0);
|
||||
if (rc) {
|
||||
DEBUG(1, ("krb5_locate_kdc failed (%s)\n", error_message(rc)));
|
||||
return -1;
|
||||
}
|
||||
for (i=0;i<num_kdcs;i++)
|
||||
if (addrs[i].sin_family == AF_INET)
|
||||
d_printf("%s:%hd\n", inet_ntoa(addrs[i].sin_addr),
|
||||
ntohs(addrs[i].sin_port));
|
||||
return 0;
|
||||
|
||||
#endif
|
||||
DEBUG(1, ("No kerberos support\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* lookup hosts or IP addresses using internal samba lookup fns */
|
||||
int net_lookup(int argc, const char **argv)
|
||||
{
|
||||
struct functable func[] = {
|
||||
{"HOST", net_lookup_host},
|
||||
{"LDAP", net_lookup_ldap},
|
||||
{"DC", net_lookup_dc},
|
||||
{"MASTER", net_lookup_master},
|
||||
{"KDC", net_lookup_kdc},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
return net_run_function(argc, argv, func, net_lookup_usage);
|
||||
}
|
||||
1051
source/utils/net_rap.c
Normal file
1051
source/utils/net_rap.c
Normal file
File diff suppressed because it is too large
Load Diff
2262
source/utils/net_rpc.c
Normal file
2262
source/utils/net_rpc.c
Normal file
File diff suppressed because it is too large
Load Diff
354
source/utils/net_rpc_join.c
Normal file
354
source/utils/net_rpc_join.c
Normal file
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
Samba Unix/Linux SMB client library
|
||||
Distributed SMB/CIFS Server Management Utility
|
||||
Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org)
|
||||
Copyright (C) Tim Potter 2001
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "../utils/net.h"
|
||||
|
||||
/* Macro for checking RPC error codes to make things more readable */
|
||||
|
||||
#define CHECK_RPC_ERR(rpc, msg) \
|
||||
if (!NT_STATUS_IS_OK(result = rpc)) { \
|
||||
DEBUG(0, (msg ": %s\n", nt_errstr(result))); \
|
||||
goto done; \
|
||||
}
|
||||
|
||||
#define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \
|
||||
if (!NT_STATUS_IS_OK(result = rpc)) { \
|
||||
DEBUG(0, debug_args); \
|
||||
goto done; \
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* confirm that a domain join is still valid
|
||||
*
|
||||
* @return A shell status integer (0 for success)
|
||||
*
|
||||
**/
|
||||
int net_rpc_join_ok(const char *domain)
|
||||
{
|
||||
struct cli_state *cli;
|
||||
uchar stored_md4_trust_password[16];
|
||||
int retval = 1;
|
||||
uint32 channel;
|
||||
NTSTATUS result;
|
||||
uint32 neg_flags = 0x000001ff;
|
||||
|
||||
/* Connect to remote machine */
|
||||
if (!(cli = net_make_ipc_connection(NET_FLAGS_ANONYMOUS | NET_FLAGS_PDC))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!cli_nt_session_open(cli, PI_NETLOGON)) {
|
||||
DEBUG(0,("Error connecting to NETLOGON pipe\n"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!secrets_fetch_trust_account_password(domain,
|
||||
stored_md4_trust_password, NULL)) {
|
||||
DEBUG(0,("Could not reterive domain trust secret"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (lp_server_role() == ROLE_DOMAIN_BDC ||
|
||||
lp_server_role() == ROLE_DOMAIN_PDC) {
|
||||
channel = SEC_CHAN_BDC;
|
||||
} else {
|
||||
channel = SEC_CHAN_WKSTA;
|
||||
}
|
||||
|
||||
CHECK_RPC_ERR(cli_nt_setup_creds(cli,
|
||||
channel,
|
||||
stored_md4_trust_password, &neg_flags, 2),
|
||||
"error in domain join verification");
|
||||
|
||||
retval = 0; /* Success! */
|
||||
|
||||
done:
|
||||
/* Close down pipe - this will clean up open policy handles */
|
||||
if (cli->nt_pipe_fnum)
|
||||
cli_nt_session_close(cli);
|
||||
|
||||
cli_shutdown(cli);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Join a domain using the administrator username and password
|
||||
*
|
||||
* @param argc Standard main() style argc
|
||||
* @param argc Standard main() style argv. Initial components are already
|
||||
* stripped. Currently not used.
|
||||
* @return A shell status integer (0 for success)
|
||||
*
|
||||
**/
|
||||
|
||||
int net_rpc_join_newstyle(int argc, const char **argv)
|
||||
{
|
||||
|
||||
/* libsmb variables */
|
||||
|
||||
struct cli_state *cli;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
uint32 acb_info;
|
||||
|
||||
/* rpc variables */
|
||||
|
||||
POLICY_HND lsa_pol, sam_pol, domain_pol, user_pol;
|
||||
DOM_SID domain_sid;
|
||||
uint32 user_rid;
|
||||
|
||||
/* Password stuff */
|
||||
|
||||
char *clear_trust_password = NULL;
|
||||
fstring ucs2_trust_password;
|
||||
int ucs2_pw_len;
|
||||
uchar pwbuf[516], sess_key[16];
|
||||
SAM_USERINFO_CTR ctr;
|
||||
SAM_USER_INFO_24 p24;
|
||||
SAM_USER_INFO_10 p10;
|
||||
|
||||
/* Misc */
|
||||
|
||||
NTSTATUS result;
|
||||
int retval = 1;
|
||||
fstring domain;
|
||||
uint32 num_rids, *name_types, *user_rids;
|
||||
uint32 flags = 0x3e8;
|
||||
char *acct_name;
|
||||
const char *const_acct_name;
|
||||
|
||||
/* Connect to remote machine */
|
||||
|
||||
if (!(cli = net_make_ipc_connection(NET_FLAGS_PDC)))
|
||||
return 1;
|
||||
|
||||
if (!(mem_ctx = talloc_init("net_rpc_join_newstyle"))) {
|
||||
DEBUG(0, ("Could not initialise talloc context\n"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Fetch domain sid */
|
||||
|
||||
if (!cli_nt_session_open(cli, PI_LSARPC)) {
|
||||
DEBUG(0, ("Error connecting to SAM pipe\n"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
CHECK_RPC_ERR(cli_lsa_open_policy(cli, mem_ctx, True,
|
||||
SEC_RIGHTS_MAXIMUM_ALLOWED,
|
||||
&lsa_pol),
|
||||
"error opening lsa policy handle");
|
||||
|
||||
CHECK_RPC_ERR(cli_lsa_query_info_policy(cli, mem_ctx, &lsa_pol,
|
||||
5, domain, &domain_sid),
|
||||
"error querying info policy");
|
||||
|
||||
cli_lsa_close(cli, mem_ctx, &lsa_pol);
|
||||
|
||||
cli_nt_session_close(cli); /* Done with this pipe */
|
||||
|
||||
/* Create domain user */
|
||||
if (!cli_nt_session_open(cli, PI_SAMR)) {
|
||||
DEBUG(0, ("Error connecting to SAM pipe\n"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
CHECK_RPC_ERR(cli_samr_connect(cli, mem_ctx,
|
||||
SEC_RIGHTS_MAXIMUM_ALLOWED,
|
||||
&sam_pol),
|
||||
"could not connect to SAM database");
|
||||
|
||||
|
||||
CHECK_RPC_ERR(cli_samr_open_domain(cli, mem_ctx, &sam_pol,
|
||||
SEC_RIGHTS_MAXIMUM_ALLOWED,
|
||||
&domain_sid, &domain_pol),
|
||||
"could not open domain");
|
||||
|
||||
/* Create domain user */
|
||||
acct_name = talloc_asprintf(mem_ctx, "%s$", lp_netbios_name());
|
||||
strlower(acct_name);
|
||||
const_acct_name = acct_name;
|
||||
|
||||
acb_info = ((lp_server_role() == ROLE_DOMAIN_BDC) || lp_server_role() == ROLE_DOMAIN_PDC) ? ACB_SVRTRUST : ACB_WSTRUST;
|
||||
|
||||
result = cli_samr_create_dom_user(cli, mem_ctx, &domain_pol,
|
||||
acct_name, acb_info,
|
||||
0xe005000b, &user_pol,
|
||||
&user_rid);
|
||||
|
||||
if (!NT_STATUS_IS_OK(result) &&
|
||||
!NT_STATUS_EQUAL(result, NT_STATUS_USER_EXISTS)) {
|
||||
d_printf("Create of workstation account failed\n");
|
||||
|
||||
/* If NT_STATUS_ACCESS_DENIED then we have a valid
|
||||
username/password combo but the user does not have
|
||||
administrator access. */
|
||||
|
||||
if (NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
|
||||
d_printf("User specified does not have administrator privileges\n");
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* We *must* do this.... don't ask... */
|
||||
|
||||
if (NT_STATUS_IS_OK(result))
|
||||
cli_samr_close(cli, mem_ctx, &user_pol);
|
||||
|
||||
CHECK_RPC_ERR_DEBUG(cli_samr_lookup_names(cli, mem_ctx,
|
||||
&domain_pol, flags,
|
||||
1, &const_acct_name,
|
||||
&num_rids,
|
||||
&user_rids, &name_types),
|
||||
("error looking up rid for user %s: %s\n",
|
||||
acct_name, nt_errstr(result)));
|
||||
|
||||
if (name_types[0] != SID_NAME_USER) {
|
||||
DEBUG(0, ("%s is not a user account\n", acct_name));
|
||||
goto done;
|
||||
}
|
||||
|
||||
user_rid = user_rids[0];
|
||||
|
||||
/* Open handle on user */
|
||||
|
||||
CHECK_RPC_ERR_DEBUG(
|
||||
cli_samr_open_user(cli, mem_ctx, &domain_pol,
|
||||
SEC_RIGHTS_MAXIMUM_ALLOWED,
|
||||
user_rid, &user_pol),
|
||||
("could not re-open existing user %s: %s\n",
|
||||
acct_name, nt_errstr(result)));
|
||||
|
||||
/* Create a random machine account password */
|
||||
|
||||
{
|
||||
char *str;
|
||||
str = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
|
||||
clear_trust_password = strdup(str);
|
||||
}
|
||||
|
||||
ucs2_pw_len = push_ucs2(NULL, ucs2_trust_password,
|
||||
clear_trust_password,
|
||||
sizeof(ucs2_trust_password), 0);
|
||||
|
||||
encode_pw_buffer((char *)pwbuf, ucs2_trust_password,
|
||||
ucs2_pw_len);
|
||||
|
||||
/* Set password on machine account */
|
||||
|
||||
ZERO_STRUCT(ctr);
|
||||
ZERO_STRUCT(p24);
|
||||
|
||||
init_sam_user_info24(&p24, (char *)pwbuf,24);
|
||||
|
||||
ctr.switch_value = 24;
|
||||
ctr.info.id24 = &p24;
|
||||
|
||||
CHECK_RPC_ERR(cli_samr_set_userinfo(cli, mem_ctx, &user_pol, 24,
|
||||
cli->user_session_key, &ctr),
|
||||
"error setting trust account password");
|
||||
|
||||
/* Why do we have to try to (re-)set the ACB to be the same as what
|
||||
we passed in the samr_create_dom_user() call? When a NT
|
||||
workstation is joined to a domain by an administrator the
|
||||
acb_info is set to 0x80. For a normal user with "Add
|
||||
workstations to the domain" rights the acb_info is 0x84. I'm
|
||||
not sure whether it is supposed to make a difference or not. NT
|
||||
seems to cope with either value so don't bomb out if the set
|
||||
userinfo2 level 0x10 fails. -tpot */
|
||||
|
||||
ZERO_STRUCT(ctr);
|
||||
ctr.switch_value = 0x10;
|
||||
ctr.info.id10 = &p10;
|
||||
|
||||
init_sam_user_info10(&p10, acb_info);
|
||||
|
||||
/* Ignoring the return value is necessary for joining a domain
|
||||
as a normal user with "Add workstation to domain" privilege. */
|
||||
|
||||
result = cli_samr_set_userinfo2(cli, mem_ctx, &user_pol, 0x10,
|
||||
sess_key, &ctr);
|
||||
|
||||
/* Now store the secret in the secrets database */
|
||||
|
||||
strupper(domain);
|
||||
|
||||
if (!secrets_store_domain_sid(domain, &domain_sid)) {
|
||||
DEBUG(0, ("error storing domain sid for %s\n", domain));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!secrets_store_machine_password(clear_trust_password)) {
|
||||
DEBUG(0, ("error storing plaintext domain secrets for %s\n", domain));
|
||||
}
|
||||
|
||||
/* Now check the whole process from top-to-bottom */
|
||||
cli_samr_close(cli, mem_ctx, &user_pol);
|
||||
cli_nt_session_close(cli); /* Done with this pipe */
|
||||
|
||||
retval = net_rpc_join_ok(domain);
|
||||
|
||||
done:
|
||||
/* Close down pipe - this will clean up open policy handles */
|
||||
|
||||
if (cli->nt_pipe_fnum)
|
||||
cli_nt_session_close(cli);
|
||||
|
||||
/* Display success or failure */
|
||||
|
||||
if (retval != 0) {
|
||||
trust_password_delete(domain);
|
||||
fprintf(stderr,"Unable to join domain %s.\n",domain);
|
||||
} else {
|
||||
printf("Joined domain %s.\n",domain);
|
||||
}
|
||||
|
||||
cli_shutdown(cli);
|
||||
|
||||
SAFE_FREE(clear_trust_password);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* check that a join is OK
|
||||
*
|
||||
* @return A shell status integer (0 for success)
|
||||
*
|
||||
**/
|
||||
int net_rpc_testjoin(int argc, const char **argv)
|
||||
{
|
||||
char *domain = smb_xstrdup(lp_workgroup());
|
||||
|
||||
/* Display success or failure */
|
||||
if (net_rpc_join_ok(domain) != 0) {
|
||||
fprintf(stderr,"Join to domain '%s' is not valid\n",domain);
|
||||
free(domain);
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("Join to '%s' is OK\n",domain);
|
||||
free(domain);
|
||||
return 0;
|
||||
}
|
||||
725
source/utils/net_rpc_samsync.c
Normal file
725
source/utils/net_rpc_samsync.c
Normal file
@@ -0,0 +1,725 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
dump the remote SAM using rpc samsync operations
|
||||
|
||||
Copyright (C) Andrew Tridgell 2002
|
||||
Copyright (C) Tim Potter 2001,2002
|
||||
Modified by Volker Lendecke 2002
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "../utils/net.h"
|
||||
|
||||
extern DOM_SID global_sid_Builtin;
|
||||
|
||||
static void display_group_mem_info(uint32 rid, SAM_GROUP_MEM_INFO *g)
|
||||
{
|
||||
int i;
|
||||
d_printf("Group mem %u: ", rid);
|
||||
for (i=0;i<g->num_members;i++) {
|
||||
d_printf("%u ", g->rids[i]);
|
||||
}
|
||||
d_printf("\n");
|
||||
}
|
||||
|
||||
static void display_alias_info(uint32 rid, SAM_ALIAS_INFO *a)
|
||||
{
|
||||
d_printf("Alias '%s' ", unistr2_static(&a->uni_als_name));
|
||||
d_printf("desc='%s' rid=%u\n", unistr2_static(&a->uni_als_desc), a->als_rid);
|
||||
}
|
||||
|
||||
static void display_alias_mem(uint32 rid, SAM_ALIAS_MEM_INFO *a)
|
||||
{
|
||||
int i;
|
||||
d_printf("Alias rid %u: ", rid);
|
||||
for (i=0;i<a->num_members;i++) {
|
||||
d_printf("%s ", sid_string_static(&a->sids[i].sid));
|
||||
}
|
||||
d_printf("\n");
|
||||
}
|
||||
|
||||
static void display_account_info(uint32 rid, SAM_ACCOUNT_INFO *a)
|
||||
{
|
||||
fstring hex_nt_passwd, hex_lm_passwd;
|
||||
uchar lm_passwd[16], nt_passwd[16];
|
||||
static uchar zero_buf[16];
|
||||
|
||||
/* Decode hashes from password hash (if they are not NULL) */
|
||||
|
||||
if (memcmp(a->pass.buf_lm_pwd, zero_buf, 16) != 0) {
|
||||
sam_pwd_hash(a->user_rid, a->pass.buf_lm_pwd, lm_passwd, 0);
|
||||
smbpasswd_sethexpwd(hex_lm_passwd, lm_passwd, a->acb_info);
|
||||
} else {
|
||||
smbpasswd_sethexpwd(hex_lm_passwd, NULL, 0);
|
||||
}
|
||||
|
||||
if (memcmp(a->pass.buf_nt_pwd, zero_buf, 16) != 0) {
|
||||
sam_pwd_hash(a->user_rid, a->pass.buf_nt_pwd, nt_passwd, 0);
|
||||
smbpasswd_sethexpwd(hex_nt_passwd, nt_passwd, a->acb_info);
|
||||
} else {
|
||||
smbpasswd_sethexpwd(hex_nt_passwd, NULL, 0);
|
||||
}
|
||||
|
||||
printf("%s:%d:%s:%s:%s:LCT-0\n", unistr2_static(&a->uni_acct_name),
|
||||
a->user_rid, hex_lm_passwd, hex_nt_passwd,
|
||||
smbpasswd_encode_acb_info(a->acb_info));
|
||||
}
|
||||
|
||||
static void display_domain_info(SAM_DOMAIN_INFO *a)
|
||||
{
|
||||
d_printf("Domain name: %s\n", unistr2_static(&a->uni_dom_name));
|
||||
}
|
||||
|
||||
static void display_group_info(uint32 rid, SAM_GROUP_INFO *a)
|
||||
{
|
||||
d_printf("Group '%s' ", unistr2_static(&a->uni_grp_name));
|
||||
d_printf("desc='%s', rid=%u\n", unistr2_static(&a->uni_grp_desc), rid);
|
||||
}
|
||||
|
||||
static void display_sam_entry(SAM_DELTA_HDR *hdr_delta, SAM_DELTA_CTR *delta)
|
||||
{
|
||||
switch (hdr_delta->type) {
|
||||
case SAM_DELTA_ACCOUNT_INFO:
|
||||
display_account_info(hdr_delta->target_rid, &delta->account_info);
|
||||
break;
|
||||
case SAM_DELTA_GROUP_MEM:
|
||||
display_group_mem_info(hdr_delta->target_rid, &delta->grp_mem_info);
|
||||
break;
|
||||
case SAM_DELTA_ALIAS_INFO:
|
||||
display_alias_info(hdr_delta->target_rid, &delta->alias_info);
|
||||
break;
|
||||
case SAM_DELTA_ALIAS_MEM:
|
||||
display_alias_mem(hdr_delta->target_rid, &delta->als_mem_info);
|
||||
break;
|
||||
case SAM_DELTA_DOMAIN_INFO:
|
||||
display_domain_info(&delta->domain_info);
|
||||
break;
|
||||
case SAM_DELTA_GROUP_INFO:
|
||||
display_group_info(hdr_delta->target_rid, &delta->group_info);
|
||||
break;
|
||||
default:
|
||||
d_printf("Unknown delta record type %d\n", hdr_delta->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void dump_database(struct cli_state *cli, unsigned db_type, DOM_CRED *ret_creds)
|
||||
{
|
||||
unsigned sync_context = 0;
|
||||
NTSTATUS result;
|
||||
int i;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
SAM_DELTA_HDR *hdr_deltas;
|
||||
SAM_DELTA_CTR *deltas;
|
||||
uint32 num_deltas;
|
||||
|
||||
if (!(mem_ctx = talloc_init("dump_database"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
d_printf("Dumping database %u\n", db_type);
|
||||
|
||||
do {
|
||||
result = cli_netlogon_sam_sync(cli, mem_ctx, ret_creds, db_type,
|
||||
sync_context,
|
||||
&num_deltas, &hdr_deltas, &deltas);
|
||||
clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), ret_creds);
|
||||
for (i = 0; i < num_deltas; i++) {
|
||||
display_sam_entry(&hdr_deltas[i], &deltas[i]);
|
||||
}
|
||||
sync_context += 1;
|
||||
} while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
|
||||
|
||||
talloc_destroy(mem_ctx);
|
||||
}
|
||||
|
||||
/* dump sam database via samsync rpc calls */
|
||||
int rpc_samdump(int argc, const char **argv)
|
||||
{
|
||||
NTSTATUS result;
|
||||
struct cli_state *cli = NULL;
|
||||
uchar trust_password[16];
|
||||
DOM_CRED ret_creds;
|
||||
uint32 neg_flags = 0x000001ff;
|
||||
|
||||
|
||||
ZERO_STRUCT(ret_creds);
|
||||
|
||||
/* Connect to remote machine */
|
||||
if (!(cli = net_make_ipc_connection(NET_FLAGS_ANONYMOUS | NET_FLAGS_PDC))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!cli_nt_session_open(cli, PI_NETLOGON)) {
|
||||
DEBUG(0,("Error connecting to NETLOGON pipe\n"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!secrets_fetch_trust_account_password(lp_workgroup(), trust_password, NULL)) {
|
||||
d_printf("Could not retrieve domain trust secret\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
result = cli_nt_setup_creds(cli, SEC_CHAN_BDC, trust_password, &neg_flags, 2);
|
||||
if (!NT_STATUS_IS_OK(result)) {
|
||||
d_printf("Failed to setup BDC creds\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dump_database(cli, SAM_DATABASE_DOMAIN, &ret_creds);
|
||||
dump_database(cli, SAM_DATABASE_BUILTIN, &ret_creds);
|
||||
dump_database(cli, SAM_DATABASE_PRIVS, &ret_creds);
|
||||
|
||||
cli_nt_session_close(cli);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (cli) {
|
||||
cli_nt_session_close(cli);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Convert a SAM_ACCOUNT_DELTA to a SAM_ACCOUNT. */
|
||||
|
||||
static NTSTATUS
|
||||
sam_account_from_delta(SAM_ACCOUNT *account, SAM_ACCOUNT_INFO *delta)
|
||||
{
|
||||
fstring s;
|
||||
uchar lm_passwd[16], nt_passwd[16];
|
||||
static uchar zero_buf[16];
|
||||
|
||||
/* Username, fullname, home dir, dir drive, logon script, acct
|
||||
desc, workstations, profile. */
|
||||
|
||||
unistr2_to_ascii(s, &delta->uni_acct_name, sizeof(s) - 1);
|
||||
pdb_set_nt_username(account, s, PDB_CHANGED);
|
||||
|
||||
/* Unix username is the same - for sainity */
|
||||
pdb_set_username(account, s, PDB_CHANGED);
|
||||
|
||||
unistr2_to_ascii(s, &delta->uni_full_name, sizeof(s) - 1);
|
||||
pdb_set_fullname(account, s, PDB_CHANGED);
|
||||
|
||||
unistr2_to_ascii(s, &delta->uni_home_dir, sizeof(s) - 1);
|
||||
pdb_set_homedir(account, s, PDB_CHANGED);
|
||||
|
||||
unistr2_to_ascii(s, &delta->uni_dir_drive, sizeof(s) - 1);
|
||||
pdb_set_dir_drive(account, s, PDB_CHANGED);
|
||||
|
||||
unistr2_to_ascii(s, &delta->uni_logon_script, sizeof(s) - 1);
|
||||
pdb_set_logon_script(account, s, PDB_CHANGED);
|
||||
|
||||
unistr2_to_ascii(s, &delta->uni_acct_desc, sizeof(s) - 1);
|
||||
pdb_set_acct_desc(account, s, PDB_CHANGED);
|
||||
|
||||
unistr2_to_ascii(s, &delta->uni_workstations, sizeof(s) - 1);
|
||||
pdb_set_workstations(account, s, PDB_CHANGED);
|
||||
|
||||
unistr2_to_ascii(s, &delta->uni_profile, sizeof(s) - 1);
|
||||
pdb_set_profile_path(account, s, PDB_CHANGED);
|
||||
|
||||
/* User and group sid */
|
||||
|
||||
pdb_set_user_sid_from_rid(account, delta->user_rid, PDB_CHANGED);
|
||||
pdb_set_group_sid_from_rid(account, delta->group_rid, PDB_CHANGED);
|
||||
|
||||
/* Logon and password information */
|
||||
|
||||
pdb_set_logon_time(account, nt_time_to_unix(&delta->logon_time), PDB_CHANGED);
|
||||
pdb_set_logoff_time(account, nt_time_to_unix(&delta->logoff_time),
|
||||
PDB_CHANGED);
|
||||
pdb_set_logon_divs(account, delta->logon_divs, PDB_CHANGED);
|
||||
|
||||
/* TODO: logon hours */
|
||||
/* TODO: bad password count */
|
||||
/* TODO: logon count */
|
||||
|
||||
pdb_set_pass_last_set_time(
|
||||
account, nt_time_to_unix(&delta->pwd_last_set_time), PDB_CHANGED);
|
||||
|
||||
pdb_set_kickoff_time(account, get_time_t_max(), PDB_CHANGED);
|
||||
|
||||
/* Decode hashes from password hash
|
||||
Note that win2000 may send us all zeros for the hashes if it doesn't
|
||||
think this channel is secure enough - don't set the passwords at all
|
||||
in that case
|
||||
*/
|
||||
if (memcmp(delta->pass.buf_lm_pwd, zero_buf, 16) != 0) {
|
||||
sam_pwd_hash(delta->user_rid, delta->pass.buf_lm_pwd, lm_passwd, 0);
|
||||
pdb_set_lanman_passwd(account, lm_passwd, PDB_CHANGED);
|
||||
}
|
||||
|
||||
if (memcmp(delta->pass.buf_nt_pwd, zero_buf, 16) != 0) {
|
||||
sam_pwd_hash(delta->user_rid, delta->pass.buf_nt_pwd, nt_passwd, 0);
|
||||
pdb_set_nt_passwd(account, nt_passwd, PDB_CHANGED);
|
||||
}
|
||||
|
||||
/* TODO: account expiry time */
|
||||
|
||||
pdb_set_acct_ctrl(account, delta->acb_info, PDB_CHANGED);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
fetch_account_info(uint32 rid, SAM_ACCOUNT_INFO *delta)
|
||||
{
|
||||
NTSTATUS nt_ret;
|
||||
fstring account;
|
||||
pstring add_script;
|
||||
SAM_ACCOUNT *sam_account=NULL;
|
||||
GROUP_MAP map;
|
||||
struct group *grp;
|
||||
DOM_SID sid;
|
||||
BOOL try_add = False;
|
||||
|
||||
fstrcpy(account, unistr2_static(&delta->uni_acct_name));
|
||||
d_printf("Creating account: %s\n", account);
|
||||
|
||||
if (!NT_STATUS_IS_OK(nt_ret = pdb_init_sam(&sam_account)))
|
||||
return nt_ret;
|
||||
|
||||
if (!pdb_getsampwnam(sam_account, account)) {
|
||||
/* Create appropriate user */
|
||||
if (delta->acb_info & ACB_NORMAL) {
|
||||
pstrcpy(add_script, lp_adduser_script());
|
||||
} else if ( (delta->acb_info & ACB_WSTRUST) ||
|
||||
(delta->acb_info & ACB_SVRTRUST) ) {
|
||||
pstrcpy(add_script, lp_addmachine_script());
|
||||
} else {
|
||||
DEBUG(1, ("Unknown user type: %s\n",
|
||||
smbpasswd_encode_acb_info(delta->acb_info)));
|
||||
pdb_free_sam(&sam_account);
|
||||
return NT_STATUS_NO_SUCH_USER;
|
||||
}
|
||||
if (*add_script) {
|
||||
int add_ret;
|
||||
all_string_sub(add_script, "%u", account,
|
||||
sizeof(account));
|
||||
add_ret = smbrun(add_script,NULL);
|
||||
DEBUG(1,("fetch_account: Running the command `%s' "
|
||||
"gave %d\n", add_script, add_ret));
|
||||
}
|
||||
|
||||
try_add = True;
|
||||
}
|
||||
|
||||
sam_account_from_delta(sam_account, delta);
|
||||
|
||||
if (try_add) {
|
||||
if (!pdb_add_sam_account(sam_account)) {
|
||||
DEBUG(1, ("SAM Account for %s failed to be added to the passdb!\n",
|
||||
account));
|
||||
}
|
||||
} else {
|
||||
if (!pdb_update_sam_account(sam_account)) {
|
||||
DEBUG(1, ("SAM Account for %s failed to be updated in the passdb!\n",
|
||||
account));
|
||||
}
|
||||
}
|
||||
|
||||
sid = *pdb_get_group_sid(sam_account);
|
||||
|
||||
if (!pdb_getgrsid(&map, sid, False)) {
|
||||
DEBUG(0, ("Primary group of %s has no mapping!\n",
|
||||
pdb_get_username(sam_account)));
|
||||
pdb_free_sam(&sam_account);
|
||||
return NT_STATUS_NO_SUCH_GROUP;
|
||||
}
|
||||
|
||||
if (!(grp = getgrgid(map.gid))) {
|
||||
DEBUG(0, ("Could not find unix group %d for user %s (group SID=%s)\n",
|
||||
map.gid, pdb_get_username(sam_account), sid_string_static(&sid)));
|
||||
pdb_free_sam(&sam_account);
|
||||
return NT_STATUS_NO_SUCH_GROUP;
|
||||
}
|
||||
|
||||
smb_set_primary_group(grp->gr_name, pdb_get_username(sam_account));
|
||||
|
||||
pdb_free_sam(&sam_account);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
fetch_group_info(uint32 rid, SAM_GROUP_INFO *delta)
|
||||
{
|
||||
fstring name;
|
||||
fstring comment;
|
||||
struct group *grp = NULL;
|
||||
DOM_SID group_sid;
|
||||
fstring sid_string;
|
||||
GROUP_MAP map;
|
||||
BOOL insert = True;
|
||||
|
||||
unistr2_to_ascii(name, &delta->uni_grp_name, sizeof(name)-1);
|
||||
unistr2_to_ascii(comment, &delta->uni_grp_desc, sizeof(comment)-1);
|
||||
|
||||
/* add the group to the mapping table */
|
||||
sid_copy(&group_sid, get_global_sam_sid());
|
||||
sid_append_rid(&group_sid, rid);
|
||||
sid_to_string(sid_string, &group_sid);
|
||||
|
||||
if (pdb_getgrsid(&map, group_sid, False)) {
|
||||
grp = getgrgid(map.gid);
|
||||
insert = False;
|
||||
}
|
||||
|
||||
if (grp == NULL)
|
||||
{
|
||||
gid_t gid;
|
||||
|
||||
/* No group found from mapping, find it from its name. */
|
||||
if ((grp = getgrnam(name)) == NULL) {
|
||||
/* No appropriate group found, create one */
|
||||
d_printf("Creating unix group: '%s'\n", name);
|
||||
if (smb_create_group(name, &gid) != 0)
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
if ((grp = getgrgid(gid)) == NULL)
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
map.gid = grp->gr_gid;
|
||||
map.sid = group_sid;
|
||||
map.sid_name_use = SID_NAME_DOM_GRP;
|
||||
fstrcpy(map.nt_name, name);
|
||||
fstrcpy(map.comment, comment);
|
||||
|
||||
map.priv_set.count = 0;
|
||||
map.priv_set.set = NULL;
|
||||
|
||||
if (insert)
|
||||
pdb_add_group_mapping_entry(&map);
|
||||
else
|
||||
pdb_update_group_mapping_entry(&map);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
fetch_group_mem_info(uint32 rid, SAM_GROUP_MEM_INFO *delta)
|
||||
{
|
||||
int i;
|
||||
TALLOC_CTX *t = NULL;
|
||||
char **nt_members = NULL;
|
||||
char **unix_members;
|
||||
DOM_SID group_sid;
|
||||
GROUP_MAP map;
|
||||
struct group *grp;
|
||||
|
||||
if (delta->num_members == 0) {
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
sid_copy(&group_sid, get_global_sam_sid());
|
||||
sid_append_rid(&group_sid, rid);
|
||||
|
||||
if (!get_domain_group_from_sid(group_sid, &map, False)) {
|
||||
DEBUG(0, ("Could not find global group %d\n", rid));
|
||||
return NT_STATUS_NO_SUCH_GROUP;
|
||||
}
|
||||
|
||||
if (!(grp = getgrgid(map.gid))) {
|
||||
DEBUG(0, ("Could not find unix group %d\n", map.gid));
|
||||
return NT_STATUS_NO_SUCH_GROUP;
|
||||
}
|
||||
|
||||
d_printf("Group members of %s: ", grp->gr_name);
|
||||
|
||||
if (!(t = talloc_init("fetch_group_mem_info"))) {
|
||||
DEBUG(0, ("could not talloc_init\n"));
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
nt_members = talloc_zero(t, sizeof(char *) * delta->num_members);
|
||||
|
||||
for (i=0; i<delta->num_members; i++) {
|
||||
NTSTATUS nt_status;
|
||||
SAM_ACCOUNT *member = NULL;
|
||||
DOM_SID member_sid;
|
||||
|
||||
if (!NT_STATUS_IS_OK(nt_status = pdb_init_sam_talloc(t, &member))) {
|
||||
talloc_destroy(t);
|
||||
return nt_status;
|
||||
}
|
||||
|
||||
sid_copy(&member_sid, get_global_sam_sid());
|
||||
sid_append_rid(&member_sid, delta->rids[i]);
|
||||
|
||||
if (!pdb_getsampwsid(member, &member_sid)) {
|
||||
DEBUG(1, ("Found bogus group member: %d (member_sid=%s group=%s)\n",
|
||||
delta->rids[i], sid_string_static(&member_sid), grp->gr_name));
|
||||
pdb_free_sam(&member);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pdb_get_group_rid(member) == rid) {
|
||||
d_printf("%s(primary),", pdb_get_username(member));
|
||||
pdb_free_sam(&member);
|
||||
continue;
|
||||
}
|
||||
|
||||
d_printf("%s,", pdb_get_username(member));
|
||||
nt_members[i] = talloc_strdup(t, pdb_get_username(member));
|
||||
pdb_free_sam(&member);
|
||||
}
|
||||
|
||||
d_printf("\n");
|
||||
|
||||
unix_members = grp->gr_mem;
|
||||
|
||||
while (*unix_members) {
|
||||
BOOL is_nt_member = False;
|
||||
for (i=0; i<delta->num_members; i++) {
|
||||
if (nt_members[i] == NULL) {
|
||||
/* This was a primary group */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(*unix_members, nt_members[i]) == 0) {
|
||||
is_nt_member = True;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!is_nt_member) {
|
||||
/* We look at a unix group member that is not
|
||||
an nt group member. So, remove it. NT is
|
||||
boss here. */
|
||||
smb_delete_user_group(grp->gr_name, *unix_members);
|
||||
}
|
||||
unix_members += 1;
|
||||
}
|
||||
|
||||
for (i=0; i<delta->num_members; i++) {
|
||||
BOOL is_unix_member = False;
|
||||
|
||||
if (nt_members[i] == NULL) {
|
||||
/* This was the primary group */
|
||||
continue;
|
||||
}
|
||||
|
||||
unix_members = grp->gr_mem;
|
||||
|
||||
while (*unix_members) {
|
||||
if (strcmp(*unix_members, nt_members[i]) == 0) {
|
||||
is_unix_member = True;
|
||||
break;
|
||||
}
|
||||
unix_members += 1;
|
||||
}
|
||||
|
||||
if (!is_unix_member) {
|
||||
/* We look at a nt group member that is not a
|
||||
unix group member currently. So, add the nt
|
||||
group member. */
|
||||
smb_add_user_group(grp->gr_name, nt_members[i]);
|
||||
}
|
||||
}
|
||||
|
||||
talloc_destroy(t);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS fetch_alias_info(uint32 rid, SAM_ALIAS_INFO *delta,
|
||||
DOM_SID dom_sid)
|
||||
{
|
||||
fstring name;
|
||||
fstring comment;
|
||||
struct group *grp = NULL;
|
||||
DOM_SID alias_sid;
|
||||
fstring sid_string;
|
||||
GROUP_MAP map;
|
||||
BOOL insert = True;
|
||||
|
||||
unistr2_to_ascii(name, &delta->uni_als_name, sizeof(name)-1);
|
||||
unistr2_to_ascii(comment, &delta->uni_als_desc, sizeof(comment)-1);
|
||||
|
||||
/* Find out whether the group is already mapped */
|
||||
sid_copy(&alias_sid, &dom_sid);
|
||||
sid_append_rid(&alias_sid, rid);
|
||||
sid_to_string(sid_string, &alias_sid);
|
||||
|
||||
if (pdb_getgrsid(&map, alias_sid, False)) {
|
||||
grp = getgrgid(map.gid);
|
||||
insert = False;
|
||||
}
|
||||
|
||||
if (grp == NULL) {
|
||||
gid_t gid;
|
||||
|
||||
/* No group found from mapping, find it from its name. */
|
||||
if ((grp = getgrnam(name)) == NULL) {
|
||||
/* No appropriate group found, create one */
|
||||
d_printf("Creating unix group: '%s'\n", name);
|
||||
if (smb_create_group(name, &gid) != 0)
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
if ((grp = getgrgid(gid)) == NULL)
|
||||
return NT_STATUS_ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
|
||||
map.gid = grp->gr_gid;
|
||||
map.sid = alias_sid;
|
||||
|
||||
if (sid_equal(&dom_sid, &global_sid_Builtin))
|
||||
map.sid_name_use = SID_NAME_WKN_GRP;
|
||||
else
|
||||
map.sid_name_use = SID_NAME_ALIAS;
|
||||
|
||||
fstrcpy(map.nt_name, name);
|
||||
fstrcpy(map.comment, comment);
|
||||
|
||||
map.priv_set.count = 0;
|
||||
map.priv_set.set = NULL;
|
||||
|
||||
if (insert)
|
||||
pdb_add_group_mapping_entry(&map);
|
||||
else
|
||||
pdb_update_group_mapping_entry(&map);
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
fetch_alias_mem(uint32 rid, SAM_ALIAS_MEM_INFO *delta, DOM_SID dom_sid)
|
||||
{
|
||||
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_sam_entry(SAM_DELTA_HDR *hdr_delta, SAM_DELTA_CTR *delta,
|
||||
DOM_SID dom_sid)
|
||||
{
|
||||
switch(hdr_delta->type) {
|
||||
case SAM_DELTA_ACCOUNT_INFO:
|
||||
fetch_account_info(hdr_delta->target_rid,
|
||||
&delta->account_info);
|
||||
break;
|
||||
case SAM_DELTA_GROUP_INFO:
|
||||
fetch_group_info(hdr_delta->target_rid,
|
||||
&delta->group_info);
|
||||
break;
|
||||
case SAM_DELTA_GROUP_MEM:
|
||||
fetch_group_mem_info(hdr_delta->target_rid,
|
||||
&delta->grp_mem_info);
|
||||
break;
|
||||
case SAM_DELTA_ALIAS_INFO:
|
||||
fetch_alias_info(hdr_delta->target_rid,
|
||||
&delta->alias_info, dom_sid);
|
||||
break;
|
||||
case SAM_DELTA_ALIAS_MEM:
|
||||
fetch_alias_mem(hdr_delta->target_rid,
|
||||
&delta->als_mem_info, dom_sid);
|
||||
break;
|
||||
default:
|
||||
d_printf("Unknown delta record type %d\n", hdr_delta->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_database(struct cli_state *cli, unsigned db_type, DOM_CRED *ret_creds,
|
||||
DOM_SID dom_sid)
|
||||
{
|
||||
unsigned sync_context = 0;
|
||||
NTSTATUS result;
|
||||
int i;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
SAM_DELTA_HDR *hdr_deltas;
|
||||
SAM_DELTA_CTR *deltas;
|
||||
uint32 num_deltas;
|
||||
|
||||
if (!(mem_ctx = talloc_init("fetch_database"))) {
|
||||
return;
|
||||
}
|
||||
|
||||
d_printf("Fetching database %u\n", db_type);
|
||||
|
||||
do {
|
||||
result = cli_netlogon_sam_sync(cli, mem_ctx, ret_creds,
|
||||
db_type, sync_context,
|
||||
&num_deltas,
|
||||
&hdr_deltas, &deltas);
|
||||
clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred),
|
||||
ret_creds);
|
||||
for (i = 0; i < num_deltas; i++) {
|
||||
fetch_sam_entry(&hdr_deltas[i], &deltas[i], dom_sid);
|
||||
}
|
||||
sync_context += 1;
|
||||
} while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
|
||||
|
||||
talloc_destroy(mem_ctx);
|
||||
}
|
||||
|
||||
/* dump sam database via samsync rpc calls */
|
||||
int rpc_vampire(int argc, const char **argv)
|
||||
{
|
||||
NTSTATUS result;
|
||||
struct cli_state *cli = NULL;
|
||||
uchar trust_password[16];
|
||||
DOM_CRED ret_creds;
|
||||
uint32 neg_flags = 0x000001ff;
|
||||
DOM_SID dom_sid;
|
||||
|
||||
ZERO_STRUCT(ret_creds);
|
||||
|
||||
/* Connect to remote machine */
|
||||
if (!(cli = net_make_ipc_connection(NET_FLAGS_ANONYMOUS |
|
||||
NET_FLAGS_PDC))) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!cli_nt_session_open(cli, PI_NETLOGON)) {
|
||||
DEBUG(0,("Error connecting to NETLOGON pipe\n"));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!secrets_fetch_trust_account_password(lp_workgroup(),
|
||||
trust_password, NULL)) {
|
||||
d_printf("Could not retrieve domain trust secret\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
result = cli_nt_setup_creds(cli, SEC_CHAN_BDC, trust_password,
|
||||
&neg_flags, 2);
|
||||
if (!NT_STATUS_IS_OK(result)) {
|
||||
d_printf("Failed to setup BDC creds\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dom_sid = *get_global_sam_sid();
|
||||
fetch_database(cli, SAM_DATABASE_DOMAIN, &ret_creds, dom_sid);
|
||||
|
||||
sid_copy(&dom_sid, &global_sid_Builtin);
|
||||
fetch_database(cli, SAM_DATABASE_BUILTIN, &ret_creds, dom_sid);
|
||||
|
||||
/* Currently we crash on PRIVS somewhere in unmarshalling */
|
||||
/* Dump_database(cli, SAM_DATABASE_PRIVS, &ret_creds); */
|
||||
|
||||
cli_nt_session_close(cli);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (cli) {
|
||||
cli_nt_session_close(cli);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
180
source/utils/net_time.c
Normal file
180
source/utils/net_time.c
Normal file
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
Samba Unix/Linux SMB client library
|
||||
net time command
|
||||
Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include "includes.h"
|
||||
#include "../utils/net.h"
|
||||
|
||||
|
||||
/*
|
||||
return the time on a server. This does not require any authentication
|
||||
*/
|
||||
static time_t cli_servertime(const char *host, struct in_addr *ip, int *zone)
|
||||
{
|
||||
struct nmb_name calling, called;
|
||||
time_t ret = 0;
|
||||
struct cli_state *cli = NULL;
|
||||
|
||||
cli = cli_initialise(NULL);
|
||||
if (!cli) goto done;
|
||||
|
||||
if (!cli_connect(cli, host, ip)) {
|
||||
fprintf(stderr,"Can't contact server\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
make_nmb_name(&calling, lp_netbios_name(), 0x0);
|
||||
if (host) {
|
||||
make_nmb_name(&called, host, 0x20);
|
||||
} else {
|
||||
make_nmb_name(&called, "*SMBSERVER", 0x20);
|
||||
}
|
||||
|
||||
if (!cli_session_request(cli, &calling, &called)) {
|
||||
fprintf(stderr,"Session request failed\n");
|
||||
goto done;
|
||||
}
|
||||
if (!cli_negprot(cli)) {
|
||||
fprintf(stderr,"Protocol negotiation failed\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = cli->servertime;
|
||||
if (zone) *zone = cli->serverzone;
|
||||
|
||||
done:
|
||||
if (cli) cli_shutdown(cli);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* find the servers time on the opt_host host */
|
||||
static time_t nettime(int *zone)
|
||||
{
|
||||
return cli_servertime(opt_host, opt_have_ip? &opt_dest_ip : NULL, zone);
|
||||
}
|
||||
|
||||
/* return a time as a string ready to be passed to /bin/date */
|
||||
static char *systime(time_t t)
|
||||
{
|
||||
static char s[100];
|
||||
struct tm *tm;
|
||||
|
||||
tm = localtime(&t);
|
||||
|
||||
snprintf(s, sizeof(s), "%02d%02d%02d%02d%04d.%02d",
|
||||
tm->tm_mon+1, tm->tm_mday, tm->tm_hour,
|
||||
tm->tm_min, tm->tm_year + 1900, tm->tm_sec);
|
||||
return s;
|
||||
}
|
||||
|
||||
int net_time_usage(int argc, const char **argv)
|
||||
{
|
||||
d_printf(
|
||||
"net time\n\tdisplays time on a server\n\n"\
|
||||
"net time system\n\tdisplays time on a server in a format ready for /bin/date\n\n"\
|
||||
"net time set\n\truns /bin/date with the time from the server\n\n"\
|
||||
"net time zone\n\tdisplays the timezone in hours from GMT on the remote computer\n\n"\
|
||||
"\n");
|
||||
net_common_flags_usage(argc, argv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* try to set the system clock using /bin/date */
|
||||
static int net_time_set(int argc, const char **argv)
|
||||
{
|
||||
time_t t = nettime(NULL);
|
||||
char *cmd;
|
||||
|
||||
if (t == 0) return -1;
|
||||
|
||||
/* yes, I know this is cheesy. Use "net time system" if you want to
|
||||
roll your own. I'm putting this in as it works on a large number
|
||||
of systems and the user has a choice in whether its used or not */
|
||||
asprintf(&cmd, "/bin/date %s", systime(t));
|
||||
system(cmd);
|
||||
free(cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* display the time on a remote box in a format ready for /bin/date */
|
||||
static int net_time_system(int argc, const char **argv)
|
||||
{
|
||||
time_t t = nettime(NULL);
|
||||
|
||||
if (t == 0) return -1;
|
||||
|
||||
printf("%s\n", systime(t));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* display the time on a remote box in a format ready for /bin/date */
|
||||
static int net_time_zone(int argc, const char **argv)
|
||||
{
|
||||
int zone = 0;
|
||||
int hours, mins;
|
||||
char zsign;
|
||||
time_t t;
|
||||
|
||||
t = nettime(&zone);
|
||||
|
||||
if (t == 0) return -1;
|
||||
|
||||
zsign = (zone > 0) ? '-' : '+';
|
||||
if (zone < 0) zone = -zone;
|
||||
|
||||
zone /= 60;
|
||||
hours = zone / 60;
|
||||
mins = zone % 60;
|
||||
|
||||
printf("%c%02d%02d\n", zsign, hours, mins);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* display or set the time on a host */
|
||||
int net_time(int argc, const char **argv)
|
||||
{
|
||||
time_t t;
|
||||
struct functable func[] = {
|
||||
{"SYSTEM", net_time_system},
|
||||
{"SET", net_time_set},
|
||||
{"ZONE", net_time_zone},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
if (!opt_host && !opt_have_ip &&
|
||||
!find_master_ip(opt_target_workgroup, &opt_dest_ip)) {
|
||||
d_printf("Could not locate a time server. Try "\
|
||||
"specifying a target host.\n");
|
||||
net_time_usage(argc,argv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (argc != 0) {
|
||||
return net_run_function(argc, argv, func, net_time_usage);
|
||||
}
|
||||
|
||||
/* default - print the time */
|
||||
t = cli_servertime(opt_host, opt_have_ip? &opt_dest_ip : NULL, NULL);
|
||||
if (t == 0) return -1;
|
||||
|
||||
d_printf("%s", ctime(&t));
|
||||
return 0;
|
||||
}
|
||||
338
source/utils/nmblookup.c
Normal file
338
source/utils/nmblookup.c
Normal file
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
NBT client - used to lookup netbios names
|
||||
Copyright (C) Andrew Tridgell 1994-1998
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
extern BOOL AllowDebugChange;
|
||||
|
||||
static BOOL give_flags = False;
|
||||
static BOOL use_bcast = True;
|
||||
static BOOL got_bcast = False;
|
||||
static struct in_addr bcast_addr;
|
||||
static BOOL recursion_desired = False;
|
||||
static BOOL translate_addresses = False;
|
||||
static int ServerFD= -1;
|
||||
static int RootPort = False;
|
||||
static BOOL find_status=False;
|
||||
|
||||
/****************************************************************************
|
||||
open the socket communication
|
||||
**************************************************************************/
|
||||
static BOOL open_sockets(void)
|
||||
{
|
||||
ServerFD = open_socket_in( SOCK_DGRAM,
|
||||
(RootPort ? 137 : 0),
|
||||
(RootPort ? 0 : 3),
|
||||
interpret_addr(lp_socket_address()), True );
|
||||
|
||||
if (ServerFD == -1)
|
||||
return(False);
|
||||
|
||||
set_socket_options( ServerFD, "SO_BROADCAST" );
|
||||
|
||||
DEBUG(3, ("Socket opened.\n"));
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
usage on the program
|
||||
****************************************************************************/
|
||||
static void usage(void)
|
||||
{
|
||||
d_printf("Usage: nmblookup [options] name\n");
|
||||
d_printf("Version %s\n",VERSION);
|
||||
d_printf("\t-d debuglevel set the debuglevel\n");
|
||||
d_printf("\t-B broadcast address the address to use for broadcasts\n");
|
||||
d_printf("\t-f list the NMB flags returned\n");
|
||||
d_printf("\t-U unicast address the address to use for unicast\n");
|
||||
d_printf("\t-M searches for a master browser\n");
|
||||
d_printf("\t-R set recursion desired in packet\n");
|
||||
d_printf("\t-S lookup node status as well\n");
|
||||
d_printf("\t-T translate IP addresses into names\n");
|
||||
d_printf("\t-r Use root port 137 (Win95 only replies to this)\n");
|
||||
d_printf("\t-A Do a node status on <name> as an IP Address\n");
|
||||
d_printf("\t-i NetBIOS scope Use the given NetBIOS scope for name queries\n");
|
||||
d_printf("\t-s smb.conf file Use the given path to the smb.conf file\n");
|
||||
d_printf("\t-h Print this help message.\n");
|
||||
d_printf("\n If you specify -M and name is \"-\", nmblookup looks up __MSBROWSE__<01>\n");
|
||||
d_printf("\n");
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
turn a node status flags field into a string
|
||||
****************************************************************************/
|
||||
static char *node_status_flags(unsigned char flags)
|
||||
{
|
||||
static fstring ret;
|
||||
fstrcpy(ret,"");
|
||||
|
||||
fstrcat(ret, (flags & 0x80) ? "<GROUP> " : " ");
|
||||
if ((flags & 0x60) == 0x00) fstrcat(ret,"B ");
|
||||
if ((flags & 0x60) == 0x20) fstrcat(ret,"P ");
|
||||
if ((flags & 0x60) == 0x40) fstrcat(ret,"M ");
|
||||
if ((flags & 0x60) == 0x60) fstrcat(ret,"H ");
|
||||
if (flags & 0x10) fstrcat(ret,"<DEREGISTERING> ");
|
||||
if (flags & 0x08) fstrcat(ret,"<CONFLICT> ");
|
||||
if (flags & 0x04) fstrcat(ret,"<ACTIVE> ");
|
||||
if (flags & 0x02) fstrcat(ret,"<PERMANENT> ");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
turn the NMB Query flags into a string
|
||||
****************************************************************************/
|
||||
static char *query_flags(int flags)
|
||||
{
|
||||
static fstring ret1;
|
||||
fstrcpy(ret1, "");
|
||||
|
||||
if (flags & NM_FLAGS_RS) fstrcat(ret1, "Response ");
|
||||
if (flags & NM_FLAGS_AA) fstrcat(ret1, "Authoritative ");
|
||||
if (flags & NM_FLAGS_TC) fstrcat(ret1, "Truncated ");
|
||||
if (flags & NM_FLAGS_RD) fstrcat(ret1, "Recursion_Desired ");
|
||||
if (flags & NM_FLAGS_RA) fstrcat(ret1, "Recursion_Available ");
|
||||
if (flags & NM_FLAGS_B) fstrcat(ret1, "Broadcast ");
|
||||
|
||||
return ret1;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
do a node status query
|
||||
****************************************************************************/
|
||||
static void do_node_status(int fd, const char *name, int type, struct in_addr ip)
|
||||
{
|
||||
struct nmb_name nname;
|
||||
int count, i, j;
|
||||
struct node_status *status;
|
||||
fstring cleanname;
|
||||
|
||||
d_printf("Looking up status of %s\n",inet_ntoa(ip));
|
||||
make_nmb_name(&nname, name, type);
|
||||
status = node_status_query(fd,&nname,ip, &count);
|
||||
if (status) {
|
||||
for (i=0;i<count;i++) {
|
||||
fstrcpy(cleanname, status[i].name);
|
||||
for (j=0;cleanname[j];j++) {
|
||||
if (!isprint((int)cleanname[j])) cleanname[j] = '.';
|
||||
}
|
||||
d_printf("\t%-15s <%02x> - %s\n",
|
||||
cleanname,status[i].type,
|
||||
node_status_flags(status[i].flags));
|
||||
}
|
||||
SAFE_FREE(status);
|
||||
}
|
||||
d_printf("\n");
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
send out one query
|
||||
****************************************************************************/
|
||||
static BOOL query_one(const char *lookup, unsigned int lookup_type)
|
||||
{
|
||||
int j, count, flags = 0;
|
||||
struct in_addr *ip_list=NULL;
|
||||
|
||||
if (got_bcast) {
|
||||
d_printf("querying %s on %s\n", lookup, inet_ntoa(bcast_addr));
|
||||
ip_list = name_query(ServerFD,lookup,lookup_type,use_bcast,
|
||||
use_bcast?True:recursion_desired,
|
||||
bcast_addr,&count, &flags, NULL);
|
||||
} else {
|
||||
struct in_addr *bcast;
|
||||
for (j=iface_count() - 1;
|
||||
!ip_list && j >= 0;
|
||||
j--) {
|
||||
bcast = iface_n_bcast(j);
|
||||
d_printf("querying %s on %s\n",
|
||||
lookup, inet_ntoa(*bcast));
|
||||
ip_list = name_query(ServerFD,lookup,lookup_type,
|
||||
use_bcast,
|
||||
use_bcast?True:recursion_desired,
|
||||
*bcast,&count, &flags, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ip_list) return False;
|
||||
|
||||
if (give_flags)
|
||||
d_printf("Flags: %s\n", query_flags(flags));
|
||||
|
||||
for (j=0;j<count;j++) {
|
||||
if (translate_addresses) {
|
||||
struct hostent *host = gethostbyaddr((char *)&ip_list[j], sizeof(ip_list[j]), AF_INET);
|
||||
if (host) {
|
||||
d_printf("%s, ", host -> h_name);
|
||||
}
|
||||
}
|
||||
d_printf("%s %s<%02x>\n",inet_ntoa(ip_list[j]),lookup, lookup_type);
|
||||
}
|
||||
|
||||
/* We can only do find_status if the ip address returned
|
||||
was valid - ie. name_query returned true.
|
||||
*/
|
||||
if (find_status) {
|
||||
do_node_status(ServerFD, lookup, lookup_type, ip_list[0]);
|
||||
}
|
||||
|
||||
safe_free(ip_list);
|
||||
|
||||
return (ip_list != NULL);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
main program
|
||||
****************************************************************************/
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int opt;
|
||||
unsigned int lookup_type = 0x0;
|
||||
fstring lookup;
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
BOOL find_master=False;
|
||||
int i;
|
||||
BOOL lookup_by_ip = False;
|
||||
int commandline_debuglevel = -2;
|
||||
|
||||
DEBUGLEVEL = 1;
|
||||
/* Prevent smb.conf setting from overridding */
|
||||
AllowDebugChange = False;
|
||||
|
||||
*lookup = 0;
|
||||
|
||||
setup_logging(argv[0],True);
|
||||
|
||||
while ((opt = getopt(argc, argv, "d:fB:U:i:s:SMrhART")) != EOF)
|
||||
switch (opt)
|
||||
{
|
||||
case 'B':
|
||||
bcast_addr = *interpret_addr2(optarg);
|
||||
got_bcast = True;
|
||||
use_bcast = True;
|
||||
break;
|
||||
case 'f':
|
||||
give_flags = True;
|
||||
break;
|
||||
case 'U':
|
||||
bcast_addr = *interpret_addr2(optarg);
|
||||
got_bcast = True;
|
||||
use_bcast = False;
|
||||
break;
|
||||
case 'T':
|
||||
translate_addresses = !translate_addresses;
|
||||
break;
|
||||
case 'i':
|
||||
lp_set_cmdline("netbios scope", optarg);
|
||||
break;
|
||||
case 'M':
|
||||
find_master = True;
|
||||
break;
|
||||
case 'S':
|
||||
find_status = True;
|
||||
break;
|
||||
case 'R':
|
||||
recursion_desired = True;
|
||||
break;
|
||||
case 'd':
|
||||
commandline_debuglevel = DEBUGLEVEL = atoi(optarg);
|
||||
break;
|
||||
case 's':
|
||||
pstrcpy(dyn_CONFIGFILE, optarg);
|
||||
break;
|
||||
case 'r':
|
||||
RootPort = True;
|
||||
break;
|
||||
case 'h':
|
||||
usage();
|
||||
exit(0);
|
||||
break;
|
||||
case 'A':
|
||||
lookup_by_ip = True;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
|
||||
fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure we reset DEBUGLEVEL if someone specified it
|
||||
* on the command line.
|
||||
*/
|
||||
|
||||
if(commandline_debuglevel != -2)
|
||||
DEBUGLEVEL = commandline_debuglevel;
|
||||
|
||||
load_interfaces();
|
||||
if (!open_sockets()) return(1);
|
||||
|
||||
for (i=optind;i<argc;i++)
|
||||
{
|
||||
char *p;
|
||||
struct in_addr ip;
|
||||
|
||||
fstrcpy(lookup,argv[i]);
|
||||
|
||||
if(lookup_by_ip)
|
||||
{
|
||||
fstrcpy(lookup,"*");
|
||||
ip = *interpret_addr2(argv[i]);
|
||||
do_node_status(ServerFD, lookup, lookup_type, ip);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (find_master) {
|
||||
if (*lookup == '-') {
|
||||
fstrcpy(lookup,"\01\02__MSBROWSE__\02");
|
||||
lookup_type = 1;
|
||||
} else {
|
||||
lookup_type = 0x1d;
|
||||
}
|
||||
}
|
||||
|
||||
p = strchr_m(lookup,'#');
|
||||
if (p) {
|
||||
*p = '\0';
|
||||
sscanf(++p,"%x",&lookup_type);
|
||||
}
|
||||
|
||||
if (!query_one(lookup, lookup_type)) {
|
||||
d_printf( "name_query failed to find name %s", lookup );
|
||||
if( 0 != lookup_type )
|
||||
d_printf( "#%02x", lookup_type );
|
||||
d_printf( "\n" );
|
||||
}
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
551
source/utils/ntlm_auth.c
Normal file
551
source/utils/ntlm_auth.c
Normal file
@@ -0,0 +1,551 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Winbind status program.
|
||||
|
||||
Copyright (C) Tim Potter 2000-2002
|
||||
Copyright (C) Andrew Bartlett 2003
|
||||
Copyright (C) Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it> 2000
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#undef DBGC_CLASS
|
||||
#define DBGC_CLASS DBGC_WINBIND
|
||||
|
||||
#define SQUID_BUFFER_SIZE 2010
|
||||
|
||||
enum squid_mode {
|
||||
SQUID_2_4_BASIC,
|
||||
SQUID_2_5_BASIC,
|
||||
SQUID_2_5_NTLMSSP
|
||||
};
|
||||
|
||||
|
||||
extern int winbindd_fd;
|
||||
|
||||
static const char *helper_protocol;
|
||||
static const char *username;
|
||||
static const char *domain;
|
||||
static const char *workstation;
|
||||
static const char *hex_challenge;
|
||||
static const char *hex_lm_response;
|
||||
static const char *hex_nt_response;
|
||||
static unsigned char *challenge;
|
||||
static size_t challenge_len;
|
||||
static unsigned char *lm_response;
|
||||
static size_t lm_response_len;
|
||||
static unsigned char *nt_response;
|
||||
static size_t nt_response_len;
|
||||
|
||||
static char *password;
|
||||
|
||||
static char winbind_separator(void)
|
||||
{
|
||||
struct winbindd_response response;
|
||||
static BOOL got_sep;
|
||||
static char sep;
|
||||
|
||||
if (got_sep)
|
||||
return sep;
|
||||
|
||||
ZERO_STRUCT(response);
|
||||
|
||||
/* Send off request */
|
||||
|
||||
if (winbindd_request(WINBINDD_INFO, NULL, &response) !=
|
||||
NSS_STATUS_SUCCESS) {
|
||||
d_printf("could not obtain winbind separator!\n");
|
||||
return '\\';
|
||||
}
|
||||
|
||||
sep = response.data.info.winbind_separator;
|
||||
got_sep = True;
|
||||
|
||||
if (!sep) {
|
||||
d_printf("winbind separator was NULL!\n");
|
||||
return '\\';
|
||||
}
|
||||
|
||||
return sep;
|
||||
}
|
||||
|
||||
static const char *get_winbind_domain(void)
|
||||
{
|
||||
struct winbindd_response response;
|
||||
|
||||
static fstring winbind_domain;
|
||||
if (*winbind_domain) {
|
||||
return winbind_domain;
|
||||
}
|
||||
|
||||
ZERO_STRUCT(response);
|
||||
|
||||
/* Send off request */
|
||||
|
||||
if (winbindd_request(WINBINDD_DOMAIN_NAME, NULL, &response) !=
|
||||
NSS_STATUS_SUCCESS) {
|
||||
d_printf("could not obtain winbind domain name!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fstrcpy(winbind_domain, response.data.domain_name);
|
||||
|
||||
return winbind_domain;
|
||||
|
||||
}
|
||||
|
||||
static const char *get_winbind_netbios_name(void)
|
||||
{
|
||||
struct winbindd_response response;
|
||||
|
||||
static fstring winbind_netbios_name;
|
||||
|
||||
if (*winbind_netbios_name) {
|
||||
return winbind_netbios_name;
|
||||
}
|
||||
|
||||
ZERO_STRUCT(response);
|
||||
|
||||
/* Send off request */
|
||||
|
||||
if (winbindd_request(WINBINDD_NETBIOS_NAME, NULL, &response) !=
|
||||
NSS_STATUS_SUCCESS) {
|
||||
d_printf("could not obtain winbind netbios name!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fstrcpy(winbind_netbios_name, response.data.netbios_name);
|
||||
|
||||
return winbind_netbios_name;
|
||||
|
||||
}
|
||||
|
||||
/* Authenticate a user with a plaintext password */
|
||||
|
||||
static BOOL check_plaintext_auth(const char *user, const char *pass, BOOL stdout_diagnostics)
|
||||
{
|
||||
struct winbindd_request request;
|
||||
struct winbindd_response response;
|
||||
NSS_STATUS result;
|
||||
|
||||
/* Send off request */
|
||||
|
||||
ZERO_STRUCT(request);
|
||||
ZERO_STRUCT(response);
|
||||
|
||||
fstrcpy(request.data.auth.user, user);
|
||||
fstrcpy(request.data.auth.pass, pass);
|
||||
|
||||
result = winbindd_request(WINBINDD_PAM_AUTH, &request, &response);
|
||||
|
||||
/* Display response */
|
||||
|
||||
if (stdout_diagnostics) {
|
||||
if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
|
||||
d_printf("Reading winbind reply failed! (0x01)\n");
|
||||
}
|
||||
|
||||
d_printf("%s (0x%x)\n",
|
||||
response.data.auth.nt_status_string,
|
||||
response.data.auth.nt_status);
|
||||
} else {
|
||||
if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
|
||||
DEBUG(1, ("Reading winbind reply failed! (0x01)\n"));
|
||||
}
|
||||
|
||||
DEBUG(3, ("%s (0x%x)\n",
|
||||
response.data.auth.nt_status_string,
|
||||
response.data.auth.nt_status));
|
||||
}
|
||||
|
||||
return (result == NSS_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
static NTSTATUS winbind_pw_check(struct ntlmssp_state *ntlmssp_state)
|
||||
{
|
||||
struct winbindd_request request;
|
||||
struct winbindd_response response;
|
||||
NSS_STATUS result;
|
||||
/* Send off request */
|
||||
|
||||
ZERO_STRUCT(request);
|
||||
ZERO_STRUCT(response);
|
||||
|
||||
fstrcpy(request.data.auth_crap.user, ntlmssp_state->user);
|
||||
|
||||
fstrcpy(request.data.auth_crap.domain, ntlmssp_state->domain);
|
||||
fstrcpy(request.data.auth_crap.workstation, ntlmssp_state->workstation);
|
||||
|
||||
memcpy(request.data.auth_crap.chal, ntlmssp_state->chal.data,
|
||||
MIN(ntlmssp_state->chal.length, 8));
|
||||
|
||||
memcpy(request.data.auth_crap.lm_resp, ntlmssp_state->lm_resp.data,
|
||||
MIN(ntlmssp_state->lm_resp.length, sizeof(request.data.auth_crap.lm_resp)));
|
||||
|
||||
memcpy(request.data.auth_crap.nt_resp, ntlmssp_state->lm_resp.data,
|
||||
MIN(ntlmssp_state->nt_resp.length, sizeof(request.data.auth_crap.nt_resp)));
|
||||
|
||||
request.data.auth_crap.lm_resp_len = ntlmssp_state->lm_resp.length;
|
||||
request.data.auth_crap.nt_resp_len = ntlmssp_state->nt_resp.length;
|
||||
|
||||
result = winbindd_request(WINBINDD_PAM_AUTH_CRAP, &request, &response);
|
||||
|
||||
/* Display response */
|
||||
|
||||
if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
|
||||
return NT_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
return NT_STATUS(response.data.auth.nt_status);
|
||||
}
|
||||
|
||||
static void manage_squid_ntlmssp_request(enum squid_mode squid_mode,
|
||||
char *buf, int length)
|
||||
{
|
||||
static NTLMSSP_STATE *ntlmssp_state;
|
||||
DATA_BLOB request, reply;
|
||||
NTSTATUS nt_status;
|
||||
|
||||
if (!ntlmssp_state) {
|
||||
ntlmssp_server_start(&ntlmssp_state);
|
||||
ntlmssp_state->check_password = winbind_pw_check;
|
||||
ntlmssp_state->get_domain = get_winbind_domain;
|
||||
ntlmssp_state->get_global_myname = get_winbind_netbios_name;
|
||||
}
|
||||
|
||||
if (strlen(buf) < 3) {
|
||||
x_fprintf(x_stdout, "BH\n");
|
||||
return;
|
||||
}
|
||||
|
||||
request = base64_decode_data_blob(buf + 3);
|
||||
|
||||
DEBUG(0, ("got NTLMSSP packet:\n"));
|
||||
dump_data(0, request.data, request.length);
|
||||
|
||||
nt_status = ntlmssp_server_update(ntlmssp_state, request, &reply);
|
||||
|
||||
if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
|
||||
char *reply_base64 = base64_encode_data_blob(reply);
|
||||
x_fprintf(x_stdout, "TT %s\n", reply_base64);
|
||||
SAFE_FREE(reply_base64);
|
||||
data_blob_free(&reply);
|
||||
} else if (!NT_STATUS_IS_OK(nt_status)) {
|
||||
x_fprintf(x_stdout, "NA %s\n", nt_errstr(nt_status));
|
||||
} else {
|
||||
x_fprintf(x_stdout, "AF %s\\%s\n", ntlmssp_state->domain, ntlmssp_state->user);
|
||||
}
|
||||
|
||||
data_blob_free(&request);
|
||||
}
|
||||
|
||||
static void manage_squid_basic_request(enum squid_mode squid_mode,
|
||||
char *buf, int length)
|
||||
{
|
||||
char *user, *pass;
|
||||
user=buf;
|
||||
|
||||
pass=memchr(buf,' ',length);
|
||||
if (!pass) {
|
||||
DEBUG(2, ("Password not found. Denying access\n"));
|
||||
x_fprintf(x_stderr, "ERR\n");
|
||||
return;
|
||||
}
|
||||
*pass='\0';
|
||||
pass++;
|
||||
|
||||
if (squid_mode == SQUID_2_5_BASIC) {
|
||||
rfc1738_unescape(user);
|
||||
rfc1738_unescape(pass);
|
||||
}
|
||||
|
||||
if (check_plaintext_auth(user, pass, False)) {
|
||||
x_fprintf(x_stdout, "OK\n");
|
||||
} else {
|
||||
x_fprintf(x_stdout, "ERR\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void manage_squid_request(enum squid_mode squid_mode)
|
||||
{
|
||||
char buf[SQUID_BUFFER_SIZE+1];
|
||||
int length;
|
||||
char *c;
|
||||
static BOOL err;
|
||||
|
||||
if (x_fgets(buf, sizeof(buf)-1, x_stdin) == NULL) {
|
||||
DEBUG(1, ("fgets() failed! dying..... errno=%d (%s)\n", errno,
|
||||
strerror(errno)));
|
||||
exit(1); /* BIIG buffer */
|
||||
}
|
||||
|
||||
c=memchr(buf,'\n',sizeof(buf)-1);
|
||||
if (c) {
|
||||
*c = '\0';
|
||||
length = c-buf;
|
||||
} else {
|
||||
err = 1;
|
||||
return;
|
||||
}
|
||||
if (err) {
|
||||
DEBUG(2, ("Oversized message\n"));
|
||||
x_fprintf(x_stderr, "ERR\n");
|
||||
err = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length));
|
||||
|
||||
if (buf[0] == '\0') {
|
||||
DEBUG(2, ("Invalid Request\n"));
|
||||
x_fprintf(x_stderr, "ERR\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (squid_mode == SQUID_2_5_BASIC || squid_mode == SQUID_2_4_BASIC) {
|
||||
manage_squid_basic_request(squid_mode, buf, length);
|
||||
} else if (squid_mode == SQUID_2_5_NTLMSSP) {
|
||||
manage_squid_ntlmssp_request(squid_mode, buf, length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void squid_stream(enum squid_mode squid_mode) {
|
||||
/* initialize FDescs */
|
||||
x_setbuf(x_stdout, NULL);
|
||||
x_setbuf(x_stderr, NULL);
|
||||
while(1) {
|
||||
manage_squid_request(squid_mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Authenticate a user with a challenge/response */
|
||||
|
||||
static BOOL check_auth_crap(void)
|
||||
{
|
||||
struct winbindd_request request;
|
||||
struct winbindd_response response;
|
||||
NSS_STATUS result;
|
||||
/* Send off request */
|
||||
|
||||
ZERO_STRUCT(request);
|
||||
ZERO_STRUCT(response);
|
||||
|
||||
fstrcpy(request.data.auth_crap.user, username);
|
||||
|
||||
fstrcpy(request.data.auth_crap.domain, domain);
|
||||
fstrcpy(request.data.auth_crap.workstation, workstation);
|
||||
|
||||
memcpy(request.data.auth_crap.chal, challenge, MIN(challenge_len, 8));
|
||||
|
||||
memcpy(request.data.auth_crap.lm_resp, lm_response, MIN(lm_response_len, sizeof(request.data.auth_crap.lm_resp)));
|
||||
|
||||
memcpy(request.data.auth_crap.nt_resp, nt_response, MIN(nt_response_len, sizeof(request.data.auth_crap.nt_resp)));
|
||||
|
||||
request.data.auth_crap.lm_resp_len = lm_response_len;
|
||||
request.data.auth_crap.nt_resp_len = nt_response_len;
|
||||
|
||||
result = winbindd_request(WINBINDD_PAM_AUTH_CRAP, &request, &response);
|
||||
|
||||
/* Display response */
|
||||
|
||||
if ((result != NSS_STATUS_SUCCESS) && (response.data.auth.nt_status == 0)) {
|
||||
d_printf("Reading winbind reply failed! (0x01)\n");
|
||||
}
|
||||
|
||||
d_printf("%s (0x%x)\n",
|
||||
response.data.auth.nt_status_string,
|
||||
response.data.auth.nt_status);
|
||||
|
||||
return result == NSS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Main program */
|
||||
|
||||
enum {
|
||||
OPT_USERNAME = 1000,
|
||||
OPT_DOMAIN,
|
||||
OPT_WORKSTATION,
|
||||
OPT_CHALLENGE,
|
||||
OPT_RESPONSE,
|
||||
OPT_LM,
|
||||
OPT_NT,
|
||||
OPT_PASSWORD
|
||||
};
|
||||
|
||||
/*************************************************************
|
||||
Routine to set hex password characters into an allocated array.
|
||||
**************************************************************/
|
||||
|
||||
static void hex_encode(const unsigned char *buff_in, size_t len, char **out_hex_buffer)
|
||||
{
|
||||
int i;
|
||||
char *hex_buffer;
|
||||
|
||||
*out_hex_buffer = smb_xmalloc((len*2)+1);
|
||||
hex_buffer = *out_hex_buffer;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
slprintf(&hex_buffer[i*2], 3, "%02X", buff_in[i]);
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
Routine to get the 32 hex characters and turn them
|
||||
into a 16 byte array.
|
||||
**************************************************************/
|
||||
|
||||
static BOOL hex_decode(const char *hex_buf_in, unsigned char **out_buffer, size_t *size)
|
||||
{
|
||||
int i;
|
||||
size_t hex_buf_in_len = strlen(hex_buf_in);
|
||||
unsigned char partial_byte_hex;
|
||||
unsigned char partial_byte;
|
||||
const char *hexchars = "0123456789ABCDEF";
|
||||
char *p;
|
||||
BOOL high = True;
|
||||
|
||||
if (!hex_buf_in)
|
||||
return (False);
|
||||
|
||||
*size = (hex_buf_in_len + 1) / 2;
|
||||
|
||||
*out_buffer = smb_xmalloc(*size);
|
||||
|
||||
for (i = 0; i < hex_buf_in_len; i++) {
|
||||
partial_byte_hex = toupper(hex_buf_in[i]);
|
||||
|
||||
p = strchr(hexchars, partial_byte_hex);
|
||||
|
||||
if (!p)
|
||||
return (False);
|
||||
|
||||
partial_byte = PTR_DIFF(p, hexchars);
|
||||
|
||||
if (high) {
|
||||
(*out_buffer)[i / 2] = (partial_byte << 4);
|
||||
} else {
|
||||
(*out_buffer)[i / 2] |= partial_byte;
|
||||
}
|
||||
high = !high;
|
||||
}
|
||||
return (True);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
int opt;
|
||||
|
||||
poptContext pc;
|
||||
struct poptOption long_options[] = {
|
||||
POPT_AUTOHELP
|
||||
|
||||
{ "helper-protocol", 0, POPT_ARG_STRING, &helper_protocol, OPT_DOMAIN, "operate as a stdio-based helper", "helper protocol to use"},
|
||||
{ "username", 0, POPT_ARG_STRING, &username, OPT_USERNAME, "username"},
|
||||
{ "domain", 0, POPT_ARG_STRING, &domain, OPT_DOMAIN, "domain name"},
|
||||
{ "workstation", 0, POPT_ARG_STRING, &domain, OPT_WORKSTATION, "workstation"},
|
||||
{ "challenge", 0, POPT_ARG_STRING, &hex_challenge, OPT_CHALLENGE, "challenge (HEX encoded)"},
|
||||
{ "lm-response", 0, POPT_ARG_STRING, &hex_lm_response, OPT_LM, "LM Response to the challenge (HEX encoded)"},
|
||||
{ "nt-response", 0, POPT_ARG_STRING, &hex_nt_response, OPT_NT, "NT or NTLMv2 Response to the challenge (HEX encoded)"},
|
||||
{ "password", 0, POPT_ARG_STRING, &password, OPT_PASSWORD, "User's plaintext password"},
|
||||
{ NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_debug },
|
||||
{ NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_configfile },
|
||||
{ NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_version},
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
/* Samba client initialisation */
|
||||
|
||||
dbf = x_stderr;
|
||||
|
||||
/* Parse options */
|
||||
|
||||
pc = poptGetContext("ntlm_auth", argc, argv, long_options, 0);
|
||||
|
||||
/* Parse command line options */
|
||||
|
||||
if (argc == 1) {
|
||||
poptPrintHelp(pc, stderr, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
pc = poptGetContext(NULL, argc, (const char **)argv, long_options,
|
||||
POPT_CONTEXT_KEEP_FIRST);
|
||||
|
||||
while((opt = poptGetNextOpt(pc)) != -1) {
|
||||
switch (opt) {
|
||||
case OPT_CHALLENGE:
|
||||
if (!hex_decode(hex_challenge, &challenge, &challenge_len)) {
|
||||
fprintf(stderr, "hex decode of %s failed!\n", hex_challenge);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case OPT_LM:
|
||||
if (!hex_decode(hex_lm_response, &lm_response, &lm_response_len)) {
|
||||
fprintf(stderr, "hex decode of %s failed!\n", lm_response);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case OPT_NT:
|
||||
if (!hex_decode(hex_lm_response, &lm_response, &lm_response_len)) {
|
||||
fprintf(stderr, "hex decode of %s failed!\n", lm_response);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (helper_protocol) {
|
||||
if (strcmp(helper_protocol, "squid-2.5-ntlmssp")== 0) {
|
||||
squid_stream(SQUID_2_5_NTLMSSP);
|
||||
} else if (strcmp(helper_protocol, "squid-2.5-basic")== 0) {
|
||||
squid_stream(SQUID_2_5_BASIC);
|
||||
} else if (strcmp(helper_protocol, "squid-2.4-basic")== 0) {
|
||||
squid_stream(SQUID_2_4_BASIC);
|
||||
} else {
|
||||
fprintf(stderr, "unknown helper protocol [%s]\n", helper_protocol);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (domain == NULL) {
|
||||
domain = get_winbind_domain();
|
||||
}
|
||||
|
||||
if (workstation == NULL) {
|
||||
workstation = "";
|
||||
}
|
||||
|
||||
if (challenge) {
|
||||
if (!check_auth_crap()) {
|
||||
exit(1);
|
||||
}
|
||||
} else if (password) {
|
||||
fstring user;
|
||||
snprintf(user, sizeof(user)-1, "%s%c%s", domain, winbind_separator(), username);
|
||||
if (!check_plaintext_auth(user, password, True)) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Exit code */
|
||||
|
||||
poptFreeContext(pc);
|
||||
return 0;
|
||||
}
|
||||
696
source/utils/pdbedit.c
Normal file
696
source/utils/pdbedit.c
Normal file
@@ -0,0 +1,696 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
passdb editing frontend
|
||||
|
||||
Copyright (C) Simo Sorce 2000
|
||||
Copyright (C) Andrew Bartlett 2001
|
||||
Copyright (C) Jelmer Vernooij 2002
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#define BIT_BACKEND 0x00000004
|
||||
#define BIT_VERBOSE 0x00000008
|
||||
#define BIT_SPSTYLE 0x00000010
|
||||
#define BIT_RESERV_1 0x00000020
|
||||
#define BIT_RESERV_2 0x00000040
|
||||
#define BIT_RESERV_3 0x00000080
|
||||
#define BIT_FULLNAME 0x00000100
|
||||
#define BIT_HOMEDIR 0x00000200
|
||||
#define BIT_HDIRDRIVE 0x00000400
|
||||
#define BIT_LOGSCRIPT 0x00000800
|
||||
#define BIT_PROFILE 0x00001000
|
||||
#define BIT_MACHINE 0x00002000
|
||||
#define BIT_RESERV_4 0x00004000
|
||||
#define BIT_USER 0x00008000
|
||||
#define BIT_LIST 0x00010000
|
||||
#define BIT_MODIFY 0x00020000
|
||||
#define BIT_CREATE 0x00040000
|
||||
#define BIT_DELETE 0x00080000
|
||||
#define BIT_ACCPOLICY 0x00100000
|
||||
#define BIT_ACCPOLVAL 0x00200000
|
||||
#define BIT_ACCTCTRL 0x00400000
|
||||
#define BIT_RESERV_7 0x00800000
|
||||
#define BIT_IMPORT 0x01000000
|
||||
#define BIT_EXPORT 0x02000000
|
||||
|
||||
#define MASK_ALWAYS_GOOD 0x0000001F
|
||||
#define MASK_USER_GOOD 0x00401F00
|
||||
|
||||
/*********************************************************
|
||||
Add all currently available users to another db
|
||||
********************************************************/
|
||||
|
||||
static int export_database (struct pdb_context *in, struct pdb_context *out) {
|
||||
SAM_ACCOUNT *user = NULL;
|
||||
|
||||
if (NT_STATUS_IS_ERR(in->pdb_setsampwent(in, 0))) {
|
||||
fprintf(stderr, "Can't sampwent!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!NT_STATUS_IS_OK(pdb_init_sam(&user))) {
|
||||
fprintf(stderr, "Can't initialize new SAM_ACCOUNT!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (NT_STATUS_IS_OK(in->pdb_getsampwent(in, user))) {
|
||||
out->pdb_add_sam_account(out, user);
|
||||
if (!NT_STATUS_IS_OK(pdb_reset_sam(user))){
|
||||
fprintf(stderr, "Can't reset SAM_ACCOUNT!\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
in->pdb_endsampwent(in);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
Print info from sam structure
|
||||
**********************************************************/
|
||||
|
||||
static int print_sam_info (SAM_ACCOUNT *sam_pwent, BOOL verbosity, BOOL smbpwdstyle)
|
||||
{
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
time_t tmp;
|
||||
|
||||
/* TODO: chaeck if entry is a user or a workstation */
|
||||
if (!sam_pwent) return -1;
|
||||
|
||||
if (verbosity) {
|
||||
printf ("Unix username: %s\n", pdb_get_username(sam_pwent));
|
||||
printf ("NT username: %s\n", pdb_get_nt_username(sam_pwent));
|
||||
printf ("Account Flags: %s\n", pdb_encode_acct_ctrl(pdb_get_acct_ctrl(sam_pwent), NEW_PW_FORMAT_SPACE_PADDED_LEN));
|
||||
|
||||
if (IS_SAM_UNIX_USER(sam_pwent)) {
|
||||
uid = pdb_get_uid(sam_pwent);
|
||||
gid = pdb_get_gid(sam_pwent);
|
||||
printf ("User ID/Group ID: %d/%d\n", uid, gid);
|
||||
}
|
||||
printf ("User SID: %s\n",
|
||||
sid_string_static(pdb_get_user_sid(sam_pwent)));
|
||||
printf ("Primary Group SID: %s\n",
|
||||
sid_string_static(pdb_get_group_sid(sam_pwent)));
|
||||
printf ("Full Name: %s\n", pdb_get_fullname(sam_pwent));
|
||||
printf ("Home Directory: %s\n", pdb_get_homedir(sam_pwent));
|
||||
printf ("HomeDir Drive: %s\n", pdb_get_dir_drive(sam_pwent));
|
||||
printf ("Logon Script: %s\n", pdb_get_logon_script(sam_pwent));
|
||||
printf ("Profile Path: %s\n", pdb_get_profile_path(sam_pwent));
|
||||
printf ("Domain: %s\n", pdb_get_domain(sam_pwent));
|
||||
printf ("Account desc: %s\n", pdb_get_acct_desc(sam_pwent));
|
||||
printf ("Workstations: %s\n", pdb_get_workstations(sam_pwent));
|
||||
printf ("Munged dial: %s\n", pdb_get_munged_dial(sam_pwent));
|
||||
|
||||
tmp = pdb_get_logon_time(sam_pwent);
|
||||
printf ("Logon time: %s\n", tmp ? http_timestring(tmp) : "0");
|
||||
|
||||
tmp = pdb_get_logoff_time(sam_pwent);
|
||||
printf ("Logoff time: %s\n", tmp ? http_timestring(tmp) : "0");
|
||||
|
||||
tmp = pdb_get_kickoff_time(sam_pwent);
|
||||
printf ("Kickoff time: %s\n", tmp ? http_timestring(tmp) : "0");
|
||||
|
||||
tmp = pdb_get_pass_last_set_time(sam_pwent);
|
||||
printf ("Password last set: %s\n", tmp ? http_timestring(tmp) : "0");
|
||||
|
||||
tmp = pdb_get_pass_can_change_time(sam_pwent);
|
||||
printf ("Password can change: %s\n", tmp ? http_timestring(tmp) : "0");
|
||||
|
||||
tmp = pdb_get_pass_must_change_time(sam_pwent);
|
||||
printf ("Password must change: %s\n", tmp ? http_timestring(tmp) : "0");
|
||||
|
||||
} else if (smbpwdstyle) {
|
||||
if (IS_SAM_UNIX_USER(sam_pwent)) {
|
||||
char lm_passwd[33];
|
||||
char nt_passwd[33];
|
||||
|
||||
uid = pdb_get_uid(sam_pwent);
|
||||
pdb_sethexpwd(lm_passwd,
|
||||
pdb_get_lanman_passwd(sam_pwent),
|
||||
pdb_get_acct_ctrl(sam_pwent));
|
||||
pdb_sethexpwd(nt_passwd,
|
||||
pdb_get_nt_passwd(sam_pwent),
|
||||
pdb_get_acct_ctrl(sam_pwent));
|
||||
|
||||
printf("%s:%d:%s:%s:%s:LCT-%08X:\n",
|
||||
pdb_get_username(sam_pwent),
|
||||
uid,
|
||||
lm_passwd,
|
||||
nt_passwd,
|
||||
pdb_encode_acct_ctrl(pdb_get_acct_ctrl(sam_pwent),NEW_PW_FORMAT_SPACE_PADDED_LEN),
|
||||
(uint32)pdb_get_pass_last_set_time(sam_pwent));
|
||||
} else {
|
||||
fprintf(stderr, "Can't output in smbpasswd format, no uid on this record.\n");
|
||||
}
|
||||
} else {
|
||||
if (IS_SAM_UNIX_USER(sam_pwent)) {
|
||||
printf ("%s:%d:%s\n", pdb_get_username(sam_pwent), pdb_get_uid(sam_pwent),
|
||||
pdb_get_fullname(sam_pwent));
|
||||
} else {
|
||||
printf ("%s:(null):%s\n", pdb_get_username(sam_pwent), pdb_get_fullname(sam_pwent));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
Get an Print User Info
|
||||
**********************************************************/
|
||||
|
||||
static int print_user_info (struct pdb_context *in, const char *username, BOOL verbosity, BOOL smbpwdstyle)
|
||||
{
|
||||
SAM_ACCOUNT *sam_pwent=NULL;
|
||||
BOOL ret;
|
||||
|
||||
if (!NT_STATUS_IS_OK(pdb_init_sam (&sam_pwent))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = NT_STATUS_IS_OK(in->pdb_getsampwnam (in, sam_pwent, username));
|
||||
|
||||
if (ret==False) {
|
||||
fprintf (stderr, "Username not found!\n");
|
||||
pdb_free_sam(&sam_pwent);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret=print_sam_info (sam_pwent, verbosity, smbpwdstyle);
|
||||
pdb_free_sam(&sam_pwent);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
List Users
|
||||
**********************************************************/
|
||||
static int print_users_list (struct pdb_context *in, BOOL verbosity, BOOL smbpwdstyle)
|
||||
{
|
||||
SAM_ACCOUNT *sam_pwent=NULL;
|
||||
BOOL check, ret;
|
||||
|
||||
check = NT_STATUS_IS_OK(in->pdb_setsampwent(in, False));
|
||||
if (!check) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
check = True;
|
||||
if (!(NT_STATUS_IS_OK(pdb_init_sam(&sam_pwent)))) return 1;
|
||||
|
||||
while (check && (ret = NT_STATUS_IS_OK(in->pdb_getsampwent (in, sam_pwent)))) {
|
||||
if (verbosity)
|
||||
printf ("---------------\n");
|
||||
print_sam_info (sam_pwent, verbosity, smbpwdstyle);
|
||||
pdb_free_sam(&sam_pwent);
|
||||
check = NT_STATUS_IS_OK(pdb_init_sam(&sam_pwent));
|
||||
}
|
||||
if (check) pdb_free_sam(&sam_pwent);
|
||||
|
||||
in->pdb_endsampwent(in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
Set User Info
|
||||
**********************************************************/
|
||||
|
||||
static int set_user_info (struct pdb_context *in, const char *username,
|
||||
const char *fullname, const char *homedir,
|
||||
const char *drive, const char *script,
|
||||
const char *profile, const char *account_control)
|
||||
{
|
||||
SAM_ACCOUNT *sam_pwent=NULL;
|
||||
BOOL ret;
|
||||
|
||||
pdb_init_sam(&sam_pwent);
|
||||
|
||||
ret = NT_STATUS_IS_OK(in->pdb_getsampwnam (in, sam_pwent, username));
|
||||
if (ret==False) {
|
||||
fprintf (stderr, "Username not found!\n");
|
||||
pdb_free_sam(&sam_pwent);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fullname)
|
||||
pdb_set_fullname(sam_pwent, fullname, PDB_CHANGED);
|
||||
if (homedir)
|
||||
pdb_set_homedir(sam_pwent, homedir, PDB_CHANGED);
|
||||
if (drive)
|
||||
pdb_set_dir_drive(sam_pwent,drive, PDB_CHANGED);
|
||||
if (script)
|
||||
pdb_set_logon_script(sam_pwent, script, PDB_CHANGED);
|
||||
if (profile)
|
||||
pdb_set_profile_path (sam_pwent, profile, PDB_CHANGED);
|
||||
|
||||
if (account_control) {
|
||||
uint16 not_settable = ~(ACB_DISABLED|ACB_HOMDIRREQ|ACB_PWNOTREQ|
|
||||
ACB_PWNOEXP|ACB_AUTOLOCK);
|
||||
|
||||
uint16 newflag = pdb_decode_acct_ctrl(account_control);
|
||||
|
||||
if (newflag & not_settable) {
|
||||
fprintf(stderr, "Can only set [NDHLX] flags\n");
|
||||
pdb_free_sam(&sam_pwent);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pdb_set_acct_ctrl(sam_pwent,
|
||||
(pdb_get_acct_ctrl(sam_pwent) & not_settable) | newflag,
|
||||
PDB_CHANGED);
|
||||
}
|
||||
|
||||
if (NT_STATUS_IS_OK(in->pdb_update_sam_account (in, sam_pwent)))
|
||||
print_user_info (in, username, True, False);
|
||||
else {
|
||||
fprintf (stderr, "Unable to modify entry!\n");
|
||||
pdb_free_sam(&sam_pwent);
|
||||
return -1;
|
||||
}
|
||||
pdb_free_sam(&sam_pwent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
Add New User
|
||||
**********************************************************/
|
||||
static int new_user (struct pdb_context *in, const char *username, const char *fullname, const char *homedir, const char *drive, const char *script, const char *profile)
|
||||
{
|
||||
SAM_ACCOUNT *sam_pwent=NULL;
|
||||
struct passwd *pwd = NULL;
|
||||
char *password1, *password2, *staticpass;
|
||||
|
||||
ZERO_STRUCT(sam_pwent);
|
||||
|
||||
if ((pwd = getpwnam_alloc(username))) {
|
||||
pdb_init_sam_pw (&sam_pwent, pwd);
|
||||
passwd_free(&pwd);
|
||||
} else {
|
||||
fprintf (stderr, "WARNING: user %s does not exist in system passwd\n", username);
|
||||
pdb_init_sam(&sam_pwent);
|
||||
if (!pdb_set_username(sam_pwent, username, PDB_CHANGED)) {
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
staticpass = getpass("new password:");
|
||||
password1 = strdup(staticpass);
|
||||
memset(staticpass, 0, strlen(staticpass));
|
||||
staticpass = getpass("retype new password:");
|
||||
password2 = strdup(staticpass);
|
||||
memset(staticpass, 0, strlen(staticpass));
|
||||
if (strcmp (password1, password2)) {
|
||||
fprintf (stderr, "Passwords does not match!\n");
|
||||
memset(password1, 0, strlen(password1));
|
||||
SAFE_FREE(password1);
|
||||
memset(password2, 0, strlen(password2));
|
||||
SAFE_FREE(password2);
|
||||
pdb_free_sam (&sam_pwent);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pdb_set_plaintext_passwd(sam_pwent, password1);
|
||||
memset(password1, 0, strlen(password1));
|
||||
SAFE_FREE(password1);
|
||||
memset(password2, 0, strlen(password2));
|
||||
SAFE_FREE(password2);
|
||||
|
||||
if (fullname)
|
||||
pdb_set_fullname(sam_pwent, fullname, PDB_CHANGED);
|
||||
if (homedir)
|
||||
pdb_set_homedir (sam_pwent, homedir, PDB_CHANGED);
|
||||
if (drive)
|
||||
pdb_set_dir_drive (sam_pwent, drive, PDB_CHANGED);
|
||||
if (script)
|
||||
pdb_set_logon_script(sam_pwent, script, PDB_CHANGED);
|
||||
if (profile)
|
||||
pdb_set_profile_path (sam_pwent, profile, PDB_CHANGED);
|
||||
|
||||
pdb_set_acct_ctrl (sam_pwent, ACB_NORMAL, PDB_CHANGED);
|
||||
|
||||
if (NT_STATUS_IS_OK(in->pdb_add_sam_account (in, sam_pwent))) {
|
||||
print_user_info (in, username, True, False);
|
||||
} else {
|
||||
fprintf (stderr, "Unable to add user! (does it alredy exist?)\n");
|
||||
pdb_free_sam (&sam_pwent);
|
||||
return -1;
|
||||
}
|
||||
pdb_free_sam (&sam_pwent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
Add New Machine
|
||||
**********************************************************/
|
||||
|
||||
static int new_machine (struct pdb_context *in, const char *machine_in)
|
||||
{
|
||||
SAM_ACCOUNT *sam_pwent=NULL;
|
||||
fstring machinename;
|
||||
struct passwd *pwd = NULL;
|
||||
char name[16];
|
||||
|
||||
fstrcpy(machinename, machine_in);
|
||||
|
||||
if (machinename[strlen (machinename) -1] == '$')
|
||||
machinename[strlen (machinename) -1] = '\0';
|
||||
|
||||
strlower_m(machinename);
|
||||
|
||||
safe_strcpy (name, machinename, 16);
|
||||
safe_strcat (name, "$", 16);
|
||||
|
||||
if ((pwd = getpwnam_alloc(name))) {
|
||||
if (!NT_STATUS_IS_OK(pdb_init_sam_pw( &sam_pwent, pwd))) {
|
||||
fprintf(stderr, "Could not init sam from pw\n");
|
||||
passwd_free(&pwd);
|
||||
return -1;
|
||||
}
|
||||
passwd_free(&pwd);
|
||||
} else {
|
||||
if (!NT_STATUS_IS_OK(pdb_init_sam (&sam_pwent))) {
|
||||
fprintf(stderr, "Could not init sam from pw\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
pdb_set_plaintext_passwd (sam_pwent, machinename);
|
||||
|
||||
pdb_set_username (sam_pwent, name, PDB_CHANGED);
|
||||
|
||||
pdb_set_acct_ctrl (sam_pwent, ACB_WSTRUST, PDB_CHANGED);
|
||||
|
||||
pdb_set_group_sid_from_rid(sam_pwent, DOMAIN_GROUP_RID_COMPUTERS, PDB_CHANGED);
|
||||
|
||||
if (NT_STATUS_IS_OK(in->pdb_add_sam_account (in, sam_pwent))) {
|
||||
print_user_info (in, name, True, False);
|
||||
} else {
|
||||
fprintf (stderr, "Unable to add machine! (does it already exist?)\n");
|
||||
pdb_free_sam (&sam_pwent);
|
||||
return -1;
|
||||
}
|
||||
pdb_free_sam (&sam_pwent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
Delete user entry
|
||||
**********************************************************/
|
||||
|
||||
static int delete_user_entry (struct pdb_context *in, const char *username)
|
||||
{
|
||||
SAM_ACCOUNT *samaccount = NULL;
|
||||
|
||||
if (!NT_STATUS_IS_OK(pdb_init_sam (&samaccount))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NT_STATUS_IS_ERR(in->pdb_getsampwnam(in, samaccount, username))) {
|
||||
fprintf (stderr, "user %s does not exist in the passdb\n", username);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return NT_STATUS_IS_OK(in->pdb_delete_sam_account (in, samaccount));
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
Delete machine entry
|
||||
**********************************************************/
|
||||
|
||||
static int delete_machine_entry (struct pdb_context *in, const char *machinename)
|
||||
{
|
||||
char name[16];
|
||||
SAM_ACCOUNT *samaccount = NULL;
|
||||
|
||||
safe_strcpy (name, machinename, 16);
|
||||
if (name[strlen(name)] != '$')
|
||||
safe_strcat (name, "$", 16);
|
||||
|
||||
if (!NT_STATUS_IS_OK(pdb_init_sam (&samaccount))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NT_STATUS_IS_ERR(in->pdb_getsampwnam(in, samaccount, name))) {
|
||||
fprintf (stderr, "machine %s does not exist in the passdb\n", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return NT_STATUS_IS_OK(in->pdb_delete_sam_account (in, samaccount));
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
Start here.
|
||||
**********************************************************/
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
static BOOL list_users = False;
|
||||
static BOOL verbose = False;
|
||||
static BOOL spstyle = False;
|
||||
static BOOL machine = False;
|
||||
static BOOL add_user = False;
|
||||
static BOOL delete_user = False;
|
||||
static BOOL modify_user = False;
|
||||
uint32 setparms, checkparms;
|
||||
int opt;
|
||||
static char *full_name = NULL;
|
||||
static const char *user_name = NULL;
|
||||
static char *home_dir = NULL;
|
||||
static char *home_drive = NULL;
|
||||
static char *backend = NULL;
|
||||
static char *backend_in = NULL;
|
||||
static char *backend_out = NULL;
|
||||
static char *logon_script = NULL;
|
||||
static char *profile_path = NULL;
|
||||
static char *account_control = NULL;
|
||||
static char *account_policy = NULL;
|
||||
static long int account_policy_value = 0;
|
||||
BOOL account_policy_value_set = False;
|
||||
|
||||
struct pdb_context *bin;
|
||||
struct pdb_context *bout;
|
||||
struct pdb_context *bdef;
|
||||
poptContext pc;
|
||||
struct poptOption long_options[] = {
|
||||
POPT_AUTOHELP
|
||||
{"list", 'l', POPT_ARG_NONE, &list_users, 0, "list all users", NULL},
|
||||
{"verbose", 'v', POPT_ARG_NONE, &verbose, 0, "be verbose", NULL },
|
||||
{"smbpasswd-style", 'w',POPT_ARG_NONE, &spstyle, 0, "give output in smbpasswd style", NULL},
|
||||
{"user", 'u', POPT_ARG_STRING, &user_name, 0, "use username", "USER" },
|
||||
{"fullname", 'f', POPT_ARG_STRING, &full_name, 0, "set full name", NULL},
|
||||
{"homedir", 'h', POPT_ARG_STRING, &home_dir, 0, "set home directory", NULL},
|
||||
{"drive", 'D', POPT_ARG_STRING, &home_drive, 0, "set home drive", NULL},
|
||||
{"script", 'S', POPT_ARG_STRING, &logon_script, 0, "set logon script", NULL},
|
||||
{"profile", 'p', POPT_ARG_STRING, &profile_path, 0, "set profile path", NULL},
|
||||
{"create", 'a', POPT_ARG_NONE, &add_user, 0, "create user", NULL},
|
||||
{"modify", 'r', POPT_ARG_NONE, &modify_user, 0, "modify user", NULL},
|
||||
{"machine", 'm', POPT_ARG_NONE, &machine, 0, "account is a machine account", NULL},
|
||||
{"delete", 'x', POPT_ARG_NONE, &delete_user, 0, "delete user", NULL},
|
||||
{"backend", 'b', POPT_ARG_STRING, &backend, 0, "use different passdb backend as default backend", NULL},
|
||||
{"import", 'i', POPT_ARG_STRING, &backend_in, 0, "import user accounts from this backend", NULL},
|
||||
{"export", 'e', POPT_ARG_STRING, &backend_out, 0, "export user accounts to this backend", NULL},
|
||||
{"account-policy", 'P', POPT_ARG_STRING, &account_policy, 0,"value of an account policy (like maximum password age)",NULL},
|
||||
{"value", 'V', POPT_ARG_LONG, &account_policy_value, 'V',"set the account policy to this value", NULL},
|
||||
{"account-control", 'c', POPT_ARG_STRING, &account_control, 0, "Values of account control", NULL},
|
||||
{ NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_debug },
|
||||
{ NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_configfile },
|
||||
{0,0,0,0}
|
||||
};
|
||||
|
||||
setup_logging("pdbedit", True);
|
||||
|
||||
pc = poptGetContext(NULL, argc, (const char **) argv, long_options,
|
||||
POPT_CONTEXT_KEEP_FIRST);
|
||||
|
||||
while((opt = poptGetNextOpt(pc)) != -1) {
|
||||
switch (opt) {
|
||||
case 'V':
|
||||
account_policy_value_set = True;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
poptGetArg(pc); /* Drop argv[0], the program name */
|
||||
|
||||
if (user_name == NULL)
|
||||
user_name = poptGetArg(pc);
|
||||
|
||||
if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
|
||||
fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
init_modules();
|
||||
|
||||
if (!init_names())
|
||||
exit(1);
|
||||
|
||||
setparms = (backend ? BIT_BACKEND : 0) +
|
||||
(verbose ? BIT_VERBOSE : 0) +
|
||||
(spstyle ? BIT_SPSTYLE : 0) +
|
||||
(full_name ? BIT_FULLNAME : 0) +
|
||||
(home_dir ? BIT_HOMEDIR : 0) +
|
||||
(home_drive ? BIT_HDIRDRIVE : 0) +
|
||||
(logon_script ? BIT_LOGSCRIPT : 0) +
|
||||
(profile_path ? BIT_PROFILE : 0) +
|
||||
(machine ? BIT_MACHINE : 0) +
|
||||
(user_name ? BIT_USER : 0) +
|
||||
(list_users ? BIT_LIST : 0) +
|
||||
(modify_user ? BIT_MODIFY : 0) +
|
||||
(add_user ? BIT_CREATE : 0) +
|
||||
(delete_user ? BIT_DELETE : 0) +
|
||||
(account_control ? BIT_ACCTCTRL : 0) +
|
||||
(account_policy ? BIT_ACCPOLICY : 0) +
|
||||
(account_policy_value_set ? BIT_ACCPOLVAL : 0) +
|
||||
(backend_in ? BIT_IMPORT : 0) +
|
||||
(backend_out ? BIT_EXPORT : 0);
|
||||
|
||||
if (setparms & BIT_BACKEND) {
|
||||
if (!NT_STATUS_IS_OK(make_pdb_context_string(&bdef, backend))) {
|
||||
fprintf(stderr, "Can't initialize passdb backend.\n");
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (!NT_STATUS_IS_OK(make_pdb_context_list(&bdef, lp_passdb_backend()))) {
|
||||
fprintf(stderr, "Can't initialize passdb backend.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* the lowest bit options are always accepted */
|
||||
checkparms = setparms & ~MASK_ALWAYS_GOOD;
|
||||
|
||||
/* account policy operations */
|
||||
if ((checkparms & BIT_ACCPOLICY) && !(checkparms & ~(BIT_ACCPOLICY + BIT_ACCPOLVAL))) {
|
||||
uint32 value;
|
||||
int field = account_policy_name_to_fieldnum(account_policy);
|
||||
if (field == 0) {
|
||||
fprintf(stderr, "No account policy by that name\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!account_policy_get(field, &value)) {
|
||||
fprintf(stderr, "valid account policy, but unable to fetch value!\n");
|
||||
exit(1);
|
||||
}
|
||||
if (account_policy_value_set) {
|
||||
printf("account policy value for %s was %u\n", account_policy, value);
|
||||
if (!account_policy_set(field, account_policy_value)) {
|
||||
fprintf(stderr, "valid account policy, but unable to set value!\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("account policy value for %s is now %lu\n", account_policy, account_policy_value);
|
||||
exit(0);
|
||||
} else {
|
||||
printf("account policy value for %s is %u\n", account_policy, value);
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* import and export operations */
|
||||
if (((checkparms & BIT_IMPORT) || (checkparms & BIT_EXPORT))
|
||||
&& !(checkparms & ~(BIT_IMPORT +BIT_EXPORT))) {
|
||||
if (backend_in) {
|
||||
if (!NT_STATUS_IS_OK(make_pdb_context_string(&bin, backend_in))) {
|
||||
fprintf(stderr, "Can't initialize passdb backend.\n");
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
bin = bdef;
|
||||
}
|
||||
if (backend_out) {
|
||||
if (!NT_STATUS_IS_OK(make_pdb_context_string(&bout, backend_out))) {
|
||||
fprintf(stderr, "Can't initialize %s.\n", backend_out);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
bout = bdef;
|
||||
}
|
||||
return export_database(bin, bout);
|
||||
}
|
||||
|
||||
/* if BIT_USER is defined but nothing else then threat it as -l -u for compatibility */
|
||||
/* fake up BIT_LIST if only BIT_USER is defined */
|
||||
if ((checkparms & BIT_USER) && !(checkparms & ~BIT_USER)) {
|
||||
checkparms += BIT_LIST;
|
||||
}
|
||||
|
||||
/* modify flag is optional to maintain backwards compatibility */
|
||||
/* fake up BIT_MODIFY if BIT_USER and at least one of MASK_USER_GOOD is defined */
|
||||
if (!((checkparms & ~MASK_USER_GOOD) & ~BIT_USER) && (checkparms & MASK_USER_GOOD)) {
|
||||
checkparms += BIT_MODIFY;
|
||||
}
|
||||
|
||||
/* list users operations */
|
||||
if (checkparms & BIT_LIST) {
|
||||
if (!(checkparms & ~BIT_LIST)) {
|
||||
return print_users_list (bdef, verbose, spstyle);
|
||||
}
|
||||
if (!(checkparms & ~(BIT_USER + BIT_LIST))) {
|
||||
return print_user_info (bdef, user_name, verbose, spstyle);
|
||||
}
|
||||
}
|
||||
|
||||
/* mask out users options */
|
||||
checkparms &= ~MASK_USER_GOOD;
|
||||
|
||||
/* account operation */
|
||||
if ((checkparms & BIT_CREATE) || (checkparms & BIT_MODIFY) || (checkparms & BIT_DELETE)) {
|
||||
/* check use of -u option */
|
||||
if (!(checkparms & BIT_USER)) {
|
||||
fprintf (stderr, "Username not specified! (use -u option)\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* account creation operations */
|
||||
if (!(checkparms & ~(BIT_CREATE + BIT_USER + BIT_MACHINE))) {
|
||||
if (checkparms & BIT_MACHINE) {
|
||||
return new_machine (bdef, user_name);
|
||||
} else {
|
||||
return new_user (bdef, user_name, full_name, home_dir,
|
||||
home_drive, logon_script,
|
||||
profile_path);
|
||||
}
|
||||
}
|
||||
|
||||
/* account deletion operations */
|
||||
if (!(checkparms & ~(BIT_DELETE + BIT_USER + BIT_MACHINE))) {
|
||||
if (checkparms & BIT_MACHINE) {
|
||||
return delete_machine_entry (bdef, user_name);
|
||||
} else {
|
||||
return delete_user_entry (bdef, user_name);
|
||||
}
|
||||
}
|
||||
|
||||
/* account modification operations */
|
||||
if (!(checkparms & ~(BIT_MODIFY + BIT_USER))) {
|
||||
return set_user_info (bdef, user_name, full_name,
|
||||
home_dir,
|
||||
home_drive,
|
||||
logon_script,
|
||||
profile_path, account_control);
|
||||
}
|
||||
}
|
||||
|
||||
if (setparms >= 0x20) {
|
||||
fprintf (stderr, "Incompatible or insufficient options on command line!\n");
|
||||
}
|
||||
poptPrintHelp(pc, stderr, 0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
729
source/utils/profiles.c
Normal file
729
source/utils/profiles.c
Normal file
@@ -0,0 +1,729 @@
|
||||
/*
|
||||
Samba Unix/Linux SMB client utility profiles.c
|
||||
Copyright (C) 2002 Richard Sharpe, rsharpe@richardsharpe.com
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/*************************************************************************
|
||||
|
||||
A utility to report and change SIDs in registry files
|
||||
|
||||
Many of the ideas in here come from other people and software.
|
||||
I first looked in Wine in misc/registry.c and was also influenced by
|
||||
http://www.wednesday.demon.co.uk/dosreg.html
|
||||
|
||||
Which seems to contain comments from someone else. I reproduce them here
|
||||
incase the site above disappears. It actually comes from
|
||||
http://home.eunet.no/~pnordahl/ntpasswd/WinReg.txt.
|
||||
|
||||
The windows NT registry has 2 different blocks, where one can occure many
|
||||
times...
|
||||
|
||||
the "regf"-Block
|
||||
================
|
||||
|
||||
"regf" is obviosly the abbreviation for "Registry file". "regf" is the
|
||||
signature of the header-block which is always 4kb in size, although only
|
||||
the first 64 bytes seem to be used and a checksum is calculated over
|
||||
the first 0x200 bytes only!
|
||||
|
||||
Offset Size Contents
|
||||
0x00000000 D-Word ID: ASCII-"regf" = 0x66676572
|
||||
0x00000004 D-Word ???? //see struct REGF
|
||||
0x00000008 D-Word ???? Always the same value as at 0x00000004
|
||||
0x0000000C Q-Word last modify date in WinNT date-format
|
||||
0x00000014 D-Word 1
|
||||
0x00000018 D-Word 3
|
||||
0x0000001C D-Word 0
|
||||
0x00000020 D-Word 1
|
||||
0x00000024 D-Word Offset of 1st key record
|
||||
0x00000028 D-Word Size of the data-blocks (Filesize-4kb)
|
||||
0x0000002C D-Word 1
|
||||
0x000001FC D-Word Sum of all D-Words from 0x00000000 to
|
||||
0x000001FB //XOR of all words. Nigel
|
||||
|
||||
I have analyzed more registry files (from multiple machines running
|
||||
NT 4.0 german version) and could not find an explanation for the values
|
||||
marked with ???? the rest of the first 4kb page is not important...
|
||||
|
||||
the "hbin"-Block
|
||||
================
|
||||
I don't know what "hbin" stands for, but this block is always a multiple
|
||||
of 4kb in size.
|
||||
|
||||
Inside these hbin-blocks the different records are placed. The memory-
|
||||
management looks like a C-compiler heap management to me...
|
||||
|
||||
hbin-Header
|
||||
===========
|
||||
Offset Size Contents
|
||||
0x0000 D-Word ID: ASCII-"hbin" = 0x6E696268
|
||||
0x0004 D-Word Offset from the 1st hbin-Block
|
||||
0x0008 D-Word Offset to the next hbin-Block
|
||||
0x001C D-Word Block-size
|
||||
|
||||
The values in 0x0008 and 0x001C should be the same, so I don't know
|
||||
if they are correct or swapped...
|
||||
|
||||
From offset 0x0020 inside a hbin-block data is stored with the following
|
||||
format:
|
||||
|
||||
Offset Size Contents
|
||||
0x0000 D-Word Data-block size //this size must be a
|
||||
multiple of 8. Nigel
|
||||
0x0004 ???? Data
|
||||
|
||||
If the size field is negative (bit 31 set), the corresponding block
|
||||
is free and has a size of -blocksize!
|
||||
|
||||
The data is stored as one record per block. Block size is a multiple
|
||||
of 4 and the last block reaches the next hbin-block, leaving no room.
|
||||
|
||||
Records in the hbin-blocks
|
||||
==========================
|
||||
|
||||
nk-Record
|
||||
|
||||
The nk-record can be treated as a kombination of tree-record and
|
||||
key-record of the win 95 registry.
|
||||
|
||||
lf-Record
|
||||
|
||||
The lf-record is the counterpart to the RGKN-record (the
|
||||
hash-function)
|
||||
|
||||
vk-Record
|
||||
|
||||
The vk-record consists information to a single value.
|
||||
|
||||
sk-Record
|
||||
|
||||
sk (? Security Key ?) is the ACL of the registry.
|
||||
|
||||
Value-Lists
|
||||
|
||||
The value-lists contain information about which values are inside a
|
||||
sub-key and don't have a header.
|
||||
|
||||
Datas
|
||||
|
||||
The datas of the registry are (like the value-list) stored without a
|
||||
header.
|
||||
|
||||
All offset-values are relative to the first hbin-block and point to the
|
||||
block-size field of the record-entry. to get the file offset, you have to add
|
||||
the header size (4kb) and the size field (4 bytes)...
|
||||
|
||||
the nk-Record
|
||||
=============
|
||||
Offset Size Contents
|
||||
0x0000 Word ID: ASCII-"nk" = 0x6B6E
|
||||
0x0002 Word for the root-key: 0x2C, otherwise 0x20 //key symbolic links 0x10. Nigel
|
||||
0x0004 Q-Word write-date/time in windows nt notation
|
||||
0x0010 D-Word Offset of Owner/Parent key
|
||||
0x0014 D-Word number of sub-Keys
|
||||
0x001C D-Word Offset of the sub-key lf-Records
|
||||
0x0024 D-Word number of values
|
||||
0x0028 D-Word Offset of the Value-List
|
||||
0x002C D-Word Offset of the sk-Record
|
||||
|
||||
0x0030 D-Word Offset of the Class-Name //see NK structure for the use of these fields. Nigel
|
||||
0x0044 D-Word Unused (data-trash) //some kind of run time index. Does not appear to be important. Nigel
|
||||
0x0048 Word name-length
|
||||
0x004A Word class-name length
|
||||
0x004C ???? key-name
|
||||
|
||||
the Value-List
|
||||
==============
|
||||
Offset Size Contents
|
||||
0x0000 D-Word Offset 1st Value
|
||||
0x0004 D-Word Offset 2nd Value
|
||||
0x???? D-Word Offset nth Value
|
||||
|
||||
To determine the number of values, you have to look at the owner-nk-record!
|
||||
|
||||
Der vk-Record
|
||||
=============
|
||||
Offset Size Contents
|
||||
0x0000 Word ID: ASCII-"vk" = 0x6B76
|
||||
0x0002 Word name length
|
||||
0x0004 D-Word length of the data //if top bit is set when offset contains data. Nigel
|
||||
0x0008 D-Word Offset of Data
|
||||
0x000C D-Word Type of value
|
||||
0x0010 Word Flag
|
||||
0x0012 Word Unused (data-trash)
|
||||
0x0014 ???? Name
|
||||
|
||||
If bit 0 of the flag-word is set, a name is present, otherwise the value has no name (=default)
|
||||
|
||||
If the data-size is lower 5, the data-offset value is used to store the data itself!
|
||||
|
||||
The data-types
|
||||
==============
|
||||
Wert Beteutung
|
||||
0x0001 RegSZ: character string (in UNICODE!)
|
||||
0x0002 ExpandSZ: string with "%var%" expanding (UNICODE!)
|
||||
0x0003 RegBin: raw-binary value
|
||||
0x0004 RegDWord: Dword
|
||||
0x0007 RegMultiSZ: multiple strings, separated with 0
|
||||
(UNICODE!)
|
||||
|
||||
The "lf"-record
|
||||
===============
|
||||
Offset Size Contents
|
||||
0x0000 Word ID: ASCII-"lf" = 0x666C
|
||||
0x0002 Word number of keys
|
||||
0x0004 ???? Hash-Records
|
||||
|
||||
Hash-Record
|
||||
===========
|
||||
Offset Size Contents
|
||||
0x0000 D-Word Offset of corresponding "nk"-Record
|
||||
0x0004 D-Word ASCII: the first 4 characters of the key-name, padded with 0's. Case sensitiv!
|
||||
|
||||
Keep in mind, that the value at 0x0004 is used for checking the data-consistency! If you change the
|
||||
key-name you have to change the hash-value too!
|
||||
|
||||
//These hashrecords must be sorted low to high within the lf record. Nigel.
|
||||
|
||||
The "sk"-block
|
||||
==============
|
||||
(due to the complexity of the SAM-info, not clear jet)
|
||||
|
||||
Offset Size Contents
|
||||
0x0000 Word ID: ASCII-"sk" = 0x6B73
|
||||
0x0002 Word Unused
|
||||
0x0004 D-Word Offset of previous "sk"-Record
|
||||
0x0008 D-Word Offset of next "sk"-Record
|
||||
0x000C D-Word usage-counter
|
||||
0x0010 D-Word Size of "sk"-record in bytes
|
||||
???? //standard self
|
||||
relative security desciptor. Nigel
|
||||
???? ???? Security and auditing settings...
|
||||
????
|
||||
|
||||
The usage counter counts the number of references to this
|
||||
"sk"-record. You can use one "sk"-record for the entire registry!
|
||||
|
||||
Windows nt date/time format
|
||||
===========================
|
||||
The time-format is a 64-bit integer which is incremented every
|
||||
0,0000001 seconds by 1 (I don't know how accurate it realy is!)
|
||||
It starts with 0 at the 1st of january 1601 0:00! All values are
|
||||
stored in GMT time! The time-zone is important to get the real
|
||||
time!
|
||||
|
||||
Common values for win95 and win-nt
|
||||
==================================
|
||||
Offset values marking an "end of list", are either 0 or -1 (0xFFFFFFFF).
|
||||
If a value has no name (length=0, flag(bit 0)=0), it is treated as the
|
||||
"Default" entry...
|
||||
If a value has no data (length=0), it is displayed as empty.
|
||||
|
||||
simplyfied win-3.?? registry:
|
||||
=============================
|
||||
|
||||
+-----------+
|
||||
| next rec. |---+ +----->+------------+
|
||||
| first sub | | | | Usage cnt. |
|
||||
| name | | +-->+------------+ | | length |
|
||||
| value | | | | next rec. | | | text |------->+-------+
|
||||
+-----------+ | | | name rec. |--+ +------------+ | xxxxx |
|
||||
+------------+ | | value rec. |-------->+------------+ +-------+
|
||||
v | +------------+ | Usage cnt. |
|
||||
+-----------+ | | length |
|
||||
| next rec. | | | text |------->+-------+
|
||||
| first sub |------+ +------------+ | xxxxx |
|
||||
| name | +-------+
|
||||
| value |
|
||||
+-----------+
|
||||
|
||||
Greatly simplyfied structure of the nt-registry:
|
||||
================================================
|
||||
|
||||
+---------------------------------------------------------------+
|
||||
| |
|
||||
v |
|
||||
+---------+ +---------->+-----------+ +----->+---------+ |
|
||||
| "nk" | | | lf-rec. | | | nk-rec. | |
|
||||
| ID | | | # of keys | | | parent |---+
|
||||
| Date | | | 1st key |--+ | .... |
|
||||
| parent | | +-----------+ +---------+
|
||||
| suk-keys|-----+
|
||||
| values |--------------------->+----------+
|
||||
| SK-rec. |---------------+ | 1. value |--> +----------+
|
||||
| class |--+ | +----------+ | vk-rec. |
|
||||
+---------+ | | | .... |
|
||||
v | | data |--> +-------+
|
||||
+------------+ | +----------+ | xxxxx |
|
||||
| Class name | | +-------+
|
||||
+------------+ |
|
||||
v
|
||||
+---------+ +---------+
|
||||
+----->| next sk |--->| Next sk |--+
|
||||
| +---| prev sk |<---| prev sk | |
|
||||
| | | .... | | ... | |
|
||||
| | +---------+ +---------+ |
|
||||
| | ^ | |
|
||||
| +----------+ |
|
||||
+-------------------------------+
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Hope this helps.... (Although it was "fun" for me to uncover this things,
|
||||
it took me several sleepless nights ;)
|
||||
|
||||
B.D.
|
||||
|
||||
*************************************************************************/
|
||||
#include "includes.h"
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
typedef unsigned int DWORD;
|
||||
typedef unsigned short WORD;
|
||||
|
||||
#define REG_REGF_ID 0x66676572
|
||||
|
||||
typedef struct regf_block {
|
||||
DWORD REGF_ID; /* regf */
|
||||
DWORD uk1;
|
||||
DWORD uk2;
|
||||
DWORD tim1, tim2;
|
||||
DWORD uk3; /* 1 */
|
||||
DWORD uk4; /* 3 */
|
||||
DWORD uk5; /* 0 */
|
||||
DWORD uk6; /* 1 */
|
||||
DWORD first_key; /* offset */
|
||||
unsigned int dblk_size;
|
||||
DWORD uk7[116]; /* 1 */
|
||||
DWORD chksum;
|
||||
} REGF_HDR;
|
||||
|
||||
typedef struct hbin_sub_struct {
|
||||
DWORD dblocksize;
|
||||
char data[1];
|
||||
} HBIN_SUB_HDR;
|
||||
|
||||
#define REG_HBIN_ID 0x6E696268
|
||||
|
||||
typedef struct hbin_struct {
|
||||
DWORD HBIN_ID; /* hbin */
|
||||
DWORD next_off;
|
||||
DWORD prev_off;
|
||||
DWORD uk1;
|
||||
DWORD uk2;
|
||||
DWORD uk3;
|
||||
DWORD uk4;
|
||||
DWORD blk_size;
|
||||
HBIN_SUB_HDR hbin_sub_hdr;
|
||||
} HBIN_HDR;
|
||||
|
||||
#define REG_NK_ID 0x6B6E
|
||||
|
||||
typedef struct nk_struct {
|
||||
WORD NK_ID;
|
||||
WORD type;
|
||||
DWORD t1, t2;
|
||||
DWORD uk1;
|
||||
DWORD own_off;
|
||||
DWORD subk_num;
|
||||
DWORD uk2;
|
||||
DWORD lf_off;
|
||||
DWORD uk3;
|
||||
DWORD val_cnt;
|
||||
DWORD val_off;
|
||||
DWORD sk_off;
|
||||
DWORD clsnam_off;
|
||||
} NK_HDR;
|
||||
|
||||
#define REG_SK_ID 0x6B73
|
||||
|
||||
typedef struct sk_struct {
|
||||
WORD SK_ID;
|
||||
WORD uk1;
|
||||
DWORD prev_off;
|
||||
DWORD next_off;
|
||||
DWORD ref_cnt;
|
||||
DWORD rec_size;
|
||||
char sec_desc[1];
|
||||
} SK_HDR;
|
||||
|
||||
typedef struct sec_desc_rec {
|
||||
WORD rev;
|
||||
WORD type;
|
||||
DWORD owner_off;
|
||||
DWORD group_off;
|
||||
DWORD sacl_off;
|
||||
DWORD dacl_off;
|
||||
} MY_SEC_DESC;
|
||||
|
||||
typedef struct ace_struct {
|
||||
unsigned char type;
|
||||
unsigned char flags;
|
||||
unsigned short length;
|
||||
unsigned int perms;
|
||||
DOM_SID trustee;
|
||||
} ACE;
|
||||
|
||||
typedef struct acl_struct {
|
||||
WORD rev;
|
||||
WORD size;
|
||||
DWORD num_aces;
|
||||
ACE *aces; /* One or more ACEs */
|
||||
} ACL;
|
||||
|
||||
#define OFF(f) (0x1000 + (f) + 4)
|
||||
|
||||
static void print_sid(DOM_SID *sid);
|
||||
|
||||
int verbose = 1;
|
||||
DOM_SID old_sid, new_sid;
|
||||
int change = 0, new = 0;
|
||||
|
||||
/* Compare two SIDs for equality */
|
||||
static int my_sid_equal(DOM_SID *s1, DOM_SID *s2)
|
||||
{
|
||||
int sa1, sa2;
|
||||
|
||||
if (s1->sid_rev_num != s2->sid_rev_num) return 0;
|
||||
|
||||
sa1 = s1->num_auths; sa2 = s2->num_auths;
|
||||
|
||||
if (sa1 != sa2) return 0;
|
||||
|
||||
return !memcmp((char *)&s1->id_auth, (char *)&s2->id_auth,
|
||||
6 + sa1 * 4);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Quick and dirty to read a SID in S-1-5-21-x-y-z-rid format and
|
||||
* construct a DOM_SID
|
||||
*/
|
||||
static int get_sid(DOM_SID *sid, char *sid_str)
|
||||
{
|
||||
int i = 0, auth;
|
||||
char *lstr;
|
||||
|
||||
if (strncmp(sid_str, "S-1-5", 5)) {
|
||||
fprintf(stderr, "Does not conform to S-1-5...: %s\n", sid_str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We only allow strings of form S-1-5... */
|
||||
|
||||
sid->sid_rev_num = 1;
|
||||
sid->id_auth[5] = 5;
|
||||
|
||||
lstr = sid_str + 5;
|
||||
|
||||
while (1) {
|
||||
if (!lstr || !lstr[0] || sscanf(lstr, "-%u", &auth) == 0) {
|
||||
if (i < 4) {
|
||||
fprintf(stderr, "Not of form -d-d...: %s, %u\n", lstr, i);
|
||||
return 0;
|
||||
}
|
||||
sid->num_auths=i;
|
||||
print_sid(sid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SIVAL(&sid->sub_auths[i], 0, auth);
|
||||
i++;
|
||||
lstr = strchr(lstr + 1, '-');
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace SID1, component by component with SID2
|
||||
* Assumes will never be called with unequal length SIDS
|
||||
* so only touches 21-x-y-z-rid portion
|
||||
* This routine does not need to deal with endianism as
|
||||
* long as the incoming SIDs are both in the same (LE) format.
|
||||
*/
|
||||
static void change_sid(DOM_SID *s1, DOM_SID *s2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<s1->num_auths; i++) {
|
||||
s1->sub_auths[i] = s2->sub_auths[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void print_sid(DOM_SID *sid)
|
||||
{
|
||||
int i, comps = sid->num_auths;
|
||||
fprintf(stdout, "S-%u-%u", sid->sid_rev_num, sid->id_auth[5]);
|
||||
|
||||
for (i = 0; i < comps; i++) {
|
||||
|
||||
fprintf(stdout, "-%u", IVAL(&sid->sub_auths[i],0));
|
||||
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
static void process_sid(DOM_SID *sid, DOM_SID *o_sid, DOM_SID *n_sid)
|
||||
{
|
||||
int i;
|
||||
if (my_sid_equal(sid, o_sid)) {
|
||||
|
||||
for (i=0; i<sid->num_auths; i++) {
|
||||
sid->sub_auths[i] = n_sid->sub_auths[i];
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void process_acl(ACL *acl, const char *prefix)
|
||||
{
|
||||
int ace_cnt, i;
|
||||
ACE *ace;
|
||||
|
||||
ace_cnt = IVAL(&acl->num_aces, 0);
|
||||
ace = (ACE *)&acl->aces;
|
||||
if (verbose) fprintf(stdout, "%sACEs: %u\n", prefix, ace_cnt);
|
||||
for (i=0; i<ace_cnt; i++) {
|
||||
if (verbose) fprintf(stdout, "%s Perms: %08X, SID: ", prefix,
|
||||
IVAL(&ace->perms, 0));
|
||||
if (change)
|
||||
process_sid(&ace->trustee, &old_sid, &new_sid);
|
||||
print_sid(&ace->trustee);
|
||||
ace = (ACE *)((char *)ace + SVAL(&ace->length, 0));
|
||||
}
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: profiles [-c <OLD-SID> -n <NEW-SID>] <profilefile>\n");
|
||||
fprintf(stderr, "Version: %s\n", VERSION);
|
||||
fprintf(stderr, "\n\t-v\t sets verbose mode");
|
||||
fprintf(stderr, "\n\t-c S-1-5-21-z-y-x-oldrid - provides SID to change");
|
||||
fprintf(stderr, "\n\t-n S-1-5-21-a-b-c-newrid - provides SID to change to");
|
||||
fprintf(stderr, "\n\t\tBoth must be present if the other is.");
|
||||
fprintf(stderr, "\n\t\tIf neither present, just report the SIDs found\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
int opt;
|
||||
int fd, start = 0;
|
||||
char *base;
|
||||
struct stat sbuf;
|
||||
REGF_HDR *regf_hdr;
|
||||
HBIN_HDR *hbin_hdr;
|
||||
NK_HDR *nk_hdr;
|
||||
SK_HDR *sk_hdr;
|
||||
DWORD first_sk_off, sk_off;
|
||||
MY_SEC_DESC *sec_desc;
|
||||
int *ptr;
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now, process the arguments
|
||||
*/
|
||||
|
||||
while ((opt = getopt(argc, argv, "c:n:v")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'c':
|
||||
change = 1;
|
||||
if (!get_sid(&old_sid, optarg)) {
|
||||
fprintf(stderr, "Argument to -c should be a SID in form of S-1-5-...\n");
|
||||
usage();
|
||||
exit(254);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
new = 1;
|
||||
if (!get_sid(&new_sid, optarg)) {
|
||||
fprintf(stderr, "Argument to -n should be a SID in form of S-1-5-...\n");
|
||||
usage();
|
||||
exit(253);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
|
||||
default:
|
||||
usage();
|
||||
exit(255);
|
||||
}
|
||||
}
|
||||
|
||||
if ((!change & new) || (change & !new)) {
|
||||
fprintf(stderr, "You must specify both -c and -n if one or the other is set!\n");
|
||||
usage();
|
||||
exit(252);
|
||||
}
|
||||
|
||||
fd = open(argv[optind], O_RDWR, 0000);
|
||||
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "Could not open %s: %s\n", argv[optind],
|
||||
strerror(errno));
|
||||
exit(2);
|
||||
}
|
||||
|
||||
if (fstat(fd, &sbuf) < 0) {
|
||||
fprintf(stderr, "Could not stat file %s, %s\n", argv[optind],
|
||||
strerror(errno));
|
||||
exit(3);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now, mmap the file into memory, check the header and start
|
||||
* dealing with the records. We are interested in the sk record
|
||||
*/
|
||||
start = 0;
|
||||
base = mmap(&start, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
|
||||
if ((int)base == -1) {
|
||||
fprintf(stderr, "Could not mmap file: %s, %s\n", argv[optind],
|
||||
strerror(errno));
|
||||
exit(4);
|
||||
}
|
||||
|
||||
/*
|
||||
* In what follows, and in places above, in order to work on both LE and
|
||||
* BE platforms, we have to use the Samba macros to extract SHORT, LONG
|
||||
* and associated UNSIGNED quantities from the data in the mmap'd file.
|
||||
* NOTE, however, that we do not need to do anything with memory
|
||||
* addresses that we construct from pointers in our address space.
|
||||
* For example,
|
||||
*
|
||||
* sec_desc = (MY_SEC_DESC *)&(sk_hdr->sec_desc[0]);
|
||||
*
|
||||
* is simply taking the address of a structure we already have the address
|
||||
* of in our address space, while, the fields within it, will have to
|
||||
* be accessed with the macros:
|
||||
*
|
||||
* owner_sid = (DOM_SID *)(&sk_hdr->sec_desc[0] +
|
||||
* IVAL(&sec_desc->owner_off, 0));
|
||||
*
|
||||
* Which is pulling out an offset and adding it to an existing pointer.
|
||||
*
|
||||
*/
|
||||
|
||||
regf_hdr = (REGF_HDR *)base;
|
||||
|
||||
if (verbose) fprintf(stdout, "Registry file size: %u\n", (unsigned int)sbuf.st_size);
|
||||
|
||||
if (IVAL(®f_hdr->REGF_ID, 0) != REG_REGF_ID) {
|
||||
fprintf(stderr, "Incorrect Registry file (doesn't have header ID): %s\n", argv[optind]);
|
||||
exit(5);
|
||||
}
|
||||
|
||||
if (verbose) fprintf(stdout, "First Key Off: %u, Data Block Size: %u\n",
|
||||
IVAL(®f_hdr->first_key, 0),
|
||||
IVAL(®f_hdr->dblk_size, 0));
|
||||
|
||||
hbin_hdr = (HBIN_HDR *)(base + 0x1000); /* No need for Endian stuff */
|
||||
|
||||
/*
|
||||
* This should be the hbin_hdr
|
||||
*/
|
||||
|
||||
if (IVAL(&hbin_hdr->HBIN_ID, 0) != REG_HBIN_ID) {
|
||||
fprintf(stderr, "Incorrect hbin hdr: %s\n", argv[optind]);
|
||||
exit(6);
|
||||
}
|
||||
|
||||
if (verbose) fprintf(stdout, "Next Off: %u, Prev Off: %u\n",
|
||||
IVAL(&hbin_hdr->next_off, 0),
|
||||
IVAL(&hbin_hdr->prev_off, 0));
|
||||
|
||||
nk_hdr = (NK_HDR *)(base + 0x1000 + IVAL(®f_hdr->first_key, 0) + 4);
|
||||
|
||||
if (SVAL(&nk_hdr->NK_ID, 0) != REG_NK_ID) {
|
||||
fprintf(stderr, "Incorrect NK Header: %s\n", argv[optind]);
|
||||
exit(7);
|
||||
}
|
||||
|
||||
sk_off = first_sk_off = IVAL(&nk_hdr->sk_off, 0);
|
||||
if (verbose) {
|
||||
fprintf(stdout, "Type: %0x\n", SVAL(&nk_hdr->type, 0));
|
||||
fprintf(stdout, "SK Off : %o\n", (0x1000 + sk_off + 4));
|
||||
}
|
||||
|
||||
sk_hdr = (SK_HDR *)(base + 0x1000 + sk_off + 4);
|
||||
|
||||
do {
|
||||
DOM_SID *owner_sid, *group_sid;
|
||||
ACL *sacl, *dacl;
|
||||
if (SVAL(&sk_hdr->SK_ID, 0) != REG_SK_ID) {
|
||||
fprintf(stderr, "Incorrect SK Header format: %08X\n",
|
||||
(0x1000 + sk_off + 4));
|
||||
exit(8);
|
||||
}
|
||||
ptr = (int *)sk_hdr;
|
||||
if (verbose) fprintf(stdout, "Off: %08X, Refs: %u, Size: %u\n",
|
||||
sk_off, IVAL(&sk_hdr->ref_cnt, 0),
|
||||
IVAL(&sk_hdr->rec_size, 0));
|
||||
|
||||
sec_desc = (MY_SEC_DESC *)&(sk_hdr->sec_desc[0]);
|
||||
owner_sid = (DOM_SID *)(&sk_hdr->sec_desc[0] +
|
||||
IVAL(&sec_desc->owner_off, 0));
|
||||
group_sid = (DOM_SID *)(&sk_hdr->sec_desc[0] +
|
||||
IVAL(&sec_desc->group_off, 0));
|
||||
sacl = (ACL *)(&sk_hdr->sec_desc[0] +
|
||||
IVAL(&sec_desc->sacl_off, 0));
|
||||
dacl = (ACL *)(&sk_hdr->sec_desc[0] +
|
||||
IVAL(&sec_desc->dacl_off, 0));
|
||||
if (verbose)fprintf(stdout, " Owner SID: ");
|
||||
if (change) process_sid(owner_sid, &old_sid, &new_sid);
|
||||
if (verbose) print_sid(owner_sid);
|
||||
if (verbose) fprintf(stdout, " Group SID: ");
|
||||
if (change) process_sid(group_sid, &old_sid, &new_sid);
|
||||
if (verbose) print_sid(group_sid);
|
||||
fprintf(stdout, " SACL: ");
|
||||
if (!sec_desc->sacl_off) { /* LE zero == BE zero */
|
||||
if (verbose) fprintf(stdout, "NONE\n");
|
||||
}
|
||||
else
|
||||
process_acl(sacl, " ");
|
||||
if (verbose) fprintf(stdout, " DACL: ");
|
||||
if (!sec_desc->dacl_off) {
|
||||
if (verbose) fprintf(stdout, "NONE\n");
|
||||
}
|
||||
else
|
||||
process_acl(dacl, " ");
|
||||
sk_off = IVAL(&sk_hdr->prev_off, 0);
|
||||
sk_hdr = (SK_HDR *)(base + OFF(IVAL(&sk_hdr->prev_off, 0)));
|
||||
} while (sk_off != first_sk_off);
|
||||
|
||||
munmap(base, sbuf.st_size);
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
32
source/utils/rewrite.c
Normal file
32
source/utils/rewrite.c
Normal file
@@ -0,0 +1,32 @@
|
||||
#include "includes.h"
|
||||
|
||||
/*
|
||||
|
||||
this is a set of temporary stub functions used during the samba4 rewrite.
|
||||
This file will need to go away before the rewrite is complete.
|
||||
*/
|
||||
|
||||
BOOL become_user_permanently(uid_t uid, gid_t gid)
|
||||
{ return True; }
|
||||
|
||||
BOOL is_setuid_root(void)
|
||||
{ return False; }
|
||||
|
||||
int share_mode_forall(SHAREMODE_FN(fn))
|
||||
{ return 0; }
|
||||
|
||||
#define BRLOCK_FN(fn) \
|
||||
void (*fn)(SMB_DEV_T dev, SMB_INO_T ino, int pid, \
|
||||
enum brl_type lock_type, \
|
||||
br_off start, br_off size)
|
||||
int brl_forall(BRLOCK_FN(fn))
|
||||
{ return 0; }
|
||||
|
||||
BOOL locking_end(void)
|
||||
{ return True; }
|
||||
|
||||
BOOL locking_init(int read_only)
|
||||
{ return True; }
|
||||
|
||||
uid_t sec_initial_gid(void)
|
||||
{ return 0; }
|
||||
62
source/utils/rpccheck.c
Normal file
62
source/utils/rpccheck.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Copyright (C) Jean Fran<61>ois Micouleau 2001
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
main()
|
||||
{
|
||||
char filter[]="0123456789ABCDEF";
|
||||
|
||||
char s[128];
|
||||
char d=0;
|
||||
int x=0;
|
||||
prs_struct ps;
|
||||
TALLOC_CTX *ctx;
|
||||
|
||||
/* change that struct */
|
||||
SAMR_R_QUERY_USERINFO rpc_stub;
|
||||
|
||||
ZERO_STRUCT(rpc_stub);
|
||||
|
||||
setup_logging("", True);
|
||||
DEBUGLEVEL=10;
|
||||
|
||||
ctx=talloc_init("main");
|
||||
if (!ctx) exit(1);
|
||||
|
||||
prs_init(&ps, 1600, 4, ctx, MARSHALL);
|
||||
|
||||
while (scanf("%s", s)!=-1) {
|
||||
if (strlen(s)==2 && strchr_m(filter, *s)!=NULL && strchr_m(filter, *(s+1))!=NULL) {
|
||||
d=strtol(s, NULL, 16);
|
||||
if(!prs_append_data(&ps, &d, 1))
|
||||
printf("error while reading data\n");
|
||||
}
|
||||
}
|
||||
|
||||
prs_switch_type(&ps, UNMARSHALL);
|
||||
prs_set_offset(&ps, 0);
|
||||
|
||||
/* change that call */
|
||||
if(!samr_io_r_query_userinfo("", &rpc_stub, &ps, 0))
|
||||
printf("error while UNMARSHALLING the data\n");
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
937
source/utils/smbcacls.c
Normal file
937
source/utils/smbcacls.c
Normal file
@@ -0,0 +1,937 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
ACL get/set utility
|
||||
|
||||
Copyright (C) Andrew Tridgell 2000
|
||||
Copyright (C) Tim Potter 2000
|
||||
Copyright (C) Jeremy Allison 2000
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
static fstring password;
|
||||
static pstring username;
|
||||
static pstring owner_username;
|
||||
static fstring server;
|
||||
static int got_pass;
|
||||
static int test_args;
|
||||
static TALLOC_CTX *ctx;
|
||||
|
||||
#define CREATE_ACCESS_READ READ_CONTROL_ACCESS
|
||||
#define CREATE_ACCESS_WRITE (WRITE_DAC_ACCESS | WRITE_OWNER_ACCESS)
|
||||
|
||||
/* numeric is set when the user wants numeric SIDs and ACEs rather
|
||||
than going via LSA calls to resolve them */
|
||||
static int numeric;
|
||||
|
||||
enum acl_mode {SMB_ACL_SET, SMB_ACL_DELETE, SMB_ACL_MODIFY, SMB_ACL_ADD };
|
||||
enum chown_mode {REQUEST_NONE, REQUEST_CHOWN, REQUEST_CHGRP};
|
||||
enum exit_values {EXIT_OK, EXIT_FAILED, EXIT_PARSE_ERROR};
|
||||
|
||||
struct perm_value {
|
||||
const char *perm;
|
||||
uint32 mask;
|
||||
};
|
||||
|
||||
/* These values discovered by inspection */
|
||||
|
||||
static const struct perm_value special_values[] = {
|
||||
{ "R", 0x00120089 },
|
||||
{ "W", 0x00120116 },
|
||||
{ "X", 0x001200a0 },
|
||||
{ "D", 0x00010000 },
|
||||
{ "P", 0x00040000 },
|
||||
{ "O", 0x00080000 },
|
||||
{ NULL, 0 },
|
||||
};
|
||||
|
||||
static const struct perm_value standard_values[] = {
|
||||
{ "READ", 0x001200a9 },
|
||||
{ "CHANGE", 0x001301bf },
|
||||
{ "FULL", 0x001f01ff },
|
||||
{ NULL, 0 },
|
||||
};
|
||||
|
||||
static struct cli_state *global_hack_cli;
|
||||
static POLICY_HND pol;
|
||||
static BOOL got_policy_hnd;
|
||||
|
||||
static struct cli_state *connect_one(const char *share);
|
||||
|
||||
/* Open cli connection and policy handle */
|
||||
|
||||
static BOOL cacls_open_policy_hnd(void)
|
||||
{
|
||||
/* Initialise cli LSA connection */
|
||||
|
||||
if (!global_hack_cli) {
|
||||
global_hack_cli = connect_one("IPC$");
|
||||
if (!cli_nt_session_open (global_hack_cli, PI_LSARPC)) {
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
/* Open policy handle */
|
||||
|
||||
if (!got_policy_hnd) {
|
||||
|
||||
/* Some systems don't support SEC_RIGHTS_MAXIMUM_ALLOWED,
|
||||
but NT sends 0x2000000 so we might as well do it too. */
|
||||
|
||||
if (!NT_STATUS_IS_OK(cli_lsa_open_policy(global_hack_cli, global_hack_cli->mem_ctx, True,
|
||||
GENERIC_EXECUTE_ACCESS, &pol))) {
|
||||
return False;
|
||||
}
|
||||
|
||||
got_policy_hnd = True;
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* convert a SID to a string, either numeric or username/group */
|
||||
static void SidToString(fstring str, DOM_SID *sid)
|
||||
{
|
||||
char **domains = NULL;
|
||||
char **names = NULL;
|
||||
uint32 *types = NULL;
|
||||
|
||||
sid_to_string(str, sid);
|
||||
|
||||
if (numeric) return;
|
||||
|
||||
/* Ask LSA to convert the sid to a name */
|
||||
|
||||
if (!cacls_open_policy_hnd() ||
|
||||
!NT_STATUS_IS_OK(cli_lsa_lookup_sids(global_hack_cli, global_hack_cli->mem_ctx,
|
||||
&pol, 1, sid, &domains,
|
||||
&names, &types)) ||
|
||||
!domains || !domains[0] || !names || !names[0]) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Converted OK */
|
||||
|
||||
slprintf(str, sizeof(fstring) - 1, "%s%s%s",
|
||||
domains[0], lp_winbind_separator(),
|
||||
names[0]);
|
||||
|
||||
}
|
||||
|
||||
/* convert a string to a SID, either numeric or username/group */
|
||||
static BOOL StringToSid(DOM_SID *sid, const char *str)
|
||||
{
|
||||
uint32 *types = NULL;
|
||||
DOM_SID *sids = NULL;
|
||||
BOOL result = True;
|
||||
|
||||
if (strncmp(str, "S-", 2) == 0) {
|
||||
return string_to_sid(sid, str);
|
||||
}
|
||||
|
||||
if (!cacls_open_policy_hnd() ||
|
||||
!NT_STATUS_IS_OK(cli_lsa_lookup_names(global_hack_cli, global_hack_cli->mem_ctx,
|
||||
&pol, 1, &str, &sids,
|
||||
&types))) {
|
||||
result = False;
|
||||
goto done;
|
||||
}
|
||||
|
||||
sid_copy(sid, &sids[0]);
|
||||
done:
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* print an ACE on a FILE, using either numeric or ascii representation */
|
||||
static void print_ace(FILE *f, SEC_ACE *ace)
|
||||
{
|
||||
const struct perm_value *v;
|
||||
fstring sidstr;
|
||||
int do_print = 0;
|
||||
uint32 got_mask;
|
||||
|
||||
SidToString(sidstr, &ace->trustee);
|
||||
|
||||
fprintf(f, "%s:", sidstr);
|
||||
|
||||
if (numeric) {
|
||||
fprintf(f, "%d/%d/0x%08x",
|
||||
ace->type, ace->flags, ace->info.mask);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ace type */
|
||||
|
||||
if (ace->type == SEC_ACE_TYPE_ACCESS_ALLOWED) {
|
||||
fprintf(f, "ALLOWED");
|
||||
} else if (ace->type == SEC_ACE_TYPE_ACCESS_DENIED) {
|
||||
fprintf(f, "DENIED");
|
||||
} else {
|
||||
fprintf(f, "%d", ace->type);
|
||||
}
|
||||
|
||||
/* Not sure what flags can be set in a file ACL */
|
||||
|
||||
fprintf(f, "/%d/", ace->flags);
|
||||
|
||||
/* Standard permissions */
|
||||
|
||||
for (v = standard_values; v->perm; v++) {
|
||||
if (ace->info.mask == v->mask) {
|
||||
fprintf(f, "%s", v->perm);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Special permissions. Print out a hex value if we have
|
||||
leftover bits in the mask. */
|
||||
|
||||
got_mask = ace->info.mask;
|
||||
|
||||
again:
|
||||
for (v = special_values; v->perm; v++) {
|
||||
if ((ace->info.mask & v->mask) == v->mask) {
|
||||
if (do_print) {
|
||||
fprintf(f, "%s", v->perm);
|
||||
}
|
||||
got_mask &= ~v->mask;
|
||||
}
|
||||
}
|
||||
|
||||
if (!do_print) {
|
||||
if (got_mask != 0) {
|
||||
fprintf(f, "0x%08x", ace->info.mask);
|
||||
} else {
|
||||
do_print = 1;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* parse an ACE in the same format as print_ace() */
|
||||
static BOOL parse_ace(SEC_ACE *ace, char *str)
|
||||
{
|
||||
char *p;
|
||||
const char *cp;
|
||||
fstring tok;
|
||||
unsigned atype, aflags, amask;
|
||||
DOM_SID sid;
|
||||
SEC_ACCESS mask;
|
||||
const struct perm_value *v;
|
||||
|
||||
ZERO_STRUCTP(ace);
|
||||
p = strchr_m(str,':');
|
||||
if (!p) return False;
|
||||
*p = '\0';
|
||||
p++;
|
||||
/* Try to parse numeric form */
|
||||
|
||||
if (sscanf(p, "%i/%i/%i", &atype, &aflags, &amask) == 3 &&
|
||||
StringToSid(&sid, str)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Try to parse text form */
|
||||
|
||||
if (!StringToSid(&sid, str)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
cp = p;
|
||||
if (!next_token(&cp, tok, "/", sizeof(fstring))) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if (strncmp(tok, "ALLOWED", strlen("ALLOWED")) == 0) {
|
||||
atype = SEC_ACE_TYPE_ACCESS_ALLOWED;
|
||||
} else if (strncmp(tok, "DENIED", strlen("DENIED")) == 0) {
|
||||
atype = SEC_ACE_TYPE_ACCESS_DENIED;
|
||||
} else {
|
||||
return False;
|
||||
}
|
||||
|
||||
/* Only numeric form accepted for flags at present */
|
||||
|
||||
if (!(next_token(&cp, tok, "/", sizeof(fstring)) &&
|
||||
sscanf(tok, "%i", &aflags))) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!next_token(&cp, tok, "/", sizeof(fstring))) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if (strncmp(tok, "0x", 2) == 0) {
|
||||
if (sscanf(tok, "%i", &amask) != 1) {
|
||||
return False;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
for (v = standard_values; v->perm; v++) {
|
||||
if (strcmp(tok, v->perm) == 0) {
|
||||
amask = v->mask;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
p = tok;
|
||||
|
||||
while(*p) {
|
||||
BOOL found = False;
|
||||
|
||||
for (v = special_values; v->perm; v++) {
|
||||
if (v->perm[0] == *p) {
|
||||
amask |= v->mask;
|
||||
found = True;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) return False;
|
||||
p++;
|
||||
}
|
||||
|
||||
if (*p) {
|
||||
return False;
|
||||
}
|
||||
|
||||
done:
|
||||
mask.mask = amask;
|
||||
init_sec_ace(ace, &sid, atype, mask, aflags);
|
||||
return True;
|
||||
}
|
||||
|
||||
/* add an ACE to a list of ACEs in a SEC_ACL */
|
||||
static BOOL add_ace(SEC_ACL **the_acl, SEC_ACE *ace)
|
||||
{
|
||||
SEC_ACL *new;
|
||||
SEC_ACE *aces;
|
||||
if (! *the_acl) {
|
||||
(*the_acl) = make_sec_acl(ctx, 3, 1, ace);
|
||||
return True;
|
||||
}
|
||||
|
||||
aces = calloc(1+(*the_acl)->num_aces,sizeof(SEC_ACE));
|
||||
memcpy(aces, (*the_acl)->ace, (*the_acl)->num_aces * sizeof(SEC_ACE));
|
||||
memcpy(aces+(*the_acl)->num_aces, ace, sizeof(SEC_ACE));
|
||||
new = make_sec_acl(ctx,(*the_acl)->revision,1+(*the_acl)->num_aces, aces);
|
||||
SAFE_FREE(aces);
|
||||
(*the_acl) = new;
|
||||
return True;
|
||||
}
|
||||
|
||||
/* parse a ascii version of a security descriptor */
|
||||
static SEC_DESC *sec_desc_parse(char *str)
|
||||
{
|
||||
const char *p = str;
|
||||
fstring tok;
|
||||
SEC_DESC *ret;
|
||||
size_t sd_size;
|
||||
DOM_SID *grp_sid=NULL, *owner_sid=NULL;
|
||||
SEC_ACL *dacl=NULL;
|
||||
int revision=1;
|
||||
|
||||
while (next_token(&p, tok, "\t,\r\n", sizeof(tok))) {
|
||||
|
||||
if (strncmp(tok,"REVISION:", 9) == 0) {
|
||||
revision = strtol(tok+9, NULL, 16);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(tok,"OWNER:", 6) == 0) {
|
||||
owner_sid = (DOM_SID *)calloc(1, sizeof(DOM_SID));
|
||||
if (!owner_sid ||
|
||||
!StringToSid(owner_sid, tok+6)) {
|
||||
printf("Failed to parse owner sid\n");
|
||||
return NULL;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(tok,"GROUP:", 6) == 0) {
|
||||
grp_sid = (DOM_SID *)calloc(1, sizeof(DOM_SID));
|
||||
if (!grp_sid ||
|
||||
!StringToSid(grp_sid, tok+6)) {
|
||||
printf("Failed to parse group sid\n");
|
||||
return NULL;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(tok,"ACL:", 4) == 0) {
|
||||
SEC_ACE ace;
|
||||
if (!parse_ace(&ace, tok+4)) {
|
||||
printf("Failed to parse ACL %s\n", tok);
|
||||
return NULL;
|
||||
}
|
||||
if(!add_ace(&dacl, &ace)) {
|
||||
printf("Failed to add ACL %s\n", tok);
|
||||
return NULL;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("Failed to parse security descriptor\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = make_sec_desc(ctx,revision, owner_sid, grp_sid,
|
||||
NULL, dacl, &sd_size);
|
||||
|
||||
SAFE_FREE(grp_sid);
|
||||
SAFE_FREE(owner_sid);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* print a ascii version of a security descriptor on a FILE handle */
|
||||
static void sec_desc_print(FILE *f, SEC_DESC *sd)
|
||||
{
|
||||
fstring sidstr;
|
||||
uint32 i;
|
||||
|
||||
printf("REVISION:%d\n", sd->revision);
|
||||
|
||||
/* Print owner and group sid */
|
||||
|
||||
if (sd->owner_sid) {
|
||||
SidToString(sidstr, sd->owner_sid);
|
||||
} else {
|
||||
fstrcpy(sidstr, "");
|
||||
}
|
||||
|
||||
printf("OWNER:%s\n", sidstr);
|
||||
|
||||
if (sd->grp_sid) {
|
||||
SidToString(sidstr, sd->grp_sid);
|
||||
} else {
|
||||
fstrcpy(sidstr, "");
|
||||
}
|
||||
|
||||
fprintf(f, "GROUP:%s\n", sidstr);
|
||||
|
||||
/* Print aces */
|
||||
for (i = 0; sd->dacl && i < sd->dacl->num_aces; i++) {
|
||||
SEC_ACE *ace = &sd->dacl->ace[i];
|
||||
fprintf(f, "ACL:");
|
||||
print_ace(f, ace);
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*****************************************************
|
||||
dump the acls for a file
|
||||
*******************************************************/
|
||||
static int cacl_dump(struct cli_state *cli, char *filename)
|
||||
{
|
||||
int result = EXIT_FAILED;
|
||||
int fnum = -1;
|
||||
SEC_DESC *sd;
|
||||
|
||||
if (test_args)
|
||||
return EXIT_OK;
|
||||
|
||||
fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ);
|
||||
|
||||
if (fnum == -1) {
|
||||
printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
|
||||
goto done;
|
||||
}
|
||||
|
||||
sd = cli_query_secdesc(cli, fnum, ctx);
|
||||
|
||||
if (!sd) {
|
||||
printf("ERROR: secdesc query failed: %s\n", cli_errstr(cli));
|
||||
goto done;
|
||||
}
|
||||
|
||||
sec_desc_print(stdout, sd);
|
||||
|
||||
result = EXIT_OK;
|
||||
|
||||
done:
|
||||
if (fnum != -1)
|
||||
cli_close(cli, fnum);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*****************************************************
|
||||
Change the ownership or group ownership of a file. Just
|
||||
because the NT docs say this can't be done :-). JRA.
|
||||
*******************************************************/
|
||||
|
||||
static int owner_set(struct cli_state *cli, enum chown_mode change_mode,
|
||||
char *filename, char *new_username)
|
||||
{
|
||||
int fnum;
|
||||
DOM_SID sid;
|
||||
SEC_DESC *sd, *old;
|
||||
size_t sd_size;
|
||||
|
||||
fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ);
|
||||
|
||||
if (fnum == -1) {
|
||||
printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
|
||||
return EXIT_FAILED;
|
||||
}
|
||||
|
||||
if (!StringToSid(&sid, new_username))
|
||||
return EXIT_PARSE_ERROR;
|
||||
|
||||
old = cli_query_secdesc(cli, fnum, ctx);
|
||||
|
||||
cli_close(cli, fnum);
|
||||
|
||||
if (!old) {
|
||||
printf("owner_set: Failed to query old descriptor\n");
|
||||
return EXIT_FAILED;
|
||||
}
|
||||
|
||||
sd = make_sec_desc(ctx,old->revision,
|
||||
(change_mode == REQUEST_CHOWN) ? &sid : old->owner_sid,
|
||||
(change_mode == REQUEST_CHGRP) ? &sid : old->grp_sid,
|
||||
NULL, old->dacl, &sd_size);
|
||||
|
||||
fnum = cli_nt_create(cli, filename, CREATE_ACCESS_WRITE);
|
||||
|
||||
if (fnum == -1) {
|
||||
printf("Failed to open %s: %s\n", filename, cli_errstr(cli));
|
||||
return EXIT_FAILED;
|
||||
}
|
||||
|
||||
if (!cli_set_secdesc(cli, fnum, sd)) {
|
||||
printf("ERROR: secdesc set failed: %s\n", cli_errstr(cli));
|
||||
}
|
||||
|
||||
cli_close(cli, fnum);
|
||||
|
||||
return EXIT_OK;
|
||||
}
|
||||
|
||||
|
||||
/* The MSDN is contradictory over the ordering of ACE entries in an ACL.
|
||||
However NT4 gives a "The information may have been modified by a
|
||||
computer running Windows NT 5.0" if denied ACEs do not appear before
|
||||
allowed ACEs. */
|
||||
|
||||
static int ace_compare(SEC_ACE *ace1, SEC_ACE *ace2)
|
||||
{
|
||||
if (sec_ace_equal(ace1, ace2))
|
||||
return 0;
|
||||
|
||||
if (ace1->type != ace2->type)
|
||||
return ace2->type - ace1->type;
|
||||
|
||||
if (sid_compare(&ace1->trustee, &ace2->trustee))
|
||||
return sid_compare(&ace1->trustee, &ace2->trustee);
|
||||
|
||||
if (ace1->flags != ace2->flags)
|
||||
return ace1->flags - ace2->flags;
|
||||
|
||||
if (ace1->info.mask != ace2->info.mask)
|
||||
return ace1->info.mask - ace2->info.mask;
|
||||
|
||||
if (ace1->size != ace2->size)
|
||||
return ace1->size - ace2->size;
|
||||
|
||||
return memcmp(ace1, ace2, sizeof(SEC_ACE));
|
||||
}
|
||||
|
||||
static void sort_acl(SEC_ACL *the_acl)
|
||||
{
|
||||
uint32 i;
|
||||
if (!the_acl) return;
|
||||
|
||||
qsort(the_acl->ace, the_acl->num_aces, sizeof(the_acl->ace[0]), QSORT_CAST ace_compare);
|
||||
|
||||
for (i=1;i<the_acl->num_aces;) {
|
||||
if (sec_ace_equal(&the_acl->ace[i-1], &the_acl->ace[i])) {
|
||||
int j;
|
||||
for (j=i; j<the_acl->num_aces-1; j++) {
|
||||
the_acl->ace[j] = the_acl->ace[j+1];
|
||||
}
|
||||
the_acl->num_aces--;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************
|
||||
set the ACLs on a file given an ascii description
|
||||
*******************************************************/
|
||||
static int cacl_set(struct cli_state *cli, char *filename,
|
||||
char *the_acl, enum acl_mode mode)
|
||||
{
|
||||
int fnum;
|
||||
SEC_DESC *sd, *old;
|
||||
uint32 i, j;
|
||||
size_t sd_size;
|
||||
int result = EXIT_OK;
|
||||
|
||||
sd = sec_desc_parse(the_acl);
|
||||
|
||||
if (!sd) return EXIT_PARSE_ERROR;
|
||||
if (test_args) return EXIT_OK;
|
||||
|
||||
/* The desired access below is the only one I could find that works
|
||||
with NT4, W2KP and Samba */
|
||||
|
||||
fnum = cli_nt_create(cli, filename, CREATE_ACCESS_READ);
|
||||
|
||||
if (fnum == -1) {
|
||||
printf("cacl_set failed to open %s: %s\n", filename, cli_errstr(cli));
|
||||
return EXIT_FAILED;
|
||||
}
|
||||
|
||||
old = cli_query_secdesc(cli, fnum, ctx);
|
||||
|
||||
if (!old) {
|
||||
printf("calc_set: Failed to query old descriptor\n");
|
||||
return EXIT_FAILED;
|
||||
}
|
||||
|
||||
cli_close(cli, fnum);
|
||||
|
||||
/* the logic here is rather more complex than I would like */
|
||||
switch (mode) {
|
||||
case SMB_ACL_DELETE:
|
||||
for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
|
||||
BOOL found = False;
|
||||
|
||||
for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
|
||||
if (sec_ace_equal(&sd->dacl->ace[i],
|
||||
&old->dacl->ace[j])) {
|
||||
uint32 k;
|
||||
for (k=j; k<old->dacl->num_aces-1;k++) {
|
||||
old->dacl->ace[k] = old->dacl->ace[k+1];
|
||||
}
|
||||
old->dacl->num_aces--;
|
||||
if (old->dacl->num_aces == 0) {
|
||||
SAFE_FREE(old->dacl->ace);
|
||||
SAFE_FREE(old->dacl);
|
||||
old->off_dacl = 0;
|
||||
}
|
||||
found = True;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
printf("ACL for ACE:");
|
||||
print_ace(stdout, &sd->dacl->ace[i]);
|
||||
printf(" not found\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SMB_ACL_MODIFY:
|
||||
for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
|
||||
BOOL found = False;
|
||||
|
||||
for (j=0;old->dacl && j<old->dacl->num_aces;j++) {
|
||||
if (sid_equal(&sd->dacl->ace[i].trustee,
|
||||
&old->dacl->ace[j].trustee)) {
|
||||
old->dacl->ace[j] = sd->dacl->ace[i];
|
||||
found = True;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
fstring str;
|
||||
|
||||
SidToString(str, &sd->dacl->ace[i].trustee);
|
||||
printf("ACL for SID %s not found\n", str);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SMB_ACL_ADD:
|
||||
for (i=0;sd->dacl && i<sd->dacl->num_aces;i++) {
|
||||
add_ace(&old->dacl, &sd->dacl->ace[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case SMB_ACL_SET:
|
||||
old = sd;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Denied ACE entries must come before allowed ones */
|
||||
sort_acl(old->dacl);
|
||||
|
||||
/* Create new security descriptor and set it */
|
||||
sd = make_sec_desc(ctx,old->revision, old->owner_sid, old->grp_sid,
|
||||
NULL, old->dacl, &sd_size);
|
||||
|
||||
fnum = cli_nt_create(cli, filename, CREATE_ACCESS_WRITE);
|
||||
|
||||
if (fnum == -1) {
|
||||
printf("cacl_set failed to open %s: %s\n", filename, cli_errstr(cli));
|
||||
return EXIT_FAILED;
|
||||
}
|
||||
|
||||
if (!cli_set_secdesc(cli, fnum, sd)) {
|
||||
printf("ERROR: secdesc set failed: %s\n", cli_errstr(cli));
|
||||
result = EXIT_FAILED;
|
||||
}
|
||||
|
||||
/* Clean up */
|
||||
|
||||
cli_close(cli, fnum);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************
|
||||
return a connection to a server
|
||||
*******************************************************/
|
||||
static struct cli_state *connect_one(const char *share)
|
||||
{
|
||||
struct cli_state *c;
|
||||
struct in_addr ip;
|
||||
NTSTATUS nt_status;
|
||||
zero_ip(&ip);
|
||||
|
||||
if (!got_pass) {
|
||||
char *pass = getpass("Password: ");
|
||||
if (pass) {
|
||||
fstrcpy(password, pass);
|
||||
got_pass = True;
|
||||
}
|
||||
}
|
||||
|
||||
if (NT_STATUS_IS_OK(nt_status = cli_full_connection(&c, lp_netbios_name(), server,
|
||||
&ip, 0,
|
||||
share, "?????",
|
||||
username, lp_workgroup(),
|
||||
password, 0, NULL))) {
|
||||
return c;
|
||||
} else {
|
||||
DEBUG(0,("cli_full_connection failed! (%s)\n", nt_errstr(nt_status)));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf(
|
||||
"Usage: smbcacls //server1/share1 filename [options]\n\
|
||||
\n\
|
||||
\t-D <acls> delete an acl\n\
|
||||
\t-M <acls> modify an acl\n\
|
||||
\t-A <acls> add an acl\n\
|
||||
\t-S <acls> set acls\n\
|
||||
\t-C username change ownership of a file\n\
|
||||
\t-G username change group ownership of a file\n\
|
||||
\t-n don't resolve sids or masks to names\n\
|
||||
\t-h print help\n\
|
||||
\t-d debuglevel set debug output level\n\
|
||||
\t-U username user to autheticate as\n\
|
||||
\n\
|
||||
The username can be of the form username%%password or\n\
|
||||
workgroup\\username%%password.\n\n\
|
||||
An acl is of the form ACL:<SID>:type/flags/mask\n\
|
||||
You can string acls together with spaces, commas or newlines\n\
|
||||
");
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
main program
|
||||
****************************************************************************/
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
char *share;
|
||||
pstring filename;
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
int opt;
|
||||
char *p;
|
||||
enum acl_mode mode = SMB_ACL_SET;
|
||||
char *the_acl = NULL;
|
||||
enum chown_mode change_mode = REQUEST_NONE;
|
||||
int result;
|
||||
|
||||
struct cli_state *cli;
|
||||
|
||||
ctx=talloc_init("main");
|
||||
|
||||
setlinebuf(stdout);
|
||||
|
||||
dbf = x_stderr;
|
||||
|
||||
if (argc < 3 || argv[1][0] == '-') {
|
||||
usage();
|
||||
talloc_destroy(ctx);
|
||||
exit(EXIT_PARSE_ERROR);
|
||||
}
|
||||
|
||||
setup_logging(argv[0],True);
|
||||
|
||||
share = argv[1];
|
||||
pstrcpy(filename, argv[2]);
|
||||
all_string_sub(share,"/","\\",0);
|
||||
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
|
||||
lp_load(dyn_CONFIGFILE,True,False,False);
|
||||
load_interfaces();
|
||||
|
||||
if (getenv("USER")) {
|
||||
pstrcpy(username,getenv("USER"));
|
||||
|
||||
if ((p=strchr_m(username,'%'))) {
|
||||
*p = 0;
|
||||
fstrcpy(password,p+1);
|
||||
got_pass = True;
|
||||
memset(strchr_m(getenv("USER"), '%') + 1, 'X',
|
||||
strlen(password));
|
||||
}
|
||||
}
|
||||
|
||||
while ((opt = getopt(argc, argv, "U:nhS:D:A:M:C:G:td:")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'U':
|
||||
pstrcpy(username,optarg);
|
||||
p = strchr_m(username,'%');
|
||||
if (p) {
|
||||
*p = 0;
|
||||
fstrcpy(password, p+1);
|
||||
got_pass = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
the_acl = optarg;
|
||||
mode = SMB_ACL_SET;
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
the_acl = optarg;
|
||||
mode = SMB_ACL_DELETE;
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
the_acl = optarg;
|
||||
mode = SMB_ACL_MODIFY;
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
the_acl = optarg;
|
||||
mode = SMB_ACL_ADD;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
pstrcpy(owner_username,optarg);
|
||||
change_mode = REQUEST_CHOWN;
|
||||
break;
|
||||
|
||||
case 'G':
|
||||
pstrcpy(owner_username,optarg);
|
||||
change_mode = REQUEST_CHGRP;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
numeric = 1;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
test_args = 1;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage();
|
||||
talloc_destroy(ctx);
|
||||
exit(EXIT_PARSE_ERROR);
|
||||
|
||||
case 'd':
|
||||
DEBUGLEVEL = atoi(optarg);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Unknown option %c (%d)\n", (char)opt, opt);
|
||||
talloc_destroy(ctx);
|
||||
exit(EXIT_PARSE_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc > 0) {
|
||||
usage();
|
||||
talloc_destroy(ctx);
|
||||
exit(EXIT_PARSE_ERROR);
|
||||
}
|
||||
|
||||
/* Make connection to server */
|
||||
|
||||
fstrcpy(server,share+2);
|
||||
share = strchr_m(server,'\\');
|
||||
if (!share) {
|
||||
share = strchr_m(server,'/');
|
||||
if (!share) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
*share = 0;
|
||||
share++;
|
||||
|
||||
if (!test_args) {
|
||||
cli = connect_one(share);
|
||||
if (!cli) {
|
||||
talloc_destroy(ctx);
|
||||
exit(EXIT_FAILED);
|
||||
}
|
||||
} else {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
all_string_sub(filename, "/", "\\", 0);
|
||||
if (filename[0] != '\\') {
|
||||
pstring s;
|
||||
s[0] = '\\';
|
||||
safe_strcpy(&s[1], filename, sizeof(pstring)-1);
|
||||
pstrcpy(filename, s);
|
||||
}
|
||||
|
||||
/* Perform requested action */
|
||||
|
||||
if (change_mode != REQUEST_NONE) {
|
||||
result = owner_set(cli, change_mode, filename, owner_username);
|
||||
} else if (the_acl) {
|
||||
result = cacl_set(cli, filename, the_acl, mode);
|
||||
} else {
|
||||
result = cacl_dump(cli, filename);
|
||||
}
|
||||
|
||||
talloc_destroy(ctx);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
714
source/utils/smbcontrol.c
Normal file
714
source/utils/smbcontrol.c
Normal file
@@ -0,0 +1,714 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
program to send control messages to Samba processes
|
||||
Copyright (C) Andrew Tridgell 1994-1998
|
||||
Copyright (C) 2001, 2002 by Martin Pool
|
||||
Copyright (C) Simo Sorce 2002
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
extern BOOL AllowDebugChange;
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
int value;
|
||||
} msg_types[] = {
|
||||
{"debug", MSG_DEBUG},
|
||||
{"force-election", MSG_FORCE_ELECTION},
|
||||
{"ping", MSG_PING},
|
||||
{"profile", MSG_PROFILE},
|
||||
{"profilelevel", MSG_REQ_PROFILELEVEL},
|
||||
{"debuglevel", MSG_REQ_DEBUGLEVEL},
|
||||
{"printnotify", MSG_PRINTER_NOTIFY2 },
|
||||
{"close-share", MSG_SMB_FORCE_TDIS},
|
||||
{"samsync", MSG_SMB_SAM_SYNC},
|
||||
{"samrepl", MSG_SMB_SAM_REPL},
|
||||
{"pool-usage", MSG_REQ_POOL_USAGE },
|
||||
{"dmalloc-mark", MSG_REQ_DMALLOC_MARK },
|
||||
{"dmalloc-log-changed", MSG_REQ_DMALLOC_LOG_CHANGED },
|
||||
{"shutdown", MSG_SHUTDOWN },
|
||||
{"drvupgrade", MSG_PRINTER_DRVUPGRADE},
|
||||
{"tallocdump", MSG_REQ_TALLOC_USAGE},
|
||||
{NULL, -1}
|
||||
};
|
||||
|
||||
time_t timeout_start;
|
||||
|
||||
#define MAX_WAIT 10
|
||||
|
||||
/* we need these because we link to printing*.o */
|
||||
|
||||
void become_root(void) {}
|
||||
void unbecome_root(void) {}
|
||||
|
||||
|
||||
static void usage(BOOL doexit)
|
||||
{
|
||||
int i;
|
||||
if (doexit) {
|
||||
printf("Usage: smbcontrol -i -s configfile\n");
|
||||
printf(" smbcontrol <destination> <message-type> <parameters>\n\n");
|
||||
} else {
|
||||
printf("<destination> <message-type> <parameters>\n\n");
|
||||
}
|
||||
printf("\t<destination> is one of \"nmbd\", \"smbd\" or a process ID\n");
|
||||
printf("\t<message-type> is one of:\n");
|
||||
for (i=0; msg_types[i].name; i++)
|
||||
printf("\t\t%s\n", msg_types[i].name);
|
||||
printf("\n");
|
||||
if (doexit) exit(1);
|
||||
}
|
||||
|
||||
static int pong_count;
|
||||
static BOOL got_level;
|
||||
static BOOL got_pool;
|
||||
static BOOL pong_registered = False;
|
||||
static BOOL debuglevel_registered = False;
|
||||
static BOOL poolusage_registered = False;
|
||||
static BOOL profilelevel_registered = False;
|
||||
|
||||
|
||||
/**
|
||||
* Wait for replies for up to @p *max_secs seconds, or until @p
|
||||
* max_replies are received. max_replies may be NULL in which case it
|
||||
* is ignored.
|
||||
*
|
||||
* @note This is a pretty lame timeout; all it means is that after
|
||||
* max_secs we won't look for any more messages.
|
||||
**/
|
||||
static void wait_for_replies(int max_secs, int *max_replies)
|
||||
{
|
||||
time_t timeout_end = time(NULL) + max_secs;
|
||||
|
||||
while ((!max_replies || (*max_replies)-- > 0)
|
||||
&& (time(NULL) < timeout_end)) {
|
||||
message_dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
a useful function for testing the message system
|
||||
****************************************************************************/
|
||||
void pong_function(int msg_type, pid_t src, void *buf, size_t len)
|
||||
{
|
||||
pong_count++;
|
||||
printf("PONG from PID %u\n",(unsigned int)src);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Prints out the current talloc list.
|
||||
****************************************************************************/
|
||||
void tallocdump_function(int msg_type, pid_t src, void *buf, size_t len)
|
||||
{
|
||||
char *info = (char *)buf;
|
||||
|
||||
printf("Current talloc contexts for process %u\n", (unsigned int)src );
|
||||
if (len == 0)
|
||||
printf("None returned\n");
|
||||
else
|
||||
printf(info);
|
||||
printf("\n");
|
||||
got_pool = True;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Prints out the current Debug level returned by MSG_DEBUGLEVEL
|
||||
****************************************************************************/
|
||||
void debuglevel_function(int msg_type, pid_t src, void *buf, size_t len)
|
||||
{
|
||||
const char *levels = (char *)buf;
|
||||
|
||||
printf("Current debug levels of PID %u are:\n",(unsigned int)src);
|
||||
printf("%s\n", levels);
|
||||
|
||||
got_level = True;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Prints out the current Profile level returned by MSG_PROFILELEVEL
|
||||
****************************************************************************/
|
||||
void profilelevel_function(int msg_type, pid_t src, void *buf, size_t len)
|
||||
{
|
||||
int level;
|
||||
const char *s=NULL;
|
||||
memcpy(&level, buf, sizeof(int));
|
||||
|
||||
if (level) {
|
||||
switch (level) {
|
||||
case 1:
|
||||
s = "off";
|
||||
break;
|
||||
case 3:
|
||||
s = "count only";
|
||||
break;
|
||||
case 7:
|
||||
s = "count and time";
|
||||
break;
|
||||
default:
|
||||
s = "BOGUS";
|
||||
break;
|
||||
}
|
||||
printf("Profiling %s on PID %u\n",s,(unsigned int)src);
|
||||
} else {
|
||||
printf("Profiling not available on PID %u\n",(unsigned int)src);
|
||||
}
|
||||
got_level = True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle reply from POOL_USAGE.
|
||||
**/
|
||||
static void pool_usage_cb(int msg_type, pid_t src_pid, void *buf, size_t len)
|
||||
{
|
||||
printf("Got POOL_USAGE reply from pid%u:\n%.*s",
|
||||
(unsigned int) src_pid, (int) len, (const char *) buf);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a message to a named destination
|
||||
*
|
||||
* @return False if an error occurred.
|
||||
**/
|
||||
static BOOL send_message(char *dest, int msg_type, void *buf, int len, BOOL duplicates)
|
||||
{
|
||||
pid_t pid;
|
||||
/* "smbd" is the only broadcast operation */
|
||||
if (strequal(dest,"smbd")) {
|
||||
TDB_CONTEXT *tdb;
|
||||
BOOL ret;
|
||||
int n_sent = 0;
|
||||
|
||||
tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDWR, 0);
|
||||
if (!tdb) {
|
||||
fprintf(stderr,"Failed to open connections database in send_message.\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
ret = message_send_all(tdb,msg_type, buf, len, duplicates,
|
||||
&n_sent);
|
||||
DEBUG(10,("smbcontrol/send_message: broadcast message to "
|
||||
"%d processes\n", n_sent));
|
||||
tdb_close(tdb);
|
||||
|
||||
return ret;
|
||||
} else if (strequal(dest,"nmbd")) {
|
||||
pid = pidfile_pid(dest);
|
||||
if (pid == 0) {
|
||||
fprintf(stderr,"Can't find pid for nmbd\n");
|
||||
return False;
|
||||
}
|
||||
} else if (strequal(dest,"self")) {
|
||||
pid = sys_getpid();
|
||||
} else {
|
||||
pid = atoi(dest);
|
||||
if (pid == 0) {
|
||||
fprintf(stderr,"Not a valid pid\n");
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG(10,("smbcontrol/send_message: send message to pid%d\n", pid));
|
||||
return message_send_pid(pid, msg_type, buf, len, duplicates);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
evaluate a message type string
|
||||
****************************************************************************/
|
||||
static int parse_type(char *mtype)
|
||||
{
|
||||
int i;
|
||||
for (i=0;msg_types[i].name;i++) {
|
||||
if (strequal(mtype, msg_types[i].name)) return msg_types[i].value;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static void register_all(void)
|
||||
{
|
||||
message_register(MSG_POOL_USAGE, pool_usage_cb);
|
||||
}
|
||||
|
||||
/* This guy is here so we can link printing/notify.c to the smbcontrol
|
||||
binary without having to pull in tons of other crap. */
|
||||
|
||||
TDB_CONTEXT *conn_tdb_ctx(void)
|
||||
{
|
||||
static TDB_CONTEXT *tdb;
|
||||
|
||||
if (tdb)
|
||||
return tdb;
|
||||
|
||||
tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDONLY, 0);
|
||||
|
||||
if (!tdb)
|
||||
DEBUG(3, ("Failed to open connections database in send_spoolss_notify2_msg\n"));
|
||||
|
||||
return tdb;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
do command
|
||||
****************************************************************************/
|
||||
static BOOL do_command(char *dest, char *msg_name, int iparams, char **params)
|
||||
{
|
||||
int i, n, v;
|
||||
int mtype;
|
||||
BOOL retval=False;
|
||||
BOOL check_notify_msgs = False;
|
||||
|
||||
mtype = parse_type(msg_name);
|
||||
if (mtype == -1) {
|
||||
fprintf(stderr,"Couldn't resolve message type: %s\n", msg_name);
|
||||
return(False);
|
||||
}
|
||||
|
||||
switch (mtype) {
|
||||
case MSG_DEBUG: {
|
||||
char *buf, *b;
|
||||
char **p;
|
||||
int dim = 0;
|
||||
|
||||
if (!params || !params[0]) {
|
||||
fprintf(stderr,"MSG_DEBUG needs a parameter\n");
|
||||
return(False);
|
||||
}
|
||||
|
||||
/* first pass retrieve total lenght */
|
||||
for (p = params; p && *p ; p++)
|
||||
dim += (strnlen(*p, 1024) +1); /* lenght + space */
|
||||
b = buf = malloc(dim);
|
||||
if (!buf) {
|
||||
fprintf(stderr, "Out of memory!");
|
||||
return(False);
|
||||
}
|
||||
/* now build a single string with all parameters */
|
||||
for(p = params; p && *p; p++) {
|
||||
int l = strnlen(*p, 1024);
|
||||
strncpy(b, *p, l);
|
||||
b[l] = ' ';
|
||||
b = b + l + 1;
|
||||
}
|
||||
b[-1] = '\0';
|
||||
|
||||
send_message(dest, MSG_DEBUG, buf, dim, False);
|
||||
|
||||
free(buf);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_PROFILE:
|
||||
if (!params || !params[0]) {
|
||||
fprintf(stderr,"MSG_PROFILE needs a parameter\n");
|
||||
return(False);
|
||||
}
|
||||
if (strequal(params[0], "off")) {
|
||||
v = 0;
|
||||
} else if (strequal(params[0], "count")) {
|
||||
v = 1;
|
||||
} else if (strequal(params[0], "on")) {
|
||||
v = 2;
|
||||
} else if (strequal(params[0], "flush")) {
|
||||
v = 3;
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"MSG_PROFILE parameter must be off, count, on, or flush\n");
|
||||
return(False);
|
||||
}
|
||||
send_message(dest, MSG_PROFILE, &v, sizeof(int), False);
|
||||
break;
|
||||
|
||||
case MSG_FORCE_ELECTION:
|
||||
if (!strequal(dest, "nmbd")) {
|
||||
fprintf(stderr,"force-election can only be sent to nmbd\n");
|
||||
return(False);
|
||||
}
|
||||
send_message(dest, MSG_FORCE_ELECTION, NULL, 0, False);
|
||||
break;
|
||||
|
||||
case MSG_REQ_PROFILELEVEL:
|
||||
if (!profilelevel_registered) {
|
||||
message_register(MSG_PROFILELEVEL, profilelevel_function);
|
||||
profilelevel_registered = True;
|
||||
}
|
||||
got_level = False;
|
||||
retval = send_message(dest, MSG_REQ_PROFILELEVEL, NULL, 0, True);
|
||||
if (retval) {
|
||||
timeout_start = time(NULL);
|
||||
while (!got_level) {
|
||||
message_dispatch();
|
||||
if ((time(NULL) - timeout_start) > MAX_WAIT) {
|
||||
fprintf(stderr,"profilelevel timeout\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MSG_REQ_TALLOC_USAGE:
|
||||
if (!poolusage_registered) {
|
||||
message_register(MSG_TALLOC_USAGE, tallocdump_function);
|
||||
poolusage_registered = True;
|
||||
}
|
||||
got_pool = False;
|
||||
retval = send_message(dest, MSG_REQ_TALLOC_USAGE, NULL, 0, True);
|
||||
if (retval) {
|
||||
timeout_start = time(NULL);
|
||||
while (!got_pool) {
|
||||
message_dispatch();
|
||||
if ((time(NULL) - timeout_start) > MAX_WAIT) {
|
||||
fprintf(stderr,"tallocdump timeout\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MSG_REQ_DEBUGLEVEL:
|
||||
if (!debuglevel_registered) {
|
||||
message_register(MSG_DEBUGLEVEL, debuglevel_function);
|
||||
debuglevel_registered = True;
|
||||
}
|
||||
got_level = False;
|
||||
retval = send_message(dest, MSG_REQ_DEBUGLEVEL, NULL, 0, True);
|
||||
if (retval) {
|
||||
timeout_start = time(NULL);
|
||||
while (!got_level) {
|
||||
message_dispatch();
|
||||
if ((time(NULL) - timeout_start) > MAX_WAIT) {
|
||||
fprintf(stderr,"debuglevel timeout\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/* Send a notification message to a printer */
|
||||
|
||||
case MSG_PRINTER_NOTIFY2: {
|
||||
char *cmd;
|
||||
|
||||
/* Read subcommand */
|
||||
|
||||
if (!params || !params[0]) {
|
||||
fprintf(stderr, "Must specify subcommand:\n");
|
||||
fprintf(stderr, "\tqueuepause <printername>\n");
|
||||
fprintf(stderr, "\tqueueresume <printername>\n");
|
||||
fprintf(stderr, "\tjobpause <printername> <unix jobid>\n");
|
||||
fprintf(stderr, "\tjobresume <printername> <unix jobid>\n");
|
||||
fprintf(stderr, "\tjobdelete <printername> <unix jobid>\n");
|
||||
fprintf(stderr, "\tprinter <printername> <comment|port|driver> <new value>\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
cmd = params[0];
|
||||
|
||||
check_notify_msgs = True;
|
||||
|
||||
/* Pause a print queue */
|
||||
|
||||
if (strequal(cmd, "queuepause")) {
|
||||
|
||||
if (!params[1]) {
|
||||
fprintf(stderr, "queuepause command requires a printer name\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
//TODL: notify_printer_status_byname(params[1], PRINTER_STATUS_PAUSED);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Resume a print queue */
|
||||
|
||||
if (strequal(cmd, "queueresume")) {
|
||||
|
||||
if (!params[1]) {
|
||||
fprintf(stderr, "queueresume command requires a printer name\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
//TODL: notify_printer_status_byname(params[1], PRINTER_STATUS_OK);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Pause a print job */
|
||||
|
||||
if (strequal(cmd, "jobpause")) {
|
||||
int jobid;
|
||||
|
||||
if (!params[1] || !params[2]) {
|
||||
fprintf(stderr, "jobpause command requires a printer name and a jobid\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
jobid = atoi(params[2]);
|
||||
|
||||
//TODL: notify_job_status_byname(
|
||||
//TODL: params[1], jobid, JOB_STATUS_PAUSED,
|
||||
//TODL: SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Resume a print job */
|
||||
|
||||
if (strequal(cmd, "jobresume")) {
|
||||
int jobid;
|
||||
|
||||
if (!params[1] || !params[2]) {
|
||||
fprintf(stderr, "jobresume command requires a printer name and a jobid\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
jobid = atoi(params[2]);
|
||||
|
||||
//TODL: notify_job_status_byname(
|
||||
//TODL: params[1], jobid, JOB_STATUS_QUEUED,
|
||||
//TODL: SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Delete a print job */
|
||||
|
||||
if (strequal(cmd, "jobdelete")) {
|
||||
int jobid;
|
||||
|
||||
if (!params[1] || !params[2]) {
|
||||
fprintf(stderr, "jobdelete command requires a printer name and a jobid\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
jobid = atoi(params[2]);
|
||||
|
||||
//TODL: notify_job_status_byname(
|
||||
//TODL: params[1], jobid, JOB_STATUS_DELETING,
|
||||
//TODL: SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
|
||||
|
||||
//TODL: notify_job_status_byname(
|
||||
//TODL: params[1], jobid, JOB_STATUS_DELETING|
|
||||
//TODL: JOB_STATUS_DELETED,
|
||||
//TODL: SPOOLSS_NOTIFY_MSG_UNIX_JOBID);
|
||||
}
|
||||
|
||||
/* printer change notify */
|
||||
|
||||
if (strequal(cmd, "printer")) {
|
||||
int attribute = -1;
|
||||
|
||||
if (!params[1] || !params[2] || !params[3]) {
|
||||
fprintf(stderr, "printer command requires an and attribute name and value!\n");
|
||||
fprintf(stderr, "supported attributes:\n");
|
||||
fprintf(stderr, "\tcomment:\n");
|
||||
fprintf(stderr, "\tport:\n");
|
||||
fprintf(stderr, "\tdriver:\n");
|
||||
return False;
|
||||
}
|
||||
if ( strequal(params[2], "comment") )
|
||||
attribute = PRINTER_NOTIFY_COMMENT;
|
||||
else if ( strequal(params[2], "port") )
|
||||
attribute = PRINTER_NOTIFY_PORT_NAME;
|
||||
else if ( strequal(params[2], "driver") )
|
||||
attribute = PRINTER_NOTIFY_DRIVER_NAME;
|
||||
|
||||
if ( attribute == -1 ) {
|
||||
fprintf(stderr, "bad attribute!\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
//TODL: notify_printer_byname( params[1], attribute, params[3]);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case MSG_SMB_FORCE_TDIS:
|
||||
if (!strequal(dest, "smbd")) {
|
||||
fprintf(stderr,"close-share can only be sent to smbd\n");
|
||||
return(False);
|
||||
}
|
||||
if (!params || !params[0]) {
|
||||
fprintf(stderr, "close-share needs a share name or '*'\n");
|
||||
return (False);
|
||||
}
|
||||
retval = send_message(dest, MSG_SMB_FORCE_TDIS, params[0],
|
||||
strlen(params[0]) + 1, False);
|
||||
break;
|
||||
|
||||
case MSG_SMB_SAM_SYNC:
|
||||
if (!strequal(dest, "smbd")) {
|
||||
fprintf(stderr, "samsync can only be sent to smbd\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
if (params) {
|
||||
fprintf(stderr, "samsync does not take any parameters\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
retval = send_message(dest, MSG_SMB_SAM_SYNC, NULL, 0, False);
|
||||
|
||||
break;
|
||||
|
||||
case MSG_SMB_SAM_REPL: {
|
||||
uint32 seqnum;
|
||||
|
||||
if (!strequal(dest, "smbd")) {
|
||||
fprintf(stderr, "sam repl can only be sent to smbd\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!params || !params[0]) {
|
||||
fprintf(stderr, "SAM_REPL needs a parameter\n");
|
||||
return False;
|
||||
}
|
||||
|
||||
seqnum = atoi(params[0]);
|
||||
|
||||
retval = send_message(dest, MSG_SMB_SAM_SYNC,
|
||||
(char *)&seqnum, sizeof(uint32), False);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_PING:
|
||||
if (!pong_registered) {
|
||||
message_register(MSG_PONG, pong_function);
|
||||
pong_registered = True;
|
||||
}
|
||||
if (!params || !params[0]) {
|
||||
fprintf(stderr,"MSG_PING needs a parameter\n");
|
||||
return(False);
|
||||
}
|
||||
n = atoi(params[0]);
|
||||
pong_count = 0;
|
||||
for (i=0;i<n;i++) {
|
||||
if (iparams > 1)
|
||||
retval = send_message(dest, MSG_PING, params[1], strlen(params[1]) + 1, True);
|
||||
else
|
||||
retval = send_message(dest, MSG_PING, NULL, 0, True);
|
||||
if (retval == False)
|
||||
return False;
|
||||
}
|
||||
wait_for_replies(MAX_WAIT, &n);
|
||||
if (n > 0) {
|
||||
fprintf(stderr,"PING timeout\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case MSG_REQ_POOL_USAGE:
|
||||
if (!send_message(dest, MSG_REQ_POOL_USAGE, NULL, 0, True))
|
||||
return False;
|
||||
wait_for_replies(MAX_WAIT, NULL);
|
||||
|
||||
break;
|
||||
|
||||
case MSG_REQ_DMALLOC_LOG_CHANGED:
|
||||
case MSG_REQ_DMALLOC_MARK:
|
||||
if (!send_message(dest, mtype, NULL, 0, False))
|
||||
return False;
|
||||
break;
|
||||
|
||||
case MSG_SHUTDOWN:
|
||||
if (!send_message(dest, MSG_SHUTDOWN, NULL, 0, False))
|
||||
return False;
|
||||
break;
|
||||
case MSG_PRINTER_DRVUPGRADE:
|
||||
if (!send_message(dest, MSG_PRINTER_DRVUPGRADE, params[0], 0, False))
|
||||
return False;
|
||||
break;
|
||||
}
|
||||
|
||||
/* check if we have any pending print notify messages */
|
||||
|
||||
if ( check_notify_msgs )
|
||||
;//TODO: print_notify_send_messages(0);
|
||||
|
||||
return (True);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int opt;
|
||||
char temp[255];
|
||||
extern int optind;
|
||||
BOOL interactive = False;
|
||||
|
||||
AllowDebugChange = False;
|
||||
DEBUGLEVEL = 0;
|
||||
|
||||
setup_logging(argv[0],True);
|
||||
|
||||
if (argc < 2) usage(True);
|
||||
|
||||
while ((opt = getopt(argc, argv,"is:")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'i':
|
||||
interactive = True;
|
||||
break;
|
||||
case 's':
|
||||
pstrcpy(dyn_CONFIGFILE, optarg);
|
||||
break;
|
||||
default:
|
||||
printf("Unknown option %c (%d)\n", (char)opt, opt);
|
||||
usage(True);
|
||||
}
|
||||
}
|
||||
|
||||
lp_load(dyn_CONFIGFILE,False,False,False);
|
||||
|
||||
if (!message_init()) exit(1);
|
||||
|
||||
argc -= optind;
|
||||
argv = &argv[optind];
|
||||
|
||||
register_all();
|
||||
|
||||
if (!interactive) {
|
||||
if (argc < 2) usage(True);
|
||||
/* Need to invert sense of return code -- samba
|
||||
* routines mostly return True==1 for success, but
|
||||
* shell needs 0. */
|
||||
return ! do_command(argv[0],argv[1], argc-2, argc > 2 ? &argv[2] : 0);
|
||||
}
|
||||
|
||||
while (True) {
|
||||
char *myargv[4];
|
||||
int myargc;
|
||||
|
||||
printf("smbcontrol> ");
|
||||
if (!fgets(temp, sizeof(temp)-1, stdin)) break;
|
||||
myargc = 0;
|
||||
while ((myargc < 4) &&
|
||||
(myargv[myargc] = strtok(myargc?NULL:temp," \t\n"))) {
|
||||
myargc++;
|
||||
}
|
||||
if (!myargc) break;
|
||||
if (strequal(myargv[0],"q")) break;
|
||||
if (myargc < 2)
|
||||
usage(False);
|
||||
else if (!do_command(myargv[0],myargv[1],myargc-2,myargc > 2 ? &myargv[2] : 0))
|
||||
usage(False);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
245
source/utils/smbfilter.c
Normal file
245
source/utils/smbfilter.c
Normal file
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
SMB filter/socket plugin
|
||||
Copyright (C) Andrew Tridgell 1999
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#define SECURITY_MASK 0
|
||||
#define SECURITY_SET 0
|
||||
|
||||
/* this forces non-unicode */
|
||||
#define CAPABILITY_MASK 0
|
||||
#define CAPABILITY_SET 0
|
||||
|
||||
/* and non-unicode for the client too */
|
||||
#define CLI_CAPABILITY_MASK 0
|
||||
#define CLI_CAPABILITY_SET 0
|
||||
|
||||
static char *netbiosname;
|
||||
static char packet[BUFFER_SIZE];
|
||||
|
||||
static void save_file(const char *fname, void *packet, size_t length)
|
||||
{
|
||||
int fd;
|
||||
fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
|
||||
if (fd == -1) {
|
||||
perror(fname);
|
||||
return;
|
||||
}
|
||||
if (write(fd, packet, length) != length) {
|
||||
fprintf(stderr,"Failed to write %s\n", fname);
|
||||
return;
|
||||
}
|
||||
close(fd);
|
||||
printf("Wrote %d bytes to %s\n", length, fname);
|
||||
}
|
||||
|
||||
static void filter_reply(char *buf)
|
||||
{
|
||||
int msg_type = CVAL(buf,0);
|
||||
int type = CVAL(buf,smb_com);
|
||||
unsigned x;
|
||||
|
||||
if (msg_type) return;
|
||||
|
||||
switch (type) {
|
||||
|
||||
case SMBnegprot:
|
||||
/* force the security bits */
|
||||
x = CVAL(buf, smb_vwv1);
|
||||
x = (x | SECURITY_SET) & ~SECURITY_MASK;
|
||||
SCVAL(buf, smb_vwv1, x);
|
||||
|
||||
/* force the capabilities */
|
||||
x = IVAL(buf,smb_vwv9+1);
|
||||
x = (x | CAPABILITY_SET) & ~CAPABILITY_MASK;
|
||||
SIVAL(buf, smb_vwv9+1, x);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void filter_request(char *buf)
|
||||
{
|
||||
int msg_type = CVAL(buf,0);
|
||||
int type = CVAL(buf,smb_com);
|
||||
pstring name1,name2;
|
||||
unsigned x;
|
||||
|
||||
if (msg_type) {
|
||||
/* it's a netbios special */
|
||||
switch (msg_type) {
|
||||
case 0x81:
|
||||
/* session request */
|
||||
name_extract(buf,4,name1);
|
||||
name_extract(buf,4 + name_len(buf + 4),name2);
|
||||
d_printf("sesion_request: %s -> %s\n",
|
||||
name1, name2);
|
||||
if (netbiosname) {
|
||||
/* replace the destination netbios name */
|
||||
name_mangle(netbiosname, buf+4, 0x20);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* it's an ordinary SMB request */
|
||||
switch (type) {
|
||||
case SMBsesssetupX:
|
||||
/* force the client capabilities */
|
||||
x = IVAL(buf,smb_vwv11);
|
||||
d_printf("SMBsesssetupX cap=0x%08x\n", x);
|
||||
d_printf("pwlen=%d/%d\n", SVAL(buf, smb_vwv7), SVAL(buf, smb_vwv8));
|
||||
system("mv sessionsetup.dat sessionsetup1.dat");
|
||||
save_file("sessionsetup.dat", smb_buf(buf), SVAL(buf, smb_vwv7));
|
||||
x = (x | CLI_CAPABILITY_SET) & ~CLI_CAPABILITY_MASK;
|
||||
SIVAL(buf, smb_vwv11, x);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void filter_child(int c, struct in_addr dest_ip)
|
||||
{
|
||||
int s;
|
||||
|
||||
/* we have a connection from a new client, now connect to the server */
|
||||
s = open_socket_out(SOCK_STREAM, &dest_ip, 445, LONG_CONNECT_TIMEOUT);
|
||||
|
||||
if (s == -1) {
|
||||
d_printf("Unable to connect to %s\n", inet_ntoa(dest_ip));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while (c != -1 || s != -1) {
|
||||
fd_set fds;
|
||||
int num;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
if (s != -1) FD_SET(s, &fds);
|
||||
if (c != -1) FD_SET(c, &fds);
|
||||
|
||||
num = sys_select_intr(MAX(s+1, c+1),&fds,NULL,NULL,NULL);
|
||||
if (num <= 0) continue;
|
||||
|
||||
if (c != -1 && FD_ISSET(c, &fds)) {
|
||||
if (!receive_smb(c, packet, 0)) {
|
||||
d_printf("client closed connection\n");
|
||||
exit(0);
|
||||
}
|
||||
filter_request(packet);
|
||||
if (!send_smb(s, packet)) {
|
||||
d_printf("server is dead\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (s != -1 && FD_ISSET(s, &fds)) {
|
||||
if (!receive_smb(s, packet, 0)) {
|
||||
d_printf("server closed connection\n");
|
||||
exit(0);
|
||||
}
|
||||
filter_reply(packet);
|
||||
if (!send_smb(c, packet)) {
|
||||
d_printf("client is dead\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
d_printf("Connection closed\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
static void start_filter(char *desthost)
|
||||
{
|
||||
int s, c;
|
||||
struct in_addr dest_ip;
|
||||
|
||||
CatchChild();
|
||||
|
||||
/* start listening on port 445 locally */
|
||||
s = open_socket_in(SOCK_STREAM, 445, 0, 0, True);
|
||||
|
||||
if (s == -1) {
|
||||
d_printf("bind failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (listen(s, 5) == -1) {
|
||||
d_printf("listen failed\n");
|
||||
}
|
||||
|
||||
if (!resolve_name(desthost, &dest_ip, 0x20)) {
|
||||
d_printf("Unable to resolve host %s\n", desthost);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
fd_set fds;
|
||||
int num;
|
||||
struct sockaddr addr;
|
||||
socklen_t in_addrlen = sizeof(addr);
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(s, &fds);
|
||||
|
||||
num = sys_select_intr(s+1,&fds,NULL,NULL,NULL);
|
||||
if (num > 0) {
|
||||
c = accept(s, &addr, &in_addrlen);
|
||||
if (c != -1) {
|
||||
if (fork() == 0) {
|
||||
close(s);
|
||||
filter_child(c, dest_ip);
|
||||
exit(0);
|
||||
} else {
|
||||
close(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *desthost;
|
||||
pstring configfile;
|
||||
|
||||
setup_logging(argv[0],True);
|
||||
|
||||
pstrcpy(configfile,dyn_CONFIGFILE);
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr,"smbfilter <desthost> <netbiosname>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
desthost = argv[1];
|
||||
if (argc > 2) {
|
||||
netbiosname = argv[2];
|
||||
}
|
||||
|
||||
if (!lp_load(configfile,True,False,False)) {
|
||||
d_printf("Unable to load config file\n");
|
||||
}
|
||||
|
||||
start_filter(desthost);
|
||||
return 0;
|
||||
}
|
||||
410
source/utils/smbgroupedit.c
Normal file
410
source/utils/smbgroupedit.c
Normal file
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
* Unix SMB/CIFS implementation.
|
||||
* RPC Pipe client / server routines
|
||||
* Copyright (C) Andrew Tridgell 1992-2000,
|
||||
* Copyright (C) Jean Fran<61>ois Micouleau 1998-2001.
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
/*
|
||||
* Next two lines needed for SunOS and don't
|
||||
* hurt anything else...
|
||||
*/
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
|
||||
/*********************************************************
|
||||
Print command usage on stderr and die.
|
||||
**********************************************************/
|
||||
static void usage(void)
|
||||
{
|
||||
if (getuid() == 0) {
|
||||
printf("smbgroupedit options\n");
|
||||
} else {
|
||||
printf("You need to be root to use this tool!\n");
|
||||
}
|
||||
printf("options:\n");
|
||||
printf(" -a group create new group\n");
|
||||
printf(" -n group NT group name\n");
|
||||
printf(" -p privilege only local\n");
|
||||
printf(" -d description group description\n");
|
||||
printf(" -v list groups\n");
|
||||
printf(" -l long list (include details)\n");
|
||||
printf(" -s short list (default)\n");
|
||||
printf(" -c SID change group\n");
|
||||
printf(" -u unix group\n");
|
||||
printf(" -d description group description\n");
|
||||
printf(" -r rid RID of new group\n");
|
||||
printf(" -x group delete this group\n");
|
||||
printf("\n");
|
||||
printf(" -t[b|d|l] type: builtin, domain, local \n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
Figure out if the input was an NT group or a SID string.
|
||||
Return the SID.
|
||||
**********************************************************/
|
||||
static BOOL get_sid_from_input(DOM_SID *sid, char *input)
|
||||
{
|
||||
GROUP_MAP map;
|
||||
|
||||
if (StrnCaseCmp( input, "S-", 2)) {
|
||||
/* Perhaps its the NT group name? */
|
||||
if (!pdb_getgrnam(&map, input, MAPPING_WITHOUT_PRIV)) {
|
||||
printf("NT Group %s doesn't exist in mapping DB\n", input);
|
||||
return False;
|
||||
} else {
|
||||
*sid = map.sid;
|
||||
}
|
||||
} else {
|
||||
if (!string_to_sid(sid, input)) {
|
||||
printf("converting sid %s from a string failed!\n", input);
|
||||
return False;
|
||||
}
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
add a group.
|
||||
**********************************************************/
|
||||
static int addgroup(gid_t gid, enum SID_NAME_USE sid_type, char *ntgroup, char *ntcomment, char *privilege, uint32 rid)
|
||||
{
|
||||
PRIVILEGE_SET se_priv;
|
||||
DOM_SID sid;
|
||||
fstring string_sid;
|
||||
fstring comment;
|
||||
|
||||
sid_copy(&sid, get_global_sam_sid());
|
||||
sid_append_rid(&sid, rid);
|
||||
|
||||
sid_to_string(string_sid, &sid);
|
||||
|
||||
if (ntcomment==NULL)
|
||||
fstrcpy(comment, "Local Unix group");
|
||||
else
|
||||
fstrcpy(comment, ntcomment);
|
||||
|
||||
init_privilege(&se_priv);
|
||||
if (privilege!=NULL)
|
||||
convert_priv_from_text(&se_priv, privilege);
|
||||
|
||||
if(!add_initial_entry(gid, string_sid, sid_type, ntgroup,
|
||||
comment, se_priv, PR_ACCESS_FROM_NETWORK)) {
|
||||
printf("adding entry for group %s failed!\n", ntgroup);
|
||||
free_privilege(&se_priv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free_privilege(&se_priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
Change a group.
|
||||
**********************************************************/
|
||||
static int changegroup(char *sid_string, char *group, enum SID_NAME_USE sid_type, char *ntgroup, char *groupdesc, char *privilege)
|
||||
{
|
||||
DOM_SID sid;
|
||||
GROUP_MAP map;
|
||||
gid_t gid;
|
||||
|
||||
if (!get_sid_from_input(&sid, sid_string)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the current mapping from the database */
|
||||
if(!pdb_getgrsid(&map, sid, MAPPING_WITH_PRIV)) {
|
||||
printf("This SID does not exist in the database\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If a new Unix group is specified, check and change */
|
||||
if (group!=NULL) {
|
||||
gid=nametogid(group);
|
||||
if (gid==-1) {
|
||||
printf("The UNIX group does not exist\n");
|
||||
return -1;
|
||||
} else
|
||||
map.gid=gid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow changing of group type only between domain and local
|
||||
* We disallow changing Builtin groups !!! (SID problem)
|
||||
*/
|
||||
if (sid_type==SID_NAME_ALIAS
|
||||
|| sid_type==SID_NAME_DOM_GRP
|
||||
|| sid_type==SID_NAME_UNKNOWN) {
|
||||
if (map.sid_name_use==SID_NAME_ALIAS
|
||||
|| map.sid_name_use==SID_NAME_DOM_GRP
|
||||
|| map.sid_name_use==SID_NAME_UNKNOWN) {
|
||||
map.sid_name_use=sid_type;
|
||||
} else {
|
||||
printf("cannot change group type to builtin\n");
|
||||
};
|
||||
} else {
|
||||
printf("cannot change group type from builtin\n");
|
||||
}
|
||||
|
||||
if (ntgroup!=NULL)
|
||||
fstrcpy(map.nt_name, ntgroup);
|
||||
|
||||
/* Change comment if new one */
|
||||
if (groupdesc!=NULL)
|
||||
fstrcpy(map.comment, groupdesc);
|
||||
|
||||
/* Change the privilege if new one */
|
||||
if (privilege!=NULL)
|
||||
convert_priv_from_text(&map.priv_set, privilege);
|
||||
|
||||
if (!pdb_update_group_mapping_entry(&map)) {
|
||||
printf("Could not update group database\n");
|
||||
free_privilege(&map.priv_set);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free_privilege(&map.priv_set);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
Delete the group.
|
||||
**********************************************************/
|
||||
static int deletegroup(char *group)
|
||||
{
|
||||
DOM_SID sid;
|
||||
|
||||
if (!get_sid_from_input(&sid, group)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!pdb_delete_group_mapping_entry(sid)) {
|
||||
printf("removing group %s from the mapping db failed!\n", group);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
List the groups.
|
||||
**********************************************************/
|
||||
static int listgroup(enum SID_NAME_USE sid_type, BOOL long_list)
|
||||
{
|
||||
int entries,i;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
GROUP_MAP *map=NULL;
|
||||
fstring string_sid;
|
||||
fstring group_type;
|
||||
fstring priv_text;
|
||||
|
||||
if (!long_list)
|
||||
printf("NT group (SID) -> Unix group\n");
|
||||
|
||||
if (!pdb_enum_group_mapping(sid_type, &map, &entries, ENUM_ALL_MAPPED, MAPPING_WITH_PRIV))
|
||||
return -1;
|
||||
|
||||
mem_ctx = talloc_init("smbgroupedit talloc");
|
||||
if (!mem_ctx) return -1;
|
||||
for (i=0; i<entries; i++) {
|
||||
decode_sid_name_use(group_type, (map[i]).sid_name_use);
|
||||
sid_to_string(string_sid, &map[i].sid);
|
||||
convert_priv_to_text(&(map[i].priv_set), priv_text);
|
||||
free_privilege(&(map[i].priv_set));
|
||||
|
||||
if (!long_list)
|
||||
printf("%s (%s) -> %s\n", map[i].nt_name, string_sid,
|
||||
gidtoname(mem_ctx, map[i].gid));
|
||||
else {
|
||||
printf("%s\n", map[i].nt_name);
|
||||
printf("\tSID : %s\n", string_sid);
|
||||
printf("\tUnix group: %s\n", gidtoname(mem_ctx, map[i].gid));
|
||||
printf("\tGroup type: %s\n", group_type);
|
||||
printf("\tComment : %s\n", map[i].comment);
|
||||
printf("\tPrivilege : %s\n\n", priv_text);
|
||||
}
|
||||
}
|
||||
talloc_destroy(mem_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************************************
|
||||
Start here.
|
||||
**********************************************************/
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
int ch;
|
||||
BOOL add_group = False;
|
||||
BOOL view_group = False;
|
||||
BOOL change_group = False;
|
||||
BOOL delete_group = False;
|
||||
BOOL nt_group = False;
|
||||
BOOL priv = False;
|
||||
BOOL group_type = False;
|
||||
BOOL long_list = False;
|
||||
|
||||
char *group = NULL;
|
||||
char *sid = NULL;
|
||||
char *ntgroup = NULL;
|
||||
char *privilege = NULL;
|
||||
char *groupt = NULL;
|
||||
char *group_desc = NULL;
|
||||
|
||||
enum SID_NAME_USE sid_type;
|
||||
uint32 rid = -1;
|
||||
|
||||
setup_logging("groupedit", True);
|
||||
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!lp_load(dyn_CONFIGFILE,True,False,False)) {
|
||||
fprintf(stderr, "Can't load %s - run testparm to debug it\n",
|
||||
dyn_CONFIGFILE);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!init_names())
|
||||
exit(1);
|
||||
|
||||
if(!initialize_password_db(True)) {
|
||||
fprintf(stderr, "Can't setup password database vectors.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(get_global_sam_sid()==False) {
|
||||
fprintf(stderr, "Can not read machine SID\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
while ((ch = getopt(argc, argv, "a:c:d:ln:p:r:st:u:vx:")) != EOF) {
|
||||
switch(ch) {
|
||||
case 'a':
|
||||
add_group = True;
|
||||
group=optarg;
|
||||
break;
|
||||
case 'c':
|
||||
change_group = True;
|
||||
sid=optarg;
|
||||
break;
|
||||
case 'd':
|
||||
group_desc=optarg;
|
||||
break;
|
||||
case 'l':
|
||||
long_list = True;
|
||||
break;
|
||||
case 'n':
|
||||
nt_group = True;
|
||||
ntgroup=optarg;
|
||||
break;
|
||||
case 'p':
|
||||
priv = True;
|
||||
privilege=optarg;
|
||||
break;
|
||||
case 'r':
|
||||
rid = atoi(optarg);
|
||||
break;
|
||||
case 's':
|
||||
long_list = False;
|
||||
break;
|
||||
case 't':
|
||||
group_type = True;
|
||||
groupt=optarg;
|
||||
break;
|
||||
case 'u':
|
||||
group=optarg;
|
||||
break;
|
||||
case 'v':
|
||||
view_group = True;
|
||||
break;
|
||||
case 'x':
|
||||
delete_group = True;
|
||||
group=optarg;
|
||||
break;
|
||||
/*default:
|
||||
usage();*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (((add_group?1:0) + (view_group?1:0) + (change_group?1:0) + (delete_group?1:0)) > 1) {
|
||||
fprintf (stderr, "Incompatible options on command line!\n");
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* no option on command line -> list groups */
|
||||
if (((add_group?1:0) + (view_group?1:0) + (change_group?1:0) + (delete_group?1:0)) == 0)
|
||||
view_group = True;
|
||||
|
||||
|
||||
if (group_type==False)
|
||||
sid_type=SID_NAME_UNKNOWN;
|
||||
else {
|
||||
switch (groupt[0]) {
|
||||
case 'l':
|
||||
case 'L':
|
||||
sid_type=SID_NAME_ALIAS;
|
||||
break;
|
||||
case 'd':
|
||||
case 'D':
|
||||
sid_type=SID_NAME_DOM_GRP;
|
||||
break;
|
||||
case 'b':
|
||||
case 'B':
|
||||
sid_type=SID_NAME_WKN_GRP;
|
||||
break;
|
||||
default:
|
||||
sid_type=SID_NAME_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (add_group) {
|
||||
gid_t gid=nametogid(group);
|
||||
if (gid==-1) {
|
||||
printf("unix group %s doesn't exist!\n", group);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rid == -1) {
|
||||
rid = pdb_gid_to_group_rid(gid);
|
||||
}
|
||||
return addgroup(gid, sid_type, ntgroup?ntgroup:group,
|
||||
group_desc, privilege, rid);
|
||||
}
|
||||
|
||||
if (view_group)
|
||||
return listgroup(sid_type, long_list);
|
||||
|
||||
if (delete_group)
|
||||
return deletegroup(group);
|
||||
|
||||
if (change_group) {
|
||||
return changegroup(sid, group, sid_type, ntgroup, group_desc, privilege);
|
||||
}
|
||||
|
||||
usage();
|
||||
|
||||
return 0;
|
||||
}
|
||||
605
source/utils/smbpasswd.c
Normal file
605
source/utils/smbpasswd.c
Normal file
@@ -0,0 +1,605 @@
|
||||
/*
|
||||
* Unix SMB/CIFS implementation.
|
||||
* Copyright (C) Jeremy Allison 1995-1998
|
||||
* Copyright (C) Tim Potter 2001
|
||||
*
|
||||
* 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 the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 675
|
||||
* Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
extern BOOL AllowDebugChange;
|
||||
|
||||
/*
|
||||
* Next two lines needed for SunOS and don't
|
||||
* hurt anything else...
|
||||
*/
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
|
||||
/* forced running in root-mode */
|
||||
static BOOL got_pass = False, got_username = False;
|
||||
static BOOL stdin_passwd_get = False;
|
||||
static fstring user_name, user_password;
|
||||
static char *new_passwd = NULL;
|
||||
static const char *remote_machine = NULL;
|
||||
|
||||
static fstring ldap_secret;
|
||||
|
||||
/*********************************************************
|
||||
Print command usage on stderr and die.
|
||||
**********************************************************/
|
||||
static void usage(void)
|
||||
{
|
||||
printf("When run by root:\n");
|
||||
printf(" smbpasswd [options] [username] [password]\n");
|
||||
printf("otherwise:\n");
|
||||
printf(" smbpasswd [options] [password]\n\n");
|
||||
|
||||
printf("options:\n");
|
||||
printf(" -L local mode (must be first option)\n");
|
||||
printf(" -h print this usage message\n");
|
||||
printf(" -s use stdin for password prompt\n");
|
||||
printf(" -c smb.conf file Use the given path to the smb.conf file\n");
|
||||
printf(" -D LEVEL debug level\n");
|
||||
printf(" -r MACHINE remote machine\n");
|
||||
printf(" -U USER remote username\n");
|
||||
|
||||
printf("extra options when run by root or in local mode:\n");
|
||||
printf(" -a add user\n");
|
||||
printf(" -d disable user\n");
|
||||
printf(" -e enable user\n");
|
||||
printf(" -i interdomain trust account\n");
|
||||
printf(" -m machine trust account\n");
|
||||
printf(" -n set no password\n");
|
||||
printf(" -w ldap admin password\n");
|
||||
printf(" -x delete user\n");
|
||||
printf(" -R ORDER name resolve order\n");
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void set_line_buffering(FILE *f)
|
||||
{
|
||||
setvbuf(f, NULL, _IOLBF, 0);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
Process command line options
|
||||
******************************************************************/
|
||||
static int process_options(int argc, char **argv, int local_flags)
|
||||
{
|
||||
int ch;
|
||||
pstring configfile;
|
||||
pstrcpy(configfile, dyn_CONFIGFILE);
|
||||
|
||||
local_flags |= LOCAL_SET_PASSWORD;
|
||||
|
||||
ZERO_STRUCT(user_name);
|
||||
ZERO_STRUCT(user_password);
|
||||
|
||||
user_name[0] = '\0';
|
||||
|
||||
while ((ch = getopt(argc, argv, "c:axdehminjr:sw:R:D:U:L")) != EOF) {
|
||||
switch(ch) {
|
||||
case 'L':
|
||||
local_flags |= LOCAL_AM_ROOT;
|
||||
break;
|
||||
case 'c':
|
||||
pstrcpy(configfile,optarg);
|
||||
break;
|
||||
case 'a':
|
||||
local_flags |= LOCAL_ADD_USER;
|
||||
break;
|
||||
case 'x':
|
||||
local_flags |= LOCAL_DELETE_USER;
|
||||
local_flags &= ~LOCAL_SET_PASSWORD;
|
||||
break;
|
||||
case 'd':
|
||||
local_flags |= LOCAL_DISABLE_USER;
|
||||
local_flags &= ~LOCAL_SET_PASSWORD;
|
||||
break;
|
||||
case 'e':
|
||||
local_flags |= LOCAL_ENABLE_USER;
|
||||
local_flags &= ~LOCAL_SET_PASSWORD;
|
||||
break;
|
||||
case 'm':
|
||||
local_flags |= LOCAL_TRUST_ACCOUNT;
|
||||
break;
|
||||
case 'i':
|
||||
local_flags |= LOCAL_INTERDOM_ACCOUNT;
|
||||
break;
|
||||
case 'j':
|
||||
d_printf("See 'net join' for this functionality\n");
|
||||
exit(1);
|
||||
break;
|
||||
case 'n':
|
||||
local_flags |= LOCAL_SET_NO_PASSWORD;
|
||||
local_flags &= ~LOCAL_SET_PASSWORD;
|
||||
new_passwd = smb_xstrdup("NO PASSWORD");
|
||||
break;
|
||||
case 'r':
|
||||
remote_machine = optarg;
|
||||
break;
|
||||
case 's':
|
||||
set_line_buffering(stdin);
|
||||
set_line_buffering(stdout);
|
||||
set_line_buffering(stderr);
|
||||
stdin_passwd_get = True;
|
||||
break;
|
||||
case 'w':
|
||||
local_flags |= LOCAL_SET_LDAP_ADMIN_PW;
|
||||
fstrcpy(ldap_secret, optarg);
|
||||
break;
|
||||
case 'R':
|
||||
lp_set_name_resolve_order(optarg);
|
||||
break;
|
||||
case 'D':
|
||||
DEBUGLEVEL = atoi(optarg);
|
||||
break;
|
||||
case 'U': {
|
||||
char *lp;
|
||||
|
||||
got_username = True;
|
||||
fstrcpy(user_name, optarg);
|
||||
|
||||
if ((lp = strchr(user_name, '%'))) {
|
||||
*lp = 0;
|
||||
fstrcpy(user_password, lp + 1);
|
||||
got_pass = True;
|
||||
memset(strchr_m(optarg, '%') + 1, 'X',
|
||||
strlen(user_password));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 'h':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
switch(argc) {
|
||||
case 0:
|
||||
if (!got_username)
|
||||
fstrcpy(user_name, "");
|
||||
break;
|
||||
case 1:
|
||||
if (!(local_flags & LOCAL_AM_ROOT)) {
|
||||
new_passwd = argv[0];
|
||||
} else {
|
||||
if (got_username) {
|
||||
usage();
|
||||
} else {
|
||||
fstrcpy(user_name, argv[0]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (!(local_flags & LOCAL_AM_ROOT) || got_username || got_pass) {
|
||||
usage();
|
||||
}
|
||||
|
||||
fstrcpy(user_name, argv[0]);
|
||||
new_passwd = smb_xstrdup(argv[1]);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
|
||||
if (!lp_load(configfile,True,False,False)) {
|
||||
fprintf(stderr, "Can't load %s - run testparm to debug it\n",
|
||||
dyn_CONFIGFILE);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return local_flags;
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
Utility function to prompt for passwords from stdin. Each
|
||||
password entered must end with a newline.
|
||||
*************************************************************/
|
||||
static char *stdin_new_passwd(void)
|
||||
{
|
||||
static fstring new_pw;
|
||||
size_t len;
|
||||
|
||||
ZERO_ARRAY(new_pw);
|
||||
|
||||
/*
|
||||
* if no error is reported from fgets() and string at least contains
|
||||
* the newline that ends the password, then replace the newline with
|
||||
* a null terminator.
|
||||
*/
|
||||
if ( fgets(new_pw, sizeof(new_pw), stdin) != NULL) {
|
||||
if ((len = strlen(new_pw)) > 0) {
|
||||
if(new_pw[len-1] == '\n')
|
||||
new_pw[len - 1] = 0;
|
||||
}
|
||||
}
|
||||
return(new_pw);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************
|
||||
Utility function to get passwords via tty or stdin
|
||||
Used if the '-s' option is set to silently get passwords
|
||||
to enable scripting.
|
||||
*************************************************************/
|
||||
static char *get_pass( const char *prompt, BOOL stdin_get)
|
||||
{
|
||||
char *p;
|
||||
if (stdin_get) {
|
||||
p = stdin_new_passwd();
|
||||
} else {
|
||||
p = getpass(prompt);
|
||||
}
|
||||
return smb_xstrdup(p);
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
Utility function to prompt for new password.
|
||||
*************************************************************/
|
||||
static char *prompt_for_new_password(BOOL stdin_get)
|
||||
{
|
||||
char *p;
|
||||
fstring new_pw;
|
||||
|
||||
ZERO_ARRAY(new_pw);
|
||||
|
||||
p = get_pass("New SMB password:", stdin_get);
|
||||
|
||||
fstrcpy(new_pw, p);
|
||||
SAFE_FREE(p);
|
||||
|
||||
p = get_pass("Retype new SMB password:", stdin_get);
|
||||
|
||||
if (strcmp(p, new_pw)) {
|
||||
fprintf(stderr, "Mismatch - password unchanged.\n");
|
||||
ZERO_ARRAY(new_pw);
|
||||
SAFE_FREE(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************
|
||||
Change a password either locally or remotely.
|
||||
*************************************************************/
|
||||
|
||||
static BOOL password_change(const char *remote_mach, char *username,
|
||||
char *old_passwd, char *new_pw, int local_flags)
|
||||
{
|
||||
BOOL ret;
|
||||
pstring err_str;
|
||||
pstring msg_str;
|
||||
|
||||
if (remote_mach != NULL) {
|
||||
if (local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER|
|
||||
LOCAL_TRUST_ACCOUNT|LOCAL_SET_NO_PASSWORD)) {
|
||||
/* these things can't be done remotely yet */
|
||||
return False;
|
||||
}
|
||||
ret = remote_password_change(remote_mach, username,
|
||||
old_passwd, new_pw, err_str, sizeof(err_str));
|
||||
if(*err_str)
|
||||
fprintf(stderr, err_str);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = local_password_change(username, local_flags, new_pw,
|
||||
err_str, sizeof(err_str), msg_str, sizeof(msg_str));
|
||||
|
||||
if(*msg_str)
|
||||
printf(msg_str);
|
||||
if(*err_str)
|
||||
fprintf(stderr, err_str);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
Store the LDAP admin password in secrets.tdb
|
||||
******************************************************************/
|
||||
static BOOL store_ldap_admin_pw (char* pw)
|
||||
{
|
||||
if (!pw)
|
||||
return False;
|
||||
|
||||
if (!secrets_init())
|
||||
return False;
|
||||
|
||||
return secrets_store_ldap_pw(lp_ldap_admin_dn(), pw);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************
|
||||
Handle password changing for root.
|
||||
*************************************************************/
|
||||
|
||||
static int process_root(int local_flags)
|
||||
{
|
||||
struct passwd *pwd;
|
||||
int result = 0;
|
||||
char *old_passwd = NULL;
|
||||
|
||||
if (local_flags & LOCAL_SET_LDAP_ADMIN_PW)
|
||||
{
|
||||
printf("Setting stored password for \"%s\" in secrets.tdb\n",
|
||||
lp_ldap_admin_dn());
|
||||
if (!store_ldap_admin_pw(ldap_secret))
|
||||
DEBUG(0,("ERROR: Failed to store the ldap admin password!\n"));
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure both add/delete user are not set
|
||||
* Ensure add/delete user and either remote machine or join domain are
|
||||
* not both set.
|
||||
*/
|
||||
if(((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) == (LOCAL_ADD_USER|LOCAL_DELETE_USER)) ||
|
||||
((local_flags & (LOCAL_ADD_USER|LOCAL_DELETE_USER)) &&
|
||||
(remote_machine != NULL))) {
|
||||
usage();
|
||||
}
|
||||
|
||||
/* Only load interfaces if we are doing network operations. */
|
||||
|
||||
if (remote_machine) {
|
||||
load_interfaces();
|
||||
}
|
||||
|
||||
if (!user_name[0] && (pwd = getpwuid_alloc(geteuid()))) {
|
||||
fstrcpy(user_name, pwd->pw_name);
|
||||
passwd_free(&pwd);
|
||||
}
|
||||
|
||||
if (!user_name[0]) {
|
||||
fprintf(stderr,"You must specify a username\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (local_flags & LOCAL_TRUST_ACCOUNT) {
|
||||
/* add the $ automatically */
|
||||
static fstring buf;
|
||||
|
||||
/*
|
||||
* Remove any trailing '$' before we
|
||||
* generate the initial machine password.
|
||||
*/
|
||||
|
||||
if (user_name[strlen(user_name)-1] == '$') {
|
||||
user_name[strlen(user_name)-1] = 0;
|
||||
}
|
||||
|
||||
if (local_flags & LOCAL_ADD_USER) {
|
||||
SAFE_FREE(new_passwd);
|
||||
new_passwd = smb_xstrdup(user_name);
|
||||
strlower(new_passwd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now ensure the username ends in '$' for
|
||||
* the machine add.
|
||||
*/
|
||||
|
||||
slprintf(buf, sizeof(buf)-1, "%s$", user_name);
|
||||
fstrcpy(user_name, buf);
|
||||
} else if (local_flags & LOCAL_INTERDOM_ACCOUNT) {
|
||||
static fstring buf;
|
||||
|
||||
if (local_flags & LOCAL_ADD_USER) {
|
||||
/*
|
||||
* Prompt for trusting domain's account password
|
||||
*/
|
||||
new_passwd = prompt_for_new_password(stdin_passwd_get);
|
||||
if(!new_passwd) {
|
||||
fprintf(stderr, "Unable to get newpassword.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* prepare uppercased and '$' terminated username */
|
||||
slprintf(buf, sizeof(buf) - 1, "%s$", user_name);
|
||||
fstrcpy(user_name, buf);
|
||||
|
||||
} else {
|
||||
|
||||
if (remote_machine != NULL) {
|
||||
old_passwd = get_pass("Old SMB password:",stdin_passwd_get);
|
||||
}
|
||||
|
||||
if (!(local_flags & LOCAL_SET_PASSWORD)) {
|
||||
|
||||
/*
|
||||
* If we are trying to enable a user, first we need to find out
|
||||
* if they are using a modern version of the smbpasswd file that
|
||||
* disables a user by just writing a flag into the file. If so
|
||||
* then we can re-enable a user without prompting for a new
|
||||
* password. If not (ie. they have a no stored password in the
|
||||
* smbpasswd file) then we need to prompt for a new password.
|
||||
*/
|
||||
|
||||
if(local_flags & LOCAL_ENABLE_USER) {
|
||||
SAM_ACCOUNT *sampass = NULL;
|
||||
BOOL ret;
|
||||
|
||||
pdb_init_sam(&sampass);
|
||||
ret = pdb_getsampwnam(sampass, user_name);
|
||||
if((sampass != False) && (pdb_get_lanman_passwd(sampass) == NULL)) {
|
||||
local_flags |= LOCAL_SET_PASSWORD;
|
||||
}
|
||||
pdb_free_sam(&sampass);
|
||||
}
|
||||
}
|
||||
|
||||
if(local_flags & LOCAL_SET_PASSWORD) {
|
||||
new_passwd = prompt_for_new_password(stdin_passwd_get);
|
||||
|
||||
if(!new_passwd) {
|
||||
fprintf(stderr, "Unable to get new password.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!password_change(remote_machine, user_name, old_passwd, new_passwd, local_flags)) {
|
||||
fprintf(stderr,"Failed to modify password entry for user %s\n", user_name);
|
||||
result = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if(remote_machine) {
|
||||
printf("Password changed for user %s on %s.\n", user_name, remote_machine );
|
||||
} else if(!(local_flags & (LOCAL_ADD_USER|LOCAL_DISABLE_USER|LOCAL_ENABLE_USER|LOCAL_DELETE_USER|LOCAL_SET_NO_PASSWORD|LOCAL_SET_PASSWORD))) {
|
||||
SAM_ACCOUNT *sampass = NULL;
|
||||
BOOL ret;
|
||||
|
||||
pdb_init_sam(&sampass);
|
||||
ret = pdb_getsampwnam(sampass, user_name);
|
||||
|
||||
printf("Password changed for user %s.", user_name );
|
||||
if( (ret != False) && (pdb_get_acct_ctrl(sampass)&ACB_DISABLED) )
|
||||
printf(" User has disabled flag set.");
|
||||
if((ret != False) && (pdb_get_acct_ctrl(sampass) & ACB_PWNOTREQ) )
|
||||
printf(" User has no password flag set.");
|
||||
printf("\n");
|
||||
pdb_free_sam(&sampass);
|
||||
}
|
||||
|
||||
done:
|
||||
SAFE_FREE(new_passwd);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************
|
||||
Handle password changing for non-root.
|
||||
*************************************************************/
|
||||
|
||||
static int process_nonroot(int local_flags)
|
||||
{
|
||||
struct passwd *pwd = NULL;
|
||||
int result = 0;
|
||||
char *old_pw = NULL;
|
||||
char *new_pw = NULL;
|
||||
|
||||
if (local_flags & ~(LOCAL_AM_ROOT | LOCAL_SET_PASSWORD)) {
|
||||
/* Extra flags that we can't honor non-root */
|
||||
usage();
|
||||
}
|
||||
|
||||
if (!user_name[0]) {
|
||||
pwd = getpwuid_alloc(getuid());
|
||||
if (pwd) {
|
||||
fstrcpy(user_name,pwd->pw_name);
|
||||
passwd_free(&pwd);
|
||||
} else {
|
||||
fprintf(stderr, "smbpasswd: you don't exist - go away\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* A non-root user is always setting a password
|
||||
* via a remote machine (even if that machine is
|
||||
* localhost).
|
||||
*/
|
||||
|
||||
load_interfaces(); /* Delayed from main() */
|
||||
|
||||
if (remote_machine == NULL) {
|
||||
remote_machine = "127.0.0.1";
|
||||
}
|
||||
|
||||
if (remote_machine != NULL) {
|
||||
old_pw = get_pass("Old SMB password:",stdin_passwd_get);
|
||||
}
|
||||
|
||||
if (!new_passwd) {
|
||||
new_pw = prompt_for_new_password(stdin_passwd_get);
|
||||
}
|
||||
else
|
||||
new_pw = smb_xstrdup(new_passwd);
|
||||
|
||||
if (!new_pw) {
|
||||
fprintf(stderr, "Unable to get new password.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!password_change(remote_machine, user_name, old_pw, new_pw, 0)) {
|
||||
fprintf(stderr,"Failed to change password for %s\n", user_name);
|
||||
result = 1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
printf("Password changed for user %s\n", user_name);
|
||||
|
||||
done:
|
||||
SAFE_FREE(old_pw);
|
||||
SAFE_FREE(new_pw);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*********************************************************
|
||||
Start here.
|
||||
**********************************************************/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int local_flags = 0;
|
||||
|
||||
AllowDebugChange = False;
|
||||
|
||||
#if defined(HAVE_SET_AUTH_PARAMETERS)
|
||||
set_auth_parameters(argc, argv);
|
||||
#endif /* HAVE_SET_AUTH_PARAMETERS */
|
||||
|
||||
if (getuid() == 0) {
|
||||
local_flags = LOCAL_AM_ROOT;
|
||||
}
|
||||
|
||||
local_flags = process_options(argc, argv, local_flags);
|
||||
|
||||
setup_logging("smbpasswd", True);
|
||||
|
||||
/*
|
||||
* Set the machine NETBIOS name if not already
|
||||
* set from the config file.
|
||||
*/
|
||||
|
||||
if (!init_names())
|
||||
return 1;
|
||||
|
||||
/* Check the effective uid - make sure we are not setuid */
|
||||
if (is_setuid_root()) {
|
||||
fprintf(stderr, "smbpasswd must *NOT* be setuid root.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (local_flags & LOCAL_AM_ROOT) {
|
||||
secrets_init();
|
||||
return process_root(local_flags);
|
||||
}
|
||||
|
||||
return process_nonroot(local_flags);
|
||||
}
|
||||
369
source/utils/smbtree.c
Normal file
369
source/utils/smbtree.c
Normal file
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Network neighbourhood browser.
|
||||
|
||||
Copyright (C) Tim Potter 2000
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
static BOOL use_bcast;
|
||||
|
||||
struct user_auth_info {
|
||||
pstring username;
|
||||
pstring password;
|
||||
pstring workgroup;
|
||||
};
|
||||
|
||||
/* How low can we go? */
|
||||
|
||||
enum tree_level {LEV_WORKGROUP, LEV_SERVER, LEV_SHARE};
|
||||
static enum tree_level level = LEV_SHARE;
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf(
|
||||
"Usage: smbtree [options]\n\
|
||||
\n\
|
||||
\t-d debuglevel set debug output level\n\
|
||||
\t-U username user to autheticate as\n\
|
||||
\t-W workgroup workgroup of user to authenticate as\n\
|
||||
\t-D list only domains (workgroups) of tree\n\
|
||||
\t-S list domains and servers of tree\n\
|
||||
\t-b use bcast instead of using the master browser\n\
|
||||
\n\
|
||||
The username can be of the form username%%password or\n\
|
||||
workgroup\\username%%password.\n\n\
|
||||
");
|
||||
}
|
||||
|
||||
/* Holds a list of workgroups or servers */
|
||||
|
||||
struct name_list {
|
||||
struct name_list *prev, *next;
|
||||
pstring name, comment;
|
||||
uint32 server_type;
|
||||
};
|
||||
|
||||
static struct name_list *workgroups, *servers, *shares;
|
||||
|
||||
static void free_name_list(struct name_list *list)
|
||||
{
|
||||
while(list)
|
||||
DLIST_REMOVE(list, list);
|
||||
}
|
||||
|
||||
static void add_name(const char *machine_name, uint32 server_type,
|
||||
const char *comment, void *state)
|
||||
{
|
||||
struct name_list **name_list = (struct name_list **)state;
|
||||
struct name_list *new_name;
|
||||
|
||||
new_name = (struct name_list *)malloc(sizeof(struct name_list));
|
||||
|
||||
if (!new_name)
|
||||
return;
|
||||
|
||||
ZERO_STRUCTP(new_name);
|
||||
|
||||
pstrcpy(new_name->name, machine_name);
|
||||
pstrcpy(new_name->comment, comment);
|
||||
new_name->server_type = server_type;
|
||||
|
||||
DLIST_ADD(*name_list, new_name);
|
||||
}
|
||||
|
||||
/* Return a cli_state pointing at the IPC$ share for the given server */
|
||||
|
||||
static struct cli_state *get_ipc_connect(char *server, struct in_addr *server_ip,
|
||||
struct user_auth_info *user_info)
|
||||
{
|
||||
struct cli_state *cli;
|
||||
char *myname;
|
||||
NTSTATUS nt_status;
|
||||
|
||||
myname = get_myname();
|
||||
|
||||
nt_status = cli_full_connection(&cli, myname, server, server_ip, 0, "IPC$", "IPC",
|
||||
user_info->username, lp_workgroup(), user_info->password,
|
||||
CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK, NULL);
|
||||
|
||||
free(myname);
|
||||
if (NT_STATUS_IS_OK(nt_status)) {
|
||||
return cli;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the IP address and workgroup of a master browser on the
|
||||
network. */
|
||||
|
||||
static BOOL find_master_ip_bcast(pstring workgroup, struct in_addr *server_ip)
|
||||
{
|
||||
struct in_addr *ip_list;
|
||||
int i, count;
|
||||
|
||||
/* Go looking for workgroups by broadcasting on the local network */
|
||||
|
||||
if (!name_resolve_bcast(MSBROWSE, 1, &ip_list, &count)) {
|
||||
return False;
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
static fstring name;
|
||||
|
||||
if (!name_status_find("*", 0, 0x1d, ip_list[i], name))
|
||||
continue;
|
||||
|
||||
if (!find_master_ip(name, server_ip))
|
||||
continue;
|
||||
|
||||
pstrcpy(workgroup, name);
|
||||
|
||||
DEBUG(4, ("found master browser %s, %s\n",
|
||||
name, inet_ntoa(ip_list[i])));
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
return False;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
display tree of smb workgroups, servers and shares
|
||||
****************************************************************************/
|
||||
static BOOL get_workgroups(struct user_auth_info *user_info)
|
||||
{
|
||||
struct cli_state *cli;
|
||||
struct in_addr server_ip;
|
||||
pstring master_workgroup;
|
||||
|
||||
/* Try to connect to a #1d name of our current workgroup. If that
|
||||
doesn't work broadcast for a master browser and then jump off
|
||||
that workgroup. */
|
||||
|
||||
pstrcpy(master_workgroup, lp_workgroup());
|
||||
|
||||
if (use_bcast || !find_master_ip(lp_workgroup(), &server_ip)) {
|
||||
DEBUG(4, ("Unable to find master browser for workgroup %s\n",
|
||||
master_workgroup));
|
||||
if (!find_master_ip_bcast(master_workgroup, &server_ip)) {
|
||||
DEBUG(4, ("Unable to find master browser by "
|
||||
"broadcast\n"));
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(cli = get_ipc_connect(inet_ntoa(server_ip), &server_ip, user_info)))
|
||||
return False;
|
||||
|
||||
if (!cli_NetServerEnum(cli, master_workgroup,
|
||||
SV_TYPE_DOMAIN_ENUM, add_name, &workgroups))
|
||||
return False;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/* Retrieve the list of servers for a given workgroup */
|
||||
|
||||
static BOOL get_servers(char *workgroup, struct user_auth_info *user_info)
|
||||
{
|
||||
struct cli_state *cli;
|
||||
struct in_addr server_ip;
|
||||
|
||||
/* Open an IPC$ connection to the master browser for the workgroup */
|
||||
|
||||
if (!find_master_ip(workgroup, &server_ip)) {
|
||||
DEBUG(4, ("Cannot find master browser for workgroup %s\n",
|
||||
workgroup));
|
||||
return False;
|
||||
}
|
||||
|
||||
if (!(cli = get_ipc_connect(inet_ntoa(server_ip), &server_ip, user_info)))
|
||||
return False;
|
||||
|
||||
if (!cli_NetServerEnum(cli, workgroup, SV_TYPE_ALL, add_name,
|
||||
&servers))
|
||||
return False;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
static BOOL get_shares(char *server_name, struct user_auth_info *user_info)
|
||||
{
|
||||
struct cli_state *cli;
|
||||
|
||||
if (!(cli = get_ipc_connect(server_name, NULL, user_info)))
|
||||
return False;
|
||||
|
||||
if (!cli_RNetShareEnum(cli, add_name, &shares))
|
||||
return False;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
static BOOL print_tree(struct user_auth_info *user_info)
|
||||
{
|
||||
struct name_list *wg, *sv, *sh;
|
||||
|
||||
/* List workgroups */
|
||||
|
||||
if (!get_workgroups(user_info))
|
||||
return False;
|
||||
|
||||
for (wg = workgroups; wg; wg = wg->next) {
|
||||
|
||||
printf("%s\n", wg->name);
|
||||
|
||||
/* List servers */
|
||||
|
||||
free_name_list(servers);
|
||||
servers = NULL;
|
||||
|
||||
if (level == LEV_WORKGROUP ||
|
||||
!get_servers(wg->name, user_info))
|
||||
continue;
|
||||
|
||||
for (sv = servers; sv; sv = sv->next) {
|
||||
|
||||
printf("\t\\\\%-15s\t\t%s\n",
|
||||
sv->name, sv->comment);
|
||||
|
||||
/* List shares */
|
||||
|
||||
free_name_list(shares);
|
||||
shares = NULL;
|
||||
|
||||
if (level == LEV_SERVER ||
|
||||
!get_shares(sv->name, user_info))
|
||||
continue;
|
||||
|
||||
for (sh = shares; sh; sh = sh->next) {
|
||||
printf("\t\t\\\\%s\\%-15s\t%s\n",
|
||||
sv->name, sh->name, sh->comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
main program
|
||||
****************************************************************************/
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
int opt;
|
||||
char *p;
|
||||
struct user_auth_info user_info;
|
||||
BOOL got_pass = False;
|
||||
|
||||
/* Initialise samba stuff */
|
||||
|
||||
setlinebuf(stdout);
|
||||
|
||||
dbf = x_stderr;
|
||||
|
||||
setup_logging(argv[0],True);
|
||||
|
||||
lp_load(dyn_CONFIGFILE,True,False,False);
|
||||
load_interfaces();
|
||||
|
||||
if (getenv("USER")) {
|
||||
pstrcpy(user_info.username, getenv("USER"));
|
||||
|
||||
if ((p=strchr(user_info.username, '%'))) {
|
||||
*p = 0;
|
||||
pstrcpy(user_info.password, p+1);
|
||||
got_pass = True;
|
||||
memset(strchr(getenv("USER"), '%') + 1, 'X',
|
||||
strlen(user_info.password));
|
||||
}
|
||||
}
|
||||
|
||||
pstrcpy(user_info.workgroup, lp_workgroup());
|
||||
|
||||
/* Parse command line args */
|
||||
|
||||
while ((opt = getopt(argc, argv, "U:hd:W:DSb")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'U':
|
||||
pstrcpy(user_info.username,optarg);
|
||||
p = strchr(user_info.username,'%');
|
||||
if (p) {
|
||||
*p = 0;
|
||||
pstrcpy(user_info.password, p+1);
|
||||
got_pass = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
use_bcast = True;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage();
|
||||
exit(1);
|
||||
|
||||
case 'd':
|
||||
DEBUGLEVEL = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'W':
|
||||
pstrcpy(user_info.workgroup, optarg);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
level = LEV_WORKGROUP;
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
level = LEV_SERVER;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Unknown option %c (%d)\n", (char)opt, opt);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc > 0) {
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!got_pass) {
|
||||
char *pass = getpass("Password: ");
|
||||
if (pass) {
|
||||
pstrcpy(user_info.password, pass);
|
||||
}
|
||||
got_pass = True;
|
||||
}
|
||||
|
||||
/* Now do our stuff */
|
||||
|
||||
if (!print_tree(&user_info))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
94
source/utils/smbw_sample.c
Normal file
94
source/utils/smbw_sample.c
Normal file
@@ -0,0 +1,94 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("
|
||||
smbw_sample - a sample program that uses smbw
|
||||
|
||||
smbw_sample <options> path
|
||||
|
||||
options:
|
||||
-W workgroup
|
||||
-l logfile
|
||||
-P prefix
|
||||
-d debuglevel
|
||||
-U username%%password
|
||||
-R resolve order
|
||||
|
||||
note that path must start with /smb/
|
||||
");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *dent;
|
||||
int opt;
|
||||
char *p;
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
char *path;
|
||||
|
||||
lp_load(dyn_CONFIGFILE,1,0,0);
|
||||
smbw_setup_shared();
|
||||
|
||||
while ((opt = getopt(argc, argv, "W:U:R:d:P:l:hL:")) != EOF) {
|
||||
switch (opt) {
|
||||
case 'W':
|
||||
smbw_setshared("WORKGROUP", optarg);
|
||||
break;
|
||||
case 'l':
|
||||
smbw_setshared("LOGFILE", optarg);
|
||||
break;
|
||||
case 'P':
|
||||
smbw_setshared("PREFIX", optarg);
|
||||
break;
|
||||
case 'd':
|
||||
smbw_setshared("DEBUG", optarg);
|
||||
break;
|
||||
case 'U':
|
||||
p = strchr_m(optarg,'%');
|
||||
if (p) {
|
||||
*p=0;
|
||||
smbw_setshared("PASSWORD",p+1);
|
||||
}
|
||||
smbw_setshared("USER", optarg);
|
||||
break;
|
||||
case 'R':
|
||||
smbw_setshared("RESOLVE_ORDER",optarg);
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc < 1) {
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
path = argv[0];
|
||||
|
||||
smbw_init();
|
||||
|
||||
dir = smbw_opendir(path);
|
||||
if (!dir) {
|
||||
printf("failed to open %s\n", path);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while ((dent = smbw_readdir(dir))) {
|
||||
printf("%s\n", dent->d_name);
|
||||
}
|
||||
smbw_closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
665
source/utils/status.c
Normal file
665
source/utils/status.c
Normal file
@@ -0,0 +1,665 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
status reporting
|
||||
Copyright (C) Andrew Tridgell 1994-1998
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Revision History:
|
||||
|
||||
12 aug 96: Erik.Devriendt@te6.siemens.be
|
||||
added support for shared memory implementation of share mode locking
|
||||
|
||||
21-Jul-1998: rsharpe@ns.aus.com (Richard Sharpe)
|
||||
Added -L (locks only) -S (shares only) flags and code
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* This program reports current SMB connections
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
static pstring Ucrit_username = ""; /* added by OH */
|
||||
static pid_t Ucrit_pid[100]; /* Ugly !!! */ /* added by OH */
|
||||
static int Ucrit_MaxPid=0; /* added by OH */
|
||||
static unsigned int Ucrit_IsActive = 0; /* added by OH */
|
||||
static int verbose, brief;
|
||||
static int shares_only = 0; /* Added by RJS */
|
||||
static int locks_only = 0; /* Added by RJS */
|
||||
static BOOL processes_only=False;
|
||||
static int show_brl;
|
||||
|
||||
/* we need these because we link to locking*.o */
|
||||
void become_root(void) {}
|
||||
void unbecome_root(void) {}
|
||||
|
||||
|
||||
/* added by OH */
|
||||
static void Ucrit_addUsername(const char *username)
|
||||
{
|
||||
pstrcpy(Ucrit_username, username);
|
||||
if(strlen(Ucrit_username) > 0)
|
||||
Ucrit_IsActive = 1;
|
||||
}
|
||||
|
||||
static unsigned int Ucrit_checkUsername(const char *username)
|
||||
{
|
||||
if ( !Ucrit_IsActive) return 1;
|
||||
if (strcmp(Ucrit_username,username) ==0) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int Ucrit_checkPid(pid_t pid)
|
||||
{
|
||||
int i;
|
||||
if ( !Ucrit_IsActive) return 1;
|
||||
for (i=0;i<Ucrit_MaxPid;i++)
|
||||
if( pid == Ucrit_pid[i] ) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void print_share_mode(share_mode_entry *e, char *fname)
|
||||
{
|
||||
static int count;
|
||||
if (count==0) {
|
||||
d_printf("Locked files:\n");
|
||||
d_printf("Pid DenyMode Access R/W Oplock Name\n");
|
||||
d_printf("--------------------------------------------------------------\n");
|
||||
}
|
||||
count++;
|
||||
|
||||
if (Ucrit_checkPid(e->pid)) {
|
||||
d_printf("%-5d ",(int)e->pid);
|
||||
switch (GET_DENY_MODE(e->share_mode)) {
|
||||
case DENY_NONE: d_printf("DENY_NONE "); break;
|
||||
case DENY_ALL: d_printf("DENY_ALL "); break;
|
||||
case DENY_DOS: d_printf("DENY_DOS "); break;
|
||||
case DENY_READ: d_printf("DENY_READ "); break;
|
||||
case DENY_WRITE:printf("DENY_WRITE "); break;
|
||||
case DENY_FCB: d_printf("DENY_FCB "); break;
|
||||
}
|
||||
d_printf("0x%-8x ",(unsigned int)e->desired_access);
|
||||
switch (e->share_mode&0xF) {
|
||||
case 0: d_printf("RDONLY "); break;
|
||||
case 1: d_printf("WRONLY "); break;
|
||||
case 2: d_printf("RDWR "); break;
|
||||
}
|
||||
|
||||
if((e->op_type &
|
||||
(EXCLUSIVE_OPLOCK|BATCH_OPLOCK)) ==
|
||||
(EXCLUSIVE_OPLOCK|BATCH_OPLOCK))
|
||||
d_printf("EXCLUSIVE+BATCH ");
|
||||
else if (e->op_type & EXCLUSIVE_OPLOCK)
|
||||
d_printf("EXCLUSIVE ");
|
||||
else if (e->op_type & BATCH_OPLOCK)
|
||||
d_printf("BATCH ");
|
||||
else if (e->op_type & LEVEL_II_OPLOCK)
|
||||
d_printf("LEVEL_II ");
|
||||
else
|
||||
d_printf("NONE ");
|
||||
|
||||
d_printf(" %s %s",fname,
|
||||
asctime(LocalTime((time_t *)&e->time.tv_sec)));
|
||||
}
|
||||
}
|
||||
|
||||
static void print_brl(SMB_DEV_T dev, SMB_INO_T ino, int pid,
|
||||
enum brl_type lock_type,
|
||||
br_off start, br_off size)
|
||||
{
|
||||
static int count;
|
||||
if (count==0) {
|
||||
d_printf("Byte range locks:\n");
|
||||
d_printf(" Pid dev:inode R/W start size\n");
|
||||
d_printf("------------------------------------------------\n");
|
||||
}
|
||||
count++;
|
||||
|
||||
d_printf("%6d %05x:%05x %s %9.0f %9.0f\n",
|
||||
(int)pid, (int)dev, (int)ino,
|
||||
lock_type==READ_LOCK?"R":"W",
|
||||
(double)start, (double)size);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
dump the elements of the profile structure
|
||||
******************************************************************/
|
||||
static int profile_dump(void)
|
||||
{
|
||||
#ifdef WITH_PROFILE
|
||||
if (!profile_setup(True)) {
|
||||
fprintf(stderr,"Failed to initialise profile memory\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
d_printf("smb_count: %u\n", profile_p->smb_count);
|
||||
d_printf("uid_changes: %u\n", profile_p->uid_changes);
|
||||
d_printf("************************ System Calls ****************************\n");
|
||||
d_printf("opendir_count: %u\n", profile_p->syscall_opendir_count);
|
||||
d_printf("opendir_time: %u\n", profile_p->syscall_opendir_time);
|
||||
d_printf("readdir_count: %u\n", profile_p->syscall_readdir_count);
|
||||
d_printf("readdir_time: %u\n", profile_p->syscall_readdir_time);
|
||||
d_printf("mkdir_count: %u\n", profile_p->syscall_mkdir_count);
|
||||
d_printf("mkdir_time: %u\n", profile_p->syscall_mkdir_time);
|
||||
d_printf("rmdir_count: %u\n", profile_p->syscall_rmdir_count);
|
||||
d_printf("rmdir_time: %u\n", profile_p->syscall_rmdir_time);
|
||||
d_printf("closedir_count: %u\n", profile_p->syscall_closedir_count);
|
||||
d_printf("closedir_time: %u\n", profile_p->syscall_closedir_time);
|
||||
d_printf("open_count: %u\n", profile_p->syscall_open_count);
|
||||
d_printf("open_time: %u\n", profile_p->syscall_open_time);
|
||||
d_printf("close_count: %u\n", profile_p->syscall_close_count);
|
||||
d_printf("close_time: %u\n", profile_p->syscall_close_time);
|
||||
d_printf("read_count: %u\n", profile_p->syscall_read_count);
|
||||
d_printf("read_time: %u\n", profile_p->syscall_read_time);
|
||||
d_printf("read_bytes: %u\n", profile_p->syscall_read_bytes);
|
||||
d_printf("write_count: %u\n", profile_p->syscall_write_count);
|
||||
d_printf("write_time: %u\n", profile_p->syscall_write_time);
|
||||
d_printf("write_bytes: %u\n", profile_p->syscall_write_bytes);
|
||||
#ifdef WITH_SENDFILE
|
||||
d_printf("sendfile_count: %u\n", profile_p->syscall_sendfile_count);
|
||||
d_printf("sendfile_time: %u\n", profile_p->syscall_sendfile_time);
|
||||
d_printf("sendfile_bytes: %u\n", profile_p->syscall_sendfile_bytes);
|
||||
#endif
|
||||
d_printf("lseek_count: %u\n", profile_p->syscall_lseek_count);
|
||||
d_printf("lseek_time: %u\n", profile_p->syscall_lseek_time);
|
||||
d_printf("rename_count: %u\n", profile_p->syscall_rename_count);
|
||||
d_printf("rename_time: %u\n", profile_p->syscall_rename_time);
|
||||
d_printf("fsync_count: %u\n", profile_p->syscall_fsync_count);
|
||||
d_printf("fsync_time: %u\n", profile_p->syscall_fsync_time);
|
||||
d_printf("stat_count: %u\n", profile_p->syscall_stat_count);
|
||||
d_printf("stat_time: %u\n", profile_p->syscall_stat_time);
|
||||
d_printf("fstat_count: %u\n", profile_p->syscall_fstat_count);
|
||||
d_printf("fstat_time: %u\n", profile_p->syscall_fstat_time);
|
||||
d_printf("lstat_count: %u\n", profile_p->syscall_lstat_count);
|
||||
d_printf("lstat_time: %u\n", profile_p->syscall_lstat_time);
|
||||
d_printf("unlink_count: %u\n", profile_p->syscall_unlink_count);
|
||||
d_printf("unlink_time: %u\n", profile_p->syscall_unlink_time);
|
||||
d_printf("chmod_count: %u\n", profile_p->syscall_chmod_count);
|
||||
d_printf("chmod_time: %u\n", profile_p->syscall_chmod_time);
|
||||
d_printf("fchmod_count: %u\n", profile_p->syscall_fchmod_count);
|
||||
d_printf("fchmod_time: %u\n", profile_p->syscall_fchmod_time);
|
||||
d_printf("chown_count: %u\n", profile_p->syscall_chown_count);
|
||||
d_printf("chown_time: %u\n", profile_p->syscall_chown_time);
|
||||
d_printf("fchown_count: %u\n", profile_p->syscall_fchown_count);
|
||||
d_printf("fchown_time: %u\n", profile_p->syscall_fchown_time);
|
||||
d_printf("chdir_count: %u\n", profile_p->syscall_chdir_count);
|
||||
d_printf("chdir_time: %u\n", profile_p->syscall_chdir_time);
|
||||
d_printf("getwd_count: %u\n", profile_p->syscall_getwd_count);
|
||||
d_printf("getwd_time: %u\n", profile_p->syscall_getwd_time);
|
||||
d_printf("utime_count: %u\n", profile_p->syscall_utime_count);
|
||||
d_printf("utime_time: %u\n", profile_p->syscall_utime_time);
|
||||
d_printf("ftruncate_count: %u\n", profile_p->syscall_ftruncate_count);
|
||||
d_printf("ftruncate_time: %u\n", profile_p->syscall_ftruncate_time);
|
||||
d_printf("fcntl_lock_count: %u\n", profile_p->syscall_fcntl_lock_count);
|
||||
d_printf("fcntl_lock_time: %u\n", profile_p->syscall_fcntl_lock_time);
|
||||
d_printf("readlink_count: %u\n", profile_p->syscall_readlink_count);
|
||||
d_printf("readlink_time: %u\n", profile_p->syscall_readlink_time);
|
||||
d_printf("symlink_count: %u\n", profile_p->syscall_symlink_count);
|
||||
d_printf("symlink_time: %u\n", profile_p->syscall_symlink_time);
|
||||
d_printf("************************ Statcache *******************************\n");
|
||||
d_printf("lookups: %u\n", profile_p->statcache_lookups);
|
||||
d_printf("misses: %u\n", profile_p->statcache_misses);
|
||||
d_printf("hits: %u\n", profile_p->statcache_hits);
|
||||
d_printf("************************ Writecache ******************************\n");
|
||||
d_printf("read_hits: %u\n", profile_p->writecache_read_hits);
|
||||
d_printf("abutted_writes: %u\n", profile_p->writecache_abutted_writes);
|
||||
d_printf("total_writes: %u\n", profile_p->writecache_total_writes);
|
||||
d_printf("non_oplock_writes: %u\n", profile_p->writecache_non_oplock_writes);
|
||||
d_printf("direct_writes: %u\n", profile_p->writecache_direct_writes);
|
||||
d_printf("init_writes: %u\n", profile_p->writecache_init_writes);
|
||||
d_printf("flushed_writes[SEEK]: %u\n", profile_p->writecache_flushed_writes[SEEK_FLUSH]);
|
||||
d_printf("flushed_writes[READ]: %u\n", profile_p->writecache_flushed_writes[READ_FLUSH]);
|
||||
d_printf("flushed_writes[WRITE]: %u\n", profile_p->writecache_flushed_writes[WRITE_FLUSH]);
|
||||
d_printf("flushed_writes[READRAW]: %u\n", profile_p->writecache_flushed_writes[READRAW_FLUSH]);
|
||||
d_printf("flushed_writes[OPLOCK_RELEASE]: %u\n", profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH]);
|
||||
d_printf("flushed_writes[CLOSE]: %u\n", profile_p->writecache_flushed_writes[CLOSE_FLUSH]);
|
||||
d_printf("flushed_writes[SYNC]: %u\n", profile_p->writecache_flushed_writes[SYNC_FLUSH]);
|
||||
d_printf("flushed_writes[SIZECHANGE]: %u\n", profile_p->writecache_flushed_writes[SIZECHANGE_FLUSH]);
|
||||
d_printf("num_perfect_writes: %u\n", profile_p->writecache_num_perfect_writes);
|
||||
d_printf("num_write_caches: %u\n", profile_p->writecache_num_write_caches);
|
||||
d_printf("allocated_write_caches: %u\n", profile_p->writecache_allocated_write_caches);
|
||||
d_printf("************************ SMB Calls *******************************\n");
|
||||
d_printf("mkdir_count: %u\n", profile_p->SMBmkdir_count);
|
||||
d_printf("mkdir_time: %u\n", profile_p->SMBmkdir_time);
|
||||
d_printf("rmdir_count: %u\n", profile_p->SMBrmdir_count);
|
||||
d_printf("rmdir_time: %u\n", profile_p->SMBrmdir_time);
|
||||
d_printf("open_count: %u\n", profile_p->SMBopen_count);
|
||||
d_printf("open_time: %u\n", profile_p->SMBopen_time);
|
||||
d_printf("create_count: %u\n", profile_p->SMBcreate_count);
|
||||
d_printf("create_time: %u\n", profile_p->SMBcreate_time);
|
||||
d_printf("close_count: %u\n", profile_p->SMBclose_count);
|
||||
d_printf("close_time: %u\n", profile_p->SMBclose_time);
|
||||
d_printf("flush_count: %u\n", profile_p->SMBflush_count);
|
||||
d_printf("flush_time: %u\n", profile_p->SMBflush_time);
|
||||
d_printf("unlink_count: %u\n", profile_p->SMBunlink_count);
|
||||
d_printf("unlink_time: %u\n", profile_p->SMBunlink_time);
|
||||
d_printf("mv_count: %u\n", profile_p->SMBmv_count);
|
||||
d_printf("mv_time: %u\n", profile_p->SMBmv_time);
|
||||
d_printf("getatr_count: %u\n", profile_p->SMBgetatr_count);
|
||||
d_printf("getatr_time: %u\n", profile_p->SMBgetatr_time);
|
||||
d_printf("setatr_count: %u\n", profile_p->SMBsetatr_count);
|
||||
d_printf("setatr_time: %u\n", profile_p->SMBsetatr_time);
|
||||
d_printf("read_count: %u\n", profile_p->SMBread_count);
|
||||
d_printf("read_time: %u\n", profile_p->SMBread_time);
|
||||
d_printf("write_count: %u\n", profile_p->SMBwrite_count);
|
||||
d_printf("write_time: %u\n", profile_p->SMBwrite_time);
|
||||
d_printf("lock_count: %u\n", profile_p->SMBlock_count);
|
||||
d_printf("lock_time: %u\n", profile_p->SMBlock_time);
|
||||
d_printf("unlock_count: %u\n", profile_p->SMBunlock_count);
|
||||
d_printf("unlock_time: %u\n", profile_p->SMBunlock_time);
|
||||
d_printf("ctemp_count: %u\n", profile_p->SMBctemp_count);
|
||||
d_printf("ctemp_time: %u\n", profile_p->SMBctemp_time);
|
||||
d_printf("mknew_count: %u\n", profile_p->SMBmknew_count);
|
||||
d_printf("mknew_time: %u\n", profile_p->SMBmknew_time);
|
||||
d_printf("chkpth_count: %u\n", profile_p->SMBchkpth_count);
|
||||
d_printf("chkpth_time: %u\n", profile_p->SMBchkpth_time);
|
||||
d_printf("exit_count: %u\n", profile_p->SMBexit_count);
|
||||
d_printf("exit_time: %u\n", profile_p->SMBexit_time);
|
||||
d_printf("lseek_count: %u\n", profile_p->SMBlseek_count);
|
||||
d_printf("lseek_time: %u\n", profile_p->SMBlseek_time);
|
||||
d_printf("lockread_count: %u\n", profile_p->SMBlockread_count);
|
||||
d_printf("lockread_time: %u\n", profile_p->SMBlockread_time);
|
||||
d_printf("writeunlock_count: %u\n", profile_p->SMBwriteunlock_count);
|
||||
d_printf("writeunlock_time: %u\n", profile_p->SMBwriteunlock_time);
|
||||
d_printf("readbraw_count: %u\n", profile_p->SMBreadbraw_count);
|
||||
d_printf("readbraw_time: %u\n", profile_p->SMBreadbraw_time);
|
||||
d_printf("readBmpx_count: %u\n", profile_p->SMBreadBmpx_count);
|
||||
d_printf("readBmpx_time: %u\n", profile_p->SMBreadBmpx_time);
|
||||
d_printf("readBs_count: %u\n", profile_p->SMBreadBs_count);
|
||||
d_printf("readBs_time: %u\n", profile_p->SMBreadBs_time);
|
||||
d_printf("writebraw_count: %u\n", profile_p->SMBwritebraw_count);
|
||||
d_printf("writebraw_time: %u\n", profile_p->SMBwritebraw_time);
|
||||
d_printf("writeBmpx_count: %u\n", profile_p->SMBwriteBmpx_count);
|
||||
d_printf("writeBmpx_time: %u\n", profile_p->SMBwriteBmpx_time);
|
||||
d_printf("writeBs_count: %u\n", profile_p->SMBwriteBs_count);
|
||||
d_printf("writeBs_time: %u\n", profile_p->SMBwriteBs_time);
|
||||
d_printf("writec_count: %u\n", profile_p->SMBwritec_count);
|
||||
d_printf("writec_time: %u\n", profile_p->SMBwritec_time);
|
||||
d_printf("setattrE_count: %u\n", profile_p->SMBsetattrE_count);
|
||||
d_printf("setattrE_time: %u\n", profile_p->SMBsetattrE_time);
|
||||
d_printf("getattrE_count: %u\n", profile_p->SMBgetattrE_count);
|
||||
d_printf("getattrE_time: %u\n", profile_p->SMBgetattrE_time);
|
||||
d_printf("lockingX_count: %u\n", profile_p->SMBlockingX_count);
|
||||
d_printf("lockingX_time: %u\n", profile_p->SMBlockingX_time);
|
||||
d_printf("trans_count: %u\n", profile_p->SMBtrans_count);
|
||||
d_printf("trans_time: %u\n", profile_p->SMBtrans_time);
|
||||
d_printf("transs_count: %u\n", profile_p->SMBtranss_count);
|
||||
d_printf("transs_time: %u\n", profile_p->SMBtranss_time);
|
||||
d_printf("ioctl_count: %u\n", profile_p->SMBioctl_count);
|
||||
d_printf("ioctl_time: %u\n", profile_p->SMBioctl_time);
|
||||
d_printf("ioctls_count: %u\n", profile_p->SMBioctls_count);
|
||||
d_printf("ioctls_time: %u\n", profile_p->SMBioctls_time);
|
||||
d_printf("copy_count: %u\n", profile_p->SMBcopy_count);
|
||||
d_printf("copy_time: %u\n", profile_p->SMBcopy_time);
|
||||
d_printf("move_count: %u\n", profile_p->SMBmove_count);
|
||||
d_printf("move_time: %u\n", profile_p->SMBmove_time);
|
||||
d_printf("echo_count: %u\n", profile_p->SMBecho_count);
|
||||
d_printf("echo_time: %u\n", profile_p->SMBecho_time);
|
||||
d_printf("writeclose_count: %u\n", profile_p->SMBwriteclose_count);
|
||||
d_printf("writeclose_time: %u\n", profile_p->SMBwriteclose_time);
|
||||
d_printf("openX_count: %u\n", profile_p->SMBopenX_count);
|
||||
d_printf("openX_time: %u\n", profile_p->SMBopenX_time);
|
||||
d_printf("readX_count: %u\n", profile_p->SMBreadX_count);
|
||||
d_printf("readX_time: %u\n", profile_p->SMBreadX_time);
|
||||
d_printf("writeX_count: %u\n", profile_p->SMBwriteX_count);
|
||||
d_printf("writeX_time: %u\n", profile_p->SMBwriteX_time);
|
||||
d_printf("trans2_count: %u\n", profile_p->SMBtrans2_count);
|
||||
d_printf("trans2_time: %u\n", profile_p->SMBtrans2_time);
|
||||
d_printf("transs2_count: %u\n", profile_p->SMBtranss2_count);
|
||||
d_printf("transs2_time: %u\n", profile_p->SMBtranss2_time);
|
||||
d_printf("findclose_count: %u\n", profile_p->SMBfindclose_count);
|
||||
d_printf("findclose_time: %u\n", profile_p->SMBfindclose_time);
|
||||
d_printf("findnclose_count: %u\n", profile_p->SMBfindnclose_count);
|
||||
d_printf("findnclose_time: %u\n", profile_p->SMBfindnclose_time);
|
||||
d_printf("tcon_count: %u\n", profile_p->SMBtcon_count);
|
||||
d_printf("tcon_time: %u\n", profile_p->SMBtcon_time);
|
||||
d_printf("tdis_count: %u\n", profile_p->SMBtdis_count);
|
||||
d_printf("tdis_time: %u\n", profile_p->SMBtdis_time);
|
||||
d_printf("negprot_count: %u\n", profile_p->SMBnegprot_count);
|
||||
d_printf("negprot_time: %u\n", profile_p->SMBnegprot_time);
|
||||
d_printf("sesssetupX_count: %u\n", profile_p->SMBsesssetupX_count);
|
||||
d_printf("sesssetupX_time: %u\n", profile_p->SMBsesssetupX_time);
|
||||
d_printf("ulogoffX_count: %u\n", profile_p->SMBulogoffX_count);
|
||||
d_printf("ulogoffX_time: %u\n", profile_p->SMBulogoffX_time);
|
||||
d_printf("tconX_count: %u\n", profile_p->SMBtconX_count);
|
||||
d_printf("tconX_time: %u\n", profile_p->SMBtconX_time);
|
||||
d_printf("dskattr_count: %u\n", profile_p->SMBdskattr_count);
|
||||
d_printf("dskattr_time: %u\n", profile_p->SMBdskattr_time);
|
||||
d_printf("search_count: %u\n", profile_p->SMBsearch_count);
|
||||
d_printf("search_time: %u\n", profile_p->SMBsearch_time);
|
||||
d_printf("ffirst_count: %u\n", profile_p->SMBffirst_count);
|
||||
d_printf("ffirst_time: %u\n", profile_p->SMBffirst_time);
|
||||
d_printf("funique_count: %u\n", profile_p->SMBfunique_count);
|
||||
d_printf("funique_time: %u\n", profile_p->SMBfunique_time);
|
||||
d_printf("fclose_count: %u\n", profile_p->SMBfclose_count);
|
||||
d_printf("fclose_time: %u\n", profile_p->SMBfclose_time);
|
||||
d_printf("nttrans_count: %u\n", profile_p->SMBnttrans_count);
|
||||
d_printf("nttrans_time: %u\n", profile_p->SMBnttrans_time);
|
||||
d_printf("nttranss_count: %u\n", profile_p->SMBnttranss_count);
|
||||
d_printf("nttranss_time: %u\n", profile_p->SMBnttranss_time);
|
||||
d_printf("ntcreateX_count: %u\n", profile_p->SMBntcreateX_count);
|
||||
d_printf("ntcreateX_time: %u\n", profile_p->SMBntcreateX_time);
|
||||
d_printf("ntcancel_count: %u\n", profile_p->SMBntcancel_count);
|
||||
d_printf("ntcancel_time: %u\n", profile_p->SMBntcancel_time);
|
||||
d_printf("splopen_count: %u\n", profile_p->SMBsplopen_count);
|
||||
d_printf("splopen_time: %u\n", profile_p->SMBsplopen_time);
|
||||
d_printf("splwr_count: %u\n", profile_p->SMBsplwr_count);
|
||||
d_printf("splwr_time: %u\n", profile_p->SMBsplwr_time);
|
||||
d_printf("splclose_count: %u\n", profile_p->SMBsplclose_count);
|
||||
d_printf("splclose_time: %u\n", profile_p->SMBsplclose_time);
|
||||
d_printf("splretq_count: %u\n", profile_p->SMBsplretq_count);
|
||||
d_printf("splretq_time: %u\n", profile_p->SMBsplretq_time);
|
||||
d_printf("sends_count: %u\n", profile_p->SMBsends_count);
|
||||
d_printf("sends_time: %u\n", profile_p->SMBsends_time);
|
||||
d_printf("sendb_count: %u\n", profile_p->SMBsendb_count);
|
||||
d_printf("sendb_time: %u\n", profile_p->SMBsendb_time);
|
||||
d_printf("fwdname_count: %u\n", profile_p->SMBfwdname_count);
|
||||
d_printf("fwdname_time: %u\n", profile_p->SMBfwdname_time);
|
||||
d_printf("cancelf_count: %u\n", profile_p->SMBcancelf_count);
|
||||
d_printf("cancelf_time: %u\n", profile_p->SMBcancelf_time);
|
||||
d_printf("getmac_count: %u\n", profile_p->SMBgetmac_count);
|
||||
d_printf("getmac_time: %u\n", profile_p->SMBgetmac_time);
|
||||
d_printf("sendstrt_count: %u\n", profile_p->SMBsendstrt_count);
|
||||
d_printf("sendstrt_time: %u\n", profile_p->SMBsendstrt_time);
|
||||
d_printf("sendend_count: %u\n", profile_p->SMBsendend_count);
|
||||
d_printf("sendend_time: %u\n", profile_p->SMBsendend_time);
|
||||
d_printf("sendtxt_count: %u\n", profile_p->SMBsendtxt_count);
|
||||
d_printf("sendtxt_time: %u\n", profile_p->SMBsendtxt_time);
|
||||
d_printf("invalid_count: %u\n", profile_p->SMBinvalid_count);
|
||||
d_printf("invalid_time: %u\n", profile_p->SMBinvalid_time);
|
||||
d_printf("************************ Pathworks Calls *************************\n");
|
||||
d_printf("setdir_count: %u\n", profile_p->pathworks_setdir_count);
|
||||
d_printf("setdir_time: %u\n", profile_p->pathworks_setdir_time);
|
||||
d_printf("************************ Trans2 Calls ****************************\n");
|
||||
d_printf("open_count: %u\n", profile_p->Trans2_open_count);
|
||||
d_printf("open_time: %u\n", profile_p->Trans2_open_time);
|
||||
d_printf("findfirst_count: %u\n", profile_p->Trans2_findfirst_count);
|
||||
d_printf("findfirst_time: %u\n", profile_p->Trans2_findfirst_time);
|
||||
d_printf("findnext_count: %u\n", profile_p->Trans2_findnext_count);
|
||||
d_printf("findnext_time: %u\n", profile_p->Trans2_findnext_time);
|
||||
d_printf("qfsinfo_count: %u\n", profile_p->Trans2_qfsinfo_count);
|
||||
d_printf("qfsinfo_time: %u\n", profile_p->Trans2_qfsinfo_time);
|
||||
d_printf("setfsinfo_count: %u\n", profile_p->Trans2_setfsinfo_count);
|
||||
d_printf("setfsinfo_time: %u\n", profile_p->Trans2_setfsinfo_time);
|
||||
d_printf("qpathinfo_count: %u\n", profile_p->Trans2_qpathinfo_count);
|
||||
d_printf("qpathinfo_time: %u\n", profile_p->Trans2_qpathinfo_time);
|
||||
d_printf("setpathinfo_count: %u\n", profile_p->Trans2_setpathinfo_count);
|
||||
d_printf("setpathinfo_time: %u\n", profile_p->Trans2_setpathinfo_time);
|
||||
d_printf("qfileinfo_count: %u\n", profile_p->Trans2_qfileinfo_count);
|
||||
d_printf("qfileinfo_time: %u\n", profile_p->Trans2_qfileinfo_time);
|
||||
d_printf("setfileinfo_count: %u\n", profile_p->Trans2_setfileinfo_count);
|
||||
d_printf("setfileinfo_time: %u\n", profile_p->Trans2_setfileinfo_time);
|
||||
d_printf("fsctl_count: %u\n", profile_p->Trans2_fsctl_count);
|
||||
d_printf("fsctl_time: %u\n", profile_p->Trans2_fsctl_time);
|
||||
d_printf("ioctl_count: %u\n", profile_p->Trans2_ioctl_count);
|
||||
d_printf("ioctl_time: %u\n", profile_p->Trans2_ioctl_time);
|
||||
d_printf("findnotifyfirst_count: %u\n", profile_p->Trans2_findnotifyfirst_count);
|
||||
d_printf("findnotifyfirst_time: %u\n", profile_p->Trans2_findnotifyfirst_time);
|
||||
d_printf("findnotifynext_count: %u\n", profile_p->Trans2_findnotifynext_count);
|
||||
d_printf("findnotifynext_time: %u\n", profile_p->Trans2_findnotifynext_time);
|
||||
d_printf("mkdir_count: %u\n", profile_p->Trans2_mkdir_count);
|
||||
d_printf("mkdir_time: %u\n", profile_p->Trans2_mkdir_time);
|
||||
d_printf("session_setup_count: %u\n", profile_p->Trans2_session_setup_count);
|
||||
d_printf("session_setup_time: %u\n", profile_p->Trans2_session_setup_time);
|
||||
d_printf("get_dfs_referral_count: %u\n", profile_p->Trans2_get_dfs_referral_count);
|
||||
d_printf("get_dfs_referral_time: %u\n", profile_p->Trans2_get_dfs_referral_time);
|
||||
d_printf("report_dfs_inconsistancy_count: %u\n", profile_p->Trans2_report_dfs_inconsistancy_count);
|
||||
d_printf("report_dfs_inconsistancy_time: %u\n", profile_p->Trans2_report_dfs_inconsistancy_time);
|
||||
d_printf("************************ NT Transact Calls ***********************\n");
|
||||
d_printf("create_count: %u\n", profile_p->NT_transact_create_count);
|
||||
d_printf("create_time: %u\n", profile_p->NT_transact_create_time);
|
||||
d_printf("ioctl_count: %u\n", profile_p->NT_transact_ioctl_count);
|
||||
d_printf("ioctl_time: %u\n", profile_p->NT_transact_ioctl_time);
|
||||
d_printf("set_security_desc_count: %u\n", profile_p->NT_transact_set_security_desc_count);
|
||||
d_printf("set_security_desc_time: %u\n", profile_p->NT_transact_set_security_desc_time);
|
||||
d_printf("notify_change_count: %u\n", profile_p->NT_transact_notify_change_count);
|
||||
d_printf("notify_change_time: %u\n", profile_p->NT_transact_notify_change_time);
|
||||
d_printf("rename_count: %u\n", profile_p->NT_transact_rename_count);
|
||||
d_printf("rename_time: %u\n", profile_p->NT_transact_rename_time);
|
||||
d_printf("query_security_desc_count: %u\n", profile_p->NT_transact_query_security_desc_count);
|
||||
d_printf("query_security_desc_time: %u\n", profile_p->NT_transact_query_security_desc_time);
|
||||
d_printf("************************ ACL Calls *******************************\n");
|
||||
d_printf("get_nt_acl_count: %u\n", profile_p->get_nt_acl_count);
|
||||
d_printf("get_nt_acl_time: %u\n", profile_p->get_nt_acl_time);
|
||||
d_printf("fget_nt_acl_count: %u\n", profile_p->fget_nt_acl_count);
|
||||
d_printf("fget_nt_acl_time: %u\n", profile_p->fget_nt_acl_time);
|
||||
d_printf("set_nt_acl_count: %u\n", profile_p->set_nt_acl_count);
|
||||
d_printf("set_nt_acl_time: %u\n", profile_p->set_nt_acl_time);
|
||||
d_printf("fset_nt_acl_count: %u\n", profile_p->fset_nt_acl_count);
|
||||
d_printf("fset_nt_acl_time: %u\n", profile_p->fset_nt_acl_time);
|
||||
d_printf("chmod_acl_count: %u\n", profile_p->chmod_acl_count);
|
||||
d_printf("chmod_acl_time: %u\n", profile_p->chmod_acl_time);
|
||||
d_printf("fchmod_acl_count: %u\n", profile_p->fchmod_acl_count);
|
||||
d_printf("fchmod_acl_time: %u\n", profile_p->fchmod_acl_time);
|
||||
d_printf("************************ NMBD Calls ****************************\n");
|
||||
d_printf("name_release_count: %u\n", profile_p->name_release_count);
|
||||
d_printf("name_release_time: %u\n", profile_p->name_release_time);
|
||||
d_printf("name_refresh_count: %u\n", profile_p->name_refresh_count);
|
||||
d_printf("name_refresh_time: %u\n", profile_p->name_refresh_time);
|
||||
d_printf("name_registration_count: %u\n", profile_p->name_registration_count);
|
||||
d_printf("name_registration_time: %u\n", profile_p->name_registration_time);
|
||||
d_printf("node_status_count: %u\n", profile_p->node_status_count);
|
||||
d_printf("node_status_time: %u\n", profile_p->node_status_time);
|
||||
d_printf("name_query_count: %u\n", profile_p->name_query_count);
|
||||
d_printf("name_query_time: %u\n", profile_p->name_query_time);
|
||||
d_printf("host_announce_count: %u\n", profile_p->host_announce_count);
|
||||
d_printf("host_announce_time: %u\n", profile_p->host_announce_time);
|
||||
d_printf("workgroup_announce_count: %u\n", profile_p->workgroup_announce_count);
|
||||
d_printf("workgroup_announce_time: %u\n", profile_p->workgroup_announce_time);
|
||||
d_printf("local_master_announce_count: %u\n", profile_p->local_master_announce_count);
|
||||
d_printf("local_master_announce_time: %u\n", profile_p->local_master_announce_time);
|
||||
d_printf("master_browser_announce_count: %u\n", profile_p->master_browser_announce_count);
|
||||
d_printf("master_browser_announce_time: %u\n", profile_p->master_browser_announce_time);
|
||||
d_printf("lm_host_announce_count: %u\n", profile_p->lm_host_announce_count);
|
||||
d_printf("lm_host_announce_time: %u\n", profile_p->lm_host_announce_time);
|
||||
d_printf("get_backup_list_count: %u\n", profile_p->get_backup_list_count);
|
||||
d_printf("get_backup_list_time: %u\n", profile_p->get_backup_list_time);
|
||||
d_printf("reset_browser_count: %u\n", profile_p->reset_browser_count);
|
||||
d_printf("reset_browser_time: %u\n", profile_p->reset_browser_time);
|
||||
d_printf("announce_request_count: %u\n", profile_p->announce_request_count);
|
||||
d_printf("announce_request_time: %u\n", profile_p->announce_request_time);
|
||||
d_printf("lm_announce_request_count: %u\n", profile_p->lm_announce_request_count);
|
||||
d_printf("lm_announce_request_time: %u\n", profile_p->lm_announce_request_time);
|
||||
d_printf("domain_logon_count: %u\n", profile_p->domain_logon_count);
|
||||
d_printf("domain_logon_time: %u\n", profile_p->domain_logon_time);
|
||||
d_printf("sync_browse_lists_count: %u\n", profile_p->sync_browse_lists_count);
|
||||
d_printf("sync_browse_lists_time: %u\n", profile_p->sync_browse_lists_time);
|
||||
d_printf("run_elections_count: %u\n", profile_p->run_elections_count);
|
||||
d_printf("run_elections_time: %u\n", profile_p->run_elections_time);
|
||||
d_printf("election_count: %u\n", profile_p->election_count);
|
||||
d_printf("election_time: %u\n", profile_p->election_time);
|
||||
#else /* WITH_PROFILE */
|
||||
fprintf(stderr, "Profile data unavailable\n");
|
||||
#endif /* WITH_PROFILE */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int traverse_fn1(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
|
||||
{
|
||||
struct connections_data crec;
|
||||
|
||||
if (dbuf.dsize != sizeof(crec))
|
||||
return 0;
|
||||
|
||||
memcpy(&crec, dbuf.dptr, sizeof(crec));
|
||||
|
||||
if (crec.cnum == -1)
|
||||
return 0;
|
||||
|
||||
if (!process_exists(crec.pid) || !Ucrit_checkUsername(uidtoname(crec.uid))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
d_printf("%-10.10s %5d %-12s %s",
|
||||
crec.name,(int)crec.pid,
|
||||
crec.machine,
|
||||
asctime(LocalTime(&crec.start)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int traverse_sessionid(TDB_CONTEXT *tdb, TDB_DATA kbuf, TDB_DATA dbuf, void *state)
|
||||
{
|
||||
struct sessionid sessionid;
|
||||
TALLOC_CTX *mem_ctx;
|
||||
|
||||
if (dbuf.dsize != sizeof(sessionid))
|
||||
return 0;
|
||||
|
||||
memcpy(&sessionid, dbuf.dptr, sizeof(sessionid));
|
||||
|
||||
if (!process_exists(sessionid.pid) || !Ucrit_checkUsername(uidtoname(sessionid.uid))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
mem_ctx = talloc_init("smbgroupedit talloc");
|
||||
if (!mem_ctx) return -1;
|
||||
d_printf("%5d %-12s %-12s %-12s (%s)\n",
|
||||
(int)sessionid.pid, uidtoname(sessionid.uid),
|
||||
gidtoname(mem_ctx, sessionid.gid),
|
||||
sessionid.remote_machine, sessionid.hostname);
|
||||
talloc_destroy(mem_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int c;
|
||||
static int profile_only = 0;
|
||||
TDB_CONTEXT *tdb;
|
||||
poptContext pc;
|
||||
struct poptOption long_options[] = {
|
||||
POPT_AUTOHELP
|
||||
{"processes", 'p', POPT_ARG_NONE, &processes_only, 'p', "Show processes only" },
|
||||
{"verbose", 'v', POPT_ARG_NONE, &verbose, 'v', "Be verbose" },
|
||||
{"locks", 'L', POPT_ARG_NONE, &locks_only, 'L', "Show locks only" },
|
||||
{"shares", 'S', POPT_ARG_NONE, &shares_only, 'S', "Show shares only" },
|
||||
{"user", 'u', POPT_ARG_STRING, 0, 'u', "Switch to user" },
|
||||
{"brief", 'b', POPT_ARG_NONE, &brief, 'b', "Be brief" },
|
||||
#ifdef WITH_PROFILE
|
||||
{"profile", 'P', POPT_ARG_NONE, &profile_only, 'P', "Do profiling" },
|
||||
#endif /* WITH_PROFILE */
|
||||
{"byterange", 'B', POPT_ARG_NONE, &show_brl, 'B', "Include byte range locks"},
|
||||
POPT_COMMON_SAMBA
|
||||
POPT_COMMON_CONNECTION
|
||||
POPT_COMMON_CREDENTIALS
|
||||
POPT_TABLEEND
|
||||
};
|
||||
|
||||
setup_logging(argv[0],True);
|
||||
|
||||
dbf = x_stderr;
|
||||
|
||||
if (getuid() != geteuid()) {
|
||||
d_printf("smbstatus should not be run setuid\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
pc = poptGetContext(NULL, argc, (const char **) argv, long_options,
|
||||
POPT_CONTEXT_KEEP_FIRST);
|
||||
|
||||
while ((c = poptGetNextOpt(pc)) != EOF) {
|
||||
switch (c) {
|
||||
case 'u':
|
||||
Ucrit_addUsername(poptGetOptArg(pc));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
d_printf("using configfile = %s\n", dyn_CONFIGFILE);
|
||||
}
|
||||
|
||||
if (!lp_load(dyn_CONFIGFILE,False,False,False)) {
|
||||
fprintf(stderr, "Can't load %s - run testparm to debug it\n", dyn_CONFIGFILE);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (profile_only) {
|
||||
return profile_dump();
|
||||
}
|
||||
|
||||
tdb = tdb_open_log(lock_path("sessionid.tdb"), 0, TDB_DEFAULT, O_RDONLY, 0);
|
||||
if (!tdb) {
|
||||
d_printf("sessionid.tdb not initialised\n");
|
||||
} else {
|
||||
if (locks_only) goto locks;
|
||||
|
||||
d_printf("\nSamba version %s\n",SAMBA_VERSION);
|
||||
d_printf("PID Username Group Machine \n");
|
||||
d_printf("-------------------------------------------------------------------\n");
|
||||
|
||||
tdb_traverse(tdb, traverse_sessionid, NULL);
|
||||
tdb_close(tdb);
|
||||
}
|
||||
|
||||
tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDONLY, 0);
|
||||
if (!tdb) {
|
||||
d_printf("%s not initialised\n", lock_path("connections.tdb"));
|
||||
d_printf("This is normal if an SMB client has never connected to your server.\n");
|
||||
} else {
|
||||
if (verbose) {
|
||||
d_printf("Opened %s\n", lock_path("connections.tdb"));
|
||||
}
|
||||
|
||||
if (brief)
|
||||
exit(0);
|
||||
|
||||
d_printf("\nService pid machine Connected at\n");
|
||||
d_printf("-------------------------------------------------------\n");
|
||||
|
||||
tdb_traverse(tdb, traverse_fn1, NULL);
|
||||
tdb_close(tdb);
|
||||
}
|
||||
|
||||
locks:
|
||||
if (processes_only) exit(0);
|
||||
|
||||
if (!shares_only) {
|
||||
int ret;
|
||||
|
||||
if (!locking_init(1)) {
|
||||
d_printf("Can't initialise locking module - exiting\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ret = share_mode_forall(print_share_mode);
|
||||
|
||||
if (ret == 0) {
|
||||
d_printf("No locked files\n");
|
||||
} else if (ret == -1) {
|
||||
d_printf("locked file list truncated\n");
|
||||
}
|
||||
|
||||
d_printf("\n");
|
||||
|
||||
if (show_brl) {
|
||||
brl_forall(print_brl);
|
||||
}
|
||||
|
||||
locking_end();
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
29
source/utils/tdb/Makefile
Normal file
29
source/utils/tdb/Makefile
Normal file
@@ -0,0 +1,29 @@
|
||||
#
|
||||
# Makefile for tdb directory
|
||||
#
|
||||
|
||||
CFLAGS = -DSTANDALONE -DTDB_DEBUG -g -DHAVE_MMAP=1
|
||||
CC = gcc
|
||||
|
||||
PROGS = tdbtest tdbtool tdbtorture
|
||||
TDB_OBJ = tdb.o spinlock.o
|
||||
|
||||
default: $(PROGS)
|
||||
|
||||
tdbtest: tdbtest.o $(TDB_OBJ)
|
||||
$(CC) $(CFLAGS) -o tdbtest tdbtest.o $(TDB_OBJ) -lgdbm
|
||||
|
||||
tdbtool: tdbtool.o $(TDB_OBJ)
|
||||
$(CC) $(CFLAGS) -o tdbtool tdbtool.o $(TDB_OBJ)
|
||||
|
||||
tdbtorture: tdbtorture.o $(TDB_OBJ)
|
||||
$(CC) $(CFLAGS) -o tdbtorture tdbtorture.o $(TDB_OBJ)
|
||||
|
||||
tdbdump: tdbdump.o $(TDB_OBJ)
|
||||
$(CC) $(CFLAGS) -o tdbdump tdbdump.o $(TDB_OBJ)
|
||||
|
||||
tdbbackup: tdbbackup.o $(TDB_OBJ)
|
||||
$(CC) $(CFLAGS) -o tdbbackup tdbbackup.o $(TDB_OBJ)
|
||||
|
||||
clean:
|
||||
rm -f $(PROGS) *.o *~ *% core test.db test.tdb test.gdbm
|
||||
167
source/utils/tdb/README
Normal file
167
source/utils/tdb/README
Normal file
@@ -0,0 +1,167 @@
|
||||
tdb - a trivial database system
|
||||
tridge@linuxcare.com December 1999
|
||||
==================================
|
||||
|
||||
This is a simple database API. It was inspired by the realisation that
|
||||
in Samba we have several ad-hoc bits of code that essentially
|
||||
implement small databases for sharing structures between parts of
|
||||
Samba. As I was about to add another I realised that a generic
|
||||
database module was called for to replace all the ad-hoc bits.
|
||||
|
||||
I based the interface on gdbm. I couldn't use gdbm as we need to be
|
||||
able to have multiple writers to the databases at one time.
|
||||
|
||||
Compilation
|
||||
-----------
|
||||
|
||||
add HAVE_MMAP=1 to use mmap instead of read/write
|
||||
add TDB_DEBUG=1 for verbose debug info
|
||||
add NOLOCK=1 to disable locking code
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
Compile tdbtest.c and link with gdbm for testing. tdbtest will perform
|
||||
identical operations via tdb and gdbm then make sure the result is the
|
||||
same
|
||||
|
||||
Also included is tdbtool, which allows simple database manipulation
|
||||
on the commandline.
|
||||
|
||||
tdbtest and tdbtool are not built as part of Samba, but are included
|
||||
for completeness.
|
||||
|
||||
Interface
|
||||
---------
|
||||
|
||||
The interface is very similar to gdbm except for the following:
|
||||
|
||||
- different open interface. The tdb_open call is more similar to a
|
||||
traditional open()
|
||||
- no tdbm_reorganise() function
|
||||
- no tdbm_sync() function. No operations are cached in the library anyway
|
||||
- added a tdb_traverse() function for traversing the whole database
|
||||
|
||||
A general rule for using tdb is that the caller frees any returned
|
||||
TDB_DATA structures. Just call free(p.dptr) to free a TDB_DATA
|
||||
return value called p. This is the same as gdbm.
|
||||
|
||||
here is a full list of tdb functions with brief descriptions.
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
TDB_CONTEXT *tdb_open(char *name, int hash_size, int tdb_flags,
|
||||
int open_flags, mode_t mode)
|
||||
|
||||
open the database, creating it if necessary
|
||||
|
||||
The open_flags and mode are passed straight to the open call on the database
|
||||
file. A flags value of O_WRONLY is invalid
|
||||
|
||||
The hash size is advisory, use zero for a default value.
|
||||
|
||||
return is NULL on error
|
||||
|
||||
possible tdb_flags are:
|
||||
TDB_CLEAR_IF_FIRST - clear database if we are the only one with it open
|
||||
TDB_INTERNAL - don't use a file, instaed store the data in
|
||||
memory. The filename is ignored in this case.
|
||||
TDB_NOLOCK - don't do any locking
|
||||
TDB_NOMMAP - don't use mmap
|
||||
|
||||
----------------------------------------------------------------------
|
||||
char *tdb_error(TDB_CONTEXT *tdb);
|
||||
|
||||
return a error string for the last tdb error
|
||||
|
||||
----------------------------------------------------------------------
|
||||
int tdb_close(TDB_CONTEXT *tdb);
|
||||
|
||||
close a database
|
||||
|
||||
----------------------------------------------------------------------
|
||||
int tdb_update(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf);
|
||||
|
||||
update an entry in place - this only works if the new data size
|
||||
is <= the old data size and the key exists.
|
||||
on failure return -1
|
||||
|
||||
----------------------------------------------------------------------
|
||||
TDB_DATA tdb_fetch(TDB_CONTEXT *tdb, TDB_DATA key);
|
||||
|
||||
fetch an entry in the database given a key
|
||||
if the return value has a null dptr then a error occurred
|
||||
|
||||
caller must free the resulting data
|
||||
|
||||
----------------------------------------------------------------------
|
||||
int tdb_exists(TDB_CONTEXT *tdb, TDB_DATA key);
|
||||
|
||||
check if an entry in the database exists
|
||||
|
||||
note that 1 is returned if the key is found and 0 is returned if not found
|
||||
this doesn't match the conventions in the rest of this module, but is
|
||||
compatible with gdbm
|
||||
|
||||
----------------------------------------------------------------------
|
||||
int tdb_traverse(TDB_CONTEXT *tdb, int (*fn)(TDB_CONTEXT *tdb,
|
||||
TDB_DATA key, TDB_DATA dbuf, void *state), void *state);
|
||||
|
||||
traverse the entire database - calling fn(tdb, key, data, state) on each
|
||||
element.
|
||||
|
||||
return -1 on error or the record count traversed
|
||||
|
||||
if fn is NULL then it is not called
|
||||
|
||||
a non-zero return value from fn() indicates that the traversal should stop
|
||||
|
||||
----------------------------------------------------------------------
|
||||
TDB_DATA tdb_firstkey(TDB_CONTEXT *tdb);
|
||||
|
||||
find the first entry in the database and return its key
|
||||
|
||||
the caller must free the returned data
|
||||
|
||||
----------------------------------------------------------------------
|
||||
TDB_DATA tdb_nextkey(TDB_CONTEXT *tdb, TDB_DATA key);
|
||||
|
||||
find the next entry in the database, returning its key
|
||||
|
||||
the caller must free the returned data
|
||||
|
||||
----------------------------------------------------------------------
|
||||
int tdb_delete(TDB_CONTEXT *tdb, TDB_DATA key);
|
||||
|
||||
delete an entry in the database given a key
|
||||
|
||||
----------------------------------------------------------------------
|
||||
int tdb_store(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, int flag);
|
||||
|
||||
store an element in the database, replacing any existing element
|
||||
with the same key
|
||||
|
||||
If flag==TDB_INSERT then don't overwrite an existing entry
|
||||
If flag==TDB_MODIFY then don't create a new entry
|
||||
|
||||
return 0 on success, -1 on failure
|
||||
|
||||
----------------------------------------------------------------------
|
||||
int tdb_writelock(TDB_CONTEXT *tdb);
|
||||
|
||||
lock the database. If we already have it locked then don't do anything
|
||||
|
||||
----------------------------------------------------------------------
|
||||
int tdb_writeunlock(TDB_CONTEXT *tdb);
|
||||
unlock the database
|
||||
|
||||
----------------------------------------------------------------------
|
||||
int tdb_lockchain(TDB_CONTEXT *tdb, TDB_DATA key);
|
||||
|
||||
lock one hash chain. This is meant to be used to reduce locking
|
||||
contention - it cannot guarantee how many records will be locked
|
||||
|
||||
----------------------------------------------------------------------
|
||||
int tdb_unlockchain(TDB_CONTEXT *tdb, TDB_DATA key);
|
||||
|
||||
unlock one hash chain
|
||||
10
source/utils/tdb/tdb.magic
Normal file
10
source/utils/tdb/tdb.magic
Normal file
@@ -0,0 +1,10 @@
|
||||
# Magic file(1) information about tdb files.
|
||||
#
|
||||
# Install this into /etc/magic or the corresponding location for your
|
||||
# system, or pass as a -m argument to file(1).
|
||||
|
||||
# You may use and redistribute this file without restriction.
|
||||
|
||||
0 string TDB\ file TDB database
|
||||
>32 lelong =0x2601196D version 6, little-endian
|
||||
>>36 lelong x hash size %d bytes
|
||||
315
source/utils/tdb/tdbbackup.c
Normal file
315
source/utils/tdb/tdbbackup.c
Normal file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
low level tdb backup and restore utility
|
||||
Copyright (C) Andrew Tridgell 2002
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
This program is meant for backup/restore of tdb databases. Typical usage would be:
|
||||
tdbbackup *.tdb
|
||||
when Samba shuts down cleanly, which will make a backup of all the local databases
|
||||
to *.bak files. Then on Samba startup you would use:
|
||||
tdbbackup -v *.tdb
|
||||
and this will check the databases for corruption and if corruption is detected then
|
||||
the backup will be restored.
|
||||
|
||||
You may also like to do a backup on a regular basis while Samba is
|
||||
running, perhaps using cron.
|
||||
|
||||
The reason this program is needed is to cope with power failures
|
||||
while Samba is running. A power failure could lead to database
|
||||
corruption and Samba will then not start correctly.
|
||||
|
||||
Note that many of the databases in Samba are transient and thus
|
||||
don't need to be backed up, so you can optimise the above a little
|
||||
by only running the backup on the critical databases.
|
||||
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
#include "tdb.h"
|
||||
|
||||
static int failed;
|
||||
|
||||
static char *add_suffix(const char *name, const char *suffix)
|
||||
{
|
||||
char *ret;
|
||||
int len = strlen(name) + strlen(suffix) + 1;
|
||||
ret = malloc(len);
|
||||
if (!ret) {
|
||||
fprintf(stderr,"Out of memory!\n");
|
||||
exit(1);
|
||||
}
|
||||
strncpy(ret, name, len);
|
||||
strncat(ret, suffix, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int copy_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
|
||||
{
|
||||
TDB_CONTEXT *tdb_new = (TDB_CONTEXT *)state;
|
||||
|
||||
if (tdb_store(tdb_new, key, dbuf, TDB_INSERT) != 0) {
|
||||
fprintf(stderr,"Failed to insert into %s\n", tdb_new->name);
|
||||
failed = 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int test_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
carefully backup a tdb, validating the contents and
|
||||
only doing the backup if its OK
|
||||
this function is also used for restore
|
||||
*/
|
||||
static int backup_tdb(const char *old_name, const char *new_name)
|
||||
{
|
||||
TDB_CONTEXT *tdb;
|
||||
TDB_CONTEXT *tdb_new;
|
||||
char *tmp_name;
|
||||
struct stat st;
|
||||
int count1, count2;
|
||||
|
||||
tmp_name = add_suffix(new_name, ".tmp");
|
||||
|
||||
/* stat the old tdb to find its permissions */
|
||||
if (stat(old_name, &st) != 0) {
|
||||
perror(old_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* open the old tdb */
|
||||
tdb = tdb_open(old_name, 0, 0, O_RDWR, 0);
|
||||
if (!tdb) {
|
||||
printf("Failed to open %s\n", old_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* create the new tdb */
|
||||
unlink(tmp_name);
|
||||
tdb_new = tdb_open(tmp_name, tdb->header.hash_size,
|
||||
TDB_DEFAULT, O_RDWR|O_CREAT|O_EXCL,
|
||||
st.st_mode & 0777);
|
||||
if (!tdb_new) {
|
||||
perror(tmp_name);
|
||||
free(tmp_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* lock the old tdb */
|
||||
if (tdb_lockall(tdb) != 0) {
|
||||
fprintf(stderr,"Failed to lock %s\n", old_name);
|
||||
tdb_close(tdb);
|
||||
tdb_close(tdb_new);
|
||||
unlink(tmp_name);
|
||||
free(tmp_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
failed = 0;
|
||||
|
||||
/* traverse and copy */
|
||||
count1 = tdb_traverse(tdb, copy_fn, (void *)tdb_new);
|
||||
if (count1 < 0 || failed) {
|
||||
fprintf(stderr,"failed to copy %s\n", old_name);
|
||||
tdb_close(tdb);
|
||||
tdb_close(tdb_new);
|
||||
unlink(tmp_name);
|
||||
free(tmp_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* close the old tdb */
|
||||
tdb_close(tdb);
|
||||
|
||||
/* close the new tdb and re-open read-only */
|
||||
tdb_close(tdb_new);
|
||||
tdb_new = tdb_open(tmp_name, 0, TDB_DEFAULT, O_RDONLY, 0);
|
||||
if (!tdb_new) {
|
||||
fprintf(stderr,"failed to reopen %s\n", tmp_name);
|
||||
unlink(tmp_name);
|
||||
perror(tmp_name);
|
||||
free(tmp_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* traverse the new tdb to confirm */
|
||||
count2 = tdb_traverse(tdb_new, test_fn, 0);
|
||||
if (count2 != count1) {
|
||||
fprintf(stderr,"failed to copy %s\n", old_name);
|
||||
tdb_close(tdb_new);
|
||||
unlink(tmp_name);
|
||||
free(tmp_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* make sure the new tdb has reached stable storage */
|
||||
fsync(tdb_new->fd);
|
||||
|
||||
/* close the new tdb and rename it to .bak */
|
||||
tdb_close(tdb_new);
|
||||
unlink(new_name);
|
||||
if (rename(tmp_name, new_name) != 0) {
|
||||
perror(new_name);
|
||||
free(tmp_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("%s : %d records\n", old_name, count1);
|
||||
free(tmp_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
verify a tdb and if it is corrupt then restore from *.bak
|
||||
*/
|
||||
static int verify_tdb(const char *fname, const char *bak_name)
|
||||
{
|
||||
TDB_CONTEXT *tdb;
|
||||
int count = -1;
|
||||
|
||||
/* open the tdb */
|
||||
tdb = tdb_open(fname, 0, 0, O_RDONLY, 0);
|
||||
|
||||
/* traverse the tdb, then close it */
|
||||
if (tdb) {
|
||||
count = tdb_traverse(tdb, test_fn, NULL);
|
||||
tdb_close(tdb);
|
||||
}
|
||||
|
||||
/* count is < 0 means an error */
|
||||
if (count < 0) {
|
||||
printf("restoring %s\n", fname);
|
||||
return backup_tdb(bak_name, fname);
|
||||
}
|
||||
|
||||
printf("%s : %d records\n", fname, count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
see if one file is newer than another
|
||||
*/
|
||||
static int file_newer(const char *fname1, const char *fname2)
|
||||
{
|
||||
struct stat st1, st2;
|
||||
if (stat(fname1, &st1) != 0) {
|
||||
return 0;
|
||||
}
|
||||
if (stat(fname2, &st2) != 0) {
|
||||
return 1;
|
||||
}
|
||||
return (st1.st_mtime > st2.st_mtime);
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
printf("Usage: tdbbackup [options] <fname...>\n\n");
|
||||
printf(" -h this help message\n");
|
||||
printf(" -s suffix set the backup suffix\n");
|
||||
printf(" -v veryify mode (restore if corrupt)\n");
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
int ret = 0;
|
||||
int c;
|
||||
int verify = 0;
|
||||
char *suffix = ".bak";
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
|
||||
while ((c = getopt(argc, argv, "vhs:")) != -1) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
usage();
|
||||
exit(0);
|
||||
case 'v':
|
||||
verify = 1;
|
||||
break;
|
||||
case 's':
|
||||
suffix = optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc < 1) {
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i=0; i<argc; i++) {
|
||||
const char *fname = argv[i];
|
||||
char *bak_name;
|
||||
|
||||
bak_name = add_suffix(fname, suffix);
|
||||
|
||||
if (verify) {
|
||||
if (verify_tdb(fname, bak_name) != 0) {
|
||||
ret = 1;
|
||||
}
|
||||
} else {
|
||||
if (file_newer(fname, bak_name) &&
|
||||
backup_tdb(fname, bak_name) != 0) {
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
free(bak_name);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef VALGRIND
|
||||
size_t valgrind_strlen(const char *s)
|
||||
{
|
||||
size_t count;
|
||||
for(count = 0; *s++; count++)
|
||||
;
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
89
source/utils/tdb/tdbdump.c
Normal file
89
source/utils/tdb/tdbdump.c
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
simple tdb dump util
|
||||
Copyright (C) Andrew Tridgell 2001
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
#include "tdb.h"
|
||||
|
||||
static void print_data(TDB_DATA d)
|
||||
{
|
||||
unsigned char *p = d.dptr;
|
||||
int len = d.dsize;
|
||||
while (len--) {
|
||||
if (isprint(*p) && !strchr("\"\\", *p)) {
|
||||
fputc(*p, stdout);
|
||||
} else {
|
||||
printf("\\%02X", *p);
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
|
||||
{
|
||||
printf("{\n");
|
||||
printf("key = \"");
|
||||
print_data(key);
|
||||
printf("\"\n");
|
||||
printf("data = \"");
|
||||
print_data(dbuf);
|
||||
printf("\"\n");
|
||||
printf("}\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dump_tdb(const char *fname)
|
||||
{
|
||||
TDB_CONTEXT *tdb;
|
||||
|
||||
tdb = tdb_open(fname, 0, 0, O_RDONLY, 0);
|
||||
if (!tdb) {
|
||||
printf("Failed to open %s\n", fname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
tdb_traverse(tdb, traverse_fn, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *fname;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Usage: tdbdump <fname>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fname = argv[1];
|
||||
|
||||
return dump_tdb(fname);
|
||||
}
|
||||
263
source/utils/tdb/tdbtest.c
Normal file
263
source/utils/tdb/tdbtest.c
Normal file
@@ -0,0 +1,263 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <signal.h>
|
||||
#include "tdb.h"
|
||||
#include <gdbm.h>
|
||||
|
||||
/* a test program for tdb - the trivial database */
|
||||
|
||||
|
||||
|
||||
#define DELETE_PROB 7
|
||||
#define STORE_PROB 5
|
||||
|
||||
static TDB_CONTEXT *db;
|
||||
static GDBM_FILE gdbm;
|
||||
|
||||
struct timeval tp1,tp2;
|
||||
|
||||
static void start_timer(void)
|
||||
{
|
||||
gettimeofday(&tp1,NULL);
|
||||
}
|
||||
|
||||
static double end_timer(void)
|
||||
{
|
||||
gettimeofday(&tp2,NULL);
|
||||
return((tp2.tv_sec - tp1.tv_sec) +
|
||||
(tp2.tv_usec - tp1.tv_usec)*1.0e-6);
|
||||
}
|
||||
|
||||
static void fatal(char *why)
|
||||
{
|
||||
perror(why);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vfprintf(stdout, format, ap);
|
||||
va_end(ap);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void compare_db(void)
|
||||
{
|
||||
TDB_DATA d, key, nextkey;
|
||||
datum gd, gkey, gnextkey;
|
||||
|
||||
key = tdb_firstkey(db);
|
||||
while (key.dptr) {
|
||||
d = tdb_fetch(db, key);
|
||||
gkey.dptr = key.dptr;
|
||||
gkey.dsize = key.dsize;
|
||||
|
||||
gd = gdbm_fetch(gdbm, gkey);
|
||||
|
||||
if (!gd.dptr) fatal("key not in gdbm");
|
||||
if (gd.dsize != d.dsize) fatal("data sizes differ");
|
||||
if (memcmp(gd.dptr, d.dptr, d.dsize)) {
|
||||
fatal("data differs");
|
||||
}
|
||||
|
||||
nextkey = tdb_nextkey(db, key);
|
||||
free(key.dptr);
|
||||
free(d.dptr);
|
||||
free(gd.dptr);
|
||||
key = nextkey;
|
||||
}
|
||||
|
||||
gkey = gdbm_firstkey(gdbm);
|
||||
while (gkey.dptr) {
|
||||
gd = gdbm_fetch(gdbm, gkey);
|
||||
key.dptr = gkey.dptr;
|
||||
key.dsize = gkey.dsize;
|
||||
|
||||
d = tdb_fetch(db, key);
|
||||
|
||||
if (!d.dptr) fatal("key not in db");
|
||||
if (d.dsize != gd.dsize) fatal("data sizes differ");
|
||||
if (memcmp(d.dptr, gd.dptr, gd.dsize)) {
|
||||
fatal("data differs");
|
||||
}
|
||||
|
||||
gnextkey = gdbm_nextkey(gdbm, gkey);
|
||||
free(gkey.dptr);
|
||||
free(gd.dptr);
|
||||
free(d.dptr);
|
||||
gkey = gnextkey;
|
||||
}
|
||||
}
|
||||
|
||||
static char *randbuf(int len)
|
||||
{
|
||||
char *buf;
|
||||
int i;
|
||||
buf = (char *)malloc(len+1);
|
||||
|
||||
for (i=0;i<len;i++) {
|
||||
buf[i] = 'a' + (rand() % 26);
|
||||
}
|
||||
buf[i] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void addrec_db(void)
|
||||
{
|
||||
int klen, dlen;
|
||||
char *k, *d;
|
||||
TDB_DATA key, data;
|
||||
|
||||
klen = 1 + (rand() % 4);
|
||||
dlen = 1 + (rand() % 100);
|
||||
|
||||
k = randbuf(klen);
|
||||
d = randbuf(dlen);
|
||||
|
||||
key.dptr = k;
|
||||
key.dsize = klen+1;
|
||||
|
||||
data.dptr = d;
|
||||
data.dsize = dlen+1;
|
||||
|
||||
if (rand() % DELETE_PROB == 0) {
|
||||
tdb_delete(db, key);
|
||||
} else if (rand() % STORE_PROB == 0) {
|
||||
if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
|
||||
fatal("tdb_store failed");
|
||||
}
|
||||
} else {
|
||||
data = tdb_fetch(db, key);
|
||||
if (data.dptr) free(data.dptr);
|
||||
}
|
||||
|
||||
free(k);
|
||||
free(d);
|
||||
}
|
||||
|
||||
static void addrec_gdbm(void)
|
||||
{
|
||||
int klen, dlen;
|
||||
char *k, *d;
|
||||
datum key, data;
|
||||
|
||||
klen = 1 + (rand() % 4);
|
||||
dlen = 1 + (rand() % 100);
|
||||
|
||||
k = randbuf(klen);
|
||||
d = randbuf(dlen);
|
||||
|
||||
key.dptr = k;
|
||||
key.dsize = klen+1;
|
||||
|
||||
data.dptr = d;
|
||||
data.dsize = dlen+1;
|
||||
|
||||
if (rand() % DELETE_PROB == 0) {
|
||||
gdbm_delete(gdbm, key);
|
||||
} else if (rand() % STORE_PROB == 0) {
|
||||
if (gdbm_store(gdbm, key, data, GDBM_REPLACE) != 0) {
|
||||
fatal("gdbm_store failed");
|
||||
}
|
||||
} else {
|
||||
data = gdbm_fetch(gdbm, key);
|
||||
if (data.dptr) free(data.dptr);
|
||||
}
|
||||
|
||||
free(k);
|
||||
free(d);
|
||||
}
|
||||
|
||||
static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
|
||||
{
|
||||
#if 0
|
||||
printf("[%s] [%s]\n", key.dptr, dbuf.dptr);
|
||||
#endif
|
||||
tdb_delete(tdb, key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void merge_test(void)
|
||||
{
|
||||
int i;
|
||||
char keys[5][2];
|
||||
TDB_DATA key, data;
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
sprintf(keys[i], "%d", i);
|
||||
key.dptr = keys[i];
|
||||
key.dsize = 2;
|
||||
|
||||
data.dptr = "test";
|
||||
data.dsize = 4;
|
||||
|
||||
if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
|
||||
fatal("tdb_store failed");
|
||||
}
|
||||
}
|
||||
|
||||
key.dptr = keys[0];
|
||||
tdb_delete(db, key);
|
||||
key.dptr = keys[4];
|
||||
tdb_delete(db, key);
|
||||
key.dptr = keys[2];
|
||||
tdb_delete(db, key);
|
||||
key.dptr = keys[1];
|
||||
tdb_delete(db, key);
|
||||
key.dptr = keys[3];
|
||||
tdb_delete(db, key);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i, seed=0;
|
||||
int loops = 10000;
|
||||
|
||||
unlink("test.gdbm");
|
||||
|
||||
db = tdb_open("test.tdb", 0, TDB_CLEAR_IF_FIRST,
|
||||
O_RDWR | O_CREAT | O_TRUNC, 0600);
|
||||
gdbm = gdbm_open("test.gdbm", 512, GDBM_WRITER|GDBM_NEWDB|GDBM_FAST,
|
||||
0600, NULL);
|
||||
|
||||
if (!db || !gdbm) {
|
||||
fatal("db open failed");
|
||||
}
|
||||
|
||||
tdb_logging_function(db, tdb_log);
|
||||
|
||||
#if 1
|
||||
srand(seed);
|
||||
start_timer();
|
||||
for (i=0;i<loops;i++) addrec_gdbm();
|
||||
printf("gdbm got %.2f ops/sec\n", i/end_timer());
|
||||
#endif
|
||||
|
||||
merge_test();
|
||||
|
||||
srand(seed);
|
||||
start_timer();
|
||||
for (i=0;i<loops;i++) addrec_db();
|
||||
printf("tdb got %.2f ops/sec\n", i/end_timer());
|
||||
|
||||
compare_db();
|
||||
|
||||
printf("traversed %d records\n", tdb_traverse(db, traverse_fn, NULL));
|
||||
printf("traversed %d records\n", tdb_traverse(db, traverse_fn, NULL));
|
||||
|
||||
tdb_close(db);
|
||||
gdbm_close(gdbm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
482
source/utils/tdb/tdbtool.c
Normal file
482
source/utils/tdb/tdbtool.c
Normal file
@@ -0,0 +1,482 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Samba database functions
|
||||
Copyright (C) Andrew Tridgell 1999-2000
|
||||
Copyright (C) Paul `Rusty' Russell 2000
|
||||
Copyright (C) Jeremy Allison 2000
|
||||
Copyright (C) Andrew Esh 2001
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
#include "tdb.h"
|
||||
|
||||
/* a tdb tool for manipulating a tdb database */
|
||||
|
||||
#define FSTRING_LEN 256
|
||||
typedef char fstring[FSTRING_LEN];
|
||||
|
||||
typedef struct connections_key {
|
||||
pid_t pid;
|
||||
int cnum;
|
||||
fstring name;
|
||||
} connections_key;
|
||||
|
||||
typedef struct connections_data {
|
||||
int magic;
|
||||
pid_t pid;
|
||||
int cnum;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
char name[24];
|
||||
char addr[24];
|
||||
char machine[128];
|
||||
time_t start;
|
||||
} connections_data;
|
||||
|
||||
static TDB_CONTEXT *tdb;
|
||||
|
||||
static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state);
|
||||
|
||||
static void print_asc(unsigned char *buf,int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* We're probably printing ASCII strings so don't try to display
|
||||
the trailing NULL character. */
|
||||
|
||||
if (buf[len - 1] == 0)
|
||||
len--;
|
||||
|
||||
for (i=0;i<len;i++)
|
||||
printf("%c",isprint(buf[i])?buf[i]:'.');
|
||||
}
|
||||
|
||||
static void print_data(unsigned char *buf,int len)
|
||||
{
|
||||
int i=0;
|
||||
if (len<=0) return;
|
||||
printf("[%03X] ",i);
|
||||
for (i=0;i<len;) {
|
||||
printf("%02X ",(int)buf[i]);
|
||||
i++;
|
||||
if (i%8 == 0) printf(" ");
|
||||
if (i%16 == 0) {
|
||||
print_asc(&buf[i-16],8); printf(" ");
|
||||
print_asc(&buf[i-8],8); printf("\n");
|
||||
if (i<len) printf("[%03X] ",i);
|
||||
}
|
||||
}
|
||||
if (i%16) {
|
||||
int n;
|
||||
|
||||
n = 16 - (i%16);
|
||||
printf(" ");
|
||||
if (n>8) printf(" ");
|
||||
while (n--) printf(" ");
|
||||
|
||||
n = i%16;
|
||||
if (n > 8) n = 8;
|
||||
print_asc(&buf[i-(i%16)],n); printf(" ");
|
||||
n = (i%16) - n;
|
||||
if (n>0) print_asc(&buf[i-n],n);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void help(void)
|
||||
{
|
||||
printf("
|
||||
tdbtool:
|
||||
create dbname : create a database
|
||||
open dbname : open an existing database
|
||||
erase : erase the database
|
||||
dump : dump the database as strings
|
||||
insert key data : insert a record
|
||||
store key data : store a record (replace)
|
||||
show key : show a record by key
|
||||
delete key : delete a record by key
|
||||
list : print the database hash table and freelist
|
||||
free : print the database freelist
|
||||
1 | first : print the first record
|
||||
n | next : print the next record
|
||||
q | quit : terminate
|
||||
\\n : repeat 'next' command
|
||||
");
|
||||
}
|
||||
|
||||
static void terror(char *why)
|
||||
{
|
||||
printf("%s\n", why);
|
||||
}
|
||||
|
||||
static char *get_token(int startover)
|
||||
{
|
||||
static char tmp[1024];
|
||||
static char *cont = NULL;
|
||||
char *insert, *start;
|
||||
char *k = strtok(NULL, " ");
|
||||
|
||||
if (!k)
|
||||
return NULL;
|
||||
|
||||
if (startover)
|
||||
start = tmp;
|
||||
else
|
||||
start = cont;
|
||||
|
||||
strcpy(start, k);
|
||||
insert = start + strlen(start) - 1;
|
||||
while (*insert == '\\') {
|
||||
*insert++ = ' ';
|
||||
k = strtok(NULL, " ");
|
||||
if (!k)
|
||||
break;
|
||||
strcpy(insert, k);
|
||||
insert = start + strlen(start) - 1;
|
||||
}
|
||||
|
||||
/* Get ready for next call */
|
||||
cont = start + strlen(start) + 1;
|
||||
return start;
|
||||
}
|
||||
|
||||
static void create_tdb(void)
|
||||
{
|
||||
char *tok = get_token(1);
|
||||
if (!tok) {
|
||||
help();
|
||||
return;
|
||||
}
|
||||
if (tdb) tdb_close(tdb);
|
||||
tdb = tdb_open(tok, 0, TDB_CLEAR_IF_FIRST,
|
||||
O_RDWR | O_CREAT | O_TRUNC, 0600);
|
||||
if (!tdb) {
|
||||
printf("Could not create %s: %s\n", tok, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
static void open_tdb(void)
|
||||
{
|
||||
char *tok = get_token(1);
|
||||
if (!tok) {
|
||||
help();
|
||||
return;
|
||||
}
|
||||
if (tdb) tdb_close(tdb);
|
||||
tdb = tdb_open(tok, 0, 0, O_RDWR, 0600);
|
||||
if (!tdb) {
|
||||
printf("Could not open %s: %s\n", tok, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_tdb(void)
|
||||
{
|
||||
char *k = get_token(1);
|
||||
char *d = get_token(0);
|
||||
TDB_DATA key, dbuf;
|
||||
|
||||
if (!k || !d) {
|
||||
help();
|
||||
return;
|
||||
}
|
||||
|
||||
key.dptr = k;
|
||||
key.dsize = strlen(k)+1;
|
||||
dbuf.dptr = d;
|
||||
dbuf.dsize = strlen(d)+1;
|
||||
|
||||
if (tdb_store(tdb, key, dbuf, TDB_INSERT) == -1) {
|
||||
terror("insert failed");
|
||||
}
|
||||
}
|
||||
|
||||
static void store_tdb(void)
|
||||
{
|
||||
char *k = get_token(1);
|
||||
char *d = get_token(0);
|
||||
TDB_DATA key, dbuf;
|
||||
|
||||
if (!k || !d) {
|
||||
help();
|
||||
return;
|
||||
}
|
||||
|
||||
key.dptr = k;
|
||||
key.dsize = strlen(k)+1;
|
||||
dbuf.dptr = d;
|
||||
dbuf.dsize = strlen(d)+1;
|
||||
|
||||
printf("Storing key:\n");
|
||||
print_rec(tdb, key, dbuf, NULL);
|
||||
|
||||
if (tdb_store(tdb, key, dbuf, TDB_REPLACE) == -1) {
|
||||
terror("store failed");
|
||||
}
|
||||
}
|
||||
|
||||
static void show_tdb(void)
|
||||
{
|
||||
char *k = get_token(1);
|
||||
TDB_DATA key, dbuf;
|
||||
|
||||
if (!k) {
|
||||
help();
|
||||
return;
|
||||
}
|
||||
|
||||
key.dptr = k;
|
||||
/* key.dsize = strlen(k)+1;*/
|
||||
key.dsize = strlen(k);
|
||||
|
||||
dbuf = tdb_fetch(tdb, key);
|
||||
if (!dbuf.dptr) {
|
||||
terror("fetch failed");
|
||||
return;
|
||||
}
|
||||
/* printf("%s : %*.*s\n", k, (int)dbuf.dsize, (int)dbuf.dsize, dbuf.dptr); */
|
||||
print_rec(tdb, key, dbuf, NULL);
|
||||
}
|
||||
|
||||
static void delete_tdb(void)
|
||||
{
|
||||
char *k = get_token(1);
|
||||
TDB_DATA key;
|
||||
|
||||
if (!k) {
|
||||
help();
|
||||
return;
|
||||
}
|
||||
|
||||
key.dptr = k;
|
||||
key.dsize = strlen(k)+1;
|
||||
|
||||
if (tdb_delete(tdb, key) != 0) {
|
||||
terror("delete failed");
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static int print_conn_key(TDB_DATA key)
|
||||
{
|
||||
printf( "pid =%5d ", ((connections_key*)key.dptr)->pid);
|
||||
printf( "cnum =%10d ", ((connections_key*)key.dptr)->cnum);
|
||||
printf( "name =[%s]\n", ((connections_key*)key.dptr)->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_conn_data(TDB_DATA dbuf)
|
||||
{
|
||||
printf( "pid =%5d ", ((connections_data*)dbuf.dptr)->pid);
|
||||
printf( "cnum =%10d ", ((connections_data*)dbuf.dptr)->cnum);
|
||||
printf( "name =[%s]\n", ((connections_data*)dbuf.dptr)->name);
|
||||
|
||||
printf( "uid =%5d ", ((connections_data*)dbuf.dptr)->uid);
|
||||
printf( "addr =[%s]\n", ((connections_data*)dbuf.dptr)->addr);
|
||||
printf( "gid =%5d ", ((connections_data*)dbuf.dptr)->gid);
|
||||
printf( "machine=[%s]\n", ((connections_data*)dbuf.dptr)->machine);
|
||||
printf( "start = %s\n", ctime(&((connections_data*)dbuf.dptr)->start));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int print_rec(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
|
||||
{
|
||||
#if 0
|
||||
print_conn_key(key);
|
||||
print_conn_data(dbuf);
|
||||
return 0;
|
||||
#else
|
||||
printf("\nkey %d bytes\n", key.dsize);
|
||||
print_asc(key.dptr, key.dsize);
|
||||
printf("\ndata %d bytes\n", dbuf.dsize);
|
||||
print_data(dbuf.dptr, dbuf.dsize);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int print_key(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
|
||||
{
|
||||
print_asc(key.dptr, key.dsize);
|
||||
printf("\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int total_bytes;
|
||||
|
||||
static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf, void *state)
|
||||
{
|
||||
total_bytes += dbuf.dsize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void info_tdb(void)
|
||||
{
|
||||
int count;
|
||||
total_bytes = 0;
|
||||
if ((count = tdb_traverse(tdb, traverse_fn, NULL) == -1))
|
||||
printf("Error = %s\n", tdb_errorstr(tdb));
|
||||
else
|
||||
printf("%d records totalling %d bytes\n", count, total_bytes);
|
||||
}
|
||||
|
||||
static char *tdb_getline(char *prompt)
|
||||
{
|
||||
static char line[1024];
|
||||
char *p;
|
||||
fputs(prompt, stdout);
|
||||
line[0] = 0;
|
||||
p = fgets(line, sizeof(line)-1, stdin);
|
||||
if (p) p = strchr(p, '\n');
|
||||
if (p) *p = 0;
|
||||
return p?line:NULL;
|
||||
}
|
||||
|
||||
static int do_delete_fn(TDB_CONTEXT *the_tdb, TDB_DATA key, TDB_DATA dbuf,
|
||||
void *state)
|
||||
{
|
||||
return tdb_delete(the_tdb, key);
|
||||
}
|
||||
|
||||
static void first_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey)
|
||||
{
|
||||
TDB_DATA dbuf;
|
||||
*pkey = tdb_firstkey(the_tdb);
|
||||
|
||||
dbuf = tdb_fetch(the_tdb, *pkey);
|
||||
if (!dbuf.dptr) terror("fetch failed");
|
||||
else {
|
||||
/* printf("%s : %*.*s\n", k, (int)dbuf.dsize, (int)dbuf.dsize, dbuf.dptr); */
|
||||
print_rec(the_tdb, *pkey, dbuf, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void next_record(TDB_CONTEXT *the_tdb, TDB_DATA *pkey)
|
||||
{
|
||||
TDB_DATA dbuf;
|
||||
*pkey = tdb_nextkey(the_tdb, *pkey);
|
||||
|
||||
dbuf = tdb_fetch(the_tdb, *pkey);
|
||||
if (!dbuf.dptr)
|
||||
terror("fetch failed");
|
||||
else
|
||||
/* printf("%s : %*.*s\n", k, (int)dbuf.dsize, (int)dbuf.dsize, dbuf.dptr); */
|
||||
print_rec(the_tdb, *pkey, dbuf, NULL);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int bIterate = 0;
|
||||
char *line;
|
||||
char *tok;
|
||||
TDB_DATA iterate_kbuf;
|
||||
|
||||
if (argv[1]) {
|
||||
static char tmp[1024];
|
||||
sprintf(tmp, "open %s", argv[1]);
|
||||
tok=strtok(tmp," ");
|
||||
open_tdb();
|
||||
}
|
||||
|
||||
while ((line = tdb_getline("tdb> "))) {
|
||||
|
||||
/* Shell command */
|
||||
|
||||
if (line[0] == '!') {
|
||||
system(line + 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((tok = strtok(line," "))==NULL) {
|
||||
if (bIterate)
|
||||
next_record(tdb, &iterate_kbuf);
|
||||
continue;
|
||||
}
|
||||
if (strcmp(tok,"create") == 0) {
|
||||
bIterate = 0;
|
||||
create_tdb();
|
||||
continue;
|
||||
} else if (strcmp(tok,"open") == 0) {
|
||||
open_tdb();
|
||||
continue;
|
||||
} else if ((strcmp(tok, "q") == 0) ||
|
||||
(strcmp(tok, "quit") == 0)) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* all the rest require a open database */
|
||||
if (!tdb) {
|
||||
bIterate = 0;
|
||||
terror("database not open");
|
||||
help();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(tok,"insert") == 0) {
|
||||
bIterate = 0;
|
||||
insert_tdb();
|
||||
} else if (strcmp(tok,"store") == 0) {
|
||||
bIterate = 0;
|
||||
store_tdb();
|
||||
} else if (strcmp(tok,"show") == 0) {
|
||||
bIterate = 0;
|
||||
show_tdb();
|
||||
} else if (strcmp(tok,"erase") == 0) {
|
||||
bIterate = 0;
|
||||
tdb_traverse(tdb, do_delete_fn, NULL);
|
||||
} else if (strcmp(tok,"delete") == 0) {
|
||||
bIterate = 0;
|
||||
delete_tdb();
|
||||
} else if (strcmp(tok,"dump") == 0) {
|
||||
bIterate = 0;
|
||||
tdb_traverse(tdb, print_rec, NULL);
|
||||
} else if (strcmp(tok,"list") == 0) {
|
||||
tdb_dump_all(tdb);
|
||||
} else if (strcmp(tok, "free") == 0) {
|
||||
tdb_printfreelist(tdb);
|
||||
} else if (strcmp(tok,"info") == 0) {
|
||||
info_tdb();
|
||||
} else if ( (strcmp(tok, "1") == 0) ||
|
||||
(strcmp(tok, "first") == 0)) {
|
||||
bIterate = 1;
|
||||
first_record(tdb, &iterate_kbuf);
|
||||
} else if ((strcmp(tok, "n") == 0) ||
|
||||
(strcmp(tok, "next") == 0)) {
|
||||
next_record(tdb, &iterate_kbuf);
|
||||
} else if ((strcmp(tok, "keys") == 0)) {
|
||||
bIterate = 0;
|
||||
tdb_traverse(tdb, print_key, NULL);
|
||||
} else {
|
||||
help();
|
||||
}
|
||||
}
|
||||
|
||||
if (tdb) tdb_close(tdb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
226
source/utils/tdb/tdbtorture.c
Normal file
226
source/utils/tdb/tdbtorture.c
Normal file
@@ -0,0 +1,226 @@
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include "tdb.h"
|
||||
|
||||
/* this tests tdb by doing lots of ops from several simultaneous
|
||||
writers - that stresses the locking code. Build with TDB_DEBUG=1
|
||||
for best effect */
|
||||
|
||||
|
||||
|
||||
#define REOPEN_PROB 30
|
||||
#define DELETE_PROB 8
|
||||
#define STORE_PROB 4
|
||||
#define APPEND_PROB 6
|
||||
#define LOCKSTORE_PROB 0
|
||||
#define TRAVERSE_PROB 20
|
||||
#define CULL_PROB 100
|
||||
#define KEYLEN 3
|
||||
#define DATALEN 100
|
||||
#define LOCKLEN 20
|
||||
|
||||
static TDB_CONTEXT *db;
|
||||
|
||||
static void tdb_log(TDB_CONTEXT *tdb, int level, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
vfprintf(stdout, format, ap);
|
||||
va_end(ap);
|
||||
fflush(stdout);
|
||||
#if 0
|
||||
{
|
||||
char *ptr;
|
||||
asprintf(&ptr,"xterm -e gdb /proc/%d/exe %d", getpid(), getpid());
|
||||
system(ptr);
|
||||
free(ptr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void fatal(char *why)
|
||||
{
|
||||
perror(why);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static char *randbuf(int len)
|
||||
{
|
||||
char *buf;
|
||||
int i;
|
||||
buf = (char *)malloc(len+1);
|
||||
|
||||
for (i=0;i<len;i++) {
|
||||
buf[i] = 'a' + (rand() % 26);
|
||||
}
|
||||
buf[i] = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int cull_traverse(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf,
|
||||
void *state)
|
||||
{
|
||||
if (random() % CULL_PROB == 0) {
|
||||
tdb_delete(tdb, key);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void addrec_db(void)
|
||||
{
|
||||
int klen, dlen, slen;
|
||||
char *k, *d, *s;
|
||||
TDB_DATA key, data, lockkey;
|
||||
|
||||
klen = 1 + (rand() % KEYLEN);
|
||||
dlen = 1 + (rand() % DATALEN);
|
||||
slen = 1 + (rand() % LOCKLEN);
|
||||
|
||||
k = randbuf(klen);
|
||||
d = randbuf(dlen);
|
||||
s = randbuf(slen);
|
||||
|
||||
key.dptr = k;
|
||||
key.dsize = klen+1;
|
||||
|
||||
data.dptr = d;
|
||||
data.dsize = dlen+1;
|
||||
|
||||
lockkey.dptr = s;
|
||||
lockkey.dsize = slen+1;
|
||||
|
||||
#if REOPEN_PROB
|
||||
if (random() % REOPEN_PROB == 0) {
|
||||
tdb_reopen_all();
|
||||
goto next;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DELETE_PROB
|
||||
if (random() % DELETE_PROB == 0) {
|
||||
tdb_delete(db, key);
|
||||
goto next;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if STORE_PROB
|
||||
if (random() % STORE_PROB == 0) {
|
||||
if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
|
||||
fatal("tdb_store failed");
|
||||
}
|
||||
goto next;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if APPEND_PROB
|
||||
if (random() % APPEND_PROB == 0) {
|
||||
if (tdb_append(db, key, data) != 0) {
|
||||
fatal("tdb_append failed");
|
||||
}
|
||||
goto next;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LOCKSTORE_PROB
|
||||
if (random() % LOCKSTORE_PROB == 0) {
|
||||
tdb_chainlock(db, lockkey);
|
||||
data = tdb_fetch(db, key);
|
||||
if (tdb_store(db, key, data, TDB_REPLACE) != 0) {
|
||||
fatal("tdb_store failed");
|
||||
}
|
||||
if (data.dptr) free(data.dptr);
|
||||
tdb_chainunlock(db, lockkey);
|
||||
goto next;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TRAVERSE_PROB
|
||||
if (random() % TRAVERSE_PROB == 0) {
|
||||
tdb_traverse(db, cull_traverse, NULL);
|
||||
goto next;
|
||||
}
|
||||
#endif
|
||||
|
||||
data = tdb_fetch(db, key);
|
||||
if (data.dptr) free(data.dptr);
|
||||
|
||||
next:
|
||||
free(k);
|
||||
free(d);
|
||||
free(s);
|
||||
}
|
||||
|
||||
static int traverse_fn(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA dbuf,
|
||||
void *state)
|
||||
{
|
||||
tdb_delete(tdb, key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef NPROC
|
||||
#define NPROC 6
|
||||
#endif
|
||||
|
||||
#ifndef NLOOPS
|
||||
#define NLOOPS 200000
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i, seed=0;
|
||||
int loops = NLOOPS;
|
||||
pid_t pids[NPROC];
|
||||
|
||||
pids[0] = getpid();
|
||||
|
||||
for (i=0;i<NPROC-1;i++) {
|
||||
if ((pids[i+1]=fork()) == 0) break;
|
||||
}
|
||||
|
||||
db = tdb_open("torture.tdb", 2, TDB_CLEAR_IF_FIRST,
|
||||
O_RDWR | O_CREAT, 0600);
|
||||
if (!db) {
|
||||
fatal("db open failed");
|
||||
}
|
||||
tdb_logging_function(db, tdb_log);
|
||||
|
||||
srand(seed + getpid());
|
||||
srandom(seed + getpid() + time(NULL));
|
||||
for (i=0;i<loops;i++) addrec_db();
|
||||
|
||||
tdb_traverse(db, NULL, NULL);
|
||||
tdb_traverse(db, traverse_fn, NULL);
|
||||
tdb_traverse(db, traverse_fn, NULL);
|
||||
|
||||
tdb_close(db);
|
||||
|
||||
if (getpid() == pids[0]) {
|
||||
for (i=0;i<NPROC-1;i++) {
|
||||
int status;
|
||||
if (waitpid(pids[i+1], &status, 0) != pids[i+1]) {
|
||||
printf("failed to wait for %d\n",
|
||||
(int)pids[i+1]);
|
||||
exit(1);
|
||||
}
|
||||
if (WEXITSTATUS(status) != 0) {
|
||||
printf("child %d exited with status %d\n",
|
||||
(int)pids[i+1], WEXITSTATUS(status));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
printf("OK\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
338
source/utils/testparm.c
Normal file
338
source/utils/testparm.c
Normal file
@@ -0,0 +1,338 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Test validity of smb.conf
|
||||
Copyright (C) Karl Auer 1993, 1994-1998
|
||||
|
||||
Extensively modified by Andrew Tridgell, 1995
|
||||
Converted to popt by Jelmer Vernooij (jelmer@nl.linux.org), 2002
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Testbed for loadparm.c/params.c
|
||||
*
|
||||
* This module simply loads a specified configuration file and
|
||||
* if successful, dumps it's contents to stdout. Note that the
|
||||
* operation is performed with DEBUGLEVEL at 3.
|
||||
*
|
||||
* Useful for a quick 'syntax check' of a configuration file.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
extern BOOL AllowDebugChange;
|
||||
|
||||
/***********************************************
|
||||
Here we do a set of 'hard coded' checks for bad
|
||||
configuration settings.
|
||||
************************************************/
|
||||
|
||||
static int do_global_checks(void)
|
||||
{
|
||||
int ret = 0;
|
||||
SMB_STRUCT_STAT st;
|
||||
|
||||
if (lp_security() >= SEC_DOMAIN && !lp_encrypted_passwords()) {
|
||||
printf("ERROR: in 'security=domain' mode the 'encrypt passwords' parameter must always be set to 'true'.\n");
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (lp_wins_support() && lp_wins_server_list()) {
|
||||
printf("ERROR: both 'wins support = true' and 'wins server = <server list>' \
|
||||
cannot be set in the smb.conf file. nmbd will abort with this setting.\n");
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (!directory_exist(lp_lockdir(), &st)) {
|
||||
printf("ERROR: lock directory %s does not exist\n",
|
||||
lp_lockdir());
|
||||
ret = 1;
|
||||
} else if ((st.st_mode & 0777) != 0755) {
|
||||
printf("WARNING: lock directory %s should have permissions 0755 for browsing to work\n",
|
||||
lp_lockdir());
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (!directory_exist(lp_piddir(), &st)) {
|
||||
printf("ERROR: pid directory %s does not exist\n",
|
||||
lp_piddir());
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Password server sanity checks.
|
||||
*/
|
||||
|
||||
if((lp_security() == SEC_SERVER || lp_security() >= SEC_DOMAIN) && !lp_passwordserver()) {
|
||||
pstring sec_setting;
|
||||
if(lp_security() == SEC_SERVER)
|
||||
pstrcpy(sec_setting, "server");
|
||||
else if(lp_security() == SEC_DOMAIN)
|
||||
pstrcpy(sec_setting, "domain");
|
||||
|
||||
printf("ERROR: The setting 'security=%s' requires the 'password server' parameter be set \
|
||||
to a valid password server.\n", sec_setting );
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Check 'hosts equiv' and 'use rhosts' compatibility with 'hostname lookup' value.
|
||||
*/
|
||||
|
||||
if(*lp_hosts_equiv() && !lp_hostname_lookups()) {
|
||||
printf("ERROR: The setting 'hosts equiv = %s' requires that 'hostname lookups = yes'.\n", lp_hosts_equiv());
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Password chat sanity checks.
|
||||
*/
|
||||
|
||||
if(lp_security() == SEC_USER && lp_unix_password_sync()) {
|
||||
|
||||
/*
|
||||
* Check that we have a valid lp_passwd_program() if not using pam.
|
||||
*/
|
||||
|
||||
#ifdef WITH_PAM
|
||||
if (!lp_pam_password_change()) {
|
||||
#endif
|
||||
|
||||
if(lp_passwd_program() == NULL) {
|
||||
printf("ERROR: the 'unix password sync' parameter is set and there is no valid 'passwd program' \
|
||||
parameter.\n" );
|
||||
ret = 1;
|
||||
} else {
|
||||
pstring passwd_prog;
|
||||
pstring truncated_prog;
|
||||
const char *p;
|
||||
|
||||
pstrcpy( passwd_prog, lp_passwd_program());
|
||||
p = passwd_prog;
|
||||
*truncated_prog = '\0';
|
||||
next_token(&p, truncated_prog, NULL, sizeof(pstring));
|
||||
|
||||
if(access(truncated_prog, F_OK) == -1) {
|
||||
printf("ERROR: the 'unix password sync' parameter is set and the 'passwd program' (%s) \
|
||||
cannot be executed (error was %s).\n", truncated_prog, strerror(errno) );
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_PAM
|
||||
}
|
||||
#endif
|
||||
|
||||
if(lp_passwd_chat() == NULL) {
|
||||
printf("ERROR: the 'unix password sync' parameter is set and there is no valid 'passwd chat' \
|
||||
parameter.\n");
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that we have a valid script and that it hasn't
|
||||
* been written to expect the old password.
|
||||
*/
|
||||
|
||||
if(lp_encrypted_passwords()) {
|
||||
if(strstr( lp_passwd_chat(), "%o")!=NULL) {
|
||||
printf("ERROR: the 'passwd chat' script [%s] expects to use the old plaintext password \
|
||||
via the %%o substitution. With encrypted passwords this is not possible.\n", lp_passwd_chat() );
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(lp_winbind_separator()) != 1) {
|
||||
printf("ERROR: the 'winbind separator' parameter must be a single character.\n");
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (*lp_winbind_separator() == '+') {
|
||||
printf("'winbind separator = +' might cause problems with group membership.\n");
|
||||
}
|
||||
|
||||
if (lp_algorithmic_rid_base() < BASE_RID) {
|
||||
/* Try to prevent admin foot-shooting, we can't put algorithmic
|
||||
rids below 1000, that's the 'well known RIDs' on NT */
|
||||
printf("'algorithmic rid base' must be equal to or above %lu\n", BASE_RID);
|
||||
}
|
||||
|
||||
if (lp_algorithmic_rid_base() & 1) {
|
||||
printf("'algorithmic rid base' must be even.\n");
|
||||
}
|
||||
|
||||
#ifndef HAVE_DLOPEN
|
||||
if (lp_preload_modules()) {
|
||||
printf("WARNING: 'preload modules = ' set while loading plugins not supported.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
const char *config_file = dyn_CONFIGFILE;
|
||||
int s;
|
||||
static BOOL silent_mode = False;
|
||||
int ret = 0;
|
||||
int opt;
|
||||
poptContext pc;
|
||||
static const char *term_code = "";
|
||||
static char *new_local_machine = NULL;
|
||||
const char *cname;
|
||||
const char *caddr;
|
||||
static int show_defaults;
|
||||
|
||||
struct poptOption long_options[] = {
|
||||
POPT_AUTOHELP
|
||||
{"suppress-prompt", 's', POPT_ARG_VAL, &silent_mode, 1, "Suppress prompt for enter"},
|
||||
{"verbose", 'v', POPT_ARG_NONE, &show_defaults, 1, "Show default options too"},
|
||||
{"server", 'L',POPT_ARG_STRING, &new_local_machine, 0, "Set %%L macro to servername\n"},
|
||||
{"encoding", 't', POPT_ARG_STRING, &term_code, 0, "Print parameters with encoding"},
|
||||
{NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_version},
|
||||
{0,0,0,0}
|
||||
};
|
||||
|
||||
pc = poptGetContext(NULL, argc, argv, long_options,
|
||||
POPT_CONTEXT_KEEP_FIRST);
|
||||
poptSetOtherOptionHelp(pc, "[OPTION...] <config-file> [host-name] [host-ip]");
|
||||
|
||||
while((opt = poptGetNextOpt(pc)) != -1);
|
||||
|
||||
setup_logging(poptGetArg(pc), True);
|
||||
|
||||
if (poptPeekArg(pc))
|
||||
config_file = poptGetArg(pc);
|
||||
|
||||
cname = poptGetArg(pc);
|
||||
caddr = poptGetArg(pc);
|
||||
|
||||
if (new_local_machine) {
|
||||
set_local_machine_name(new_local_machine);
|
||||
}
|
||||
|
||||
dbf = x_stdout;
|
||||
DEBUGLEVEL = 2;
|
||||
AllowDebugChange = False;
|
||||
|
||||
printf("Load smb config files from %s\n",config_file);
|
||||
|
||||
if (!lp_load(config_file,False,True,False)) {
|
||||
printf("Error loading services.\n");
|
||||
return(1);
|
||||
}
|
||||
|
||||
printf("Loaded services file OK.\n");
|
||||
|
||||
ret = do_global_checks();
|
||||
|
||||
for (s=0;s<1000;s++) {
|
||||
if (VALID_SNUM(s))
|
||||
if (strlen(lp_servicename(s)) > 8) {
|
||||
printf("WARNING: You have some share names that are longer than 8 chars\n");
|
||||
printf("These may give errors while browsing or may not be accessible\nto some older clients\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (s=0;s<1000;s++) {
|
||||
if (VALID_SNUM(s)) {
|
||||
const char **deny_list = lp_hostsdeny(s);
|
||||
const char **allow_list = lp_hostsallow(s);
|
||||
int i;
|
||||
if(deny_list) {
|
||||
for (i=0; deny_list[i]; i++) {
|
||||
char *hasstar = strchr_m(deny_list[i], '*');
|
||||
char *hasquery = strchr_m(deny_list[i], '?');
|
||||
if(hasstar || hasquery) {
|
||||
printf("Invalid character %c in hosts deny list (%s) for service %s.\n",
|
||||
hasstar ? *hasstar : *hasquery, deny_list[i], lp_servicename(s) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(allow_list) {
|
||||
for (i=0; allow_list[i]; i++) {
|
||||
char *hasstar = strchr_m(allow_list[i], '*');
|
||||
char *hasquery = strchr_m(allow_list[i], '?');
|
||||
if(hasstar || hasquery) {
|
||||
printf("Invalid character %c in hosts allow list (%s) for service %s.\n",
|
||||
hasstar ? *hasstar : *hasquery, allow_list[i], lp_servicename(s) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(lp_level2_oplocks(s) && !lp_oplocks(s)) {
|
||||
printf("Invalid combination of parameters for service %s. \
|
||||
Level II oplocks can only be set if oplocks are also set.\n",
|
||||
lp_servicename(s) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!silent_mode) {
|
||||
printf("Server role: ");
|
||||
switch(lp_server_role()) {
|
||||
case ROLE_STANDALONE:
|
||||
printf("ROLE_STANDALONE\n");
|
||||
break;
|
||||
case ROLE_DOMAIN_MEMBER:
|
||||
printf("ROLE_DOMAIN_MEMBER\n");
|
||||
break;
|
||||
case ROLE_DOMAIN_BDC:
|
||||
printf("ROLE_DOMAIN_BDC\n");
|
||||
break;
|
||||
case ROLE_DOMAIN_PDC:
|
||||
printf("ROLE_DOMAIN_PDC\n");
|
||||
break;
|
||||
default:
|
||||
printf("Unknown -- internal error?\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cname) {
|
||||
if (!silent_mode) {
|
||||
printf("Press enter to see a dump of your service definitions\n");
|
||||
fflush(stdout);
|
||||
getc(stdin);
|
||||
}
|
||||
lp_dump(stdout, show_defaults, lp_numservices());
|
||||
}
|
||||
|
||||
if(cname && caddr){
|
||||
/* this is totally ugly, a real `quick' hack */
|
||||
for (s=0;s<1000;s++) {
|
||||
if (VALID_SNUM(s)) {
|
||||
if (allow_access(lp_hostsdeny(s), lp_hostsallow(s), cname, caddr)) {
|
||||
printf("Allow connection from %s (%s) to %s\n",
|
||||
cname,caddr,lp_servicename(s));
|
||||
} else {
|
||||
printf("Deny connection from %s (%s) to %s\n",
|
||||
cname,caddr,lp_servicename(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return(ret);
|
||||
}
|
||||
61
source/utils/testprns.c
Normal file
61
source/utils/testprns.c
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
test printer setup
|
||||
Copyright (C) Karl Auer 1993, 1994-1998
|
||||
|
||||
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
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Testbed for pcap.c
|
||||
*
|
||||
* This module simply checks a given printer name against the compiled-in
|
||||
* printcap file.
|
||||
*
|
||||
* The operation is performed with DEBUGLEVEL at 3.
|
||||
*
|
||||
* Useful for a quick check of a printcap file.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char *pszTemp;
|
||||
|
||||
setup_logging(argv[0],True);
|
||||
|
||||
if (argc < 2 || argc > 3)
|
||||
printf("Usage: testprns printername [printcapfile]\n");
|
||||
else
|
||||
{
|
||||
dbf = x_fopen("test.log", O_WRONLY|O_CREAT|O_TRUNC, 0644);
|
||||
if (dbf == NULL) {
|
||||
printf("Unable to open logfile.\n");
|
||||
} else {
|
||||
DEBUGLEVEL = 3;
|
||||
pszTemp = (argc < 3) ? PRINTCAP_NAME : argv[2];
|
||||
printf("Looking for printer %s in printcap file %s\n",
|
||||
argv[1], pszTemp);
|
||||
if (!pcap_printername_ok(argv[1], pszTemp))
|
||||
printf("Printer name %s is not valid.\n", argv[1]);
|
||||
else
|
||||
printf("Printer name %s is valid.\n", argv[1]);
|
||||
x_fclose(dbf);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
Reference in New Issue
Block a user