1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-24 10:50:22 +03:00

This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.(This used to be commit 9a5541595f78f2cbba16030552c6e780f6fddcf6)

This commit is contained in:
cvs2svn Import User 2002-09-25 12:59:48 +00:00
commit 3054ef8a6e
80 changed files with 22029 additions and 0 deletions

View File

@ -0,0 +1,237 @@
<chapter id="CodingSuggestions">
<chapterinfo>
<author>
<firstname>Steve</firstname><surname>French</surname>
</author>
<author>
<firstname>Simo</firstname><surname>Sorce</surname>
</author>
<author>
<firstname>Andrew</firstname><surname>Bartlett</surname>
</author>
<author>
<firstname>Tim</firstname><surname>Potter</surname>
</author>
<author>
<firstname>Martin</firstname><surname>Pool</surname>
</author>
</chapterinfo>
<title>Coding Suggestions</title>
<para>
So you want to add code to Samba ...
</para>
<para>
One of the daunting tasks facing a programmer attempting to write code for
Samba is understanding the various coding conventions used by those most
active in the project. These conventions were mostly unwritten and helped
improve either the portability, stability or consistency of the code. This
document will attempt to document a few of the more important coding
practices used at this time on the Samba project. The coding practices are
expected to change slightly over time, and even to grow as more is learned
about obscure portability considerations. Two existing documents
<filename>samba/source/internals.doc</filename> and
<filename>samba/source/architecture.doc</filename> provide
additional information.
</para>
<para>
The loosely related question of coding style is very personal and this
document does not attempt to address that subject, except to say that I
have observed that eight character tabs seem to be preferred in Samba
source. If you are interested in the topic of coding style, two oft-quoted
documents are:
</para>
<para>
<ulink url="http://lxr.linux.no/source/Documentation/CodingStyle">http://lxr.linux.no/source/Documentation/CodingStyle</ulink>
</para>
<para>
<ulink url="http://www.fsf.org/prep/standards_toc.html">http://www.fsf.org/prep/standards_toc.html</ulink>
</para>
<para>
But note that coding style in Samba varies due to the many different
programmers who have contributed.
</para>
<para>
Following are some considerations you should use when adding new code to
Samba. First and foremost remember that:
</para>
<para>
Portability is a primary consideration in adding function, as is network
compatability with de facto, existing, real world CIFS/SMB implementations.
There are lots of platforms that Samba builds on so use caution when adding
a call to a library function that is not invoked in existing Samba code.
Also note that there are many quite different SMB/CIFS clients that Samba
tries to support, not all of which follow the SNIA CIFS Technical Reference
(or the earlier Microsoft reference documents or the X/Open book on the SMB
Standard) perfectly.
</para>
<para>
Here are some other suggestions:
</para>
<orderedlist>
<listitem><para>
use d_printf instead of printf for display text
reason: enable auto-substitution of translated language text
</para></listitem>
<listitem><para>
use SAFE_FREE instead of free
reason: reduce traps due to null pointers
</para></listitem>
<listitem><para>
don't use bzero use memset, or ZERO_STRUCT and ZERO_STRUCTP macros
reason: not POSIX
</para></listitem>
<listitem><para>
don't use strcpy and strlen (use safe_* equivalents)
reason: to avoid traps due to buffer overruns
</para></listitem>
<listitem><para>
don't use getopt_long, use popt functions instead
reason: portability
</para></listitem>
<listitem><para>
explicitly add const qualifiers on parm passing in functions where parm
is input only (somewhat controversial but const can be #defined away)
</para></listitem>
<listitem><para>
when passing a va_list as an arg, or assigning one to another
please use the VA_COPY() macro
reason: on some platforms, va_list is a struct that must be
initialized in each function...can SEGV if you don't.
</para></listitem>
<listitem><para>
discourage use of threads
reason: portability (also see architecture.doc)
</para></listitem>
<listitem><para>
don't explicitly include new header files in C files - new h files
should be included by adding them once to includes.h
reason: consistency
</para></listitem>
<listitem><para>
don't explicitly extern functions (they are autogenerated by
"make proto" into proto.h)
reason: consistency
</para></listitem>
<listitem><para>
use endian safe macros when unpacking SMBs (see byteorder.h and
internals.doc)
reason: not everyone uses Intel
</para></listitem>
<listitem><para>
Note Unicode implications of charset handling (see internals.doc). See
pull_* and push_* and convert_string functions.
reason: Internationalization
</para></listitem>
<listitem><para>
Don't assume English only
reason: See above
</para></listitem>
<listitem><para>
Try to avoid using in/out parameters (functions that return data which
overwrites input parameters)
reason: Can cause stability problems
</para></listitem>
<listitem><para>
Ensure copyright notices are correct, don't append Tridge's name to code
that he didn't write. If you did not write the code, make sure that it
can coexist with the rest of the Samba GPLed code.
</para></listitem>
<listitem><para>
Consider usage of DATA_BLOBs for length specified byte-data.
reason: stability
</para></listitem>
<listitem><para>
Take advantage of tdbs for database like function
reason: consistency
</para></listitem>
<listitem><para>
Don't access the SAM_ACCOUNT structure directly, they should be accessed
via pdb_get...() and pdb_set...() functions.
reason: stability, consistency
</para></listitem>
<listitem><para>
Don't check a password directly against the passdb, always use the
check_password() interface.
reason: long term pluggability
</para></listitem>
<listitem><para>
Try to use asprintf rather than pstrings and fstrings where possible
</para></listitem>
<listitem><para>
Use normal C comments / * instead of C++ comments // like
this. Although the C++ comment format is part of the C99
standard, some older vendor C compilers do not accept it.
</para></listitem>
<listitem><para>
Try to write documentation for API functions and structures
explaining the point of the code, the way it should be used, and
any special conditions or results. Mark these with a double-star
comment start / ** so that they can be picked up by Doxygen, as in
this file.
</para></listitem>
<listitem><para>
Keep the scope narrow. This means making functions/variables
static whenever possible. We don't want our namespace
polluted. Each module should have a minimal number of externally
visible functions or variables.
</para></listitem>
<listitem><para>
Use function pointers to keep knowledge about particular pieces of
code isolated in one place. We don't want a particular piece of
functionality to be spread out across lots of places - that makes
for fragile, hand to maintain code. Instead, design an interface
and use tables containing function pointers to implement specific
functionality. This is particularly important for command
interpreters.
</para></listitem>
<listitem><para>
Think carefully about what it will be like for someone else to add
to and maintain your code. If it would be hard for someone else to
maintain then do it another way.
</para></listitem>
</orderedlist>
<para>
The suggestions above are simply that, suggestions, but the information may
help in reducing the routine rework done on new code. The preceeding list
is expected to change routinely as new support routines and macros are
added.
</para>
</chapter>

View File

@ -0,0 +1,154 @@
<chapter id="netbios">
<chapterinfo>
<author>
<firstname>Luke</firstname><surname>Leighton</surname>
</author>
<pubdate>12 June 1997</pubdate>
</chapterinfo>
<title>Definition of NetBIOS Protocol and Name Resolution Modes</title>
<sect1>
<title>NETBIOS</title>
<para>
NetBIOS runs over the following tranports: TCP/IP; NetBEUI and IPX/SPX.
Samba only uses NetBIOS over TCP/IP. For details on the TCP/IP NetBIOS
Session Service NetBIOS Datagram Service, and NetBIOS Names, see
rfc1001.txt and rfc1002.txt.
</para>
<para>
NetBEUI is a raw NetBIOS frame protocol implementation that allows NetBIOS
datagrams to be sent out over the 'wire' embedded within LLC frames.
NetBEUI is not required when using NetBIOS over TCP/IP protocols and it
is preferable NOT to install NetBEUI if it can be avoided.
</para>
<para>
IPX/SPX is also not required when using NetBIOS over TCP/IP, and it is
preferable NOT to install the IPX/SPX transport unless you are using Novell
servers. At the very least, it is recommended that you do not install
'NetBIOS over IPX/SPX'.
</para>
<para>
[When installing Windows 95, you will find that NetBEUI and IPX/SPX are
installed as the default protocols. This is because they are the simplest
to manage: no Windows 95 user-configuration is required].
</para>
<para>
NetBIOS applications (such as samba) offer their services (for example,
SMB file and print sharing) on a NetBIOS name. They must claim this name
on the network before doing so. The NetBIOS session service will then
accept connections on the application's behalf (on the NetBIOS name
claimed by the application). A NetBIOS session between the application
and the client can then commence.
</para>
<para>
NetBIOS names consist of 15 characters plus a 'type' character. This is
similar, in concept, to an IP address and a TCP port number, respectively.
A NetBIOS-aware application on a host will offer different services under
different NetBIOS name types, just as a host will offer different TCP/IP
services on different port numbers.
</para>
<para>
NetBIOS names must be claimed on a network, and must be defended. The use
of NetBIOS names is most suitable on a single subnet; a Local Area Network
or a Wide Area Network.
</para>
<para>
NetBIOS names are either UNIQUE or GROUP. Only one application can claim a
UNIQUE NetBIOS name on a network.
</para>
<para>
There are two kinds of NetBIOS Name resolution: Broadcast and Point-to-Point.
</para>
</sect1>
<sect1>
<title>BROADCAST NetBIOS</title>
<para>
Clients can claim names, and therefore offer services on successfully claimed
names, on their broadcast-isolated subnet. One way to get NetBIOS services
(such as browsing: see ftp.microsoft.com/drg/developr/CIFS/browdiff.txt; and
SMB file/print sharing: see cifs4.txt) working on a LAN or WAN is to make
your routers forward all broadcast packets from TCP/IP ports 137, 138 and 139.
</para>
<para>
This, however, is not recommended. If you have a large LAN or WAN, you will
find that some of your hosts spend 95 percent of their time dealing with
broadcast traffic. [If you have IPX/SPX on your LAN or WAN, you will find
that this is already happening: a packet analyzer will show, roughly
every twelve minutes, great swathes of broadcast traffic!].
</para>
</sect1>
<sect1>
<title>NBNS NetBIOS</title>
<para>
rfc1001.txt describes, amongst other things, the implementation and use
of, a 'NetBIOS Name Service'. NT/AS offers 'Windows Internet Name Service'
which is fully rfc1001/2 compliant, but has had to take specific action
with certain NetBIOS names in order to make it useful. (for example, it
deals with the registration of <1c> <1d> <1e> names all in different ways.
I recommend the reading of the Microsoft WINS Server Help files for full
details).
</para>
<para>
The use of a WINS server cuts down on broadcast network traffic for
NetBIOS name resolution. It has the effect of pulling all the broadcast
isolated subnets together into a single NetBIOS scope, across your LAN
or WAN, while avoiding the use of TCP/IP broadcast packets.
</para>
<para>
When you have a WINS server on your LAN, WINS clients will be able to
contact the WINS server to resolve NetBIOS names. Note that only those
WINS clients that have registered with the same WINS server will be
visible. The WINS server _can_ have static NetBIOS entries added to its
database (usually for security reasons you might want to consider putting
your domain controllers or other important servers as static entries,
but you should not rely on this as your sole means of security), but for
the most part, NetBIOS names are registered dynamically.
</para>
<para>
This provides some confusion for lots of people, and is worth mentioning
here: a Browse Server is NOT a WINS Server, even if these services are
implemented in the same application. A Browse Server _needs_ a WINS server
because a Browse Server is a WINS client, which is _not_ the same thing].
</para>
<para>
Clients can claim names, and therefore offer services on successfully claimed
names, on their broadcast-isolated subnet. One way to get NetBIOS services
(such as browsing: see ftp.microsoft.com/drg/developr/CIFS/browdiff.txt; and
SMB file/print sharing: see cifs6.txt) working on a LAN or WAN is to make
your routers forward all broadcast packets from TCP/IP ports 137, 138 and 139.
You will find, however, if you do this on a large LAN or a WAN, that your
network is completely swamped by NetBIOS and browsing packets, which is why
WINS was developed to minimise the necessity of broadcast traffic.
</para>
<para>
WINS Clients therefore claim names from the WINS server. If the WINS
server allows them to register a name, the client's NetBIOS session service
can then offer services on this name. Other WINS clients will then
contact the WINS server to resolve a NetBIOS name.
</para>
</sect1>
</chapter>

View File

@ -0,0 +1,129 @@
<chapter id="tracing">
<chapterinfo>
<author>
<firstname>Andrew</firstname><surname>Tridgell</surname>
<affiliation>
<orgname>Samba Team</orgname>
</affiliation>
</author>
</chapterinfo>
<title>Tracing samba system calls</title>
<para>
This file describes how to do a system call trace on Samba to work out
what its doing wrong. This is not for the faint of heart, but if you
are reading this then you are probably desperate.
</para>
<para>
Actually its not as bad as the the above makes it sound, just don't
expect the output to be very pretty :-)
</para>
<para>
Ok, down to business. One of the big advantages of unix systems is
that they nearly all come with a system trace utility that allows you
to monitor all system calls that a program is making. This is
extremely using for debugging and also helps when trying to work out
why something is slower than you expect. You can use system tracing
without any special compilation options.
</para>
<para>
The system trace utility is called different things on different
systems. On Linux systems its called strace. Under SunOS 4 its called
trace. Under SVR4 style systems (including solaris) its called
truss. Under many BSD systems its called ktrace.
</para>
<para>
The first thing you should do is read the man page for your native
system call tracer. In the discussion below I'll assume its called
strace as strace is the only portable system tracer (its available for
free for many unix types) and its also got some of the nicest
features.
</para>
<para>
Next, try using strace on some simple commands. For example, <command>strace
ls</command> or <command>strace echo hello</command>.
</para>
<para>
You'll notice that it produces a LOT of output. It is showing you the
arguments to every system call that the program makes and the
result. Very little happens in a program without a system call so you
get lots of output. You'll also find that it produces a lot of
"preamble" stuff showing the loading of shared libraries etc. Ignore
this (unless its going wrong!)
</para>
<para>
For example, the only line that really matters in the <command>strace echo
hello</command> output is:
</para>
<para><programlisting>
write(1, "hello\n", 6) = 6
</programlisting></para>
<para>all the rest is just setting up to run the program.</para>
<para>
Ok, now you're familiar with strace. To use it on Samba you need to
strace the running smbd daemon. The way I tend ot use it is to first
login from my Windows PC to the Samba server, then use smbstatus to
find which process ID that client is attached to, then as root I do
<command>strace -p PID</command> to attach to that process. I normally redirect the
stderr output from this command to a file for later perusal. For
example, if I'm using a csh style shell:
</para>
<para><command>strace -f -p 3872 >& strace.out</command></para>
<para>or with a sh style shell:</para>
<para><command>strace -f -p 3872 > strace.out 2>&1</command></para>
<para>
Note the "-f" option. This is only available on some systems, and
allows you to trace not just the current process, but any children it
forks. This is great for finding printing problems caused by the
"print command" being wrong.
</para>
<para>
Once you are attached you then can do whatever it is on the client
that is causing problems and you will capture all the system calls
that smbd makes.
</para>
<para>
So how do you interpret the results? Generally I search through the
output for strings that I know will appear when the problem
happens. For example, if I am having touble with permissions on a file
I would search for that files name in the strace output and look at
the surrounding lines. Another trick is to match up file descriptor
numbers and "follow" what happens to an open file until it is closed.
</para>
<para>
Beyond this you will have to use your initiative. To give you an idea
of what you are looking for here is a piece of strace output that
shows that <filename>/dev/null</filename> is not world writeable, which
causes printing to fail with Samba:
</para>
<para><programlisting>
[pid 28268] open("/dev/null", O_RDWR) = -1 EACCES (Permission denied)
[pid 28268] open("/dev/null", O_WRONLY) = -1 EACCES (Permission denied)
</programlisting></para>
<para>
The process is trying to first open <filename>/dev/null</filename> read-write
then read-only. Both fail. This means <filename>/dev/null</filename> has
incorrect permissions.
</para>
</chapter>

View File

@ -0,0 +1,184 @@
<chapter id="architecture">
<chapterinfo>
<author>
<firstname>Dan</firstname><surname>Shearer</surname>
</author>
<pubdate> November 1997</pubdate>
</chapterinfo>
<title>Samba Architecture</title>
<sect1>
<title>Introduction</title>
<para>
This document gives a general overview of how Samba works
internally. The Samba Team has tried to come up with a model which is
the best possible compromise between elegance, portability, security
and the constraints imposed by the very messy SMB and CIFS
protocol.
</para>
<para>
It also tries to answer some of the frequently asked questions such as:
</para>
<orderedlist>
<listitem><para>
Is Samba secure when running on Unix? The xyz platform?
What about the root priveliges issue?
</para></listitem>
<listitem><para>Pros and cons of multithreading in various parts of Samba</para></listitem>
<listitem><para>Why not have a separate process for name resolution, WINS, and browsing?</para></listitem>
</orderedlist>
</sect1>
<sect1>
<title>Multithreading and Samba</title>
<para>
People sometimes tout threads as a uniformly good thing. They are very
nice in their place but are quite inappropriate for smbd. nmbd is
another matter, and multi-threading it would be very nice.
</para>
<para>
The short version is that smbd is not multithreaded, and alternative
servers that take this approach under Unix (such as Syntax, at the
time of writing) suffer tremendous performance penalties and are less
robust. nmbd is not threaded either, but this is because it is not
possible to do it while keeping code consistent and portable across 35
or more platforms. (This drawback also applies to threading smbd.)
</para>
<para>
The longer versions is that there are very good reasons for not making
smbd multi-threaded. Multi-threading would actually make Samba much
slower, less scalable, less portable and much less robust. The fact
that we use a separate process for each connection is one of Samba's
biggest advantages.
</para>
</sect1>
<sect1>
<title>Threading smbd</title>
<para>
A few problems that would arise from a threaded smbd are:
</para>
<orderedlist>
<listitem><para>
It's not only to create threads instead of processes, but you
must care about all variables if they have to be thread specific
(currently they would be global).
</para></listitem>
<listitem><para>
if one thread dies (eg. a seg fault) then all threads die. We can
immediately throw robustness out the window.
</para></listitem>
<listitem><para>
many of the system calls we make are blocking. Non-blocking
equivalents of many calls are either not available or are awkward (and
slow) to use. So while we block in one thread all clients are
waiting. Imagine if one share is a slow NFS filesystem and the others
are fast, we will end up slowing all clients to the speed of NFS.
</para></listitem>
<listitem><para>
you can't run as a different uid in different threads. This means
we would have to switch uid/gid on _every_ SMB packet. It would be
horrendously slow.
</para></listitem>
<listitem><para>
the per process file descriptor limit would mean that we could only
support a limited number of clients.
</para></listitem>
<listitem><para>
we couldn't use the system locking calls as the locking context of
fcntl() is a process, not a thread.
</para></listitem>
</orderedlist>
</sect1>
<sect1>
<title>Threading nmbd</title>
<para>
This would be ideal, but gets sunk by portability requirements.
</para>
<para>
Andrew tried to write a test threads library for nmbd that used only
ansi-C constructs (using setjmp and longjmp). Unfortunately some OSes
defeat this by restricting longjmp to calling addresses that are
shallower than the current address on the stack (apparently AIX does
this). This makes a truly portable threads library impossible. So to
support all our current platforms we would have to code nmbd both with
and without threads, and as the real aim of threads is to make the
code clearer we would not have gained anything. (it is a myth that
threads make things faster. threading is like recursion, it can make
things clear but the same thing can always be done faster by some
other method)
</para>
<para>
Chris tried to spec out a general design that would abstract threading
vs separate processes (vs other methods?) and make them accessible
through some general API. This doesn't work because of the data
sharing requirements of the protocol (packets in the future depending
on packets now, etc.) At least, the code would work but would be very
clumsy, and besides the fork() type model would never work on Unix. (Is there an OS that it would work on, for nmbd?)
</para>
<para>
A fork() is cheap, but not nearly cheap enough to do on every UDP
packet that arrives. Having a pool of processes is possible but is
nasty to program cleanly due to the enormous amount of shared data (in
complex structures) between the processes. We can't rely on each
platform having a shared memory system.
</para>
</sect1>
<sect1>
<title>nbmd Design</title>
<para>
Originally Andrew used recursion to simulate a multi-threaded
environment, which use the stack enormously and made for really
confusing debugging sessions. Luke Leighton rewrote it to use a
queuing system that keeps state information on each packet. The
first version used a single structure which was used by all the
pending states. As the initialisation of this structure was
done by adding arguments, as the functionality developed, it got
pretty messy. So, it was replaced with a higher-order function
and a pointer to a user-defined memory block. This suddenly
made things much simpler: large numbers of functions could be
made static, and modularised. This is the same principle as used
in NT's kernel, and achieves the same effect as threads, but in
a single process.
</para>
<para>
Then Jeremy rewrote nmbd. The packet data in nmbd isn't what's on the
wire. It's a nice format that is very amenable to processing but still
keeps the idea of a distinct packet. See "struct packet_struct" in
nameserv.h. It has all the detail but none of the on-the-wire
mess. This makes it ideal for using in disk or memory-based databases
for browsing and WINS support.
</para>
</sect1>
</chapter>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,321 @@
<chapter id="debug">
<chapterinfo>
<author>
<firstname>Chris</firstname><surname>Hertel</surname>
</author>
<pubdate>July 1998</pubdate>
</chapterinfo>
<title>The samba DEBUG system</title>
<sect1>
<title>New Output Syntax</title>
<para>
The syntax of a debugging log file is represented as:
</para>
<para><programlisting>
&gt;debugfile&lt; :== { &gt;debugmsg&lt; }
&gt;debugmsg&lt; :== &gt;debughdr&lt; '\n' &gt;debugtext&lt;
&gt;debughdr&lt; :== '[' TIME ',' LEVEL ']' FILE ':' [FUNCTION] '(' LINE ')'
&gt;debugtext&lt; :== { &gt;debugline&lt; }
&gt;debugline&lt; :== TEXT '\n'
</programlisting></para>
<para>
TEXT is a string of characters excluding the newline character.
</para>
<para>
LEVEL is the DEBUG level of the message (an integer in the range
0..10).
</para>
<para>
TIME is a timestamp.
</para>
<para>
FILE is the name of the file from which the debug message was
generated.
</para>
<para>
FUNCTION is the function from which the debug message was generated.
</para>
<para>
LINE is the line number of the debug statement that generated the
message.
</para>
<para>Basically, what that all means is:</para>
<orderedlist>
<listitem><para>
A debugging log file is made up of debug messages.
</para></listitem>
<listitem><para>
Each debug message is made up of a header and text. The header is
separated from the text by a newline.
</para></listitem>
<listitem><para>
The header begins with the timestamp and debug level of the
message enclosed in brackets. The filename, function, and line
number at which the message was generated follow. The filename is
terminated by a colon, and the function name is terminated by the
parenthesis which contain the line number. Depending upon the
compiler, the function name may be missing (it is generated by the
__FUNCTION__ macro, which is not universally implemented, dangit).
</para></listitem>
<listitem><para>
The message text is made up of zero or more lines, each terminated
by a newline.
</para></listitem>
</orderedlist>
<para>Here's some example output:</para>
<para><programlisting>
[1998/08/03 12:55:25, 1] nmbd.c:(659)
Netbios nameserver version 1.9.19-prealpha started.
Copyright Andrew Tridgell 1994-1997
[1998/08/03 12:55:25, 3] loadparm.c:(763)
Initializing global parameters
</programlisting></para>
<para>
Note that in the above example the function names are not listed on
the header line. That's because the example above was generated on an
SGI Indy, and the SGI compiler doesn't support the __FUNCTION__ macro.
</para>
</sect1>
<sect1>
<title>The DEBUG() Macro</title>
<para>
Use of the DEBUG() macro is unchanged. DEBUG() takes two parameters.
The first is the message level, the second is the body of a function
call to the Debug1() function.
</para>
<para>That's confusing.</para>
<para>Here's an example which may help a bit. If you would write</para>
<para><programlisting>
printf( "This is a %s message.\n", "debug" );
</programlisting></para>
<para>
to send the output to stdout, then you would write
</para>
<para><programlisting>
DEBUG( 0, ( "This is a %s message.\n", "debug" ) );
</programlisting></para>
<para>
to send the output to the debug file. All of the normal printf()
formatting escapes work.
</para>
<para>
Note that in the above example the DEBUG message level is set to 0.
Messages at level 0 always print. Basically, if the message level is
less than or equal to the global value DEBUGLEVEL, then the DEBUG
statement is processed.
</para>
<para>
The output of the above example would be something like:
</para>
<para><programlisting>
[1998/07/30 16:00:51, 0] file.c:function(128)
This is a debug message.
</programlisting></para>
<para>
Each call to DEBUG() creates a new header *unless* the output produced
by the previous call to DEBUG() did not end with a '\n'. Output to the
debug file is passed through a formatting buffer which is flushed
every time a newline is encountered. If the buffer is not empty when
DEBUG() is called, the new input is simply appended.
</para>
<para>
...but that's really just a Kludge. It was put in place because
DEBUG() has been used to write partial lines. Here's a simple (dumb)
example of the kind of thing I'm talking about:
</para>
<para><programlisting>
DEBUG( 0, ("The test returned " ) );
if( test() )
DEBUG(0, ("True") );
else
DEBUG(0, ("False") );
DEBUG(0, (".\n") );
</programlisting></para>
<para>
Without the format buffer, the output (assuming test() returned true)
would look like this:
</para>
<para><programlisting>
[1998/07/30 16:00:51, 0] file.c:function(256)
The test returned
[1998/07/30 16:00:51, 0] file.c:function(258)
True
[1998/07/30 16:00:51, 0] file.c:function(261)
.
</programlisting></para>
<para>Which isn't much use. The format buffer kludge fixes this problem.
</para>
</sect1>
<sect1>
<title>The DEBUGADD() Macro</title>
<para>
In addition to the kludgey solution to the broken line problem
described above, there is a clean solution. The DEBUGADD() macro never
generates a header. It will append new text to the current debug
message even if the format buffer is empty. The syntax of the
DEBUGADD() macro is the same as that of the DEBUG() macro.
</para>
<para><programlisting>
DEBUG( 0, ("This is the first line.\n" ) );
DEBUGADD( 0, ("This is the second line.\nThis is the third line.\n" ) );
</programlisting></para>
<para>Produces</para>
<para><programlisting>
[1998/07/30 16:00:51, 0] file.c:function(512)
This is the first line.
This is the second line.
This is the third line.
</programlisting></para>
</sect1>
<sect1>
<title>The DEBUGLVL() Macro</title>
<para>
One of the problems with the DEBUG() macro was that DEBUG() lines
tended to get a bit long. Consider this example from
nmbd_sendannounce.c:
</para>
<para><programlisting>
DEBUG(3,("send_local_master_announcement: type %x for name %s on subnet %s for workgroup %s\n",
type, global_myname, subrec->subnet_name, work->work_group));
</programlisting></para>
<para>
One solution to this is to break it down using DEBUG() and DEBUGADD(),
as follows:
</para>
<para><programlisting>
DEBUG( 3, ( "send_local_master_announcement: " ) );
DEBUGADD( 3, ( "type %x for name %s ", type, global_myname ) );
DEBUGADD( 3, ( "on subnet %s ", subrec->subnet_name ) );
DEBUGADD( 3, ( "for workgroup %s\n", work->work_group ) );
</programlisting></para>
<para>
A similar, but arguably nicer approach is to use the DEBUGLVL() macro.
This macro returns True if the message level is less than or equal to
the global DEBUGLEVEL value, so:
</para>
<para><programlisting>
if( DEBUGLVL( 3 ) )
{
dbgtext( "send_local_master_announcement: " );
dbgtext( "type %x for name %s ", type, global_myname );
dbgtext( "on subnet %s ", subrec->subnet_name );
dbgtext( "for workgroup %s\n", work->work_group );
}
</programlisting></para>
<para>(The dbgtext() function is explained below.)</para>
<para>There are a few advantages to this scheme:</para>
<orderedlist>
<listitem><para>
The test is performed only once.
</para></listitem>
<listitem><para>
You can allocate variables off of the stack that will only be used
within the DEBUGLVL() block.
</para></listitem>
<listitem><para>
Processing that is only relevant to debug output can be contained
within the DEBUGLVL() block.
</para></listitem>
</orderedlist>
</sect1>
<sect1>
<title>New Functions</title>
<sect2>
<title>dbgtext()</title>
<para>
This function prints debug message text to the debug file (and
possibly to syslog) via the format buffer. The function uses a
variable argument list just like printf() or Debug1(). The
input is printed into a buffer using the vslprintf() function,
and then passed to format_debug_text().
If you use DEBUGLVL() you will probably print the body of the
message using dbgtext().
</para>
</sect2>
<sect2>
<title>dbghdr()</title>
<para>
This is the function that writes a debug message header.
Headers are not processed via the format buffer. Also note that
if the format buffer is not empty, a call to dbghdr() will not
produce any output. See the comments in dbghdr() for more info.
</para>
<para>
It is not likely that this function will be called directly. It
is used by DEBUG() and DEBUGADD().
</para>
</sect2>
<sect2>
<title>format_debug_text()</title>
<para>
This is a static function in debug.c. It stores the output text
for the body of the message in a buffer until it encounters a
newline. When the newline character is found, the buffer is
written to the debug file via the Debug1() function, and the
buffer is reset. This allows us to add the indentation at the
beginning of each line of the message body, and also ensures
that the output is written a line at a time (which cleans up
syslog output).
</para>
</sect2>
</sect1>
</chapter>

View File

@ -0,0 +1,62 @@
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
<!ENTITY NetBIOS SYSTEM "NetBIOS.sgml">
<!ENTITY Architecture SYSTEM "architecture.sgml">
<!ENTITY debug SYSTEM "debug.sgml">
<!ENTITY internals SYSTEM "internals.sgml">
<!ENTITY parsing SYSTEM "parsing.sgml">
<!ENTITY unix-smb SYSTEM "unix-smb.sgml">
<!ENTITY CodingSuggestions SYSTEM "CodingSuggestions.sgml">
<!ENTITY Tracing SYSTEM "Tracing.sgml">
<!ENTITY cifsntdomain SYSTEM "cifsntdomain.sgml">
]>
<book id="Samba-Developer-Documentation">
<title>SAMBA Developers Guide</title>
<bookinfo>
<author>
<surname>SAMBA Team</surname>
</author>
<address><email>samba@samba.org</email></address>
</bookinfo>
<dedication>
<title>Abstract</title>
<para>
<emphasis>Last Update</emphasis> : Mon aug 26 12:41:19 CEST 2002
</para>
<para>
This book is a collection of documents that might be useful for
people developing samba or those interested in doing so.
It's nothing more than a collection of documents written by samba developers about
the internals of various parts of samba and the SMB protocol. It's still incomplete.
The most recent version of this document
can be found at <ulink url="http://devel.samba.org/">http://devel.samba.org/</ulink>.
Please send updates to <ulink
url="mailto:jelmer@samba.org">jelmer@samba.org</ulink>.
</para>
<para>
This documentation is distributed under the GNU General Public License (GPL)
version 2. A copy of the license is included with the Samba source
distribution. A copy can be found on-line at <ulink
url="http://www.fsf.org/licenses/gpl.txt">http://www.fsf.org/licenses/gpl.txt</ulink>
</para>
</dedication>
<!-- Chapters -->
&NetBIOS;
&Architecture;
&debug;
&CodingSuggestions;
&internals;
&parsing;
&unix-smb;
&Tracing;
&cifsntdomain;
</book>

View File

@ -0,0 +1,439 @@
<chapter id="internals">
<chapterinfo>
<author>
<firstname>David</firstname><surname>Chappell</surname>
<affiliation>
<address><email>David.Chappell@mail.trincoll.edu</email></address>
</affiliation>
</author>
<pubdate>8 May 1996</pubdate>
</chapterinfo>
<title>Samba Internals</title>
<sect1>
<title>Character Handling</title>
<para>
This section describes character set handling in Samba, as implemented in
Samba 3.0 and above
</para>
<para>
In the past Samba had very ad-hoc character set handling. Scattered
throughout the code were numerous calls which converted particular
strings to/from DOS codepages. The problem is that there was no way of
telling if a particular char* is in dos codepage or unix
codepage. This led to a nightmare of code that tried to cope with
particular cases without handlingt the general case.
</para>
<sect1>
<title>The new functions</title>
<para>
The new system works like this:
</para>
<orderedlist>
<listitem><para>
all char* strings inside Samba are "unix" strings. These are
multi-byte strings that are in the charset defined by the "unix
charset" option in smb.conf.
</para></listitem>
<listitem><para>
there is no single fixed character set for unix strings, but any
character set that is used does need the following properties:
</para>
<orderedlist>
<listitem><para>
must not contain NULLs except for termination
</para></listitem>
<listitem><para>
must be 7-bit compatible with C strings, so that a constant
string or character in C will be byte-for-byte identical to the
equivalent string in the chosen character set.
</para></listitem>
<listitem><para>
when you uppercase or lowercase a string it does not become
longer than the original string
</para></listitem>
<listitem><para>
must be able to correctly hold all characters that your client
will throw at it
</para></listitem>
</orderedlist>
<para>
For example, UTF-8 is fine, and most multi-byte asian character sets
are fine, but UCS2 could not be used for unix strings as they
contain nulls.
</para>
</listitem>
<listitem><para>
when you need to put a string into a buffer that will be sent on the
wire, or you need a string in a character set format that is
compatible with the clients character set then you need to use a
pull_ or push_ function. The pull_ functions pull a string from a
wire buffer into a (multi-byte) unix string. The push_ functions
push a string out to a wire buffer.
</para></listitem>
<listitem><para>
the two main pull_ and push_ functions you need to understand are
pull_string and push_string. These functions take a base pointer
that should point at the start of the SMB packet that the string is
in. The functions will check the flags field in this packet to
automatically determine if the packet is marked as a unicode packet,
and they will choose whether to use unicode for this string based on
that flag. You may also force this decision using the STR_UNICODE or
STR_ASCII flags. For use in smbd/ and libsmb/ there are wrapper
functions clistr_ and srvstr_ that call the pull_/push_ functions
with the appropriate first argument.
</para>
<para>
You may also call the pull_ascii/pull_ucs2 or push_ascii/push_ucs2
functions if you know that a particular string is ascii or
unicode. There are also a number of other convenience functions in
charcnv.c that call the pull_/push_ functions with particularly
common arguments, such as pull_ascii_pstring()
</para>
</listitem>
<listitem><para>
The biggest thing to remember is that internal (unix) strings in Samba
may now contain multi-byte characters. This means you cannot assume
that characters are always 1 byte long. Often this means that you will
have to convert strings to ucs2 and back again in order to do some
(seemingly) simple task. For examples of how to do this see functions
like strchr_m(). I know this is very slow, and we will eventually
speed it up but right now we want this stuff correct not fast.
</para></listitem>
<listitem><para>
all lp_ functions now return unix strings. The magic "DOS" flag on
parameters is gone.
</para></listitem>
<listitem><para>
all vfs functions take unix strings. Don't convert when passing to them
</para></listitem>
</orderedlist>
</sect1>
<sect1>
<title>Macros in byteorder.h</title>
<para>
This section describes the macros defined in byteorder.h. These macros
are used extensively in the Samba code.
</para>
<sect2>
<title>CVAL(buf,pos)</title>
<para>
returns the byte at offset pos within buffer buf as an unsigned character.
</para>
</sect2>
<sect2>
<title>PVAL(buf,pos)</title>
<para>returns the value of CVAL(buf,pos) cast to type unsigned integer.</para>
</sect2>
<sect2>
<title>SCVAL(buf,pos,val)</title>
<para>sets the byte at offset pos within buffer buf to value val.</para>
</sect2>
<sect2>
<title>SVAL(buf,pos)</title>
<para>
returns the value of the unsigned short (16 bit) little-endian integer at
offset pos within buffer buf. An integer of this type is sometimes
refered to as "USHORT".
</para>
</sect2>
<sect2>
<title>IVAL(buf,pos)</title>
<para>returns the value of the unsigned 32 bit little-endian integer at offset
pos within buffer buf.</para>
</sect2>
<sect2>
<title>SVALS(buf,pos)</title>
<para>returns the value of the signed short (16 bit) little-endian integer at
offset pos within buffer buf.</para>
</sect2>
<sect2>
<title>IVALS(buf,pos)</title>
<para>returns the value of the signed 32 bit little-endian integer at offset pos
within buffer buf.</para>
</sect2>
<sect2>
<title>SSVAL(buf,pos,val)</title>
<para>sets the unsigned short (16 bit) little-endian integer at offset pos within
buffer buf to value val.</para>
</sect2>
<sect2>
<title>SIVAL(buf,pos,val)</title>
<para>sets the unsigned 32 bit little-endian integer at offset pos within buffer
buf to the value val.</para>
</sect2>
<sect2>
<title>SSVALS(buf,pos,val)</title>
<para>sets the short (16 bit) signed little-endian integer at offset pos within
buffer buf to the value val.</para>
</sect2>
<sect2>
<title>SIVALS(buf,pos,val)</title>
<para>sets the signed 32 bit little-endian integer at offset pos withing buffer
buf to the value val.</para>
</sect2>
<sect2>
<title>RSVAL(buf,pos)</title>
<para>returns the value of the unsigned short (16 bit) big-endian integer at
offset pos within buffer buf.</para>
</sect2>
<sect2>
<title>RIVAL(buf,pos)</title>
<para>returns the value of the unsigned 32 bit big-endian integer at offset
pos within buffer buf.</para>
</sect2>
<sect2>
<title>RSSVAL(buf,pos,val)</title>
<para>sets the value of the unsigned short (16 bit) big-endian integer at
offset pos within buffer buf to value val.
refered to as "USHORT".</para>
</sect2>
<sect2>
<title>RSIVAL(buf,pos,val)</title>
<para>sets the value of the unsigned 32 bit big-endian integer at offset
pos within buffer buf to value val.</para>
</sect2>
</sect1>
<sect1>
<title>LAN Manager Samba API</title>
<para>
This section describes the functions need to make a LAN Manager RPC call.
This information had been obtained by examining the Samba code and the LAN
Manager 2.0 API documentation. It should not be considered entirely
reliable.
</para>
<para>
<programlisting>
call_api(int prcnt, int drcnt, int mprcnt, int mdrcnt,
char *param, char *data, char **rparam, char **rdata);
</programlisting>
</para>
<para>
This function is defined in client.c. It uses an SMB transaction to call a
remote api.
</para>
<sect2>
<title>Parameters</title>
<para>The parameters are as follows:</para>
<orderedlist>
<listitem><para>
prcnt: the number of bytes of parameters begin sent.
</para></listitem>
<listitem><para>
drcnt: the number of bytes of data begin sent.
</para></listitem>
<listitem><para>
mprcnt: the maximum number of bytes of parameters which should be returned
</para></listitem>
<listitem><para>
mdrcnt: the maximum number of bytes of data which should be returned
</para></listitem>
<listitem><para>
param: a pointer to the parameters to be sent.
</para></listitem>
<listitem><para>
data: a pointer to the data to be sent.
</para></listitem>
<listitem><para>
rparam: a pointer to a pointer which will be set to point to the returned
paramters. The caller of call_api() must deallocate this memory.
</para></listitem>
<listitem><para>
rdata: a pointer to a pointer which will be set to point to the returned
data. The caller of call_api() must deallocate this memory.
</para></listitem>
</orderedlist>
<para>
These are the parameters which you ought to send, in the order of their
appearance in the parameter block:
</para>
<orderedlist>
<listitem><para>
An unsigned 16 bit integer API number. You should set this value with
SSVAL(). I do not know where these numbers are described.
</para></listitem>
<listitem><para>
An ASCIIZ string describing the parameters to the API function as defined
in the LAN Manager documentation. The first parameter, which is the server
name, is ommited. This string is based uppon the API function as described
in the manual, not the data which is actually passed.
</para></listitem>
<listitem><para>
An ASCIIZ string describing the data structure which ought to be returned.
</para></listitem>
<listitem><para>
Any parameters which appear in the function call, as defined in the LAN
Manager API documentation, after the "Server" and up to and including the
"uLevel" parameters.
</para></listitem>
<listitem><para>
An unsigned 16 bit integer which gives the size in bytes of the buffer we
will use to receive the returned array of data structures. Presumably this
should be the same as mdrcnt. This value should be set with SSVAL().
</para></listitem>
<listitem><para>
An ASCIIZ string describing substructures which should be returned. If no
substructures apply, this string is of zero length.
</para></listitem>
</orderedlist>
<para>
The code in client.c always calls call_api() with no data. It is unclear
when a non-zero length data buffer would be sent.
</para>
</sect2>
<sect2>
<title>Return value</title>
<para>
The returned parameters (pointed to by rparam), in their order of appearance
are:</para>
<orderedlist>
<listitem><para>
An unsigned 16 bit integer which contains the API function's return code.
This value should be read with SVAL().
</para></listitem>
<listitem><para>
An adjustment which tells the amount by which pointers in the returned
data should be adjusted. This value should be read with SVAL(). Basically,
the address of the start of the returned data buffer should have the returned
pointer value added to it and then have this value subtracted from it in
order to obtain the currect offset into the returned data buffer.
</para></listitem>
<listitem><para>
A count of the number of elements in the array of structures returned.
It is also possible that this may sometimes be the number of bytes returned.
</para></listitem>
</orderedlist>
<para>
When call_api() returns, rparam points to the returned parameters. The
first if these is the result code. It will be zero if the API call
suceeded. This value by be read with "SVAL(rparam,0)".
</para>
<para>
The second parameter may be read as "SVAL(rparam,2)". It is a 16 bit offset
which indicates what the base address of the returned data buffer was when
it was built on the server. It should be used to correct pointer before
use.
</para>
<para>
The returned data buffer contains the array of returned data structures.
Note that all pointers must be adjusted before use. The function
fix_char_ptr() in client.c can be used for this purpose.
</para>
<para>
The third parameter (which may be read as "SVAL(rparam,4)") has something to
do with indicating the amount of data returned or possibly the amount of
data which can be returned if enough buffer space is allowed.
</para>
</sect2>
</sect1>
<sect1>
<title>Code character table</title>
<para>
Certain data structures are described by means of ASCIIz strings containing
code characters. These are the code characters:
</para>
<orderedlist>
<listitem><para>
W a type byte little-endian unsigned integer
</para></listitem>
<listitem><para>
N a count of substructures which follow
</para></listitem>
<listitem><para>
D a four byte little-endian unsigned integer
</para></listitem>
<listitem><para>
B a byte (with optional count expressed as trailing ASCII digits)
</para></listitem>
<listitem><para>
z a four byte offset to a NULL terminated string
</para></listitem>
<listitem><para>
l a four byte offset to non-string user data
</para></listitem>
<listitem><para>
b an offset to data (with count expressed as trailing ASCII digits)
</para></listitem>
<listitem><para>
r pointer to returned data buffer???
</para></listitem>
<listitem><para>
L length in bytes of returned data buffer???
</para></listitem>
<listitem><para>
h number of bytes of information available???
</para></listitem>
</orderedlist>
</sect1>
</chapter>

View File

@ -0,0 +1,239 @@
<chapter id="parsing">
<chapterinfo>
<author>
<firstname>Chris</firstname><surname>Hertel</surname>
</author>
<pubdate>November 1997</pubdate>
</chapterinfo>
<title>The smb.conf file</title>
<sect1>
<title>Lexical Analysis</title>
<para>
Basically, the file is processed on a line by line basis. There are
four types of lines that are recognized by the lexical analyzer
(params.c):
</para>
<orderedlist>
<listitem><para>
Blank lines - Lines containing only whitespace.
</para></listitem>
<listitem><para>
Comment lines - Lines beginning with either a semi-colon or a
pound sign (';' or '#').
</para></listitem>
<listitem><para>
Section header lines - Lines beginning with an open square bracket ('[').
</para></listitem>
<listitem><para>
Parameter lines - Lines beginning with any other character.
(The default line type.)
</para></listitem>
</orderedlist>
<para>
The first two are handled exclusively by the lexical analyzer, which
ignores them. The latter two line types are scanned for
</para>
<orderedlist>
<listitem><para>
- Section names
</para></listitem>
<listitem><para>
- Parameter names
</para></listitem>
<listitem><para>
- Parameter values
</para></listitem>
</orderedlist>
<para>
These are the only tokens passed to the parameter loader
(loadparm.c). Parameter names and values are divided from one
another by an equal sign: '='.
</para>
<sect2>
<title>Handling of Whitespace</title>
<para>
Whitespace is defined as all characters recognized by the isspace()
function (see ctype(3C)) except for the newline character ('\n')
The newline is excluded because it identifies the end of the line.
</para>
<orderedlist>
<listitem><para>
The lexical analyzer scans past white space at the beginning of a line.
</para></listitem>
<listitem><para>
Section and parameter names may contain internal white space. All
whitespace within a name is compressed to a single space character.
</para></listitem>
<listitem><para>
Internal whitespace within a parameter value is kept verbatim with
the exception of carriage return characters ('\r'), all of which
are removed.
</para></listitem>
<listitem><para>
Leading and trailing whitespace is removed from names and values.
</para></listitem>
</orderedlist>
</sect2>
<sect2>
<title>Handling of Line Continuation</title>
<para>
Long section header and parameter lines may be extended across
multiple lines by use of the backslash character ('\\'). Line
continuation is ignored for blank and comment lines.
</para>
<para>
If the last (non-whitespace) character within a section header or on
a parameter line is a backslash, then the next line will be
(logically) concatonated with the current line by the lexical
analyzer. For example:
</para>
<para><programlisting>
param name = parameter value string \
with line continuation.
</programlisting></para>
<para>Would be read as</para>
<para><programlisting>
param name = parameter value string with line continuation.
</programlisting></para>
<para>
Note that there are five spaces following the word 'string',
representing the one space between 'string' and '\\' in the top
line, plus the four preceeding the word 'with' in the second line.
(Yes, I'm counting the indentation.)
</para>
<para>
Line continuation characters are ignored on blank lines and at the end
of comments. They are *only* recognized within section and parameter
lines.
</para>
</sect2>
<sect2>
<title>Line Continuation Quirks</title>
<para>Note the following example:</para>
<para><programlisting>
param name = parameter value string \
\
with line continuation.
</programlisting></para>
<para>
The middle line is *not* parsed as a blank line because it is first
concatonated with the top line. The result is
</para>
<para><programlisting>
param name = parameter value string with line continuation.
</programlisting></para>
<para>The same is true for comment lines.</para>
<para><programlisting>
param name = parameter value string \
; comment \
with a comment.
</programlisting></para>
<para>This becomes:</para>
<para><programlisting>
param name = parameter value string ; comment with a comment.
</programlisting></para>
<para>
On a section header line, the closing bracket (']') is considered a
terminating character, and the rest of the line is ignored. The lines
</para>
<para><programlisting>
[ section name ] garbage \
param name = value
</programlisting></para>
<para>are read as</para>
<para><programlisting>
[section name]
param name = value
</programlisting></para>
</sect2>
</sect1>
<sect1>
<title>Syntax</title>
<para>The syntax of the smb.conf file is as follows:</para>
<para><programlisting>
&lt;file&gt; :== { &lt;section&gt; } EOF
&lt;section&gt; :== &lt;section header&gt; { &lt;parameter line&gt; }
&lt;section header&gt; :== '[' NAME ']'
&lt;parameter line&gt; :== NAME '=' VALUE NL
</programlisting><para>
<para>Basically, this means that</para>
<orderedlist>
<listitem><para>
a file is made up of zero or more sections, and is terminated by
an EOF (we knew that).
</para></listitem>
<listitem><para>
A section is made up of a section header followed by zero or more
parameter lines.
</para></listitem>
<listitem><para>
A section header is identified by an opening bracket and
terminated by the closing bracket. The enclosed NAME identifies
the section.
</para></listitem>
<listitem><para>
A parameter line is divided into a NAME and a VALUE. The *first*
equal sign on the line separates the NAME from the VALUE. The
VALUE is terminated by a newline character (NL = '\n').
</para></listitem>
</orderedlist>
<sect2>
<title>About params.c</title>
<para>
The parsing of the config file is a bit unusual if you are used to
lex, yacc, bison, etc. Both lexical analysis (scanning) and parsing
are performed by params.c. Values are loaded via callbacks to
loadparm.c.
</para>
</sect2>
</sect1>
</chapter>

View File

@ -0,0 +1,311 @@
<chapter id="unix-smb">
<chapterinfo>
<author>
<firstname>Andrew</firstname><surname>Tridgell</surname>
</author>
<pubdate>April 1995</pubdate>
</chapterinfo>
<title>NetBIOS in a Unix World</title>
<sect1>
<title>Introduction</title>
<para>
This is a short document that describes some of the issues that
confront a SMB implementation on unix, and how Samba copes with
them. They may help people who are looking at unix<->PC
interoperability.
</para>
<para>
It was written to help out a person who was writing a paper on unix to
PC connectivity.
</para>
</sect1>
<sect1>
<title>Usernames</title>
<para>
The SMB protocol has only a loose username concept. Early SMB
protocols (such as CORE and COREPLUS) have no username concept at
all. Even in later protocols clients often attempt operations
(particularly printer operations) without first validating a username
on the server.
</para>
<para>
Unix security is based around username/password pairs. A unix box
should not allow clients to do any substantive operation without some
sort of validation.
</para>
<para>
The problem mostly manifests itself when the unix server is in "share
level" security mode. This is the default mode as the alternative
"user level" security mode usually forces a client to connect to the
server as the same user for each connected share, which is
inconvenient in many sites.
</para>
<para>
In "share level" security the client normally gives a username in the
"session setup" protocol, but does not supply an accompanying
password. The client then connects to resources using the "tree
connect" protocol, and supplies a password. The problem is that the
user on the PC types the username and the password in different
contexts, unaware that they need to go together to give access to the
server. The username is normally the one the user typed in when they
"logged onto" the PC (this assumes Windows for Workgroups). The
password is the one they chose when connecting to the disk or printer.
</para>
<para>
The user often chooses a totally different username for their login as
for the drive connection. Often they also want to access different
drives as different usernames. The unix server needs some way of
divining the correct username to combine with each password.
</para>
<para>
Samba tries to avoid this problem using several methods. These succeed
in the vast majority of cases. The methods include username maps, the
service%user syntax, the saving of session setup usernames for later
validation and the derivation of the username from the service name
(either directly or via the user= option).
</para>
</sect1>
<sect1>
<title>File Ownership</title>
<para>
The commonly used SMB protocols have no way of saying "you can't do
that because you don't own the file". They have, in fact, no concept
of file ownership at all.
</para>
<para>
This brings up all sorts of interesting problems. For example, when
you copy a file to a unix drive, and the file is world writeable but
owned by another user the file will transfer correctly but will
receive the wrong date. This is because the utime() call under unix
only succeeds for the owner of the file, or root, even if the file is
world writeable. For security reasons Samba does all file operations
as the validated user, not root, so the utime() fails. This can stuff
up shared development diectories as programs like "make" will not get
file time comparisons right.
</para>
<para>
There are several possible solutions to this problem, including
username mapping, and forcing a specific username for particular
shares.
</para>
</sect1>
<sect1>
<title>Passwords</title>
<para>
Many SMB clients uppercase passwords before sending them. I have no
idea why they do this. Interestingly WfWg uppercases the password only
if the server is running a protocol greater than COREPLUS, so
obviously it isn't just the data entry routines that are to blame.
</para>
<para>
Unix passwords are case sensitive. So if users use mixed case
passwords they are in trouble.
</para>
<para>
Samba can try to cope with this by either using the "password level"
option which causes Samba to try the offered password with up to the
specified number of case changes, or by using the "password server"
option which allows Samba to do its validation via another machine
(typically a WinNT server).
</para>
<para>
Samba supports the password encryption method used by SMB
clients. Note that the use of password encryption in Microsoft
networking leads to password hashes that are "plain text equivalent".
This means that it is *VERY* important to ensure that the Samba
smbpasswd file containing these password hashes is only readable
by the root user. See the documentation ENCRYPTION.txt for more
details.
</para>
</sect1>
<sect1>
<title>Locking</title>
<para>
The locking calls available under a DOS/Windows environment are much
richer than those available in unix. This means a unix server (like
Samba) choosing to use the standard fcntl() based unix locking calls
to implement SMB locking has to improvise a bit.
</para>
<para>
One major problem is that dos locks can be in a 32 bit (unsigned)
range. Unix locking calls are 32 bits, but are signed, giving only a 31
bit range. Unfortunately OLE2 clients use the top bit to select a
locking range used for OLE semaphores.
</para>
<para>
To work around this problem Samba compresses the 32 bit range into 31
bits by appropriate bit shifting. This seems to work but is not
ideal. In a future version a separate SMB lockd may be added to cope
with the problem.
</para>
<para>
It also doesn't help that many unix lockd daemons are very buggy and
crash at the slightest provocation. They normally go mostly unused in
a unix environment because few unix programs use byte range
locking. The stress of huge numbers of lock requests from dos/windows
clients can kill the daemon on some systems.
</para>
<para>
The second major problem is the "opportunistic locking" requested by
some clients. If a client requests opportunistic locking then it is
asking the server to notify it if anyone else tries to do something on
the same file, at which time the client will say if it is willing to
give up its lock. Unix has no simple way of implementing
opportunistic locking, and currently Samba has no support for it.
</para>
</sect1>
<sect1>
<title>Deny Modes</title>
<para>
When a SMB client opens a file it asks for a particular "deny mode" to
be placed on the file. These modes (DENY_NONE, DENY_READ, DENY_WRITE,
DENY_ALL, DENY_FCB and DENY_DOS) specify what actions should be
allowed by anyone else who tries to use the file at the same time. If
DENY_READ is placed on the file, for example, then any attempt to open
the file for reading should fail.
</para>
<para>
Unix has no equivalent notion. To implement this Samba uses either lock
files based on the files inode and placed in a separate lock
directory or a shared memory implementation. The lock file method
is clumsy and consumes processing and file resources,
the shared memory implementation is vastly prefered and is turned on
by default for those systems that support it.
</para>
</sect1>
<sect1>
<title>Trapdoor UIDs</title>
<para>
A SMB session can run with several uids on the one socket. This
happens when a user connects to two shares with different
usernames. To cope with this the unix server needs to switch uids
within the one process. On some unixes (such as SCO) this is not
possible. This means that on those unixes the client is restricted to
a single uid.
</para>
<para>
Note that you can also get the "trapdoor uid" message for other
reasons. Please see the FAQ for details.
</para>
</sect1>
<sect1>
<title>Port numbers</title>
<para>
There is a convention that clients on sockets use high "unprivilaged"
port numbers (>1000) and connect to servers on low "privilaged" port
numbers. This is enforced in Unix as non-root users can't open a
socket for listening on port numbers less than 1000.
</para>
<para>
Most PC based SMB clients (such as WfWg and WinNT) don't follow this
convention completely. The main culprit is the netbios nameserving on
udp port 137. Name query requests come from a source port of 137. This
is a problem when you combine it with the common firewalling technique
of not allowing incoming packets on low port numbers. This means that
these clients can't query a netbios nameserver on the other side of a
low port based firewall.
</para>
<para>
The problem is more severe with netbios node status queries. I've
found that WfWg, Win95 and WinNT3.5 all respond to netbios node status
queries on port 137 no matter what the source port was in the
request. This works between machines that are both using port 137, but
it means it's not possible for a unix user to do a node status request
to any of these OSes unless they are running as root. The answer comes
back, but it goes to port 137 which the unix user can't listen
on. Interestingly WinNT3.1 got this right - it sends node status
responses back to the source port in the request.
</para>
</sect1>
<sect1>
<title>Protocol Complexity</title>
<para>
There are many "protocol levels" in the SMB protocol. It seems that
each time new functionality was added to a Microsoft operating system,
they added the equivalent functions in a new protocol level of the SMB
protocol to "externalise" the new capabilities.
</para>
<para>
This means the protocol is very "rich", offering many ways of doing
each file operation. This means SMB servers need to be complex and
large. It also means it is very difficult to make them bug free. It is
not just Samba that suffers from this problem, other servers such as
WinNT don't support every variation of every call and it has almost
certainly been a headache for MS developers to support the myriad of
SMB calls that are available.
</para>
<para>
There are about 65 "top level" operations in the SMB protocol (things
like SMBread and SMBwrite). Some of these include hundreds of
sub-functions (SMBtrans has at least 120 sub-functions, like
DosPrintQAdd and NetSessionEnum). All of them take several options
that can change the way they work. Many take dozens of possible
"information levels" that change the structures that need to be
returned. Samba supports all but 2 of the "top level" functions. It
supports only 8 (so far) of the SMBtrans sub-functions. Even NT
doesn't support them all.
</para>
<para>
Samba currently supports up to the "NT LM 0.12" protocol, which is the
one preferred by Win95 and WinNT3.5. Luckily this protocol level has a
"capabilities" field which specifies which super-duper new-fangled
options the server suports. This helps to make the implementation of
this protocol level much easier.
</para>
<para>
There is also a problem with the SMB specications. SMB is a X/Open
spec, but the X/Open book is far from ideal, and fails to cover many
important issues, leaving much to the imagination. Microsoft recently
renamed the SMB protocol CIFS (Common Internet File System) and have
published new specifications. These are far superior to the old
X/Open documents but there are still undocumented calls and features.
This specification is actively being worked on by a CIFS developers
mailing list hosted by Microsft.
</para>
</sect1>
</chapter>

View File

@ -0,0 +1,159 @@
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
<refentry id="vfstest">
<refmeta>
<refentrytitle>vfstest</refentrytitle>
<manvolnum>1</manvolnum>
</refmeta>
<refnamediv>
<refname>vfstest</refname>
<refpurpose>tool for testing samba VFS modules </refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>vfstest</command>
<arg choice="opt">-d debuglevel</arg>
<arg choice="opt">-c &quot;command&quot;</arg>
<arg choice="opt">-l &quot;logfile&quot;</arg>
<arg choice="opt">-h</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>DESCRIPTION</title>
<para>This tool is part of the <ulink url="samba.7.html">
Samba</ulink> suite.</para>
<para><command>vfstest</command> is a small command line
utility that has the ability to test dso samba VFS modules. It gives the
user the ability to call the various VFS functions manually and
supports cascaded VFS modules.
</para>
</refsect1>
<refsect1>
<title>OPTIONS</title>
<variablelist>
<varlistentry>
<term>-c|--command=command</term>
<listitem><para>Execute the specified (colon-seperated) commands.
See below for the commands that are available.
</para> </listitem>
</varlistentry>
<varlistentry>
<term>-d|--debug=debuglevel</term>
<listitem><para>set the debuglevel. Debug level 0 is the lowest
and 100 being the highest. This should be set to 100 if you are
planning on submitting a bug report to the Samba team (see
<filename>BUGS.txt</filename>).
</para></listitem>
</varlistentry>
<varlistentry>
<term>-h|--help</term>
<listitem><para>Print a summary of command line options.
</para></listitem>
</varlistentry>
<varlistentry>
<term>-l|--logfile=logbasename</term>
<listitem><para>File name for log/debug files. The extension
<constant>'.client'</constant> will be appended. The log file is never removed
by the client.
</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>COMMANDS</title>
<para><emphasis>VFS COMMANDS</emphasis></para>
<itemizedlist>
<listitem><para><command>load &lt;module.so&gt;</command> - Load specified VFS module </para></listitem>
<listitem><para><command>populate &lt;char&gt; &lt;size&gt;</command> - Populate a data buffer with the specified data
</para></listitem>
<listitem><para><command>showdata [&lt;offset&gt; &lt;len&gt;]</command> - Show data currently in data buffer
</para></listitem>
<listitem><para><command>connect</command> - VFS connect()</para></listitem>
<listitem><para><command>disconnect</command> - VFS disconnect()</para></listitem>
<listitem><para><command>disk_free</command> - VFS disk_free()</para></listitem>
<listitem><para><command>opendir</command> - VFS opendir()</para></listitem>
<listitem><para><command>readdir</command> - VFS readdir()</para></listitem>
<listitem><para><command>mkdir</command> - VFS mkdir()</para></listitem>
<listitem><para><command>rmdir</command> - VFS rmdir()</para></listitem>
<listitem><para><command>closedir</command> - VFS closedir()</para></listitem>
<listitem><para><command>open</command> - VFS open()</para></listitem>
<listitem><para><command>close</command> - VFS close()</para></listitem>
<listitem><para><command>read</command> - VFS read()</para></listitem>
<listitem><para><command>write</command> - VFS write()</para></listitem>
<listitem><para><command>lseek</command> - VFS lseek()</para></listitem>
<listitem><para><command>rename</command> - VFS rename()</para></listitem>
<listitem><para><command>fsync</command> - VFS fsync()</para></listitem>
<listitem><para><command>stat</command> - VFS stat()</para></listitem>
<listitem><para><command>fstat</command> - VFS fstat()</para></listitem>
<listitem><para><command>lstat</command> - VFS lstat()</para></listitem>
<listitem><para><command>unlink</command> - VFS unlink()</para></listitem>
<listitem><para><command>chmod</command> - VFS chmod()</para></listitem>
<listitem><para><command>fchmod</command> - VFS fchmod()</para></listitem>
<listitem><para><command>chown</command> - VFS chown()</para></listitem>
<listitem><para><command>fchown</command> - VFS fchown()</para></listitem>
<listitem><para><command>chdir</command> - VFS chdir()</para></listitem>
<listitem><para><command>getwd</command> - VFS getwd()</para></listitem>
<listitem><para><command>utime</command> - VFS utime()</para></listitem>
<listitem><para><command>ftruncate</command> - VFS ftruncate()</para></listitem>
<listitem><para><command>lock</command> - VFS lock()</para></listitem>
<listitem><para><command>symlink</command> - VFS symlink()</para></listitem>
<listitem><para><command>readlink</command> - VFS readlink()</para></listitem>
<listitem><para><command>link</command> - VFS link()</para></listitem>
<listitem><para><command>mknod</command> - VFS mknod()</para></listitem>
<listitem><para><command>realpath</command> - VFS realpath()</para></listitem>
</itemizedlist>
<para><emphasis>GENERAL COMMANDS</emphasis></para>
<itemizedlist>
<listitem><para><command>conf &lt;smb.conf&gt;</command> - Load a different configuration file</para></listitem>
<listitem><para><command>help [&lt;command&gt;]</command> - Get list of commands or info about specified command</para></listitem>
<listitem><para><command>debuglevel &lt;level&gt;</command> - Set debug level</para></listitem>
<listitem><para><command>freemem</command> - Free memory currently in use</para></listitem>
<listitem><para><command>exit</command> - Exit vfstest</para></listitem>
</itemizedlist>
</refsect1>
<refsect1>
<title>VERSION</title>
<para>This man page is correct for version 3.0 of the Samba
suite.</para>
</refsect1>
<refsect1>
<title>AUTHOR</title>
<para>The original Samba software and related utilities
were created by Andrew Tridgell. Samba is now developed
by the Samba Team as an Open Source project similar
to the way the Linux kernel is developed.</para>
<para>The vfstest man page was written by Jelmer Vernooij.</para>
</refsect1>
</refentry>

View File

@ -0,0 +1,78 @@
<chapter id="groupmapping">
<chapterinfo>
<author>
<firstname>Jean François</firstname><surname>Micouleau</surname>
</author>
</chapterinfo>
<title>Group mapping HOWTO</title>
<para>
Starting with Samba 3.0 alpha 2, a new group mapping function is available. The
current method (likely to change) to manage the groups is a new command called
<command>smbgroupedit</command>.
</para>
<para>
The first immediate reason to use the group mapping on a PDC, is that
the <command>domain admin group</command> of <filename>smb.conf</filename> is
now gone. This parameter was used to give the listed users local admin rights
on their workstations. It was some magic stuff that simply worked but didn't
scale very well for complex setups.
</para>
<para>
Let me explain how it works on NT/W2K, to have this magic fade away.
When installing NT/W2K on a computer, the installer program creates some users
and groups. Notably the 'Administrators' group, and gives to that group some
privileges like the ability to change the date and time or to kill any process
(or close too) running on the local machine. The 'Administrator' user is a
member of the 'Administrators' group, and thus 'inherit' the 'Administrators'
group privileges. If a 'joe' user is created and become a member of the
'Administrator' group, 'joe' has exactly the same rights as 'Administrator'.
</para>
<para>
When a NT/W2K machine is joined to a domain, during that phase, the "Domain
Administrators' group of the PDC is added to the 'Administrators' group of the
workstation. Every members of the 'Domain Administrators' group 'inherit' the
rights of the 'Administrators' group when logging on the workstation.
</para>
<para>
You are now wondering how to make some of your samba PDC users members of the
'Domain Administrators' ? That's really easy.
</para>
<orderedlist>
<listitem><para>create a unix group (usually in <filename>/etc/group</filename>), let's call it domadm</para></listitem>
<listitem><para>add to this group the users that must be Administrators. For example if you want joe,john and mary, your entry in <filename>/etc/group</filename> will look like:</para>
<para><programlisting>
domadm:x:502:joe,john,mary
</programlisting></para>
</listitem>
<listitem><para>Map this domadm group to the <command>domain admins</command> group by running the command:</para>
<para><command>smbgroupedit -c "Domain Admins" -u domadm</command></para></listitem>
</orderedlist>
<para>You're set, joe, john and mary are domain administrators !</para>
<para>
Like the Domain Admins group, you can map any arbitrary Unix group to any NT
group. You can also make any Unix group a domain group. For example, on a domain
member machine (an NT/W2K or a samba server running winbind), you would like to
give access to a certain directory to some users who are member of a group on
your samba PDC. Flag that group as a domain group by running:
</para>
<para><command>smbgroupedit -a unixgroup -td</command></para>
<para>You can list the various groups in the mapping database like this</para>
<para><command>smbgroupedit -v</command></para>
</chapter>

View File

@ -0,0 +1,332 @@
<chapter id="Other-Clients">
<chapterinfo>
<author>
<firstname>Jim</firstname><surname>McDonough</surname>
<affiliation>
<orgname>IBM</orgname>
</affiliation>
<firstname>Jelmer</firstname><surname>Vernooij</surname>
<affiliation>
<orgname>Samba Team</orgname>
<address>jelmer@samba.org</address>
</affiliation>
</author>
<pubdate>5 Mar 2001</pubdate>
</chapterinfo>
<title>Samba and other CIFS clients</title>
<para>This chapter contains client-specific information.</para>
<sect1>
<title>Macintosh clients?</title>
<para>
Yes. <ulink url="http://www.thursby.com/">Thursby</ulink> now have a CIFS Client / Server called DAVE - see
</para>
<para>
They test it against Windows 95, Windows NT and samba for
compatibility issues. At the time of writing, DAVE was at version
1.0.1. The 1.0.0 to 1.0.1 update is available as a free download from
the Thursby web site (the speed of finder copies has been greatly
enhanced, and there are bug-fixes included).
</para>
<para>
Alternatives - There are two free implementations of AppleTalk for
several kinds of UNIX machnes, and several more commercial ones.
These products allow you to run file services and print services
natively to Macintosh users, with no additional support required on
the Macintosh. The two free omplementations are
<ulink url="http://www.umich.edu/~rsug/netatalk/">Netatalk</ulink>, and
<ulink url="http://www.cs.mu.oz.au/appletalk/atalk.html">CAP</ulink>.
What Samba offers MS
Windows users, these packages offer to Macs. For more info on these
packages, Samba, and Linux (and other UNIX-based systems) see
<ulink url="http://www.eats.com/linux_mac_win.html">http://www.eats.com/linux_mac_win.html</ulink>
</para>
</sect1>
<sect1>
<title>OS2 Client</title>
<sect2>
<title>How can I configure OS/2 Warp Connect or
OS/2 Warp 4 as a client for Samba?</title>
<para>A more complete answer to this question can be
found on <ulink url="http://carol.wins.uva.nl/~leeuw/samba/warp.html">
http://carol.wins.uva.nl/~leeuw/samba/warp.html</ulink>.</para>
<para>Basically, you need three components:</para>
<itemizedlist>
<listitem><para>The File and Print Client ('IBM Peer')
</para></listitem>
<listitem><para>TCP/IP ('Internet support')
</para></listitem>
<listitem><para>The "NetBIOS over TCP/IP" driver ('TCPBEUI')
</para></listitem>
</itemizedlist>
<para>Installing the first two together with the base operating
system on a blank system is explained in the Warp manual. If Warp
has already been installed, but you now want to install the
networking support, use the "Selective Install for Networking"
object in the "System Setup" folder.</para>
<para>Adding the "NetBIOS over TCP/IP" driver is not described
in the manual and just barely in the online documentation. Start
MPTS.EXE, click on OK, click on "Configure LAPS" and click
on "IBM OS/2 NETBIOS OVER TCP/IP" in 'Protocols'. This line
is then moved to 'Current Configuration'. Select that line,
click on "Change number" and increase it from 0 to 1. Save this
configuration.</para>
<para>If the Samba server(s) is not on your local subnet, you
can optionally add IP names and addresses of these servers
to the "Names List", or specify a WINS server ('NetBIOS
Nameserver' in IBM and RFC terminology). For Warp Connect you
may need to download an update for 'IBM Peer' to bring it on
the same level as Warp 4. See the webpage mentioned above.</para>
</sect2>
<sect2>
<title>How can I configure OS/2 Warp 3 (not Connect),
OS/2 1.2, 1.3 or 2.x for Samba?</title>
<para>You can use the free Microsoft LAN Manager 2.2c Client
for OS/2 from
<ulink url="ftp://ftp.microsoft.com/BusSys/Clients/LANMAN.OS2/">
ftp://ftp.microsoft.com/BusSys/Clients/LANMAN.OS2/</ulink>.
See <ulink url="http://carol.wins.uva.nl/~leeuw/lanman.html">
http://carol.wins.uva.nl/~leeuw/lanman.html</ulink> for
more information on how to install and use this client. In
a nutshell, edit the file \OS2VER in the root directory of
the OS/2 boot partition and add the lines:</para>
<para><programlisting>
20=setup.exe
20=netwksta.sys
20=netvdd.sys
</programlisting></para>
<para>before you install the client. Also, don't use the
included NE2000 driver because it is buggy. Try the NE2000
or NS2000 driver from
<ulink url="ftp://ftp.cdrom.com/pub/os2/network/ndis/">
ftp://ftp.cdrom.com/pub/os2/network/ndis/</ulink> instead.
</para>
</sect2>
<sect2>
<title>Are there any other issues when OS/2 (any version)
is used as a client?</title>
<para>When you do a NET VIEW or use the "File and Print
Client Resource Browser", no Samba servers show up. This can
be fixed by a patch from <ulink
url="http://carol.wins.uva.nl/~leeuw/samba/fix.html">
http://carol.wins.uva.nl/~leeuw/samba/fix.html</ulink>.
The patch will be included in a later version of Samba. It also
fixes a couple of other problems, such as preserving long
filenames when objects are dragged from the Workplace Shell
to the Samba server. </para>
</sect2>
<sect2>
<title>How do I get printer driver download working
for OS/2 clients?</title>
<para>First, create a share called [PRINTDRV] that is
world-readable. Copy your OS/2 driver files there. Note
that the .EA_ files must still be separate, so you will need
to use the original install files, and not copy an installed
driver from an OS/2 system.</para>
<para>Install the NT driver first for that printer. Then,
add to your smb.conf a parameter, os2 driver map =
<replaceable>filename</replaceable>". Then, in the file
specified by <replaceable>filename</replaceable>, map the
name of the NT driver name to the OS/2 driver name as
follows:</para>
<para><command>nt driver name = os2 "driver
name"."device name"</command>, e.g.:
HP LaserJet 5L = LASERJET.HP LaserJet 5L</para>
<para>You can have multiple drivers mapped in this file.</para>
<para>If you only specify the OS/2 driver name, and not the
device name, the first attempt to download the driver will
actually download the files, but the OS/2 client will tell
you the driver is not available. On the second attempt, it
will work. This is fixed simply by adding the device name
to the mapping, after which it will work on the first attempt.
</para>
</sect2>
</sect1>
<sect1>
<title>Windows for Workgroups</title>
<sect2>
<title>Use latest TCP/IP stack from Microsoft</title>
<para>Use the latest TCP/IP stack from microsoft if you use Windows
for workgroups.</para>
<para>The early TCP/IP stacks had lots of bugs.</para>
<para>
Microsoft has released an incremental upgrade to their TCP/IP 32-Bit
VxD drivers. The latest release can be found on their ftp site at
ftp.microsoft.com, located in /peropsys/windows/public/tcpip/wfwt32.exe.
There is an update.txt file there that describes the problems that were
fixed. New files include WINSOCK.DLL, TELNET.EXE, WSOCK.386, VNBT.386,
WSTCP.386, TRACERT.EXE, NETSTAT.EXE, and NBTSTAT.EXE.
</para>
</sect2>
<sect2>
<title>Delete .pwl files after password change</title>
<para>
WfWg does a lousy job with passwords. I find that if I change my
password on either the unix box or the PC the safest thing to do is to
delete the .pwl files in the windows directory. The PC will complain about not finding the files, but will soon get over it, allowing you to enter the new password.
</para>
<para>
If you don't do this you may find that WfWg remembers and uses the old
password, even if you told it a new one.
</para>
<para>
Often WfWg will totally ignore a password you give it in a dialog box.
</para>
</sect2>
<sect2>
<title>Configure WfW password handling</title>
<para>
There is a program call admincfg.exe
on the last disk (disk 8) of the WFW 3.11 disk set. To install it
type EXPAND A:\ADMINCFG.EX_ C:\WINDOWS\ADMINCFG.EXE Then add an icon
for it via the "Progam Manager" "New" Menu. This program allows you
to control how WFW handles passwords. ie disable Password Caching etc
for use with <command>security = user</command>
</para>
</sect2>
<sect2>
<title>Case handling of passwords</title>
<para>Windows for Workgroups uppercases the password before sending it to the server. Unix passwords can be case-sensitive though. Check the <ulink url="smb.conf.5.html">smb.conf(5)</ulink> information on <command>password level</command> to specify what characters samba should try to uppercase when checking.</para>
</sect2>
</sect1>
<sect1>
<title>Windows '95/'98</title>
<para>
When using Windows 95 OEM SR2 the following updates are recommended where Samba
is being used. Please NOTE that the above change will affect you once these
updates have been installed.
</para>
<para>
There are more updates than the ones mentioned here. You are referred to the
Microsoft Web site for all currently available updates to your specific version
of Windows 95.
</para>
<orderedlist>
<listitem><para>Kernel Update: KRNLUPD.EXE</para></listitem>
<listitem><para>Ping Fix: PINGUPD.EXE</para></listitem>
<listitem><para>RPC Update: RPCRTUPD.EXE</para></listitem>
<listitem><para>TCP/IP Update: VIPUPD.EXE</para></listitem>
<listitem><para>Redirector Update: VRDRUPD.EXE</para></listitem>
</orderedlist>
<para>
Also, if using MS OutLook it is desirable to install the OLEUPD.EXE fix. This
fix may stop your machine from hanging for an extended period when exiting
OutLook and you may also notice a significant speedup when accessing network
neighborhood services.
</para>
</sect1>
<sect1>
<title>Windows 2000 Service Pack 2</title>
<para>
There are several annoyances with Windows 2000 SP2. One of which
only appears when using a Samba server to host user profiles
to Windows 2000 SP2 clients in a Windows domain. This assumes
that Samba is a member of the domain, but the problem will
likely occur if it is not.
</para>
<para>
In order to server profiles successfully to Windows 2000 SP2
clients (when not operating as a PDC), Samba must have
<command>nt acl support = no</command>
added to the file share which houses the roaming profiles.
If this is not done, then the Windows 2000 SP2 client will
complain about not being able to access the profile (Access
Denied) and create multiple copies of it on disk (DOMAIN.user.001,
DOMAIN.user.002, etc...). See the
<ulink url="smb.conf.5.html">smb.conf(5)</ulink> man page
for more details on this option. Also note that the
<command>nt acl support</command> parameter was formally a global parameter in
releases prior to Samba 2.2.2.
</para>
<para>
The following is a minimal profile share:
</para>
<para><programlisting>
[profile]
path = /export/profile
create mask = 0600
directory mask = 0700
nt acl support = no
read only = no
</programlisting></para>
<para>
The reason for this bug is that the Win2k SP2 client copies
the security descriptor for the profile which contains
the Samba server's SID, and not the domain SID. The client
compares the SID for SAMBA\user and realizes it is
different that the one assigned to DOMAIN\user. Hence the reason
for the "access denied" message.
</para>
<para>
By disabling the <command>nt acl support</command> parameter, Samba will send
the Win2k client a response to the QuerySecurityDescriptor
trans2 call which causes the client to set a default ACL
for the profile. This default ACL includes
</para>
<para><command>DOMAIN\user "Full Control"</command></para>
<para><emphasis>NOTE : This bug does not occur when using winbind to
create accounts on the Samba host for Domain users.</emphasis></para>
</sect1>
</chapter>

View File

@ -0,0 +1,148 @@
<chapter id="Portability">
<chapterinfo>
<author>
<firstname>Jelmer</firstname><surname>Vernooij</surname>
</author>
</chapterinfo>
<title>Portability</title>
<para>Samba works on a wide range of platforms but the interface all the
platforms provide is not always compatible. This chapter contains
platform-specific information about compiling and using samba.</para>
<sect1>
<title>HPUX</title>
<para>
HP's implementation of supplementary groups is, er, non-standard (for
hysterical reasons). There are two group files, /etc/group and
/etc/logingroup; the system maps UIDs to numbers using the former, but
initgroups() reads the latter. Most system admins who know the ropes
symlink /etc/group to /etc/logingroup (hard link doesn't work for reasons
too stupid to go into here). initgroups() will complain if one of the
groups you're in in /etc/logingroup has what it considers to be an invalid
ID, which means outside the range [0..UID_MAX], where UID_MAX is (I think)
60000 currently on HP-UX. This precludes -2 and 65534, the usual 'nobody'
GIDs.
</para>
<para>
If you encounter this problem, make sure that the programs that are failing
to initgroups() be run as users not in any groups with GIDs outside the
allowed range.
</para>
<para>This is documented in the HP manual pages under setgroups(2) and passwd(4).
</para>
</sect1>
<sect1>
<title>SCO Unix</title>
<para>
If you run an old version of SCO Unix then you may need to get important
TCP/IP patches for Samba to work correctly. Without the patch, you may
encounter corrupt data transfers using samba.
</para>
<para>
The patch you need is UOD385 Connection Drivers SLS. It is available from
SCO (ftp.sco.com, directory SLS, files uod385a.Z and uod385a.ltr.Z).
</para>
</sect1>
<sect1>
<title>DNIX</title>
<para>
DNIX has a problem with seteuid() and setegid(). These routines are
needed for Samba to work correctly, but they were left out of the DNIX
C library for some reason.
</para>
<para>
For this reason Samba by default defines the macro NO_EID in the DNIX
section of includes.h. This works around the problem in a limited way,
but it is far from ideal, some things still won't work right.
</para>
<para>
To fix the problem properly you need to assemble the following two
functions and then either add them to your C library or link them into
Samba.
</para>
<para>
put this in the file <filename>setegid.s</filename>:
</para>
<para><programlisting>
.globl _setegid
_setegid:
moveq #47,d0
movl #100,a0
moveq #1,d1
movl 4(sp),a1
trap #9
bccs 1$
jmp cerror
1$:
clrl d0
rts
</programlisting></para>
<para>
put this in the file <filename>seteuid.s</filename>:
</para>
<para><programlisting>
.globl _seteuid
_seteuid:
moveq #47,d0
movl #100,a0
moveq #0,d1
movl 4(sp),a1
trap #9
bccs 1$
jmp cerror
1$:
clrl d0
rts
</programlisting></para>
<para>
after creating the above files you then assemble them using
</para>
<para><command>as seteuid.s</command></para>
<para><command>as setegid.s</command></para>
<para>
that should produce the files <filename>seteuid.o</filename> and
<filename>setegid.o</filename>
</para>
<para>
then you need to add these to the LIBSM line in the DNIX section of
the Samba Makefile. Your LIBSM line will then look something like this:
</para>
<para><programlisting>
LIBSM = setegid.o seteuid.o -ln
</programlisting></para>
<para>
You should then remove the line:
</para>
<para><programlisting>
#define NO_EID
</programlisting></para>
<para>from the DNIX section of <filename>includes.h</filename></para>
</sect1>
</chapter>

82
docs/docbook/samba.dsl Normal file
View File

@ -0,0 +1,82 @@
<!-- This file defines the DocBook-utils Style Sheet for DocBook
Eric Bischoff <eric@caldera.de>
-->
<!DOCTYPE style-sheet PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN" [
<!ENTITY % html "IGNORE">
<![%html; [
<!ENTITY % print "IGNORE">
<!ENTITY docbook.dsl PUBLIC "-//Norman Walsh//DOCUMENT DocBook HTML Stylesheet//EN" CDATA dsssl>
]]>
<!ENTITY % print "INCLUDE">
<![%print; [
<!ENTITY docbook.dsl PUBLIC "-//Norman Walsh//DOCUMENT DocBook Print Stylesheet//EN" CDATA dsssl>
]]>
]>
<STYLE-SHEET>
<STYLE-SPECIFICATION ID="UTILS" USE="DOCBOOK">
<STYLE-SPECIFICATION-BODY>
;; ===================================================================
;; Generic Parameters
;; (Generic currently means: both print and html)
(define (chunk-element-list)
(list (normalize "preface")
(normalize "chapter")
(normalize "appendix")
(normalize "article")
(normalize "glossary")
(normalize "bibliography")
(normalize "index")
(normalize "colophon")
(normalize "setindex")
(normalize "reference")
(normalize "refentry")
(normalize "part")
; (normalize "sect1")
(normalize "section")
(normalize "book") ;; just in case nothing else matches...
(normalize "set") ;; sets are definitely chunks...
))
(define %chapter-autolabel% #t)
(define %section-autolabel% #t)
(define (toc-depth nd) 3)
(define %root-filename% "Samba-HOWTO") ;; name for the root html file
(define %html-ext% ".html") ;; default extension for html output files
(define %html-prefix% "") ;; prefix for all filenames generated (except root)
(define %use-id-as-filename% #t)
; === HTML settings ===
(define %html-pubid% "-//W3C//DTD HTML 4.01 Transitional//EN") ;; Nearly true :-(
(define %html40% #t)
; === Media objects ===
(define preferred-mediaobject-extensions ;; this magic allows to use different graphical
(list "png" "jpg" "jpeg")) ;; formats for printing and putting online
(define acceptable-mediaobject-extensions
(list "bmp" "gif" "eps" "epsf" "avi" "mpg" "mpeg" "qt"))
(define preferred-mediaobject-notations
(list "PNG" "JPG" "JPEG"))
(define acceptable-mediaobject-notations
(list "EPS" "BMP" "GIF" "linespecific"))
; === Rendering ===
(define %admon-graphics% #t) ;; use symbols for Caution|Important|Note|Tip|Warning
; === Books only ===
(define %generate-book-titlepage% #t)
(define %generate-book-toc% #t)
(define ($generate-chapter-toc$) #f) ;; never generate a chapter TOC in books
; === Articles only ===
(define %generate-article-titlepage% #t)
(define %generate-article-toc% #t) ;; make TOC
</STYLE-SPECIFICATION-BODY>
</STYLE-SPECIFICATION>
<EXTERNAL-SPECIFICATION ID="DOCBOOK" DOCUMENT="docbook.dsl">
</STYLE-SHEET>

178
docs/manpages/vfstest.1 Normal file
View File

@ -0,0 +1,178 @@
.\" This manpage has been automatically generated by docbook2man
.\" from a DocBook document. This tool can be found at:
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve@ggi-project.org>.
.TH "VFSTEST" "1" "20 August 2002" "" ""
.SH NAME
vfstest \- tool for testing samba VFS modules
.SH SYNOPSIS
\fBvfstest\fR [ \fB-d debuglevel\fR ] [ \fB-c command\fR ] [ \fB-l logfile\fR ] [ \fB-h\fR ]
.SH "DESCRIPTION"
.PP
This tool is part of the Sambasuite.
.PP
\fBvfstest\fR is a small command line
utility that has the ability to test dso samba VFS modules. It gives the
user the ability to call the various VFS functions manually and
supports cascaded VFS modules.
.SH "OPTIONS"
.TP
\fB-c|--command=command\fR
Execute the specified (colon-seperated) commands.
See below for the commands that are available.
.TP
\fB-d|--debug=debuglevel\fR
set the debuglevel. Debug level 0 is the lowest
and 100 being the highest. This should be set to 100 if you are
planning on submitting a bug report to the Samba team (see \fIBUGS.txt\fR).
.TP
\fB-h|--help\fR
Print a summary of command line options.
.TP
\fB-l|--logfile=logbasename\fR
File name for log/debug files. The extension
\&'.client' will be appended. The log file is never removed
by the client.
.SH "COMMANDS"
.PP
\fBVFS COMMANDS\fR
.TP 0.2i
\(bu
\fBload <module.so>\fR - Load specified VFS module
.TP 0.2i
\(bu
\fBpopulate <char> <size>\fR - Populate a data buffer with the specified data
.TP 0.2i
\(bu
\fBshowdata [<offset> <len>]\fR - Show data currently in data buffer
.TP 0.2i
\(bu
\fBconnect\fR - VFS connect()
.TP 0.2i
\(bu
\fBdisconnect\fR - VFS disconnect()
.TP 0.2i
\(bu
\fBdisk_free\fR - VFS disk_free()
.TP 0.2i
\(bu
\fBopendir\fR - VFS opendir()
.TP 0.2i
\(bu
\fBreaddir\fR - VFS readdir()
.TP 0.2i
\(bu
\fBmkdir\fR - VFS mkdir()
.TP 0.2i
\(bu
\fBrmdir\fR - VFS rmdir()
.TP 0.2i
\(bu
\fBclosedir\fR - VFS closedir()
.TP 0.2i
\(bu
\fBopen\fR - VFS open()
.TP 0.2i
\(bu
\fBclose\fR - VFS close()
.TP 0.2i
\(bu
\fBread\fR - VFS read()
.TP 0.2i
\(bu
\fBwrite\fR - VFS write()
.TP 0.2i
\(bu
\fBlseek\fR - VFS lseek()
.TP 0.2i
\(bu
\fBrename\fR - VFS rename()
.TP 0.2i
\(bu
\fBfsync\fR - VFS fsync()
.TP 0.2i
\(bu
\fBstat\fR - VFS stat()
.TP 0.2i
\(bu
\fBfstat\fR - VFS fstat()
.TP 0.2i
\(bu
\fBlstat\fR - VFS lstat()
.TP 0.2i
\(bu
\fBunlink\fR - VFS unlink()
.TP 0.2i
\(bu
\fBchmod\fR - VFS chmod()
.TP 0.2i
\(bu
\fBfchmod\fR - VFS fchmod()
.TP 0.2i
\(bu
\fBchown\fR - VFS chown()
.TP 0.2i
\(bu
\fBfchown\fR - VFS fchown()
.TP 0.2i
\(bu
\fBchdir\fR - VFS chdir()
.TP 0.2i
\(bu
\fBgetwd\fR - VFS getwd()
.TP 0.2i
\(bu
\fButime\fR - VFS utime()
.TP 0.2i
\(bu
\fBftruncate\fR - VFS ftruncate()
.TP 0.2i
\(bu
\fBlock\fR - VFS lock()
.TP 0.2i
\(bu
\fBsymlink\fR - VFS symlink()
.TP 0.2i
\(bu
\fBreadlink\fR - VFS readlink()
.TP 0.2i
\(bu
\fBlink\fR - VFS link()
.TP 0.2i
\(bu
\fBmknod\fR - VFS mknod()
.TP 0.2i
\(bu
\fBrealpath\fR - VFS realpath()
.PP
\fBGENERAL COMMANDS\fR
.TP 0.2i
\(bu
\fBconf <smb.conf>\fR - Load a different configuration file
.TP 0.2i
\(bu
\fBhelp [<command>]\fR - Get list of commands or info about specified command
.TP 0.2i
\(bu
\fBdebuglevel <level>\fR - Set debug level
.TP 0.2i
\(bu
\fBfreemem\fR - Free memory currently in use
.TP 0.2i
\(bu
\fBexit\fR - Exit vfstest
.SH "VERSION"
.PP
This man page is correct for version 3.0 of the Samba
suite.
.SH "AUTHOR"
.PP
The original Samba software and related utilities
were created by Andrew Tridgell. Samba is now developed
by the Samba Team as an Open Source project similar
to the way the Linux kernel is developed.
.PP
The vfstest man page was written by Jelmer Vernooij.

View File

@ -0,0 +1,18 @@
There is the new netatalk module both for HEAD.
This one has some difference from previous module:
-- it doesn't care about creating of .AppleDouble forks, just keeps ones in
sync;
-- if share in smb.conf doesn't contain .AppleDouble item in hide or veto
list, it will be added automatically.
To my way of thinking, module became more lightweight and speedy.
How to compile:
you should place proper netatalk.c into examples/VFS/ then run 'configure'
from source/ and then run 'make' from examples/VFS/.
add string 'vfs object = <path_to_netatalk_so>/netatlk.so' to smb.conf. It may
be defined either as global or as share-specific parameter.

430
examples/VFS/netatalk.c Normal file
View File

@ -0,0 +1,430 @@
/*
* AppleTalk VFS module for Samba-3.x
*
* Copyright (C) Alexei Kotovich, 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 "config.h"
#include <stdio.h>
#include <sys/stat.h>
#ifdef HAVE_UTIME_H
#include <utime.h>
#endif
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <errno.h>
#include <string.h>
#include <includes.h>
#include <vfs.h>
#define APPLEDOUBLE ".AppleDouble"
#define ADOUBLEMODE 0777
/* atalk functions */
static int atalk_build_paths(TALLOC_CTX *ctx, const char *path,
const char *fname, char **adbl_path, char **orig_path,
SMB_STRUCT_STAT *adbl_info, SMB_STRUCT_STAT *orig_info);
static int atalk_unlink_file(const char *path);
static struct vfs_ops default_vfs_ops; /* For passthrough operation */
static struct smb_vfs_handle_struct *atalk_handle;
static int atalk_get_path_ptr(char *path)
{
int i = 0;
int ptr = 0;
for (i = 0; path[i]; i ++) {
if (path[i] == '/')
ptr = i;
/* get out some 'spam';) from win32's file name */
else if (path[i] == ':') {
path[i] = '\0';
break;
}
}
return ptr;
}
static int atalk_build_paths(TALLOC_CTX *ctx, const char *path, const char *fname,
char **adbl_path, char **orig_path,
SMB_STRUCT_STAT *adbl_info, SMB_STRUCT_STAT *orig_info)
{
int ptr0 = 0;
int ptr1 = 0;
char *dname = 0;
char *name = 0;
if (!ctx || !path || !fname || !adbl_path || !orig_path ||
!adbl_info || !orig_info)
return -1;
#if 0
DEBUG(3, ("ATALK: PATH: %s[%s]\n", path, fname));
#endif
if (strstr(path, APPLEDOUBLE) || strstr(fname, APPLEDOUBLE)) {
DEBUG(3, ("ATALK: path %s[%s] already contains %s\n", path, fname, APPLEDOUBLE));
return -1;
}
if (fname[0] == '.') ptr0 ++;
if (fname[1] == '/') ptr0 ++;
*orig_path = talloc_asprintf(ctx, "%s/%s", path, &fname[ptr0]);
/* get pointer to last '/' */
ptr1 = atalk_get_path_ptr(*orig_path);
sys_lstat(*orig_path, orig_info);
if (S_ISDIR(orig_info->st_mode)) {
*adbl_path = talloc_asprintf(ctx, "%s/%s/%s/",
path, &fname[ptr0], APPLEDOUBLE);
} else {
dname = talloc_strdup(ctx, *orig_path);
dname[ptr1] = '\0';
name = *orig_path;
*adbl_path = talloc_asprintf(ctx, "%s/%s/%s",
dname, APPLEDOUBLE, &name[ptr1 + 1]);
}
#if 0
DEBUG(3, ("ATALK: DEBUG:\n%s\n%s\n", *orig_path, *adbl_path));
#endif
sys_lstat(*adbl_path, adbl_info);
return 0;
}
static int atalk_unlink_file(const char *path)
{
int ret = 0;
become_root();
ret = unlink(path);
unbecome_root();
return ret;
}
static void atalk_add_to_list(name_compare_entry **list)
{
int i, count = 0;
name_compare_entry *new_list = 0;
name_compare_entry *cur_list = 0;
cur_list = *list;
if (cur_list) {
for (i = 0, count = 0; cur_list[i].name; i ++, count ++) {
if (strstr(cur_list[i].name, APPLEDOUBLE))
return;
}
}
if (!(new_list = calloc(1,
(count == 0 ? 1 : count + 1) * sizeof(name_compare_entry))))
return;
for (i = 0; i < count; i ++) {
new_list[i].name = strdup(cur_list[i].name);
new_list[i].is_wild = cur_list[i].is_wild;
}
new_list[i].name = strdup(APPLEDOUBLE);
new_list[i].is_wild = False;
free_namearray(*list);
*list = new_list;
new_list = 0;
cur_list = 0;
}
static void atalk_rrmdir(TALLOC_CTX *ctx, char *path)
{
int n;
char *dpath;
struct dirent **namelist;
if (!path) return;
n = scandir(path, &namelist, 0, alphasort);
if (n < 0) {
return;
} else {
while (n --) {
if (strcmp(namelist[n]->d_name, ".") == 0 ||
strcmp(namelist[n]->d_name, "..") == 0)
continue;
if (!(dpath = talloc_asprintf(ctx, "%s/%s",
path, namelist[n]->d_name)))
continue;
atalk_unlink_file(dpath);
free(namelist[n]);
}
}
}
/* Disk operations */
/* Directory operations */
DIR *atalk_opendir(struct connection_struct *conn, const char *fname)
{
DIR *ret = 0;
ret = default_vfs_ops.opendir(conn, fname);
/*
* when we try to perform delete operation upon file which has fork
* in ./.AppleDouble and this directory wasn't hidden by Samba,
* MS Windows explorer causes the error: "Cannot find the specified file"
* There is some workaround to avoid this situation, i.e. if
* connection has not .AppleDouble entry in either veto or hide
* list then it would be nice to add one.
*/
atalk_add_to_list(&conn->hide_list);
atalk_add_to_list(&conn->veto_list);
return ret;
}
static int atalk_rmdir(struct connection_struct *conn, const char *path)
{
BOOL add = False;
TALLOC_CTX *ctx = 0;
char *dpath;
if (!conn || !conn->origpath || !path) goto exit_rmdir;
/* due to there is no way to change bDeleteVetoFiles variable
* from this module, gotta use talloc stuff..
*/
strstr(path, APPLEDOUBLE) ? (add = False) : (add = True);
if (!(ctx = talloc_init_named("remove_directory")))
goto exit_rmdir;
if (!(dpath = talloc_asprintf(ctx, "%s/%s%s",
conn->origpath, path, add ? "/"APPLEDOUBLE : "")))
goto exit_rmdir;
atalk_rrmdir(ctx, dpath);
exit_rmdir:
talloc_destroy(ctx);
return default_vfs_ops.rmdir(conn, path);
}
/* File operations */
static int atalk_rename(struct connection_struct *conn, const char *old, const char *new)
{
int ret = 0;
char *adbl_path = 0;
char *orig_path = 0;
SMB_STRUCT_STAT adbl_info;
SMB_STRUCT_STAT orig_info;
TALLOC_CTX *ctx;
ret = default_vfs_ops.rename(conn, old, new);
if (!conn || !old) return ret;
if (!(ctx = talloc_init_named("rename_file")))
return ret;
if (atalk_build_paths(ctx, conn->origpath, old, &adbl_path, &orig_path,
&adbl_info, &orig_info) != 0)
return ret;
if (S_ISDIR(orig_info.st_mode) || S_ISREG(orig_info.st_mode)) {
DEBUG(3, ("ATALK: %s has passed..\n", adbl_path));
goto exit_rename;
}
atalk_unlink_file(adbl_path);
exit_rename:
talloc_destroy(ctx);
return ret;
}
static int atalk_unlink(struct connection_struct *conn, const char *path)
{
int ret = 0, i;
char *adbl_path = 0;
char *orig_path = 0;
SMB_STRUCT_STAT adbl_info;
SMB_STRUCT_STAT orig_info;
TALLOC_CTX *ctx;
ret = default_vfs_ops.unlink(conn, path);
if (!conn || !path) return ret;
/* no .AppleDouble sync if veto or hide list is empty,
* otherwise "Cannot find the specified file" error will be caused
*/
if (!conn->veto_list) return ret;
if (!conn->hide_list) return ret;
for (i = 0; conn->veto_list[i].name; i ++) {
if (strstr(conn->veto_list[i].name, APPLEDOUBLE))
break;
}
if (!conn->veto_list[i].name) {
for (i = 0; conn->hide_list[i].name; i ++) {
if (strstr(conn->hide_list[i].name, APPLEDOUBLE))
break;
else {
DEBUG(3, ("ATALK: %s is not hidden, skipped..\n",
APPLEDOUBLE));
return ret;
}
}
}
if (!(ctx = talloc_init_named("unlink_file")))
return ret;
if (atalk_build_paths(ctx, conn->origpath, path, &adbl_path, &orig_path,
&adbl_info, &orig_info) != 0)
return ret;
if (S_ISDIR(orig_info.st_mode) || S_ISREG(orig_info.st_mode)) {
DEBUG(3, ("ATALK: %s has passed..\n", adbl_path));
goto exit_unlink;
}
atalk_unlink_file(adbl_path);
exit_unlink:
talloc_destroy(ctx);
return ret;
}
static int atalk_chmod(struct connection_struct *conn, const char *path, mode_t mode)
{
int ret = 0;
char *adbl_path = 0;
char *orig_path = 0;
SMB_STRUCT_STAT adbl_info;
SMB_STRUCT_STAT orig_info;
TALLOC_CTX *ctx;
ret = default_vfs_ops.chmod(conn, path, mode);
if (!conn || !path) return ret;
if (!(ctx = talloc_init_named("chmod_file")))
return ret;
if (atalk_build_paths(ctx, conn->origpath, path, &adbl_path, &orig_path,
&adbl_info, &orig_info) != 0)
return ret;
if (!S_ISDIR(orig_info.st_mode) && !S_ISREG(orig_info.st_mode)) {
DEBUG(3, ("ATALK: %s has passed..\n", orig_path));
goto exit_chmod;
}
chmod(adbl_path, ADOUBLEMODE);
exit_chmod:
talloc_destroy(ctx);
return ret;
}
static int atalk_chown(struct connection_struct *conn, const char *path, uid_t uid, gid_t gid)
{
int ret = 0;
char *adbl_path = 0;
char *orig_path = 0;
SMB_STRUCT_STAT adbl_info;
SMB_STRUCT_STAT orig_info;
TALLOC_CTX *ctx;
ret = default_vfs_ops.chown(conn, path, uid, gid);
if (!conn || !path) return ret;
if (!(ctx = talloc_init_named("chown_file")))
return ret;
if (atalk_build_paths(ctx, conn->origpath, path, &adbl_path, &orig_path,
&adbl_info, &orig_info) != 0)
return ret;
if (!S_ISDIR(orig_info.st_mode) && !S_ISREG(orig_info.st_mode)) {
DEBUG(3, ("ATALK: %s has passed..\n", orig_path));
goto exit_chown;
}
chown(adbl_path, uid, gid);
exit_chown:
talloc_destroy(ctx);
return ret;
}
static vfs_op_tuple atalk_ops[] = {
/* Directory operations */
{atalk_opendir, SMB_VFS_OP_OPENDIR, SMB_VFS_LAYER_TRANSPARENT},
{atalk_rmdir, SMB_VFS_OP_RMDIR, SMB_VFS_LAYER_TRANSPARENT},
/* File operations */
{atalk_rename, SMB_VFS_OP_RENAME, SMB_VFS_LAYER_TRANSPARENT},
{atalk_unlink, SMB_VFS_OP_UNLINK, SMB_VFS_LAYER_TRANSPARENT},
{atalk_chmod, SMB_VFS_OP_CHMOD, SMB_VFS_LAYER_TRANSPARENT},
{atalk_chown, SMB_VFS_OP_CHOWN, SMB_VFS_LAYER_TRANSPARENT},
/* Finish VFS operations definition */
{NULL, SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
};
/* VFS initialisation function. Return vfs_op_tuple array back to SAMBA. */
vfs_op_tuple *vfs_init(int *vfs_version, struct vfs_ops *def_vfs_ops,
struct smb_vfs_handle_struct *vfs_handle)
{
*vfs_version = SMB_VFS_INTERFACE_VERSION;
memcpy(&default_vfs_ops, def_vfs_ops, sizeof(struct vfs_ops));
atalk_handle = vfs_handle;
DEBUG(3, ("ATALK: vfs module loaded\n"));
return atalk_ops;
}
/* VFS finalization function. */
void vfs_done(connection_struct *conn)
{
DEBUG(3, ("ATALK: vfs module unloaded\n"));
}

28
examples/sam/Makefile.in Normal file
View File

@ -0,0 +1,28 @@
CC = @CC@
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LDSHFLAGS = -shared
srcdir = @builddir@
FLAGS = $(CFLAGS) -Iinclude -I$(srcdir)/include -I$(srcdir)/ubiqx -I$(srcdir)/smbwrapper -I. $(CPPFLAGS) -I$(srcdir)
SAM_OBJS = sam_skel.so
# Default target
default: $(SAM_OBJS)
# Pattern rules
%.so: %.o
$(CC) $(LDSHFLAGS) $(LDFLAGS) -o $@ $<
%.o: %.c
$(CC) $(FLAGS) -c $<
# Misc targets
clean:
rm -rf .libs
rm -f core *~ *% *.bak \
$(SAM_OBJ) $(SAM_OBJS)

29
examples/sam/README Normal file
View File

@ -0,0 +1,29 @@
README for Samba SAM Database examples
====================================================
26-08-2002 Stefan (metze) Metzmacher <metze@metzemix.de>
Every module MUST have a sam_version() function.
this is defined in include/sam.h:
#define SAM_MODULE_VERSIONING_MAGIC \
int sam_version(void)\
{\
return SAM_INTERFACE_VERSION;\
}
You MUST add this line inside a module:
SAM_MODULE_VERSIONING_MAGIC
The sam_skel.c file in this directory contains a very basic example of
a SAM plugin. It just prints the name of the function that is executed using
DEBUG. Maybe it's nice to include some of the arguments to the function in the
future too..
New SAM plugins should go into the samba lib directory, (/usr/lib/samba/
for most distributions) and should be prefixed with 'sam_' and should go into the
subdir sam/. The SAM subsystem will search in /usr/lib/samba/sam and fall back to
/usr/lib/samba/ .
An example path would be:
/usr/lib/samba/sam/sam_skel.so

250
examples/sam/sam_skel.c Normal file
View File

@ -0,0 +1,250 @@
/*
Unix SMB/CIFS implementation.
this is a skeleton for SAM backend modules.
Copyright (C) Stefan (metze) Metzmacher 2002
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"
static int sam_skel_debug_level = DBGC_SAM;
#undef DBGC_CLASS
#define DBGC_CLASS sam_skel_debug_level
/* define the version of the SAM interface */
SAM_MODULE_VERSIONING_MAGIC
/* General API */
NTSTATUS sam_skel_get_sec_desc(const SAM_METHODS *sam_methods, const NT_USER_TOKEN *access_token, const DOM_SID *sid, SEC_DESC **sd)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_skel_set_sec_desc(const SAM_METHODS *sam_methods, const NT_USER_TOKEN *access_token, const DOM_SID *sid, const SEC_DESC *sd)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_skel_lookup_sid(const SAM_METHODS *sam_methods, const NT_USER_TOKEN *access_token, const DOM_SID *sid, char **name, uint32 *type)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_skel_lookup_name(const SAM_METHODS *sam_methods, const NT_USER_TOKEN *access_token, const char *name, DOM_SID **sid, uint32 *type)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
/* Domain API */
NTSTATUS sam_skel_update_domain(const SAM_METHODS *sam_methods, const SAM_DOMAIN_HANDLE *domain)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_skel_get_domain_handle(const SAM_METHODS *sam_methods, const NT_USER_TOKEN *access_token, uint32 access_desired, SAM_DOMAIN_HANDLE **domain)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
/* Account API */
NTSTATUS sam_skel_create_account(const SAM_METHODS *sam_methods, const NT_USER_TOKEN *access_token, uint32 access_desired, const char *group_name, uint16 acct_ctrl, SAM_ACCOUNT_HANDLE **account)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_skel_add_account(const SAM_METHODS *sam_methods, const SAM_ACCOUNT_HANDLE *account)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_skel_update_account(const SAM_METHODS *sam_methods, const SAM_ACCOUNT_HANDLE *account)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_skel_delete_account(const SAM_METHODS *sam_methods, const SAM_ACCOUNT_HANDLE *account)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_skel_enum_accounts(const SAM_METHODS *sam_methods, const NT_USER_TOKEN *access_token, uint16 acct_ctrl, uint32 *account_count, SAM_ACCOUNT_ENUM **accounts)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_skel_get_account_by_sid(const SAM_METHODS *sam_methods, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *accountsid, SAM_ACCOUNT_HANDLE **account)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_skel_get_account_by_name(const SAM_METHODS *sam_methods, const NT_USER_TOKEN *access_token, uint32 access_desired, const char *name, SAM_ACCOUNT_HANDLE **account)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
/* Group API */
NTSTATUS sam_skel_create_group(const SAM_METHODS *sam_methods, const NT_USER_TOKEN *access_token, uint32 access_desired, const char *account_name, uint16 group_ctrl, SAM_GROUP_HANDLE **group)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_skel_add_group(const SAM_METHODS *sam_methods, const SAM_GROUP_HANDLE *group)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_skel_update_group(const SAM_METHODS *sam_methods, const SAM_GROUP_HANDLE *group)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_skel_delete_group(const SAM_METHODS *sam_methods, const SAM_GROUP_HANDLE *group)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_skel_enum_groups(const SAM_METHODS *sam_methods, const NT_USER_TOKEN *access_token, uint16 group_ctrl, uint32 *groups_count, SAM_GROUP_ENUM **groups)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_skel_get_group_by_sid(const SAM_METHODS *sam_methods, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *groupsid, SAM_GROUP_HANDLE **group)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_skel_get_group_by_name(const SAM_METHODS *sam_methods, const NT_USER_TOKEN *access_token, uint32 access_desired, const char *name, SAM_GROUP_HANDLE **group)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_skel_add_member_to_group(const SAM_METHODS *sam_methods, const SAM_GROUP_HANDLE *group, const SAM_GROUP_MEMBER *member)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_skel_delete_member_from_group(const SAM_METHODS *sam_methods, const SAM_GROUP_HANDLE *group, const SAM_GROUP_MEMBER *member)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_skel_enum_groupmembers(const SAM_METHODS *sam_methods, const SAM_GROUP_HANDLE *group, uint32 *members_count, SAM_GROUP_MEMBER **members)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_skel_get_groups_of_sid(const SAM_METHODS *sam_methods, const NT_USER_TOKEN *access_token, const DOM_SID **sids, uint16 group_ctrl, uint32 *group_count, SAM_GROUP_ENUM **groups)
{
DEBUG(0,("sam_skel: %s was called!\n",__FUNCTION__));
return NT_STATUS_NOT_IMPLEMENTED;
}
NTSTATUS sam_init(SAM_METHODS *sam_methods, const char *module_params)
{
/* Functions your SAM module doesn't provide should be set
* to NULL */
sam_methods->sam_get_sec_desc = sam_skel_get_sec_desc;
sam_methods->sam_set_sec_desc = sam_skel_set_sec_desc;
sam_methods->sam_lookup_sid = sam_skel_lookup_sid;
sam_methods->sam_lookup_name = sam_skel_lookup_name;
/* Domain API */
sam_methods->sam_update_domain = sam_skel_update_domain;
sam_methods->sam_get_domain_handle = sam_skel_get_domain_handle;
/* Account API */
sam_methods->sam_create_account = sam_skel_create_account;
sam_methods->sam_add_account = sam_skel_add_account;
sam_methods->sam_update_account = sam_skel_update_account;
sam_methods->sam_delete_account = sam_skel_delete_account;
sam_methods->sam_enum_accounts = sam_skel_enum_accounts;
sam_methods->sam_get_account_by_sid = sam_skel_get_account_by_sid;
sam_methods->sam_get_account_by_name = sam_skel_get_account_by_name;
/* Group API */
sam_methods->sam_create_group = sam_skel_create_group;
sam_methods->sam_add_group = sam_skel_add_group;
sam_methods->sam_update_group = sam_skel_update_group;
sam_methods->sam_delete_group = sam_skel_delete_group;
sam_methods->sam_enum_groups = sam_skel_enum_groups;
sam_methods->sam_get_group_by_sid = sam_skel_get_group_by_sid;
sam_methods->sam_get_group_by_name = sam_skel_get_group_by_name;
sam_methods->sam_add_member_to_group = sam_skel_add_member_to_group;
sam_methods->sam_delete_member_from_group = sam_skel_delete_member_from_group;
sam_methods->sam_enum_groupmembers = sam_skel_enum_groupmembers;
sam_methods->sam_get_groups_of_sid = sam_skel_get_groups_of_sid;
sam_methods->free_private_data = NULL;
sam_skel_debug_level = debug_add_class("sam_skel");
if (sam_skel_debug_level == -1) {
sam_skel_debug_level = DBGC_SAM;
DEBUG(0, ("sam_skel: Couldn't register custom debugging class!\n"));
} else DEBUG(2, ("sam_skel: Debug class number of 'sam_skel': %d\n", sam_skel_debug_level));
if(module_params)
DEBUG(0, ("Starting 'sam_skel' with parameters '%s' for domain %s\n", module_params, sam_methods->domain_name));
else
DEBUG(0, ("Starting 'sam_skel' for domain %s without paramters\n", sam_methods->domain_name));
return NT_STATUS_OK;
}

View File

@ -0,0 +1,62 @@
/*
Unix SMB/CIFS implementation.
SMB parameters and setup, plus a whole lot more.
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.
*/
#ifndef _NT_STATUS_H
#define _NT_STATUS_H
/* The Splint code analysis tool doesn't like immediate structures. */
#ifdef _SPLINT_ /* http://www.splint.org */
#undef HAVE_IMMEDIATE_STRUCTURES
#endif
/* the following rather strange looking definitions of NTSTATUS and WERROR
and there in order to catch common coding errors where different error types
are mixed up. This is especially important as we slowly convert Samba
from using BOOL for internal functions
*/
#if defined(HAVE_IMMEDIATE_STRUCTURES)
typedef struct {uint32 v;} NTSTATUS;
#define NT_STATUS(x) ((NTSTATUS) { x })
#define NT_STATUS_V(x) ((x).v)
#else
typedef uint32 NTSTATUS;
#define NT_STATUS(x) (x)
#define NT_STATUS_V(x) (x)
#endif
#if defined(HAVE_IMMEDIATE_STRUCTURES)
typedef struct {uint32 v;} WERROR;
#define W_ERROR(x) ((WERROR) { x })
#define W_ERROR_V(x) ((x).v)
#else
typedef uint32 WERROR;
#define W_ERROR(x) (x)
#define W_ERROR_V(x) (x)
#endif
#define NT_STATUS_IS_OK(x) (NT_STATUS_V(x) == 0)
#define NT_STATUS_IS_ERR(x) ((NT_STATUS_V(x) & 0xc0000000) == 0xc0000000)
#define NT_STATUS_EQUAL(x,y) (NT_STATUS_V(x) == NT_STATUS_V(y))
#define W_ERROR_IS_OK(x) (W_ERROR_V(x) == 0)
#endif

282
source3/include/sam.h Normal file
View File

@ -0,0 +1,282 @@
/*
Unix SMB/CIFS implementation.
SAM structures
Copyright (C) Kai Krueger 2002
Copyright (C) Stefan (metze) Metzmacher 2002
Copyright (C) Simo Sorce 2002
Copyright (C) Andrew Bartlett 2002
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.
*/
#ifndef _SAM_H
#define _SAM_H
/* We want to track down bugs early */
#if 1
#define SAM_ASSERT(x) SMB_ASSERT(x)
#else
#define SAM_ASSERT(x) while (0) { \
if (!(x)) {
DEBUG(0, ("SAM_ASSERT failed!\n"))
return NT_STATUS_FAIL_CHECK;\
} \
}
#endif
/* let it be 0 until we have a stable interface --metze */
#define SAM_INTERFACE_VERSION 0
/* use this inside a passdb module */
#define SAM_MODULE_VERSIONING_MAGIC \
int sam_version(void)\
{\
return SAM_INTERFACE_VERSION;\
}
/* Backend to use by default when no backend was specified */
#define SAM_DEFAULT_BACKEND "plugin"
typedef struct sam_domain_handle {
TALLOC_CTX *mem_ctx;
uint32 access_granted;
const struct sam_methods *current_sam_methods; /* sam_methods creating this handle */
void (*free_fn)(struct sam_domain_handle **);
struct domain_data {
DOM_SID sid; /*SID of the domain. Should not be changed */
char *name; /* Name of the domain */
char *servername; /* */
NTTIME max_passwordage; /* time till next password expiration */
NTTIME min_passwordage; /* time till password can be changed again */
NTTIME lockout_duration; /* time till login is allowed again after lockout*/
NTTIME reset_count; /* time till bad login counter is reset */
uint16 min_passwordlength; /* minimum number of characters for a password */
uint16 password_history; /* number of passwords stored in history */
uint16 lockout_count; /* number of bad login attempts before lockout */
BOOL force_logoff; /* force logoff after logon hours have expired */
BOOL login_pwdchange; /* Users need to logon to change their password */
uint32 num_accounts; /* number of accounts in the domain */
uint32 num_groups; /* number of global groups */
uint32 num_aliases; /* number of local groups */
} private;
} SAM_DOMAIN_HANDLE;
typedef struct sam_account_handle {
TALLOC_CTX *mem_ctx;
uint32 access_granted;
const struct sam_methods *current_sam_methods; /* sam_methods creating this handle */
void (*free_fn)(struct sam_account_handle **);
struct sam_account_data {
uint32 init_flag;
NTTIME logon_time; /* logon time */
NTTIME logoff_time; /* logoff time */
NTTIME kickoff_time; /* kickoff time */
NTTIME pass_last_set_time; /* password last set time */
NTTIME pass_can_change_time; /* password can change time */
NTTIME pass_must_change_time; /* password must change time */
char * account_name; /* account_name string */
SAM_DOMAIN_HANDLE * domain; /* domain of account */
char *full_name; /* account's full name string */
char *unix_home_dir; /* UNIX home directory string */
char *home_dir; /* home directory string */
char *dir_drive; /* home directory drive string */
char *logon_script; /* logon script string */
char *profile_path; /* profile path string */
char *acct_desc; /* account description string */
char *workstations; /* login from workstations string */
char *unknown_str; /* don't know what this is, yet. */
char *munged_dial; /* munged path name and dial-back tel number */
DOM_SID account_sid; /* Primary Account SID */
DOM_SID group_sid; /* Primary Group SID */
DATA_BLOB lm_pw; /* .data is Null if no password */
DATA_BLOB nt_pw; /* .data is Null if no password */
char *plaintext_pw; /* if Null not available */
uint16 acct_ctrl; /* account info (ACB_xxxx bit-mask) */
uint32 unknown_1; /* 0x00ff ffff */
uint16 logon_divs; /* 168 - number of hours in a week */
uint32 hours_len; /* normally 21 bytes */
uint8 hours[MAX_HOURS_LEN];
uint32 unknown_2; /* 0x0002 0000 */
uint32 unknown_3; /* 0x0000 04ec */
} private;
} SAM_ACCOUNT_HANDLE;
typedef struct sam_group_handle {
TALLOC_CTX *mem_ctx;
uint32 access_granted;
const struct sam_methods *current_sam_methods; /* sam_methods creating this handle */
void (*free_fn)(struct sam_group_handle **);
struct sam_group_data {
char *group_name;
char *group_desc;
DOM_SID sid;
uint16 group_ctrl; /* specifies if the group is a local group or a global group */
uint32 num_members;
} private;
} SAM_GROUP_HANDLE;
typedef struct sam_group_member {
DOM_SID sid;
BOOL group; /* specifies if it is a group or a account */
} SAM_GROUP_MEMBER;
typedef struct sam_account_enum {
DOM_SID sid;
char *account_name;
char *full_name;
char *account_desc;
uint16 acct_ctrl;
} SAM_ACCOUNT_ENUM;
typedef struct sam_group_enum {
DOM_SID sid;
char *group_name;
char *group_desc;
uint16 group_ctrl;
} SAM_GROUP_ENUM;
/* bits for group_ctrl: to spezify if the group is global group or alias */
#define GCB_LOCAL_GROUP 0x0001
#define GCB_ALIAS_GROUP (GCB_LOCAL_GROUP |GCB_BUILTIN)
#define GCB_GLOBAL_GROUP 0x0002
#define GCB_BUILTIN 0x1000
typedef struct sam_context
{
struct sam_methods *methods;
TALLOC_CTX *mem_ctx;
/* General API */
NTSTATUS (*sam_get_sec_desc) (const struct sam_context *, const NT_USER_TOKEN *access_token, const DOM_SID *sid, SEC_DESC **sd);
NTSTATUS (*sam_set_sec_desc) (const struct sam_context *, const NT_USER_TOKEN *access_token, const DOM_SID *sid, const SEC_DESC *sd);
NTSTATUS (*sam_lookup_sid) (const struct sam_context *, const NT_USER_TOKEN *access_token, const DOM_SID *sid, char **name, uint32 *type);
NTSTATUS (*sam_lookup_name) (const struct sam_context *, const NT_USER_TOKEN *access_token, const char *domain, const char *name, DOM_SID **sid, uint32 *type);
/* Domain API */
NTSTATUS (*sam_update_domain) (const struct sam_context *, const SAM_DOMAIN_HANDLE *domain);
NTSTATUS (*sam_enum_domains) (const struct sam_context *, const NT_USER_TOKEN *access_token, int32 *domain_count, DOM_SID **domains, char **domain_names);
NTSTATUS (*sam_lookup_domain) (const struct sam_context *, const NT_USER_TOKEN * access_token, const char *domain, DOM_SID **domainsid);
NTSTATUS (*sam_get_domain_by_sid) (const struct sam_context *, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *domainsid, SAM_DOMAIN_HANDLE **domain);
/* Account API */
NTSTATUS (*sam_create_account) (const struct sam_context *context, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *domainsid, const char *account_name, uint16 acct_ctrl, SAM_ACCOUNT_HANDLE **account);
NTSTATUS (*sam_add_account) (const struct sam_context *, const DOM_SID *domainsid, const SAM_ACCOUNT_HANDLE *account);
NTSTATUS (*sam_update_account) (const struct sam_context *, const SAM_ACCOUNT_HANDLE *account);
NTSTATUS (*sam_delete_account) (const struct sam_context *, const SAM_ACCOUNT_HANDLE *account);
NTSTATUS (*sam_enum_accounts) (const struct sam_context *, const NT_USER_TOKEN *access_token, const DOM_SID *domain, uint16 acct_ctrl, uint32 *account_count, SAM_ACCOUNT_ENUM **accounts);
NTSTATUS (*sam_get_account_by_sid) (const struct sam_context *, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *accountsid, SAM_ACCOUNT_HANDLE **account);
NTSTATUS (*sam_get_account_by_name) (const struct sam_context *, const NT_USER_TOKEN *access_token, uint32 access_desired, const char *domain, const char *name, SAM_ACCOUNT_HANDLE **account);
/* Group API */
NTSTATUS (*sam_create_group) (const struct sam_context *, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *domainsid, const char *group_name, uint16 group_ctrl, SAM_GROUP_HANDLE **group);
NTSTATUS (*sam_add_group) (const struct sam_context *, const DOM_SID *domainsid, const SAM_GROUP_HANDLE *group);
NTSTATUS (*sam_update_group) (const struct sam_context *, const SAM_GROUP_HANDLE *group);
NTSTATUS (*sam_delete_group) (const struct sam_context *, const SAM_GROUP_HANDLE *group);
NTSTATUS (*sam_enum_groups) (const struct sam_context *, const NT_USER_TOKEN *access_token, const DOM_SID *domainsid, const uint16 group_ctrl, uint32 *groups_count, SAM_GROUP_ENUM **groups);
NTSTATUS (*sam_get_group_by_sid) (const struct sam_context *, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *groupsid, SAM_GROUP_HANDLE **group);
NTSTATUS (*sam_get_group_by_name) (const struct sam_context *, const NT_USER_TOKEN *access_token, uint32 access_desired, const char *domain, const char *name, SAM_GROUP_HANDLE **group);
NTSTATUS (*sam_add_member_to_group) (const struct sam_context *, const SAM_GROUP_HANDLE *group, const SAM_GROUP_MEMBER *member);
NTSTATUS (*sam_delete_member_from_group) (const struct sam_context *, const SAM_GROUP_HANDLE *group, const SAM_GROUP_MEMBER *member);
NTSTATUS (*sam_enum_groupmembers) (const struct sam_context *, const SAM_GROUP_HANDLE *group, uint32 *members_count, SAM_GROUP_MEMBER **members);
NTSTATUS (*sam_get_groups_of_sid) (const struct sam_context *, const NT_USER_TOKEN *access_token, const DOM_SID **sids, uint16 group_ctrl, uint32 *group_count, SAM_GROUP_ENUM **groups);
void (*free_fn)(struct sam_context **);
} SAM_CONTEXT;
typedef struct sam_methods
{
struct sam_context *parent;
struct sam_methods *next;
struct sam_methods *prev;
const char *backendname;
const char *domain_name;
DOM_SID domain_sid;
void *private_data;
/* General API */
NTSTATUS (*sam_get_sec_desc) (const struct sam_methods *, const NT_USER_TOKEN *access_token, const DOM_SID *sid, SEC_DESC **sd);
NTSTATUS (*sam_set_sec_desc) (const struct sam_methods *, const NT_USER_TOKEN *access_token, const DOM_SID *sid, const SEC_DESC *sd);
NTSTATUS (*sam_lookup_sid) (const struct sam_methods *, const NT_USER_TOKEN *access_token, const DOM_SID *sid, char **name, uint32 *type);
NTSTATUS (*sam_lookup_name) (const struct sam_methods *, const NT_USER_TOKEN *access_token, const char *name, DOM_SID **sid, uint32 *type);
/* Domain API */
NTSTATUS (*sam_update_domain) (const struct sam_methods *, const SAM_DOMAIN_HANDLE *domain);
NTSTATUS (*sam_get_domain_handle) (const struct sam_methods *, const NT_USER_TOKEN *access_token, uint32 access_desired, SAM_DOMAIN_HANDLE **domain);
/* Account API */
NTSTATUS (*sam_create_account) (const struct sam_methods *, const NT_USER_TOKEN *access_token, uint32 access_desired, const char *account_name, uint16 acct_ctrl, SAM_ACCOUNT_HANDLE **account);
NTSTATUS (*sam_add_account) (const struct sam_methods *, const SAM_ACCOUNT_HANDLE *account);
NTSTATUS (*sam_update_account) (const struct sam_methods *, const SAM_ACCOUNT_HANDLE *account);
NTSTATUS (*sam_delete_account) (const struct sam_methods *, const SAM_ACCOUNT_HANDLE *account);
NTSTATUS (*sam_enum_accounts) (const struct sam_methods *, const NT_USER_TOKEN *access_token, uint16 acct_ctrl, uint32 *account_count, SAM_ACCOUNT_ENUM **accounts);
NTSTATUS (*sam_get_account_by_sid) (const struct sam_methods *, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *accountsid, SAM_ACCOUNT_HANDLE **account);
NTSTATUS (*sam_get_account_by_name) (const struct sam_methods *, const NT_USER_TOKEN *access_token, uint32 access_desired, const char *name, SAM_ACCOUNT_HANDLE **account);
/* Group API */
NTSTATUS (*sam_create_group) (const struct sam_methods *, const NT_USER_TOKEN *access_token, uint32 access_desired, const char *group_name, uint16 group_ctrl, SAM_GROUP_HANDLE **group);
NTSTATUS (*sam_add_group) (const struct sam_methods *, const SAM_GROUP_HANDLE *group);
NTSTATUS (*sam_update_group) (const struct sam_methods *, const SAM_GROUP_HANDLE *group);
NTSTATUS (*sam_delete_group) (const struct sam_methods *, const SAM_GROUP_HANDLE *group);
NTSTATUS (*sam_enum_groups) (const struct sam_methods *, const NT_USER_TOKEN *access_token, uint16 group_ctrl, uint32 *groups_count, SAM_GROUP_ENUM **groups);
NTSTATUS (*sam_get_group_by_sid) (const struct sam_methods *, const NT_USER_TOKEN *access_token, uint32 access_desired, const DOM_SID *groupsid, SAM_GROUP_HANDLE **group);
NTSTATUS (*sam_get_group_by_name) (const struct sam_methods *, const NT_USER_TOKEN *access_token, uint32 access_desired, const char *name, SAM_GROUP_HANDLE **group);
NTSTATUS (*sam_add_member_to_group) (const struct sam_methods *, const SAM_GROUP_HANDLE *group, const SAM_GROUP_MEMBER *member);
NTSTATUS (*sam_delete_member_from_group) (const struct sam_methods *, const SAM_GROUP_HANDLE *group, const SAM_GROUP_MEMBER *member);
NTSTATUS (*sam_enum_groupmembers) (const struct sam_methods *, const SAM_GROUP_HANDLE *group, uint32 *members_count, SAM_GROUP_MEMBER **members);
NTSTATUS (*sam_get_groups_of_sid) (const struct sam_methods *, const NT_USER_TOKEN *access_token, const DOM_SID **sids, uint16 group_ctrl, uint32 *group_count, SAM_GROUP_ENUM **groups);
void (*free_private_data)(void **);
} SAM_METHODS;
typedef NTSTATUS (*sam_init_function)(SAM_METHODS *, const char *);
struct sam_init_function_entry {
char *module_name;
/* Function to create a member of the sam_methods list */
sam_init_function init;
};
typedef struct sam_backend_entry {
char *module_name;
char *module_params;
char *domain_name;
DOM_SID *domain_sid;
} SAM_BACKEND_ENTRY;
#endif /* _SAM_H */

319
source3/lib/gencache.c Normal file
View File

@ -0,0 +1,319 @@
/*
Unix SMB/CIFS implementation.
Generic, persistent and shared between processes cache mechanism for use
by various parts of the Samba code
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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_TDB
#define TIMEOUT_LEN 12
#define CACHE_DATA_FMT "%12u/%s"
static TDB_CONTEXT *cache;
/**
* @file gencache.c
* @brief Generic, persistent and shared between processes cache mechanism
* for use by various parts of the Samba code
*
**/
/**
* Cache initialisation function. Opens cache tdb file or creates
* it if does not exist.
*
* @return true on successful initialisation of the cache or
* false on failure
**/
BOOL gencache_init(void)
{
char* cache_fname = NULL;
/* skip file open if it's already opened */
if (cache) return True;
asprintf(&cache_fname, "%s/%s", lp_lockdir(), "gencache.tdb");
if (cache_fname)
DEBUG(5, ("Opening cache file at %s\n", cache_fname));
else {
DEBUG(0, ("Filename allocation failed.\n"));
return False;
}
cache = tdb_open_log(cache_fname, 0, TDB_DEFAULT,
O_RDWR|O_CREAT, 0644);
SAFE_FREE(cache_fname);
if (!cache) {
DEBUG(0, ("Attempt to open the cache file has failed.\n"));
return False;
}
return True;
}
/**
* Cache shutdown function. Closes opened cache tdb file.
*
* @return true on successful closing the cache or
* false on failure during cache shutdown
**/
BOOL gencache_shutdown(void)
{
/* tdb_close routine returns 0 on successful close */
if (!cache) return False;
DEBUG(5, ("Closing cache file\n"));
return tdb_close(cache) ? False : True;
}
/**
* Add one entry to the cache file.
* (it part of tridge's proposed API)
*
* @param key string that represents a key of this entry
* @param value text representation value being cached
* @param timeout time when the value is expired
*
* @return true when entry is successfuly stored or
* false on the attempt's failure
**/
BOOL gencache_add(const char *keystr, const char *value, time_t timeout)
{
int ret;
TDB_DATA keybuf, databuf;
char* valstr = NULL;
/* fail completely if get null pointers passed */
SMB_ASSERT(keystr && value);
if (!gencache_init()) return False;
asprintf(&valstr, CACHE_DATA_FMT, (int)timeout, value);
keybuf.dptr = strdup(keystr);
keybuf.dsize = strlen(keystr);
databuf.dptr = strdup(valstr);
databuf.dsize = strlen(valstr);
DEBUG(10, ("Adding cache entry with key = %s; value = %s and timeout \
= %s (%d seconds %s)\n", keybuf.dptr, value, ctime(&timeout),
(int)(timeout - time(NULL)), timeout > time(NULL) ? "ahead" : "in the past"));
ret = tdb_store(cache, keybuf, databuf, TDB_INSERT);
SAFE_FREE(valstr);
SAFE_FREE(keybuf.dptr);
SAFE_FREE(databuf.dptr);
return ret == 0 ? True : False;
}
/**
* Set existing entry to the cache file.
* (it part of tridge's proposed API)
*
* @param key string that represents a key of this entry
* @param value text representation value being cached
* @param timeout time when the value is expired
*
* @return true when entry is successfuly set or
* false on the attempt's failure
**/
BOOL gencache_set(const char *keystr, const char *valstr, time_t timeout)
{
int ret = -1;
TDB_DATA keybuf, databuf;
char *old_valstr, *datastr;
time_t old_timeout;
/* fail completely if get null pointers passed */
SMB_ASSERT(keystr && valstr);
if (!gencache_init()) return False;
/*
* Check whether entry exists in the cache
* Don't verify gencache_get exit code, since the entry may be expired
*/
gencache_get(keystr, &old_valstr, &old_timeout);
if (!(old_valstr && old_timeout)) return False;
DEBUG(10, ("Setting cache entry with key = %s; old value = %s and old timeout \
= %s\n", keystr, old_valstr, ctime(&old_timeout)));
asprintf(&datastr, CACHE_DATA_FMT, (int)timeout, valstr);
keybuf.dptr = strdup(keystr);
keybuf.dsize = strlen(keystr);
databuf.dptr = strdup(datastr);
databuf.dsize = strlen(datastr);
DEBUGADD(10, ("New value = %s, new timeout = %s (%d seconds %s)", valstr,
ctime(&timeout), (int)(timeout - time(NULL)),
timeout > time(NULL) ? "ahead" : "in the past"));
ret = tdb_store(cache, keybuf, databuf, TDB_REPLACE);
SAFE_FREE(datastr);
SAFE_FREE(old_valstr);
SAFE_FREE(keybuf.dptr);
SAFE_FREE(databuf.dptr);
return ret == 0 ? True : False;
}
/**
* Delete one entry from the cache file.
* (it part of tridge's proposed API)
*
* @param key string that represents a key of this entry
*
* @return true upon successful deletion or
* false in case of failure
**/
BOOL gencache_del(const char *keystr)
{
int ret;
TDB_DATA keybuf;
/* fail completely if get null pointers passed */
SMB_ASSERT(keystr);
if (!gencache_init()) return False;
keybuf.dptr = strdup(keystr);
keybuf.dsize = strlen(keystr);
DEBUG(10, ("Deleting cache entry (key = %s)\n", keystr));
ret = tdb_delete(cache, keybuf);
SAFE_FREE(keybuf.dptr);
return ret == 0 ? True : False;
}
/**
* Get existing entry from the cache file.
* (it part of tridge's proposed API)
*
* @param key string that represents a key of this entry
* @param value buffer that is allocated and filled with the entry value
* buffer's disposing is done outside
* @param timeout pointer to a time_t that is filled with entry's
* timeout
*
* @return true when entry is successfuly fetched or
* false on the failure
**/
BOOL gencache_get(const char *keystr, char **valstr, time_t *timeout)
{
TDB_DATA keybuf, databuf;
/* fail completely if get null pointers passed */
SMB_ASSERT(keystr && valstr && timeout);
if (!gencache_init()) return False;
keybuf.dptr = strdup(keystr);
keybuf.dsize = strlen(keystr);
databuf = tdb_fetch(cache, keybuf);
if (databuf.dptr) {
char* entry_buf = strndup(databuf.dptr, databuf.dsize);
*valstr = (char*)malloc(sizeof(char) * (databuf.dsize - TIMEOUT_LEN));
sscanf(entry_buf, CACHE_DATA_FMT, (int*)timeout, *valstr);
SAFE_FREE(entry_buf);
DEBUG(10, ("Returning %s cache entry: key = %s, value = %s, timeout = %s\n",
*timeout > time(NULL) ? "valid" : "expired", keystr, *valstr,
ctime(timeout)));
return *timeout > time(NULL);
} else {
*valstr = NULL;
timeout = NULL;
DEBUG(10, ("Cache entry with key = %s couldn't be found\n", keystr));
return False;
}
}
/**
* Iterate through all entries which key matches to specified pattern
*
* @param fn pointer to the function that will be supplied with each single
* matching cache entry (key, value and timeout) as an arguments
* @param keystr_pattern pattern the existing entries' keys are matched to
*
**/
void gencache_iterate(void (*fn)(const char* key, const char *value, time_t timeout),
const char* keystr_pattern)
{
TDB_LIST_NODE *node, *first_node;
TDB_DATA databuf;
char *keystr = NULL, *valstr = NULL, *entry = NULL;
time_t timeout = 0;
/* fail completely if get null pointers passed */
SMB_ASSERT(fn && keystr_pattern);
if (!gencache_init()) return;
DEBUG(5, ("Searching cache keys with pattern %s", keystr_pattern));
node = tdb_search_keys(cache, keystr_pattern);
first_node = node;
while (node) {
/* ensure null termination of the key string */
node->node_key.dptr[node->node_key.dsize] = '\0';
keystr = node->node_key.dptr;
/*
* We don't use gencache_get function, because we need to iterate through
* all of the entries. Validity verification is up to fn routine.
*/
databuf = tdb_fetch(cache, node->node_key);
entry = strndup(databuf.dptr, databuf.dsize);
valstr = (char*)malloc(sizeof(char) * (databuf.dsize - TIMEOUT_LEN));
sscanf(entry, CACHE_DATA_FMT, (int*)(&timeout), valstr);
DEBUG(10, ("Calling function with arguments (key = %s, value = %s, timeout = %s)\n",
keystr, valstr, ctime(&timeout)));
fn(keystr, valstr, timeout);
SAFE_FREE(valstr);
SAFE_FREE(entry);
node = node->next;
}
tdb_search_list_free(first_node);
}

302
source3/lib/sendfile.c Normal file
View File

@ -0,0 +1,302 @@
/*
Unix SMB/Netbios implementation.
Version 2.2.x / 3.0.x
sendfile implementations.
Copyright (C) Jeremy Allison 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 file handles the OS dependent sendfile implementations.
* The API is such that it returns -1 on error, else returns the
* number of bytes written.
*/
#include "includes.h"
#if defined(LINUX_SENDFILE_API)
#include <sys/sendfile.h>
#ifndef MSG_MORE
#define MSG_MORE 0x8000
#endif
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
{
size_t total=0;
ssize_t ret;
ssize_t hdr_len = 0;
/*
* Send the header first.
* Use MSG_MORE to cork the TCP output until sendfile is called.
*/
if (header) {
hdr_len = header->length;
while (total < hdr_len) {
ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE);
if (ret == -1)
return -1;
total += ret;
}
}
total = count;
while (total) {
ssize_t nwritten;
do {
#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64)
nwritten = sendfile64(tofd, fromfd, &offset, total);
#else
nwritten = sendfile(tofd, fromfd, &offset, total);
#endif
} while (nwritten == -1 && errno == EINTR);
if (nwritten == -1)
return -1;
if (nwritten == 0)
return -1; /* I think we're at EOF here... */
total -= nwritten;
}
return count + hdr_len;
}
#elif defined(LINUX_BROKEN_SENDFILE_API)
/*
* We must use explicit 32 bit types here. This code path means Linux
* won't do proper 64-bit sendfile. JRA.
*/
extern int32 sendfile (int out_fd, int in_fd, int32 *offset, uint32 count);
#ifndef MSG_MORE
#define MSG_MORE 0x8000
#endif
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
{
size_t total=0;
ssize_t ret;
ssize_t hdr_len = 0;
uint32 small_total = 0;
int32 small_offset;
/*
* Fix for broken Linux 2.4 systems with no working sendfile64().
* If the offset+count > 2 GB then pretend we don't have the
* system call sendfile at all. The upper layer catches this
* and uses a normal read. JRA.
*/
if ((sizeof(SMB_OFF_T) >= 8) && (offset + count > (SMB_OFF_T)0x7FFFFFFF)) {
errno = ENOSYS;
return -1;
}
/*
* Send the header first.
* Use MSG_MORE to cork the TCP output until sendfile is called.
*/
if (header) {
hdr_len = header->length;
while (total < hdr_len) {
ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE);
if (ret == -1)
return -1;
total += ret;
}
}
small_total = (uint32)count;
small_offset = (int32)offset;
while (small_total) {
int32 nwritten;
do {
nwritten = sendfile(tofd, fromfd, &small_offset, small_total);
} while (nwritten == -1 && errno == EINTR);
if (nwritten == -1)
return -1;
if (nwritten == 0)
return -1; /* I think we're at EOF here... */
small_total -= nwritten;
}
return count + hdr_len;
}
#elif defined(SOLARIS_SENDFILE_API)
/* Hmmm. Can't find Solaris sendfile API docs.... Where is it ? */
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
{
errno = ENOSYS;
return -1;
}
#elif defined(HPUX_SENDFILE_API)
#include <sys/socket.h>
#include <sys/uio.h>
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
{
size_t total=0;
struct iovec hdtrl[2];
size_t hdr_len = 0;
if (header) {
/* Set up the header/trailer iovec. */
hdtrl[0].iov_base = header->data;
hdtrl[0].iov_len = hdr_len = header->length;
} else {
hdtrl[0].iov_base = NULL;
hdtrl[0].iov_len = hdr_len = 0;
}
hdtrl[1].iov_base = NULL;
hdtrl[1].iov_base = 0;
total = count;
while (total + hdtrl[0].iov_len) {
ssize_t nwritten;
/*
* HPUX guarantees that if any data was written before
* a signal interrupt then sendfile returns the number of
* bytes written (which may be less than requested) not -1.
* nwritten includes the header data sent.
*/
do {
#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64)
nwritten = sendfile64(tofd, fromfd, offset, total, &hdtrl[0], 0);
#else
nwritten = sendfile(tofd, fromfd, offset, total, &hdtrl[0], 0);
#endif
} while (nwritten == -1 && errno == EINTR);
if (nwritten == -1)
return -1;
if (nwritten == 0)
return -1; /* I think we're at EOF here... */
/*
* If this was a short (signal interrupted) write we may need
* to subtract it from the header data, or null out the header
* data altogether if we wrote more than hdtrl[0].iov_len bytes.
* We change nwritten to be the number of file bytes written.
*/
if (hdtrl[0].iov_base && hdtrl[0].iov_len) {
if (nwritten >= hdtrl[0].iov_len) {
nwritten -= hdtrl[0].iov_len;
hdtrl[0].iov_base = NULL;
hdtrl[0].iov_len = 0;
} else {
nwritten = 0;
/* iov_base is defined as a void *... */
hdtrl[0].iov_base = ((char *)hdtrl[0].iov_base) + nwritten;
hdtrl[0].iov_len -= nwritten;
}
}
total -= nwritten;
offset += nwritten;
}
return count + hdr_len;
}
#elif defined(FREEBSD_SENDFILE_API)
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
{
size_t total=0;
struct sf_hdtr hdr;
struct iovec hdtrl;
size_t hdr_len = 0;
hdr.headers = &hdtrl;
hdr.hdr_cnt = 1;
hdr.trailers = NULL;
hdr.trl_cnt = 0;
/* Set up the header iovec. */
if (header) {
hdtrl.iov_base = header->data;
hdtrl.iov_len = hdr_len = header->length;
} else {
hdtrl.iov_base = NULL;
hdtrl.iov_len = 0;
}
total = count;
while (total + hdtrl.iov_len) {
SMB_OFF_T nwritten;
int ret;
/*
* FreeBSD sendfile returns 0 on success, -1 on error.
* Remember, the tofd and fromfd are reversed..... :-).
* nwritten includes the header data sent.
*/
do {
ret = sendfile(fromfd, tofd, offset, total, &hdr, &nwritten, 0);
} while (ret == -1 && errno == EINTR);
if (ret == -1)
return -1;
if (nwritten == 0)
return -1; /* I think we're at EOF here... */
/*
* If this was a short (signal interrupted) write we may need
* to subtract it from the header data, or null out the header
* data altogether if we wrote more than hdtrl.iov_len bytes.
* We change nwritten to be the number of file bytes written.
*/
if (hdtrl.iov_base && hdtrl.iov_len) {
if (nwritten >= hdtrl.iov_len) {
nwritten -= hdtrl.iov_len;
hdtrl.iov_base = NULL;
hdtrl.iov_len = 0;
} else {
nwritten = 0;
hdtrl.iov_base += nwritten;
hdtrl.iov_len -= nwritten;
}
}
total -= nwritten;
offset += nwritten;
}
return count + hdr_len;
}
#else /* No sendfile implementation. Return error. */
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
{
/* No sendfile syscall. */
errno = ENOSYS;
return -1;
}
#endif

171
source3/libads/ads_utils.c Normal file
View File

@ -0,0 +1,171 @@
/*
Unix SMB/CIFS implementation.
ads (active directory) utility library
Copyright (C) Stefan (metze) Metzmacher 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"
#ifdef HAVE_ADS
/*
translated the ACB_CTRL Flags to UserFlags (userAccountControl)
*/
uint32 ads_acb2uf(uint16 acb)
{
uint32 uf = 0x00000000;
if (acb & ACB_DISABLED) uf |= UF_ACCOUNTDISABLE;
if (acb & ACB_HOMDIRREQ) uf |= UF_HOMEDIR_REQUIRED;
if (acb & ACB_PWNOTREQ) uf |= UF_PASSWD_NOTREQD;
if (acb & ACB_TEMPDUP) uf |= UF_TEMP_DUPLICATE_ACCOUNT;
if (acb & ACB_NORMAL) uf |= UF_NORMAL_ACCOUNT;
if (acb & ACB_MNS) uf |= UF_MNS_LOGON_ACCOUNT;
if (acb & ACB_DOMTRUST) uf |= UF_INTERDOMAIN_TRUST_ACCOUNT;
if (acb & ACB_WSTRUST) uf |= UF_WORKSTATION_TRUST_ACCOUNT;
if (acb & ACB_SVRTRUST) uf |= UF_SERVER_TRUST_ACCOUNT;
if (acb & ACB_PWNOEXP) uf |= UF_DONT_EXPIRE_PASSWD;
if (acb & ACB_AUTOLOCK) uf |= UF_LOCKOUT;
return uf;
}
/*
translated the UserFlags (userAccountControl) to ACB_CTRL Flags
*/
uint16 ads_uf2acb(uint32 uf)
{
uint16 acb = 0x0000;
if (uf & UF_ACCOUNTDISABLE) acb |= ACB_DISABLED;
if (uf & UF_HOMEDIR_REQUIRED) acb |= ACB_HOMDIRREQ;
if (uf & UF_PASSWD_NOTREQD) acb |= ACB_PWNOTREQ;
if (uf & UF_MNS_LOGON_ACCOUNT) acb |= ACB_MNS;
if (uf & UF_DONT_EXPIRE_PASSWD) acb |= ACB_PWNOEXP;
if (uf & UF_LOCKOUT) acb |= ACB_AUTOLOCK;
switch (uf & UF_ACCOUNT_TYPE_MASK)
{
case UF_TEMP_DUPLICATE_ACCOUNT: acb |= ACB_TEMPDUP;break;
case UF_NORMAL_ACCOUNT: acb |= ACB_NORMAL;break;
case UF_INTERDOMAIN_TRUST_ACCOUNT: acb |= ACB_DOMTRUST;break;
case UF_WORKSTATION_TRUST_ACCOUNT: acb |= ACB_WSTRUST;break;
case UF_SERVER_TRUST_ACCOUNT: acb |= ACB_SVRTRUST;break;
/*Fix Me: what should we do here? */
default: acb |= ACB_NORMAL;break;
}
return acb;
}
/*
get the accountType from the UserFlags
*/
uint32 ads_uf2atype(uint32 uf)
{
uint32 atype = 0x00000000;
if (uf & UF_NORMAL_ACCOUNT) atype = ATYPE_NORMAL_ACCOUNT;
else if (uf & UF_TEMP_DUPLICATE_ACCOUNT) atype = ATYPE_NORMAL_ACCOUNT;
else if (uf & UF_SERVER_TRUST_ACCOUNT) atype = ATYPE_WORKSTATION_TRUST;
else if (uf & UF_WORKSTATION_TRUST_ACCOUNT) atype = ATYPE_WORKSTATION_TRUST;
else if (uf & UF_INTERDOMAIN_TRUST_ACCOUNT) atype = ATYPE_INTERDOMAIN_TRUST;
return atype;
}
/*
translated the GROUP_CTRL Flags to GroupType (groupType)
*/
uint32 ads_gcb2gtype(uint16 gcb)
{
uint32 gtype = 0x00000000;
if (gcb & GCB_ALIAS_GROUP) gtype |= GTYPE_SECURITY_BUILTIN_LOCAL_GROUP;
else if(gcb & GCB_LOCAL_GROUP) gtype |= GTYPE_SECURITY_DOMAIN_LOCAL_GROUP;
if (gcb & GCB_GLOBAL_GROUP) gtype |= GTYPE_SECURITY_GLOBAL_GROUP;
return gtype;
}
/*
translated the GroupType (groupType) to GROUP_CTRL Flags
*/
uint16 ads_gtype2gcb(uint32 gtype)
{
uint16 gcb = 0x0000;
switch(gtype) {
case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP:
gcb = GCB_ALIAS_GROUP;
break;
case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP:
gcb = GCB_LOCAL_GROUP;
break;
case GTYPE_SECURITY_GLOBAL_GROUP:
gcb = GCB_GLOBAL_GROUP;
break;
case GTYPE_DISTRIBUTION_GLOBAL_GROUP:
gcb = GCB_GLOBAL_GROUP;
break;
case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP:
gcb = GCB_LOCAL_GROUP;
break;
case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP:
gcb = GCB_GLOBAL_GROUP;
break;
}
return gcb;
}
/*
get the accountType from the groupType
*/
uint32 ads_gtype2atype(uint32 gtype)
{
uint32 atype = 0x00000000;
switch(gtype) {
case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP:
atype = ATYPE_SECURITY_LOCAL_GROUP;
break;
case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP:
atype = ATYPE_SECURITY_LOCAL_GROUP;
break;
case GTYPE_SECURITY_GLOBAL_GROUP:
atype = ATYPE_SECURITY_GLOBAL_GROUP;
break;
case GTYPE_DISTRIBUTION_GLOBAL_GROUP:
atype = ATYPE_DISTRIBUTION_GLOBAL_GROUP;
break;
case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP:
atype = ATYPE_DISTRIBUTION_UNIVERSAL_GROUP;
break;
case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP:
atype = ATYPE_DISTRIBUTION_LOCAL_GROUP;
break;
}
return atype;
}
#endif

View File

@ -0,0 +1,16 @@
#include "winbind_nss_config.h"
#include "winbindd_nss.h"
void init_request(struct winbindd_request *req,int rq_type);
NSS_STATUS winbindd_send_request(int req_type,
struct winbindd_request *request);
NSS_STATUS winbindd_get_response(struct winbindd_response *response);
NSS_STATUS winbindd_request(int req_type,
struct winbindd_request *request,
struct winbindd_response *response);
int winbind_open_pipe_sock(void);
int write_sock(void *buffer, int count);
int read_reply(struct winbindd_response *response);
void close_sock(void);
void free_response(struct winbindd_response *response);

View File

@ -0,0 +1 @@
*.pyc

28
source3/python/README Normal file
View File

@ -0,0 +1,28 @@
This directory contains Python bindings to allow you to access various
aspects of Samba. At the moment their status is "experimental" and
they are not built by default.
In order to be able to compile samba-python you need to have python
and the python-dev packages installed.
Python libraries are always built for a particular version of Python
(2.2, 2.1, etc), and libraries built for one version will not be seen
by another. By default Samba's libraries are built for whatever is
installed as "python" on your $PATH, but you can override this using
the --with-python option. For example
$ ./configure --with-python=python2.2
To build:
$ autoconf
$ ./configure
$ make python_ext
Now, you can install the modules:
$ cp build/lib.*/*.so /usr/lib/python2.1/lib-dynload/
(the directory /usr/lib/python2.1 may vary, depending on your installation)
Samba-python should work now!

View File

@ -0,0 +1,34 @@
#!/usr/bin/python
#
# Display the changeid for a list of printers given on the command line
#
# Sample usage:
#
# changeid.py '\\win2kdc1\magpie'
#
import sys
from samba import spoolss
if len(sys.argv) == 1:
print "Usage: changeid.py <printername>"
sys.exit(1)
for printer in sys.argv[1:]:
# Open printer handle
try:
hnd = spoolss.openprinter(printer)
except:
print "error opening printer %s" % printer
sys.exit(1)
# Fetch and display changeid
info = hnd.getprinter(level = 0)
print info["change_id"]
# Clean up
spoolss.closeprinter(hnd)

View File

@ -0,0 +1,36 @@
#!/usr/bin/env python
#
# Display information on all printers on a print server. Defaults to
# printer info level 1.
#
# Example: enumprinters.py win2kdc1
#
import sys
from samba import spoolss
if len(sys.argv) < 2 or len(sys.argv) > 3:
print "Usage: enumprinters.py <servername> [infolevel]"
sys.exit(1)
printserver = sys.argv[1]
level = 1
if len(sys.argv) == 3:
level = int(sys.argv[2])
# Get list of printers
try:
printer_list = spoolss.enumprinters("\\\\%s" % printserver)
except:
print "error enumerating printers on %s" % printserver
sys.exit(1)
# Display basic info
for printer in printer_list:
h = spoolss.openprinter("\\\\%s\\%s" % (printserver, printer))
info = h.getprinter(level = level)
print "Printer info %d for %s: %s" % (level, printer, info)
print

View File

@ -0,0 +1,88 @@
#!/usr/bin/env python
#
# Get or set the security descriptor on a printer
#
import sys, re, string
from samba import spoolss
if len(sys.argv) != 3:
print "Usage: psec.py getsec|setsec printername"
sys.exit(1)
op = sys.argv[1]
printername = sys.argv[2]
# Display security descriptor
if op == "getsec":
try:
hnd = spoolss.openprinter(printername)
except:
print "error opening printer %s" % printername
sys.exit(1)
secdesc = hnd.getprinter(level = 3)["security_descriptor"]
print secdesc["owner_sid"]
print secdesc["group_sid"]
for acl in secdesc["dacl"]["ace_list"]:
print "%d %d 0x%08x %s" % (acl["type"], acl["flags"],
acl["mask"], acl["trustee"])
spoolss.closeprinter(hnd)
sys.exit(0)
# Set security descriptor
if op == "setsec":
# Open printer
try:
hnd = spoolss.openprinter(printername,
creds = {"domain": "NPSD-TEST2",
"username": "Administrator",
"password": "penguin"})
except:
print "error opening printer %s" % printername
sys.exit(1)
# Read lines from standard input and build security descriptor
lines = sys.stdin.readlines()
secdesc = {}
secdesc["owner_sid"] = lines[0]
secdesc["group_sid"] = lines[1]
secdesc["revision"] = 1
secdesc["dacl"] = {}
secdesc["dacl"]["revision"] = 2
secdesc["dacl"]["ace_list"] = []
for acl in lines[2:]:
match = re.match("(\d+) (\d+) (0[xX][\dA-Fa-f]+) (\S+)", acl)
secdesc["dacl"]["ace_list"].append(
{"type": int(match.group(1)), "flags": int(match.group(2)),
"mask": string.atoi(match.group(3), 0), "trustee": match.group(4)})
# Build info3 structure
info3 = {}
info3["flags"] = 0x8004 # self-relative, dacl present
info3["level"] = 3
info3["security_descriptor"] = secdesc
hnd.setprinter(info3)
spoolss.closeprinter(hnd)
sys.exit(0)
print "invalid operation %s" % op
sys.exit(1)

View File

@ -0,0 +1,12 @@
#! /usr/bin/python2.2
def run_trial():
# import tdbutil
from samba.tdbpack import pack
for i in xrange(500000):
pack("ddffd", (10, 2, "mbp", "martin", 0))
#s = "\n\0\0\0" + "\x02\0\0\0" + "mbp\0" + "martin\0" + "\0\0\0\0"
if __name__ == '__main__':
run_trial()

View File

@ -0,0 +1,195 @@
#! /usr/bin/env python2.2
__doc__ = """test case for samba.tdbkpack functions
tdbpack provides a means of pickling values into binary formats
compatible with that used by the samba tdbpack()/tdbunpack()
functions.
Numbers are always stored in little-endian format; strings are stored
in either DOS or Unix codepage as appropriate.
The format for any particular element is encoded as a short ASCII
string, with one character per field."""
# Copyright (C) 2002 Hewlett-Packard.
__author__ = 'Martin Pool <mbp@sourcefrog.net>'
import unittest
# import tdbutil
import samba.tdbpack
packer = samba.tdbpack.pack
unpacker = samba.tdbpack.unpack
class PackTests(unittest.TestCase):
symm_cases = [('B', ['hello' * 51], '\xff\0\0\0' + 'hello' * 51),
('w', [42], '\x2a\0'),
('www', [42, 2, 69], '\x2a\0\x02\0\x45\0'),
('wd', [42, 256], '\x2a\0\0\x01\0\0'),
('w', [0], '\0\0'),
('w', [255], '\xff\0'),
('w', [256], '\0\x01'),
('w', [0xdead], '\xad\xde'),
('w', [0xffff], '\xff\xff'),
('p', [0], '\0\0\0\0'),
('p', [1], '\x01\0\0\0'),
('d', [0x01020304], '\x04\x03\x02\x01'),
('d', [0x7fffffff], '\xff\xff\xff\x7f'),
('d', [0x80000000], '\x00\x00\x00\x80'),
('d', [-1], '\xff\xff\xff\xff'),
('d', [-255], '\x01\xff\xff\xff'),
('d', [-256], '\x00\xff\xff\xff'),
('ddd', [1, 10, 50], '\x01\0\0\0\x0a\0\0\0\x32\0\0\0'),
('ff', ['hello', 'world'], 'hello\0world\0'),
('fP', ['hello', 'world'], 'hello\0world\0'),
('PP', ['hello', 'world'], 'hello\0world\0'),
('B', [''], '\0\0\0\0'),
('B', ['hello'], '\x05\0\0\0hello'),
('BB', ['hello\0world', 'now'],
'\x0b\0\0\0hello\0world\x03\0\0\0now'),
('pd', [1, 10], '\x01\0\0\0\x0a\0\0\0'),
('BBB', ['hello', '', 'world'],
'\x05\0\0\0hello\0\0\0\0\x05\0\0\0world'),
# strings are sequences in Python, there's no getting away
# from it
('ffff', 'evil', 'e\0v\0i\0l\0'),
('BBBB', 'evil',
'\x01\0\0\0e'
'\x01\0\0\0v'
'\x01\0\0\0i'
'\x01\0\0\0l'),
('', [], ''),
# exercise some long strings
('PP', ['hello' * 255, 'world' * 255],
'hello' * 255 + '\0' + 'world' * 255 + '\0'),
('PP', ['hello' * 40000, 'world' * 50000],
'hello' * 40000 + '\0' + 'world' * 50000 + '\0'),
('B', ['hello' * 51], '\xff\0\0\0' + 'hello' * 51),
('BB', ['hello' * 40000, 'world' * 50000],
'\x40\x0d\x03\0' + 'hello' * 40000 + '\x90\xd0\x03\x00' + 'world' * 50000),
]
def test_symmetric(self):
"""Cookbook of symmetric pack/unpack tests
"""
for format, values, expected in self.symm_cases:
self.assertEquals(packer(format, values), expected)
out, rest = unpacker(format, expected)
self.assertEquals(rest, '')
self.assertEquals(list(values), list(out))
def test_pack(self):
"""Cookbook of expected pack values
These can't be used for the symmetric test because the unpacked value is
not "canonical".
"""
cases = [('w', (42,), '\x2a\0'),
('p', [None], '\0\0\0\0'),
('p', ['true'], '\x01\0\0\0'),
('w', {1: 'fruit'}, '\x01\0'),
# passing a dictionary is dodgy, but it gets coerced to keys
# as if you called list()
]
for format, values, expected in cases:
self.assertEquals(packer(format, values), expected)
def test_unpack_extra(self):
# Test leftover data
for format, values, packed in self.symm_cases:
out, rest = unpacker(format, packed + 'hello sailor!')
self.assertEquals(rest, 'hello sailor!')
self.assertEquals(list(values), list(out))
def test_unpack(self):
"""Cookbook of tricky unpack tests"""
cases = [
]
for format, values, expected in cases:
out, rest = unpacker(format, expected)
self.assertEquals(rest, '')
self.assertEquals(list(values), list(out))
def test_pack_failures(self):
"""Expected errors for incorrect packing"""
cases = [('w', [], IndexError),
('w', (), IndexError),
('w', {}, IndexError),
('ww', [2], IndexError),
('w', 2, TypeError),
('', [1, 2, 3], IndexError),
('w', None, TypeError),
('wwwwwwwwwwww', [], IndexError),
('w', [2, 3], IndexError),
('w', [0x60A15EC5L], TypeError),
('w', [None], TypeError),
('w', xrange(10000), IndexError),
('d', [], IndexError),
('d', [0L], TypeError),
('p', [], IndexError),
('f', [2], TypeError),
('P', [None], TypeError),
('P', (), IndexError),
('f', [packer], TypeError),
('fw', ['hello'], IndexError),
('f', [u'hello'], TypeError),
('B', [2], TypeError),
(None, [2, 3, 4], TypeError),
(ord('f'), [20], TypeError),
(['w', 'w'], [2, 2], TypeError),
('Q', [2], ValueError),
('fQ', ['2', 3], ValueError),
('fQ', ['2'], IndexError),
(2, [2], TypeError),
({}, {}, TypeError)]
for format, values, throwable_class in cases:
def do_pack():
packer(format, values)
self.assertRaises(throwable_class, do_pack)
def test_unpack_failures(self):
"""Expected errors for incorrect unpacking"""
cases = [('$', '', ValueError),
('Q', '', ValueError),
('Q$', '', ValueError),
('f', '', IndexError),
('d', '', IndexError),
('d', '2', IndexError),
('d', '22', IndexError),
('d', '222', IndexError),
('w', '', IndexError),
('w', '2', IndexError),
('f', 'hello', IndexError),
('f', '', IndexError),
('p', '\x01\0', IndexError),
('B', '\xff\0\0\0hello', IndexError),
('B', '\xff\0', IndexError),
('B', '\x01\0\0\0', IndexError),
('B', '\x05\0\0\0hell', IndexError),
('B', '\xff\xff\xff\xff', ValueError),
('B', 'foobar', IndexError),
('BB', '\x01\0\0\0a\x01', IndexError),
]
for format, values, throwable_class in cases:
def do_unpack():
unpacker(format, values)
self.assertRaises(throwable_class, do_unpack)
if __name__ == '__main__':
unittest.main()

39
source3/python/gprinterdata Executable file
View File

@ -0,0 +1,39 @@
#!/usr/bin/env python
import sys
from gtkdictbrowser import GtkDictBrowser, hex_string
import gtk
from samba import spoolss
import string
import printerdata
# Initialise printerdata dictionary
if len(sys.argv) < 2 or len(sys.argv) > 3:
print "Usage: gprinterdata [--ex] <printer>"
print "where <printer> is a UNC printer name."
sys.exit(1)
try:
host = string.replace(sys.argv[len(sys.argv) - 1], "/", "\\")
if sys.argv[1] == "--ex":
t = printerdata.printerdata_ex(host)
else:
t = printerdata.printerdata(host)
except:
print "gprinterdata: error opening %s" % sys.argv[len(sys.argv) - 1]
sys.exit(1)
# Create interface
db = GtkDictBrowser(t)
db.register_get_value_text_fn("", hex_string)
db.build_ui('gprinterdata')
# Override Python's handling of ctrl-c so we can break out of the
# gui from the command line.
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
gtk.mainloop()

39
source3/python/gtdbtool Executable file
View File

@ -0,0 +1,39 @@
#!/usr/bin/env python
import sys
from gtkdictbrowser import GtkDictBrowser
import gtk
from samba import tdb
import string
# Open handle on tdb
if len(sys.argv) != 2:
print "Usage: gdbtool <tdbfile>"
sys.exit(1)
try:
t = tdb.open(sys.argv[1])
except tdb.error, t:
print "gtdbtool: error opening %s: %s" % (sys.argv[1], t)
sys.exit(1)
# Create interface
db = GtkDictBrowser(t)
def display_key_x00(key):
"""Remove \x00 from all keys as they mucks up GTK."""
return string.replace(key, "\x00", "")
db.register_get_key_text_fn(display_key_x00)
db.build_ui('gtdbtool')
# Override Python's handling of ctrl-c so we can break out of the
# gui from the command line.
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
gtk.mainloop()

272
source3/python/gtkdictbrowser.py Executable file
View File

@ -0,0 +1,272 @@
#!/usr/bin/python
#
# Browse a Python dictionary in a two pane graphical interface written
# in GTK.
#
# The GtkDictBrowser class is supposed to be generic enough to allow
# applications to override enough methods and produce a
# domain-specific browser provided the information is presented as a
# Python dictionary.
#
# Possible applications:
#
# - Windows registry browser
# - SPOOLSS printerdata browser
# - tdb file browser
#
from gtk import *
import string, re
class GtkDictBrowser:
def __init__(self, dict):
self.dict = dict
# This variable stores a list of (regexp, function) used to
# convert the raw value data to a displayable string.
self.get_value_text_fns = []
self.get_key_text = lambda x: x
# We can filter the list of keys displayed using a regex
self.filter_regex = ""
# Create and configure user interface widgets. A string argument is
# used to set the window title.
def build_ui(self, title):
win = GtkWindow()
win.set_title(title)
win.connect("destroy", mainquit)
hpaned = GtkHPaned()
win.add(hpaned)
hpaned.set_border_width(5)
hpaned.show()
vbox = GtkVBox()
hpaned.add1(vbox)
vbox.show()
scrolled_win = GtkScrolledWindow()
scrolled_win.set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC)
vbox.pack_start(scrolled_win)
scrolled_win.show()
hbox = GtkHBox()
vbox.pack_end(hbox, expand = 0, padding = 5)
hbox.show()
label = GtkLabel("Filter:")
hbox.pack_start(label, expand = 0, padding = 5)
label.show()
self.entry = GtkEntry()
hbox.pack_end(self.entry, padding = 5)
self.entry.show()
self.entry.connect("activate", self.filter_activated)
self.list = GtkList()
self.list.set_selection_mode(SELECTION_MULTIPLE)
self.list.set_selection_mode(SELECTION_BROWSE)
scrolled_win.add_with_viewport(self.list)
self.list.show()
self.list.connect("select_child", self.key_selected)
scrolled_win = GtkScrolledWindow()
scrolled_win.set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC)
hpaned.add2(scrolled_win)
scrolled_win.set_usize(500,400)
scrolled_win.show()
self.text = GtkText()
self.text.set_editable(FALSE)
scrolled_win.add_with_viewport(self.text)
self.text.show()
self.text.connect("event", self.event_handler)
self.menu = GtkMenu()
self.menu.show()
self.font = load_font("fixed")
self.update_keylist()
win.show()
# Add a key to the left hand side of the user interface
def add_key(self, key):
display_key = self.get_key_text(key)
list_item = GtkListItem(display_key)
list_item.set_data("raw_key", key) # Store raw key in item data
self.list.add(list_item)
list_item.show()
# Event handler registered by build_ui()
def event_handler(self, event, menu):
return FALSE
# Set the text to appear in the right hand side of the user interface
def set_value_text(self, item):
# Clear old old value in text window
self.text.delete_text(0, self.text.get_length())
if type(item) == str:
# The text widget has trouble inserting text containing NULL
# characters.
item = string.replace(item, "\x00", ".")
self.text.insert(self.font, None, None, item)
else:
# A non-text item
self.text.insert(self.font, None, None, repr(item))
# This function is called when a key is selected in the left hand side
# of the user interface.
def key_selected(self, list, list_item):
key = list_item.children()[0].get()
# Look for a match in the value display function list
text = self.dict[list_item.get_data("raw_key")]
for entry in self.get_value_text_fns:
if re.match(entry[0], key):
text = entry[1](text)
break
self.set_value_text(text)
# Refresh the key list by removing all items and re-inserting them.
# Items are only inserted if they pass through the filter regexp.
def update_keylist(self):
self.list.remove_items(self.list.children())
self.set_value_text("")
for k in self.dict.keys():
if re.match(self.filter_regex, k):
self.add_key(k)
# Invoked when the user hits return in the filter text entry widget.
def filter_activated(self, entry):
self.filter_regex = entry.get_text()
self.update_keylist()
# Register a key display function
def register_get_key_text_fn(self, fn):
self.get_key_text = fn
# Register a value display function
def register_get_value_text_fn(self, regexp, fn):
self.get_value_text_fns.append((regexp, fn))
#
# A utility function to convert a string to the standard hex + ascii format.
# To display all values in hex do:
# register_get_value_text_fn("", gtkdictbrowser.hex_string)
#
def hex_string(data):
"""Return a hex dump of a string as a string.
The output produced is in the standard 16 characters per line hex +
ascii format:
00000000: 40 00 00 00 00 00 00 00 40 00 00 00 01 00 04 80 @....... @.......
00000010: 01 01 00 00 00 00 00 01 00 00 00 00 ........ ....
"""
pos = 0 # Position in data
line = 0 # Line of data
hex = "" # Hex display
ascii = "" # ASCII display
result = ""
while pos < len(data):
# Start with header
if pos % 16 == 0:
hex = "%08x: " % (line * 16)
ascii = ""
# Add character
hex = hex + "%02x " % (ord(data[pos]))
if ord(data[pos]) < 32 or ord(data[pos]) > 176:
ascii = ascii + '.'
else:
ascii = ascii + data[pos]
pos = pos + 1
# Add separator if half way
if pos % 16 == 8:
hex = hex + " "
ascii = ascii + " "
# End of line
if pos % 16 == 0:
result = result + "%s %s\n" % (hex, ascii)
line = line + 1
# Leftover bits
if pos % 16 != 0:
# Pad hex string
for i in range(0, (16 - (pos % 16))):
hex = hex + " "
# Half way separator
if (pos % 16) < 8:
hex = hex + " "
result = result + "%s %s\n" % (hex, ascii)
return result
# For testing purposes, create a fixed dictionary to browse with
if __name__ == "__main__":
dict = {"chicken": "ham", "spam": "fun", "subdict": {"a": "b", "c": "d"}}
db = GtkDictBrowser(dict)
db.build_ui("GtkDictBrowser")
# Override Python's handling of ctrl-c so we can break out of the
# gui from the command line.
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
mainloop()

270
source3/python/py_common.c Normal file
View File

@ -0,0 +1,270 @@
/*
Python wrappers for DCERPC/SMB client routines.
Copyright (C) Tim Potter, 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 "Python.h"
#include "python/py_common_proto.h"
/* Return a tuple of (error code, error string) from a WERROR */
PyObject *py_werror_tuple(WERROR werror)
{
return Py_BuildValue("[is]", W_ERROR_V(werror),
dos_errstr(werror));
}
/* Return a tuple of (error code, error string) from a WERROR */
PyObject *py_ntstatus_tuple(NTSTATUS ntstatus)
{
return Py_BuildValue("[is]", NT_STATUS_V(ntstatus),
nt_errstr(ntstatus));
}
/* Initialise samba client routines */
static BOOL initialised;
void py_samba_init(void)
{
extern pstring global_myname;
char *p;
if (initialised)
return;
/* Load configuration file */
if (!lp_load(dyn_CONFIGFILE, True, False, False))
fprintf(stderr, "Can't load %s\n", dyn_CONFIGFILE);
/* Misc other stuff */
load_interfaces();
fstrcpy(global_myname, myhostname());
p = strchr(global_myname, '.');
if (p)
*p = 0;
initialised = True;
}
/* Debuglevel routines */
PyObject *get_debuglevel(PyObject *self, PyObject *args)
{
PyObject *debuglevel;
if (!PyArg_ParseTuple(args, ""))
return NULL;
debuglevel = PyInt_FromLong(DEBUGLEVEL);
return debuglevel;
}
PyObject *set_debuglevel(PyObject *self, PyObject *args)
{
int debuglevel;
if (!PyArg_ParseTuple(args, "i", &debuglevel))
return NULL;
DEBUGLEVEL = debuglevel;
Py_INCREF(Py_None);
return Py_None;
}
/* Initialise logging */
PyObject *py_setup_logging(PyObject *self, PyObject *args, PyObject *kw)
{
BOOL interactive = False;
char *logfilename = NULL;
static char *kwlist[] = {"interactive", "logfilename", NULL};
if (!PyArg_ParseTupleAndKeywords(
args, kw, "|is", kwlist, &interactive, &logfilename))
return NULL;
if (interactive && logfilename) {
PyErr_SetString(PyExc_RuntimeError,
"can't be interactive and set log file name");
return NULL;
}
if (interactive)
setup_logging("spoolss", True);
if (logfilename) {
lp_set_logfile(logfilename);
setup_logging(logfilename, False);
reopen_logs();
}
Py_INCREF(Py_None);
return Py_None;
}
/* Parse credentials from a python dictionary. The dictionary can
only have the keys "username", "domain" and "password". Return
True for valid credentials in which case the username, domain and
password are set to pointers to their values from the dicationary.
If returns False, the errstr is set to point at some mallocated
memory describing the error. */
BOOL py_parse_creds(PyObject *creds, char **username, char **domain,
char **password, char **errstr)
{
/* Initialise anonymous credentials */
*username = "";
*domain = "";
*password = "";
if (creds && PyDict_Size(creds) > 0) {
PyObject *username_obj, *password_obj, *domain_obj;
PyObject *key, *value;
int i;
/* Check for presence of required fields */
username_obj = PyDict_GetItemString(creds, "username");
domain_obj = PyDict_GetItemString(creds, "domain");
password_obj = PyDict_GetItemString(creds, "password");
if (!username_obj) {
*errstr = strdup("no username field in credential");
return False;
}
if (!domain_obj) {
*errstr = strdup("no domain field in credential");
return False;
}
if (!password_obj) {
*errstr = strdup("no password field in credential");
return False;
}
/* Check type of required fields */
if (!PyString_Check(username_obj)) {
*errstr = strdup("username field is not string type");
return False;
}
if (!PyString_Check(domain_obj)) {
*errstr = strdup("domain field is not string type");
return False;
}
if (!PyString_Check(password_obj)) {
*errstr = strdup("password field is not string type");
return False;
}
/* Look for any extra fields */
i = 0;
while (PyDict_Next(creds, &i, &key, &value)) {
if (strcmp(PyString_AsString(key), "domain") != 0 &&
strcmp(PyString_AsString(key), "username") != 0 &&
strcmp(PyString_AsString(key), "password") != 0) {
asprintf(errstr,
"creds contain extra field '%s'",
PyString_AsString(key));
return False;
}
}
/* Assign values */
*username = PyString_AsString(username_obj);
*domain = PyString_AsString(domain_obj);
*password = PyString_AsString(password_obj);
}
*errstr = NULL;
return True;
}
/* Return a cli_state to a RPC pipe on the given server. Use the
credentials passed if not NULL. If an error occurs errstr is set to a
string describing the error and NULL is returned. If set, errstr must
be freed by calling free(). */
struct cli_state *open_pipe_creds(char *server, PyObject *creds,
char *pipe_name, char **errstr)
{
char *username, *password, *domain;
struct cli_state *cli;
NTSTATUS result;
/* Extract credentials from the python dictionary */
if (!py_parse_creds(creds, &username, &domain, &password, errstr))
return NULL;
/* Now try to connect */
result = cli_full_connection(
&cli, NULL, server, NULL, 0, "IPC$", "IPC",
username, domain, password, 0);
if (!NT_STATUS_IS_OK(result)) {
*errstr = strdup("error connecting to IPC$ pipe");
return NULL;
}
if (!cli_nt_session_open(cli, pipe_name)) {
cli_shutdown(cli);
free(cli);
asprintf(errstr, "error opening %s", pipe_name);
return NULL;
}
*errstr = NULL;
return cli;
}
/* Return true if a dictionary contains a "level" key with an integer
value. Set the value if so. */
BOOL get_level_value(PyObject *dict, uint32 *level)
{
PyObject *obj;
if (!(obj = PyDict_GetItemString(dict, "level")) ||
!PyInt_Check(obj))
return False;
if (level)
*level = PyInt_AsLong(obj);
return True;
}

184
source3/python/py_conv.c Normal file
View File

@ -0,0 +1,184 @@
/*
Python wrappers for DCERPC/SMB client routines.
Copyright (C) Tim Potter, 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 "Python.h"
#include "py_conv.h"
/* Helper for rpcstr_pull() function */
static void fstr_pull(fstring str, UNISTR *uni)
{
rpcstr_pull(str, uni->buffer, sizeof(fstring), -1, STR_TERMINATE);
}
/* Convert a structure to a Python dict */
PyObject *from_struct(void *s, struct pyconv *conv)
{
PyObject *obj, *item;
int i;
obj = PyDict_New();
for (i = 0; conv[i].name; i++) {
switch (conv[i].type) {
case PY_UNISTR: {
UNISTR *u = (UNISTR *)((char *)s + conv[i].offset);
fstring s = "";
if (u->buffer)
fstr_pull(s, u);
item = PyString_FromString(s);
PyDict_SetItemString(obj, conv[i].name, item);
break;
}
case PY_UINT32: {
uint32 *u = (uint32 *)((char *)s + conv[i].offset);
item = PyInt_FromLong(*u);
PyDict_SetItemString(obj, conv[i].name, item);
break;
}
case PY_UINT16: {
uint16 *u = (uint16 *)((char *)s + conv[i].offset);
item = PyInt_FromLong(*u);
PyDict_SetItemString(obj, conv[i].name, item);
break;
}
case PY_STRING: {
char *str = (char *)s + conv[i].offset;
item = PyString_FromString(str);
PyDict_SetItemString(obj, conv[i].name, item);
break;
}
case PY_UID: {
uid_t *uid = (uid_t *)((char *)s + conv[i].offset);
item = PyInt_FromLong(*uid);
PyDict_SetItemString(obj, conv[i].name, item);
break;
}
case PY_GID: {
gid_t *gid = (gid_t *)((char *)s + conv[i].offset);
item = PyInt_FromLong(*gid);
PyDict_SetItemString(obj, conv[i].name, item);
break;
}
default:
break;
}
}
return obj;
}
/* Convert a Python dict to a structure */
BOOL to_struct(void *s, PyObject *dict, struct pyconv *conv)
{
PyObject *visited, *key, *value;
BOOL result = False;
int i;
visited = PyDict_New();
for (i = 0; conv[i].name; i++) {
PyObject *obj;
obj = PyDict_GetItemString(dict, conv[i].name);
if (!obj)
goto done;
switch (conv[i].type) {
case PY_UNISTR: {
UNISTR *u = (UNISTR *)((char *)s + conv[i].offset);
char *s = "";
if (!PyString_Check(obj))
goto done;
s = PyString_AsString(obj);
init_unistr(u, s);
break;
}
case PY_UINT32: {
uint32 *u = (uint32 *)((char *)s + conv[i].offset);
if (!PyInt_Check(obj))
goto done;
*u = PyInt_AsLong(obj);
break;
}
case PY_UINT16: {
uint16 *u = (uint16 *)((char *)s + conv[i].offset);
if (!PyInt_Check(obj))
goto done;
*u = PyInt_AsLong(obj);
break;
}
default:
break;
}
/* Mark as visited */
PyDict_SetItemString(visited, conv[i].name,
PyInt_FromLong(1));
}
/* Iterate over each item in the input dictionary and see if it was
visited. If it wasn't then the user has added some extra crap
to the dictionary. */
i = 0;
while (PyDict_Next(dict, &i, &key, &value)) {
if (!PyDict_GetItem(visited, key))
goto done;
}
result = True;
done:
/* We must decrement the reference count here or the visited
dictionary will not be freed. */
Py_DECREF(visited);
return result;
}

40
source3/python/py_conv.h Normal file
View File

@ -0,0 +1,40 @@
/*
Python wrappers for DCERPC/SMB client routines.
Copyright (C) Tim Potter, 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.
*/
#ifndef _PY_CONV_H
#define _PY_CONV_H
enum pyconv_types { PY_UNISTR, PY_UINT32, PY_UINT16, PY_STRING, PY_UID, PY_GID };
struct pyconv {
char *name; /* Name of member */
enum pyconv_types type; /* Type */
size_t offset; /* Offset into structure */
};
PyObject *from_struct(void *s, struct pyconv *conv);
BOOL to_struct(void *s, PyObject *dict, struct pyconv *conv);
/* Another version of offsetof (-: */
#undef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif /* _PY_CONV_H */

56
source3/python/py_samba.c Normal file
View File

@ -0,0 +1,56 @@
/*
Python wrappers for DCERPC/SMB client routines.
Copyright (C) Tim Potter, 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 "Python.h"
#include "python/py_common.h"
/*
* Module initialisation
*/
static PyObject *lsa_open_policy(PyObject *self, PyObject *args,
PyObject *kw)
{
return NULL;
}
static PyMethodDef samba_methods[] = {
{ NULL }
};
static PyMethodDef cheepy_methods[] = {
{ "open_policy", (PyCFunction)lsa_open_policy, METH_VARARGS|METH_KEYWORDS,
"Foo"},
{ NULL }
};
void initsamba(void)
{
PyObject *module, *new_module, *dict;
/* Initialise module */
module = Py_InitModule("samba", samba_methods);
dict = PyModule_GetDict(module);
/* Do samba initialisation */
py_samba_init();
}

498
source3/python/py_samr.c Normal file
View File

@ -0,0 +1,498 @@
/*
Python wrappers for DCERPC/SMB client routines.
Copyright (C) Tim Potter, 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 "python/py_samr.h"
/*
* Exceptions raised by this module
*/
PyObject *samr_error; /* This indicates a non-RPC related error
such as name lookup failure */
PyObject *samr_ntstatus; /* This exception is raised when a RPC call
returns a status code other than
NT_STATUS_OK */
/* SAMR connect handle object */
static void py_samr_connect_hnd_dealloc(PyObject* self)
{
PyObject_Del(self);
}
PyObject *new_samr_domain_hnd_object(struct cli_state *cli, TALLOC_CTX *mem_ctx,
POLICY_HND *pol)
{
samr_domain_hnd_object *o;
o = PyObject_New(samr_domain_hnd_object, &samr_domain_hnd_type);
o->cli = cli;
o->mem_ctx = mem_ctx;
memcpy(&o->domain_pol, pol, sizeof(POLICY_HND));
return (PyObject*)o;
}
static PyObject *samr_open_domain(PyObject *self, PyObject *args, PyObject *kw)
{
samr_connect_hnd_object *connect_hnd = (samr_connect_hnd_object *)self;
static char *kwlist[] = { "sid", "access", NULL };
uint32 desired_access = MAXIMUM_ALLOWED_ACCESS;
char *sid_str;
DOM_SID sid;
TALLOC_CTX *mem_ctx = NULL;
POLICY_HND domain_pol;
NTSTATUS ntstatus;
PyObject *result = NULL;
if (!PyArg_ParseTupleAndKeywords(
args, kw, "s|i", kwlist, &sid_str, &desired_access))
return NULL;
if (!string_to_sid(&sid, sid_str)) {
PyErr_SetString(PyExc_TypeError, "string is not a sid");
return NULL;
}
if (!(mem_ctx = talloc_init())) {
PyErr_SetString(samr_error, "unable to init talloc context");
return NULL;
}
ntstatus = cli_samr_open_domain(
connect_hnd->cli, mem_ctx, &connect_hnd->connect_pol,
desired_access, &sid, &domain_pol);
if (!NT_STATUS_IS_OK(ntstatus)) {
PyErr_SetObject(samr_ntstatus, py_ntstatus_tuple(ntstatus));
goto done;
}
result = new_samr_domain_hnd_object(
connect_hnd->cli, mem_ctx, &domain_pol);
done:
if (!result) {
if (mem_ctx)
talloc_destroy(mem_ctx);
}
return result;
}
static PyMethodDef samr_connect_methods[] = {
{ "open_domain", (PyCFunction)samr_open_domain,
METH_VARARGS | METH_KEYWORDS,
"Open a handle on a domain" },
{ NULL }
};
static PyObject *py_samr_connect_hnd_getattr(PyObject *self, char *attrname)
{
return Py_FindMethod(samr_connect_methods, self, attrname);
}
PyTypeObject samr_connect_hnd_type = {
PyObject_HEAD_INIT(NULL)
0,
"SAMR Connect Handle",
sizeof(samr_connect_hnd_object),
0,
py_samr_connect_hnd_dealloc, /*tp_dealloc*/
0, /*tp_print*/
py_samr_connect_hnd_getattr, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
};
PyObject *new_samr_connect_hnd_object(struct cli_state *cli, TALLOC_CTX *mem_ctx,
POLICY_HND *pol)
{
samr_connect_hnd_object *o;
o = PyObject_New(samr_connect_hnd_object, &samr_connect_hnd_type);
o->cli = cli;
o->mem_ctx = mem_ctx;
memcpy(&o->connect_pol, pol, sizeof(POLICY_HND));
return (PyObject*)o;
}
/* SAMR domain handle object */
static void py_samr_domain_hnd_dealloc(PyObject* self)
{
PyObject_Del(self);
}
static PyObject *samr_enum_dom_groups(PyObject *self, PyObject *args,
PyObject *kw)
{
samr_domain_hnd_object *domain_hnd = (samr_domain_hnd_object *)self;
static char *kwlist[] = { NULL };
TALLOC_CTX *mem_ctx;
uint32 desired_access = MAXIMUM_ALLOWED_ACCESS;
uint32 start_idx, size, num_dom_groups;
struct acct_info *dom_groups;
NTSTATUS result;
PyObject *py_result = NULL;
if (!PyArg_ParseTupleAndKeywords(
args, kw, "", kwlist))
return NULL;
if (!(mem_ctx = talloc_init())) {
PyErr_SetString(samr_error, "unable to init talloc context");
return NULL;
}
start_idx = 0;
size = 0xffff;
do {
result = cli_samr_enum_dom_groups(
domain_hnd->cli, mem_ctx, &domain_hnd->domain_pol,
&start_idx, size, &dom_groups, &num_dom_groups);
if (NT_STATUS_IS_OK(result) ||
NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES)) {
py_from_acct_info(&py_result, dom_groups,
num_dom_groups);
}
} while (NT_STATUS_V(result) == NT_STATUS_V(STATUS_MORE_ENTRIES));
return py_result;
}
static PyMethodDef samr_domain_methods[] = {
{ "enum_domain_groups", (PyCFunction)samr_enum_dom_groups,
METH_VARARGS | METH_KEYWORDS, "Enumerate domain groups" },
{ NULL }
};
static PyObject *py_samr_domain_hnd_getattr(PyObject *self, char *attrname)
{
return Py_FindMethod(samr_domain_methods, self, attrname);
}
PyTypeObject samr_domain_hnd_type = {
PyObject_HEAD_INIT(NULL)
0,
"SAMR Domain Handle",
sizeof(samr_domain_hnd_object),
0,
py_samr_domain_hnd_dealloc, /*tp_dealloc*/
0, /*tp_print*/
py_samr_domain_hnd_getattr, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
};
/* SAMR user handle object */
static void py_samr_user_hnd_dealloc(PyObject* self)
{
PyObject_Del(self);
}
static PyMethodDef samr_user_methods[] = {
{ NULL }
};
static PyObject *py_samr_user_hnd_getattr(PyObject *self, char *attrname)
{
return Py_FindMethod(samr_user_methods, self, attrname);
}
PyTypeObject samr_user_hnd_type = {
PyObject_HEAD_INIT(NULL)
0,
"SAMR User Handle",
sizeof(samr_user_hnd_object),
0,
py_samr_user_hnd_dealloc, /*tp_dealloc*/
0, /*tp_print*/
py_samr_user_hnd_getattr, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
};
PyObject *new_samr_user_hnd_object(struct cli_state *cli, TALLOC_CTX *mem_ctx,
POLICY_HND *pol)
{
samr_user_hnd_object *o;
o = PyObject_New(samr_user_hnd_object, &samr_user_hnd_type);
o->cli = cli;
o->mem_ctx = mem_ctx;
memcpy(&o->user_pol, pol, sizeof(POLICY_HND));
return (PyObject*)o;
}
/* SAMR group handle object */
static void py_samr_group_hnd_dealloc(PyObject* self)
{
PyObject_Del(self);
}
static PyMethodDef samr_group_methods[] = {
{ NULL }
};
static PyObject *py_samr_group_hnd_getattr(PyObject *self, char *attrname)
{
return Py_FindMethod(samr_group_methods, self, attrname);
}
PyTypeObject samr_group_hnd_type = {
PyObject_HEAD_INIT(NULL)
0,
"SAMR Group Handle",
sizeof(samr_group_hnd_object),
0,
py_samr_group_hnd_dealloc, /*tp_dealloc*/
0, /*tp_print*/
py_samr_group_hnd_getattr, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
};
PyObject *new_samr_group_hnd_object(struct cli_state *cli, TALLOC_CTX *mem_ctx,
POLICY_HND *pol)
{
samr_group_hnd_object *o;
o = PyObject_New(samr_group_hnd_object, &samr_group_hnd_type);
o->cli = cli;
o->mem_ctx = mem_ctx;
memcpy(&o->group_pol, pol, sizeof(POLICY_HND));
return (PyObject*)o;
}
/* Alias handle object */
static void py_samr_alias_hnd_dealloc(PyObject* self)
{
PyObject_Del(self);
}
static PyMethodDef samr_alias_methods[] = {
{ NULL }
};
static PyObject *py_samr_alias_hnd_getattr(PyObject *self, char *attrname)
{
return Py_FindMethod(samr_alias_methods, self, attrname);
}
PyTypeObject samr_alias_hnd_type = {
PyObject_HEAD_INIT(NULL)
0,
"SAMR Alias Handle",
sizeof(samr_alias_hnd_object),
0,
py_samr_alias_hnd_dealloc, /*tp_dealloc*/
0, /*tp_print*/
py_samr_alias_hnd_getattr, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
};
PyObject *new_samr_alias_hnd_object(struct cli_state *cli, TALLOC_CTX *mem_ctx,
POLICY_HND *pol)
{
samr_alias_hnd_object *o;
o = PyObject_New(samr_alias_hnd_object, &samr_alias_hnd_type);
o->cli = cli;
o->mem_ctx = mem_ctx;
memcpy(&o->alias_pol, pol, sizeof(POLICY_HND));
return (PyObject*)o;
}
static PyObject *samr_connect(PyObject *self, PyObject *args, PyObject *kw)
{
static char *kwlist[] = { "server", "creds", "access", NULL };
uint32 desired_access = MAXIMUM_ALLOWED_ACCESS;
char *server, *errstr;
struct cli_state *cli = NULL;
POLICY_HND hnd;
TALLOC_CTX *mem_ctx = NULL;
PyObject *result = NULL, *creds = NULL;
NTSTATUS ntstatus;
if (!PyArg_ParseTupleAndKeywords(
args, kw, "s|Oi", kwlist, &server, &creds,
&desired_access))
return NULL;
if (server[0] != '\\' || server[1] != '\\') {
PyErr_SetString(PyExc_ValueError, "UNC name required");
return NULL;
}
server += 2;
if (creds && creds != Py_None && !PyDict_Check(creds)) {
PyErr_SetString(PyExc_TypeError,
"credentials must be dictionary or None");
return NULL;
}
if (!(cli = open_pipe_creds(server, creds, PIPE_SAMR, &errstr))) {
PyErr_SetString(samr_error, errstr);
free(errstr);
return NULL;
}
if (!(mem_ctx = talloc_init())) {
PyErr_SetString(samr_ntstatus,
"unable to init talloc context\n");
goto done;
}
ntstatus = cli_samr_connect(cli, mem_ctx, desired_access, &hnd);
if (!NT_STATUS_IS_OK(ntstatus)) {
cli_shutdown(cli);
SAFE_FREE(cli);
PyErr_SetObject(samr_ntstatus, py_ntstatus_tuple(ntstatus));
goto done;
}
result = new_samr_connect_hnd_object(cli, mem_ctx, &hnd);
done:
if (!result) {
if (cli)
cli_shutdown(cli);
if (mem_ctx)
talloc_destroy(mem_ctx);
}
return result;
}
/*
* Module initialisation
*/
static PyMethodDef samr_methods[] = {
/* Open/close samr connect handles */
{ "connect", (PyCFunction)samr_connect,
METH_VARARGS | METH_KEYWORDS,
"Open a connect handle" },
{ NULL }
};
static struct const_vals {
char *name;
uint32 value;
} module_const_vals[] = {
{ NULL }
};
static void const_init(PyObject *dict)
{
struct const_vals *tmp;
PyObject *obj;
for (tmp = module_const_vals; tmp->name; tmp++) {
obj = PyInt_FromLong(tmp->value);
PyDict_SetItemString(dict, tmp->name, obj);
Py_DECREF(obj);
}
}
void initsamr(void)
{
PyObject *module, *dict;
/* Initialise module */
module = Py_InitModule("samr", samr_methods);
dict = PyModule_GetDict(module);
samr_error = PyErr_NewException("samr.error", NULL, NULL);
PyDict_SetItemString(dict, "error", samr_error);
samr_ntstatus = PyErr_NewException("samr.ntstatus", NULL, NULL);
PyDict_SetItemString(dict, "ntstatus", samr_ntstatus);
/* Initialise policy handle object */
samr_connect_hnd_type.ob_type = &PyType_Type;
samr_domain_hnd_type.ob_type = &PyType_Type;
samr_user_hnd_type.ob_type = &PyType_Type;
samr_group_hnd_type.ob_type = &PyType_Type;
samr_alias_hnd_type.ob_type = &PyType_Type;
/* Initialise constants */
const_init(dict);
/* Do samba initialisation */
py_samba_init();
setup_logging("samr", True);
DEBUGLEVEL = 10;
}

View File

@ -0,0 +1,58 @@
/*
Python wrappers for DCERPC/SMB client routines.
Copyright (C) Tim Potter, 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 "python/py_samr.h"
#include "python/py_conv.h"
/*
* Convert between acct_info and Python
*/
BOOL py_from_acct_info(PyObject **array, struct acct_info *info, int num_accts)
{
int i;
*array = PyList_New(num_accts);
for (i = 0; i < num_accts; i++) {
PyObject *obj;
obj = PyDict_New();
PyDict_SetItemString(
obj, "name", PyString_FromString(info[i].acct_name));
PyDict_SetItemString(
obj, "description",
PyString_FromString(info[i].acct_desc));
PyDict_SetItemString(obj, "rid", PyInt_FromLong(info[i].rid));
PyList_SetItem(*array, i, obj);
}
return True;
}
BOOL py_to_acct_info(PRINTER_INFO_3 *info, PyObject *dict,
TALLOC_CTX *mem_ctx)
{
return False;
}

490
source3/python/py_spoolss.c Normal file
View File

@ -0,0 +1,490 @@
/*
Python wrappers for DCERPC/SMB client routines.
Copyright (C) Tim Potter, 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 "python/py_spoolss.h"
/* Exceptions this module can raise */
PyObject *spoolss_error, *spoolss_werror;
/*
* Routines to convert from python hashes to Samba structures
*/
PyObject *new_spoolss_policy_hnd_object(struct cli_state *cli,
TALLOC_CTX *mem_ctx, POLICY_HND *pol)
{
spoolss_policy_hnd_object *o;
o = PyObject_New(spoolss_policy_hnd_object, &spoolss_policy_hnd_type);
o->cli = cli;
o->mem_ctx = mem_ctx;
memcpy(&o->pol, pol, sizeof(POLICY_HND));
return (PyObject*)o;
}
/*
* Method dispatch table
*/
static PyMethodDef spoolss_methods[] = {
/* Open/close printer handles */
{ "openprinter", (PyCFunction)spoolss_openprinter, METH_VARARGS | METH_KEYWORDS,
"Open a printer by name in UNC format.
Optionally a dictionary of (domain, username, password) may be given in
which case they are used when opening the RPC pipe. An access mask may
also be given which defaults to MAXIMUM_ALLOWED_ACCESS.
Example:
>>> hnd = spoolss.openprinter(\"\\\\\\\\NPSD-PDC2\\\\meanie\")"},
{ "closeprinter", spoolss_closeprinter, METH_VARARGS,
"Close a printer handle opened with openprinter or addprinter.
Example:
>>> spoolss.closeprinter(hnd)"},
{ "addprinterex", (PyCFunction)spoolss_addprinterex, METH_VARARGS,
"addprinterex()"},
/* Server enumeratation functions */
{ "enumprinters", (PyCFunction)spoolss_enumprinters,
METH_VARARGS | METH_KEYWORDS,
"Enumerate printers on a print server.
Return a list of printers on a print server. The credentials, info level
and flags may be specified as keyword arguments.
Example:
>>> print spoolss.enumprinters(\"\\\\\\\\npsd-pdc2\")
[{'comment': 'i am a comment', 'printer_name': 'meanie', 'flags': 8388608,
'description': 'meanie,Generic / Text Only,i am a location'},
{'comment': '', 'printer_name': 'fileprint', 'flags': 8388608,
'description': 'fileprint,Generic / Text Only,'}]"},
{ "enumports", (PyCFunction)spoolss_enumports,
METH_VARARGS | METH_KEYWORDS,
"Enumerate ports on a print server.
Return a list of ports on a print server.
Example:
>>> print spoolss.enumports(\"\\\\\\\\npsd-pdc2\")
[{'name': 'LPT1:'}, {'name': 'LPT2:'}, {'name': 'COM1:'}, {'name': 'COM2:'},
{'name': 'FILE:'}, {'name': '\\\\nautilus1\\zpekt3r'}]"},
{ "enumprinterdrivers", (PyCFunction)spoolss_enumprinterdrivers,
METH_VARARGS | METH_KEYWORDS,
"Enumerate printer drivers on a print server.
Return a list of printer drivers."},
/* Miscellaneous other commands */
{ "getprinterdriverdir", (PyCFunction)spoolss_getprinterdriverdir,
METH_VARARGS | METH_KEYWORDS,
"Return printer driver directory.
Return the printer driver directory for a given architecture. The
architecture defaults to \"Windows NT x86\"."},
/* Other stuff - this should really go into a samba config module
but for the moment let's leave it here. */
{ "setup_logging", (PyCFunction)py_setup_logging,
METH_VARARGS | METH_KEYWORDS,
"Set up debug logging.
Initialises Samba's debug logging system. One argument is expected which
is a boolean specifying whether debugging is interactive and sent to stdout
or logged to a file.
Example:
>>> spoolss.setup_logging(interactive = 1)" },
{ "get_debuglevel", (PyCFunction)get_debuglevel,
METH_VARARGS,
"Set the current debug level.
Example:
>>> spoolss.get_debuglevel()
0" },
{ "set_debuglevel", (PyCFunction)set_debuglevel,
METH_VARARGS,
"Get the current debug level.
Example:
>>> spoolss.set_debuglevel(10)" },
/* Printer driver routines */
{ "addprinterdriver", (PyCFunction)spoolss_addprinterdriver,
METH_VARARGS | METH_KEYWORDS,
"Add a printer driver." },
{ "addprinterdriverex", (PyCFunction)spoolss_addprinterdriverex,
METH_VARARGS | METH_KEYWORDS,
"Add a printer driver." },
{ "deleteprinterdriver", (PyCFunction)spoolss_deleteprinterdriver,
METH_VARARGS | METH_KEYWORDS,
"Delete a printer driver." },
{ "deleteprinterdriverex", (PyCFunction)spoolss_deleteprinterdriverex,
METH_VARARGS | METH_KEYWORDS,
"Delete a printer driver." },
{ NULL }
};
/* Methods attached to a spoolss handle object */
static PyMethodDef spoolss_hnd_methods[] = {
/* Printer info */
{ "getprinter", (PyCFunction)spoolss_hnd_getprinter,
METH_VARARGS | METH_KEYWORDS,
"Get printer information.
Return a dictionary of print information. The info level defaults to 1.
Example:
>>> hnd.getprinter()
{'comment': 'i am a comment', 'printer_name': '\\\\NPSD-PDC2\\meanie',
'description': '\\\\NPSD-PDC2\\meanie,Generic / Text Only,i am a location',
'flags': 8388608}"},
{ "setprinter", (PyCFunction)spoolss_hnd_setprinter,
METH_VARARGS | METH_KEYWORDS,
"Set printer information."},
/* Printer drivers */
{ "getprinterdriver", (PyCFunction)spoolss_hnd_getprinterdriver,
METH_VARARGS | METH_KEYWORDS,
"Return printer driver information.
Return a dictionary of printer driver information for the printer driver
bound to this printer."},
/* Forms */
{ "enumforms", (PyCFunction)spoolss_hnd_enumforms,
METH_VARARGS | METH_KEYWORDS,
"Enumerate supported forms.
Return a list of forms supported by this printer or print server."},
{ "setform", (PyCFunction)spoolss_hnd_setform,
METH_VARARGS | METH_KEYWORDS,
"Set form data.
Set the form given by the dictionary argument."},
{ "addform", (PyCFunction)spoolss_hnd_addform,
METH_VARARGS | METH_KEYWORDS,
"Add a new form." },
{ "getform", (PyCFunction)spoolss_hnd_getform,
METH_VARARGS | METH_KEYWORDS,
"Get form properties." },
{ "deleteform", (PyCFunction)spoolss_hnd_deleteform,
METH_VARARGS | METH_KEYWORDS,
"Delete a form." },
/* Job related methods */
{ "enumjobs", (PyCFunction)spoolss_hnd_enumjobs,
METH_VARARGS | METH_KEYWORDS,
"Enumerate jobs." },
{ "setjob", (PyCFunction)spoolss_hnd_setjob,
METH_VARARGS | METH_KEYWORDS,
"Set job information." },
{ "getjob", (PyCFunction)spoolss_hnd_getjob,
METH_VARARGS | METH_KEYWORDS,
"Get job information." },
{ "startpageprinter", (PyCFunction)spoolss_hnd_startpageprinter,
METH_VARARGS | METH_KEYWORDS,
"Notify spooler that a page is about to be printed." },
{ "endpageprinter", (PyCFunction)spoolss_hnd_endpageprinter,
METH_VARARGS | METH_KEYWORDS,
"Notify spooler that a page is about to be printed." },
{ "startdocprinter", (PyCFunction)spoolss_hnd_startdocprinter,
METH_VARARGS | METH_KEYWORDS,
"Notify spooler that a document is about to be printed." },
{ "enddocprinter", (PyCFunction)spoolss_hnd_enddocprinter,
METH_VARARGS | METH_KEYWORDS,
"Notify spooler that a document is about to be printed." },
{ "writeprinter", (PyCFunction)spoolss_hnd_writeprinter,
METH_VARARGS | METH_KEYWORDS,
"Write job data to a printer." },
{ "addjob", (PyCFunction)spoolss_hnd_addjob,
METH_VARARGS | METH_KEYWORDS,
"Add a job to the list of print jobs." },
/* Printer data */
{ "getprinterdata", (PyCFunction)spoolss_hnd_getprinterdata,
METH_VARARGS | METH_KEYWORDS,
"Get printer data." },
{ "setprinterdata", (PyCFunction)spoolss_hnd_setprinterdata,
METH_VARARGS | METH_KEYWORDS,
"Set printer data." },
{ "enumprinterdata", (PyCFunction)spoolss_hnd_enumprinterdata,
METH_VARARGS | METH_KEYWORDS,
"Enumerate printer data." },
{ "deleteprinterdata", (PyCFunction)spoolss_hnd_deleteprinterdata,
METH_VARARGS | METH_KEYWORDS,
"Delete printer data." },
{ "getprinterdataex", (PyCFunction)spoolss_hnd_getprinterdataex,
METH_VARARGS | METH_KEYWORDS,
"Get printer data." },
{ "setprinterdataex", (PyCFunction)spoolss_hnd_setprinterdataex,
METH_VARARGS | METH_KEYWORDS,
"Set printer data." },
{ "enumprinterdataex", (PyCFunction)spoolss_hnd_enumprinterdataex,
METH_VARARGS | METH_KEYWORDS,
"Enumerate printer data." },
{ "deleteprinterdataex", (PyCFunction)spoolss_hnd_deleteprinterdataex,
METH_VARARGS | METH_KEYWORDS,
"Delete printer data." },
{ NULL }
};
static void py_policy_hnd_dealloc(PyObject* self)
{
spoolss_policy_hnd_object *hnd;
/* Close down policy handle and free talloc context */
hnd = (spoolss_policy_hnd_object*)self;
cli_shutdown(hnd->cli);
talloc_destroy(hnd->mem_ctx);
PyObject_Del(self);
}
static PyObject *py_policy_hnd_getattr(PyObject *self, char *attrname)
{
return Py_FindMethod(spoolss_hnd_methods, self, attrname);
}
static char spoolss_type_doc[] =
"Python wrapper for Windows NT SPOOLSS rpc pipe.";
PyTypeObject spoolss_policy_hnd_type = {
PyObject_HEAD_INIT(NULL)
0,
"spoolss.hnd",
sizeof(spoolss_policy_hnd_object),
0,
py_policy_hnd_dealloc, /* tp_dealloc*/
0, /* tp_print*/
py_policy_hnd_getattr, /* tp_getattr*/
0, /* tp_setattr*/
0, /* tp_compare*/
0, /* tp_repr*/
0, /* tp_as_number*/
0, /* tp_as_sequence*/
0, /* tp_as_mapping*/
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /* tp_flags */
spoolss_type_doc, /* tp_doc */
};
/* Initialise constants */
static struct const_vals {
char *name;
uint32 value;
} module_const_vals[] = {
/* Access permissions */
{ "MAXIMUM_ALLOWED_ACCESS", MAXIMUM_ALLOWED_ACCESS },
{ "SERVER_ALL_ACCESS", SERVER_ALL_ACCESS },
{ "SERVER_READ", SERVER_READ },
{ "SERVER_WRITE", SERVER_WRITE },
{ "SERVER_EXECUTE", SERVER_EXECUTE },
{ "SERVER_ACCESS_ADMINISTER", SERVER_ACCESS_ADMINISTER },
{ "SERVER_ACCESS_ENUMERATE", SERVER_ACCESS_ENUMERATE },
{ "PRINTER_ALL_ACCESS", PRINTER_ALL_ACCESS },
{ "PRINTER_READ", PRINTER_READ },
{ "PRINTER_WRITE", PRINTER_WRITE },
{ "PRINTER_EXECUTE", PRINTER_EXECUTE },
{ "PRINTER_ACCESS_ADMINISTER", PRINTER_ACCESS_ADMINISTER },
{ "PRINTER_ACCESS_USE", PRINTER_ACCESS_USE },
{ "JOB_ACCESS_ADMINISTER", JOB_ACCESS_ADMINISTER },
{ "JOB_ALL_ACCESS", JOB_ALL_ACCESS },
{ "JOB_READ", JOB_READ },
{ "JOB_WRITE", JOB_WRITE },
{ "JOB_EXECUTE", JOB_EXECUTE },
{ "STANDARD_RIGHTS_ALL_ACCESS", STANDARD_RIGHTS_ALL_ACCESS },
{ "STANDARD_RIGHTS_EXECUTE_ACCESS", STANDARD_RIGHTS_EXECUTE_ACCESS },
{ "STANDARD_RIGHTS_READ_ACCESS", STANDARD_RIGHTS_READ_ACCESS },
{ "STANDARD_RIGHTS_REQUIRED_ACCESS", STANDARD_RIGHTS_REQUIRED_ACCESS },
{ "STANDARD_RIGHTS_WRITE_ACCESS", STANDARD_RIGHTS_WRITE_ACCESS },
/* Printer enumeration flags */
{ "PRINTER_ENUM_DEFAULT", PRINTER_ENUM_DEFAULT },
{ "PRINTER_ENUM_LOCAL", PRINTER_ENUM_LOCAL },
{ "PRINTER_ENUM_CONNECTIONS", PRINTER_ENUM_CONNECTIONS },
{ "PRINTER_ENUM_FAVORITE", PRINTER_ENUM_FAVORITE },
{ "PRINTER_ENUM_NAME", PRINTER_ENUM_NAME },
{ "PRINTER_ENUM_REMOTE", PRINTER_ENUM_REMOTE },
{ "PRINTER_ENUM_SHARED", PRINTER_ENUM_SHARED },
{ "PRINTER_ENUM_NETWORK", PRINTER_ENUM_NETWORK },
/* Form types */
{ "FORM_USER", FORM_USER },
{ "FORM_BUILTIN", FORM_BUILTIN },
{ "FORM_PRINTER", FORM_PRINTER },
/* WERRORs */
{ "WERR_OK", 0 },
{ "WERR_BADFILE", 2 },
{ "WERR_ACCESS_DENIED", 5 },
{ "WERR_BADFID", 6 },
{ "WERR_BADFUNC", 1 },
{ "WERR_INSUFFICIENT_BUFFER", 122 },
{ "WERR_NO_SUCH_SHARE", 67 },
{ "WERR_ALREADY_EXISTS", 80 },
{ "WERR_INVALID_PARAM", 87 },
{ "WERR_NOT_SUPPORTED", 50 },
{ "WERR_BAD_PASSWORD", 86 },
{ "WERR_NOMEM", 8 },
{ "WERR_INVALID_NAME", 123 },
{ "WERR_UNKNOWN_LEVEL", 124 },
{ "WERR_OBJECT_PATH_INVALID", 161 },
{ "WERR_NO_MORE_ITEMS", 259 },
{ "WERR_MORE_DATA", 234 },
{ "WERR_UNKNOWN_PRINTER_DRIVER", 1797 },
{ "WERR_INVALID_PRINTER_NAME", 1801 },
{ "WERR_PRINTER_ALREADY_EXISTS", 1802 },
{ "WERR_INVALID_DATATYPE", 1804 },
{ "WERR_INVALID_ENVIRONMENT", 1805 },
{ "WERR_INVALID_FORM_NAME", 1902 },
{ "WERR_INVALID_FORM_SIZE", 1903 },
{ "WERR_BUF_TOO_SMALL", 2123 },
{ "WERR_JOB_NOT_FOUND", 2151 },
{ "WERR_DEST_NOT_FOUND", 2152 },
{ "WERR_NOT_LOCAL_DOMAIN", 2320 },
{ "WERR_PRINTER_DRIVER_IN_USE", 3001 },
{ "WERR_STATUS_MORE_ENTRIES ", 0x0105 },
/* Job control constants */
{ "JOB_CONTROL_PAUSE", JOB_CONTROL_PAUSE },
{ "JOB_CONTROL_RESUME", JOB_CONTROL_RESUME },
{ "JOB_CONTROL_CANCEL", JOB_CONTROL_CANCEL },
{ "JOB_CONTROL_RESTART", JOB_CONTROL_RESTART },
{ "JOB_CONTROL_DELETE", JOB_CONTROL_DELETE },
{ NULL },
};
static void const_init(PyObject *dict)
{
struct const_vals *tmp;
PyObject *obj;
for (tmp = module_const_vals; tmp->name; tmp++) {
obj = PyInt_FromLong(tmp->value);
PyDict_SetItemString(dict, tmp->name, obj);
Py_DECREF(obj);
}
}
/* Module initialisation */
void initspoolss(void)
{
PyObject *module, *dict;
/* Initialise module */
module = Py_InitModule("spoolss", spoolss_methods);
dict = PyModule_GetDict(module);
/* Exceptions we can raise */
spoolss_error = PyErr_NewException("spoolss.error", NULL, NULL);
PyDict_SetItemString(dict, "error", spoolss_error);
spoolss_werror = PyErr_NewException("spoolss.werror", NULL, NULL);
PyDict_SetItemString(dict, "werror", spoolss_werror);
/* Initialise policy handle object */
spoolss_policy_hnd_type.ob_type = &PyType_Type;
PyDict_SetItemString(dict, "spoolss.hnd",
(PyObject *)&spoolss_policy_hnd_type);
/* Initialise constants */
const_init(dict);
/* Do samba initialisation */
py_samba_init();
}

View File

@ -0,0 +1,420 @@
/*
Python wrappers for DCERPC/SMB client routines.
Copyright (C) Tim Potter, 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 "python/py_spoolss.h"
/* Enumerate printer drivers */
PyObject *spoolss_enumprinterdrivers(PyObject *self, PyObject *args,
PyObject *kw)
{
WERROR werror;
PyObject *result = NULL, *creds = NULL;
PRINTER_DRIVER_CTR ctr;
int level = 1, i;
uint32 needed, num_drivers;
char *arch = "Windows NT x86", *server, *errstr;
static char *kwlist[] = {"server", "level", "creds", "arch", NULL};
struct cli_state *cli = NULL;
TALLOC_CTX *mem_ctx = NULL;
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(
args, kw, "s|iOs", kwlist, &server, &level, &creds,
&arch))
return NULL;
if (server[0] != '\\' || server[1] != '\\') {
PyErr_SetString(PyExc_ValueError, "UNC name required");
return NULL;
}
server += 2;
if (creds && creds != Py_None && !PyDict_Check(creds)) {
PyErr_SetString(PyExc_TypeError,
"credentials must be dictionary or None");
return NULL;
}
/* Call rpc function */
if (!(cli = open_pipe_creds(server, creds, PIPE_SPOOLSS, &errstr))) {
PyErr_SetString(spoolss_error, errstr);
free(errstr);
goto done;
}
if (!(mem_ctx = talloc_init())) {
PyErr_SetString(
spoolss_error, "unable to init talloc context\n");
goto done;
}
werror = cli_spoolss_enumprinterdrivers(
cli, mem_ctx, 0, &needed, level, arch,
&num_drivers, &ctr);
if (W_ERROR_V(werror) == ERRinsufficientbuffer)
werror = cli_spoolss_enumprinterdrivers(
cli, mem_ctx, needed, NULL, level, arch,
&num_drivers, &ctr);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
goto done;
}
/* Return value */
switch (level) {
case 1:
result = PyDict_New();
for (i = 0; i < num_drivers; i++) {
PyObject *value;
fstring name;
rpcstr_pull(name, ctr.info1[i].name.buffer,
sizeof(fstring), -1, STR_TERMINATE);
py_from_DRIVER_INFO_1(&value, &ctr.info1[i]);
PyDict_SetItemString(result, name, value);
}
break;
case 2:
result = PyDict_New();
for(i = 0; i < num_drivers; i++) {
PyObject *value;
fstring name;
rpcstr_pull(name, ctr.info2[i].name.buffer,
sizeof(fstring), -1, STR_TERMINATE);
py_from_DRIVER_INFO_2(&value, &ctr.info2[i]);
PyDict_SetItemString(result, name, value);
}
break;
case 3:
result = PyDict_New();
for(i = 0; i < num_drivers; i++) {
PyObject *value;
fstring name;
rpcstr_pull(name, ctr.info3[i].name.buffer,
sizeof(fstring), -1, STR_TERMINATE);
py_from_DRIVER_INFO_3(&value, &ctr.info3[i]);
PyDict_SetItemString(result, name, value);
}
break;
case 6:
result = PyDict_New();
for(i = 0; i < num_drivers; i++) {
PyObject *value;
fstring name;
rpcstr_pull(name, ctr.info6[i].name.buffer,
sizeof(fstring), -1, STR_TERMINATE);
py_from_DRIVER_INFO_6(&value, &ctr.info6[i]);
PyList_SetItem(result, i, value);
}
break;
default:
PyErr_SetString(spoolss_error, "unknown info level");
goto done;
}
done:
if (cli)
cli_shutdown(cli);
if (mem_ctx)
talloc_destroy(mem_ctx);
return result;
}
/* Fetch printer driver */
PyObject *spoolss_hnd_getprinterdriver(PyObject *self, PyObject *args,
PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
WERROR werror;
PyObject *result = Py_None;
PRINTER_DRIVER_CTR ctr;
int level = 1;
uint32 needed;
char *arch = "Windows NT x86";
static char *kwlist[] = {"level", "arch", NULL};
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(
args, kw, "|is", kwlist, &level, &arch))
return NULL;
/* Call rpc function */
werror = cli_spoolss_getprinterdriver(
hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, level,
arch, &ctr);
if (W_ERROR_V(werror) == ERRinsufficientbuffer)
werror = cli_spoolss_getprinterdriver(
hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol,
level, arch, &ctr);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
/* Return value */
switch (level) {
case 1:
py_from_DRIVER_INFO_1(&result, ctr.info1);
break;
case 2:
py_from_DRIVER_INFO_2(&result, ctr.info2);
break;
case 3:
py_from_DRIVER_INFO_3(&result, ctr.info3);
break;
case 6:
py_from_DRIVER_INFO_6(&result, ctr.info6);
break;
default:
PyErr_SetString(spoolss_error, "unsupported info level");
return NULL;
}
Py_INCREF(result);
return result;
}
/* Fetch printer driver directory */
PyObject *spoolss_getprinterdriverdir(PyObject *self, PyObject *args,
PyObject *kw)
{
WERROR werror;
PyObject *result = NULL, *creds = NULL;
DRIVER_DIRECTORY_CTR ctr;
uint32 needed, level = 1;
char *arch = "Windows NT x86", *server, *errstr;
static char *kwlist[] = {"server", "level", "arch", "creds", NULL};
struct cli_state *cli = NULL;
TALLOC_CTX *mem_ctx = NULL;
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(
args, kw, "s|isO", kwlist, &server, &level,
&arch, &creds))
return NULL;
if (server[0] != '\\' || server[1] != '\\') {
PyErr_SetString(PyExc_ValueError, "UNC name required");
return NULL;
}
server += 2;
if (creds && creds != Py_None && !PyDict_Check(creds)) {
PyErr_SetString(PyExc_TypeError,
"credentials must be dictionary or None");
return NULL;
}
/* Call rpc function */
if (!(cli = open_pipe_creds(server, creds, PIPE_SPOOLSS, &errstr))) {
PyErr_SetString(spoolss_error, errstr);
free(errstr);
goto done;
}
if (!(mem_ctx = talloc_init())) {
PyErr_SetString(
spoolss_error, "unable to init talloc context\n");
goto done;
}
werror = cli_spoolss_getprinterdriverdir(
cli, mem_ctx, 0, &needed, level, arch, &ctr);
if (W_ERROR_V(werror) == ERRinsufficientbuffer)
werror = cli_spoolss_getprinterdriverdir(
cli, mem_ctx, needed, NULL, level, arch, &ctr);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
goto done;
}
/* Return value */
switch (level) {
case 1:
py_from_DRIVER_DIRECTORY_1(&result, ctr.info1);
break;
default:
PyErr_SetString(spoolss_error, "unknown info level");
goto done;
}
done:
if (cli)
cli_shutdown(cli);
if (mem_ctx)
talloc_destroy(mem_ctx);
return result;
}
PyObject *spoolss_addprinterdriver(PyObject *self, PyObject *args,
PyObject *kw)
{
static char *kwlist[] = { "server", "info", "creds", NULL };
char *server, *errstr;
uint32 level;
PyObject *info, *result = NULL, *creds = NULL;
WERROR werror;
TALLOC_CTX *mem_ctx = NULL;
struct cli_state *cli = NULL;
PRINTER_DRIVER_CTR ctr;
union {
DRIVER_INFO_3 driver_3;
} dinfo;
if (!PyArg_ParseTupleAndKeywords(
args, kw, "sO!|O", kwlist, &server, &PyDict_Type,
&info, &creds))
return NULL;
if (server[0] == '\\' || server[1] == '\\')
server += 2;
if (creds && creds != Py_None && !PyDict_Check(creds)) {
PyErr_SetString(PyExc_TypeError,
"credentials must be dictionary or None");
return NULL;
}
if (!(mem_ctx = talloc_init())) {
PyErr_SetString(
spoolss_error, "unable to init talloc context\n");
return NULL;
}
if (!(cli = open_pipe_creds(server, creds, PIPE_SPOOLSS, &errstr))) {
PyErr_SetString(spoolss_error, errstr);
free(errstr);
goto done;
}
if (!get_level_value(info, &level)) {
PyErr_SetString(spoolss_error, "invalid info level");
goto done;
}
if (level != 3) {
PyErr_SetString(spoolss_error, "unsupported info level");
goto done;
}
ZERO_STRUCT(ctr);
switch(level) {
case 3:
ctr.info3 = &dinfo.driver_3;
if (!py_to_DRIVER_INFO_3(&dinfo.driver_3, info)) {
PyErr_SetString(spoolss_error,
"error converting to driver info 3");
goto done;
}
break;
default:
PyErr_SetString(spoolss_error, "unsupported info level");
goto done;
}
werror = cli_spoolss_addprinterdriver(cli, mem_ctx, level, &ctr);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
goto done;
}
Py_INCREF(Py_None);
result = Py_None;
done:
if (cli)
cli_shutdown(cli);
if (mem_ctx)
talloc_destroy(mem_ctx);
return result;
}
PyObject *spoolss_addprinterdriverex(PyObject *self, PyObject *args,
PyObject *kw)
{
/* Not supported by Samba server */
PyErr_SetString(spoolss_error, "Not implemented");
return NULL;
}
PyObject *spoolss_deleteprinterdriver(PyObject *self, PyObject *args,
PyObject *kw)
{
PyErr_SetString(spoolss_error, "Not implemented");
return NULL;
}
PyObject *spoolss_deleteprinterdriverex(PyObject *self, PyObject *args,
PyObject *kw)
{
PyErr_SetString(spoolss_error, "Not implemented");
return NULL;
}

View File

@ -0,0 +1,177 @@
/*
Python wrappers for DCERPC/SMB client routines.
Copyright (C) Tim Potter, 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 "python/py_spoolss.h"
#include "python/py_conv.h"
/* Structure/hash conversions */
struct pyconv py_DRIVER_INFO_1[] = {
{ "name", PY_UNISTR, offsetof(DRIVER_INFO_1, name) },
{ NULL }
};
struct pyconv py_DRIVER_INFO_2[] = {
{ "version", PY_UINT32, offsetof(DRIVER_INFO_2, version) },
{ "name", PY_UNISTR, offsetof(DRIVER_INFO_2, name) },
{ "architecture", PY_UNISTR, offsetof(DRIVER_INFO_2, architecture) },
{ "driver_path", PY_UNISTR, offsetof(DRIVER_INFO_2, driverpath) },
{ "data_file", PY_UNISTR, offsetof(DRIVER_INFO_2, datafile) },
{ "config_file", PY_UNISTR, offsetof(DRIVER_INFO_2, configfile) },
{ NULL }
};
struct pyconv py_DRIVER_INFO_3[] = {
{ "version", PY_UINT32, offsetof(DRIVER_INFO_3, version) },
{ "name", PY_UNISTR, offsetof(DRIVER_INFO_3, name) },
{ "architecture", PY_UNISTR, offsetof(DRIVER_INFO_3, architecture) },
{ "driver_path", PY_UNISTR, offsetof(DRIVER_INFO_3, driverpath) },
{ "data_file", PY_UNISTR, offsetof(DRIVER_INFO_3, datafile) },
{ "config_file", PY_UNISTR, offsetof(DRIVER_INFO_3, configfile) },
{ "help_file", PY_UNISTR, offsetof(DRIVER_INFO_3, helpfile) },
{ "monitor_name", PY_UNISTR, offsetof(DRIVER_INFO_3, monitorname) },
{ "default_datatype", PY_UNISTR, offsetof(DRIVER_INFO_3, defaultdatatype) },
{ NULL }
};
struct pyconv py_DRIVER_INFO_6[] = {
{ "version", PY_UINT32, offsetof(DRIVER_INFO_6, version) },
{ "name", PY_UNISTR, offsetof(DRIVER_INFO_6, name) },
{ "architecture", PY_UNISTR, offsetof(DRIVER_INFO_6, architecture) },
{ "driver_path", PY_UNISTR, offsetof(DRIVER_INFO_6, driverpath) },
{ "data_file", PY_UNISTR, offsetof(DRIVER_INFO_6, datafile) },
{ "config_file", PY_UNISTR, offsetof(DRIVER_INFO_6, configfile) },
{ "help_file", PY_UNISTR, offsetof(DRIVER_INFO_6, helpfile) },
{ "monitor_name", PY_UNISTR, offsetof(DRIVER_INFO_6, monitorname) },
{ "default_datatype", PY_UNISTR, offsetof(DRIVER_INFO_6, defaultdatatype) },
/* driver_date */
{ "padding", PY_UINT32, offsetof(DRIVER_INFO_6, padding) },
{ "driver_version_low", PY_UINT32, offsetof(DRIVER_INFO_6, driver_version_low) },
{ "driver_version_high", PY_UINT32, offsetof(DRIVER_INFO_6, driver_version_high) },
{ "mfg_name", PY_UNISTR, offsetof(DRIVER_INFO_6, mfgname) },
{ "oem_url", PY_UNISTR, offsetof(DRIVER_INFO_6, oem_url) },
{ "hardware_id", PY_UNISTR, offsetof(DRIVER_INFO_6, hardware_id) },
{ "provider", PY_UNISTR, offsetof(DRIVER_INFO_6, provider) },
{ NULL }
};
struct pyconv py_DRIVER_DIRECTORY_1[] = {
{ "name", PY_UNISTR, offsetof(DRIVER_DIRECTORY_1, name) },
{ NULL }
};
/* Convert a NULL terminated list of NULL terminated unicode strings
to a list of (char *) strings */
static PyObject *from_dependentfiles(uint16 *dependentfiles)
{
PyObject *list;
int offset = 0;
list = PyList_New(0);
while (*(dependentfiles + offset) != 0) {
fstring name;
int len;
len = rpcstr_pull(name, dependentfiles + offset,
sizeof(fstring), -1, STR_TERMINATE);
offset += len / 2;
PyList_Append(list, PyString_FromString(name));
}
return list;
}
BOOL py_from_DRIVER_INFO_1(PyObject **dict, DRIVER_INFO_1 *info)
{
*dict = from_struct(info, py_DRIVER_INFO_1);
PyDict_SetItemString(*dict, "level", PyInt_FromLong(1));
return True;
}
BOOL py_to_DRIVER_INFO_1(DRIVER_INFO_1 *info, PyObject *dict)
{
return False;
}
BOOL py_from_DRIVER_INFO_2(PyObject **dict, DRIVER_INFO_2 *info)
{
*dict = from_struct(info, py_DRIVER_INFO_2);
PyDict_SetItemString(*dict, "level", PyInt_FromLong(2));
return True;
}
BOOL py_to_DRIVER_INFO_2(DRIVER_INFO_2 *info, PyObject *dict)
{
return False;
}
BOOL py_from_DRIVER_INFO_3(PyObject **dict, DRIVER_INFO_3 *info)
{
*dict = from_struct(info, py_DRIVER_INFO_3);
PyDict_SetItemString(*dict, "level", PyInt_FromLong(3));
PyDict_SetItemString(
*dict, "dependent_files",
from_dependentfiles(info->dependentfiles));
return True;
}
BOOL py_to_DRIVER_INFO_3(DRIVER_INFO_3 *info, PyObject *dict)
{
PyObject *dict_copy = PyDict_Copy(dict);
BOOL result;
PyDict_DelItemString(dict_copy, "level");
result = to_struct(info, dict_copy, py_DRIVER_INFO_3);
Py_DECREF(dict_copy);
return result;
}
BOOL py_from_DRIVER_INFO_6(PyObject **dict, DRIVER_INFO_6 *info)
{
*dict = from_struct(info, py_DRIVER_INFO_6);
PyDict_SetItemString(*dict, "level", PyInt_FromLong(6));
PyDict_SetItemString(
*dict, "dependent_files",
from_dependentfiles (info->dependentfiles));
return True;
}
BOOL py_to_DRIVER_INFO_6(DRIVER_INFO_6 *info, PyObject *dict)
{
return False;
}
BOOL py_from_DRIVER_DIRECTORY_1(PyObject **dict, DRIVER_DIRECTORY_1 *info)
{
*dict = from_struct(info, py_DRIVER_DIRECTORY_1);
PyDict_SetItemString(*dict, "level", PyInt_FromLong(1));
return True;
}
BOOL py_to_DRIVER_DIRECTORY_1(DRIVER_DIRECTORY_1 *info, PyObject *dict)
{
return False;
}

View File

@ -0,0 +1,266 @@
/*
Python wrappers for DCERPC/SMB client routines.
Copyright (C) Tim Potter, 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 "python/py_spoolss.h"
/* Add a form */
PyObject *spoolss_hnd_addform(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
WERROR werror;
PyObject *info;
FORM form;
int level;
static char *kwlist[] = {"form", NULL};
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(
args, kw, "O!", kwlist, &PyDict_Type, &info))
return NULL;
/* Call rpc function */
if (!py_to_FORM(&form, info)) {
PyErr_SetString(spoolss_error, "invalid form");
return NULL;
}
if (!get_level_value(info, &level)) {
PyErr_SetString(spoolss_error, "invalid info level");
return NULL;
}
if (level != 1) {
PyErr_SetString(spoolss_error, "unsupported info level");
return NULL;
}
switch (level) {
case 1: {
PyObject *obj = PyDict_GetItemString(info, "name");
char *form_name = PyString_AsString(obj);
init_unistr2(&form.name, form_name, strlen(form_name) + 1);
break;
}
default:
PyErr_SetString(spoolss_error, "unsupported info level");
return NULL;
}
werror = cli_spoolss_addform(hnd->cli, hnd->mem_ctx, &hnd->pol,
level, &form);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
/* Get form properties */
PyObject *spoolss_hnd_getform(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
WERROR werror;
PyObject *result;
char *form_name;
int level = 1;
static char *kwlist[] = {"form_name", "level", NULL};
uint32 needed;
FORM_1 form;
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(
args, kw, "s|i", kwlist, &form_name, &level))
return NULL;
/* Call rpc function */
werror = cli_spoolss_getform(hnd->cli, hnd->mem_ctx, 0, &needed,
&hnd->pol, form_name, level, &form);
if (W_ERROR_V(werror) == ERRinsufficientbuffer)
werror = cli_spoolss_getform(
hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol,
form_name, 1, &form);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
result = Py_None;
switch(level) {
case 1:
py_from_FORM_1(&result, &form);
break;
}
Py_INCREF(result);
return result;
}
/* Set form properties */
PyObject *spoolss_hnd_setform(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
WERROR werror;
PyObject *info, *form_name;
int level;
static char *kwlist[] = { "form", NULL};
FORM form;
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(
args, kw, "O!", kwlist, &PyDict_Type, &info))
return NULL;
if (!get_level_value(info, &level)) {
PyErr_SetString(spoolss_error, "invalid info level");
return NULL;
}
if (level != 1) {
PyErr_SetString(spoolss_error, "unsupported info level");
return NULL;
}
/* Call rpc function */
if (!py_to_FORM(&form, info)) {
PyErr_SetString(spoolss_error, "invalid form");
return NULL;
}
form_name = PyDict_GetItemString(info, "name");
werror = cli_spoolss_setform(
hnd->cli, hnd->mem_ctx, &hnd->pol, level,
PyString_AsString(form_name), &form);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
/* Delete a form */
PyObject *spoolss_hnd_deleteform(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
WERROR werror;
static char *kwlist[] = {"form_name", NULL};
char *form_name;
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(
args, kw, "s", kwlist, &form_name))
return NULL;
/* Call rpc function */
werror = cli_spoolss_deleteform(
hnd->cli, hnd->mem_ctx, &hnd->pol, form_name);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
/* Enumerate forms */
PyObject *spoolss_hnd_enumforms(PyObject *self, PyObject *args, PyObject *kw)
{
PyObject *result;
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
WERROR werror;
uint32 level = 1, num_forms, needed, i;
static char *kwlist[] = {"level", NULL};
FORM_1 *forms;
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(
args, kw, "|i", kwlist, &level))
return NULL;
/* Call rpc function */
werror = cli_spoolss_enumforms(
hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, level,
&num_forms, &forms);
if (W_ERROR_V(werror) == ERRinsufficientbuffer)
werror = cli_spoolss_enumforms(
hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol, level,
&num_forms, &forms);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
switch(level) {
case 1:
result = PyDict_New();
for (i = 0; i < num_forms; i++) {
PyObject *value;
fstring name;
rpcstr_pull(name, forms[i].name.buffer,
sizeof(fstring), -1, STR_TERMINATE);
py_from_FORM_1(&value, &forms[i]);
PyDict_SetItemString(
value, "level", PyInt_FromLong(1));
PyDict_SetItemString(result, name, value);
}
break;
default:
PyErr_SetString(spoolss_error, "unknown info level");
return NULL;
}
return result;
}

View File

@ -0,0 +1,377 @@
/*
Python wrappers for DCERPC/SMB client routines.
Copyright (C) Tim Potter, 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 "python/py_spoolss.h"
/* Enumerate jobs */
PyObject *spoolss_hnd_enumjobs(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
WERROR werror;
PyObject *result;
int level = 1;
uint32 i, needed, num_jobs;
static char *kwlist[] = {"level", NULL};
JOB_INFO_CTR ctr;
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(args, kw, "|i", kwlist, &level))
return NULL;
/* Call rpc function */
werror = cli_spoolss_enumjobs(
hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, level, 0,
1000, &num_jobs, &ctr);
if (W_ERROR_V(werror) == ERRinsufficientbuffer)
werror = cli_spoolss_enumjobs(
hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol,
level, 0, 1000, &num_jobs, &ctr);
/* Return value */
result = Py_None;
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
goto done;
}
result = PyList_New(num_jobs);
switch (level) {
case 1:
for (i = 0; i < num_jobs; i++) {
PyObject *value;
py_from_JOB_INFO_1(&value, &ctr.job.job_info_1[i]);
PyList_SetItem(result, i, value);
}
break;
case 2:
for(i = 0; i < num_jobs; i++) {
PyObject *value;
py_from_JOB_INFO_2(&value, &ctr.job.job_info_2[i]);
PyList_SetItem(result, i, value);
}
break;
}
done:
Py_INCREF(result);
return result;
}
/* Set job command */
PyObject *spoolss_hnd_setjob(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
WERROR werror;
uint32 level = 0, command, jobid;
static char *kwlist[] = {"jobid", "command", "level", NULL};
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(
args, kw, "ii|i", kwlist, &jobid, &command, &level))
return NULL;
/* Call rpc function */
werror = cli_spoolss_setjob(hnd->cli, hnd->mem_ctx, &hnd->pol,
jobid, level, command);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
/* Get job */
PyObject *spoolss_hnd_getjob(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
WERROR werror;
PyObject *result;
uint32 level = 1, jobid, needed;
static char *kwlist[] = {"jobid", "level", NULL};
JOB_INFO_CTR ctr;
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(
args, kw, "i|i", kwlist, &jobid, &level))
return NULL;
/* Call rpc function */
werror = cli_spoolss_getjob(hnd->cli, hnd->mem_ctx, 0, &needed,
&hnd->pol, jobid, level, &ctr);
if (W_ERROR_V(werror) == ERRinsufficientbuffer)
werror = cli_spoolss_getjob(
hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol,
jobid, level, &ctr);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
switch(level) {
case 1:
py_from_JOB_INFO_1(&result, &ctr.job.job_info_1[0]);
break;
case 2:
py_from_JOB_INFO_2(&result, &ctr.job.job_info_2[0]);
break;
}
return result;
}
/* Start page printer. This notifies the spooler that a page is about to be
printed on the specified printer. */
PyObject *spoolss_hnd_startpageprinter(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
WERROR werror;
static char *kwlist[] = { NULL };
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(args, kw, "", kwlist))
return NULL;
/* Call rpc function */
werror = cli_spoolss_startpageprinter(
hnd->cli, hnd->mem_ctx, &hnd->pol);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
/* End page printer. This notifies the spooler that a page has finished
being printed on the specified printer. */
PyObject *spoolss_hnd_endpageprinter(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
WERROR werror;
static char *kwlist[] = { NULL };
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(args, kw, "", kwlist))
return NULL;
/* Call rpc function */
werror = cli_spoolss_endpageprinter(
hnd->cli, hnd->mem_ctx, &hnd->pol);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
/* Start doc printer. This notifies the spooler that a document is about to be
printed on the specified printer. */
PyObject *spoolss_hnd_startdocprinter(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
WERROR werror;
static char *kwlist[] = { "document_info", NULL };
PyObject *info, *obj;
uint32 level, jobid;
char *document_name = NULL, *output_file = NULL, *data_type = NULL;
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(
args, kw, "O!", kwlist, &PyDict_Type, &info))
return NULL;
/* Check document_info parameter */
if (!get_level_value(info, &level)) {
PyErr_SetString(spoolss_error, "invalid info level");
return NULL;
}
if (level != 1) {
PyErr_SetString(spoolss_error, "unsupported info level");
return NULL;
}
if ((obj = PyDict_GetItemString(info, "document_name"))) {
if (!PyString_Check(obj) && obj != Py_None) {
PyErr_SetString(spoolss_error,
"document_name not a string");
return NULL;
}
if (PyString_Check(obj))
document_name = PyString_AsString(obj);
} else {
PyErr_SetString(spoolss_error, "no document_name present");
return NULL;
}
if ((obj = PyDict_GetItemString(info, "output_file"))) {
if (!PyString_Check(obj) && obj != Py_None) {
PyErr_SetString(spoolss_error,
"output_file not a string");
return NULL;
}
if (PyString_Check(obj))
output_file = PyString_AsString(obj);
} else {
PyErr_SetString(spoolss_error, "no output_file present");
return NULL;
}
if ((obj = PyDict_GetItemString(info, "data_type"))) {
if (!PyString_Check(obj) && obj != Py_None) {
PyErr_SetString(spoolss_error,
"data_type not a string");
return NULL;
}
if (PyString_Check(obj))
data_type = PyString_AsString(obj);
} else {
PyErr_SetString(spoolss_error, "no data_type present");
return NULL;
}
/* Call rpc function */
werror = cli_spoolss_startdocprinter(
hnd->cli, hnd->mem_ctx, &hnd->pol, document_name,
output_file, data_type, &jobid);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
/* The return value is zero for an error (where does the status
code come from now??) and the return value is the jobid
allocated for the new job. */
return Py_BuildValue("i", jobid);
}
/* End doc printer. This notifies the spooler that a document has finished
being printed on the specified printer. */
PyObject *spoolss_hnd_enddocprinter(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
WERROR werror;
static char *kwlist[] = { NULL };
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(args, kw, "", kwlist))
return NULL;
/* Call rpc function */
werror = cli_spoolss_enddocprinter(hnd->cli, hnd->mem_ctx, &hnd->pol);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
/* Write data to a printer */
PyObject *spoolss_hnd_writeprinter(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
WERROR werror;
static char *kwlist[] = { "data", NULL };
PyObject *data;
uint32 num_written;
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(
args, kw, "O!", kwlist, &PyString_Type, &data))
return NULL;
/* Call rpc function */
werror = cli_spoolss_writeprinter(
hnd->cli, hnd->mem_ctx, &hnd->pol, PyString_Size(data),
PyString_AsString(data), &num_written);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
PyObject *spoolss_hnd_addjob(PyObject *self, PyObject *args, PyObject *kw)
{
PyErr_SetString(spoolss_error, "Not implemented");
return NULL;
}

View File

@ -0,0 +1,393 @@
/*
Python wrappers for DCERPC/SMB client routines.
Copyright (C) Tim Potter, 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 "python/py_spoolss.h"
static BOOL py_from_printerdata(PyObject **dict, char *key, char *value,
uint16 data_type, uint8 *data,
uint32 data_size)
{
*dict = PyDict_New();
PyDict_SetItemString(*dict, "key", Py_BuildValue("s", key ? key : ""));
PyDict_SetItemString(*dict, "value", Py_BuildValue("s", value));
PyDict_SetItemString(*dict, "type", Py_BuildValue("i", data_type));
PyDict_SetItemString(*dict, "data",
Py_BuildValue("s#", data, data_size));
return True;
}
static BOOL py_to_printerdata(char **key, char **value, uint16 *data_type,
uint8 **data, uint32 *data_size,
PyObject *dict)
{
PyObject *obj;
if ((obj = PyDict_GetItemString(dict, "key"))) {
if (!PyString_Check(obj)) {
PyErr_SetString(spoolss_error,
"key not a string");
return False;
}
if (key) {
*key = PyString_AsString(obj);
if (!key[0])
*key = NULL;
}
} else
*key = NULL;
if ((obj = PyDict_GetItemString(dict, "value"))) {
if (!PyString_Check(obj)) {
PyErr_SetString(spoolss_error,
"value not a string");
return False;
}
*value = PyString_AsString(obj);
} else {
PyErr_SetString(spoolss_error, "no value present");
return False;
}
if ((obj = PyDict_GetItemString(dict, "type"))) {
if (!PyInt_Check(obj)) {
PyErr_SetString(spoolss_error,
"type not an integer");
return False;
}
*data_type = PyInt_AsLong(obj);
} else {
PyErr_SetString(spoolss_error, "no type present");
return False;
}
if ((obj = PyDict_GetItemString(dict, "data"))) {
if (!PyString_Check(obj)) {
PyErr_SetString(spoolss_error,
"data not a string");
return False;
}
*data = PyString_AsString(obj);
*data_size = PyString_Size(obj);
} else {
PyErr_SetString(spoolss_error, "no data present");
return False;
}
return True;
}
PyObject *spoolss_hnd_getprinterdata(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
static char *kwlist[] = { "value", NULL };
char *valuename;
WERROR werror;
uint32 needed;
PyObject *result;
REGISTRY_VALUE value;
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(args, kw, "s", kwlist, &valuename))
return NULL;
/* Call rpc function */
werror = cli_spoolss_getprinterdata(
hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, valuename,
&value);
if (W_ERROR_V(werror) == ERRmoredata)
werror = cli_spoolss_getprinterdata(
hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol,
valuename, &value);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
py_from_printerdata(
&result, NULL, valuename, value.type, value.data_p,
value.size);
return result;
}
PyObject *spoolss_hnd_setprinterdata(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
static char *kwlist[] = { "data", NULL };
PyObject *py_data;
char *valuename;
WERROR werror;
REGISTRY_VALUE value;
if (!PyArg_ParseTupleAndKeywords(
args, kw, "O!", kwlist, &PyDict_Type, &py_data))
return NULL;
if (!py_to_printerdata(
NULL, &valuename, &value.type, &value.data_p,
&value.size, py_data))
return NULL;
fstrcpy(value.valuename, valuename);
/* Call rpc function */
werror = cli_spoolss_setprinterdata(
hnd->cli, hnd->mem_ctx, &hnd->pol, &value);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
PyObject *spoolss_hnd_enumprinterdata(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
static char *kwlist[] = { NULL };
uint32 data_needed, value_needed, ndx = 0;
WERROR werror;
PyObject *result;
REGISTRY_VALUE value;
if (!PyArg_ParseTupleAndKeywords(args, kw, "", kwlist))
return NULL;
/* Get max buffer sizes for value and data */
werror = cli_spoolss_enumprinterdata(
hnd->cli, hnd->mem_ctx, &hnd->pol, ndx, 0, 0,
&value_needed, &data_needed, NULL);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
/* Iterate over all printerdata */
result = PyDict_New();
while (W_ERROR_IS_OK(werror)) {
PyObject *obj;
werror = cli_spoolss_enumprinterdata(
hnd->cli, hnd->mem_ctx, &hnd->pol, ndx,
value_needed, data_needed, NULL, NULL, &value);
if (py_from_printerdata(
&obj, NULL, value.valuename, value.type,
value.data_p, value.size))
PyDict_SetItemString(result, value.valuename, obj);
ndx++;
}
return result;
}
PyObject *spoolss_hnd_deleteprinterdata(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
static char *kwlist[] = { "value", NULL };
char *value;
WERROR werror;
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(args, kw, "s", kwlist, &value))
return NULL;
/* Call rpc function */
werror = cli_spoolss_deleteprinterdata(
hnd->cli, hnd->mem_ctx, &hnd->pol, value);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
PyObject *spoolss_hnd_getprinterdataex(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
static char *kwlist[] = { "key", "value", NULL };
char *key, *valuename;
WERROR werror;
uint32 needed;
PyObject *result;
REGISTRY_VALUE value;
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(args, kw, "ss", kwlist, &key, &valuename))
return NULL;
/* Call rpc function */
werror = cli_spoolss_getprinterdataex(
hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, key,
valuename, &value);
if (W_ERROR_V(werror) == ERRmoredata)
werror = cli_spoolss_getprinterdataex(
hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol, key,
valuename, &value);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
py_from_printerdata(
&result, key, valuename, value.type, value.data_p, value.size);
return result;
}
PyObject *spoolss_hnd_setprinterdataex(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
static char *kwlist[] = { "data", NULL };
PyObject *py_data;
char *keyname, *valuename;
WERROR werror;
REGISTRY_VALUE value;
if (!PyArg_ParseTupleAndKeywords(
args, kw, "O!", kwlist, &PyDict_Type, &py_data))
return NULL;
if (!py_to_printerdata(
&keyname, &valuename, &value.type, &value.data_p, &value.size, py_data))
return NULL;
fstrcpy(value.valuename, valuename);
/* Call rpc function */
werror = cli_spoolss_setprinterdataex(
hnd->cli, hnd->mem_ctx, &hnd->pol, keyname, &value);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
PyObject *spoolss_hnd_enumprinterdataex(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
static char *kwlist[] = { "key", NULL };
uint32 needed, i;
char *key;
WERROR werror;
PyObject *result;
REGVAL_CTR ctr;
if (!PyArg_ParseTupleAndKeywords(args, kw, "s", kwlist, &key))
return NULL;
/* Get max buffer sizes for value and data */
werror = cli_spoolss_enumprinterdataex(
hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, key, &ctr);
if (W_ERROR_V(werror) == ERRmoredata)
werror = cli_spoolss_enumprinterdataex(
hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol, key,
&ctr);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
/* Iterate over all printerdata */
result = PyDict_New();
for (i = 0; i < regval_ctr_numvals(&ctr); i++) {
REGISTRY_VALUE *value;
PyObject *item;
item = PyDict_New();
value = regval_ctr_specific_value(&ctr, i);
if (py_from_printerdata(
&item, key, value->valuename, value->type,
value->data_p, value->size))
PyDict_SetItemString(result, value->valuename, item);
}
return result;
}
PyObject *spoolss_hnd_deleteprinterdataex(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
static char *kwlist[] = { "key", "value", NULL };
char *key, *value;
WERROR werror;
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(args, kw, "ss", kwlist, &key, &value))
return NULL;
/* Call rpc function */
werror = cli_spoolss_deleteprinterdataex(
hnd->cli, hnd->mem_ctx, &hnd->pol, key, value);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}

View File

@ -0,0 +1,475 @@
/*
Python wrappers for DCERPC/SMB client routines.
Copyright (C) Tim Potter, 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 "python/py_spoolss.h"
/* Open a printer */
PyObject *spoolss_openprinter(PyObject *self, PyObject *args, PyObject *kw)
{
char *unc_name, *server, *errstr;
TALLOC_CTX *mem_ctx = NULL;
POLICY_HND hnd;
WERROR werror;
PyObject *result = NULL, *creds = NULL;
static char *kwlist[] = { "printername", "creds", "access", NULL };
uint32 desired_access = MAXIMUM_ALLOWED_ACCESS;
struct cli_state *cli;
if (!PyArg_ParseTupleAndKeywords(
args, kw, "s|Oi", kwlist, &unc_name, &creds,
&desired_access))
return NULL;
if (unc_name[0] != '\\' || unc_name[1] != '\\') {
PyErr_SetString(PyExc_ValueError, "UNC name required");
return NULL;
}
server = strdup(unc_name + 2);
if (strchr(server, '\\')) {
char *c = strchr(server, '\\');
*c = 0;
}
if (creds && creds != Py_None && !PyDict_Check(creds)) {
PyErr_SetString(PyExc_TypeError,
"credentials must be dictionary or None");
return NULL;
}
if (!(cli = open_pipe_creds(server, creds, PIPE_SPOOLSS, &errstr))) {
PyErr_SetString(spoolss_error, errstr);
free(errstr);
goto done;
}
if (!(mem_ctx = talloc_init())) {
PyErr_SetString(spoolss_error,
"unable to init talloc context\n");
goto done;
}
werror = cli_spoolss_open_printer_ex(
cli, mem_ctx, unc_name, "", desired_access, server,
"", &hnd);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
goto done;
}
result = new_spoolss_policy_hnd_object(cli, mem_ctx, &hnd);
done:
if (!result) {
if (cli)
cli_shutdown(cli);
if (mem_ctx)
talloc_destroy(mem_ctx);
}
SAFE_FREE(server);
return result;
}
/* Close a printer */
PyObject *spoolss_closeprinter(PyObject *self, PyObject *args)
{
PyObject *po;
spoolss_policy_hnd_object *hnd;
WERROR result;
/* Parse parameters */
if (!PyArg_ParseTuple(args, "O!", &spoolss_policy_hnd_type, &po))
return NULL;
hnd = (spoolss_policy_hnd_object *)po;
/* Call rpc function */
result = cli_spoolss_close_printer(hnd->cli, hnd->mem_ctx, &hnd->pol);
/* Return value */
Py_INCREF(Py_None);
return Py_None;
}
/* Fetch printer information */
PyObject *spoolss_hnd_getprinter(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
WERROR werror;
PyObject *result = NULL;
PRINTER_INFO_CTR ctr;
int level = 1;
uint32 needed;
static char *kwlist[] = {"level", NULL};
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(args, kw, "|i", kwlist, &level))
return NULL;
ZERO_STRUCT(ctr);
/* Call rpc function */
werror = cli_spoolss_getprinter(
hnd->cli, hnd->mem_ctx, 0, &needed, &hnd->pol, level, &ctr);
if (W_ERROR_V(werror) == ERRinsufficientbuffer)
werror = cli_spoolss_getprinter(
hnd->cli, hnd->mem_ctx, needed, NULL, &hnd->pol,
level, &ctr);
/* Return value */
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
result = Py_None;
switch (level) {
case 0:
py_from_PRINTER_INFO_0(&result, ctr.printers_0);
break;
case 1:
py_from_PRINTER_INFO_1(&result, ctr.printers_1);
break;
case 2:
py_from_PRINTER_INFO_2(&result, ctr.printers_2);
break;
case 3:
py_from_PRINTER_INFO_3(&result, ctr.printers_3);
break;
}
Py_INCREF(result);
return result;
}
/* Set printer information */
PyObject *spoolss_hnd_setprinter(PyObject *self, PyObject *args, PyObject *kw)
{
spoolss_policy_hnd_object *hnd = (spoolss_policy_hnd_object *)self;
WERROR werror;
PyObject *info;
PRINTER_INFO_CTR ctr;
uint32 level;
static char *kwlist[] = {"dict", NULL};
union {
PRINTER_INFO_1 printers_1;
PRINTER_INFO_2 printers_2;
PRINTER_INFO_3 printers_3;
} pinfo;
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(
args, kw, "O!", kwlist, &PyDict_Type, &info))
return NULL;
if (!get_level_value(info, &level)) {
PyErr_SetString(spoolss_error, "invalid info level");
return NULL;
}
if (level < 1 && level > 3) {
PyErr_SetString(spoolss_error, "unsupported info level");
return NULL;
}
/* Fill in printer info */
ZERO_STRUCT(ctr);
switch (level) {
case 1:
ctr.printers_1 = &pinfo.printers_1;
if (!py_to_PRINTER_INFO_1(ctr.printers_1, info)){
PyErr_SetString(spoolss_error,
"error converting printer to info 1");
return NULL;
}
break;
case 2:
ctr.printers_2 = &pinfo.printers_2;
if (!py_to_PRINTER_INFO_2(ctr.printers_2, info,
hnd->mem_ctx)){
PyErr_SetString(spoolss_error,
"error converting printer to info 2");
return NULL;
}
break;
case 3:
ctr.printers_3 = &pinfo.printers_3;
if (!py_to_PRINTER_INFO_3(ctr.printers_3, info,
hnd->mem_ctx)) {
PyErr_SetString(spoolss_error,
"error converting to printer info 3");
return NULL;
}
break;
default:
PyErr_SetString(spoolss_error, "unsupported info level");
return NULL;
}
/* Call rpc function */
werror = cli_spoolss_setprinter(hnd->cli, hnd->mem_ctx, &hnd->pol,
level, &ctr, 0);
/* Return value */
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
/* Enumerate printers */
PyObject *spoolss_enumprinters(PyObject *self, PyObject *args, PyObject *kw)
{
WERROR werror;
PyObject *result = NULL, *creds = NULL;
PRINTER_INFO_CTR ctr;
int level = 1, flags = PRINTER_ENUM_LOCAL, i;
uint32 needed, num_printers;
static char *kwlist[] = {"server", "name", "level", "flags",
"creds", NULL};
TALLOC_CTX *mem_ctx = NULL;
struct cli_state *cli = NULL;
char *server, *errstr, *name = NULL;
/* Parse parameters */
if (!PyArg_ParseTupleAndKeywords(
args, kw, "s|siiO", kwlist, &server, &name, &level,
&flags, &creds))
return NULL;
if (server[0] != '\\' || server[1] != '\\') {
PyErr_SetString(PyExc_ValueError, "UNC name required");
return NULL;
}
server += 2;
if (creds && creds != Py_None && !PyDict_Check(creds)) {
PyErr_SetString(PyExc_TypeError,
"credentials must be dictionary or None");
return NULL;
}
if (!(cli = open_pipe_creds(server, creds, PIPE_SPOOLSS, &errstr))) {
PyErr_SetString(spoolss_error, errstr);
free(errstr);
goto done;
}
if (!(mem_ctx = talloc_init())) {
PyErr_SetString(
spoolss_error, "unable to init talloc context\n");
goto done;
}
/* This RPC is weird. By setting the server name to different
values we can get different behaviour. If however the server
name is not specified, we default it to being the full server
name as this is probably what the caller intended. To pass a
NULL name, pass a value of "" */
if (!name)
name = server;
else {
if (!name[0])
name = NULL;
}
/* Call rpc function */
werror = cli_spoolss_enum_printers(
cli, mem_ctx, 0, &needed, name, flags, level,
&num_printers, &ctr);
if (W_ERROR_V(werror) == ERRinsufficientbuffer)
werror = cli_spoolss_enum_printers(
cli, mem_ctx, needed, NULL, name, flags,
level, &num_printers, &ctr);
if (!W_ERROR_IS_OK(werror)) {
PyErr_SetObject(spoolss_werror, py_werror_tuple(werror));
goto done;
}
/* Return value */
switch (level) {
case 0:
result = PyDict_New();
for (i = 0; i < num_printers; i++) {
PyObject *value;
fstring name;
rpcstr_pull(name, ctr.printers_0[i].printername.buffer,
sizeof(fstring), -1, STR_TERMINATE);
py_from_PRINTER_INFO_0(&value, &ctr.printers_0[i]);
PyDict_SetItemString(
value, "level", PyInt_FromLong(0));
PyDict_SetItemString(result, name, value);
}
break;
case 1:
result = PyDict_New();
for(i = 0; i < num_printers; i++) {
PyObject *value;
fstring name;
rpcstr_pull(name, ctr.printers_1[i].name.buffer,
sizeof(fstring), -1, STR_TERMINATE);
py_from_PRINTER_INFO_1(&value, &ctr.printers_1[i]);
PyDict_SetItemString(
value, "level", PyInt_FromLong(1));
PyDict_SetItemString(result, name, value);
}
break;
case 2:
result = PyDict_New();
for(i = 0; i < num_printers; i++) {
PyObject *value;
fstring name;
rpcstr_pull(name, ctr.printers_2[i].printername.buffer,
sizeof(fstring), -1, STR_TERMINATE);
py_from_PRINTER_INFO_2(&value, &ctr.printers_2[i]);
PyDict_SetItemString(
value, "level", PyInt_FromLong(2));
PyDict_SetItemString(result, name, value);
}
break;
default:
PyErr_SetString(spoolss_error, "unknown info level");
goto done;
}
done:
if (cli)
cli_shutdown(cli);
if (mem_ctx)
talloc_destroy(mem_ctx);
return result;
}
/* Add a printer */
PyObject *spoolss_addprinterex(PyObject *self, PyObject *args, PyObject *kw)
{
static char *kwlist[] = { "server", "printername", "info", "creds",
NULL};
char *printername, *server, *errstr;
PyObject *info, *result = NULL, *creds = NULL;
struct cli_state *cli = NULL;
TALLOC_CTX *mem_ctx = NULL;
PRINTER_INFO_CTR ctr;
PRINTER_INFO_2 info2;
WERROR werror;
if (!PyArg_ParseTupleAndKeywords(
args, kw, "ssO!|O!", kwlist, &server, &printername,
&PyDict_Type, &info, &PyDict_Type, &creds))
return NULL;
if (!(cli = open_pipe_creds(server, creds, PIPE_SPOOLSS, &errstr))) {
PyErr_SetString(spoolss_error, errstr);
free(errstr);
goto done;
}
if (!(mem_ctx = talloc_init())) {
PyErr_SetString(
spoolss_error, "unable to init talloc context\n");
goto done;
}
if (!py_to_PRINTER_INFO_2(&info2, info, mem_ctx)) {
PyErr_SetString(spoolss_error,
"error converting to printer info 2");
goto done;
}
ctr.printers_2 = &info2;
werror = cli_spoolss_addprinterex(cli, mem_ctx, 2, &ctr);
Py_INCREF(Py_None);
result = Py_None;
done:
if (cli)
cli_shutdown(cli);
if (mem_ctx)
talloc_destroy(mem_ctx);
return result;
}

View File

@ -0,0 +1,306 @@
/*
Python wrappers for DCERPC/SMB client routines.
Copyright (C) Tim Potter, 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 "python/py_spoolss.h"
#include "python/py_conv.h"
struct pyconv py_PRINTER_INFO_0[] = {
{ "name", PY_UNISTR, offsetof(PRINTER_INFO_0, printername) },
{ "server_name", PY_UNISTR, offsetof(PRINTER_INFO_0, servername) },
{ "cjobs", PY_UINT32, offsetof(PRINTER_INFO_0, cjobs) },
{ "total_jobs", PY_UINT32, offsetof(PRINTER_INFO_0, total_jobs) },
{ "total_bytes", PY_UINT32, offsetof(PRINTER_INFO_0, total_bytes) },
{ "year", PY_UINT16, offsetof(PRINTER_INFO_0, year) },
{ "month", PY_UINT16, offsetof(PRINTER_INFO_0, month) },
{ "day_of_week", PY_UINT16, offsetof(PRINTER_INFO_0, dayofweek) },
{ "day", PY_UINT16, offsetof(PRINTER_INFO_0, day) },
{ "hour", PY_UINT16, offsetof(PRINTER_INFO_0, hour) },
{ "minute", PY_UINT16, offsetof(PRINTER_INFO_0, minute) },
{ "second", PY_UINT16, offsetof(PRINTER_INFO_0, second) },
{ "milliseconds", PY_UINT16, offsetof(PRINTER_INFO_0, milliseconds) },
{ "global_counter", PY_UINT32, offsetof(PRINTER_INFO_0, global_counter) },
{ "total_pages", PY_UINT32, offsetof(PRINTER_INFO_0, total_pages) },
{ "major_version", PY_UINT16, offsetof(PRINTER_INFO_0, major_version) },
{ "build_version", PY_UINT16, offsetof(PRINTER_INFO_0, build_version) },
{ "unknown7", PY_UINT32, offsetof(PRINTER_INFO_0, unknown7) },
{ "unknown8", PY_UINT32, offsetof(PRINTER_INFO_0, unknown8) },
{ "unknown9", PY_UINT32, offsetof(PRINTER_INFO_0, unknown9) },
{ "session_counter", PY_UINT32, offsetof(PRINTER_INFO_0, session_counter)},
{ "unknown11", PY_UINT32, offsetof(PRINTER_INFO_0, unknown11) },
{ "printer_errors", PY_UINT32, offsetof(PRINTER_INFO_0, printer_errors) },
{ "unknown13", PY_UINT32, offsetof(PRINTER_INFO_0, unknown13) },
{ "unknown14", PY_UINT32, offsetof(PRINTER_INFO_0, unknown14) },
{ "unknown15", PY_UINT32, offsetof(PRINTER_INFO_0, unknown15) },
{ "unknown16", PY_UINT32, offsetof(PRINTER_INFO_0, unknown16) },
{ "change_id", PY_UINT32, offsetof(PRINTER_INFO_0, change_id) },
{ "unknown18", PY_UINT32, offsetof(PRINTER_INFO_0, unknown18) },
{ "status", PY_UINT32, offsetof(PRINTER_INFO_0, status) },
{ "unknown20", PY_UINT32, offsetof(PRINTER_INFO_0, unknown20) },
{ "c_setprinter", PY_UINT32, offsetof(PRINTER_INFO_0, c_setprinter) },
{ "unknown22", PY_UINT32, offsetof(PRINTER_INFO_0, unknown22) },
{ "unknown23", PY_UINT32, offsetof(PRINTER_INFO_0, unknown23) },
{ "unknown24", PY_UINT32, offsetof(PRINTER_INFO_0, unknown24) },
{ "unknown25", PY_UINT32, offsetof(PRINTER_INFO_0, unknown25) },
{ "unknown26", PY_UINT32, offsetof(PRINTER_INFO_0, unknown26) },
{ "unknown27", PY_UINT32, offsetof(PRINTER_INFO_0, unknown27) },
{ "unknown28", PY_UINT32, offsetof(PRINTER_INFO_0, unknown28) },
{ "unknown29", PY_UINT32, offsetof(PRINTER_INFO_0, unknown29) },
{ NULL }
};
struct pyconv py_PRINTER_INFO_1[] = {
{ "name", PY_UNISTR, offsetof(PRINTER_INFO_1, name) },
{ "description", PY_UNISTR, offsetof(PRINTER_INFO_1, description) },
{ "comment", PY_UNISTR, offsetof(PRINTER_INFO_1, comment) },
{ "flags", PY_UINT32, offsetof(PRINTER_INFO_1, flags) },
{ NULL }
};
struct pyconv py_PRINTER_INFO_2[] = {
{ "server_name", PY_UNISTR, offsetof(PRINTER_INFO_2, servername) },
{ "name", PY_UNISTR, offsetof(PRINTER_INFO_2, printername) },
{ "share_name", PY_UNISTR, offsetof(PRINTER_INFO_2, sharename) },
{ "port_name", PY_UNISTR, offsetof(PRINTER_INFO_2, portname) },
{ "driver_name", PY_UNISTR, offsetof(PRINTER_INFO_2, drivername) },
{ "comment", PY_UNISTR, offsetof(PRINTER_INFO_2, comment) },
{ "location", PY_UNISTR, offsetof(PRINTER_INFO_2, location) },
{ "datatype", PY_UNISTR, offsetof(PRINTER_INFO_2, datatype) },
{ "sepfile", PY_UNISTR, offsetof(PRINTER_INFO_2, sepfile) },
{ "print_processor", PY_UNISTR, offsetof(PRINTER_INFO_2, printprocessor) },
{ "parameters", PY_UNISTR, offsetof(PRINTER_INFO_2, parameters) },
{ "attributes", PY_UINT32, offsetof(PRINTER_INFO_2, attributes) },
{ "default_priority", PY_UINT32, offsetof(PRINTER_INFO_2, defaultpriority) },
{ "priority", PY_UINT32, offsetof(PRINTER_INFO_2, priority) },
{ "start_time", PY_UINT32, offsetof(PRINTER_INFO_2, starttime) },
{ "until_time", PY_UINT32, offsetof(PRINTER_INFO_2, untiltime) },
{ "status", PY_UINT32, offsetof(PRINTER_INFO_2, status) },
{ "cjobs", PY_UINT32, offsetof(PRINTER_INFO_2, cjobs) },
{ "average_ppm", PY_UINT32, offsetof(PRINTER_INFO_2, averageppm) },
{ NULL }
};
struct pyconv py_PRINTER_INFO_3[] = {
{ "flags", PY_UINT32, offsetof(PRINTER_INFO_3, flags) },
{ NULL }
};
struct pyconv py_DEVICEMODE[] = {
{ "device_name", PY_UNISTR, offsetof(DEVICEMODE, devicename) },
{ "spec_version", PY_UINT16, offsetof(DEVICEMODE, specversion) },
{ "driver_version", PY_UINT16, offsetof(DEVICEMODE, driverversion) },
{ "size", PY_UINT16, offsetof(DEVICEMODE, size) },
{ "fields", PY_UINT16, offsetof(DEVICEMODE, fields) },
{ "orientation", PY_UINT16, offsetof(DEVICEMODE, orientation) },
{ "paper_size", PY_UINT16, offsetof(DEVICEMODE, papersize) },
{ "paper_width", PY_UINT16, offsetof(DEVICEMODE, paperwidth) },
{ "paper_length", PY_UINT16, offsetof(DEVICEMODE, paperlength) },
{ "scale", PY_UINT16, offsetof(DEVICEMODE, scale) },
{ "copies", PY_UINT16, offsetof(DEVICEMODE, copies) },
{ "default_source", PY_UINT16, offsetof(DEVICEMODE, defaultsource) },
{ "print_quality", PY_UINT16, offsetof(DEVICEMODE, printquality) },
{ "color", PY_UINT16, offsetof(DEVICEMODE, color) },
{ "duplex", PY_UINT16, offsetof(DEVICEMODE, duplex) },
{ "y_resolution", PY_UINT16, offsetof(DEVICEMODE, yresolution) },
{ "tt_option", PY_UINT16, offsetof(DEVICEMODE, ttoption) },
{ "collate", PY_UINT16, offsetof(DEVICEMODE, collate) },
{ "form_name", PY_UNISTR, offsetof(DEVICEMODE, formname) },
{ "log_pixels", PY_UINT16, offsetof(DEVICEMODE, logpixels) },
{ "bits_per_pel", PY_UINT32, offsetof(DEVICEMODE, bitsperpel) },
{ "pels_width", PY_UINT32, offsetof(DEVICEMODE, pelswidth) },
{ "pels_height", PY_UINT32, offsetof(DEVICEMODE, pelsheight) },
{ "display_flags", PY_UINT32, offsetof(DEVICEMODE, displayflags) },
{ "display_frequency", PY_UINT32, offsetof(DEVICEMODE, displayfrequency) },
{ "icm_method", PY_UINT32, offsetof(DEVICEMODE, icmmethod) },
{ "icm_intent", PY_UINT32, offsetof(DEVICEMODE, icmintent) },
{ "media_type", PY_UINT32, offsetof(DEVICEMODE, mediatype) },
{ "dither_type", PY_UINT32, offsetof(DEVICEMODE, dithertype) },
{ "reserved1", PY_UINT32, offsetof(DEVICEMODE, reserved1) },
{ "reserved2", PY_UINT32, offsetof(DEVICEMODE, reserved2) },
{ "panning_width", PY_UINT32, offsetof(DEVICEMODE, panningwidth) },
{ "panning_height", PY_UINT32, offsetof(DEVICEMODE, panningheight) },
{ NULL }
};
/*
* Convert between DEVICEMODE and Python
*/
BOOL py_from_DEVICEMODE(PyObject **dict, DEVICEMODE *devmode)
{
*dict = from_struct(devmode, py_DEVICEMODE);
PyDict_SetItemString(*dict, "private",
PyString_FromStringAndSize(
devmode->private, devmode->driverextra));
return True;
}
BOOL py_to_DEVICEMODE(DEVICEMODE *devmode, PyObject *dict)
{
PyObject *obj;
if (!to_struct(devmode, dict, py_DEVICEMODE))
return False;
if (!(obj = PyDict_GetItemString(dict, "private")))
return False;
devmode->private = PyString_AsString(obj);
devmode->driverextra = PyString_Size(obj);
return True;
}
/*
* Convert between PRINTER_INFO_0 and Python
*/
BOOL py_from_PRINTER_INFO_0(PyObject **dict, PRINTER_INFO_0 *info)
{
*dict = from_struct(info, py_PRINTER_INFO_0);
PyDict_SetItemString(*dict, "level", PyInt_FromLong(0));
return True;
}
BOOL py_to_PRINTER_INFO_0(PRINTER_INFO_0 *info, PyObject *dict)
{
return False;
}
/*
* Convert between PRINTER_INFO_1 and Python
*/
BOOL py_from_PRINTER_INFO_1(PyObject **dict, PRINTER_INFO_1 *info)
{
*dict = from_struct(info, py_PRINTER_INFO_1);
PyDict_SetItemString(*dict, "level", PyInt_FromLong(1));
return True;
}
BOOL py_to_PRINTER_INFO_1(PRINTER_INFO_1 *info, PyObject *dict)
{
PyObject *dict_copy = PyDict_Copy(dict);
BOOL result;
PyDict_DelItemString(dict_copy, "level");
result = to_struct(info, dict_copy, py_PRINTER_INFO_1);
Py_DECREF(dict_copy);
return result;
}
/*
* Convert between PRINTER_INFO_2 and Python
*/
BOOL py_from_PRINTER_INFO_2(PyObject **dict, PRINTER_INFO_2 *info)
{
PyObject *obj;
*dict = from_struct(info, py_PRINTER_INFO_2);
/* The security descriptor could be NULL */
if (info->secdesc) {
if (py_from_SECDESC(&obj, info->secdesc))
PyDict_SetItemString(*dict, "security_descriptor", obj);
}
/* Bong! The devmode could be NULL */
if (info->devmode)
py_from_DEVICEMODE(&obj, info->devmode);
else
obj = PyDict_New();
PyDict_SetItemString(*dict, "device_mode", obj);
PyDict_SetItemString(*dict, "level", PyInt_FromLong(2));
return True;
}
BOOL py_to_PRINTER_INFO_2(PRINTER_INFO_2 *info, PyObject *dict,
TALLOC_CTX *mem_ctx)
{
PyObject *obj;
if (!to_struct(info, dict, py_PRINTER_INFO_2))
return False;
if (!(obj = PyDict_GetItemString(dict, "security_descriptor")))
return False;
if (!py_to_SECDESC(&info->secdesc, obj, mem_ctx))
return False;
if (!(obj = PyDict_GetItemString(dict, "device_mode")))
return False;
info->devmode = talloc(mem_ctx, sizeof(DEVICEMODE));
if (!py_to_DEVICEMODE(info->devmode, obj))
return False;
return True;
}
/*
* Convert between PRINTER_INFO_1 and Python
*/
BOOL py_from_PRINTER_INFO_3(PyObject **dict, PRINTER_INFO_3 *info)
{
PyObject *obj;
*dict = from_struct(info, py_PRINTER_INFO_3);
if (py_from_SECDESC(&obj, info->secdesc))
PyDict_SetItemString(*dict, "security_descriptor", obj);
PyDict_SetItemString(*dict, "level", PyInt_FromLong(3));
return True;
}
BOOL py_to_PRINTER_INFO_3(PRINTER_INFO_3 *info, PyObject *dict,
TALLOC_CTX *mem_ctx)
{
PyObject *obj;
if (!to_struct(info, dict, py_PRINTER_INFO_3))
return False;
if (!(obj = PyDict_GetItemString(dict, "security_descriptor")))
return False;
if (!py_to_SECDESC(&info->secdesc, obj, mem_ctx))
return False;
return True;
}

View File

@ -0,0 +1,123 @@
#ifndef _PY_SPOOLSS_PROTO_H
#define _PY_SPOOLSS_PROTO_H
/* This file is automatically generated with "make proto". DO NOT EDIT */
/* The following definitions come from python/py_spoolss.c */
PyObject *new_spoolss_policy_hnd_object(struct cli_state *cli,
TALLOC_CTX *mem_ctx, POLICY_HND *pol);
void initspoolss(void);
/* The following definitions come from python/py_spoolss_drivers.c */
PyObject *spoolss_enumprinterdrivers(PyObject *self, PyObject *args,
PyObject *kw);
PyObject *spoolss_hnd_getprinterdriver(PyObject *self, PyObject *args,
PyObject *kw);
PyObject *spoolss_getprinterdriverdir(PyObject *self, PyObject *args,
PyObject *kw);
PyObject *spoolss_addprinterdriver(PyObject *self, PyObject *args,
PyObject *kw);
PyObject *spoolss_addprinterdriverex(PyObject *self, PyObject *args,
PyObject *kw);
PyObject *spoolss_deleteprinterdriver(PyObject *self, PyObject *args,
PyObject *kw);
PyObject *spoolss_deleteprinterdriverex(PyObject *self, PyObject *args,
PyObject *kw);
/* The following definitions come from python/py_spoolss_drivers_conv.c */
BOOL py_from_DRIVER_INFO_1(PyObject **dict, DRIVER_INFO_1 *info);
BOOL py_to_DRIVER_INFO_1(DRIVER_INFO_1 *info, PyObject *dict);
BOOL py_from_DRIVER_INFO_2(PyObject **dict, DRIVER_INFO_2 *info);
BOOL py_to_DRIVER_INFO_2(DRIVER_INFO_2 *info, PyObject *dict);
BOOL py_from_DRIVER_INFO_3(PyObject **dict, DRIVER_INFO_3 *info);
BOOL py_to_DRIVER_INFO_3(DRIVER_INFO_3 *info, PyObject *dict);
BOOL py_from_DRIVER_INFO_6(PyObject **dict, DRIVER_INFO_6 *info);
BOOL py_to_DRIVER_INFO_6(DRIVER_INFO_6 *info, PyObject *dict);
BOOL py_from_DRIVER_DIRECTORY_1(PyObject **dict, DRIVER_DIRECTORY_1 *info);
BOOL py_to_DRIVER_DIRECTORY_1(DRIVER_DIRECTORY_1 *info, PyObject *dict);
/* The following definitions come from python/py_spoolss_forms.c */
PyObject *spoolss_hnd_addform(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_hnd_getform(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_hnd_setform(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_hnd_deleteform(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_hnd_enumforms(PyObject *self, PyObject *args, PyObject *kw);
/* The following definitions come from python/py_spoolss_forms_conv.c */
BOOL py_from_FORM_1(PyObject **dict, FORM_1 *form);
BOOL py_to_FORM(FORM *form, PyObject *dict);
/* The following definitions come from python/py_spoolss_jobs.c */
PyObject *spoolss_hnd_enumjobs(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_hnd_setjob(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_hnd_getjob(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_hnd_startpageprinter(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_hnd_endpageprinter(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_hnd_startdocprinter(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_hnd_enddocprinter(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_hnd_writeprinter(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_hnd_addjob(PyObject *self, PyObject *args, PyObject *kw);
/* The following definitions come from python/py_spoolss_jobs_conv.c */
BOOL py_from_JOB_INFO_1(PyObject **dict, JOB_INFO_1 *info);
BOOL py_to_JOB_INFO_1(JOB_INFO_1 *info, PyObject *dict);
BOOL py_from_JOB_INFO_2(PyObject **dict, JOB_INFO_2 *info);
BOOL py_to_JOB_INFO_2(JOB_INFO_2 *info, PyObject *dict);
BOOL py_from_DOC_INFO_1(PyObject **dict, DOC_INFO_1 *info);
BOOL py_to_DOC_INFO_1(DOC_INFO_1 *info, PyObject *dict);
/* The following definitions come from python/py_spoolss_ports.c */
PyObject *spoolss_enumports(PyObject *self, PyObject *args, PyObject *kw);
/* The following definitions come from python/py_spoolss_ports_conv.c */
BOOL py_from_PORT_INFO_1(PyObject **dict, PORT_INFO_1 *info);
BOOL py_to_PORT_INFO_1(PORT_INFO_1 *info, PyObject *dict);
BOOL py_from_PORT_INFO_2(PyObject **dict, PORT_INFO_2 *info);
BOOL py_to_PORT_INFO_2(PORT_INFO_2 *info, PyObject *dict);
/* The following definitions come from python/py_spoolss_printerdata.c */
PyObject *spoolss_hnd_getprinterdata(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_hnd_setprinterdata(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_hnd_enumprinterdata(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_hnd_deleteprinterdata(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_hnd_getprinterdataex(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_hnd_setprinterdataex(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_hnd_enumprinterdataex(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_hnd_deleteprinterdataex(PyObject *self, PyObject *args, PyObject *kw);
/* The following definitions come from python/py_spoolss_printers.c */
PyObject *spoolss_openprinter(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_closeprinter(PyObject *self, PyObject *args);
PyObject *spoolss_hnd_getprinter(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_hnd_setprinter(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_enumprinters(PyObject *self, PyObject *args, PyObject *kw);
PyObject *spoolss_addprinterex(PyObject *self, PyObject *args, PyObject *kw);
/* The following definitions come from python/py_spoolss_printers_conv.c */
BOOL py_from_DEVICEMODE(PyObject **dict, DEVICEMODE *devmode);
BOOL py_to_DEVICEMODE(DEVICEMODE *devmode, PyObject *dict);
BOOL py_from_PRINTER_INFO_0(PyObject **dict, PRINTER_INFO_0 *info);
BOOL py_to_PRINTER_INFO_0(PRINTER_INFO_0 *info, PyObject *dict);
BOOL py_from_PRINTER_INFO_1(PyObject **dict, PRINTER_INFO_1 *info);
BOOL py_to_PRINTER_INFO_1(PRINTER_INFO_1 *info, PyObject *dict);
BOOL py_from_PRINTER_INFO_2(PyObject **dict, PRINTER_INFO_2 *info);
BOOL py_to_PRINTER_INFO_2(PRINTER_INFO_2 *info, PyObject *dict,
TALLOC_CTX *mem_ctx);
BOOL py_from_PRINTER_INFO_3(PyObject **dict, PRINTER_INFO_3 *info);
BOOL py_to_PRINTER_INFO_3(PRINTER_INFO_3 *info, PyObject *dict,
TALLOC_CTX *mem_ctx);
#endif /* _PY_SPOOLSS_PROTO_H */

662
source3/python/py_tdbpack.c Normal file
View File

@ -0,0 +1,662 @@
/* -*- c-file-style: "python"; indent-tabs-mode: nil; -*-
Python wrapper for Samba tdb pack/unpack functions
Copyright (C) Martin Pool 2002
NOTE PYTHON STYLE GUIDE
http://www.python.org/peps/pep-0007.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.
*/
#include "Python.h"
static int pytdbpack_calc_reqd_len(char *format_str,
PyObject *val_seq);
static PyObject *pytdbpack_unpack_item(char,
char **pbuf,
int *plen);
static int
pytdbpack_calc_item_len(char format_ch,
PyObject *val_obj);
static PyObject *pytdbpack_pack_data(const char *format_str,
PyObject *val_seq,
unsigned char *buf);
static const char * pytdbpack_docstring =
"Convert between Python values and Samba binary encodings.
This module is conceptually similar to the standard 'struct' module, but it
uses both a different binary format and a different description string.
Samba's encoding is based on that used inside DCE-RPC and SMB: a
little-endian, unpadded, non-self-describing binary format. It is intended
that these functions be as similar as possible to the routines in Samba's
tdb/tdbutil module, with appropriate adjustments for Python datatypes.
Python strings are used to specify the format of data to be packed or
unpacked.
Strings in TDBs are typically stored in DOS codepages. The caller of this
module must make appropriate translations if necessary, typically to and from
Unicode objects.
tdbpack format strings:
'f': NULL-terminated string in DOS codepage
'P': same as 'f'
'd': 4 byte little-endian number
'w': 2 byte little-endian number
'P': \"Pointer\" value -- in the subset of DCERPC used by Samba, this is
really just an \"exists\" or \"does not exist\" flag. The boolean
value of the Python object is used.
'B': 4-byte LE length, followed by that many bytes of binary data.
Corresponds to a Python byte string of the appropriate length.
'$': Special flag indicating that the preceding format code should be
repeated while data remains. This is only supported for unpacking.
Every code corresponds to a single Python object, except 'B' which
corresponds to two values (length and contents), and '$', which produces
however many make sense.
";
static char const pytdbpack_pack_doc[] =
"pack(format, values) -> buffer
Pack Python objects into Samba binary format according to format string.
arguments:
format -- string of tdbpack format characters
values -- sequence of value objects corresponding 1:1 to format characters
returns:
buffer -- string containing packed data
raises:
IndexError -- if there are not the same number of format codes as of
values
ValueError -- if any of the format characters is illegal
TypeError -- if the format is not a string, or values is not a sequence,
or any of the values is of the wrong type for the corresponding
format character
";
static char const pytdbpack_unpack_doc[] =
"unpack(format, buffer) -> (values, rest)
Unpack Samba binary data according to format string.
arguments:
format -- string of tdbpack characters
buffer -- string of packed binary data
returns:
2-tuple of:
values -- sequence of values corresponding 1:1 to format characters
rest -- string containing data that was not decoded, or '' if the
whole string was consumed
raises:
IndexError -- if there is insufficient data in the buffer for the
format (or if the data is corrupt and contains a variable-length
field extending past the end)
ValueError -- if any of the format characters is illegal
notes:
Because unconsumed data is returned, you can feed it back in to the
unpacker to extract further fields. Alternatively, if you wish to modify
some fields near the start of the data, you may be able to save time by
only unpacking and repacking the necessary part.
";
/*
Game plan is to first of all walk through the arguments and calculate the
total length that will be required. We allocate a Python string of that
size, then walk through again and fill it in.
We just borrow references to all the passed arguments, since none of them
need to be permanently stored. We transfer ownership to the returned
object.
*/
static PyObject *
pytdbpack_pack(PyObject *self,
PyObject *args)
{
char *format_str;
PyObject *val_seq, *fast_seq, *buf_str;
int reqd_len;
char *packed_buf;
/* TODO: Test passing wrong types or too many arguments */
if (!PyArg_ParseTuple(args, "sO", &format_str, &val_seq))
return NULL;
/* Convert into a list or tuple (if not already one), so that we can
* index more easily. */
fast_seq = PySequence_Fast(val_seq,
__FUNCTION__ ": argument 2 must be sequence");
if (!fast_seq)
return NULL;
reqd_len = pytdbpack_calc_reqd_len(format_str, fast_seq);
if (reqd_len == -1) /* exception was thrown */
return NULL;
/* Allocate space.
This design causes an unnecessary copying of the data when Python
constructs an object, and that might possibly be avoided by using a
Buffer object of some kind instead. I'm not doing that for now
though. */
packed_buf = malloc(reqd_len);
if (!packed_buf) {
PyErr_Format(PyExc_MemoryError,
"%s: couldn't allocate %d bytes for packed buffer",
__FUNCTION__, reqd_len);
return NULL;
}
if (!pytdbpack_pack_data(format_str, fast_seq, packed_buf)) {
free(packed_buf);
return NULL;
}
buf_str = PyString_FromStringAndSize(packed_buf, reqd_len);
free(packed_buf); /* get rid of tmp buf */
return buf_str;
}
static PyObject *
pytdbpack_unpack(PyObject *self,
PyObject *args)
{
char *format_str, *packed_str, *ppacked;
PyObject *val_list = NULL, *ret_tuple = NULL;
PyObject *rest_string = NULL;
int format_len, packed_len;
int i;
char last_format = '#';
/* get arguments */
if (!PyArg_ParseTuple(args, "ss#", &format_str, &packed_str, &packed_len))
return NULL;
format_len = strlen(format_str);
/* allocate list to hold results */
val_list = PyList_New(format_len);
if (!val_list)
goto failed;
ret_tuple = PyTuple_New(2);
if (!ret_tuple)
goto failed;
/* For every object, unpack. */
for (ppacked = packed_str, i = 0; i < format_len; i++) {
PyObject *val_obj;
char format;
format = format_str[i];
if (format == '$') {
if (i == 0) {
PyErr_Format(PyExc_ValueError,
"%s: '$' may not be first character in format",
__FUNCTION__);
goto failed;
}
else {
format = last_format; /* repeat */
}
}
val_obj = pytdbpack_unpack_item(format,
&ppacked,
&packed_len);
if (!val_obj)
goto failed;
PyList_SET_ITEM(val_list, i, val_obj);
last_format = format;
}
/* put leftovers in box for lunch tomorrow */
rest_string = PyString_FromStringAndSize(ppacked, packed_len);
if (!rest_string)
goto failed;
/* return (values, rest) tuple; give up references to them */
PyTuple_SET_ITEM(ret_tuple, 0, val_list);
val_list = NULL;
PyTuple_SET_ITEM(ret_tuple, 1, rest_string);
val_list = NULL;
return ret_tuple;
failed:
/* handle failure: deallocate anything */
Py_XDECREF(val_list);
Py_XDECREF(ret_tuple);
Py_XDECREF(rest_string);
return NULL;
}
/*
Internal routine that calculates how many bytes will be required to
encode the values in the format.
Also checks that the value list is the right size for the format list.
Returns number of bytes (may be 0), or -1 if there's something wrong, in
which case a Python exception has been raised.
Arguments:
val_seq: a Fast Sequence (list or tuple), being all the values
*/
static int
pytdbpack_calc_reqd_len(char *format_str,
PyObject *val_seq)
{
int len = 0;
char *p;
int val_i;
int val_len;
val_len = PySequence_Fast_GET_SIZE(val_seq);
for (p = format_str, val_i = 0; *p; p++, val_i++) {
char ch = *p;
PyObject *val_obj;
int item_len;
if (val_i >= val_len) {
PyErr_Format(PyExc_IndexError,
"samba.tdbpack.pack: value list is too short for format string");
return -1;
}
/* borrow a reference to the item */
val_obj = PySequence_Fast_GET_ITEM(val_seq, val_i);
if (!val_obj)
return -1;
item_len = pytdbpack_calc_item_len(ch, val_obj);
if (item_len == -1)
return -1;
else
len += item_len;
}
if (val_i != val_len) {
PyErr_Format(PyExc_IndexError,
"%s: value list is wrong length for format string",
__FUNCTION__);
return -1;
}
return len;
}
/*
Calculate the number of bytes required to pack a single value.
*/
static int
pytdbpack_calc_item_len(char ch,
PyObject *val_obj)
{
if (ch == 'd' || ch == 'w') {
if (!PyInt_Check(val_obj)) {
PyErr_Format(PyExc_TypeError,
"tdbpack: format '%c' requires an Int",
ch);
return -1;
}
if (ch == 'w')
return 2;
else
return 4;
} else if (ch == 'p') {
return 4;
}
else if (ch == 'f' || ch == 'P' || ch == 'B') {
/* nul-terminated 8-bit string */
if (!PyString_Check(val_obj)) {
PyErr_Format(PyExc_TypeError,
"tdbpack: format '%c' requires a String",
ch);
return -1;
}
if (ch == 'B') {
/* byte buffer; just use Python string's length, plus
a preceding word */
return 4 + PyString_GET_SIZE(val_obj);
}
else {
/* one nul character */
return 1 + PyString_GET_SIZE(val_obj);
}
}
else {
PyErr_Format(PyExc_ValueError,
__FUNCTION__ ": format character '%c' is not supported",
ch);
return -1;
}
}
/*
XXX: glib and Samba have quicker macro for doing the endianness conversions,
but I don't know of one in plain libc, and it's probably not a big deal. I
realize this is kind of dumb because we'll almost always be on x86, but
being safe is important.
*/
static void pack_int32(unsigned long val_long, unsigned char **pbuf)
{
(*pbuf)[0] = val_long & 0xff;
(*pbuf)[1] = (val_long >> 8) & 0xff;
(*pbuf)[2] = (val_long >> 16) & 0xff;
(*pbuf)[3] = (val_long >> 24) & 0xff;
(*pbuf) += 4;
}
static void pack_bytes(long len, const char *from,
unsigned char **pbuf)
{
memcpy(*pbuf, from, len);
(*pbuf) += len;
}
static void
unpack_err_too_short(void)
{
PyErr_Format(PyExc_IndexError,
__FUNCTION__ ": data too short for unpack format");
}
static PyObject *
unpack_int32(char **pbuf, int *plen)
{
long v;
unsigned char *b;
if (*plen < 4) {
unpack_err_too_short();
return NULL;
}
b = *pbuf;
v = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24;
(*pbuf) += 4;
(*plen) -= 4;
return PyInt_FromLong(v);
}
static PyObject *unpack_int16(char **pbuf, int *plen)
{
long v;
unsigned char *b;
if (*plen < 2) {
unpack_err_too_short();
return NULL;
}
b = *pbuf;
v = b[0] | b[1]<<8;
(*pbuf) += 2;
(*plen) -= 2;
return PyInt_FromLong(v);
}
static PyObject *
unpack_string(char **pbuf, int *plen)
{
int len;
char *nul_ptr, *start;
start = *pbuf;
nul_ptr = memchr(start, '\0', *plen);
if (!nul_ptr) {
unpack_err_too_short();
return NULL;
}
len = nul_ptr - start;
*pbuf += len + 1; /* skip \0 */
*plen -= len + 1;
return PyString_FromStringAndSize(start, len);
}
static PyObject *
unpack_buffer(char **pbuf, int *plen)
{
/* first get 32-bit len */
long slen;
unsigned char *b;
unsigned char *start;
if (*plen < 4) {
unpack_err_too_short();
return NULL;
}
b = *pbuf;
slen = b[0] | b[1]<<8 | b[2]<<16 | b[3]<<24;
if (slen < 0) { /* surely you jest */
PyErr_Format(PyExc_ValueError,
__FUNCTION__ ": buffer seems to have negative length");
return NULL;
}
(*pbuf) += 4;
(*plen) -= 4;
start = *pbuf;
if (*plen < slen) {
PyErr_Format(PyExc_IndexError,
__FUNCTION__ ": not enough data to unpack buffer: "
"need %d bytes, have %d",
(int) slen, *plen);
return NULL;
}
(*pbuf) += slen;
(*plen) -= slen;
return PyString_FromStringAndSize(start, slen);
}
/* Unpack a single field from packed data, according to format character CH.
Remaining data is at *PBUF, of *PLEN.
*PBUF is advanced, and *PLEN reduced to reflect the amount of data that has
been consumed.
Returns a reference to the unpacked Python object, or NULL for failure.
*/
static PyObject *pytdbpack_unpack_item(char ch,
char **pbuf,
int *plen)
{
if (ch == 'w') { /* 16-bit int */
return unpack_int16(pbuf, plen);
}
else if (ch == 'd' || ch == 'p') { /* 32-bit int */
/* pointers can just come through as integers */
return unpack_int32(pbuf, plen);
}
else if (ch == 'f' || ch == 'P') { /* nul-term string */
return unpack_string(pbuf, plen);
}
else if (ch == 'B') { /* length, buffer */
return unpack_buffer(pbuf, plen);
}
else {
PyErr_Format(PyExc_ValueError,
__FUNCTION__ ": format character '%c' is not supported",
ch);
return NULL;
}
}
/*
Pack a single item VAL_OBJ, encoded using format CH, into a buffer at *PBUF,
and advance the pointer. Buffer length has been pre-calculated so we are
sure that there is enough space.
*/
static PyObject *
pytdbpack_pack_item(char ch,
PyObject *val_obj,
unsigned char **pbuf)
{
if (ch == 'w') {
unsigned long val_long = PyInt_AsLong(val_obj);
(*pbuf)[0] = val_long & 0xff;
(*pbuf)[1] = (val_long >> 8) & 0xff;
(*pbuf) += 2;
}
else if (ch == 'd') {
/* 4-byte LE number */
pack_int32(PyInt_AsLong(val_obj), pbuf);
}
else if (ch == 'p') {
/* "Pointer" value -- in the subset of DCERPC used by Samba,
this is really just an "exists" or "does not exist"
flag. */
pack_int32(PyObject_IsTrue(val_obj), pbuf);
}
else if (ch == 'f' || ch == 'P') {
int size;
char *sval;
size = PyString_GET_SIZE(val_obj);
sval = PyString_AS_STRING(val_obj);
pack_bytes(size+1, sval, pbuf); /* include nul */
}
else if (ch == 'B') {
int size;
char *sval;
size = PyString_GET_SIZE(val_obj);
pack_int32(size, pbuf);
sval = PyString_AS_STRING(val_obj);
pack_bytes(size, sval, pbuf); /* do not include nul */
}
else {
/* this ought to be caught while calculating the length, but
just in case. */
PyErr_Format(PyExc_ValueError,
"%s: format character '%c' is not supported",
__FUNCTION__, ch);
return NULL;
}
return Py_None;
}
/*
Pack data according to FORMAT_STR from the elements of VAL_SEQ into
PACKED_BUF.
The string has already been checked out, so we know that VAL_SEQ is large
enough to hold the packed data, and that there are enough value items.
(However, their types may not have been thoroughly checked yet.)
In addition, val_seq is a Python Fast sequence.
Returns NULL for error (with exception set), or None.
*/
PyObject *
pytdbpack_pack_data(const char *format_str,
PyObject *val_seq,
unsigned char *packed_buf)
{
int i;
for (i = 0; format_str[i]; i++) {
char ch = format_str[i];
PyObject *val_obj;
/* borrow a reference to the item */
val_obj = PySequence_Fast_GET_ITEM(val_seq, i);
if (!val_obj)
return NULL;
if (!pytdbpack_pack_item(ch, val_obj, &packed_buf))
return NULL;
}
return Py_None;
}
static PyMethodDef pytdbpack_methods[] = {
{ "pack", pytdbpack_pack, METH_VARARGS, (char *) pytdbpack_pack_doc },
{ "unpack", pytdbpack_unpack, METH_VARARGS, (char *) pytdbpack_unpack_doc },
};
DL_EXPORT(void)
inittdbpack(void)
{
Py_InitModule3("tdbpack", pytdbpack_methods,
(char *) pytdbpack_docstring);
}

716
source3/python/py_winbind.c Normal file
View File

@ -0,0 +1,716 @@
/*
Unix SMB/CIFS implementation.
Python wrapper for winbind client functions.
Copyright (C) Tim Potter 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 "Python.h"
#include "py_common_proto.h"
/*
* Exceptions raised by this module
*/
PyObject *winbind_error; /* A winbind call returned WINBINDD_ERROR */
/* Prototypes from common.h */
NSS_STATUS winbindd_request(int req_type,
struct winbindd_request *request,
struct winbindd_response *response);
/*
* Name <-> SID conversion
*/
/* Convert a name to a sid */
static PyObject *py_name_to_sid(PyObject *self, PyObject *args)
{
struct winbindd_request request;
struct winbindd_response response;
PyObject *result;
char *name, *p, *sep;
if (!PyArg_ParseTuple(args, "s", &name))
return NULL;
ZERO_STRUCT(request);
ZERO_STRUCT(response);
sep = lp_winbind_separator();
if ((p = strchr(name, sep[0]))) {
*p = 0;
fstrcpy(request.data.name.dom_name, name);
fstrcpy(request.data.name.name, p + 1);
} else {
fstrcpy(request.data.name.dom_name, lp_workgroup());
fstrcpy(request.data.name.name, name);
}
if (winbindd_request(WINBINDD_LOOKUPNAME, &request, &response)
!= NSS_STATUS_SUCCESS) {
PyErr_SetString(winbind_error, "lookup failed");
return NULL;
}
result = PyString_FromString(response.data.sid.sid);
return result;
}
/* Convert a sid to a name */
static PyObject *py_sid_to_name(PyObject *self, PyObject *args)
{
struct winbindd_request request;
struct winbindd_response response;
PyObject *result;
char *sid, *name;
if (!PyArg_ParseTuple(args, "s", &sid))
return NULL;
ZERO_STRUCT(request);
ZERO_STRUCT(response);
fstrcpy(request.data.sid, sid);
if (winbindd_request(WINBINDD_LOOKUPSID, &request, &response)
!= NSS_STATUS_SUCCESS) {
PyErr_SetString(winbind_error, "lookup failed");
return NULL;
}
asprintf(&name, "%s%s%s", response.data.name.dom_name,
lp_winbind_separator(), response.data.name.name);
result = PyString_FromString(name);
free(name);
return result;
}
/*
* Enumerate users/groups
*/
/* Enumerate domain users */
static PyObject *py_enum_domain_users(PyObject *self, PyObject *args)
{
struct winbindd_response response;
PyObject *result;
if (!PyArg_ParseTuple(args, ""))
return NULL;
ZERO_STRUCT(response);
if (winbindd_request(WINBINDD_LIST_USERS, NULL, &response)
!= NSS_STATUS_SUCCESS) {
PyErr_SetString(winbind_error, "lookup failed");
return NULL;
}
result = PyList_New(0);
if (response.extra_data) {
char *extra_data = response.extra_data;
fstring name;
while (next_token(&extra_data, name, ",", sizeof(fstring)))
PyList_Append(result, PyString_FromString(name));
}
return result;
}
/* Enumerate domain groups */
static PyObject *py_enum_domain_groups(PyObject *self, PyObject *args)
{
struct winbindd_response response;
PyObject *result = NULL;
if (!PyArg_ParseTuple(args, ""))
return NULL;
ZERO_STRUCT(response);
if (winbindd_request(WINBINDD_LIST_GROUPS, NULL, &response)
!= NSS_STATUS_SUCCESS) {
PyErr_SetString(winbind_error, "lookup failed");
return NULL;
}
result = PyList_New(0);
if (response.extra_data) {
char *extra_data = response.extra_data;
fstring name;
while (next_token(&extra_data, name, ",", sizeof(fstring)))
PyList_Append(result, PyString_FromString(name));
}
return result;
}
/*
* Miscellaneous domain related
*/
/* Enumerate domain groups */
static PyObject *py_enum_trust_dom(PyObject *self, PyObject *args)
{
struct winbindd_response response;
PyObject *result = NULL;
if (!PyArg_ParseTuple(args, ""))
return NULL;
ZERO_STRUCT(response);
if (winbindd_request(WINBINDD_LIST_TRUSTDOM, NULL, &response)
!= NSS_STATUS_SUCCESS) {
PyErr_SetString(winbind_error, "lookup failed");
return NULL;
}
result = PyList_New(0);
if (response.extra_data) {
char *extra_data = response.extra_data;
fstring name;
while (next_token(&extra_data, name, ",", sizeof(fstring)))
PyList_Append(result, PyString_FromString(name));
}
return result;
}
/* Check machine account password */
static PyObject *py_check_secret(PyObject *self, PyObject *args)
{
struct winbindd_response response;
if (!PyArg_ParseTuple(args, ""))
return NULL;
ZERO_STRUCT(response);
if (winbindd_request(WINBINDD_CHECK_MACHACC, NULL, &response)
!= NSS_STATUS_SUCCESS) {
PyErr_SetString(winbind_error, "lookup failed");
return NULL;
}
return PyInt_FromLong(response.data.num_entries);
}
/*
* Return a dictionary consisting of all the winbind related smb.conf
* parameters. This is stored in the module object.
*/
static PyObject *py_config_dict(void)
{
PyObject *result;
uid_t ulow, uhi;
gid_t glow, ghi;
if (!(result = PyDict_New()))
return NULL;
/* Various string parameters */
PyDict_SetItemString(result, "workgroup",
PyString_FromString(lp_workgroup()));
PyDict_SetItemString(result, "separator",
PyString_FromString(lp_winbind_separator()));
PyDict_SetItemString(result, "template_homedir",
PyString_FromString(lp_template_homedir()));
PyDict_SetItemString(result, "template_shell",
PyString_FromString(lp_template_shell()));
/* Winbind uid/gid range */
if (lp_winbind_uid(&ulow, &uhi)) {
PyDict_SetItemString(result, "uid_low", PyInt_FromLong(ulow));
PyDict_SetItemString(result, "uid_high", PyInt_FromLong(uhi));
}
if (lp_winbind_gid(&glow, &ghi)) {
PyDict_SetItemString(result, "gid_low", PyInt_FromLong(glow));
PyDict_SetItemString(result, "gid_high", PyInt_FromLong(ghi));
}
return result;
}
/*
* ID mapping
*/
/* Convert a uid to a SID */
static PyObject *py_uid_to_sid(PyObject *self, PyObject *args)
{
struct winbindd_request request;
struct winbindd_response response;
int id;
if (!PyArg_ParseTuple(args, "i", &id))
return NULL;
ZERO_STRUCT(request);
ZERO_STRUCT(response);
request.data.uid = id;
if (winbindd_request(WINBINDD_UID_TO_SID, &request, &response)
!= NSS_STATUS_SUCCESS) {
PyErr_SetString(winbind_error, "lookup failed");
return NULL;
}
return PyString_FromString(response.data.sid.sid);
}
/* Convert a gid to a SID */
static PyObject *py_gid_to_sid(PyObject *self, PyObject *args)
{
struct winbindd_request request;
struct winbindd_response response;
int id;
if (!PyArg_ParseTuple(args, "i", &id))
return NULL;
ZERO_STRUCT(request);
ZERO_STRUCT(response);
request.data.gid = id;
if (winbindd_request(WINBINDD_GID_TO_SID, &request, &response)
!= NSS_STATUS_SUCCESS) {
PyErr_SetString(winbind_error, "lookup failed");
return NULL;
}
return PyString_FromString(response.data.sid.sid);
}
/* Convert a sid to a uid */
static PyObject *py_sid_to_uid(PyObject *self, PyObject *args)
{
struct winbindd_request request;
struct winbindd_response response;
char *sid;
if (!PyArg_ParseTuple(args, "s", &sid))
return NULL;
ZERO_STRUCT(request);
ZERO_STRUCT(response);
fstrcpy(request.data.sid, sid);
if (winbindd_request(WINBINDD_SID_TO_UID, &request, &response)
!= NSS_STATUS_SUCCESS) {
PyErr_SetString(winbind_error, "lookup failed");
return NULL;
}
return PyInt_FromLong(response.data.uid);
}
/* Convert a sid to a gid */
static PyObject *py_sid_to_gid(PyObject *self, PyObject *args)
{
struct winbindd_request request;
struct winbindd_response response;
char *sid;
if (!PyArg_ParseTuple(args, "s", &sid))
return NULL;
ZERO_STRUCT(request);
ZERO_STRUCT(response);
fstrcpy(request.data.sid, sid);
if (winbindd_request(WINBINDD_SID_TO_GID, &request, &response)
!= NSS_STATUS_SUCCESS) {
PyErr_SetString(winbind_error, "lookup failed");
return NULL;
}
return PyInt_FromLong(response.data.gid);
}
/*
* PAM authentication functions
*/
/* Plaintext authentication */
static PyObject *py_auth_plaintext(PyObject *self, PyObject *args)
{
struct winbindd_request request;
struct winbindd_response response;
char *username, *password;
if (!PyArg_ParseTuple(args, "ss", &username, &password))
return NULL;
ZERO_STRUCT(request);
ZERO_STRUCT(response);
fstrcpy(request.data.auth.user, username);
fstrcpy(request.data.auth.pass, password);
if (winbindd_request(WINBINDD_PAM_AUTH, &request, &response)
!= NSS_STATUS_SUCCESS) {
PyErr_SetString(winbind_error, "lookup failed");
return NULL;
}
return PyInt_FromLong(response.data.auth.nt_status);
}
/* Challenge/response authentication */
static PyObject *py_auth_crap(PyObject *self, PyObject *args)
{
struct winbindd_request request;
struct winbindd_response response;
char *username, *password;
if (!PyArg_ParseTuple(args, "ss", &username, &password))
return NULL;
ZERO_STRUCT(request);
ZERO_STRUCT(response);
fstrcpy(request.data.auth_crap.user, username);
generate_random_buffer(request.data.auth_crap.chal, 8, False);
SMBencrypt((uchar *)password, request.data.auth_crap.chal,
(uchar *)request.data.auth_crap.lm_resp);
SMBNTencrypt((uchar *)password, request.data.auth_crap.chal,
(uchar *)request.data.auth_crap.nt_resp);
request.data.auth_crap.lm_resp_len = 24;
request.data.auth_crap.nt_resp_len = 24;
if (winbindd_request(WINBINDD_PAM_AUTH_CRAP, &request, &response)
!= NSS_STATUS_SUCCESS) {
PyErr_SetString(winbind_error, "lookup failed");
return NULL;
}
return PyInt_FromLong(response.data.auth.nt_status);
}
/* Get user info from name */
static PyObject *py_getpwnam(PyObject *self, PyObject *args)
{
struct winbindd_request request;
struct winbindd_response response;
char *username;
PyObject *result;
if (!PyArg_ParseTuple(args, "s", &username))
return NULL;
ZERO_STRUCT(request);
ZERO_STRUCT(response);
fstrcpy(request.data.username, username);
if (winbindd_request(WINBINDD_GETPWNAM, &request, &response)
!= NSS_STATUS_SUCCESS) {
PyErr_SetString(winbind_error, "lookup failed");
return NULL;
}
if (!py_from_winbind_passwd(&result, &response)) {
result = Py_None;
Py_INCREF(result);
}
return result;
}
/* Get user info from uid */
static PyObject *py_getpwuid(PyObject *self, PyObject *args)
{
struct winbindd_request request;
struct winbindd_response response;
uid_t uid;
PyObject *result;
if (!PyArg_ParseTuple(args, "i", &uid))
return NULL;
ZERO_STRUCT(request);
ZERO_STRUCT(response);
request.data.uid = uid;
if (winbindd_request(WINBINDD_GETPWUID, &request, &response)
!= NSS_STATUS_SUCCESS) {
PyErr_SetString(winbind_error, "lookup failed");
return NULL;
}
if (!py_from_winbind_passwd(&result, &response)) {
result = Py_None;
Py_INCREF(result);
}
return result;
}
/*
* Method dispatch table
*/
static PyMethodDef winbind_methods[] = {
{ "getpwnam", py_getpwnam, METH_VARARGS, "getpwnam(3)" },
{ "getpwuid", py_getpwuid, METH_VARARGS, "getpwuid(3)" },
/* Name <-> SID conversion */
{ "name_to_sid", py_name_to_sid, METH_VARARGS,
"name_to_sid(s) -> string
Return the SID for a name.
Example:
>>> winbind.name_to_sid('FOO/Administrator')
'S-1-5-21-406022937-1377575209-526660263-500' " },
{ "sid_to_name", py_sid_to_name, METH_VARARGS,
"sid_to_name(s) -> string
Return the name for a SID.
Example:
>>> import winbind
>>> winbind.sid_to_name('S-1-5-21-406022937-1377575209-526660263-500')
'FOO/Administrator' " },
/* Enumerate users/groups */
{ "enum_domain_users", py_enum_domain_users, METH_VARARGS,
"enum_domain_users() -> list of strings
Return a list of domain users.
Example:
>>> winbind.enum_domain_users()
['FOO/Administrator', 'FOO/anna', 'FOO/Anne Elk', 'FOO/build',
'FOO/foo', 'FOO/foo2', 'FOO/foo3', 'FOO/Guest', 'FOO/user1',
'FOO/whoops-ptang'] " },
{ "enum_domain_groups", py_enum_domain_groups, METH_VARARGS,
"enum_domain_groups() -> list of strings
Return a list of domain groups.
Example:
>>> winbind.enum_domain_groups()
['FOO/cows', 'FOO/Domain Admins', 'FOO/Domain Guests',
'FOO/Domain Users'] " },
/* ID mapping */
{ "uid_to_sid", py_uid_to_sid, METH_VARARGS,
"uid_to_sid(int) -> string
Return the SID for a UNIX uid.
Example:
>>> winbind.uid_to_sid(10000)
'S-1-5-21-406022937-1377575209-526660263-500' " },
{ "gid_to_sid", py_gid_to_sid, METH_VARARGS,
"gid_to_sid(int) -> string
Return the UNIX gid for a SID.
Example:
>>> winbind.gid_to_sid(10001)
'S-1-5-21-406022937-1377575209-526660263-512' " },
{ "sid_to_uid", py_sid_to_uid, METH_VARARGS,
"sid_to_uid(string) -> int
Return the UNIX uid for a SID.
Example:
>>> winbind.sid_to_uid('S-1-5-21-406022937-1377575209-526660263-500')
10000 " },
{ "sid_to_gid", py_sid_to_gid, METH_VARARGS,
"sid_to_gid(string) -> int
Return the UNIX gid corresponding to a SID.
Example:
>>> winbind.sid_to_gid('S-1-5-21-406022937-1377575209-526660263-512')
10001 " },
/* Miscellaneous */
{ "check_secret", py_check_secret, METH_VARARGS,
"check_secret() -> int
Check the machine trust account password. The NT status is returned
with zero indicating success. " },
{ "enum_trust_dom", py_enum_trust_dom, METH_VARARGS,
"enum_trust_dom() -> list of strings
Return a list of trusted domains. The domain the server is a member
of is not included.
Example:
>>> winbind.enum_trust_dom()
['NPSD-TEST2', 'SP2NDOM'] " },
/* PAM authorisation functions */
{ "auth_plaintext", py_auth_plaintext, METH_VARARGS,
"auth_plaintext(s, s) -> int
Authenticate a username and password using plaintext authentication.
The NT status code is returned with zero indicating success." },
{ "auth_crap", py_auth_crap, METH_VARARGS,
"auth_crap(s, s) -> int
Authenticate a username and password using the challenge/response
protocol. The NT status code is returned with zero indicating
success." },
{ NULL }
};
static struct const_vals {
char *name;
uint32 value;
char *docstring;
} module_const_vals[] = {
/* Well known RIDs */
{ "DOMAIN_USER_RID_ADMIN", DOMAIN_USER_RID_ADMIN,
"Well-known RID for Administrator user" },
{ "DOMAIN_USER_RID_GUEST", DOMAIN_USER_RID_GUEST,
"Well-known RID for Guest user" },
{ "DOMAIN_GROUP_RID_ADMINS", DOMAIN_GROUP_RID_ADMINS,
"Well-known RID for Domain Admins group" },
{ "DOMAIN_GROUP_RID_USERS", DOMAIN_GROUP_RID_USERS,
"Well-known RID for Domain Users group" },
{ "DOMAIN_GROUP_RID_GUESTS", DOMAIN_GROUP_RID_GUESTS,
"Well-known RID for Domain Guests group" },
{ NULL }
};
static void const_init(PyObject *dict)
{
struct const_vals *tmp;
PyObject *obj;
for (tmp = module_const_vals; tmp->name; tmp++) {
obj = PyInt_FromLong(tmp->value);
PyDict_SetItemString(dict, tmp->name, obj);
Py_DECREF(obj);
}
}
/*
* Module initialisation
*/
static char winbind_module__doc__[] =
"A python extension to winbind client functions.";
void initwinbind(void)
{
PyObject *module, *dict;
/* Initialise module */
module = Py_InitModule3("winbind", winbind_methods,
winbind_module__doc__);
dict = PyModule_GetDict(module);
winbind_error = PyErr_NewException("winbind.error", NULL, NULL);
PyDict_SetItemString(dict, "error", winbind_error);
/* Do samba initialisation */
py_samba_init();
/* Initialise constants */
const_init(dict);
/* Insert configuration dictionary */
PyDict_SetItemString(dict, "config", py_config_dict());
}

View File

@ -0,0 +1,42 @@
/*
Python wrappers for DCERPC/SMB client routines.
Copyright (C) Tim Potter, 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 "Python.h"
#include "python/py_conv.h"
/* Convert a struct passwd to a dictionary */
static struct pyconv py_passwd[] = {
{ "pw_name", PY_STRING, offsetof(struct winbindd_response, data.pw.pw_name) },
{ "pw_passwd", PY_STRING, offsetof(struct winbindd_response, data.pw.pw_passwd) },
{ "pw_uid", PY_UID, offsetof(struct winbindd_response, data.pw.pw_uid) },
{ "pw_guid", PY_GID, offsetof(struct winbindd_response, data.pw.pw_gid) },
{ "pw_gecos", PY_STRING, offsetof(struct winbindd_response, data.pw.pw_gecos) },
{ "pw_dir", PY_STRING, offsetof(struct winbindd_response, data.pw.pw_dir) },
{ "pw_shell", PY_STRING, offsetof(struct winbindd_response, data.pw.pw_shell) },
{ NULL}
};
BOOL py_from_winbind_passwd(PyObject **dict, struct winbindd_response *response)
{
*dict = from_struct(response, py_passwd);
return True;
}

View File

@ -0,0 +1 @@
*.pyc

View File

@ -0,0 +1,7 @@
"""samba
Various Python modules for interfacing to Samba.
Try using help() to examine their documentation.
"""

View File

@ -0,0 +1,59 @@
#!/usr/bin/env python
#
# A python module that maps printerdata to a dictionary. We define
# two classes. The printerdata class maps to Get/Set/Enum/DeletePrinterData
# and the printerdata_ex class maps to Get/Set/Enum/DeletePrinterDataEx
#
#
# TODO:
#
# - Implement __delitem__
#
from samba import spoolss
class printerdata:
def __init__(self, host, creds = {}):
self.hnd = spoolss.openprinter(host, creds = creds)
def keys(self):
return self.hnd.enumprinterdata().keys()
def __getitem__(self, key):
return self.hnd.getprinterdata(key)['data']
def __setitem__(self, key, value):
# Store as REG_BINARY for now
self.hnd.setprinterdata({"key": "", "value": key, "type": 3,
"data": value})
class printerdata_ex:
def __init__(self, host):
self.host = host
self.top_level_keys = ["PrinterDriverData", "DsSpooler", "DsDriver",
"DsUser"]
def keys(self):
return self.top_level_keys
def has_key(self, key):
for k in self.top_level_keys:
if k == key:
return 1
return 0
class printerdata_ex_subkey:
def __init__(self, host, key):
self.hnd = spoolss.openprinter(host)
self.key = key
def keys(self):
return self.hnd.enumprinterdataex(self.key).keys()
def __getitem__(self, key):
return self.hnd.getprinterdataex(self.key, key)['data']
def __getitem__(self, key):
return self.printerdata_ex_subkey(self.host, key)

183
source3/python/setup.py Executable file
View File

@ -0,0 +1,183 @@
# -*- mode: python -*-
#
# Unix SMB/CIFS implementation.
# Module packaging setup for Samba python extensions
#
# Copyright (C) Tim Potter, 2002
# Copyright (C) Martin Pool, 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.
#
from distutils.core import setup
from distutils.extension import Extension
import sys, string, os
# The Makefile passes in environment variable $PYTHON_OBJ as being the
# list of Samba objects. This kind of goes against the distutils.cmd
# method of adding setup commands and will also confuse people who are
# familiar with the python Distutils module.
samba_objs = os.environ.get("PYTHON_OBJS", "")
samba_cflags = os.environ.get("PYTHON_CFLAGS", "")
samba_srcdir = os.environ.get("SRCDIR", "")
# These variables are filled in by configure
samba_libs = os.environ.get("LIBS", "")
# Convert libs and objs from space separated strings to lists of strings
# for distutils to digest. Split "-l" prefix off library list.
obj_list = string.split(samba_objs)
lib_list = []
for lib in string.split(samba_libs):
lib_list.append(string.replace(lib, "-l", ""))
flags_list = string.split(samba_cflags)
# Invoke distutils.setup
setup(
# Overview information
name = "Samba Python Extensions",
version = "0.1",
author = "Tim Potter",
author_email = "tpot@samba.org",
license = "GPL",
# Get the "samba" directory of Python source. At the moment this
# just contains the __init__ file that makes it work as a
# subpackage. This is needed even though everything else is an
# extension module.
package_dir = {"samba": os.path.join(samba_srcdir, "python", "samba")},
packages = ["samba"],
# Module list
ext_package = "samba",
ext_modules = [
# SPOOLSS pipe module
Extension(name = "spoolss",
sources = [samba_srcdir + "python/py_spoolss.c",
samba_srcdir + "python/py_common.c",
samba_srcdir + "python/py_conv.c",
samba_srcdir + "python/py_ntsec.c",
samba_srcdir + "python/py_spoolss_forms.c",
samba_srcdir + "python/py_spoolss_forms_conv.c",
samba_srcdir + "python/py_spoolss_drivers.c",
samba_srcdir + "python/py_spoolss_drivers_conv.c",
samba_srcdir + "python/py_spoolss_printers.c",
samba_srcdir + "python/py_spoolss_printers_conv.c",
samba_srcdir + "python/py_spoolss_printerdata.c",
samba_srcdir + "python/py_spoolss_ports.c",
samba_srcdir + "python/py_spoolss_ports_conv.c",
samba_srcdir + "python/py_spoolss_jobs.c",
samba_srcdir + "python/py_spoolss_jobs_conv.c",
],
libraries = lib_list,
library_dirs = ["/usr/kerberos/lib"],
extra_compile_args = flags_list,
extra_objects = obj_list),
# LSA pipe module
Extension(name = "lsa",
sources = [samba_srcdir + "python/py_lsa.c",
samba_srcdir + "python/py_common.c",
samba_srcdir + "python/py_ntsec.c"],
libraries = lib_list,
library_dirs = ["/usr/kerberos/lib"],
extra_compile_args = flags_list,
extra_objects = obj_list),
# SAMR pipe module
Extension(name = "samr",
sources = [samba_srcdir + "python/py_samr.c",
samba_srcdir + "python/py_samr_conv.c",
samba_srcdir + "python/py_common.c"],
libraries = lib_list,
library_dirs = ["/usr/kerberos/lib"],
extra_compile_args = flags_list,
extra_objects = obj_list),
# winbind client module
Extension(name = "winbind",
sources = [samba_srcdir + "python/py_winbind.c",
samba_srcdir + "python/py_winbind_conv.c",
samba_srcdir + "python/py_conv.c",
samba_srcdir + "python/py_common.c"],
libraries = lib_list,
library_dirs = ["/usr/kerberos/lib"],
extra_compile_args = flags_list,
extra_objects = obj_list),
# WINREG pipe module
Extension(name = "winreg",
sources = [samba_srcdir + "python/py_winreg.c",
samba_srcdir + "python/py_common.c"],
libraries = lib_list,
library_dirs = ["/usr/kerberos/lib"],
extra_compile_args = flags_list,
extra_objects = obj_list),
# tdb module
Extension(name = "tdb",
sources = [samba_srcdir + "python/py_tdb.c"],
libraries = lib_list,
library_dirs = ["/usr/kerberos/lib"],
extra_compile_args = flags_list,
extra_objects = obj_list),
# libsmb module
Extension(name = "smb",
sources = [samba_srcdir + "python/py_smb.c",
samba_srcdir + "python/py_common.c"],
libraries = lib_list,
library_dirs = ["/usr/kerberos/lib"],
extra_compile_args = flags_list,
extra_objects = obj_list),
# Moving to merge all individual extensions in to one big
# extension. This is to avoid the fact that each extension is 3MB
# in size due to the lack of proper depedency management in Samba.
Extension(name = "samba",
sources = [samba_srcdir + "python/py_samba.c",
samba_srcdir + "python/py_common.c"],
libraries = lib_list,
library_dirs = ["/usr/kerberos/lib"],
extra_compile_args = flags_list,
extra_objects = obj_list),
# tdbpack/unpack extensions. Does not actually link to any Samba
# code, although it implements a compatible data format.
Extension(name = "tdbpack",
sources = [os.path.join(samba_srcdir, "python", "py_tdbpack.c")]),
],
)

View File

@ -0,0 +1,372 @@
/*
* Unix SMB/CIFS implementation.
* RPC Pipe client / server routines
* Copyright (C) Gerald Carter 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.
*/
/* Implementation of registry frontend view functions. */
#include "includes.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_RPC_SRV
/***********************************************************************
Init the talloc context held by a REGSUBKEY_CTR structure
**********************************************************************/
void regsubkey_ctr_init( REGSUBKEY_CTR *ctr )
{
if ( !ctr->ctx )
ctr->ctx = talloc_init();
}
/***********************************************************************
Add a new key to the array
**********************************************************************/
int regsubkey_ctr_addkey( REGSUBKEY_CTR *ctr, char *keyname )
{
uint32 len;
char **pp;
if ( keyname )
{
len = strlen( keyname );
/* allocate a space for the char* in the array */
if ( ctr->subkeys == 0 )
ctr->subkeys = talloc( ctr->ctx, sizeof(char*) );
else {
pp = talloc_realloc( ctr->ctx, ctr->subkeys, sizeof(char*)*(ctr->num_subkeys+1) );
if ( pp )
ctr->subkeys = pp;
}
/* allocate the string and save it in the array */
ctr->subkeys[ctr->num_subkeys] = talloc( ctr->ctx, len+1 );
strncpy( ctr->subkeys[ctr->num_subkeys], keyname, len+1 );
ctr->num_subkeys++;
}
return ctr->num_subkeys;
}
/***********************************************************************
How many keys does the container hold ?
**********************************************************************/
int regsubkey_ctr_numkeys( REGSUBKEY_CTR *ctr )
{
return ctr->num_subkeys;
}
/***********************************************************************
Retreive a specific key string
**********************************************************************/
char* regsubkey_ctr_specific_key( REGSUBKEY_CTR *ctr, uint32 key_index )
{
if ( ! (key_index < ctr->num_subkeys) )
return NULL;
return ctr->subkeys[key_index];
}
/***********************************************************************
free memory held by a REGSUBKEY_CTR structure
**********************************************************************/
void regsubkey_ctr_destroy( REGSUBKEY_CTR *ctr )
{
if ( ctr ) {
talloc_destroy( ctr->ctx );
ZERO_STRUCTP( ctr );
}
}
/*
* Utility functions for REGVAL_CTR
*/
/***********************************************************************
Init the talloc context held by a REGSUBKEY_CTR structure
**********************************************************************/
void regval_ctr_init( REGVAL_CTR *ctr )
{
if ( !ctr->ctx )
ctr->ctx = talloc_init();
}
/***********************************************************************
How many keys does the container hold ?
**********************************************************************/
int regval_ctr_numvals( REGVAL_CTR *ctr )
{
return ctr->num_values;
}
/***********************************************************************
allocate memory for and duplicate a REGISTRY_VALUE.
This is malloc'd memory so the caller should free it when done
**********************************************************************/
REGISTRY_VALUE* dup_registry_value( REGISTRY_VALUE *val )
{
REGISTRY_VALUE *copy = NULL;
if ( !val )
return NULL;
if ( !(copy = malloc( sizeof(REGISTRY_VALUE) )) ) {
DEBUG(0,("dup_registry_value: malloc() failed!\n"));
return NULL;
}
/* copy all the non-pointer initial data */
memcpy( copy, val, sizeof(REGISTRY_VALUE) );
if ( val->data_p )
{
if ( !(copy->data_p = memdup( val->data_p, val->size )) ) {
DEBUG(0,("dup_registry_value: memdup() failed for [%d] bytes!\n",
val->size));
SAFE_FREE( copy );
}
}
return copy;
}
/**********************************************************************
free the memory allocated to a REGISTRY_VALUE
*********************************************************************/
void free_registry_value( REGISTRY_VALUE *val )
{
if ( !val )
return;
SAFE_FREE( val->data_p );
SAFE_FREE( val );
return;
}
/**********************************************************************
*********************************************************************/
uint8* regval_data_p( REGISTRY_VALUE *val )
{
return val->data_p;
}
/**********************************************************************
*********************************************************************/
int regval_size( REGISTRY_VALUE *val )
{
return val->size;
}
/**********************************************************************
*********************************************************************/
char* regval_name( REGISTRY_VALUE *val )
{
return val->valuename;
}
/**********************************************************************
*********************************************************************/
uint32 regval_type( REGISTRY_VALUE *val )
{
return val->type;
}
/***********************************************************************
Retreive a pointer to a specific value. Caller shoud dup the structure
since this memory may go away with a regval_ctr_destroy()
**********************************************************************/
REGISTRY_VALUE* regval_ctr_specific_value( REGVAL_CTR *ctr, uint32 idx )
{
if ( !(idx < ctr->num_values) )
return NULL;
return ctr->values[idx];
}
/***********************************************************************
Retrive the TALLOC_CTX associated with a REGISTRY_VALUE
**********************************************************************/
TALLOC_CTX* regval_ctr_getctx( REGVAL_CTR *val )
{
if ( !val )
return NULL;
return val->ctx;
}
/***********************************************************************
Add a new registry value to the array
**********************************************************************/
int regval_ctr_addvalue( REGVAL_CTR *ctr, char *name, uint16 type,
char *data_p, size_t size )
{
REGISTRY_VALUE **ppreg;
if ( name )
{
/* allocate a slot in the array of pointers */
if ( ctr->num_values == 0 )
ctr->values = talloc( ctr->ctx, sizeof(REGISTRY_VALUE*) );
else {
ppreg = talloc_realloc( ctr->ctx, ctr->values, sizeof(REGISTRY_VALUE*)*(ctr->num_values+1) );
if ( ppreg )
ctr->values = ppreg;
}
/* allocate a new value and store the pointer in the arrya */
ctr->values[ctr->num_values] = talloc( ctr->ctx, sizeof(REGISTRY_VALUE) );
/* init the value */
fstrcpy( ctr->values[ctr->num_values]->valuename, name );
ctr->values[ctr->num_values]->type = type;
ctr->values[ctr->num_values]->data_p = talloc_memdup( ctr->ctx, data_p, size );
ctr->values[ctr->num_values]->size = size;
ctr->num_values++;
}
return ctr->num_values;
}
/***********************************************************************
Add a new registry value to the array
**********************************************************************/
int regval_ctr_copyvalue( REGVAL_CTR *ctr, REGISTRY_VALUE *val )
{
REGISTRY_VALUE **ppreg;
if ( val )
{
/* allocate a slot in the array of pointers */
if ( ctr->num_values == 0 )
ctr->values = talloc( ctr->ctx, sizeof(REGISTRY_VALUE*) );
else {
ppreg = talloc_realloc( ctr->ctx, ctr->values, sizeof(REGISTRY_VALUE*)*(ctr->num_values+1) );
if ( ppreg )
ctr->values = ppreg;
}
/* allocate a new value and store the pointer in the arrya */
ctr->values[ctr->num_values] = talloc( ctr->ctx, sizeof(REGISTRY_VALUE) );
/* init the value */
fstrcpy( ctr->values[ctr->num_values]->valuename, val->valuename );
ctr->values[ctr->num_values]->type = val->type;
ctr->values[ctr->num_values]->data_p = talloc_memdup( ctr->ctx, val->data_p, val->size );
ctr->values[ctr->num_values]->size = val->size;
ctr->num_values++;
}
return ctr->num_values;
}
/***********************************************************************
Delete a single value from the registry container.
No need to free memory since it is talloc'd.
**********************************************************************/
int regval_ctr_delvalue( REGVAL_CTR *ctr, char *name )
{
int i;
/* search for the value */
for ( i=0; i<ctr->num_values; i++ ) {
if ( strcmp( ctr->values[i]->valuename, name ) == 0)
break;
}
/* just return if we don't find it */
if ( i == ctr->num_values )
return ctr->num_values;
/* just shift everything down one */
for ( /* use previous i */; i<(ctr->num_values-1); i++ )
memcpy( ctr->values[i], ctr->values[i+1], sizeof(REGISTRY_VALUE) );
/* paranoia */
ZERO_STRUCTP( ctr->values[i] );
ctr->num_values--;
return ctr->num_values;
}
/***********************************************************************
Delete a single value from the registry container.
No need to free memory since it is talloc'd.
**********************************************************************/
REGISTRY_VALUE* regval_ctr_getvalue( REGVAL_CTR *ctr, char *name )
{
int i;
/* search for the value */
for ( i=0; i<ctr->num_values; i++ ) {
if ( strequal( ctr->values[i]->valuename, name ) )
return ctr->values[i];
}
return NULL;
}
/***********************************************************************
free memory held by a REGVAL_CTR structure
**********************************************************************/
void regval_ctr_destroy( REGVAL_CTR *ctr )
{
if ( ctr ) {
talloc_destroy( ctr->ctx );
ZERO_STRUCTP( ctr );
}
}

307
source3/sam/account.c Normal file
View File

@ -0,0 +1,307 @@
/*
Unix SMB/CIFS implementation.
Password and authentication handling
Copyright (C) Jeremy Allison 1996-2001
Copyright (C) Luke Kenneth Casson Leighton 1996-1998
Copyright (C) Gerald (Jerry) Carter 2000-2001
Copyright (C) Andrew Bartlett 2001-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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_SAM
/************************************************************
Fill the SAM_ACCOUNT_HANDLE with default values.
***********************************************************/
static void sam_fill_default_account(SAM_ACCOUNT_HANDLE *account)
{
ZERO_STRUCT(account->private); /* Don't touch the talloc context */
/* Don't change these timestamp settings without a good reason.
They are important for NT member server compatibility. */
account->private.init_flag = FLAG_SAM_UNINIT;
/* FIXME: We should actually call get_nt_time_max() or sthng
* here */
unix_to_nt_time(&(account->private.logoff_time),get_time_t_max());
unix_to_nt_time(&(account->private.kickoff_time),get_time_t_max());
unix_to_nt_time(&(account->private.pass_must_change_time),get_time_t_max());
account->private.unknown_1 = 0x00ffffff; /* don't know */
account->private.logon_divs = 168; /* hours per week */
account->private.hours_len = 21; /* 21 times 8 bits = 168 */
memset(account->private.hours, 0xff, account->private.hours_len); /* available at all hours */
account->private.unknown_2 = 0x00000000; /* don't know */
account->private.unknown_3 = 0x000004ec; /* don't know */
}
static void destroy_sam_talloc(SAM_ACCOUNT_HANDLE **account)
{
if (*account) {
data_blob_clear_free(&((*account)->private.lm_pw));
data_blob_clear_free(&((*account)->private.nt_pw));
if((*account)->private.plaintext_pw!=NULL)
memset((*account)->private.plaintext_pw,'\0',strlen((*account)->private.plaintext_pw));
talloc_destroy((*account)->mem_ctx);
*account = NULL;
}
}
/**********************************************************************
Alloc memory and initialises a SAM_ACCOUNT_HANDLE on supplied mem_ctx.
***********************************************************************/
NTSTATUS sam_init_account_talloc(TALLOC_CTX *mem_ctx, SAM_ACCOUNT_HANDLE **account)
{
SMB_ASSERT(*account != NULL);
if (!mem_ctx) {
DEBUG(0,("sam_init_account_talloc: mem_ctx was NULL!\n"));
return NT_STATUS_UNSUCCESSFUL;
}
*account=(SAM_ACCOUNT_HANDLE *)talloc(mem_ctx, sizeof(SAM_ACCOUNT_HANDLE));
if (*account==NULL) {
DEBUG(0,("sam_init_account_talloc: error while allocating memory\n"));
return NT_STATUS_NO_MEMORY;
}
(*account)->mem_ctx = mem_ctx;
(*account)->free_fn = NULL;
sam_fill_default_account(*account);
return NT_STATUS_OK;
}
/*************************************************************
Alloc memory and initialises a struct sam_passwd.
************************************************************/
NTSTATUS sam_init_account(SAM_ACCOUNT_HANDLE **account)
{
TALLOC_CTX *mem_ctx;
NTSTATUS nt_status;
mem_ctx = talloc_init_named("sam internal SAM_ACCOUNT_HANDLE allocation");
if (!mem_ctx) {
DEBUG(0,("sam_init_account: error while doing talloc_init()\n"));
return NT_STATUS_NO_MEMORY;
}
if (!NT_STATUS_IS_OK(nt_status = sam_init_account_talloc(mem_ctx, account))) {
talloc_destroy(mem_ctx);
return nt_status;
}
(*account)->free_fn = destroy_sam_talloc;
return NT_STATUS_OK;
}
/**
* Free the contents of the SAM_ACCOUNT_HANDLE, but not the structure.
*
* Also wipes the LM and NT hashes and plaintext password from
* memory.
*
* @param account SAM_ACCOUNT_HANDLE to free members of.
**/
static void sam_free_account_contents(SAM_ACCOUNT_HANDLE *account)
{
/* Kill off sensitive data. Free()ed by the
talloc mechinism */
data_blob_clear_free(&(account->private.lm_pw));
data_blob_clear_free(&(account->private.nt_pw));
if (account->private.plaintext_pw)
memset(account->private.plaintext_pw,'\0',strlen(account->private.plaintext_pw));
}
/************************************************************
Reset the SAM_ACCOUNT_HANDLE and free the NT/LM hashes.
***********************************************************/
NTSTATUS sam_reset_sam(SAM_ACCOUNT_HANDLE *account)
{
SMB_ASSERT(account != NULL);
sam_free_account_contents(account);
sam_fill_default_account(account);
return NT_STATUS_OK;
}
/************************************************************
Free the SAM_ACCOUNT_HANDLE and the member pointers.
***********************************************************/
NTSTATUS sam_free_account(SAM_ACCOUNT_HANDLE **account)
{
SMB_ASSERT(*account != NULL);
sam_free_account_contents(*account);
if ((*account)->free_fn) {
(*account)->free_fn(account);
}
return NT_STATUS_OK;
}
/**********************************************************
Encode the account control bits into a string.
length = length of string to encode into (including terminating
null). length *MUST BE MORE THAN 2* !
**********************************************************/
char *sam_encode_acct_ctrl(uint16 acct_ctrl, size_t length)
{
static fstring acct_str;
size_t i = 0;
acct_str[i++] = '[';
if (acct_ctrl & ACB_PWNOTREQ ) acct_str[i++] = 'N';
if (acct_ctrl & ACB_DISABLED ) acct_str[i++] = 'D';
if (acct_ctrl & ACB_HOMDIRREQ) acct_str[i++] = 'H';
if (acct_ctrl & ACB_TEMPDUP ) acct_str[i++] = 'T';
if (acct_ctrl & ACB_NORMAL ) acct_str[i++] = 'U';
if (acct_ctrl & ACB_MNS ) acct_str[i++] = 'M';
if (acct_ctrl & ACB_WSTRUST ) acct_str[i++] = 'W';
if (acct_ctrl & ACB_SVRTRUST ) acct_str[i++] = 'S';
if (acct_ctrl & ACB_AUTOLOCK ) acct_str[i++] = 'L';
if (acct_ctrl & ACB_PWNOEXP ) acct_str[i++] = 'X';
if (acct_ctrl & ACB_DOMTRUST ) acct_str[i++] = 'I';
for ( ; i < length - 2 ; i++ )
acct_str[i] = ' ';
i = length - 2;
acct_str[i++] = ']';
acct_str[i++] = '\0';
return acct_str;
}
/**********************************************************
Decode the account control bits from a string.
**********************************************************/
uint16 sam_decode_acct_ctrl(const char *p)
{
uint16 acct_ctrl = 0;
BOOL finished = False;
/*
* Check if the account type bits have been encoded after the
* NT password (in the form [NDHTUWSLXI]).
*/
if (*p != '[')
return 0;
for (p++; *p && !finished; p++) {
switch (*p) {
case 'N': { acct_ctrl |= ACB_PWNOTREQ ; break; /* 'N'o password. */ }
case 'D': { acct_ctrl |= ACB_DISABLED ; break; /* 'D'isabled. */ }
case 'H': { acct_ctrl |= ACB_HOMDIRREQ; break; /* 'H'omedir required. */ }
case 'T': { acct_ctrl |= ACB_TEMPDUP ; break; /* 'T'emp account. */ }
case 'U': { acct_ctrl |= ACB_NORMAL ; break; /* 'U'ser account (normal). */ }
case 'M': { acct_ctrl |= ACB_MNS ; break; /* 'M'NS logon user account. What is this ? */ }
case 'W': { acct_ctrl |= ACB_WSTRUST ; break; /* 'W'orkstation account. */ }
case 'S': { acct_ctrl |= ACB_SVRTRUST ; break; /* 'S'erver account. */ }
case 'L': { acct_ctrl |= ACB_AUTOLOCK ; break; /* 'L'ocked account. */ }
case 'X': { acct_ctrl |= ACB_PWNOEXP ; break; /* No 'X'piry on password */ }
case 'I': { acct_ctrl |= ACB_DOMTRUST ; break; /* 'I'nterdomain trust account. */ }
case ' ': { break; }
case ':':
case '\n':
case '\0':
case ']':
default: { finished = True; }
}
}
return acct_ctrl;
}
/*************************************************************
Routine to set 32 hex password characters from a 16 byte array.
**************************************************************/
void sam_sethexpwd(char *p, const unsigned char *pwd, uint16 acct_ctrl)
{
if (pwd != NULL) {
int i;
for (i = 0; i < 16; i++)
slprintf(&p[i*2], 3, "%02X", pwd[i]);
} else {
if (acct_ctrl & ACB_PWNOTREQ)
safe_strcpy(p, "NO PASSWORDXXXXXXXXXXXXXXXXXXXXX", 33);
else
safe_strcpy(p, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", 33);
}
}
/*************************************************************
Routine to get the 32 hex characters and turn them
into a 16 byte array.
**************************************************************/
BOOL sam_gethexpwd(const char *p, unsigned char *pwd)
{
int i;
unsigned char lonybble, hinybble;
char *hexchars = "0123456789ABCDEF";
char *p1, *p2;
if (!p)
return (False);
for (i = 0; i < 32; i += 2) {
hinybble = toupper(p[i]);
lonybble = toupper(p[i + 1]);
p1 = strchr(hexchars, hinybble);
p2 = strchr(hexchars, lonybble);
if (!p1 || !p2)
return (False);
hinybble = PTR_DIFF(p1, hexchars);
lonybble = PTR_DIFF(p2, hexchars);
pwd[i / 2] = (hinybble << 4) | lonybble;
}
return (True);
}

322
source3/sam/api.c Normal file
View File

@ -0,0 +1,322 @@
/*
Unix SMB/CIFS implementation.
SAM interface API.
Copyright (C) Stefan (metze) Metzmacher 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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_SAM
/* these functions should be used by the rest of SAMBA --metze */
/* General API */
NTSTATUS sam_get_sec_desc(const NT_USER_TOKEN *access_token, const DOM_SID *sid, SEC_DESC **sd)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_get_sec_desc(sam_context, access_token, sid, sd);
}
NTSTATUS sam_set_sec_desc(const NT_USER_TOKEN *access_token, const DOM_SID *sid, const SEC_DESC *sd)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_set_sec_desc(sam_context, access_token, sid, sd);
}
NTSTATUS sam_lookup_sid(const NT_USER_TOKEN *access_token, const DOM_SID *sid, char **name, uint32 *type)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_lookup_sid(sam_context, access_token, sid, name, type);
}
NTSTATUS sam_lookup_name(const NT_USER_TOKEN *access_token, const char *domain, const char *name, DOM_SID **sid, uint32 *type)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_lookup_name(sam_context, access_token, domain, name, sid, type);
}
/* Domain API */
NTSTATUS sam_update_domain(const SAM_DOMAIN_HANDLE *domain)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_update_domain(sam_context, domain);
}
NTSTATUS sam_enum_domains(const NT_USER_TOKEN *access_token, int32 *domain_count, DOM_SID **domains, char **domain_names)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_enum_domains(sam_context, access_token, domain_count, domains, domain_names);
}
NTSTATUS sam_lookup_domain(const NT_USER_TOKEN * access_token, const char *domain, DOM_SID **domainsid)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_lookup_domain(sam_context, access_token, domain, domainsid);
}
NTSTATUS sam_get_domain_by_sid(const NT_USER_TOKEN *access_token, const uint32 access_desired, const DOM_SID *domainsid, SAM_DOMAIN_HANDLE **domain)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_get_domain_by_sid(sam_context, access_token, access_desired, domainsid, domain);
}
/* Account API */
NTSTATUS sam_create_account(const NT_USER_TOKEN *access_token, const uint32 access_desired, const DOM_SID *domainsid, const char *account_name, uint16 acct_ctrl, SAM_ACCOUNT_HANDLE **account)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_create_account(sam_context, access_token, access_desired, domainsid, account_name, acct_ctrl, account);
}
NTSTATUS sam_add_account(const DOM_SID *domainsid, const SAM_ACCOUNT_HANDLE *account)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_add_account(sam_context, domainsid, account);
}
NTSTATUS sam_update_account(const SAM_ACCOUNT_HANDLE *account)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_update_account(sam_context, account);
}
NTSTATUS sam_delete_account(const SAM_ACCOUNT_HANDLE *account)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_delete_account(sam_context, account);
}
NTSTATUS sam_enum_accounts(const NT_USER_TOKEN *access_token, const DOM_SID *domain, uint16 acct_ctrl, uint32 *account_count, SAM_ACCOUNT_ENUM **accounts)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_enum_accounts(sam_context, access_token, domain, acct_ctrl, account_count, accounts);
}
NTSTATUS sam_get_account_by_sid(const NT_USER_TOKEN *access_token, const uint32 access_desired, const DOM_SID *accountsid, SAM_ACCOUNT_HANDLE **account)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_get_account_by_sid(sam_context, access_token, access_desired, accountsid, account);
}
NTSTATUS sam_get_account_by_name(const NT_USER_TOKEN *access_token, const uint32 access_desired, const char *domain, const char *name, SAM_ACCOUNT_HANDLE **account)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_get_account_by_name(sam_context, access_token, access_desired, domain, name, account);
}
/* Group API */
NTSTATUS sam_create_group(const NT_USER_TOKEN *access_token, const uint32 access_desired, const DOM_SID *domainsid, const char *group_name, uint16 group_ctrl, SAM_GROUP_HANDLE **group)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_create_group(sam_context, access_token, access_desired, domainsid, group_name, group_ctrl, group);
}
NTSTATUS sam_add_group(const DOM_SID *domainsid, const SAM_GROUP_HANDLE *group)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_add_group(sam_context, domainsid, group);
}
NTSTATUS sam_update_group(const SAM_GROUP_HANDLE *group)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_update_group(sam_context, group);
}
NTSTATUS sam_delete_group(const SAM_GROUP_HANDLE *group)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_delete_group(sam_context, group);
}
NTSTATUS sam_enum_groups(const NT_USER_TOKEN *access_token, const DOM_SID *domainsid, uint16 group_ctrl, uint32 *groups_count, SAM_GROUP_ENUM **groups)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_enum_groups(sam_context, access_token, domainsid, group_ctrl, groups_count, groups);
}
NTSTATUS sam_get_group_by_sid(const NT_USER_TOKEN *access_token, const uint32 access_desired, const DOM_SID *groupsid, SAM_GROUP_HANDLE **group)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_get_group_by_sid(sam_context, access_token, access_desired, groupsid, group);
}
NTSTATUS sam_get_group_by_name(const NT_USER_TOKEN *access_token, const uint32 access_desired, const char *domain, const char *name, SAM_GROUP_HANDLE **group)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_get_group_by_name(sam_context, access_token, access_desired, domain, name, group);
}
NTSTATUS sam_add_member_to_group(const SAM_GROUP_HANDLE *group, const SAM_GROUP_MEMBER *member)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_add_member_to_group(sam_context, group, member);
}
NTSTATUS sam_delete_member_from_group(const SAM_GROUP_HANDLE *group, const SAM_GROUP_MEMBER *member)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_delete_member_from_group(sam_context, group, member);
}
NTSTATUS sam_enum_groupmembers(const SAM_GROUP_HANDLE *group, uint32 *members_count, SAM_GROUP_MEMBER **members)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_enum_groupmembers(sam_context, group, members_count, members);
}
NTSTATUS sam_get_groups_of_sid(const NT_USER_TOKEN *access_token, const DOM_SID **sids, uint16 group_ctrl, uint32 *group_count, SAM_GROUP_ENUM **groups)
{
SAM_CONTEXT *sam_context = sam_get_static_context(False);
if (!sam_context) {
return NT_STATUS_UNSUCCESSFUL;
}
return sam_context->sam_get_groups_of_sid(sam_context, access_token, sids, group_ctrl, group_count, groups);
}

View File

@ -0,0 +1,872 @@
/*
Unix SMB/CIFS implementation.
SAM_ACCOUNT_HANDLE access routines
Copyright (C) Andrew Bartlett 2002
Copyright (C) Stefan (metze) Metzmacher 2002
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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_SAM
NTSTATUS sam_get_account_domain_sid(const SAM_ACCOUNT_HANDLE *sampass, const DOM_SID **sid)
{
NTSTATUS status;
SAM_DOMAIN_HANDLE *domain;
SAM_ASSERT(!sampass || !sid);
if (!NT_STATUS_IS_OK(status = sam_get_account_domain(sampass, &domain))){
DEBUG(0, ("sam_get_account_domain_sid: Can't get domain for account\n"));
return status;
}
return sam_get_domain_sid(domain, sid);
}
NTSTATUS sam_get_account_domain_name(const SAM_ACCOUNT_HANDLE *sampass, const char **domain_name)
{
NTSTATUS status;
SAM_DOMAIN_HANDLE *domain;
SAM_ASSERT(sampass && domain_name);
if (!NT_STATUS_IS_OK(status = sam_get_account_domain(sampass, &domain))){
DEBUG(0, ("sam_get_account_domain_name: Can't get domain for account\n"));
return status;
}
return sam_get_domain_name(domain, domain_name);
}
NTSTATUS sam_get_account_acct_ctrl(const SAM_ACCOUNT_HANDLE *sampass, uint16 *acct_ctrl)
{
SAM_ASSERT(sampass && acct_ctrl);
*acct_ctrl = sampass->private.acct_ctrl;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_logon_time(const SAM_ACCOUNT_HANDLE *sampass, NTTIME *logon_time)
{
SAM_ASSERT(sampass && logon_time) ;
*logon_time = sampass->private.logon_time;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_logoff_time(const SAM_ACCOUNT_HANDLE *sampass, NTTIME *logoff_time)
{
SAM_ASSERT(sampass && logoff_time) ;
*logoff_time = sampass->private.logoff_time;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_kickoff_time(const SAM_ACCOUNT_HANDLE *sampass, NTTIME *kickoff_time)
{
SAM_ASSERT(sampass && kickoff_time);
*kickoff_time = sampass->private.kickoff_time;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_pass_last_set_time(const SAM_ACCOUNT_HANDLE *sampass, NTTIME *pass_last_set_time)
{
SAM_ASSERT(sampass && pass_last_set_time);
*pass_last_set_time = sampass->private.pass_last_set_time;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_pass_can_change_time(const SAM_ACCOUNT_HANDLE *sampass, NTTIME *pass_can_change_time)
{
SAM_ASSERT(sampass && pass_can_change_time);
*pass_can_change_time = sampass->private.pass_can_change_time;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_pass_must_change_time(const SAM_ACCOUNT_HANDLE *sampass, NTTIME *pass_must_change_time)
{
SAM_ASSERT(sampass && pass_must_change_time);
*pass_must_change_time = sampass->private.pass_must_change_time;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_logon_divs(const SAM_ACCOUNT_HANDLE *sampass, uint16 *logon_divs)
{
SAM_ASSERT(sampass && logon_divs);
*logon_divs = sampass->private.logon_divs;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_hours_len(const SAM_ACCOUNT_HANDLE *sampass, uint32 *hours_len)
{
SAM_ASSERT(sampass && hours_len);
*hours_len = sampass->private.hours_len;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_hours(const SAM_ACCOUNT_HANDLE *sampass, const uint8 **hours)
{
SAM_ASSERT(sampass && hours);
*hours = sampass->private.hours;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_nt_pwd(const SAM_ACCOUNT_HANDLE *sampass, DATA_BLOB *nt_pwd)
{
SAM_ASSERT(sampass);
SMB_ASSERT((!sampass->private.nt_pw.data)
|| sampass->private.nt_pw.length == NT_HASH_LEN);
*nt_pwd = sampass->private.nt_pw;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_lm_pwd(const SAM_ACCOUNT_HANDLE *sampass, DATA_BLOB *lm_pwd)
{
SAM_ASSERT(sampass);
SMB_ASSERT((!sampass->private.lm_pw.data)
|| sampass->private.lm_pw.length == LM_HASH_LEN);
*lm_pwd = sampass->private.lm_pw;
return NT_STATUS_OK;
}
/* Return the plaintext password if known. Most of the time
it isn't, so don't assume anything magic about this function.
Used to pass the plaintext to sam backends that might
want to store more than just the NTLM hashes.
*/
NTSTATUS sam_get_account_plaintext_pwd(const SAM_ACCOUNT_HANDLE *sampass, char **plain_pwd)
{
SAM_ASSERT(sampass && plain_pwd);
*plain_pwd = sampass->private.plaintext_pw;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_sid(const SAM_ACCOUNT_HANDLE *sampass, const DOM_SID **sid)
{
SAM_ASSERT(sampass);
*sid = &(sampass->private.account_sid);
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_pgroup(const SAM_ACCOUNT_HANDLE *sampass, const DOM_SID **sid)
{
SAM_ASSERT(sampass);
*sid = &(sampass->private.group_sid);
return NT_STATUS_OK;
}
/**
* Get flags showing what is initalised in the SAM_ACCOUNT_HANDLE
* @param sampass the SAM_ACCOUNT_HANDLE in question
* @return the flags indicating the members initialised in the struct.
**/
NTSTATUS sam_get_account_init_flag(const SAM_ACCOUNT_HANDLE *sampass, uint32 *initflag)
{
SAM_ASSERT(sampass);
*initflag = sampass->private.init_flag;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_name(const SAM_ACCOUNT_HANDLE *sampass, char **account_name)
{
SAM_ASSERT(sampass);
*account_name = sampass->private.account_name;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_domain(const SAM_ACCOUNT_HANDLE *sampass, SAM_DOMAIN_HANDLE **domain)
{
SAM_ASSERT(sampass);
*domain = sampass->private.domain;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_fullname(const SAM_ACCOUNT_HANDLE *sampass, char **fullname)
{
SAM_ASSERT(sampass);
*fullname = sampass->private.full_name;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_homedir(const SAM_ACCOUNT_HANDLE *sampass, char **homedir)
{
SAM_ASSERT(sampass);
*homedir = sampass->private.home_dir;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_unix_home_dir(const SAM_ACCOUNT_HANDLE *sampass, char **uhomedir)
{
SAM_ASSERT(sampass);
*uhomedir = sampass->private.unix_home_dir;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_dir_drive(const SAM_ACCOUNT_HANDLE *sampass, char **dirdrive)
{
SAM_ASSERT(sampass);
*dirdrive = sampass->private.dir_drive;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_logon_script(const SAM_ACCOUNT_HANDLE *sampass, char **logon_script)
{
SAM_ASSERT(sampass);
*logon_script = sampass->private.logon_script;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_profile_path(const SAM_ACCOUNT_HANDLE *sampass, char **profile_path)
{
SAM_ASSERT(sampass);
*profile_path = sampass->private.profile_path;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_description(const SAM_ACCOUNT_HANDLE *sampass, char **description)
{
SAM_ASSERT(sampass);
*description = sampass->private.acct_desc;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_workstations(const SAM_ACCOUNT_HANDLE *sampass, char **workstations)
{
SAM_ASSERT(sampass);
*workstations = sampass->private.workstations;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_unknown_str(const SAM_ACCOUNT_HANDLE *sampass, char **unknown_str)
{
SAM_ASSERT(sampass);
*unknown_str = sampass->private.unknown_str;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_munged_dial(const SAM_ACCOUNT_HANDLE *sampass, char **munged_dial)
{
SAM_ASSERT(sampass);
*munged_dial = sampass->private.munged_dial;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_unknown_1(const SAM_ACCOUNT_HANDLE *sampass, uint32 *unknown1)
{
SAM_ASSERT(sampass && unknown1);
*unknown1 = sampass->private.unknown_1;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_unknown_2(const SAM_ACCOUNT_HANDLE *sampass, uint32 *unknown2)
{
SAM_ASSERT(sampass && unknown2);
*unknown2 = sampass->private.unknown_2;
return NT_STATUS_OK;
}
NTSTATUS sam_get_account_unknown_3(const SAM_ACCOUNT_HANDLE *sampass, uint32 *unknown3)
{
SAM_ASSERT(sampass && unknown3);
*unknown3 = sampass->private.unknown_3;
return NT_STATUS_OK;
}
/*********************************************************************
Collection of set...() functions for SAM_ACCOUNT_HANDLE_INFO.
********************************************************************/
NTSTATUS sam_set_account_acct_ctrl(SAM_ACCOUNT_HANDLE *sampass, uint16 flags)
{
SAM_ASSERT(sampass);
sampass->private.acct_ctrl = flags;
return NT_STATUS_OK;
}
NTSTATUS sam_set_account_logon_time(SAM_ACCOUNT_HANDLE *sampass, NTTIME mytime, BOOL store)
{
SAM_ASSERT(sampass);
sampass->private.logon_time = mytime;
if (store)
sam_set_account_init_flag(sampass, FLAG_SAM_LOGONTIME);
return NT_STATUS_UNSUCCESSFUL;
}
NTSTATUS sam_set_account_logoff_time(SAM_ACCOUNT_HANDLE *sampass, NTTIME mytime, BOOL store)
{
SAM_ASSERT(sampass);
sampass->private.logoff_time = mytime;
if (store)
sam_set_account_init_flag(sampass, FLAG_SAM_LOGOFFTIME);
return NT_STATUS_OK;
}
NTSTATUS sam_set_account_kickoff_time(SAM_ACCOUNT_HANDLE *sampass, NTTIME mytime, BOOL store)
{
SAM_ASSERT(sampass);
sampass->private.kickoff_time = mytime;
if (store)
sam_set_account_init_flag(sampass, FLAG_SAM_KICKOFFTIME);
return NT_STATUS_OK;
}
NTSTATUS sam_set_account_pass_can_change_time(SAM_ACCOUNT_HANDLE *sampass, NTTIME mytime, BOOL store)
{
SAM_ASSERT(sampass);
sampass->private.pass_can_change_time = mytime;
if (store)
sam_set_account_init_flag(sampass, FLAG_SAM_CANCHANGETIME);
return NT_STATUS_OK;
}
NTSTATUS sam_set_account_pass_must_change_time(SAM_ACCOUNT_HANDLE *sampass, NTTIME mytime, BOOL store)
{
SAM_ASSERT(sampass);
sampass->private.pass_must_change_time = mytime;
if (store)
sam_set_account_init_flag(sampass, FLAG_SAM_MUSTCHANGETIME);
return NT_STATUS_OK;
}
NTSTATUS sam_set_account_pass_last_set_time(SAM_ACCOUNT_HANDLE *sampass, NTTIME mytime)
{
SAM_ASSERT(sampass);
sampass->private.pass_last_set_time = mytime;
return NT_STATUS_OK;
}
NTSTATUS sam_set_account_hours_len(SAM_ACCOUNT_HANDLE *sampass, uint32 len)
{
SAM_ASSERT(sampass);
sampass->private.hours_len = len;
return NT_STATUS_OK;
}
NTSTATUS sam_set_account_logon_divs(SAM_ACCOUNT_HANDLE *sampass, uint16 hours)
{
SAM_ASSERT(sampass);
sampass->private.logon_divs = hours;
return NT_STATUS_OK;
}
/**
* Set flags showing what is initalised in the SAM_ACCOUNT_HANDLE
* @param sampass the SAM_ACCOUNT_HANDLE in question
* @param flag The *new* flag to be set. Old flags preserved
* this flag is only added.
**/
NTSTATUS sam_set_account_init_flag(SAM_ACCOUNT_HANDLE *sampass, uint32 flag)
{
SAM_ASSERT(sampass);
sampass->private.init_flag |= flag;
return NT_STATUS_OK;
}
NTSTATUS sam_set_account_sid(SAM_ACCOUNT_HANDLE *sampass, const DOM_SID *u_sid)
{
SAM_ASSERT(sampass && u_sid);
sid_copy(&sampass->private.account_sid, u_sid);
DEBUG(10, ("sam_set_account_sid: setting account sid %s\n",
sid_string_static(&sampass->private.account_sid)));
return NT_STATUS_OK;
}
NTSTATUS sam_set_account_sid_from_string(SAM_ACCOUNT_HANDLE *sampass, const char *u_sid)
{
DOM_SID new_sid;
SAM_ASSERT(sampass && u_sid);
DEBUG(10, ("sam_set_account_sid_from_string: setting account sid %s\n",
u_sid));
if (!string_to_sid(&new_sid, u_sid)) {
DEBUG(1, ("sam_set_account_sid_from_string: %s isn't a valid SID!\n", u_sid));
return NT_STATUS_UNSUCCESSFUL;
}
if (!NT_STATUS_IS_OK(sam_set_account_sid(sampass, &new_sid))) {
DEBUG(1, ("sam_set_account_sid_from_string: could not set sid %s on SAM_ACCOUNT_HANDLE!\n", u_sid));
return NT_STATUS_UNSUCCESSFUL;
}
return NT_STATUS_OK;
}
NTSTATUS sam_set_account_pgroup_sid(SAM_ACCOUNT_HANDLE *sampass, const DOM_SID *g_sid)
{
SAM_ASSERT(sampass && g_sid);
sid_copy(&sampass->private.group_sid, g_sid);
DEBUG(10, ("sam_set_group_sid: setting group sid %s\n",
sid_string_static(&sampass->private.group_sid)));
return NT_STATUS_OK;
}
NTSTATUS sam_set_account_pgroup_string(SAM_ACCOUNT_HANDLE *sampass, const char *g_sid)
{
DOM_SID new_sid;
SAM_ASSERT(sampass && g_sid);
DEBUG(10, ("sam_set_group_sid_from_string: setting group sid %s\n",
g_sid));
if (!string_to_sid(&new_sid, g_sid)) {
DEBUG(1, ("sam_set_group_sid_from_string: %s isn't a valid SID!\n", g_sid));
return NT_STATUS_UNSUCCESSFUL;
}
if (!NT_STATUS_IS_OK(sam_set_account_pgroup_sid(sampass, &new_sid))) {
DEBUG(1, ("sam_set_group_sid_from_string: could not set sid %s on SAM_ACCOUNT_HANDLE!\n", g_sid));
return NT_STATUS_UNSUCCESSFUL;
}
return NT_STATUS_OK;
}
/*********************************************************************
Set the domain name.
********************************************************************/
NTSTATUS sam_set_account_domain(SAM_ACCOUNT_HANDLE *sampass, SAM_DOMAIN_HANDLE *domain)
{
SAM_ASSERT(sampass);
sampass->private.domain = domain;
return NT_STATUS_OK;
}
/*********************************************************************
Set the account's NT name.
********************************************************************/
NTSTATUS sam_set_account_name(SAM_ACCOUNT_HANDLE *sampass, const char *account_name)
{
SAM_ASSERT(sampass);
DEBUG(10, ("sam_set_account_name: setting nt account_name %s, was %s\n", account_name, sampass->private.account_name));
sampass->private.account_name = talloc_strdup(sampass->mem_ctx, account_name);
return NT_STATUS_OK;
}
/*********************************************************************
Set the account's full name.
********************************************************************/
NTSTATUS sam_set_account_fullname(SAM_ACCOUNT_HANDLE *sampass, const char *full_name)
{
SAM_ASSERT(sampass);
DEBUG(10, ("sam_set_account_fullname: setting full name %s, was %s\n", full_name, sampass->private.full_name));
sampass->private.full_name = talloc_strdup(sampass->mem_ctx, full_name);
return NT_STATUS_OK;
}
/*********************************************************************
Set the account's logon script.
********************************************************************/
NTSTATUS sam_set_account_logon_script(SAM_ACCOUNT_HANDLE *sampass, const char *logon_script, BOOL store)
{
SAM_ASSERT(sampass);
DEBUG(10, ("sam_set_logon_script: from %s to %s\n", logon_script, sampass->private.logon_script));
sampass->private.logon_script = talloc_strdup(sampass->mem_ctx, logon_script);
sam_set_account_init_flag(sampass, FLAG_SAM_LOGONSCRIPT);
return NT_STATUS_OK;
}
/*********************************************************************
Set the account's profile path.
********************************************************************/
NTSTATUS sam_set_account_profile_path(SAM_ACCOUNT_HANDLE *sampass, const char *profile_path, BOOL store)
{
SAM_ASSERT(sampass);
DEBUG(10, ("sam_set_profile_path: setting profile path %s, was %s\n", profile_path, sampass->private.profile_path));
sampass->private.profile_path = talloc_strdup(sampass->mem_ctx, profile_path);
if (store) {
DEBUG(10, ("sam_set_profile_path: setting profile path sam flag!\n"));
sam_set_account_init_flag(sampass, FLAG_SAM_PROFILE);
}
return NT_STATUS_OK;
}
/*********************************************************************
Set the account's directory drive.
********************************************************************/
NTSTATUS sam_set_account_dir_drive(SAM_ACCOUNT_HANDLE *sampass, const char *dir_drive, BOOL store)
{
SAM_ASSERT(sampass);
DEBUG(10, ("sam_set_dir_drive: setting dir drive %s, was %s\n", dir_drive,
sampass->private.dir_drive));
sampass->private.dir_drive = talloc_strdup(sampass->mem_ctx, dir_drive);
if (store) {
DEBUG(10, ("sam_set_dir_drive: setting dir drive sam flag!\n"));
sam_set_account_init_flag(sampass, FLAG_SAM_DRIVE);
}
return NT_STATUS_OK;
}
/*********************************************************************
Set the account's home directory.
********************************************************************/
NTSTATUS sam_set_account_homedir(SAM_ACCOUNT_HANDLE *sampass, const char *home_dir, BOOL store)
{
SAM_ASSERT(sampass);
DEBUG(10, ("sam_set_homedir: setting home dir %s, was %s\n", home_dir,
sampass->private.home_dir));
sampass->private.home_dir = talloc_strdup(sampass->mem_ctx, home_dir);
if (store) {
DEBUG(10, ("sam_set_homedir: setting home dir sam flag!\n"));
sam_set_account_init_flag(sampass, FLAG_SAM_SMBHOME);
}
return NT_STATUS_OK;
}
/*********************************************************************
Set the account's unix home directory.
********************************************************************/
NTSTATUS sam_set_account_unix_homedir(SAM_ACCOUNT_HANDLE *sampass, const char *unix_home_dir)
{
SAM_ASSERT(sampass);
DEBUG(10, ("sam_set_unix_homedir: setting home dir %s, was %s\n", unix_home_dir,
sampass->private.unix_home_dir));
sampass->private.unix_home_dir = talloc_strdup(sampass->mem_ctx, unix_home_dir);
return NT_STATUS_OK;
}
/*********************************************************************
Set the account's account description.
********************************************************************/
NTSTATUS sam_set_account_acct_desc(SAM_ACCOUNT_HANDLE *sampass, const char *acct_desc)
{
SAM_ASSERT(sampass);
sampass->private.acct_desc = talloc_strdup(sampass->mem_ctx, acct_desc);
return NT_STATUS_OK;
}
/*********************************************************************
Set the account's workstation allowed list.
********************************************************************/
NTSTATUS sam_set_account_workstations(SAM_ACCOUNT_HANDLE *sampass, const char *workstations)
{
SAM_ASSERT(sampass);
DEBUG(10, ("sam_set_workstations: setting workstations %s, was %s\n", workstations,
sampass->private.workstations));
sampass->private.workstations = talloc_strdup(sampass->mem_ctx, workstations);
return NT_STATUS_OK;
}
/*********************************************************************
Set the account's 'unknown_str', whatever the heck this actually is...
********************************************************************/
NTSTATUS sam_set_account_unknown_str(SAM_ACCOUNT_HANDLE *sampass, const char *unknown_str)
{
SAM_ASSERT(sampass);
sampass->private.unknown_str = talloc_strdup(sampass->mem_ctx, unknown_str);
return NT_STATUS_OK;
}
/*********************************************************************
Set the account's dial string.
********************************************************************/
NTSTATUS sam_set_account_munged_dial(SAM_ACCOUNT_HANDLE *sampass, const char *munged_dial)
{
SAM_ASSERT(sampass);
sampass->private.munged_dial = talloc_strdup(sampass->mem_ctx, munged_dial);
return NT_STATUS_OK;
}
/*********************************************************************
Set the account's NT hash.
********************************************************************/
NTSTATUS sam_set_account_nt_pwd(SAM_ACCOUNT_HANDLE *sampass, const DATA_BLOB data)
{
SAM_ASSERT(sampass);
sampass->private.nt_pw = data;
return NT_STATUS_OK;
}
/*********************************************************************
Set the account's LM hash.
********************************************************************/
NTSTATUS sam_set_account_lm_pwd(SAM_ACCOUNT_HANDLE *sampass, const DATA_BLOB data)
{
SAM_ASSERT(sampass);
sampass->private.lm_pw = data;
return NT_STATUS_OK;
}
/*********************************************************************
Set the account's plaintext password only (base procedure, see helper
below)
********************************************************************/
NTSTATUS sam_set_account_plaintext_pwd(SAM_ACCOUNT_HANDLE *sampass, const char *plain_pwd)
{
SAM_ASSERT(sampass);
sampass->private.plaintext_pw = talloc_strdup(sampass->mem_ctx, plain_pwd);
return NT_STATUS_OK;
}
NTSTATUS sam_set_account_unknown_1(SAM_ACCOUNT_HANDLE *sampass, uint32 unkn)
{
SAM_ASSERT(sampass);
sampass->private.unknown_1 = unkn;
return NT_STATUS_OK;
}
NTSTATUS sam_set_account_unknown_2(SAM_ACCOUNT_HANDLE *sampass, uint32 unkn)
{
SAM_ASSERT(sampass);
sampass->private.unknown_2 = unkn;
return NT_STATUS_OK;
}
NTSTATUS sam_set_account_unknown_3(SAM_ACCOUNT_HANDLE *sampass, uint32 unkn)
{
SAM_ASSERT(sampass);
sampass->private.unknown_3 = unkn;
return NT_STATUS_OK;
}
NTSTATUS sam_set_account_hours(SAM_ACCOUNT_HANDLE *sampass, const uint8 *hours)
{
SAM_ASSERT(sampass);
if (!hours) {
memset ((char *)sampass->private.hours, 0, MAX_HOURS_LEN);
return NT_STATUS_OK;
}
memcpy(sampass->private.hours, hours, MAX_HOURS_LEN);
return NT_STATUS_OK;
}
/* Helpful interfaces to the above */
/*********************************************************************
Sets the last changed times and must change times for a normal
password change.
********************************************************************/
NTSTATUS sam_set_account_pass_changed_now(SAM_ACCOUNT_HANDLE *sampass)
{
uint32 expire;
NTTIME temptime;
SAM_ASSERT(sampass);
unix_to_nt_time(&temptime, time(NULL));
if (!NT_STATUS_IS_OK(sam_set_account_pass_last_set_time(sampass, temptime)))
return NT_STATUS_UNSUCCESSFUL;
if (!account_policy_get(AP_MAX_PASSWORD_AGE, &expire)
|| (expire==(uint32)-1)) {
get_nttime_max(&temptime);
if (!NT_STATUS_IS_OK(sam_set_account_pass_must_change_time(sampass, temptime, False)))
return NT_STATUS_UNSUCCESSFUL;
} else {
/* FIXME: Add expire to temptime */
if (!NT_STATUS_IS_OK(sam_get_account_pass_last_set_time(sampass,&temptime)) || !NT_STATUS_IS_OK(sam_set_account_pass_must_change_time(sampass, temptime,True)))
return NT_STATUS_UNSUCCESSFUL;
}
return NT_STATUS_OK;
}
/*********************************************************************
Set the account's PLAINTEXT password. Used as an interface to the above.
Also sets the last change time to NOW.
********************************************************************/
NTSTATUS sam_set_account_passwd(SAM_ACCOUNT_HANDLE *sampass, const char *plaintext)
{
DATA_BLOB data;
uchar new_lanman_p16[16];
uchar new_nt_p16[16];
SAM_ASSERT(sampass && plaintext);
nt_lm_owf_gen(plaintext, new_nt_p16, new_lanman_p16);
data = data_blob(new_nt_p16, 16);
if (!NT_STATUS_IS_OK(sam_set_account_nt_pwd(sampass, data)))
return NT_STATUS_UNSUCCESSFUL;
data = data_blob(new_lanman_p16, 16);
if (!NT_STATUS_IS_OK(sam_set_account_lm_pwd(sampass, data)))
return NT_STATUS_UNSUCCESSFUL;
if (!NT_STATUS_IS_OK(sam_set_account_plaintext_pwd(sampass, plaintext)))
return NT_STATUS_UNSUCCESSFUL;
if (!NT_STATUS_IS_OK(sam_set_account_pass_changed_now(sampass)))
return NT_STATUS_UNSUCCESSFUL;
return NT_STATUS_OK;
}

View File

@ -0,0 +1,263 @@
/*
Unix SMB/CIFS implementation.
SAM_DOMAIN access routines
Copyright (C) Andrew Bartlett 2002
Copyright (C) Stefan (metze) Metzmacher 2002
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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_SAM
NTSTATUS sam_get_domain_sid(SAM_DOMAIN_HANDLE *domain, const DOM_SID **sid)
{
SAM_ASSERT(domain &&sid);
*sid = &(domain->private.sid);
return NT_STATUS_OK;
}
NTSTATUS sam_get_domain_num_accounts(SAM_DOMAIN_HANDLE *domain, uint32 *num_accounts)
{
SAM_ASSERT(domain &&num_accounts);
*num_accounts = domain->private.num_accounts;
return NT_STATUS_OK;
}
NTSTATUS sam_get_domain_num_groups(SAM_DOMAIN_HANDLE *domain, uint32 *num_groups)
{
SAM_ASSERT(domain &&num_groups);
*num_groups = domain->private.num_groups;
return NT_STATUS_OK;
}
NTSTATUS sam_get_domain_num_aliases(SAM_DOMAIN_HANDLE *domain, uint32 *num_aliases)
{
SAM_ASSERT(domain &&num_aliases);
*num_aliases = domain->private.num_aliases;
return NT_STATUS_OK;
}
NTSTATUS sam_get_domain_name(SAM_DOMAIN_HANDLE *domain, const char **domain_name)
{
SAM_ASSERT(domain &&domain_name);
*domain_name = domain->private.name;
return NT_STATUS_OK;
}
NTSTATUS sam_get_domain_server(SAM_DOMAIN_HANDLE *domain, const char **server_name)
{
SAM_ASSERT(domain &&server_name);
*server_name = domain->private.servername;
return NT_STATUS_OK;
}
NTSTATUS sam_get_domain_max_pwdage(SAM_DOMAIN_HANDLE *domain, NTTIME *max_passwordage)
{
SAM_ASSERT(domain &&max_passwordage);
*max_passwordage = domain->private.max_passwordage;
return NT_STATUS_OK;
}
NTSTATUS sam_get_domain_min_pwdage(SAM_DOMAIN_HANDLE *domain, NTTIME *min_passwordage)
{
SAM_ASSERT(domain &&min_passwordage);
*min_passwordage = domain->private.min_passwordage;
return NT_STATUS_OK;
}
NTSTATUS sam_get_domain_lockout_duration(SAM_DOMAIN_HANDLE *domain, NTTIME *lockout_duration)
{
SAM_ASSERT(domain &&lockout_duration);
*lockout_duration = domain->private.lockout_duration;
return NT_STATUS_OK;
}
NTSTATUS sam_get_domain_reset_count(SAM_DOMAIN_HANDLE *domain, NTTIME *reset_lockout_count)
{
SAM_ASSERT(domain &&reset_lockout_count);
*reset_lockout_count = domain->private.reset_count;
return NT_STATUS_OK;
}
NTSTATUS sam_get_domain_min_pwdlength(SAM_DOMAIN_HANDLE *domain, uint16 *min_passwordlength)
{
SAM_ASSERT(domain &&min_passwordlength);
*min_passwordlength = domain->private.min_passwordlength;
return NT_STATUS_OK;
}
NTSTATUS sam_get_domain_pwd_history(SAM_DOMAIN_HANDLE *domain, uint16 *password_history)
{
SAM_ASSERT(domain &&password_history);
*password_history = domain->private.password_history;
return NT_STATUS_OK;
}
NTSTATUS sam_get_domain_lockout_count(SAM_DOMAIN_HANDLE *domain, uint16 *lockout_count)
{
SAM_ASSERT(domain &&lockout_count);
*lockout_count = domain->private.lockout_count;
return NT_STATUS_OK;
}
NTSTATUS sam_get_domain_force_logoff(SAM_DOMAIN_HANDLE *domain, BOOL *force_logoff)
{
SAM_ASSERT(domain &&force_logoff);
*force_logoff = domain->private.force_logoff;
return NT_STATUS_OK;
}
NTSTATUS sam_get_domain_login_pwdchange(SAM_DOMAIN_HANDLE *domain, BOOL *login_pwdchange)
{
SAM_ASSERT(domain && login_pwdchange);
*login_pwdchange = domain->private.login_pwdchange;
return NT_STATUS_OK;
}
/* Set */
NTSTATUS sam_set_domain_name(SAM_DOMAIN_HANDLE *domain, const char *domain_name)
{
SAM_ASSERT(domain);
domain->private.name = talloc_strdup(domain->mem_ctx, domain_name);
return NT_STATUS_OK;
}
NTSTATUS sam_set_domain_max_pwdage(SAM_DOMAIN_HANDLE *domain, NTTIME max_passwordage)
{
SAM_ASSERT(domain);
domain->private.max_passwordage = max_passwordage;
return NT_STATUS_OK;
}
NTSTATUS sam_set_domain_min_pwdage(SAM_DOMAIN_HANDLE *domain, NTTIME min_passwordage)
{
SAM_ASSERT(domain);
domain->private.min_passwordage = min_passwordage;
return NT_STATUS_OK;
}
NTSTATUS sam_set_domain_lockout_duration(SAM_DOMAIN_HANDLE *domain, NTTIME lockout_duration)
{
SAM_ASSERT(domain);
domain->private.lockout_duration = lockout_duration;
return NT_STATUS_OK;
}
NTSTATUS sam_set_domain_reset_count(SAM_DOMAIN_HANDLE *domain, NTTIME reset_lockout_count)
{
SAM_ASSERT(domain);
domain->private.reset_count = reset_lockout_count;
return NT_STATUS_OK;
}
NTSTATUS sam_set_domain_min_pwdlength(SAM_DOMAIN_HANDLE *domain, uint16 min_passwordlength)
{
SAM_ASSERT(domain);
domain->private.min_passwordlength = min_passwordlength;
return NT_STATUS_OK;
}
NTSTATUS sam_set_domain_pwd_history(SAM_DOMAIN_HANDLE *domain, uint16 password_history)
{
SAM_ASSERT(domain);
domain->private.password_history = password_history;
return NT_STATUS_OK;
}
NTSTATUS sam_set_domain_lockout_count(SAM_DOMAIN_HANDLE *domain, uint16 lockout_count)
{
SAM_ASSERT(domain);
domain->private.lockout_count = lockout_count;
return NT_STATUS_OK;
}
NTSTATUS sam_set_domain_force_logoff(SAM_DOMAIN_HANDLE *domain, BOOL force_logoff)
{
SAM_ASSERT(domain);
domain->private.force_logoff = force_logoff;
return NT_STATUS_OK;
}
NTSTATUS sam_set_domain_login_pwdchange(SAM_DOMAIN_HANDLE *domain, BOOL login_pwdchange)
{
SAM_ASSERT(domain);
domain->private.login_pwdchange = login_pwdchange;
return NT_STATUS_OK;
}
NTSTATUS sam_set_domain_server(SAM_DOMAIN_HANDLE *domain, const char *server_name)
{
SAM_ASSERT(domain);
domain->private.servername = talloc_strdup(domain->mem_ctx, server_name);
return NT_STATUS_OK;
}

106
source3/sam/get_set_group.c Normal file
View File

@ -0,0 +1,106 @@
/*
Unix SMB/CIFS implementation.
SAM_USER_HANDLE access routines
Copyright (C) Andrew Bartlett 2002
Copyright (C) Stefan (metze) Metzmacher 2002
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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_SAM
/* sam group get functions */
NTSTATUS sam_get_group_sid(const SAM_GROUP_HANDLE *group, const DOM_SID **sid)
{
SAM_ASSERT(group && sid);
*sid = &(group->private.sid);
return NT_STATUS_OK;
}
NTSTATUS sam_get_group_ctrl(const SAM_GROUP_HANDLE *group, uint32 *group_ctrl)
{
SAM_ASSERT(group && group_ctrl);
*group_ctrl = group->private.group_ctrl;
return NT_STATUS_OK;
}
NTSTATUS sam_get_group_name(const SAM_GROUP_HANDLE *group, const char **group_name)
{
SAM_ASSERT(group);
*group_name = group->private.group_name;
return NT_STATUS_OK;
}
NTSTATUS sam_get_group_comment(const SAM_GROUP_HANDLE *group, const char **group_desc)
{
SAM_ASSERT(group);
*group_desc = group->private.group_desc;
return NT_STATUS_OK;
}
/* sam group set functions */
NTSTATUS sam_set_group_sid(SAM_GROUP_HANDLE *group, const DOM_SID *sid)
{
SAM_ASSERT(group);
if (!sid)
ZERO_STRUCT(group->private.sid);
else
sid_copy(&(group->private.sid), sid);
return NT_STATUS_OK;
}
NTSTATUS sam_set_group_group_ctrl(SAM_GROUP_HANDLE *group, uint32 group_ctrl)
{
SAM_ASSERT(group);
group->private.group_ctrl = group_ctrl;
return NT_STATUS_OK;
}
NTSTATUS sam_set_group_name(SAM_GROUP_HANDLE *group, const char *group_name)
{
SAM_ASSERT(group);
group->private.group_name = talloc_strdup(group->mem_ctx, group_name);
return NT_STATUS_OK;
}
NTSTATUS sam_set_group_description(SAM_GROUP_HANDLE *group, const char *group_desc)
{
SAM_ASSERT(group);
group->private.group_desc = talloc_strdup(group->mem_ctx, group_desc);
return NT_STATUS_OK;
}

193
source3/sam/group.c Normal file
View File

@ -0,0 +1,193 @@
/*
Unix SMB/CIFS implementation.
SAM_GROUP_HANDLE /SAM_GROUP_ENUM helpers
Copyright (C) Stefan (metze) Metzmacher 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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_SAM
/************************************************************
Fill the SAM_GROUP_HANDLE with default values.
***********************************************************/
static void sam_fill_default_group(SAM_GROUP_HANDLE *group)
{
ZERO_STRUCT(group->private); /* Don't touch the talloc context */
}
static void destroy_sam_group_handle_talloc(SAM_GROUP_HANDLE **group)
{
if (*group) {
talloc_destroy((*group)->mem_ctx);
*group = NULL;
}
}
/**********************************************************************
Alloc memory and initialises a SAM_GROUP_HANDLE on supplied mem_ctx.
***********************************************************************/
NTSTATUS sam_init_group_talloc(TALLOC_CTX *mem_ctx, SAM_GROUP_HANDLE **group)
{
SMB_ASSERT(*group != NULL);
if (!mem_ctx) {
DEBUG(0,("sam_init_group_talloc: mem_ctx was NULL!\n"));
return NT_STATUS_UNSUCCESSFUL;
}
*group=(SAM_GROUP_HANDLE *)talloc(mem_ctx, sizeof(SAM_GROUP_HANDLE));
if (*group==NULL) {
DEBUG(0,("sam_init_group_talloc: error while allocating memory\n"));
return NT_STATUS_NO_MEMORY;
}
(*group)->mem_ctx = mem_ctx;
(*group)->free_fn = NULL;
sam_fill_default_group(*group);
return NT_STATUS_OK;
}
/*************************************************************
Alloc memory and initialises a struct SAM_GROUP_HANDLE.
************************************************************/
NTSTATUS sam_init_group(SAM_GROUP_HANDLE **group)
{
TALLOC_CTX *mem_ctx;
NTSTATUS nt_status;
mem_ctx = talloc_init_named("sam internal SAM_GROUP_HANDLE allocation");
if (!mem_ctx) {
DEBUG(0,("sam_init_group: error while doing talloc_init()\n"));
return NT_STATUS_NO_MEMORY;
}
if (!NT_STATUS_IS_OK(nt_status = sam_init_group_talloc(mem_ctx, group))) {
talloc_destroy(mem_ctx);
return nt_status;
}
(*group)->free_fn = destroy_sam_group_handle_talloc;
return NT_STATUS_OK;
}
/************************************************************
Reset the SAM_GROUP_HANDLE.
***********************************************************/
NTSTATUS sam_reset_group(SAM_GROUP_HANDLE *group)
{
SMB_ASSERT(group != NULL);
sam_fill_default_group(group);
return NT_STATUS_OK;
}
/************************************************************
Free the SAM_GROUP_HANDLE and the member pointers.
***********************************************************/
NTSTATUS sam_free_group(SAM_ACCOUNT_HANDLE **group)
{
SMB_ASSERT(*group != NULL);
if ((*group)->free_fn) {
(*group)->free_fn(group);
}
return NT_STATUS_OK;
}
/**********************************************************
Encode the group control bits into a string.
length = length of string to encode into (including terminating
null). length *MUST BE MORE THAN 2* !
**********************************************************/
char *sam_encode_acct_ctrl(uint16 group_ctrl, size_t length)
{
static fstring group_str;
size_t i = 0;
group_str[i++] = '[';
if (group_ctrl & GCB_LOCAL_GROUP ) group_str[i++] = 'L';
if (group_ctrl & GCB_GLOBAL_GROUP ) group_str[i++] = 'G';
for ( ; i < length - 2 ; i++ )
group_str[i] = ' ';
i = length - 2;
group_str[i++] = ']';
group_str[i++] = '\0';
return group_str;
}
/**********************************************************
Decode the group control bits from a string.
**********************************************************/
uint16 sam_decode_group_ctrl(const char *p)
{
uint16 group_ctrl = 0;
BOOL finished = False;
/*
* Check if the account type bits have been encoded after the
* NT password (in the form [NDHTUWSLXI]).
*/
if (*p != '[')
return 0;
for (p++; *p && !finished; p++) {
switch (*p) {
case 'L': { group_ctrl |= GCB_LOCAL_GROUP; break; /* 'L'ocal Aliases Group. */ }
case 'G': { group_ctrl |= GCB_GLOBAL_GROUP; break; /* 'G'lobal Domain Group. */ }
case ' ': { break; }
case ':':
case '\n':
case '\0':
case ']':
default: { finished = True; }
}
}
return group_ctrl;
}

1238
source3/sam/interface.c Normal file

File diff suppressed because it is too large Load Diff

79
source3/sam/sam_plugin.c Normal file
View File

@ -0,0 +1,79 @@
/*
Unix SMB/CIFS implementation.
Loadable san module interface.
Copyright (C) Jelmer Vernooij 2002
Copyright (C) Andrew Bartlett 2002
Copyright (C) Stefan (metze) Metzmacher 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"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_SAM
NTSTATUS sam_init_plugin(SAM_METHODS *sam_methods, const char *module_params)
{
void *dl_handle;
char *plugin_params, *plugin_name, *p;
sam_init_function plugin_init;
int (*plugin_version)(void);
if (module_params == NULL) {
DEBUG(0, ("The plugin module needs an argument!\n"));
return NT_STATUS_UNSUCCESSFUL;
}
plugin_name = smb_xstrdup(module_params);
p = strchr(plugin_name, ':');
if (p) {
*p = 0;
plugin_params = p+1;
trim_string(plugin_params, " ", " ");
} else plugin_params = NULL;
trim_string(plugin_name, " ", " ");
DEBUG(5, ("Trying to load sam plugin %s\n", plugin_name));
dl_handle = sys_dlopen(plugin_name, RTLD_NOW);
if (!dl_handle) {
DEBUG(0, ("Failed to load sam plugin %s using sys_dlopen (%s)\n", plugin_name, sys_dlerror()));
return NT_STATUS_UNSUCCESSFUL;
}
plugin_version = sys_dlsym(dl_handle, "sam_version");
if (!plugin_version) {
sys_dlclose(dl_handle);
DEBUG(0, ("Failed to find function 'sam_version' using sys_dlsym in sam plugin %s (%s)\n", plugin_name, sys_dlerror()));
return NT_STATUS_UNSUCCESSFUL;
}
if (plugin_version()!=SAM_INTERFACE_VERSION) {
sys_dlclose(dl_handle);
DEBUG(0, ("Wrong SAM_INTERFACE_VERSION! sam plugin has version %d and version %d is needed! Please update!\n",
plugin_version(),SAM_INTERFACE_VERSION));
return NT_STATUS_UNSUCCESSFUL;
}
plugin_init = sys_dlsym(dl_handle, "sam_init");
if (!plugin_init) {
sys_dlclose(dl_handle);
DEBUG(0, ("Failed to find function 'sam_init' using sys_dlsym in sam plugin %s (%s)\n", plugin_name, sys_dlerror()));
return NT_STATUS_UNSUCCESSFUL;
}
DEBUG(5, ("Starting sam plugin %s with parameters %s for domain %s\n", plugin_name, plugin_params, sam_methods->domain_name));
return plugin_init(sam_methods, plugin_params);
}

View File

@ -0,0 +1,43 @@
#!/usr/bin/perl -w
#reads in the list of parameters from the source
#compares this list to the list of parms documented in the docbook source
#prints out the names of the parameters that are in need of documentation
# (C) 2002 Bradley W. Langhorst" <brad@langhorst.com>
my $doc_file = "./docs/docbook/manpages/smb.conf.5.sgml";
my $source_file = "./source/param/loadparm.c";
my $ln;
my %params;
open(SOURCE, "<$source_file") ||
die "Unable to open $source_file for input: $!\n";
open(DOC, "<$doc_file") ||
die "Unable to open $doc_file for input: $!\n";
while ($ln= <SOURCE>) {
last if $ln =~ m/^static\ struct\ parm_struct\ parm_table.*/;
} #burn through the preceding lines
while ($ln = <SOURCE>) {
last if $ln =~ m/^\s*\}\;\s*$/;
#pull in the param names only
next if $ln =~ m/.*P_SEPARATOR.*/;
$ln =~ m/.*\"(.*)\".*/;
$params{lc($1)}='not_found'; #not case sensitive
}
close SOURCE;
#now read in the params list from the docs
@doclines = <DOC>;
foreach $ln (grep (/\<anchor\ id\=/, @doclines)) {
$ln =~ m/^.*\<anchor\ id\=\".*\"\>\s*(?:\<.*?\>)*\s*(.*?)(?:\s*\(?[S,G]?\)?\s*(\<\/term\>)?){1}\s*$/;
#print "got: $1 from: $ln";
if (exists $params{lc($1)}) {
$params{$1} = 'found';
}
}
foreach (keys %params) {
print "$_\n" if $params{$_} eq 'not_found' and $_ cmp "valid" and $_ eq "";
}

301
source3/torture/cmd_sam.c Normal file
View File

@ -0,0 +1,301 @@
/*
Unix SMB/CIFS implementation.
SAM module functions
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"
#include "samtest.h"
static NTSTATUS cmd_load_module(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
char *plugin_arg[2];
NTSTATUS status;
if (argc != 2 && argc != 3) {
printf("Usage: load <module path> [domain-sid]\n");
return NT_STATUS_OK;
}
if (argc == 3)
asprintf(&plugin_arg[0], "%s|plugin:%s", argv[2], argv[1]);
else
asprintf(&plugin_arg[0], "plugin:%s", argv[1]);
plugin_arg[1] = NULL;
if(!NT_STATUS_IS_OK(status = make_sam_context_list(&st->context, plugin_arg))) {
free(plugin_arg[0]);
return status;
}
free(plugin_arg[0]);
printf("load: ok\n");
return NT_STATUS_OK;
}
static NTSTATUS cmd_get_sec_desc(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_set_sec_desc(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_lookup_sid(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
char *name;
uint32 type;
NTSTATUS status;
DOM_SID sid;
if (argc != 2) {
printf("Usage: lookup_sid <sid>\n");
return NT_STATUS_INVALID_PARAMETER;
}
if (!string_to_sid(&sid, argv[1])){
printf("Unparseable SID specified!\n");
return NT_STATUS_INVALID_PARAMETER;
}
if (!NT_STATUS_IS_OK(status = context_sam_lookup_sid(st->context, st->token, &sid, &name, &type))) {
printf("context_sam_lookup_sid failed!\n");
return status;
}
printf("Name: %s\n", name);
printf("Type: %d\n", type); /* FIXME: What kind of an integer is type ? */
return NT_STATUS_OK;
}
static NTSTATUS cmd_lookup_name(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
DOM_SID *sid;
uint32 type;
NTSTATUS status;
if (argc != 3) {
printf("Usage: lookup_name <domain> <name>\n");
return NT_STATUS_INVALID_PARAMETER;
}
if (!NT_STATUS_IS_OK(status = context_sam_lookup_name(st->context, st->token, argv[1], argv[2], &sid, &type))) {
printf("context_sam_lookup_name failed!\n");
return status;
}
printf("SID: %s\n", sid_string_static(sid));
printf("Type: %d\n", type);
return NT_STATUS_OK;
}
static NTSTATUS cmd_lookup_account(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_lookup_group(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_lookup_domain(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
DOM_SID *sid;
NTSTATUS status;
if (argc != 2) {
printf("Usage: lookup_domain <domain>\n");
return NT_STATUS_INVALID_PARAMETER;
}
if (!NT_STATUS_IS_OK(status = context_sam_lookup_domain(st->context, st->token, argv[1], &sid))) {
printf("context_sam_lookup_name failed!\n");
return status;
}
printf("SID: %s\n", sid_string_static(sid));
return NT_STATUS_OK;
}
static NTSTATUS cmd_enum_domains(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
int32 domain_count, i;
DOM_SID *domain_sids;
char **domain_names;
NTSTATUS status;
if (!NT_STATUS_IS_OK(status = context_sam_enum_domains(st->context, st->token, &domain_count, &domain_sids, &domain_names))) {
printf("context_sam_enum_domains failed!\n");
return status;
}
for (i = 0; i < domain_count; i++) {
printf("%s %s\n", domain_names[i], sid_string_static(&domain_sids[i]));
}
SAFE_FREE(domain_sids);
SAFE_FREE(domain_names);
return NT_STATUS_OK;
}
static NTSTATUS cmd_update_domain(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_show_domain(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_create_account(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_update_account(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_delete_account(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_enum_accounts(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_lookup_account_sid(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_lookup_account_name(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_create_group(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_update_group(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_delete_group(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_enum_groups(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_lookup_group_sid(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_lookup_group_name(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_group_add_member(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_group_del_member(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_group_enum(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
static NTSTATUS cmd_get_sid_groups(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
return NT_STATUS_NOT_IMPLEMENTED;
}
struct cmd_set sam_general_commands[] = {
{ "General SAM Commands" },
{ "load", cmd_load_module, "Load a module", "load <module.so> [domain-sid]" },
{ "get_sec_desc", cmd_get_sec_desc, "Get security descriptor info", "get_sec_desc <access-token> <sid>" },
{ "set_sec_desc", cmd_set_sec_desc, "Set security descriptor info", "set_sec_desc <access-token> <sid>" },
{ "lookup_sid", cmd_lookup_sid, "Lookup type of specified SID", "lookup_sid <sid>" },
{ "lookup_name", cmd_lookup_name, "Lookup type of specified name", "lookup_name <sid>" },
{ NULL }
};
struct cmd_set sam_domain_commands[] = {
{ "Domain Commands" },
{ "update_domain", cmd_update_domain, "Update domain information", "update_domain [domain-options] domain-name | domain-sid" },
{ "show_domain", cmd_show_domain, "Show domain information", "show_domain domain-sid | domain-name" },
{ "enum_domains", cmd_enum_domains, "Enumerate all domains", "enum_domains <token> <acct-ctrl>" },
{ "lookup_domain", cmd_lookup_domain, "Lookup a domain by name", "lookup_domain domain-name" },
{ NULL }
};
struct cmd_set sam_account_commands[] = {
{ "Account Commands" },
{ "create_account", cmd_create_account, "Create a new account with specified properties", "create_account [account-options]" },
{ "update_account", cmd_update_account, "Update an existing account", "update_account [account-options] account-sid | account-name" },
{ "delete_account", cmd_delete_account, "Delete an account", "delete_account account-sid | account-name" },
{ "enum_accounts", cmd_enum_accounts, "Enumerate all accounts", "enum_accounts <token> <acct-ctrl>" },
{ "lookup_account", cmd_lookup_account, "Lookup an account by either sid or name", "lookup_account account-sid | account-name" },
{ "lookup_account_sid", cmd_lookup_account_sid, "Lookup an account by sid", "lookup_account_sid account-sid" },
{ "lookup_account_name", cmd_lookup_account_name, "Lookup an account by name", "lookup_account_name account-name" },
{ NULL }
};
struct cmd_set sam_group_commands[] = {
{ "Group Commands" },
{ "create_group", cmd_create_group, "Create a new group", "create_group [group-opts]" },
{ "update_group", cmd_update_group, "Update an existing group", "update_group [group-opts] group-name | group-sid" },
{ "delete_group", cmd_delete_group, "Delete an existing group", "delete_group group-name | group-sid" },
{ "enum_groups", cmd_enum_groups, "Enumerate all groups", "enum_groups <token> <group-ctrl>" },
{ "lookup_group", cmd_lookup_group, "Lookup a group by SID or name", "lookup_group group-sid | group-name" },
{ "lookup_group_sid", cmd_lookup_group_sid, "Lookup a group by SID", "lookup_group_sid <sid>" },
{ "lookup_group_name", cmd_lookup_group_name, "Lookup a group by name", "lookup_group_name <name>" },
{ "group_add_member", cmd_group_add_member, "Add group member to group", "group_add_member <group-name | group-sid> <member-name | member-sid>" },
{ "group_del_member", cmd_group_del_member, "Delete group member from group", "group_del_member <group-name | group-sid> <member-name | member-sid>" },
{ "group_enum", cmd_group_enum, "Enumerate all members of specified group", "group_enum group-sid | group-name" },
{ "get_sid_groups", cmd_get_sid_groups, "Get a list of groups specified sid is a member of", "group_enum <group-sid | group-name>" },
{ NULL }
};

1045
source3/torture/cmd_vfs.c Normal file

File diff suppressed because it is too large Load Diff

449
source3/torture/samtest.c Normal file
View File

@ -0,0 +1,449 @@
/*
Unix SMB/CIFS implementation.
SAM module tester
Copyright (C) 2002 Jelmer Vernooij
Parts of the code stolen from vfstest by Simo Sorce and Eric Lorimer
Parts of the code stolen from rpcclient by Tim Potter
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 "samtest.h"
struct func_entry {
char *name;
int (*fn)(struct connection_struct *conn, const char *path);
};
/* List to hold groups of commands */
static struct cmd_list {
struct cmd_list *prev, *next;
struct cmd_set *cmd_set;
} *cmd_list;
static char* next_command (char** cmdstr)
{
static pstring command;
char *p;
if (!cmdstr || !(*cmdstr))
return NULL;
p = strchr_m(*cmdstr, ';');
if (p)
*p = '\0';
pstrcpy(command, *cmdstr);
*cmdstr = p;
return command;
}
/* Load specified configuration file */
static NTSTATUS cmd_conf(struct samtest_state *sam, TALLOC_CTX *mem_ctx,
int argc, char **argv)
{
if (argc != 2) {
printf("Usage: %s <smb.conf>\n", argv[0]);
return NT_STATUS_OK;
}
if (!lp_load(argv[1], False, True, False)) {
printf("Error loading \"%s\"\n", argv[1]);
return NT_STATUS_OK;
}
printf("\"%s\" successfully loaded\n", argv[1]);
return NT_STATUS_OK;
}
/* Display help on commands */
static NTSTATUS cmd_help(struct samtest_state *st, TALLOC_CTX *mem_ctx,
int argc, char **argv)
{
struct cmd_list *tmp;
struct cmd_set *tmp_set;
/* Usage */
if (argc > 2) {
printf("Usage: %s [command]\n", argv[0]);
return NT_STATUS_OK;
}
/* Help on one command */
if (argc == 2) {
for (tmp = cmd_list; tmp; tmp = tmp->next) {
tmp_set = tmp->cmd_set;
while(tmp_set->name) {
if (strequal(argv[1], tmp_set->name)) {
if (tmp_set->usage &&
tmp_set->usage[0])
printf("%s\n", tmp_set->usage);
else
printf("No help for %s\n", tmp_set->name);
return NT_STATUS_OK;
}
tmp_set++;
}
}
printf("No such command: %s\n", argv[1]);
return NT_STATUS_OK;
}
/* List all commands */
for (tmp = cmd_list; tmp; tmp = tmp->next) {
tmp_set = tmp->cmd_set;
while(tmp_set->name) {
printf("%20s\t%s\n", tmp_set->name,
tmp_set->description ? tmp_set->description:
"");
tmp_set++;
}
}
return NT_STATUS_OK;
}
/* Change the debug level */
static NTSTATUS cmd_debuglevel(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
if (argc > 2) {
printf("Usage: %s [debuglevel]\n", argv[0]);
return NT_STATUS_OK;
}
if (argc == 2) {
DEBUGLEVEL = atoi(argv[1]);
}
printf("debuglevel is %d\n", DEBUGLEVEL);
return NT_STATUS_OK;
}
static NTSTATUS cmd_quit(struct samtest_state *st, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
/* Cleanup */
talloc_destroy(mem_ctx);
exit(0);
return NT_STATUS_OK; /* NOTREACHED */
}
static struct cmd_set samtest_commands[] = {
{ "GENERAL OPTIONS" },
{ "help", cmd_help, "Get help on commands", "" },
{ "?", cmd_help, "Get help on commands", "" },
{ "conf", cmd_conf, "Load smb configuration file", "conf <smb.conf>" },
{ "debuglevel", cmd_debuglevel, "Set debug level", "" },
{ "exit", cmd_quit, "Exit program", "" },
{ "quit", cmd_quit, "Exit program", "" },
{ NULL }
};
static struct cmd_set separator_command[] = {
{ "---------------", NULL, "----------------------" },
{ NULL }
};
/*extern struct cmd_set sam_commands[];*/
extern struct cmd_set sam_general_commands[];
extern struct cmd_set sam_domain_commands[];
extern struct cmd_set sam_account_commands[];
extern struct cmd_set sam_group_commands[];
static struct cmd_set *samtest_command_list[] = {
samtest_commands,
sam_general_commands,
sam_domain_commands,
sam_account_commands,
sam_group_commands,
NULL
};
static void add_command_set(struct cmd_set *cmd_set)
{
struct cmd_list *entry;
if (!(entry = (struct cmd_list *)malloc(sizeof(struct cmd_list)))) {
DEBUG(0, ("out of memory\n"));
return;
}
ZERO_STRUCTP(entry);
entry->cmd_set = cmd_set;
DLIST_ADD(cmd_list, entry);
}
static NTSTATUS do_cmd(struct samtest_state *st, struct cmd_set *cmd_entry, char *cmd)
{
char *p = cmd, **argv = NULL;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
TALLOC_CTX *mem_ctx = NULL;
pstring buf;
int argc = 0, i;
/* Count number of arguments first time through the loop then
allocate memory and strdup them. */
again:
while(next_token(&p, buf, " ", sizeof(buf))) {
if (argv) {
argv[argc] = strdup(buf);
}
argc++;
}
if (!argv) {
/* Create argument list */
argv = (char **)malloc(sizeof(char *) * argc);
memset(argv, 0, sizeof(char *) * argc);
if (!argv) {
fprintf(stderr, "out of memory\n");
result = NT_STATUS_NO_MEMORY;
goto done;
}
p = cmd;
argc = 0;
goto again;
}
/* Call the function */
if (cmd_entry->fn) {
if (mem_ctx == NULL) {
/* Create mem_ctx */
if (!(mem_ctx = talloc_init())) {
DEBUG(0, ("talloc_init() failed\n"));
goto done;
}
}
/* Run command */
result = cmd_entry->fn(st, mem_ctx, argc, argv);
} else {
fprintf (stderr, "Invalid command\n");
goto done;
}
done:
/* Cleanup */
if (argv) {
for (i = 0; i < argc; i++)
SAFE_FREE(argv[i]);
SAFE_FREE(argv);
}
return result;
}
/* Process a command entered at the prompt or as part of -c */
static NTSTATUS process_cmd(struct samtest_state *st, char *cmd)
{
struct cmd_list *temp_list;
BOOL found = False;
pstring buf;
char *p = cmd;
NTSTATUS result = NT_STATUS_OK;
int len = 0;
if (cmd[strlen(cmd) - 1] == '\n')
cmd[strlen(cmd) - 1] = '\0';
if (!next_token(&p, buf, " ", sizeof(buf))) {
return NT_STATUS_OK;
}
/* strip the trainly \n if it exsists */
len = strlen(buf);
if (buf[len-1] == '\n')
buf[len-1] = '\0';
/* Search for matching commands */
for (temp_list = cmd_list; temp_list; temp_list = temp_list->next) {
struct cmd_set *temp_set = temp_list->cmd_set;
while(temp_set->name) {
if (strequal(buf, temp_set->name)) {
found = True;
result = do_cmd(st, temp_set, cmd);
goto done;
}
temp_set++;
}
}
done:
if (!found && buf[0]) {
printf("command not found: %s\n", buf);
return NT_STATUS_OK;
}
if (!NT_STATUS_IS_OK(result)) {
printf("result was %s\n", nt_errstr(result));
}
return result;
}
void exit_server(char *reason)
{
DEBUG(3,("Server exit (%s)\n", (reason ? reason : "")));
exit(0);
}
static int server_fd = -1;
int last_message = -1;
int smbd_server_fd(void)
{
return server_fd;
}
BOOL reload_services(BOOL test)
{
return True;
}
/* Main function */
int main(int argc, char *argv[])
{
BOOL interactive = True;
int opt;
static char *cmdstr = "";
static char *opt_logfile=NULL;
static char *config_file = dyn_CONFIGFILE;
pstring logfile;
struct cmd_set **cmd_set;
struct samtest_state st;
/* make sure the vars that get altered (4th field) are in
a fixed location or certain compilers complain */
poptContext pc;
struct poptOption long_options[] = {
POPT_AUTOHELP
{ NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_debug },
{"command", 'e', POPT_ARG_STRING, &cmdstr, 'e', "Execute semicolon seperated cmds"},
{"logfile", 'l', POPT_ARG_STRING, &opt_logfile, 'l', "Logfile to use instead of stdout"},
{"configfile", 'c', POPT_ARG_STRING, &config_file, 0,"use different configuration file",NULL},
{ 0, 0, 0, 0}
};
ZERO_STRUCT(st);
setlinebuf(stdout);
DEBUGLEVEL = 1;
pc = poptGetContext("samtest", argc, (const char **) argv,
long_options, 0);
while((opt = poptGetNextOpt(pc)) != -1) {
switch (opt) {
case 'l':
slprintf(logfile, sizeof(logfile) - 1, "%s.client",
opt_logfile);
lp_set_logfile(logfile);
interactive = False;
break;
}
}
if (!lp_load(config_file,True,False,False)) {
fprintf(stderr, "Can't load %s - run testparm to debug it\n", config_file);
exit(1);
}
poptFreeContext(pc);
/* the following functions are part of the Samba debugging
facilities. See lib/debug.c */
setup_logging("samtest", interactive);
if (!interactive)
reopen_logs();
/* Load command lists */
cmd_set = samtest_command_list;
while(*cmd_set) {
add_command_set(*cmd_set);
add_command_set(separator_command);
cmd_set++;
}
/* Do anything specified with -c */
if (cmdstr[0]) {
char *cmd;
char *p = cmdstr;
while((cmd=next_command(&p)) != NULL) {
process_cmd(&st, cmd);
}
return 0;
}
/* Loop around accepting commands */
while(1) {
pstring prompt;
char *line;
slprintf(prompt, sizeof(prompt) - 1, "samtest $> ");
line = smb_readline(prompt, NULL, NULL);
if (line == NULL)
break;
if (line[0] != '\n')
process_cmd(&st, line);
}
return 0;
}

38
source3/torture/samtest.h Normal file
View File

@ -0,0 +1,38 @@
/*
Unix SMB/CIFS implementation.
SAM module tester
Copyright (C) Jelmer Vernooij 2002
Most of this code was ripped off of rpcclient.
Copyright (C) Tim Potter 2000-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.
*/
struct samtest_state {
SAM_CONTEXT *context;
NT_USER_TOKEN *token;
};
struct cmd_set {
char *name;
NTSTATUS (*fn)(struct samtest_state *sam, TALLOC_CTX *mem_ctx, int argc,
char **argv);
char *description;
char *usage;
};

593
source3/torture/vfstest.c Normal file
View File

@ -0,0 +1,593 @@
/*
Unix SMB/CIFS implementation.
VFS module tester
Copyright (C) Simo Sorce 2002
Copyright (C) Eric Lorimer 2002
Copyright (C) Jelmer Vernooij 2002
Most of this code was ripped off of rpcclient.
Copyright (C) Tim Potter 2000-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 "vfstest.h"
/* List to hold groups of commands */
static struct cmd_list {
struct cmd_list *prev, *next;
struct cmd_set *cmd_set;
} *cmd_list;
extern pstring user_socket_options;
/****************************************************************************
handle completion of commands for readline
****************************************************************************/
static char **completion_fn(char *text, int start, int end)
{
#define MAX_COMPLETIONS 100
char **matches;
int i, count=0;
struct cmd_list *commands = cmd_list;
if (start)
return NULL;
/* make sure we have a list of valid commands */
if (!commands)
return NULL;
matches = (char **)malloc(sizeof(matches[0])*MAX_COMPLETIONS);
if (!matches) return NULL;
matches[count++] = strdup(text);
if (!matches[0]) return NULL;
while (commands && count < MAX_COMPLETIONS-1)
{
if (!commands->cmd_set)
break;
for (i=0; commands->cmd_set[i].name; i++)
{
if ((strncmp(text, commands->cmd_set[i].name, strlen(text)) == 0) &&
commands->cmd_set[i].fn)
{
matches[count] = strdup(commands->cmd_set[i].name);
if (!matches[count])
return NULL;
count++;
}
}
commands = commands->next;
}
if (count == 2) {
SAFE_FREE(matches[0]);
matches[0] = strdup(matches[1]);
}
matches[count] = NULL;
return matches;
}
static char* next_command(char** cmdstr)
{
static pstring command;
char *p;
if (!cmdstr || !(*cmdstr))
return NULL;
p = strchr_m(*cmdstr, ';');
if (p)
*p = '\0';
pstrcpy(command, *cmdstr);
*cmdstr = p;
return command;
}
/* Load specified configuration file */
static NTSTATUS cmd_conf(struct vfs_state *vfs, TALLOC_CTX *mem_ctx,
int argc, char **argv)
{
if (argc != 2) {
printf("Usage: %s <smb.conf>\n", argv[0]);
return NT_STATUS_OK;
}
if (!lp_load(argv[1], False, True, False)) {
printf("Error loading \"%s\"\n", argv[1]);
return NT_STATUS_OK;
}
printf("\"%s\" successfully loaded\n", argv[1]);
return NT_STATUS_OK;
}
/* Display help on commands */
static NTSTATUS cmd_help(struct vfs_state *vfs, TALLOC_CTX *mem_ctx,
int argc, char **argv)
{
struct cmd_list *tmp;
struct cmd_set *tmp_set;
/* Usage */
if (argc > 2) {
printf("Usage: %s [command]\n", argv[0]);
return NT_STATUS_OK;
}
/* Help on one command */
if (argc == 2) {
for (tmp = cmd_list; tmp; tmp = tmp->next) {
tmp_set = tmp->cmd_set;
while(tmp_set->name) {
if (strequal(argv[1], tmp_set->name)) {
if (tmp_set->usage &&
tmp_set->usage[0])
printf("%s\n", tmp_set->usage);
else
printf("No help for %s\n", tmp_set->name);
return NT_STATUS_OK;
}
tmp_set++;
}
}
printf("No such command: %s\n", argv[1]);
return NT_STATUS_OK;
}
/* List all commands */
for (tmp = cmd_list; tmp; tmp = tmp->next) {
tmp_set = tmp->cmd_set;
while(tmp_set->name) {
printf("%15s\t\t%s\n", tmp_set->name,
tmp_set->description ? tmp_set->description:
"");
tmp_set++;
}
}
return NT_STATUS_OK;
}
/* Change the debug level */
static NTSTATUS cmd_debuglevel(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
if (argc > 2) {
printf("Usage: %s [debuglevel]\n", argv[0]);
return NT_STATUS_OK;
}
if (argc == 2) {
DEBUGLEVEL = atoi(argv[1]);
}
printf("debuglevel is %d\n", DEBUGLEVEL);
return NT_STATUS_OK;
}
static NTSTATUS cmd_freemem(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
/* Cleanup */
talloc_destroy(mem_ctx);
mem_ctx = NULL;
vfs->data = NULL;
vfs->data_size = 0;
return NT_STATUS_OK;
}
static NTSTATUS cmd_quit(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, char **argv)
{
/* Cleanup */
talloc_destroy(mem_ctx);
exit(0);
return NT_STATUS_OK; /* NOTREACHED */
}
static struct cmd_set vfstest_commands[] = {
{ "GENERAL OPTIONS" },
{ "conf", cmd_conf, "Load smb configuration file", "conf <smb.conf>" },
{ "help", cmd_help, "Get help on commands", "" },
{ "?", cmd_help, "Get help on commands", "" },
{ "debuglevel", cmd_debuglevel, "Set debug level", "" },
{ "freemem", cmd_freemem, "Free currently allocated buffers", "" },
{ "exit", cmd_quit, "Exit program", "" },
{ "quit", cmd_quit, "Exit program", "" },
{ NULL }
};
static struct cmd_set separator_command[] = {
{ "---------------", NULL, "----------------------" },
{ NULL }
};
extern struct cmd_set vfs_commands[];
static struct cmd_set *vfstest_command_list[] = {
vfstest_commands,
vfs_commands,
NULL
};
static void add_command_set(struct cmd_set *cmd_set)
{
struct cmd_list *entry;
if (!(entry = (struct cmd_list *)malloc(sizeof(struct cmd_list)))) {
DEBUG(0, ("out of memory\n"));
return;
}
ZERO_STRUCTP(entry);
entry->cmd_set = cmd_set;
DLIST_ADD(cmd_list, entry);
}
static NTSTATUS do_cmd(struct vfs_state *vfs, struct cmd_set *cmd_entry, char *cmd)
{
char *p = cmd, **argv = NULL;
NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
pstring buf;
TALLOC_CTX *mem_ctx = NULL;
int argc = 0, i;
/* Count number of arguments first time through the loop then
allocate memory and strdup them. */
again:
while(next_token(&p, buf, " ", sizeof(buf))) {
if (argv) {
argv[argc] = strdup(buf);
}
argc++;
}
if (!argv) {
/* Create argument list */
argv = (char **)malloc(sizeof(char *) * argc);
memset(argv, 0, sizeof(char *) * argc);
if (!argv) {
fprintf(stderr, "out of memory\n");
result = NT_STATUS_NO_MEMORY;
goto done;
}
p = cmd;
argc = 0;
goto again;
}
/* Call the function */
if (cmd_entry->fn) {
if (mem_ctx == NULL) {
/* Create mem_ctx */
if (!(mem_ctx = talloc_init())) {
DEBUG(0, ("talloc_init() failed\n"));
goto done;
}
}
/* Run command */
result = cmd_entry->fn(vfs, mem_ctx, argc, argv);
} else {
fprintf (stderr, "Invalid command\n");
goto done;
}
done:
/* Cleanup */
if (argv) {
for (i = 0; i < argc; i++)
SAFE_FREE(argv[i]);
SAFE_FREE(argv);
}
return result;
}
/* Process a command entered at the prompt or as part of -c */
static NTSTATUS process_cmd(struct vfs_state *vfs, char *cmd)
{
struct cmd_list *temp_list;
BOOL found = False;
pstring buf;
char *p = cmd;
NTSTATUS result = NT_STATUS_OK;
int len = 0;
if (cmd[strlen(cmd) - 1] == '\n')
cmd[strlen(cmd) - 1] = '\0';
if (!next_token(&p, buf, " ", sizeof(buf))) {
return NT_STATUS_OK;
}
/* strip the trainly \n if it exsists */
len = strlen(buf);
if (buf[len-1] == '\n')
buf[len-1] = '\0';
/* Search for matching commands */
for (temp_list = cmd_list; temp_list; temp_list = temp_list->next) {
struct cmd_set *temp_set = temp_list->cmd_set;
while(temp_set->name) {
if (strequal(buf, temp_set->name)) {
found = True;
result = do_cmd(vfs, temp_set, cmd);
goto done;
}
temp_set++;
}
}
done:
if (!found && buf[0]) {
printf("command not found: %s\n", buf);
return NT_STATUS_OK;
}
if (!NT_STATUS_IS_OK(result)) {
printf("result was %s\n", nt_errstr(result));
}
return result;
}
static void process_file(struct vfs_state *pvfs, char *filename) {
FILE *file;
char command[3 * PATH_MAX];
if (*filename == '-') {
file = stdin;
} else {
file = fopen(filename, "r");
if (file == NULL) {
printf("vfstest: error reading file (%s)!", filename);
printf("errno n.%d: %s", errno, strerror(errno));
exit(-1);
}
}
while (fgets(command, 3 * PATH_MAX, file) != NULL) {
process_cmd(pvfs, command);
}
}
void exit_server(char *reason)
{
DEBUG(3,("Server exit (%s)\n", (reason ? reason : "")));
exit(0);
}
static int server_fd = -1;
int last_message = -1;
int smbd_server_fd(void)
{
return server_fd;
}
/****************************************************************************
Reload the services file.
**************************************************************************/
BOOL reload_services(BOOL test)
{
BOOL ret;
if (lp_loaded()) {
pstring fname;
pstrcpy(fname,lp_configfile());
if (file_exist(fname, NULL) &&
!strcsequal(fname, dyn_CONFIGFILE)) {
pstrcpy(dyn_CONFIGFILE, fname);
test = False;
}
}
reopen_logs();
if (test && !lp_file_list_changed())
return(True);
lp_killunused(conn_snum_used);
ret = lp_load(dyn_CONFIGFILE, False, False, True);
load_printers();
/* perhaps the config filename is now set */
if (!test)
reload_services(True);
reopen_logs();
load_interfaces();
{
if (smbd_server_fd() != -1) {
set_socket_options(smbd_server_fd(),"SO_KEEPALIVE");
set_socket_options(smbd_server_fd(), user_socket_options);
}
}
mangle_reset_cache();
reset_stat_cache();
/* this forces service parameters to be flushed */
set_current_service(NULL,True);
return (ret);
}
/* Main function */
int main(int argc, char *argv[])
{
BOOL interactive = True;
int opt;
static char *cmdstr = "";
static char *opt_logfile=NULL;
static int opt_debuglevel;
pstring logfile;
struct cmd_set **cmd_set;
extern BOOL AllowDebugChange;
static struct vfs_state vfs;
int i;
static char *filename = "";
/* make sure the vars that get altered (4th field) are in
a fixed location or certain compilers complain */
poptContext pc;
struct poptOption long_options[] = {
POPT_AUTOHELP
{"file", 'f', POPT_ARG_STRING, &filename, 0, },
{"command", 'c', POPT_ARG_STRING, &cmdstr, 0, "Execute specified list of commands" },
{"logfile", 'l', POPT_ARG_STRING, &opt_logfile, 'l', "Write output to specified logfile" },
{ NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_common_debug },
{ 0, 0, 0, 0}
};
setlinebuf(stdout);
DEBUGLEVEL = 1;
AllowDebugChange = False;
pc = poptGetContext("vfstest", argc, (const char **) argv,
long_options, 0);
while((opt = poptGetNextOpt(pc)) != -1) {
switch (opt) {
case 'l':
slprintf(logfile, sizeof(logfile) - 1, "%s.client",
opt_logfile);
lp_set_logfile(logfile);
interactive = False;
break;
case 'd':
DEBUGLEVEL = opt_debuglevel;
break;
}
}
poptFreeContext(pc);
/* TODO: check output */
reload_services(False);
/* the following functions are part of the Samba debugging
facilities. See lib/debug.c */
setup_logging("vfstest", interactive);
if (!interactive)
reopen_logs();
/* Load command lists */
cmd_set = vfstest_command_list;
while(*cmd_set) {
add_command_set(*cmd_set);
add_command_set(separator_command);
cmd_set++;
}
/* some basic initialization stuff */
vfs.conn = (struct connection_struct *)malloc(sizeof(struct connection_struct));
vfs.conn->user = "vfstest";
for (i=0; i < 1024; i++)
vfs.files[i] = NULL;
/* some advanced initiliazation stuff */
smbd_vfs_init(vfs.conn);
/* Do we have a file input? */
if (filename[0]) {
process_file(&vfs, filename);
return 0;
}
/* Do anything specified with -c */
if (cmdstr[0]) {
char *cmd;
char *p = cmdstr;
while((cmd=next_command(&p)) != NULL) {
process_cmd(&vfs, cmd);
}
return 0;
}
/* Loop around accepting commands */
while(1) {
pstring prompt;
char *line;
slprintf(prompt, sizeof(prompt) - 1, "vfstest $> ");
line = smb_readline(prompt, NULL, completion_fn);
if (line == NULL)
break;
if (line[0] != '\n')
process_cmd(&vfs, line);
}
free(vfs.conn);
return 0;
}

45
source3/torture/vfstest.h Normal file
View File

@ -0,0 +1,45 @@
/*
Unix SMB/CIFS implementation.
VFS module tester
Copyright (C) Simo Sorce 2002
Copyright (C) Eric Lorimer 2002
Most of this code was ripped off of rpcclient.
Copyright (C) Tim Potter 2000-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.
*/
struct func_entry {
char *name;
int (*fn)(struct connection_struct *conn, const char *path);
};
struct vfs_state {
struct connection_struct *conn;
struct files_struct *files[1024];
DIR *currentdir;
void *data;
size_t data_size;
};
struct cmd_set {
char *name;
NTSTATUS (*fn)(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc,
char **argv);
char *description;
char *usage;
};

View File

@ -0,0 +1,274 @@
/*
Samba Unix/Linux SMB client library
net ads cldap functions
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"
#ifdef HAVE_ADS
struct cldap_netlogon_reply {
uint32 version;
uint32 flags;
GUID guid;
char *domain;
char *server_name;
char *domain_flatname;
char *server_flatname;
char *dns_name;
uint32 unknown2[2];
};
/*
pull a length prefixed string from a packet
return number of bytes consumed
*/
static unsigned pull_len_string(char **ret, const char *p)
{
unsigned len = *p;
(*ret) = NULL;
if (len == 0) return 1;
(*ret) = smb_xstrndup(p+1, len);
return len+1;
}
/*
pull a dotted string from a packet
return number of bytes consumed
*/
static unsigned pull_dotted_string(char **ret, const char *p)
{
char *s;
unsigned len, total_len=0;
(*ret) = NULL;
while ((len = pull_len_string(&s, p)) > 1) {
if (total_len) {
char *s2;
asprintf(&s2, "%s.%s", *ret, s);
SAFE_FREE(*ret);
(*ret) = s2;
} else {
(*ret) = s;
}
total_len += len;
p += len;
}
return total_len + 1;
}
/*
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->version = IVAL(p, 0); p += 4;
reply->flags = IVAL(p, 0); p += 4;
memcpy(&reply->guid.info, p, GUID_SIZE);
p += GUID_SIZE;
p += pull_dotted_string(&reply->domain, p);
p += 2; /* 0xc018 - whats this? */
p += pull_len_string(&reply->server_name, p);
p += 2; /* 0xc018 - whats this? */
p += pull_len_string(&reply->domain_flatname, p);
p += 1;
p += pull_len_string(&reply->server_flatname, p);
p += 2;
p += pull_len_string(&reply->dns_name, p);
data_blob_free(&os1);
data_blob_free(&os2);
data_blob_free(&os3);
data_blob_free(&blob);
return 0;
}
/*
free a cldap reply packet
*/
static void cldap_reply_free(struct cldap_netlogon_reply *reply)
{
SAFE_FREE(reply->domain);
SAFE_FREE(reply->server_name);
SAFE_FREE(reply->domain_flatname);
SAFE_FREE(reply->server_flatname);
SAFE_FREE(reply->dns_name);
}
/*
do a cldap netlogon query
*/
int ads_cldap_netlogon(ADS_STRUCT *ads)
{
int sock;
int ret;
extern pstring global_myname;
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, global_myname, 6);
if (ret != 0) {
return ret;
}
ret = recv_cldap_netlogon(sock, &reply);
close(sock);
if (ret == -1) {
return -1;
}
d_printf("Version: 0x%x\n", reply.version);
d_printf("GUID: ");
print_guid(&reply.guid);
d_printf("Flags: 0x%x\n", reply.flags);
d_printf("Domain: %s\n", reply.domain);
d_printf("Server Name: %s\n", reply.server_name);
d_printf("Flatname: %s\n", reply.domain_flatname);
d_printf("Server Name2: %s\n", reply.server_flatname);
d_printf("DNS Name: %s\n", reply.dns_name);
cldap_reply_free(&reply);
return ret;
}
#endif

328
source3/utils/net_cache.c Normal file
View File

@ -0,0 +1,328 @@
/*
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)
{
char* timeout_str = ctime(&timeout);
timeout_str[strlen(timeout_str) - 1] = '\0';
d_printf("Key: %s\t\t Value: %s\t\t Timeout: %s %s\n", keystr, datastr,
timeout_str, timeout > time(NULL) ? "": "(expired)");
}
static void delete_cache_entry(const char* keystr, const char* datastr, const time_t timeout)
{
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
*
* @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_add(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
*
* @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(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);
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, 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, 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, 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);
}

View File

@ -0,0 +1,716 @@
/*
Unix SMB/CIFS implementation.
dump the remote SAM using rpc samsync operations
Copyright (C) Andrew Tridgell 2002
Copyright (C) Tim Potter 2001,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];
/* Decode hashes from password hash */
sam_pwd_hash(a->user_rid, a->pass.buf_lm_pwd, lm_passwd, 0);
sam_pwd_hash(a->user_rid, a->pass.buf_nt_pwd, nt_passwd, 0);
/* Encode as strings */
smbpasswd_sethexpwd(hex_lm_passwd, lm_passwd, a->acb_info);
smbpasswd_sethexpwd(hex_nt_passwd, nt_passwd, a->acb_info);
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 last_rid = -1;
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())) {
return;
}
d_printf("Dumping database %u\n", db_type);
do {
result = cli_netlogon_sam_sync(cli, mem_ctx, ret_creds, db_type, last_rid+1,
&num_deltas, &hdr_deltas, &deltas);
clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred), ret_creds);
last_rid = 0;
for (i = 0; i < num_deltas; i++) {
display_sam_entry(&hdr_deltas[i], &deltas[i]);
last_rid = hdr_deltas[i].target_rid;
}
} while (last_rid && 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, PIPE_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");
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)
{
DOM_SID sid;
fstring s;
uchar lm_passwd[16], nt_passwd[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);
/* Unix username is the same - for sainity */
pdb_set_username(account, s);
unistr2_to_ascii(s, &delta->uni_full_name, sizeof(s) - 1);
pdb_set_fullname(account, s);
unistr2_to_ascii(s, &delta->uni_home_dir, sizeof(s) - 1);
pdb_set_homedir(account, s, True);
unistr2_to_ascii(s, &delta->uni_dir_drive, sizeof(s) - 1);
pdb_set_dir_drive(account, s, True);
unistr2_to_ascii(s, &delta->uni_logon_script, sizeof(s) - 1);
pdb_set_logon_script(account, s, True);
unistr2_to_ascii(s, &delta->uni_acct_desc, sizeof(s) - 1);
pdb_set_acct_desc(account, s);
unistr2_to_ascii(s, &delta->uni_workstations, sizeof(s) - 1);
pdb_set_workstations(account, s);
unistr2_to_ascii(s, &delta->uni_profile, sizeof(s) - 1);
pdb_set_profile_path(account, s, True);
/* User and group sid */
sid_copy(&sid, get_global_sam_sid());
sid_append_rid(&sid, delta->user_rid);
pdb_set_user_sid(account, &sid);
sid_copy(&sid, get_global_sam_sid());
sid_append_rid(&sid, delta->group_rid);
pdb_set_group_sid(account, &sid);
/* Logon and password information */
pdb_set_logon_time(account, nt_time_to_unix(&delta->logon_time), True);
pdb_set_logoff_time(account, nt_time_to_unix(&delta->logoff_time),
True);
pdb_set_logon_divs(account, delta->logon_divs);
/* 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_set_kickoff_time(account, get_time_t_max(), True);
/* Decode hashes from password hash */
sam_pwd_hash(delta->user_rid, delta->pass.buf_lm_pwd, lm_passwd, 0);
sam_pwd_hash(delta->user_rid, delta->pass.buf_nt_pwd, nt_passwd, 0);
pdb_set_nt_passwd(account, nt_passwd);
pdb_set_lanman_passwd(account, lm_passwd);
/* TODO: account expiry time */
pdb_set_acct_ctrl(account, delta->acb_info);
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;
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)) {
struct passwd *pw;
pdb_free_sam(&sam_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));
}
pw = getpwnam_alloc(account);
if (pw) {
nt_ret = pdb_init_sam_pw(&sam_account, pw);
if (!NT_STATUS_IS_OK(nt_ret)) {
passwd_free(&pw);
pdb_free_sam(&sam_account);
return nt_ret;
}
passwd_free(&pw);
} else {
DEBUG(3, ("Could not create account %s\n", account));
pdb_free_sam(&sam_account);
return NT_STATUS_NO_SUCH_USER;
}
}
sam_account_from_delta(sam_account, delta);
if (!pdb_add_sam_account(sam_account)) {
DEBUG(1, ("SAM Account for %s already existed, updating\n",
account));
pdb_update_sam_account(sam_account);
}
if (!get_group_map_from_sid(*pdb_get_group_sid(sam_account),
&map, 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\n", map.gid));
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;
int flag = TDB_INSERT;
gid_t gid;
unistr2_to_ascii(name, &delta->uni_grp_name, sizeof(name)-1);
unistr2_to_ascii(comment, &delta->uni_grp_desc, sizeof(comment)-1);
if ((grp = getgrnam(name)) == NULL)
smb_create_group(name, &gid);
if ((grp = getgrgid(gid)) == NULL)
return NT_STATUS_ACCESS_DENIED;
/* 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 (get_group_map_from_sid(group_sid, &map, False)) {
grp = getgrgid(map.gid);
flag = 0; /* Don't TDB_INSERT, mapping exists */
}
if (grp == NULL)
{
gid_t new_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, &new_gid) != 0)
return NT_STATUS_ACCESS_DENIED;
}
if ((grp = getgrgid(new_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;
add_mapping_entry(&map, flag);
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())) {
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\n",
delta->rids[i]));
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;
int insert_flag = TDB_INSERT;
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 (get_group_map_from_sid(alias_sid, &map, False)) {
grp = getgrgid(map.gid);
insert_flag = 0; /* Don't TDB_INSERT, mapping exists */
}
if (grp == NULL) {
gid_t new_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, &new_gid) != 0)
return NT_STATUS_ACCESS_DENIED;
}
if ((grp = getgrgid(new_gid)) == NULL)
return NT_STATUS_ACCESS_DENIED;
}
map.gid = grp->gr_gid;
map.sid = alias_sid;
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;
add_mapping_entry(&map, insert_flag);
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 last_rid = -1;
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())) {
return;
}
d_printf("Fetching database %u\n", db_type);
do {
result = cli_netlogon_sam_sync(cli, mem_ctx, ret_creds,
db_type, last_rid+1,
&num_deltas,
&hdr_deltas, &deltas);
clnt_deal_with_creds(cli->sess_key, &(cli->clnt_cred),
ret_creds);
last_rid = 0;
for (i = 0; i < num_deltas; i++) {
fetch_sam_entry(&hdr_deltas[i], &deltas[i], dom_sid);
last_rid = hdr_deltas[i].target_rid;
}
} while (last_rid && 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, PIPE_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");
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;
}

BIN
swat/images/wizard.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 853 B

15
testsuite/build_farm/backtrace Executable file
View File

@ -0,0 +1,15 @@
#!/bin/sh
# Modified version of tridge's backtrace script.
# we want everything on stderr, so the program is not disturbed
exec 1>&2
PID=$1
TMPFILE=$prefix/backtrace.$$
cat << EOF > $TMPFILE
set height 0
up 8
bt full
quit
EOF
gdb -x $TMPFILE $prefix/sbin/smbd $PID
/bin/rm -f $TMPFILE