1
0
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:
Andrew Tridgell
-
commit b0510b5428
779 changed files with 352638 additions and 0 deletions

1
source/utils/.cvsignore Normal file
View File

@@ -0,0 +1 @@
net_proto.h

253
source/utils/debug2html.c Normal file
View 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( "&lt;" );
break;
case '>':
(void)printf( "&gt;" );
break;
case '&':
(void)printf( "&amp;" );
break;
case '\"':
(void)printf( "&#34;" );
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

File diff suppressed because it is too large Load Diff

642
source/utils/net.c Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

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
View 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;
}

View 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
View 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
View 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
View 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
View 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
View 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(&regf_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(&regf_hdr->first_key, 0),
IVAL(&regf_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(&regf_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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}

View 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
View 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
View 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
View 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

View 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

View 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

View 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
View 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
View 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;
}

View 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
View 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
View 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);
}