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:
commit
3054ef8a6e
237
docs/docbook/devdoc/CodingSuggestions.sgml
Normal file
237
docs/docbook/devdoc/CodingSuggestions.sgml
Normal 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>
|
154
docs/docbook/devdoc/NetBIOS.sgml
Normal file
154
docs/docbook/devdoc/NetBIOS.sgml
Normal 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>
|
129
docs/docbook/devdoc/Tracing.sgml
Normal file
129
docs/docbook/devdoc/Tracing.sgml
Normal 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>
|
184
docs/docbook/devdoc/architecture.sgml
Normal file
184
docs/docbook/devdoc/architecture.sgml
Normal 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>
|
2923
docs/docbook/devdoc/cifsntdomain.sgml
Normal file
2923
docs/docbook/devdoc/cifsntdomain.sgml
Normal file
File diff suppressed because it is too large
Load Diff
321
docs/docbook/devdoc/debug.sgml
Normal file
321
docs/docbook/devdoc/debug.sgml
Normal 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>
|
||||
>debugfile< :== { >debugmsg< }
|
||||
|
||||
>debugmsg< :== >debughdr< '\n' >debugtext<
|
||||
|
||||
>debughdr< :== '[' TIME ',' LEVEL ']' FILE ':' [FUNCTION] '(' LINE ')'
|
||||
|
||||
>debugtext< :== { >debugline< }
|
||||
|
||||
>debugline< :== 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>
|
62
docs/docbook/devdoc/dev-doc.sgml
Normal file
62
docs/docbook/devdoc/dev-doc.sgml
Normal 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>
|
439
docs/docbook/devdoc/internals.sgml
Normal file
439
docs/docbook/devdoc/internals.sgml
Normal 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>
|
239
docs/docbook/devdoc/parsing.sgml
Normal file
239
docs/docbook/devdoc/parsing.sgml
Normal 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>
|
||||
<file> :== { <section> } EOF
|
||||
<section> :== <section header> { <parameter line> }
|
||||
<section header> :== '[' NAME ']'
|
||||
<parameter line> :== 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>
|
311
docs/docbook/devdoc/unix-smb.sgml
Normal file
311
docs/docbook/devdoc/unix-smb.sgml
Normal 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>
|
||||
|
159
docs/docbook/manpages/vfstest.1.sgml
Normal file
159
docs/docbook/manpages/vfstest.1.sgml
Normal 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 "command"</arg>
|
||||
<arg choice="opt">-l "logfile"</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 <module.so></command> - Load specified VFS module </para></listitem>
|
||||
|
||||
<listitem><para><command>populate <char> <size></command> - Populate a data buffer with the specified data
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para><command>showdata [<offset> <len>]</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 <smb.conf></command> - Load a different configuration file</para></listitem>
|
||||
|
||||
<listitem><para><command>help [<command>]</command> - Get list of commands or info about specified command</para></listitem>
|
||||
|
||||
<listitem><para><command>debuglevel <level></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>
|
78
docs/docbook/projdoc/GROUP-MAPPING-HOWTO.sgml
Normal file
78
docs/docbook/projdoc/GROUP-MAPPING-HOWTO.sgml
Normal 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>
|
332
docs/docbook/projdoc/Other-Clients.sgml
Normal file
332
docs/docbook/projdoc/Other-Clients.sgml
Normal 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>
|
148
docs/docbook/projdoc/Portability.sgml
Normal file
148
docs/docbook/projdoc/Portability.sgml
Normal 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
82
docs/docbook/samba.dsl
Normal 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
178
docs/manpages/vfstest.1
Normal 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.
|
18
examples/VFS/README.netatalk
Normal file
18
examples/VFS/README.netatalk
Normal 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
430
examples/VFS/netatalk.c
Normal 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
28
examples/sam/Makefile.in
Normal 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
29
examples/sam/README
Normal 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
250
examples/sam/sam_skel.c
Normal 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;
|
||||
}
|
62
source3/include/nt_status.h
Normal file
62
source3/include/nt_status.h
Normal 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
282
source3/include/sam.h
Normal 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
319
source3/lib/gencache.c
Normal 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
302
source3/lib/sendfile.c
Normal 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
171
source3/libads/ads_utils.c
Normal 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
|
16
source3/nsswitch/winbind_client.h
Normal file
16
source3/nsswitch/winbind_client.h
Normal 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);
|
||||
|
1
source3/python/.cvsignore
Normal file
1
source3/python/.cvsignore
Normal file
@ -0,0 +1 @@
|
||||
*.pyc
|
28
source3/python/README
Normal file
28
source3/python/README
Normal 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!
|
34
source3/python/examples/spoolss/changeid.py
Executable file
34
source3/python/examples/spoolss/changeid.py
Executable 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)
|
36
source3/python/examples/spoolss/enumprinters.py
Executable file
36
source3/python/examples/spoolss/enumprinters.py
Executable 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
|
88
source3/python/examples/spoolss/psec.py
Executable file
88
source3/python/examples/spoolss/psec.py
Executable 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)
|
12
source3/python/examples/tdbpack/tdbtimetrial.py
Executable file
12
source3/python/examples/tdbpack/tdbtimetrial.py
Executable 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()
|
195
source3/python/examples/tdbpack/test_tdbpack.py
Executable file
195
source3/python/examples/tdbpack/test_tdbpack.py
Executable 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
39
source3/python/gprinterdata
Executable 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
39
source3/python/gtdbtool
Executable 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
272
source3/python/gtkdictbrowser.py
Executable 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
270
source3/python/py_common.c
Normal 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
184
source3/python/py_conv.c
Normal 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
40
source3/python/py_conv.h
Normal 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
56
source3/python/py_samba.c
Normal 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
498
source3/python/py_samr.c
Normal 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;
|
||||
}
|
58
source3/python/py_samr_conv.c
Normal file
58
source3/python/py_samr_conv.c
Normal 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
490
source3/python/py_spoolss.c
Normal 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();
|
||||
}
|
420
source3/python/py_spoolss_drivers.c
Normal file
420
source3/python/py_spoolss_drivers.c
Normal 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;
|
||||
}
|
177
source3/python/py_spoolss_drivers_conv.c
Normal file
177
source3/python/py_spoolss_drivers_conv.c
Normal 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;
|
||||
}
|
266
source3/python/py_spoolss_forms.c
Normal file
266
source3/python/py_spoolss_forms.c
Normal 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;
|
||||
}
|
377
source3/python/py_spoolss_jobs.c
Normal file
377
source3/python/py_spoolss_jobs.c
Normal 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;
|
||||
}
|
393
source3/python/py_spoolss_printerdata.c
Normal file
393
source3/python/py_spoolss_printerdata.c
Normal 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;
|
||||
}
|
475
source3/python/py_spoolss_printers.c
Normal file
475
source3/python/py_spoolss_printers.c
Normal 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;
|
||||
}
|
306
source3/python/py_spoolss_printers_conv.c
Normal file
306
source3/python/py_spoolss_printers_conv.c
Normal 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;
|
||||
}
|
123
source3/python/py_spoolss_proto.h
Normal file
123
source3/python/py_spoolss_proto.h
Normal 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
662
source3/python/py_tdbpack.c
Normal 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
716
source3/python/py_winbind.c
Normal 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());
|
||||
}
|
42
source3/python/py_winbind_conv.c
Normal file
42
source3/python/py_winbind_conv.c
Normal 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;
|
||||
}
|
1
source3/python/samba/.cvsignore
Normal file
1
source3/python/samba/.cvsignore
Normal file
@ -0,0 +1 @@
|
||||
*.pyc
|
7
source3/python/samba/__init__.py
Normal file
7
source3/python/samba/__init__.py
Normal file
@ -0,0 +1,7 @@
|
||||
"""samba
|
||||
|
||||
Various Python modules for interfacing to Samba.
|
||||
|
||||
Try using help() to examine their documentation.
|
||||
"""
|
||||
|
59
source3/python/samba/printerdata.py
Normal file
59
source3/python/samba/printerdata.py
Normal 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
183
source3/python/setup.py
Executable 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")]),
|
||||
],
|
||||
)
|
372
source3/registry/reg_objects.c
Normal file
372
source3/registry/reg_objects.c
Normal 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
307
source3/sam/account.c
Normal 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
322
source3/sam/api.c
Normal 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);
|
||||
}
|
||||
|
872
source3/sam/get_set_account.c
Normal file
872
source3/sam/get_set_account.c
Normal 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;
|
||||
}
|
||||
|
263
source3/sam/get_set_domain.c
Normal file
263
source3/sam/get_set_domain.c
Normal 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
106
source3/sam/get_set_group.c
Normal 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
193
source3/sam/group.c
Normal 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
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
79
source3/sam/sam_plugin.c
Normal 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);
|
||||
}
|
43
source3/script/find_missing_doc.pl
Executable file
43
source3/script/find_missing_doc.pl
Executable 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
301
source3/torture/cmd_sam.c
Normal 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
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
449
source3/torture/samtest.c
Normal 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
38
source3/torture/samtest.h
Normal 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
593
source3/torture/vfstest.c
Normal 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
45
source3/torture/vfstest.h
Normal 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;
|
||||
};
|
274
source3/utils/net_ads_cldap.c
Normal file
274
source3/utils/net_ads_cldap.c
Normal 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
328
source3/utils/net_cache.c
Normal 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);
|
||||
}
|
716
source3/utils/net_rpc_samsync.c
Normal file
716
source3/utils/net_rpc_samsync.c
Normal 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
BIN
swat/images/wizard.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 853 B |
15
testsuite/build_farm/backtrace
Executable file
15
testsuite/build_farm/backtrace
Executable 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
|
Loading…
x
Reference in New Issue
Block a user