summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcvs2svn Import User <samba-bugs@samba.org>2001-07-05 11:34:51 +0000
committercvs2svn Import User <samba-bugs@samba.org>2001-07-05 11:34:51 +0000
commit6ad113dce11db901ff666dac9a34e74f7b763f14 (patch)
tree41ed346ab6ccc946294ecbe90b42d790c6d66a0f
parent57066e1f6bdff7311cd8667df8167a16aa7e67bd (diff)
parent805c20452e98c5e3d3fb24537ce722d4318ffa90 (diff)
downloadsamba-6ad113dce11db901ff666dac9a34e74f7b763f14.tar.gz
samba-6ad113dce11db901ff666dac9a34e74f7b763f14.tar.xz
samba-6ad113dce11db901ff666dac9a34e74f7b763f14.zip
This commit was manufactured by cvs2svn to create branch
'SAMBA_2_2_RELEASE'.
-rw-r--r--docs/docbook/manpages/make_unicodemap.1.sgml172
-rw-r--r--docs/docbook/projdoc/CVS-Access.sgml157
-rw-r--r--docs/docbook/scripts/README.ldp_print60
-rw-r--r--docs/docbook/scripts/fix_print_html.lib172
-rwxr-xr-xdocs/docbook/scripts/ldp_print71
-rw-r--r--docs/docbook/stylesheets/ldp.dsl.in256
-rw-r--r--docs/htmldocs/CVS-Access.html193
-rw-r--r--docs/htmldocs/make_unicodemap.1.html276
-rw-r--r--docs/textdocs/outdated/NTDOMAIN.txt51
-rw-r--r--docs/textdocs/outdated/PRINTER_DRIVER.txt240
-rw-r--r--docs/textdocs/outdated/PROJECTS88
-rw-r--r--examples/libsmbclient/testsmbc.c456
-rw-r--r--examples/libsmbclient/tree.c812
-rw-r--r--packaging/LSB/README6
-rw-r--r--packaging/LSB/lsb-samba.spec100
-rwxr-xr-xpackaging/LSB/samba.sh80
-rw-r--r--packaging/LSB/samba.xinetd15
-rw-r--r--packaging/LSB/smb.conf290
-rw-r--r--packaging/Mandrake/empty.patch0
-rw-r--r--source/include/libsmbclient.h780
-rw-r--r--source/lib/util_getent.c239
-rw-r--r--source/libsmb/clidgram.c272
-rw-r--r--source/libsmb/clistr.c44
-rw-r--r--source/libsmb/libsmbclient.c2515
-rw-r--r--source/pam_smbpass/pam_smb_acct.c112
-rw-r--r--source/pam_smbpass/pam_smb_auth.c245
-rw-r--r--source/pam_smbpass/pam_smb_passwd.c313
-rw-r--r--source/rpcclient/cmd_netlogon.c108
-rw-r--r--source/rpcclient/cmd_srvsvc.c243
-rw-r--r--source/smbd/session.c179
-rw-r--r--source/smbd/utmp.c576
-rw-r--r--testsuite/build_farm/basicsmb.fns64
-rw-r--r--testsuite/build_farm/basicsmb.smb.conf.server3
-rw-r--r--testsuite/build_farm/basicsmb.smb.conf.template39
-rw-r--r--testsuite/build_farm/basicsmb.smb.conf.user1
-rw-r--r--testsuite/build_farm/runlist3
36 files changed, 9231 insertions, 0 deletions
diff --git a/docs/docbook/manpages/make_unicodemap.1.sgml b/docs/docbook/manpages/make_unicodemap.1.sgml
new file mode 100644
index 00000000000..50a5446d60b
--- /dev/null
+++ b/docs/docbook/manpages/make_unicodemap.1.sgml
@@ -0,0 +1,172 @@
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry id="make-unicodemap">
+
+<refmeta>
+ <refentrytitle>make_unicodemap</refentrytitle>
+ <manvolnum>1</manvolnum>
+</refmeta>
+
+
+<refnamediv>
+ <refname>make_unicodemap</refname>
+ <refpurpose>construct a unicode map file for Samba</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>make_unicodemap</command>
+ <arg choice="req">codepage</arg>
+ <arg choice="req">inputfile</arg>
+ <arg choice="req">outputfile</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>make_unicodemap</command> compiles text unicode map
+ files into binary unicodef map files for use with the
+ internationalization features of Samba 2.2.
+ </para>
+</refsect1>
+
+
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>codepage</term>
+ <listitem><para>This is the codepage or UNIX character
+ set we are processing (a number, e.g. 850).
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>inputfile</term>
+ <listitem><para>This is the input file to process. This is a
+ text unicode map file such as the ones found in the Samba
+ <filename>source/codepages</filename> directory.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>outputfile</term>
+ <listitem><para>This is the binary output file to produce.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+
+<refsect1>
+ <title>Samba Unicode Map Files</title>
+
+ <para>
+ A text Samba unicode map file is a description that tells Samba
+ how to map characters from a specified DOS code page or UNIX character
+ set to 16 bit unicode.
+ </para>
+
+ <para>A binary Samba unicode map file is a binary representation
+ of the same information, including a value that specifies what
+ codepage or UNIX character set this file is describing.
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>Files</title>
+
+ <para><filename>CP&lt;codepage&gt;.TXT</filename></para>
+
+ <para>
+ These are the input (text) unicode map files provided
+ in the Samba <filename>source/codepages</filename>
+ directory.
+ </para>
+
+ <para>
+ A text unicode map file consists of multiple lines
+ containing two fields. These fields are :
+ </para>
+
+ <itemizedlist>
+ <listitem><para><parameter>character</parameter> - which is
+ the (hex) character mapped on this line.
+ </para></listitem>
+
+ <listitem><para><parameter>unicode</parameter> - which
+ is the (hex) 16 bit unicode character that the character
+ will map to.
+ </para></listitem>
+ </itemizedlist>
+
+ <para>
+ <filename>unicode_map.&lt;codepage&gt;</filename> - These are
+ the output (binary) unicode map files produced and placed in
+ the Samba destination <filename>lib/codepage</filename>
+ directory.
+ </para>
+</refsect1>
+
+
+<refsect1>
+ <title>Installation</title>
+
+ <para>
+ The location of the server and its support files is a matter
+ for individual system administrators. The following are thus
+ suggestions only.
+ </para>
+
+ <para>
+ It is recommended that the <command>make_unicodemap</command>
+ program be installed under the
+ <filename>$prefix/samba</filename> hierarchy,
+ in a directory readable by all, writeable only by root. The
+ program itself should be executable by all. The program
+ should NOT be setuid or setgid!
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is correct for version 2.2 of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><ulink url="smbd.8.html"><command>smbd(8)</command></ulink>,
+ <ulink url="smb.conf.5.html">smb.conf(5)</ulink>
+ </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 original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <ulink url="ftp://ftp.icce.rug.nl/pub/unix/">
+ ftp://ftp.icce.rug.nl/pub/unix/</ulink>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</para>
+</refsect1>
+
+</refentry>
diff --git a/docs/docbook/projdoc/CVS-Access.sgml b/docs/docbook/projdoc/CVS-Access.sgml
new file mode 100644
index 00000000000..aea146b66a1
--- /dev/null
+++ b/docs/docbook/projdoc/CVS-Access.sgml
@@ -0,0 +1,157 @@
+<chapter>
+
+
+<chapterinfo>
+ <author>
+ <affiliation>
+ <orgname>Samba Team</orgname>
+ </affiliation>
+ </author>
+
+
+ <pubdate> (22 May 2001) </pubdate>
+</chapterinfo>
+
+<title>HOWTO Access Samba source code via CVS</title>
+
+<sect1>
+<title>Introduction</title>
+
+<para>
+Samba is developed in an open environnment. Developers use CVS
+(Concurrent Versioning System) to "checkin" (also known as
+"commit") new source code. Samba's various CVS branches can
+be accessed via anonymouns CVS using the instructions
+detailed in this chapter.
+</para>
+
+<para>
+This document is a modified version of the instructions found at
+<ulink url="http://samba.org/samba/cvs.html">http://samba.org/samba/cvs.html</ulink>
+</para>
+
+</sect1>
+
+
+<sect1>
+<title>CVS Access to samba.org</title>
+
+<para>
+The machine samba.org runs a publicly accessible CVS
+repository for access to the source code of several packages,
+including samba, rsync and jitterbug. There are two main ways of
+accessing the CVS server on this host.
+</para>
+
+<sect2>
+<title>Access via CVSweb</title>
+
+<para>
+You can access the source code via your
+favourite WWW browser. This allows you to access the contents of
+individual files in the repository and also to look at the revision
+history and commit logs of individual files. You can also ask for a diff
+listing between any two versions on the repository.
+</para>
+
+<para>
+Use the URL : <ulink
+url="http://samba.org/cgi-bin/cvsweb">http://samba.org/cgi-bin/cvsweb</ulink>
+</para>
+</sect2>
+
+<sect2>
+<title>Access via cvs</title>
+
+<para>
+You can also access the source code via a
+normal cvs client. This gives you much more control over you can
+do with the repository and allows you to checkout whole source trees
+and keep them uptodate via normal cvs commands. This is the
+preferred method of access if you are a developer and not
+just a casual browser.
+</para>
+
+<para>
+To download the latest cvs source code, point your
+browser at the URL : <ulink url="http://www.cyclic.com/">http://www.cyclic.com/</ulink>.
+and click on the 'How to get cvs' link. CVS is free software under
+the GNU GPL (as is Samba). Note that there are several graphical CVS clients
+which provide a graphical interface to the sometimes mundane CVS commands.
+Links to theses clients are also available from http://www.cyclic.com.
+</para>
+
+<para>
+To gain access via anonymous cvs use the following steps.
+For this example it is assumed that you want a copy of the
+samba source code. For the other source code repositories
+on this system just substitute the correct package name
+</para>
+
+<orderedlist>
+<listitem>
+ <para>
+ Install a recent copy of cvs. All you really need is a
+ copy of the cvs client binary.
+ </para>
+</listitem>
+
+
+<listitem>
+ <para>
+ Run the command
+ </para>
+
+ <para>
+ <command>cvs -d :pserver:cvs@samba.org:/cvsroot login</command>
+ </para>
+
+ <para>
+ When it asks you for a password type <userinput>cvs</userinput>.
+ </para>
+</listitem>
+
+
+<listitem>
+ <para>
+ Run the command
+ </para>
+
+ <para>
+ <command>cvs -d :pserver:cvs@samba.org:/cvsroot co samba</command>
+ </para>
+
+ <para>
+ This will create a directory called samba containing the
+ latest samba source code (i.e. the HEAD tagged cvs branch). This
+ currently corresponds to the 3.0 development tree.
+ </para>
+
+ <para>
+ CVS branches other HEAD can be obtained by using the <parameter>-r</parameter>
+ and defining a tag name. A list of branch tag names can be found on the
+ "Development" page of the samba web site. A common request is to obtain the
+ latest 2.2 release code. This could be done by using the following command.
+ </para>
+
+ <para>
+ <command>cvs -d :pserver:cvs@samba.org:/cvsroot co -r SAMBA_2_2 samba</command>
+ </para>
+</listitem>
+
+<listitem>
+ <para>
+ Whenever you want to merge in the latest code changes use
+ the following command from within the samba directory:
+ </para>
+
+ <para>
+ <command>cvs update -d -P</command>
+ </para>
+</listitem>
+</orderedlist>
+
+</sect2>
+</sect1>
+
+</chapter>
diff --git a/docs/docbook/scripts/README.ldp_print b/docs/docbook/scripts/README.ldp_print
new file mode 100644
index 00000000000..8d61a855343
--- /dev/null
+++ b/docs/docbook/scripts/README.ldp_print
@@ -0,0 +1,60 @@
+
+######################################################################
+ ldp_print - print tool/script for DocBook SGML/XML documents
+######################################################################
+
+This process/script is used in the production environment for the
+LDP. It relies on the HTMLDOC software package (GPL'ed) which can be
+obtained from the Easy Software Products (c) web site:
+
+ http://www.easysw.com/htmldoc/
+
+This process creates a PDF variant from the single-file HTML
+representation of a DocBook SGML (or XML) instance. The simple
+wrapper script (ldp_print) assumes that the file was created using
+{open}jade in a manner similar to:
+
+ jade -t sgml -i html -V nochunks -d $style $fname > $fname.html
+
+Give the script the filename as an argument. It will then parse the
+file into 'title.html' and 'body.html' and send each to htmldoc (as
+the corresponding title page and body of the document).
+
+
+CAVEATS
+=======
+
+o Assumes perl is in /usr/bin; adjust if necessary
+
+o You may need to specify where the htmldoc executable resides.
+ The script assumes it's within your $PATH.
+
+o If you want Postscript as an output variant, uncomment the
+ appropriate lines (see below).
+
+o Relies on output from a DocBook instance created via DSSSL/{open}jade!
+
+o Cleans up (removes) the intermediate files it creates (but not the
+ PDF or Postscript files, obviously!)
+
+o Works silently; PDF (PostScript) will be created in the same directory
+ as was specified for the input (single-file HTML) file.
+
+o Provided without warranty or support!
+
+o I ran into a problem with htmldoc v1.8.8 which required a source
+ code change (I was getting a core dump from the htmldoc process).
+ Here is the change required:
+
+ htmldoc/ps-pdf.cxx :
+ 3662,3665d3661
+ < /* gjf = 11Oct2000 */
+ < if( temprow == NULL )
+ < break;
+ <
+
+
+====
+gferg (at) sgi.com / Ferg
+11 Jan 2000
+
diff --git a/docs/docbook/scripts/fix_print_html.lib b/docs/docbook/scripts/fix_print_html.lib
new file mode 100644
index 00000000000..e8a9aaa4c77
--- /dev/null
+++ b/docs/docbook/scripts/fix_print_html.lib
@@ -0,0 +1,172 @@
+#
+# fix_print_html.lib
+#
+# Dan Scott / <dan.scott (at) acm.org>
+# Ferg / <gferg (at) sgi.com>
+#
+# Used to prepare single-file HTML variant for PDF/Postscript creation
+# thru htmldoc.
+#
+# log:
+# 16Oct2000 - initial entry <gferg (at) sgi.com>
+# 03Apr2001 - fix for <preface>
+#
+#
+
+sub fix_print_html {
+
+ my($in,$out,$ttl) = @_;
+
+ open(IN_FILE, "< $in") || do {
+ print "fix_print_html: cannot open $in: $!\n";
+ return 0;
+ };
+
+ my($buf,$ttl_buf) = '';
+ my($indx) = -1;
+ my($is_article) = 0;
+ while(<IN_FILE>) {
+
+ if( $indx == 1 ) {
+
+ # ignore everything until we see the chapter or sect
+ #
+ if( $_ =~ /CLASS="CHAP/i || $_ =~ /CLASS="PREF/i ) {
+
+ $buf .= $_;
+ $indx++;
+
+ } elsif( $_ =~ /CLASS="SECT/ || $_ =~ /CLASS="sect/ ) {
+
+ $buf .= $_;
+ $indx++;
+ $is_article = 1;
+
+ } else {
+ next;
+ }
+
+ } elsif( $indx == 0 ) {
+
+ # write out the title page file
+ #
+ if( $_ =~ /CLASS="TOC"/ ) {
+
+ $ttl_buf .= "></DIV>\n</BODY>\n</HTML>\n";
+ $ttl_buf =~ s/<\/H1\n/<\/H1\n><P><BR><BR\n/ms;
+
+ open(TOC_FILE, "> $ttl") || do {
+ print "fix_print_html: cannot open $ttl: $!\n";
+ close(IN_FILE);
+ return 0;
+ };
+ print TOC_FILE $ttl_buf;
+ close(TOC_FILE);
+ $ttl_buf = '';
+ $indx++;
+
+ } else {
+ $ttl_buf .= $_;
+ }
+
+ } elsif( $indx < 0 ) {
+
+ # up to this point, both buffers get the line
+ #
+ if( $_ =~ /CLASS="TITLEPAGE"/ ) {
+
+ $ttl_buf .= $_ . ">\n<P>\n<BR><BR><BR><BR>\n<\/P\n";
+ $indx++;
+
+ } else {
+ $buf .= $_;
+ $ttl_buf .= $_;
+ }
+
+ } else {
+
+ $buf .= $_;
+ }
+ }
+ close(IN_FILE);
+
+ open(OUT_FILE, "> $out") || do {
+ print "fix_print_html: cannot open $out: $!\n";
+ return 0;
+ };
+
+
+ # make these corrections and write out the file
+ #
+
+ $buf =~ s/(\n><LI\n)><P\n(.*?)<\/P\n>/$1$2\n/gms;
+ $buf =~ s/(\n><LI\n><DIV\nCLASS="FORMALPARA"\n)><P\n(.*?)<\/P\n>/$1$2\n/gms;
+ $buf =~ s/(\n><LI\nSTYLE="[^\"]+"\n)><P\n(.*?)<\/P\n>/$1$2\n/gms;
+ if( $is_article == 0 ) {
+ $buf =~ s/(\nCLASS="SECT[TION\d]+"\n>)<H1\n(.*?)<\/H1/$1<H2\n$2<\/H2/gims;
+ $buf =~ s/(\nCLASS="SECT[TION\d]+"\n><HR>)<H1\n(.*?)<\/H1/$1<H2\n$2<\/H2/gims;
+ }
+ $buf =~ s/<H1(\nCLASS="INDEXDIV"\n)(.*?)<\/H1/<H2$1$2<\/H2/gims;
+ if( ($indx = rindex($buf, "<H1\n><A\nNAME=\"DOC-INDEX\"")) > -1 ) {
+ $buf = substr($buf, 0, $indx);
+ $buf .= "\n<\/BODY>\n<\/HTML>\n\n";
+ } elsif( ($indx = rindex($buf, "<H1\n><A\nNAME=\"doc-index\"")) > -1 ) {
+ $buf = substr($buf, 0, $indx);
+ $buf .= "\n<\/BODY>\n<\/HTML>\n\n";
+ }
+ $buf =~ s/\&\#13;//g;
+ $buf =~ s/\&\#60;/\&lt;/g;
+ $buf =~ s/\&\#62;/\&gt;/g;
+ $buf =~ s/\&\#8211;/\-/g;
+ $buf =~ s/WIDTH=\"\d\"//g;
+ $buf =~ s/><[\/]*TBODY//g;
+ $buf =~ s/><[\/]*THEAD//g;
+ $buf =~ s/TYPE=\"1\"\n//gim;
+
+ if( $is_article == 0 ) {
+
+ # for books...decrement the headers by 1 and then re-set the
+ # chapter level only to H1...
+ #
+ my($cnt,$j) = 0;
+ for($cnt=5; $cnt > 0; $cnt--) {
+ $j = $cnt + 1;
+ $buf =~ s/<H${cnt}/<H${j}/g;
+ $buf =~ s/<\/H${cnt}/<\/H${j}/g;
+ }
+
+ my(@l) = split(/\n/, $buf);
+ for( $cnt=0; $cnt < (@l + 0); $cnt++ ) {
+
+ if( $j == 1 ) {
+ if( $l[$cnt] =~ /<DIV/ ) {
+ $j = 0;
+ next;
+ }
+ $l[$cnt] =~ s/<H2/<H1/g;
+ $l[$cnt] =~ s/<\/H2/<\/H1/g;
+ }
+ if( $l[$cnt] =~ /^CLASS=\"CHAP/i
+ ||
+ $l[$cnt] =~ /^CLASS=\"PREF/i ) {
+ $j = 1;
+ }
+ }
+
+ $buf = join("\n", @l);
+
+ }
+ $buf =~ s/><DIV\nCLASS="\w+"\n//gms;
+ $buf =~ s/><\/DIV\n//gms;
+ $buf =~ s/(><LI\n)><P\n(.*?)<\/P\n>(<\/LI\n)/$1$2$3/gms;
+
+ print OUT_FILE $buf;
+ close(OUT_FILE);
+
+ return 1;
+}
+
+# Return true from package include
+#
+1;
+
diff --git a/docs/docbook/scripts/ldp_print b/docs/docbook/scripts/ldp_print
new file mode 100755
index 00000000000..70bb801def4
--- /dev/null
+++ b/docs/docbook/scripts/ldp_print
@@ -0,0 +1,71 @@
+#!/usr/bin/perl -w
+#
+# usage: ldp_print <single_file.html>
+#
+# Creates a PDF variant of a single-file HTML representation of a
+# DocBook SGML (or XML) instance. This simple wrapper assumes that
+# the file was created using {open}jade in a manner similar to:
+#
+# jade -t sgml -i html -V nochunks -d $style $fname > $fname.html
+#
+# Give this script the filename as an argument. It will then parse
+# the file into 'title.html' and 'body.html' and send each to
+# htmldoc (as the corresponding title page and body of the document).
+#
+#
+# CAVEATS:
+#
+# Assumes perl is in /usr/bin; adjust if necessary
+#
+# You may need to specify where the htmldoc executable resides.
+# The script assumes it's within your $PATH.
+#
+# If you want Postscript as an output variant, uncomment the
+# appropriate lines (see below).
+#
+# Relies on output from a DocBook instance created via DSSSL/{open}jade!
+#
+# Cleans up (removes) the intermediate files it creates (but not the
+# PDF or Postscript files, obviously!)
+#
+# Works silently; PDF (PostScript) will be created in the same directory
+# as was specified for the input (single-file HTML) file.
+#
+# Provided without warranty or support!
+#
+# gferg@sgi.com / Ferg (used as part of the LDP production env)
+#
+
+use strict;
+push(@INC, "./");
+require 'fix_print_html.lib';
+
+if( $ARGV[0] eq '' || !(-r $ARGV[0]) ) {
+ die "\nusage: ldp_print <single_file.html>\n\n";
+}
+
+my($fname_wo_ext) = $ARGV[0];
+$fname_wo_ext =~ s/\.[\w]+$//;
+
+
+# create new files from single HTML file to use for print
+#
+&fix_print_html($ARGV[0], 'body.html', 'title.html');
+
+my($cmd) = "htmldoc --size universal -t pdf -f ${fname_wo_ext}.pdf " .
+ "--firstpage p1 --titlefile title.html body.html";
+
+# For postscript output; append onto the above cmd string:
+#
+# "; htmldoc --size universal -t ps -f -f ${fname_wo_ext}.ps " .
+# "--firstpage p1 --titlefile title.html body.html";
+#
+system($cmd);
+die "\nldp_print: could not create ${fname_wo_ext}.pdf ($!)\n" if ($?);
+
+# cleanup
+#
+system("rm -f body.html title.html");
+
+exit(0);
+
diff --git a/docs/docbook/stylesheets/ldp.dsl.in b/docs/docbook/stylesheets/ldp.dsl.in
new file mode 100644
index 00000000000..d6e06f4b6d1
--- /dev/null
+++ b/docs/docbook/stylesheets/ldp.dsl.in
@@ -0,0 +1,256 @@
+<!DOCTYPE style-sheet PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN" [
+<!ENTITY % html "IGNORE">
+<![%html;[
+<!ENTITY % print "IGNORE">
+<!ENTITY docbook.dsl SYSTEM "@SGML_SHARE@/dsssl/docbook/html/docbook.dsl" CDATA dsssl>
+]]>
+<!ENTITY % print "INCLUDE">
+<![%print;[
+<!ENTITY docbook.dsl SYSTEM "@SGML_SHARE@/dsssl/docbook/print/docbook.dsl" CDATA dsssl>
+]]>
+]>
+
+<style-sheet>
+
+<style-specification id="print" use="docbook">
+<style-specification-body>
+
+;; ==============================
+;; customize the print stylesheet
+;; ==============================
+
+(declare-characteristic preserve-sdata?
+ ;; this is necessary because right now jadetex does not understand
+ ;; symbolic entities, whereas things work well with numeric entities.
+ "UNREGISTERED::James Clark//Characteristic::preserve-sdata?"
+ #f)
+
+(define %generate-article-toc%
+ ;; Should a Table of Contents be produced for Articles?
+ #t)
+
+(define (toc-depth nd)
+ 2)
+
+(define %generate-article-titlepage-on-separate-page%
+ ;; Should the article title page be on a separate page?
+ #t)
+
+(define %section-autolabel%
+ ;; Are sections enumerated?
+ #t)
+
+(define %footnote-ulinks%
+ ;; Generate footnotes for ULinks?
+ #f)
+
+(define %bop-footnotes%
+ ;; Make "bottom-of-page" footnotes?
+ #f)
+
+(define %body-start-indent%
+ ;; Default indent of body text
+ 0pi)
+
+(define %para-indent-firstpara%
+ ;; First line start-indent for the first paragraph
+ 0pt)
+
+(define %para-indent%
+ ;; First line start-indent for paragraphs (other than the first)
+ 0pt)
+
+(define %block-start-indent%
+ ;; Extra start-indent for block-elements
+ 0pt)
+
+(define formal-object-float
+ ;; Do formal objects float?
+ #t)
+
+(define %hyphenation%
+ ;; Allow automatic hyphenation?
+ #t)
+
+(define %admon-graphics%
+ ;; Use graphics in admonitions?
+ #f)
+
+</style-specification-body>
+</style-specification>
+
+
+<!--
+;; ===================================================
+;; customize the html stylesheet; borrowed from Cygnus
+;; at http://sourceware.cygnus.com/ (cygnus-both.dsl)
+;; ===================================================
+-->
+
+<style-specification id="html" use="docbook">
+<style-specification-body>
+
+(declare-characteristic preserve-sdata?
+ ;; this is necessary because right now jadetex does not understand
+ ;; symbolic entities, whereas things work well with numeric entities.
+ "UNREGISTERED::James Clark//Characteristic::preserve-sdata?"
+ #f)
+
+(define %generate-legalnotice-link%
+ ;; put the legal notice in a separate file
+ #t)
+
+(define %admon-graphics-path%
+ ;; use graphics in admonitions, set their
+ "../images/")
+
+(define %admon-graphics%
+ #f)
+
+(define %funcsynopsis-decoration%
+ ;; make funcsynopsis look pretty
+ #t)
+
+(define %html-ext%
+ ;; when producing HTML files, use this extension
+ ".html")
+
+(define %generate-book-toc%
+ ;; Should a Table of Contents be produced for books?
+ #t)
+
+(define %generate-article-toc%
+ ;; Should a Table of Contents be produced for articles?
+ #t)
+
+(define %generate-part-toc%
+ ;; Should a Table of Contents be produced for parts?
+ #t)
+
+(define %generate-book-titlepage%
+ ;; produce a title page for books
+ #t)
+
+(define %generate-article-titlepage%
+ ;; produce a title page for articles
+ #t)
+
+(define (chunk-skip-first-element-list)
+ ;; forces the Table of Contents on separate page
+ '())
+
+(define (list-element-list)
+ ;; fixes bug in Table of Contents generation
+ '())
+
+(define %root-filename%
+ ;; The filename of the root HTML document (e.g, "index").
+ "index")
+
+(define %shade-verbatim%
+ ;; verbatim sections will be shaded if t(rue)
+ #t)
+
+(define %use-id-as-filename%
+ ;; Use ID attributes as name for component HTML files?
+ #t)
+
+(define %graphic-extensions%
+ ;; graphic extensions allowed
+ '("gif" "png" "jpg" "jpeg" "tif" "tiff" "eps" "epsf" ))
+
+(define %graphic-default-extension%
+ "gif")
+
+(define %section-autolabel%
+ ;; For enumerated sections (1.1, 1.1.1, 1.2, etc.)
+ #t)
+
+(define (toc-depth nd)
+ ;; more depth (2 levels) to toc; instead of flat hierarchy
+ ;; 2)
+ 4)
+
+(element emphasis
+ ;; make role=strong equate to bold for emphasis tag
+ (if (equal? (attribute-string "role") "strong")
+ (make element gi: "STRONG" (process-children))
+ (make element gi: "EM" (process-children))))
+
+(define (book-titlepage-recto-elements)
+ ;; elements on a book's titlepage
+ ;; note: added revhistory to the default list
+ (list (normalize "title")
+ (normalize "subtitle")
+ (normalize "graphic")
+ (normalize "mediaobject")
+ (normalize "corpauthor")
+ (normalize "authorgroup")
+ (normalize "author")
+ (normalize "editor")
+ (normalize "copyright")
+ (normalize "revhistory")
+ (normalize "abstract")
+ (normalize "legalnotice")))
+
+(define (article-titlepage-recto-elements)
+ ;; elements on an article's titlepage
+ ;; note: added othercredit to the default list
+ (list (normalize "title")
+ (normalize "subtitle")
+ (normalize "authorgroup")
+ (normalize "author")
+ (normalize "othercredit")
+ (normalize "releaseinfo")
+ (normalize "copyright")
+ (normalize "pubdate")
+ (normalize "revhistory")
+ (normalize "abstract")))
+
+(mode article-titlepage-recto-mode
+
+ (element contrib
+ ;; print out with othercredit information; for translators, etc.
+ (make sequence
+ (make element gi: "SPAN"
+ attributes: (list (list "CLASS" (gi)))
+ (process-children))))
+
+ (element othercredit
+ ;; print out othercredit information; for translators, etc.
+ (let ((author-name (author-string))
+ (author-contrib (select-elements (children (current-node))
+ (normalize "contrib"))))
+ (make element gi: "P"
+ attributes: (list (list "CLASS" (gi)))
+ (make element gi: "B"
+ (literal author-name)
+ (literal " - "))
+ (process-node-list author-contrib))))
+)
+
+(define (article-title nd)
+ (let* ((artchild (children nd))
+ (artheader (select-elements artchild (normalize "artheader")))
+ (artinfo (select-elements artchild (normalize "articleinfo")))
+ (ahdr (if (node-list-empty? artheader)
+ artinfo
+ artheader))
+ (ahtitles (select-elements (children ahdr)
+ (normalize "title")))
+ (artitles (select-elements artchild (normalize "title")))
+ (titles (if (node-list-empty? artitles)
+ ahtitles
+ artitles)))
+ (if (node-list-empty? titles)
+ ""
+ (node-list-first titles))))
+
+
+</style-specification-body>
+</style-specification>
+
+<external-specification id="docbook" document="docbook.dsl">
+
+</style-sheet>
+
diff --git a/docs/htmldocs/CVS-Access.html b/docs/htmldocs/CVS-Access.html
new file mode 100644
index 00000000000..ea47cede040
--- /dev/null
+++ b/docs/htmldocs/CVS-Access.html
@@ -0,0 +1,193 @@
+<HTML
+><HEAD
+><TITLE
+>HOWTO Access Samba source code via CVS</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="ARTICLE"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><DIV
+CLASS="ARTICLE"
+><DIV
+CLASS="TITLEPAGE"
+><H1
+CLASS="TITLE"
+><A
+NAME="AEN1"
+>HOWTO Access Samba source code via CVS</A
+></H1
+><HR></DIV
+><DIV
+CLASS="SECT1"
+><H1
+CLASS="SECT1"
+><A
+NAME="AEN3"
+>Introduction</A
+></H1
+><P
+>Samba is developed in an open environnment. Developers use CVS
+(Concurrent Versioning System) to "checkin" (also known as
+"commit") new source code. Samba's various CVS branches can
+be accessed via anonymouns CVS using the instructions
+detailed in this chapter.</P
+><P
+>This document is a modified version of the instructions found at
+<A
+HREF="http://samba.org/samba/cvs.html"
+TARGET="_top"
+>http://samba.org/samba/cvs.html</A
+></P
+></DIV
+><DIV
+CLASS="SECT1"
+><HR><H1
+CLASS="SECT1"
+><A
+NAME="AEN8"
+>CVS Access to samba.org</A
+></H1
+><P
+>The machine samba.org runs a publicly accessible CVS
+repository for access to the source code of several packages,
+including samba, rsync and jitterbug. There are two main ways of
+accessing the CVS server on this host.</P
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN11"
+>Access via CVSweb</A
+></H2
+><P
+>You can access the source code via your
+favourite WWW browser. This allows you to access the contents of
+individual files in the repository and also to look at the revision
+history and commit logs of individual files. You can also ask for a diff
+listing between any two versions on the repository.</P
+><P
+>Use the URL : <A
+HREF="http://samba.org/cgi-bin/cvsweb"
+TARGET="_top"
+>http://samba.org/cgi-bin/cvsweb</A
+></P
+></DIV
+><DIV
+CLASS="SECT2"
+><HR><H2
+CLASS="SECT2"
+><A
+NAME="AEN16"
+>Access via cvs</A
+></H2
+><P
+>You can also access the source code via a
+normal cvs client. This gives you much more control over you can
+do with the repository and allows you to checkout whole source trees
+and keep them uptodate via normal cvs commands. This is the
+preferred method of access if you are a developer and not
+just a casual browser.</P
+><P
+>To download the latest cvs source code, point your
+browser at the URL : <A
+HREF="http://www.cyclic.com/"
+TARGET="_top"
+>http://www.cyclic.com/</A
+>.
+and click on the 'How to get cvs' link. CVS is free software under
+the GNU GPL (as is Samba). Note that there are several graphical CVS clients
+which provide a graphical interface to the sometimes mundane CVS commands.
+Links to theses clients are also available from http://www.cyclic.com.</P
+><P
+>To gain access via anonymous cvs use the following steps.
+For this example it is assumed that you want a copy of the
+samba source code. For the other source code repositories
+on this system just substitute the correct package name</P
+><P
+></P
+><OL
+TYPE="1"
+><LI
+><P
+> Install a recent copy of cvs. All you really need is a
+ copy of the cvs client binary.
+ </P
+></LI
+><LI
+><P
+> Run the command
+ </P
+><P
+> <B
+CLASS="COMMAND"
+>cvs -d :pserver:cvs@samba.org:/cvsroot login</B
+>
+ </P
+><P
+> When it asks you for a password type <TT
+CLASS="USERINPUT"
+><B
+>cvs</B
+></TT
+>.
+ </P
+></LI
+><LI
+><P
+> Run the command
+ </P
+><P
+> <B
+CLASS="COMMAND"
+>cvs -d :pserver:cvs@samba.org:/cvsroot co samba</B
+>
+ </P
+><P
+> This will create a directory called samba containing the
+ latest samba source code (i.e. the HEAD tagged cvs branch). This
+ currently corresponds to the 3.0 development tree.
+ </P
+><P
+> CVS branches other HEAD can be obtained by using the <TT
+CLASS="PARAMETER"
+><I
+>-r</I
+></TT
+>
+ and defining a tag name. A list of branch tag names can be found on the
+ "Development" page of the samba web site. A common request is to obtain the
+ latest 2.2 release code. This could be done by using the following command.
+ </P
+><P
+> <B
+CLASS="COMMAND"
+>cvs -d :pserver:cvs@samba.org:/cvsroot co -r SAMBA_2_2 samba</B
+>
+ </P
+></LI
+><LI
+><P
+> Whenever you want to merge in the latest code changes use
+ the following command from within the samba directory:
+ </P
+><P
+> <B
+CLASS="COMMAND"
+>cvs update -d -P</B
+>
+ </P
+></LI
+></OL
+></DIV
+></DIV
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/htmldocs/make_unicodemap.1.html b/docs/htmldocs/make_unicodemap.1.html
new file mode 100644
index 00000000000..a0b87406936
--- /dev/null
+++ b/docs/htmldocs/make_unicodemap.1.html
@@ -0,0 +1,276 @@
+<HTML
+><HEAD
+><TITLE
+>make_unicodemap</TITLE
+><META
+NAME="GENERATOR"
+CONTENT="Modular DocBook HTML Stylesheet Version 1.57"></HEAD
+><BODY
+CLASS="REFENTRY"
+BGCOLOR="#FFFFFF"
+TEXT="#000000"
+LINK="#0000FF"
+VLINK="#840084"
+ALINK="#0000FF"
+><H1
+><A
+NAME="MAKE-UNICODEMAP"
+>make_unicodemap</A
+></H1
+><DIV
+CLASS="REFNAMEDIV"
+><A
+NAME="AEN5"
+></A
+><H2
+>Name</H2
+>make_unicodemap&nbsp;--&nbsp;construct a unicode map file for Samba</DIV
+><DIV
+CLASS="REFSYNOPSISDIV"
+><A
+NAME="AEN8"
+></A
+><H2
+>Synopsis</H2
+><P
+><B
+CLASS="COMMAND"
+>make_unicodemap</B
+> {codepage} {inputfile} {outputfile}</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN14"
+></A
+><H2
+>DESCRIPTION</H2
+><P
+> This tool is part of the <A
+HREF="samba.7.html"
+TARGET="_top"
+>Samba</A
+>
+ suite.
+ </P
+><P
+> <B
+CLASS="COMMAND"
+>make_unicodemap</B
+> compiles text unicode map
+ files into binary unicodef map files for use with the
+ internationalization features of Samba 2.2.
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN20"
+></A
+><H2
+>OPTIONS</H2
+><P
+></P
+><DIV
+CLASS="VARIABLELIST"
+><DL
+><DT
+>codepage</DT
+><DD
+><P
+>This is the codepage or UNIX character
+ set we are processing (a number, e.g. 850).
+ </P
+></DD
+><DT
+>inputfile</DT
+><DD
+><P
+>This is the input file to process. This is a
+ text unicode map file such as the ones found in the Samba
+ <TT
+CLASS="FILENAME"
+>source/codepages</TT
+> directory.
+ </P
+></DD
+><DT
+>outputfile</DT
+><DD
+><P
+>This is the binary output file to produce.
+ </P
+></DD
+></DL
+></DIV
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN36"
+></A
+><H2
+>Samba Unicode Map Files</H2
+><P
+> A text Samba unicode map file is a description that tells Samba
+ how to map characters from a specified DOS code page or UNIX character
+ set to 16 bit unicode.
+ </P
+><P
+>A binary Samba unicode map file is a binary representation
+ of the same information, including a value that specifies what
+ codepage or UNIX character set this file is describing.
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN40"
+></A
+><H2
+>Files</H2
+><P
+><TT
+CLASS="FILENAME"
+>CP&#60;codepage&#62;.TXT</TT
+></P
+><P
+> These are the input (text) unicode map files provided
+ in the Samba <TT
+CLASS="FILENAME"
+>source/codepages</TT
+>
+ directory.
+ </P
+><P
+> A text unicode map file consists of multiple lines
+ containing two fields. These fields are :
+ </P
+><P
+></P
+><UL
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>character</I
+></TT
+> - which is
+ the (hex) character mapped on this line.
+ </P
+></LI
+><LI
+><P
+><TT
+CLASS="PARAMETER"
+><I
+>unicode</I
+></TT
+> - which
+ is the (hex) 16 bit unicode character that the character
+ will map to.
+ </P
+></LI
+></UL
+><P
+> <TT
+CLASS="FILENAME"
+>unicode_map.&#60;codepage&#62;</TT
+> - These are
+ the output (binary) unicode map files produced and placed in
+ the Samba destination <TT
+CLASS="FILENAME"
+>lib/codepage</TT
+>
+ directory.
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN57"
+></A
+><H2
+>Installation</H2
+><P
+> The location of the server and its support files is a matter
+ for individual system administrators. The following are thus
+ suggestions only.
+ </P
+><P
+> It is recommended that the <B
+CLASS="COMMAND"
+>make_unicodemap</B
+>
+ program be installed under the
+ <TT
+CLASS="FILENAME"
+>$prefix/samba</TT
+> hierarchy,
+ in a directory readable by all, writeable only by root. The
+ program itself should be executable by all. The program
+ should NOT be setuid or setgid!
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN63"
+></A
+><H2
+>VERSION</H2
+><P
+>This man page is correct for version 2.2 of
+ the Samba suite.</P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN66"
+></A
+><H2
+>SEE ALSO</H2
+><P
+><A
+HREF="smbd.8.html"
+TARGET="_top"
+><B
+CLASS="COMMAND"
+>smbd(8)</B
+></A
+>,
+ <A
+HREF="smb.conf.5.html"
+TARGET="_top"
+>smb.conf(5)</A
+>
+ </P
+></DIV
+><DIV
+CLASS="REFSECT1"
+><A
+NAME="AEN72"
+></A
+><H2
+>AUTHOR</H2
+><P
+>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.</P
+><P
+>The original Samba man pages were written by Karl Auer.
+ The man page sources were converted to YODL format (another
+ excellent piece of Open Source software, available at
+ <A
+HREF="ftp://ftp.icce.rug.nl/pub/unix/"
+TARGET="_top"
+> ftp://ftp.icce.rug.nl/pub/unix/</A
+>) and updated for the Samba 2.0
+ release by Jeremy Allison. The conversion to DocBook for
+ Samba 2.2 was done by Gerald Carter</P
+></DIV
+></BODY
+></HTML
+> \ No newline at end of file
diff --git a/docs/textdocs/outdated/NTDOMAIN.txt b/docs/textdocs/outdated/NTDOMAIN.txt
new file mode 100644
index 00000000000..8408acb979a
--- /dev/null
+++ b/docs/textdocs/outdated/NTDOMAIN.txt
@@ -0,0 +1,51 @@
+!==
+!== NTDOMAIN.txt for Samba release 2.0.4 18 May 1999
+!==
+Contributor: Luke Kenneth Casson Leighton (samba-bugs@samba.org)
+ Copyright (C) 1997 Luke Kenneth Casson Leighton
+Created: October 20, 1997
+Updated: February 25, 1999 (Jerry Carter)
+
+Subject: NT Domain Logons
+===========================================================================
+
+As of 1.9.18alpha1, Samba supports logins for NT 3.51 and 4.0 Workstations,
+without the need, use or intervention of NT Server. This document describes
+how to set this up. Over the continued development of the 1.9.18alpha
+series, this process (and therefore this document) should become simpler.
+
+One useful thing to do is to get this version of Samba up and running
+with Win95 profiles, as you would for the current stable version of
+Samba (currently at 1.9.17p4), and is fully documented. You will need
+to set up encrypted passwords. Even if you don't have any Win95 machines,
+using your Samba Server to store the profile for one of your NT Workstation
+users is a good test that you have 1.9.18alpha1 correctly configured *prior*
+to attempting NT Domain Logons.
+
+The support is still experimental, so should be used at your own risk.
+
+NT is not as robust as you might have been led to believe: during the
+development of the Domain Logon Support, one person reported having to
+reinstall NT from scratch: their workstation had become totally unuseable.
+
+[further reports on ntsec@iss.net by independent administrators showing
+ similar symptoms lead us to believe that the SAM database file may be
+ corruptible. this _is_ recoverable (or, at least the machine is accessible),
+ by deleting the SAM file, under which circumstances all user account details
+ are lost, but at least the Administrator can log in with a blank password.
+ this is *not* possible except if the NT system is installed in a FAT
+ partition.]
+
+This *has* been reported to the NTBUGTRAQ@LISTSERV.NTBUGTRAQ.COM digest.
+
+==========================================================================
+Please note that Samba 2.0 does not **officially** support domain logons
+for Windows NT clients. Of course, domain logon support for Windows 9x
+clients is complete and official. These are two different issues.
+
+Samba's capability to act as a Primary Domain Controller for Windows NT
+domains is not advertised as it is not completed yet. For more information
+regarding how to obtain the latest development (HEAD branch) source code
+and what features are available, please refer to the NT Domain FAQ on-line
+at the Samba web site under the documentation page.
+
diff --git a/docs/textdocs/outdated/PRINTER_DRIVER.txt b/docs/textdocs/outdated/PRINTER_DRIVER.txt
new file mode 100644
index 00000000000..5bf82e0cfe4
--- /dev/null
+++ b/docs/textdocs/outdated/PRINTER_DRIVER.txt
@@ -0,0 +1,240 @@
+!==
+!== PRINTER_DRIVER.txt for Samba release 2.0.4 18 May 1999
+!==
+==========================================================================
+ Supporting the famous PRINTER$ share
+
+ Jean-Francois.Micouleau@utc.fr, 10/26/97
+ modified by herb@sgi.com 1/2/98
+
+===========================================================================
+
+Disclaimer:
+
+ This ONLY works with Windows 95
+ It does NOT work with Windows NT 4
+
+
+Goal:
+
+ When you click on a samba shared printer, you can now install the driver
+ automatically onto the Windows 95 machine, as you would from an NT server.
+
+How To:
+
+ It's a three step config.
+
+ First, create a new directory, where you will put the driver files, and
+ make a share in smb.conf pointing to it.
+
+ Example:
+
+ [printer$]
+ path=/usr/local/samba/printer
+ public=yes
+ writable=no
+ browseable=yes
+
+ Second, you have to build the list of drivers required for a specific
+ printer. This is the most complicated thing to do. Get the files
+ 'msprint.inf' and 'msprint2.inf' from Windows 95, the easiest way is to
+ grab them from a working Windows 95 computer. They are usually located
+ in 'c:\windows\inf'. Look in them for the printer you have. Run the new
+ program 'make_printerdef' with the file name and the printer name as
+ parameters. If you have drivers for an unsupported or updated printer,
+ first install these drivers on an Windows 95 system. There will be a
+ file created in your inf directory named 'oem?.inf' (where the ? is some
+ number). Use this file instead of msprint.inf.
+
+ Example: (from the /usr/local/samba/lib directory)
+
+ make_printerdef msprint.inf "Apple LaserWriter" >> printers.def
+
+ The program will print out a list of required files to stderr.
+ Copy all the files listed into the directory you created in step 1.
+ If you have "preserve case = yes" make sure your files names match
+ EXACTLY the names listed.
+
+ Third, you need to add 2 new parameters in smb.conf. One is in the
+ [global] section, called 'printer driver file' pointing to the printer
+ description file you just created, and the other in each printer share,
+ called 'printer driver location' pointing to where the client will get
+ the drivers. Don't forget to set correctly the printer driver parameter
+ to the Windows printer name.
+
+ Example:
+
+ [global]
+ printer driver file=/usr/local/samba/lib/printers.def
+
+ [lp]
+ comment = My old printer laser
+ browseable = yes
+ printable = yes
+ public = yes
+ writable = no
+ create mode = 0700
+ printer driver=Apple LaserWriter
+ printer driver location=\\%h\PRINTER$
+
+ %h will expand to the computer name, and PRINTER$ is the name of the
+ share created in step one.
+
+
+If it doesn't work for you, don't send flame ! It worked for me. In case of
+trouble don't hesitate to send me a mail with your smb.conf file and
+printers.def
+
+
+******* added by herb@sgi.com
+
+For those of you who like to know the details, and in case I have guessed
+wrong on some of the fields - The following is the format of the entries
+in the printers.def file: (entries are 1 single line - they are split here
+for readability)
+
+<Long Printer Name>:<Driver File Name>:<Data File Name>:<Help File Name>:
+<Language Monitor Name>:<Default Data Type>:<Comma Separated list of Files>
+
+The <Help File Name> and the <Language Monitor Name> can be empty.
+If no <Driver File Name> or <Data File Name> are specified in the inf file,
+these will default to the section name for the printer.
+
+The following is an excerpt from the MSPRINT2.INF file on a WIN95 machine.
+I have deleted all but the entries relating to installing a driver for the
+"QMS ColorScript 100 Model 30" printer. Using this "file" I'll try to
+explain how the printers.def file is created.
+
+make_printerdef is run with the first argument being the name of this
+file (MSPRINT2.INF in this case) and the second argument being the
+name of the printer ("QMS ColorScript 100 Model 30" in this case).
+
+The printer name is first found in the "Model section" to obtain the
+name of the "Installer Section" (this is the name after the equal sign).
+We ignore the alternate name.
+
+The "Installer Section" contains entries for "CopyFiles" and "DataSection".
+The "CopyFiles" line gives a list of all the required files for this
+printer. If the name begins with an @ it is the name of a file (after
+you strip off the @), otherwise it is the name of a "Copy Section" which
+in turn is a list of files required. This printer has one file listed
+"QCS30503.SPD" and two sections "COLOR_QMS_100_30" and "PSCRIPT". The
+"COLOR_QMS_100_30" section is listed in the "[DestinationDirs]" as
+having a value of 23. This means that all files listed in this section
+should go into the "color" subdirectory. The list of files to copy for
+this printer is thus:
+
+QCS30503.SPD,color\QMS10030.ICM,PSCRIPT.DRV,PSCRIPT.HLP,PSCRIPT.INI,
+TESTPS.TXT,APPLE380.SPD,FONTS.MFM,ICONLIB.DLL,PSMON.DLL
+
+From the "Data Section" we obtain values for "DriverFile", "HelpFile",
+and "LanguageMonitor". The % around the value for "LanguageMonitor"
+indicates that it is a string that can be localized so its actual value
+is obtained from the "[Strings]" section. The "Data Section" could also
+have contained an entry for "DefaultDataType".
+
+Using the information we have obtained we can now construct the entry
+for the printers.def file.
+
+<Long Printer Name> -> QMS ColorScript 100 Model 30 (name given
+ on the command line)
+<Driver File Name> -> PSCRIPT.DRV (given in Data Section)
+<Data File Name> -> QCS30503.SPD (defaults to Install Section name)
+<Help File Name> -> PSCRIPT.HLP (given in Data Section)
+<Language Monitor Name> -> PostScript Language Monitor (given in Data Section)
+<Default Data Type> -> RAW (default if not specified)
+
+
+So.... the enty (actually one line but split here for readability) would
+be:
+
+QMS ColorScript 100 Model 30:PSCRIPT.DRV:QCS30503.SPD:
+PSCRIPT.HLP:PostScript Language Monitor:RAW:
+QCS30503.SPD,color\QMS10030.ICM,PSCRIPT.DRV,PSCRIPT.HLP,PSCRIPT.INI,
+TESTPS.TXT,APPLE380.SPD,FONTS.MFM,ICONLIB.DLL,PSMON.DLL
+
+---------------------- Info from MSPRINT2.INF ------------------------
+;
+; The Manufacturer section lists all of the manufacturers that we will
+; display in the Dialog box
+
+[Manufacturer]
+"QMS"
+
+
+;
+; Model sections. Each section here corresponds with an entry listed in the
+; [Manufacturer] section, above. The models will be displayed in the order
+; that they appear in the INF file.
+;
+; Each model lists a variation of its own name as a compatible ID. This
+; is done primarily as an optimization during upgrade.
+;
+[QMS]
+"QMS ColorScript 100 Model 30" = QCS30503.SPD,QMS_ColorScript_100_Model_30
+
+
+;
+; Installer Sections
+;
+; These sections control file installation, and reference all files that
+; need to be copied. The section name will be assumed to be the driver
+; file, unless there is an explicit DriverFile section listed.
+;
+[QCS30503.SPD]
+CopyFiles=@QCS30503.SPD,COLOR_QMS_100_30,PSCRIPT
+DataSection=PSCRIPT_DATA
+
+; Copy Sections
+;
+; Lists of files that are actually copied. These sections are referenced
+; from the installer sections, above. Only create a section if it contains
+; two or more files (if we only copy a single file, identify it in the
+; installer section, using the @filename notation) or if it's a color
+; profile (since the DestinationDirs can only handle sections, and not
+; individual files).
+;
+[COLOR_QMS_100_30]
+QMS10030.ICM
+
+[PSCRIPT]
+PSCRIPT.DRV
+PSCRIPT.HLP
+PSCRIPT.INI
+TESTPS.TXT
+APPLE380.SPD
+FONTS.MFM
+ICONLIB.DLL
+PSMON.DLL
+
+
+;
+; Data Sections
+;
+; These sections contain data that is shared between devices.
+;
+[PSCRIPT_DATA]
+DriverFile=PSCRIPT.DRV
+HelpFile=PSCRIPT.HLP
+LanguageMonitor=%PS_MONITOR%
+
+
+;
+; Color profiles go to the colors directory. All other files go to the
+; system directory
+;
+
+[DestinationDirs]
+DefaultDestDir=11
+COLOR_QMS_100_30=23
+COLOR_TEKTRONIX_200I=23
+COLOR_TEKTRONIX_III_PXI=23
+
+
+;
+; Localizable Strings
+;
+[Strings]
+MS="Microsoft"
+PS_MONITOR="PostScript Language Monitor,PSMON.DLL"
+
diff --git a/docs/textdocs/outdated/PROJECTS b/docs/textdocs/outdated/PROJECTS
new file mode 100644
index 00000000000..3008bea430d
--- /dev/null
+++ b/docs/textdocs/outdated/PROJECTS
@@ -0,0 +1,88 @@
+ Samba Projects Directory
+ ========================
+
+
+>>>>> NOTE: THIS FILE IS NOW VERY OUT OF DATE <<<<<
+
+
+This is a list of who's working on what in Samba. It's not guaranteed
+to be uptodate or accurate but I hope it will help us getting
+coordinated.
+
+If you are working on something to do with Samba and you aren't here
+then please let me know! Also, if you are listed below and you have
+any corrections or updates then please let me know.
+
+Email contact:
+samba-bugs@samba.org
+
+========================================================================
+Documentation and FAQ
+
+Docs and FAQ files for the Samba suite of software.
+
+Contact samba-bugs@samba.org with the diffs. These are urgently
+required.
+
+The FAQ is being added to on an ad hoc basis, see the web pages for info.
+
+Mark Preston was working on a set of formatted docs for Samba. Is this
+still happening? Contact mpreston@sghms.ac.uk
+
+Status last updated 2nd October 1996
+========================================================================
+
+========================================================================
+Netbeui support
+
+This aimed to produce patches so that Samba can be used with clients
+that do not have TCP/IP. It will try to remain as portable as possible.
+Contact Brian.Onn@Canada.Sun.COM (Brian Onn) Unfortunately it died, and
+although a lot of people have expressed interest nobody has come forward
+to do it. The Novell port (see Samba web pages) includes NetBEUI
+functionality in a proprietrary library which should still be helpful as
+we have the interfaces. Alan Cox (a.cox@li.org) has the information
+required to write the state machine if someone is going to do the work.
+
+Status last updated 2nd October 1996
+========================================================================
+
+========================================================================
+Smbfs
+
+A mountable smb filesystem for Linux using the userfs userspace filesystem
+
+Contact lendecke@namu01.gwdg.de (Volker Lendecke)
+
+This works really well, and is measurably more efficient than commercial
+client software. It is now part of the Linux kernel. Long filename support
+is in use.
+
+Status last updated June 1997
+========================================================================
+
+========================================================================
+Admin Tool
+
+Aims to produce a nice smb.conf editor and other useful tools for
+administering a Samba system.
+
+Contact: Steve Brown (steve@unicorn.dungeon.com)
+
+In the design phase.
+
+Status last updated 4th September 1994
+========================================================================
+
+
+========================================================================
+Lanman Client.
+
+Contact: john@amanda.xs4all.nl (John Stewart)
+
+Aims to produce a reliable LANMAN Client implementation for LINUX,
+and possibly other variations of UNIX. Project ably started by
+Tor Lillqvist; tml@hemuli.tte.vtt.fi
+
+Status last updated 17th January 1995
+========================================================================
diff --git a/examples/libsmbclient/testsmbc.c b/examples/libsmbclient/testsmbc.c
new file mode 100644
index 00000000000..7aae9d85616
--- /dev/null
+++ b/examples/libsmbclient/testsmbc.c
@@ -0,0 +1,456 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ SMB client library test program
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000
+ Copyright (C) John Terpsra 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <libsmbclient.h>
+
+void auth_fn(const char *server, const char *share,
+ char *workgroup, int wgmaxlen, char *username, int unmaxlen,
+ char *password, int pwmaxlen)
+{
+ char temp[128];
+
+ fprintf(stdout, "Need password for //%s/%s\n", server, share);
+
+ fprintf(stdout, "Enter workgroup: [%s] ", workgroup);
+ fgets(temp, sizeof(temp), stdin);
+
+ if (temp[strlen(temp) - 1] == 0x0a) /* A new line? */
+ temp[strlen(temp) - 1] = 0x00;
+
+ if (temp[0]) strncpy(workgroup, temp, wgmaxlen - 1);
+
+ fprintf(stdout, "Enter username: [%s] ", username);
+ fgets(temp, sizeof(temp), stdin);
+
+ if (temp[strlen(temp) - 1] == 0x0a) /* A new line? */
+ temp[strlen(temp) - 1] = 0x00;
+
+ if (temp[0]) strncpy(username, temp, unmaxlen - 1);
+
+ fprintf(stdout, "Enter password: [%s] ", password);
+ fgets(temp, sizeof(temp), stdin);
+
+ if (temp[strlen(temp) - 1] == 0x0a) /* A new line? */
+ temp[strlen(temp) - 1] = 0x00;
+
+ if (temp[0]) strncpy(password, temp, pwmaxlen - 1);
+
+}
+
+int global_id = 0;
+
+void print_list_fn(struct print_job_info *pji)
+{
+
+ fprintf(stdout, "Print job: ID: %u, Prio: %u, Size: %u, User: %s, Name: %s\n",
+ pji->id, pji->priority, pji->size, pji->user, pji->name);
+
+ global_id = pji->id;
+
+}
+
+int main(int argc, char *argv[])
+{
+ int err, fd, dh1, dh2, dh3, dsize, dirc;
+ const char *file = "smb://samba/public/testfile.txt";
+ const char *file2 = "smb://samba/public/testfile2.txt";
+ char buff[256];
+ char dirbuf[512];
+ char *dirp;
+ struct stat st1, st2;
+
+ err = smbc_init(auth_fn, 10); /* Initialize things */
+
+ if (err < 0) {
+
+ fprintf(stderr, "Initializing the smbclient library ...: %s\n", strerror(errno));
+
+ }
+
+ if (argc > 1) {
+
+ /* Try to list the print jobs ... */
+
+ if (smbc_list_print_jobs("smb://samba/pclp", print_list_fn) < 0) {
+
+ fprintf(stderr, "Could not list print jobs: %s, %d\n", strerror(errno), errno);
+ exit(1);
+
+ }
+
+ /* Try to delete the last job listed */
+
+ if (global_id > 0) {
+
+ fprintf(stdout, "Trying to delete print job %u\n", global_id);
+
+ if (smbc_unlink_print_job("smb://samba/pclp", global_id) < 0) {
+
+ fprintf(stderr, "Failed to unlink job id %u, %s, %u\n", global_id,
+ strerror(errno), errno);
+
+ exit(1);
+
+ }
+
+ }
+
+ /* Try to print a file ... */
+
+ if (smbc_print_file("smb://samba/public/testfile2.txt", "smb://samba/pclp") < 0) {
+
+ fprintf(stderr, "Failed to print job: %s %u\n", strerror(errno), errno);
+ exit(1);
+
+ }
+
+ /* Try to delete argv[1] as a file ... */
+
+ if (smbc_unlink(argv[1]) < 0) {
+
+ fprintf(stderr, "Could not unlink: %s, %s, %d\n",
+ argv[1], strerror(errno), errno);
+
+ exit(0);
+
+ }
+
+ if ((dh1 = smbc_opendir("smb://"))<1) {
+
+ fprintf(stderr, "Could not open directory: smb://: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ if ((dh2 = smbc_opendir("smb://sambanet")) < 0) {
+
+ fprintf(stderr, "Could not open directory: smb://sambanet: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ if ((dh3 = smbc_opendir("smb://samba")) < 0) {
+
+ fprintf(stderr, "Could not open directory: smb://samba: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ fprintf(stdout, "Directory handles: %u, %u, %u\n", dh1, dh2, dh3);
+
+ /* Now, list those directories, but in funny ways ... */
+
+ dirp = (char *)dirbuf;
+
+ if ((dirc = smbc_getdents(dh1, (struct smbc_dirent *)dirp,
+ sizeof(dirbuf))) < 0) {
+
+ fprintf(stderr, "Problems getting directory entries: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ /* Now, process the list of names ... */
+
+ fprintf(stdout, "Directory listing, size = %u\n", dirc);
+
+ while (dirc > 0) {
+
+ dsize = ((struct smbc_dirent *)dirp)->dirlen;
+ fprintf(stdout, "Dir Ent, Type: %u, Name: %s, Comment: %s\n",
+ ((struct smbc_dirent *)dirp)->smbc_type,
+ ((struct smbc_dirent *)dirp)->name,
+ ((struct smbc_dirent *)dirp)->comment);
+
+ dirp += dsize;
+ (char *)dirc -= dsize;
+
+ }
+
+ dirp = (char *)dirbuf;
+
+ if ((dirc = smbc_getdents(dh2, (struct smbc_dirent *)dirp,
+ sizeof(dirbuf))) < 0) {
+
+ fprintf(stderr, "Problems getting directory entries: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ /* Now, process the list of names ... */
+
+ fprintf(stdout, "\nDirectory listing, size = %u\n", dirc);
+
+ while (dirc > 0) {
+
+ dsize = ((struct smbc_dirent *)dirp)->dirlen;
+ fprintf(stdout, "Dir Ent, Type: %u, Name: %s, Comment: %s\n",
+ ((struct smbc_dirent *)dirp)->smbc_type,
+ ((struct smbc_dirent *)dirp)->name,
+ ((struct smbc_dirent *)dirp)->comment);
+
+ dirp += dsize;
+ (char *)dirc -= dsize;
+
+ }
+
+ dirp = (char *)dirbuf;
+
+ if ((dirc = smbc_getdents(dh3, (struct smbc_dirent *)dirp,
+ sizeof(dirbuf))) < 0) {
+
+ fprintf(stderr, "Problems getting directory entries: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ /* Now, process the list of names ... */
+
+ fprintf(stdout, "Directory listing, size = %u\n", dirc);
+
+ while (dirc > 0) {
+
+ dsize = ((struct smbc_dirent *)dirp)->dirlen;
+ fprintf(stdout, "\nDir Ent, Type: %u, Name: %s, Comment: %s\n",
+ ((struct smbc_dirent *)dirp)->smbc_type,
+ ((struct smbc_dirent *)dirp)->name,
+ ((struct smbc_dirent *)dirp)->comment);
+
+ (char *)dirp += dsize;
+ (char *)dirc -= dsize;
+
+ }
+
+ exit(1);
+
+ }
+
+ /* For now, open a file on a server that is hard coded ... later will
+ * read from the command line ...
+ */
+
+ fd = smbc_open(file, O_RDWR | O_CREAT | O_TRUNC, 0666);
+
+ if (fd < 0) {
+
+ fprintf(stderr, "Creating file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Opened or created file: %s\n", file);
+
+ /* Now, write some date to the file ... */
+
+ bzero(buff, sizeof(buff));
+ strcpy(buff, "Some test data for the moment ...");
+
+ err = smbc_write(fd, buff, sizeof(buff));
+
+ if (err < 0) {
+
+ fprintf(stderr, "writing file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Wrote %d bytes to file: %s\n", sizeof(buff), buff);
+
+ /* Now, seek the file back to offset 0 */
+
+ err = smbc_lseek(fd, SEEK_SET, 0);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Seeking file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Completed lseek on file: %s\n", file);
+
+ /* Now, read the file contents back ... */
+
+ err = smbc_read(fd, buff, sizeof(buff));
+
+ if (err < 0) {
+
+ fprintf(stderr, "Reading file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Read file: %s\n", buff); /* Should check the contents */
+
+ fprintf(stdout, "Now fstat'ing file: %s\n", file);
+
+ err = smbc_fstat(fd, &st1);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Fstat'ing file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+
+ /* Now, close the file ... */
+
+ err = smbc_close(fd);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Closing file: %s: %s\n", file, strerror(errno));
+
+ }
+
+ /* Now, rename the file ... */
+
+ err = smbc_rename(file, file2);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Renaming file: %s to %s: %s\n", file, file2, strerror(errno));
+
+ }
+
+ fprintf(stdout, "Renamed file %s to %s\n", file, file2);
+
+ /* Now, create a file and delete it ... */
+
+ fprintf(stdout, "Now, creating file: %s so we can delete it.\n", file);
+
+ fd = smbc_open(file, O_RDWR | O_CREAT, 0666);
+
+ if (fd < 0) {
+
+ fprintf(stderr, "Creating file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Opened or created file: %s\n", file);
+
+ err = smbc_close(fd);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Closing file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ /* Now, delete the file ... */
+
+ fprintf(stdout, "File %s created, now deleting ...\n", file);
+
+ err = smbc_unlink(file);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Deleting file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ /* Now, stat the file, file 2 ... */
+
+ fprintf(stdout, "Now stat'ing file: %s\n", file);
+
+ err = smbc_stat(file2, &st2);
+
+ if (err < 0) {
+
+ fprintf(stderr, "Stat'ing file: %s: %s\n", file, strerror(errno));
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Stat'ed file: %s. Size = %d, mode = %04X\n", file2,
+ (int)st2.st_size, st2.st_mode);
+ fprintf(stdout, " time: %s\n", ctime(&st2.st_atime));
+ fprintf(stdout, "Earlier stat: %s, Size = %d, mode = %04X\n", file,
+ (int)st1.st_size, st1.st_mode);
+ fprintf(stdout, " time: %s\n", ctime(&st1.st_atime));
+
+ /* Now, make a directory ... */
+
+ fprintf(stdout, "Making directory smb://samba/public/make-dir\n");
+
+ if (smbc_mkdir("smb://samba/public/make-dir", 0666) < 0) {
+
+ fprintf(stderr, "Error making directory: smb://samba/public/make-dir: %s\n",
+ strerror(errno));
+
+ if (errno == EEXIST) { /* Try to delete the directory */
+
+ fprintf(stdout, "Trying to delete directory: smb://samba/public/make-dir\n");
+
+ if (smbc_rmdir("smb://samba/public/make-dir") < 0) { /* Error */
+
+ fprintf(stderr, "Error removing directory: smb://samba/public/make-dir: %s\n", strerror(errno));
+
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Making directory: smb://samba/public/make-dir\n");
+
+ if (smbc_mkdir("smb://samba/public/make-dir", 666) < 0) {
+
+ fprintf(stderr, "Error making directory: smb://samba/public/make-dir: %s\n",
+ strerror(errno));
+
+ fprintf(stderr, "I give up!\n");
+
+ exit(1);
+
+ }
+
+ }
+
+ exit(0);
+
+ }
+
+ fprintf(stdout, "Made dir: make-dir\n");
+ return 0;
+}
diff --git a/examples/libsmbclient/tree.c b/examples/libsmbclient/tree.c
new file mode 100644
index 00000000000..da60236e601
--- /dev/null
+++ b/examples/libsmbclient/tree.c
@@ -0,0 +1,812 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ SMB client GTK+ tree-based application
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2001
+ Copyright (C) John Terpstra 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.
+*/
+
+/* example-gtk+ application, ripped off from the gtk+ tree.c sample */
+
+#include <stdio.h>
+#include <errno.h>
+#include <gtk/gtk.h>
+#include "libsmbclient.h"
+
+static GtkWidget *clist;
+
+struct tree_data {
+
+ guint32 type; /* Type of tree item, an SMBC_TYPE */
+ char name[256]; /* May need to change this later */
+
+};
+
+void error_message(gchar *message) {
+
+ GtkWidget *dialog, *label, *okay_button;
+
+ /* Create the widgets */
+
+ dialog = gtk_dialog_new();
+ gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
+ label = gtk_label_new (message);
+ okay_button = gtk_button_new_with_label("Okay");
+
+ /* Ensure that the dialog box is destroyed when the user clicks ok. */
+
+ gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked",
+ GTK_SIGNAL_FUNC (gtk_widget_destroy), dialog);
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
+ okay_button);
+
+ /* Add the label, and show everything we've added to the dialog. */
+
+ gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
+ label);
+ gtk_widget_show_all (dialog);
+}
+
+/*
+ * We are given a widget, and we want to retrieve its URL so we
+ * can do a directory listing.
+ *
+ * We walk back up the tree, picking up pieces until we hit a server or
+ * workgroup type and return a path from there
+ */
+
+static char path_string[1024];
+
+char *get_path(GtkWidget *item)
+{
+ GtkWidget *p = item;
+ struct tree_data *pd;
+ char *comps[1024]; /* We keep pointers to the components here */
+ int i = 0, j, level,type;
+
+ /* Walk back up the tree, getting the private data */
+
+ level = GTK_TREE(item->parent)->level;
+
+ /* Pick up this item's component info */
+
+ pd = (struct tree_data *)gtk_object_get_user_data(GTK_OBJECT(item));
+
+ comps[i++] = pd->name;
+ type = pd->type;
+
+ while (level > 0 && type != SMBC_SERVER && type != SMBC_WORKGROUP) {
+
+ /* Find the parent and extract the data etc ... */
+
+ p = GTK_WIDGET(p->parent);
+ p = GTK_WIDGET(GTK_TREE(p)->tree_owner);
+
+ pd = (struct tree_data *)gtk_object_get_user_data(GTK_OBJECT(p));
+
+ level = GTK_TREE(item->parent)->level;
+
+ comps[i++] = pd->name;
+ type = pd->type;
+
+ }
+
+ /*
+ * Got a list of comps now, should check that we did not hit a workgroup
+ * when we got other things as well ... Later
+ *
+ * Now, build the path
+ */
+
+ snprintf(path_string, sizeof(path_string), "smb:/");
+
+ for (j = i - 1; j >= 0; j--) {
+
+ strncat(path_string, "/", sizeof(path_string) - strlen(path_string));
+ strncat(path_string, comps[j], sizeof(path_string) - strlen(path_string));
+
+ }
+
+ fprintf(stdout, "Path string = %s\n", path_string);
+
+ return path_string;
+
+}
+
+struct tree_data *make_tree_data(guint32 type, const char *name)
+{
+ struct tree_data *p = (struct tree_data *)malloc(sizeof(struct tree_data));
+
+ if (p) {
+
+ p->type = type;
+ strncpy(p->name, name, sizeof(p->name));
+
+ }
+
+ return p;
+
+}
+
+/* Note that this is called every time the user clicks on an item,
+ whether it is already selected or not. */
+static void cb_select_child (GtkWidget *root_tree, GtkWidget *child,
+ GtkWidget *subtree)
+{
+ gint dh, err, dirlen;
+ char dirbuf[512];
+ struct smbc_dirent *dirp;
+ struct stat st1;
+ char path[1024], path1[1024];
+
+ g_print ("select_child called for root tree %p, subtree %p, child %p\n",
+ root_tree, subtree, child);
+
+ /* Now, figure out what it is, and display it in the clist ... */
+
+ gtk_clist_clear(GTK_CLIST(clist)); /* Clear the CLIST */
+
+ /* Now, get the private data for the subtree */
+
+ strncpy(path, get_path(child), 1024);
+
+ if ((dh = smbc_opendir(path)) < 0) { /* Handle error */
+
+ g_print("cb_select_child: Could not open dir %s, %s\n", path,
+ strerror(errno));
+
+ gtk_main_quit();
+
+ return;
+
+ }
+
+ while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf,
+ sizeof(dirbuf))) != 0) {
+
+ if (err < 0) {
+
+ g_print("cb_select_child: Could not read dir %s, %s\n", path,
+ strerror(errno));
+
+ gtk_main_quit();
+
+ return;
+
+ }
+
+ dirp = (struct smbc_dirent *)dirbuf;
+
+ while (err > 0) {
+ gchar col1[128], col2[128], col3[128], col4[128];
+ gchar *rowdata[4] = {col1, col2, col3, col4};
+
+ dirlen = dirp->dirlen;
+
+ /* Format each of the items ... */
+
+ strncpy(col1, dirp->name, 128);
+
+ col2[0] = col3[0] = col4[0] = (char)0;
+
+ switch (dirp->smbc_type) {
+
+ case SMBC_WORKGROUP:
+
+ break;
+
+ case SMBC_SERVER:
+
+ strncpy(col2, (dirp->comment?dirp->comment:""), 128);
+
+ break;
+
+ case SMBC_FILE_SHARE:
+
+ strncpy(col2, (dirp->comment?dirp->comment:""), 128);
+
+ break;
+
+ case SMBC_PRINTER_SHARE:
+
+ strncpy(col2, (dirp->comment?dirp->comment:""), 128);
+ break;
+
+ case SMBC_COMMS_SHARE:
+
+ break;
+
+ case SMBC_IPC_SHARE:
+
+ break;
+
+ case SMBC_DIR:
+ case SMBC_FILE:
+
+ /* Get stats on the file/dir and see what we have */
+
+ if ((strcmp(dirp->name, ".") != 0) &&
+ (strcmp(dirp->name, "..") != 0)) {
+
+ strncpy(path1, path, sizeof(path1));
+ strncat(path1, "/", sizeof(path) - strlen(path));
+ strncat(path1, dirp->name, sizeof(path) - strlen(path));
+
+ if (smbc_stat(path1, &st1) < 0) {
+
+ if (errno != EBUSY) {
+
+ g_print("cb_select_child: Could not stat file %s, %s\n", path1,
+ strerror(errno));
+
+ gtk_main_quit();
+
+ return;
+
+ }
+ else {
+
+ strncpy(col2, "Device or resource busy", sizeof(col2));
+
+ }
+ }
+ else {
+ /* Now format each of the relevant things ... */
+
+ snprintf(col2, sizeof(col2), "%c%c%c%c%c%c%c%c%c(%0X)",
+ (st1.st_mode&S_IRUSR?'r':'-'),
+ (st1.st_mode&S_IWUSR?'w':'-'),
+ (st1.st_mode&S_IXUSR?'x':'-'),
+ (st1.st_mode&S_IRGRP?'r':'-'),
+ (st1.st_mode&S_IWGRP?'w':'-'),
+ (st1.st_mode&S_IXGRP?'x':'-'),
+ (st1.st_mode&S_IROTH?'r':'-'),
+ (st1.st_mode&S_IWOTH?'w':'-'),
+ (st1.st_mode&S_IXOTH?'x':'-'),
+ st1.st_mode);
+ snprintf(col3, sizeof(col3), "%u", st1.st_size);
+ snprintf(col4, sizeof(col4), "%s", ctime(&st1.st_mtime));
+ }
+ }
+
+ break;
+
+ default:
+
+ break;
+ }
+
+ gtk_clist_append(GTK_CLIST(clist), rowdata);
+
+ (char *)dirp += dirlen;
+ err -= dirlen;
+
+ }
+
+ }
+
+}
+
+/* Note that this is never called */
+static void cb_unselect_child( GtkWidget *root_tree,
+ GtkWidget *child,
+ GtkWidget *subtree )
+{
+ g_print ("unselect_child called for root tree %p, subtree %p, child %p\n",
+ root_tree, subtree, child);
+}
+
+/* for all the GtkItem:: and GtkTreeItem:: signals */
+static void cb_itemsignal( GtkWidget *item,
+ gchar *signame )
+{
+ GtkWidget *real_tree, *aitem, *subtree;
+ gchar *name;
+ GtkLabel *label;
+ gint dh, err, dirlen, level;
+ char dirbuf[512];
+ struct smbc_dirent *dirp;
+
+ label = GTK_LABEL (GTK_BIN (item)->child);
+ /* Get the text of the label */
+ gtk_label_get (label, &name);
+
+ level = GTK_TREE(item->parent)->level;
+
+ /* Get the level of the tree which the item is in */
+ g_print ("%s called for item %s->%p, level %d\n", signame, name,
+ item, GTK_TREE (item->parent)->level);
+
+ real_tree = GTK_TREE_ITEM_SUBTREE(item); /* Get the subtree */
+
+ if (strncmp(signame, "expand", 6) == 0) { /* Expand called */
+ char server[128];
+
+ if ((dh = smbc_opendir(get_path(item))) < 0) { /* Handle error */
+ gchar errmsg[256];
+
+ g_print("cb_itemsignal: Could not open dir %s, %s\n", get_path(item),
+ strerror(errno));
+
+ snprintf(errmsg, sizeof(errmsg), "cb_itemsignal: Could not open dir %s, %s\n", get_path(item), strerror(errno));
+
+ error_message(errmsg);
+
+ /* gtk_main_quit();*/
+
+ return;
+
+ }
+
+ while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf,
+ sizeof(dirbuf))) != 0) {
+
+ if (err < 0) { /* An error, report it */
+ gchar errmsg[256];
+
+ g_print("cb_itemsignal: Could not read dir smbc://, %s\n",
+ strerror(errno));
+
+ snprintf(errmsg, sizeof(errmsg), "cb_itemsignal: Could not read dir smbc://, %s\n", strerror(errno));
+
+ error_message(errmsg);
+
+ /* gtk_main_quit();*/
+
+ return;
+
+ }
+
+ dirp = (struct smbc_dirent *)dirbuf;
+
+ while (err > 0) {
+ struct tree_data *my_data;
+
+ dirlen = dirp->dirlen;
+
+ my_data = make_tree_data(dirp->smbc_type, dirp->name);
+
+ if (!my_data) {
+
+ g_print("Could not allocate space for tree_data: %s\n",
+ dirp->name);
+
+ gtk_main_quit();
+ return;
+
+ }
+
+ aitem = gtk_tree_item_new_with_label(dirp->name);
+
+ /* Connect all GtkItem:: and GtkTreeItem:: signals */
+ gtk_signal_connect (GTK_OBJECT(aitem), "select",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+ gtk_signal_connect (GTK_OBJECT(aitem), "deselect",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+ gtk_signal_connect (GTK_OBJECT(aitem), "toggle",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+ gtk_signal_connect (GTK_OBJECT(aitem), "expand",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
+ gtk_signal_connect (GTK_OBJECT(aitem), "collapse",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
+ /* Add it to the parent tree */
+ gtk_tree_append (GTK_TREE(real_tree), aitem);
+
+ gtk_widget_show (aitem);
+
+ gtk_object_set_user_data(GTK_OBJECT(aitem), (gpointer)my_data);
+
+ fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen);
+
+ if (dirp->smbc_type != SMBC_FILE &&
+ dirp->smbc_type != SMBC_IPC_SHARE &&
+ (strcmp(dirp->name, ".") != 0) &&
+ (strcmp(dirp->name, "..") !=0)){
+
+ subtree = gtk_tree_new();
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(aitem), subtree);
+
+ gtk_signal_connect(GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), real_tree);
+ gtk_signal_connect(GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), real_tree);
+
+ }
+
+ (char *)dirp += dirlen;
+ err -= dirlen;
+
+ }
+
+ }
+
+ smbc_closedir(dh);
+
+ }
+ else if (strncmp(signame, "collapse", 8) == 0) {
+ GtkWidget *subtree = gtk_tree_new();
+
+ gtk_tree_remove_items(GTK_TREE(real_tree), GTK_TREE(real_tree)->children);
+
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree);
+
+ gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), real_tree);
+ gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), real_tree);
+
+ }
+
+}
+
+static void cb_selection_changed( GtkWidget *tree )
+{
+ GList *i;
+
+ g_print ("selection_change called for tree %p\n", tree);
+ g_print ("selected objects are:\n");
+
+ i = GTK_TREE_SELECTION(tree);
+ while (i){
+ gchar *name;
+ GtkLabel *label;
+ GtkWidget *item;
+
+ /* Get a GtkWidget pointer from the list node */
+ item = GTK_WIDGET (i->data);
+ label = GTK_LABEL (GTK_BIN (item)->child);
+ gtk_label_get (label, &name);
+ g_print ("\t%s on level %d\n", name, GTK_TREE
+ (item->parent)->level);
+ i = i->next;
+ }
+}
+
+/*
+ * Expand or collapse the whole network ...
+ */
+static void cb_wholenet(GtkWidget *item, gchar *signame)
+{
+ GtkWidget *real_tree, *aitem, *subtree;
+ gchar *name;
+ GtkLabel *label;
+ gint dh, err, dirlen;
+ char dirbuf[512];
+ struct smbc_dirent *dirp;
+
+ label = GTK_LABEL (GTK_BIN (item)->child);
+ gtk_label_get (label, &name);
+ g_print ("%s called for item %s->%p, level %d\n", signame, name,
+ item, GTK_TREE (item->parent)->level);
+
+ real_tree = GTK_TREE_ITEM_SUBTREE(item); /* Get the subtree */
+
+ if (strncmp(signame, "expand", 6) == 0) { /* Expand called */
+
+ if ((dh = smbc_opendir("smb://")) < 0) { /* Handle error */
+
+ g_print("cb_wholenet: Could not open dir smbc://, %s\n",
+ strerror(errno));
+
+ gtk_main_quit();
+
+ return;
+
+ }
+
+ while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf,
+ sizeof(dirbuf))) != 0) {
+
+ if (err < 0) { /* An error, report it */
+
+ g_print("cb_wholenet: Could not read dir smbc://, %s\n",
+ strerror(errno));
+
+ gtk_main_quit();
+
+ return;
+
+ }
+
+ dirp = (struct smbc_dirent *)dirbuf;
+
+ while (err > 0) {
+ struct tree_data *my_data;
+
+ dirlen = dirp->dirlen;
+
+ my_data = make_tree_data(dirp->smbc_type, dirp->name);
+
+ aitem = gtk_tree_item_new_with_label(dirp->name);
+
+ /* Connect all GtkItem:: and GtkTreeItem:: signals */
+ gtk_signal_connect (GTK_OBJECT(aitem), "select",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+ gtk_signal_connect (GTK_OBJECT(aitem), "deselect",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+ gtk_signal_connect (GTK_OBJECT(aitem), "toggle",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+ gtk_signal_connect (GTK_OBJECT(aitem), "expand",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
+ gtk_signal_connect (GTK_OBJECT(aitem), "collapse",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
+
+ gtk_tree_append (GTK_TREE(real_tree), aitem);
+ /* Show it - this can be done at any time */
+ gtk_widget_show (aitem);
+
+ gtk_object_set_user_data(GTK_OBJECT(aitem), (gpointer)my_data);
+
+ fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen);
+
+ subtree = gtk_tree_new();
+
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(aitem), subtree);
+
+ gtk_signal_connect(GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), real_tree);
+ gtk_signal_connect(GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), real_tree);
+
+ (char *)dirp += dirlen;
+ err -= dirlen;
+
+ }
+
+ }
+
+ smbc_closedir(dh);
+
+ }
+ else { /* Must be collapse ... FIXME ... */
+ GtkWidget *subtree = gtk_tree_new();
+
+ gtk_tree_remove_items(GTK_TREE(real_tree), GTK_TREE(real_tree)->children);
+
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree);
+
+ gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), real_tree);
+ gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), real_tree);
+
+
+ }
+
+}
+
+/* Should put up a dialog box to ask the user for username and password */
+
+static void
+auth_fn(const char *server, const char *share,
+ char *workgroup, int wgmaxlen, char *username, int unmaxlen,
+ char *password, int pwmaxlen)
+{
+
+ strncpy(username, "test", unmaxlen);
+ strncpy(password, "test", pwmaxlen);
+
+}
+
+static char *col_titles[] = {
+ "Name", "Attributes", "Size", "Modification Date",
+};
+
+int main( int argc,
+ char *argv[] )
+{
+ GtkWidget *window, *scrolled_win, *scrolled_win2, *tree;
+ GtkWidget *subtree, *item, *main_hbox, *r_pane, *l_pane;
+ gint err, dh;
+ gint i;
+ char dirbuf[512];
+ struct smbc_dirent *dirp;
+
+ gtk_init (&argc, &argv);
+
+ /* Init the smbclient library */
+
+ err = smbc_init(auth_fn, 10);
+
+ /* Print an error response ... */
+
+ if (err < 0) {
+
+ fprintf(stderr, "smbc_init returned %s (%i)\nDo you have a ~/.smb/smb.conf file?\n", strerror(errno), errno);
+ exit(1);
+
+ }
+
+ /* a generic toplevel window */
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_widget_set_name(window, "main browser window");
+ gtk_signal_connect (GTK_OBJECT(window), "delete_event",
+ GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+ gtk_window_set_title(GTK_WINDOW(window), "The Linux Windows Network Browser");
+ gtk_widget_set_usize(GTK_WIDGET(window), 750, -1);
+ gtk_container_set_border_width (GTK_CONTAINER(window), 5);
+
+ gtk_widget_show (window);
+
+ /* A container for the two panes ... */
+
+ main_hbox = gtk_hbox_new(FALSE, 1);
+ gtk_container_border_width(GTK_CONTAINER(main_hbox), 1);
+ gtk_container_add(GTK_CONTAINER(window), main_hbox);
+
+ gtk_widget_show(main_hbox);
+
+ l_pane = gtk_hpaned_new();
+ gtk_paned_gutter_size(GTK_PANED(l_pane), (GTK_PANED(l_pane))->handle_size);
+ r_pane = gtk_hpaned_new();
+ gtk_paned_gutter_size(GTK_PANED(r_pane), (GTK_PANED(r_pane))->handle_size);
+ gtk_container_add(GTK_CONTAINER(main_hbox), l_pane);
+ gtk_widget_show(l_pane);
+
+ /* A generic scrolled window */
+ scrolled_win = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_widget_set_usize (scrolled_win, 150, 200);
+ gtk_container_add (GTK_CONTAINER(l_pane), scrolled_win);
+ gtk_widget_show (scrolled_win);
+
+ /* Another generic scrolled window */
+ scrolled_win2 = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win2),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_widget_set_usize (scrolled_win2, 150, 200);
+ gtk_paned_add2 (GTK_PANED(l_pane), scrolled_win2);
+ gtk_widget_show (scrolled_win2);
+
+ /* Create the root tree */
+ tree = gtk_tree_new();
+ g_print ("root tree is %p\n", tree);
+ /* connect all GtkTree:: signals */
+ gtk_signal_connect (GTK_OBJECT(tree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), tree);
+ gtk_signal_connect (GTK_OBJECT(tree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), tree);
+ gtk_signal_connect (GTK_OBJECT(tree), "selection_changed",
+ GTK_SIGNAL_FUNC(cb_selection_changed), tree);
+ /* Add it to the scrolled window */
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW(scrolled_win),
+ tree);
+ /* Set the selection mode */
+ gtk_tree_set_selection_mode (GTK_TREE(tree),
+ GTK_SELECTION_MULTIPLE);
+ /* Show it */
+ gtk_widget_show (tree);
+
+ /* Now, create a clist and attach it to the second pane */
+
+ clist = gtk_clist_new_with_titles(4, col_titles);
+
+ gtk_container_add (GTK_CONTAINER(scrolled_win2), clist);
+
+ gtk_widget_show(clist);
+
+ /* Now, build the top level display ... */
+
+ if ((dh = smbc_opendir("smb:///")) < 0) {
+
+ fprintf(stderr, "Could not list default workgroup: smb:///: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ /* Create a tree item for Whole Network */
+
+ item = gtk_tree_item_new_with_label ("Whole Network");
+ /* Connect all GtkItem:: and GtkTreeItem:: signals */
+ gtk_signal_connect (GTK_OBJECT(item), "select",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+ gtk_signal_connect (GTK_OBJECT(item), "deselect",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+ gtk_signal_connect (GTK_OBJECT(item), "toggle",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+ gtk_signal_connect (GTK_OBJECT(item), "expand",
+ GTK_SIGNAL_FUNC(cb_wholenet), "expand");
+ gtk_signal_connect (GTK_OBJECT(item), "collapse",
+ GTK_SIGNAL_FUNC(cb_wholenet), "collapse");
+ /* Add it to the parent tree */
+ gtk_tree_append (GTK_TREE(tree), item);
+ /* Show it - this can be done at any time */
+ gtk_widget_show (item);
+
+ subtree = gtk_tree_new(); /* A subtree for Whole Network */
+
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree);
+
+ gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), tree);
+ gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), tree);
+
+ /* Now, get the items in smb:/// and add them to the tree */
+
+ dirp = (struct smbc_dirent *)dirbuf;
+
+ while ((err = smbc_getdents(dh, (struct smbc_dirent *)dirbuf,
+ sizeof(dirbuf))) != 0) {
+
+ if (err < 0) { /* Handle the error */
+
+ fprintf(stderr, "Could not read directory for smbc:///: %s\n",
+ strerror(errno));
+
+ exit(1);
+
+ }
+
+ fprintf(stdout, "Dir len: %u\n", err);
+
+ while (err > 0) { /* Extract each entry and make a sub-tree */
+ struct tree_data *my_data;
+ int dirlen = dirp->dirlen;
+
+ my_data = make_tree_data(dirp->smbc_type, dirp->name);
+
+ item = gtk_tree_item_new_with_label(dirp->name);
+ /* Connect all GtkItem:: and GtkTreeItem:: signals */
+ gtk_signal_connect (GTK_OBJECT(item), "select",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+ gtk_signal_connect (GTK_OBJECT(item), "deselect",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+ gtk_signal_connect (GTK_OBJECT(item), "toggle",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+ gtk_signal_connect (GTK_OBJECT(item), "expand",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
+ gtk_signal_connect (GTK_OBJECT(item), "collapse",
+ GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
+ /* Add it to the parent tree */
+ gtk_tree_append (GTK_TREE(tree), item);
+ /* Show it - this can be done at any time */
+ gtk_widget_show (item);
+
+ gtk_object_set_user_data(GTK_OBJECT(item), (gpointer)my_data);
+
+ fprintf(stdout, "Added: %s, len: %u\n", dirp->name, dirlen);
+
+ subtree = gtk_tree_new();
+
+ gtk_tree_item_set_subtree(GTK_TREE_ITEM(item), subtree);
+
+ gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
+ GTK_SIGNAL_FUNC(cb_select_child), tree);
+ gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
+ GTK_SIGNAL_FUNC(cb_unselect_child), tree);
+
+ (char *)dirp += dirlen;
+ err -= dirlen;
+
+ }
+
+ }
+
+ smbc_closedir(dh); /* FIXME, check for error :-) */
+
+ /* Show the window and loop endlessly */
+ gtk_main();
+ return 0;
+}
+/* example-end */
diff --git a/packaging/LSB/README b/packaging/LSB/README
new file mode 100644
index 00000000000..4ff0b99d769
--- /dev/null
+++ b/packaging/LSB/README
@@ -0,0 +1,6 @@
+README.lsb - 1 July 2001
+------------------------
+
+The files in this directory allow you to build an LSB-compliant
+version of SAMBA using the RPM software and the LSB development
+environment.
diff --git a/packaging/LSB/lsb-samba.spec b/packaging/LSB/lsb-samba.spec
new file mode 100644
index 00000000000..516eaa430eb
--- /dev/null
+++ b/packaging/LSB/lsb-samba.spec
@@ -0,0 +1,100 @@
+#
+# "$Id: lsb-samba.spec,v 1.2 2001/07/03 01:01:12 jra Exp $"
+#
+# Linux Standards Based RPM "spec" file for SAMBA.
+#
+
+Summary: SAMBA
+Name: lsb-samba
+Version: 2.2.1
+Release: 0
+Copyright: GPL
+Group: System Environment/Daemons
+Source: ftp://ftp.samba.org/pub/samba/samba-%{version}.tar.gz
+Url: http://www.samba.org
+Packager: Michael Sweet <mike@easysw.com>
+Vendor: SAMBA Team
+
+# Require the "lsb" package, which guarantees LSB compliance.
+Requires: lsb
+
+# use BuildRoot so as not to disturb the version already installed
+BuildRoot: /var/tmp/%{name}-root
+
+%description
+
+%prep
+%setup
+
+%build
+export LDFLAGS="-L/usr/lib/lsb --dynamic-linker=/lib/ld-lsb.so.1"
+
+./configure --with-fhs --prefix=/usr --sysconfdir=/etc \
+ --sharedstatedir=/var --datadir=/usr/share \
+ --with-configdir=/etc/samba \
+ --with-swatdir=/usr/share/samba/swat
+
+# If we got this far, all prerequisite libraries must be here.
+make
+
+%install
+# Make sure the RPM_BUILD_ROOT directory exists.
+rm -rf $RPM_BUILD_ROOT
+mkdir $RPM_BUILD_ROOT
+
+make \
+ BASEDIR=$RPM_BUILD_ROOT/usr \
+ BINDIR=$RPM_BUILD_ROOT/usr/bin \
+ CODEPAGEDIR=$RPM_BUILD_ROOT/usr/share/samba/codepages \
+ CONFIGDIR=$RPM_BUILD_ROOT/etc/samba \
+ INCLUDEDIR=$RPM_BUILD_ROOT/usr/include \
+ LIBDIR=$RPM_BUILD_ROOT/usr/lib \
+ LOCKDIR=$RPM_BUILD_ROOT/var/lock/samba \
+ LOGFILEBASE=$RPM_BUILD_ROOT/var/log/samba \
+ MANDIR=$RPM_BUILD_ROOT/usr/share/man \
+ SBINDIR=$RPM_BUILD_ROOT/usr/sbin \
+ SWATDIR=$RPM_BUILD_ROOT/usr/share/samba/swat \
+ VARDIR=$RPM_BUILD_ROOT/var \
+ install
+
+mkdir -p $RPM_BUILD_ROOT/etc/init.d
+install -m 700 packaging/LSB/samba.sh /etc/init.d/samba
+
+mkdir -p $RPM_BUILD_ROOT/etc/samba
+install -m 644 packaging/LSB/smb.conf /etc/samba
+
+mkdir -p $RPM_BUILD_ROOT/etc/xinetd.d
+install -m 644 packaging/LSB/samba.xinetd /etc/xinetd.d/samba
+
+%post
+/usr/lib/lsb/install_initd /etc/init.d/samba
+
+%preun
+/usr/lib/lsb/remove_initd /etc/init.d/samba
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+%dir /etc/init.d
+/etc/init.d/samba
+%dir /etc/samba
+%config(noreplace) /etc/samba/smb.conf
+%dir /etc/samba/private
+%dir /etc/xinetd.d
+%config(noreplace) /etc/xinetd.d/samba
+%dir /usr/bin
+/usr/bin/*
+%dir /usr/sbin
+/usr/sbin/*
+%dir /usr/share/man
+/usr/share/man/*
+%dir /usr/share/samba
+/usr/share/samba/*
+%dir /var/lock/samba
+%dir /var/log/samba
+
+#
+# End of "$Id: lsb-samba.spec,v 1.2 2001/07/03 01:01:12 jra Exp $".
+#
diff --git a/packaging/LSB/samba.sh b/packaging/LSB/samba.sh
new file mode 100755
index 00000000000..99fa1b0117d
--- /dev/null
+++ b/packaging/LSB/samba.sh
@@ -0,0 +1,80 @@
+#!/bin/sh
+#
+# "$Id: samba.sh,v 1.2 2001/07/03 01:01:12 jra Exp $"
+#
+# SAMBA startup (init) script for LSB-compliant systems.
+#
+# Provides: smbd nmbd
+# Required-Start: 3 5
+# Required-Stop: 0 2 1 6
+# Default-Start: 3 5
+# Default-Stop: 0 2 1 6
+# Description: Starts and stops the SAMBA smbd and nmbd daemons \
+# used to provide SMB network services.
+#
+
+# Source LSB function library.
+. /lib/lsb/init-functions
+
+# Check that smb.conf exists.
+if test ! -f /etc/samba/smb.conf; then
+ log_failure_msg "The smb.conf file does not exist."
+ exit 6
+fi
+
+# Make sure that smbd and nmbd exist...
+if test ! -f /usr/sbin/nmbd -o ! -f /usr/sbin/smbd; then
+ log_failure_msg "The nmbd and/or smbd daemons are not installed."
+ exit 5
+fi
+
+# See how we were called.
+case "$1" in
+ start)
+ start_daemon nmbd -D
+ start_daemon smbd -D
+ log_success_msg "Started SMB services."
+ ;;
+
+ stop)
+ killproc smbd
+ killproc nmbd
+ log_success_msg "Shutdown SMB services."
+ ;;
+
+ reload)
+ # smbd and nmbd automatically re-read the smb.conf file...
+ log_success_msg "Reload not necessary with SAMBA."
+ ;;
+
+ status)
+ if test -z "`pidofproc smbd`"; then
+ log_success_msg "smbd is not running."
+ else
+ log_success_msg "smbd is running."
+ fi
+ if test -z "`pidofproc nmbd`"; then
+ log_success_msg "nmbd is not running."
+ else
+ log_success_msg "nmbd is running."
+ fi
+ ;;
+
+
+ restart | force-reload)
+ $0 stop
+ $0 start
+ ;;
+
+ *)
+ echo "Usage: smb {start|stop|reload|force-reload|restart|status}"
+ exit 1
+ ;;
+esac
+
+# Return "success"
+exit 0
+
+#
+# End of "$Id: samba.sh,v 1.2 2001/07/03 01:01:12 jra Exp $".
+#
diff --git a/packaging/LSB/samba.xinetd b/packaging/LSB/samba.xinetd
new file mode 100644
index 00000000000..8c38b354218
--- /dev/null
+++ b/packaging/LSB/samba.xinetd
@@ -0,0 +1,15 @@
+# default: off
+# description: SWAT is the Samba Web Admin Tool. Use swat \
+# to configure your Samba server. To use SWAT, \
+# connect to port 901 with your favorite web browser.
+service swat
+{
+ port = 901
+ socket_type = stream
+ wait = no
+ only_from = localhost
+ user = root
+ server = /usr/sbin/swat
+ log_on_failure += USERID
+ disable = yes
+}
diff --git a/packaging/LSB/smb.conf b/packaging/LSB/smb.conf
new file mode 100644
index 00000000000..71ff9463884
--- /dev/null
+++ b/packaging/LSB/smb.conf
@@ -0,0 +1,290 @@
+# This is the main Samba configuration file. You should read the
+# smb.conf(5) manual page in order to understand the options listed
+# here. Samba has a huge number of configurable options (perhaps too
+# many!) most of which are not shown in this example
+#
+# Any line which starts with a ; (semi-colon) or a # (hash)
+# is a comment and is ignored. In this example we will use a #
+# for commentry and a ; for parts of the config file that you
+# may wish to enable
+#
+# NOTE: Whenever you modify this file you should run the command "testparm"
+# to check that you have not made any basic syntactic errors.
+#
+#======================= Global Settings =====================================
+[global]
+
+# workgroup = NT-Domain-Name or Workgroup-Name
+ workgroup = MYGROUP
+
+# server string is the equivalent of the NT Description field
+ server string = Samba Server
+
+# This option is important for security. It allows you to restrict
+# connections to machines which are on your local network. The
+# following example restricts access to two C class networks and
+# the "loopback" interface. For more examples of the syntax see
+# the smb.conf man page
+; hosts allow = 192.168.1. 192.168.2. 127.
+
+# if you want to automatically load your printer list rather
+# than setting them up individually then you'll need this
+ printcap name = /etc/printcap
+ load printers = yes
+
+# It should not be necessary to spell out the print system type unless
+# yours is non-standard. Currently supported print systems include:
+# bsd, sysv, plp, lprng, aix, hpux, qnx
+; printing = bsd
+
+# Uncomment this if you want a guest account, you must add this to /etc/passwd
+# otherwise the user "nobody" is used
+; guest account = pcguest
+
+# this tells Samba to use a separate log file for each machine
+# that connects
+ log file = /var/log/samba/log.%m
+
+# Put a capping on the size of the log files (in Kb).
+ max log size = 50
+
+# Security mode. Most people will want user level security. See
+# security_level.txt for details.
+ security = user
+# Use password server option only with security = server
+; password server = <NT-Server-Name>
+
+# Password Level allows matching of _n_ characters of the password for
+# all combinations of upper and lower case.
+; password level = 8
+; username level = 8
+
+# You may wish to use password encryption. Please read
+# ENCRYPTION.txt, Win95.txt and WinNT.txt in the Samba documentation.
+# Do not enable this option unless you have read those documents
+; encrypt passwords = yes
+; smb passwd file = /etc/samba/smbpasswd
+
+# The following are needed to allow password changing from Windows to
+# update the Linux sytsem password also.
+# NOTE: Use these with 'encrypt passwords' and 'smb passwd file' above.
+# NOTE2: You do NOT need these to allow workstations to change only
+# the encrypted SMB passwords. They allow the Unix password
+# to be kept in sync with the SMB password.
+; unix password sync = Yes
+; passwd program = /usr/bin/passwd %u
+; passwd chat = *New*UNIX*password* %n\n *ReType*new*UNIX*password* %n\n *passwd:*all*authentication*tokens*updated*successfully*
+
+# Unix users can map to different SMB User names
+; username map = /etc/samba/smbusers
+
+# Using the following line enables you to customise your configuration
+# on a per machine basis. The %m gets replaced with the netbios name
+# of the machine that is connecting
+; include = /etc/samba/smb.conf.%m
+
+# Most people will find that this option gives better performance.
+# See speed.txt and the manual pages for details
+ socket options = TCP_NODELAY SO_RCVBUF=8192 SO_SNDBUF=8192
+
+# Configure Samba to use multiple interfaces
+# If you have multiple network interfaces then you must list them
+# here. See the man page for details.
+; interfaces = 192.168.12.2/24 192.168.13.2/24
+
+# Configure remote browse list synchronisation here
+# request announcement to, or browse list sync from:
+# a specific host or from / to a whole subnet (see below)
+; remote browse sync = 192.168.3.25 192.168.5.255
+# Cause this host to announce itself to local subnets here
+; remote announce = 192.168.1.255 192.168.2.44
+
+# Browser Control Options:
+# set local master to no if you don't want Samba to become a master
+# browser on your network. Otherwise the normal election rules apply
+; local master = no
+
+# OS Level determines the precedence of this server in master browser
+# elections. The default value should be reasonable
+; os level = 33
+
+# Domain Master specifies Samba to be the Domain Master Browser. This
+# allows Samba to collate browse lists between subnets. Don't use this
+# if you already have a Windows NT domain controller doing this job
+; domain master = yes
+
+# Preferred Master causes Samba to force a local browser election on startup
+# and gives it a slightly higher chance of winning the election
+; preferred master = yes
+
+# Use only if you have an NT server on your network that has been
+# configured at install time to be a primary domain controller.
+; domain controller = <NT-Domain-Controller-SMBName>
+
+# Enable this if you want Samba to be a domain logon server for
+# Windows95 workstations.
+; domain logons = yes
+
+# if you enable domain logons then you may want a per-machine or
+# per user logon script
+# run a specific logon batch file per workstation (machine)
+; logon script = %m.bat
+# run a specific logon batch file per username
+; logon script = %U.bat
+
+# Where to store roving profiles (only for Win95 and WinNT)
+# %L substitutes for this servers netbios name, %U is username
+# You must uncomment the [Profiles] share below
+; logon path = \\%L\Profiles\%U
+
+# All NetBIOS names must be resolved to IP Addresses
+# 'Name Resolve Order' allows the named resolution mechanism to be specified
+# the default order is "host lmhosts wins bcast". "host" means use the unix
+# system gethostbyname() function call that will use either /etc/hosts OR
+# DNS or NIS depending on the settings of /etc/host.config, /etc/nsswitch.conf
+# and the /etc/resolv.conf file. "host" therefore is system configuration
+# dependant. This parameter is most often of use to prevent DNS lookups
+# in order to resolve NetBIOS names to IP Addresses. Use with care!
+# The example below excludes use of name resolution for machines that are NOT
+# on the local network segment
+# - OR - are not deliberately to be known via lmhosts or via WINS.
+; name resolve order = wins lmhosts bcast
+
+# Windows Internet Name Serving Support Section:
+# WINS Support - Tells the NMBD component of Samba to enable it's WINS Server
+; wins support = yes
+
+# WINS Server - Tells the NMBD components of Samba to be a WINS Client
+# Note: Samba can be either a WINS Server, or a WINS Client, but NOT both
+; wins server = w.x.y.z
+
+# WINS Proxy - Tells Samba to answer name resolution queries on
+# behalf of a non WINS capable client, for this to work there must be
+# at least one WINS Server on the network. The default is NO.
+; wins proxy = yes
+
+# DNS Proxy - tells Samba whether or not to try to resolve NetBIOS names
+# via DNS nslookups. The built-in default for versions 1.9.17 is yes,
+# this has been changed in version 1.9.18 to no.
+ dns proxy = no
+
+# Case Preservation can be handy - system default is _no_
+# NOTE: These can be set on a per share basis
+; preserve case = no
+; short preserve case = no
+# Default case is normally upper case for all DOS files
+; default case = lower
+# Be very careful with case sensitivity - it can break things!
+; case sensitive = no
+
+#============================ Share Definitions ==============================
+[homes]
+ comment = Home Directories
+ browseable = no
+ writable = yes
+
+# Un-comment the following and create the netlogon directory for Domain Logons
+; [netlogon]
+; comment = Network Logon Service
+; path = /home/netlogon
+; guest ok = yes
+; writable = no
+; share modes = no
+
+
+# Un-comment the following to provide a specific roving profile share
+# the default is to use the user's home directory
+;[Profiles]
+; path = /home/profiles
+; browseable = no
+; guest ok = yes
+
+
+# NOTE: If you have a BSD-style print system there is no need to
+# specifically define each individual printer
+[printers]
+ comment = All Printers
+ path = /var/spool/samba
+ browseable = no
+# Set public = yes to allow user 'guest account' to print
+ guest ok = no
+ writable = no
+ printable = yes
+
+# This one is useful for people to share files
+;[tmp]
+; comment = Temporary file space
+; path = /tmp
+; read only = no
+; public = yes
+
+# A publicly accessible directory, but read only, except for people in
+# the "staff" group
+;[public]
+; comment = Public Stuff
+; path = /home/samba
+; public = yes
+; read only = yes
+; write list = @staff
+
+# Other examples.
+#
+# A private printer, usable only by fred. Spool data will be placed in fred's
+# home directory. Note that fred must have write access to the spool directory,
+# wherever it is.
+;[fredsprn]
+; comment = Fred's Printer
+; valid users = fred
+; path = /homes/fred
+; printer = freds_printer
+; public = no
+; writable = no
+; printable = yes
+
+# A private directory, usable only by fred. Note that fred requires write
+# access to the directory.
+;[fredsdir]
+; comment = Fred's Service
+; path = /usr/somewhere/private
+; valid users = fred
+; public = no
+; writable = yes
+; printable = no
+
+# a service which has a different directory for each machine that connects
+# this allows you to tailor configurations to incoming machines. You could
+# also use the %u option to tailor it by user name.
+# The %m gets replaced with the machine name that is connecting.
+;[pchome]
+; comment = PC Directories
+; path = /usr/pc/%m
+; public = no
+; writable = yes
+
+# A publicly accessible directory, read/write to all users. Note that all files
+# created in the directory by users will be owned by the default user, so
+# any user with access can delete any other user's files. Obviously this
+# directory must be writable by the default user. Another user could of course
+# be specified, in which case all files would be owned by that user instead.
+;[public]
+; path = /usr/somewhere/else/public
+; public = yes
+; only guest = yes
+; writable = yes
+; printable = no
+
+# The following two entries demonstrate how to share a directory so that two
+# users can place files there that will be owned by the specific users. In this
+# setup, the directory should be writable by both users and should have the
+# sticky bit set on it to prevent abuse. Obviously this could be extended to
+# as many users as required.
+;[myshare]
+; comment = Mary's and Fred's stuff
+; path = /usr/somewhere/shared
+; valid users = mary fred
+; public = no
+; writable = yes
+; printable = no
+; create mask = 0765
+
+
diff --git a/packaging/Mandrake/empty.patch b/packaging/Mandrake/empty.patch
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/packaging/Mandrake/empty.patch
diff --git a/source/include/libsmbclient.h b/source/include/libsmbclient.h
new file mode 100644
index 00000000000..54660c48535
--- /dev/null
+++ b/source/include/libsmbclient.h
@@ -0,0 +1,780 @@
+/*=====================================================================
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ SMB client library API definitions
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000
+ Copyright (C) John Terpsra 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+=====================================================================*/
+
+#ifndef SMBCLIENT_H_INCLUDED
+#define SMBCLIENT_H_INCLUDED
+
+/*-------------------------------------------------------------------*/
+/* The following are special comments to instruct DOXYGEN (automated
+ * documentation tool:
+*/
+/** \defgroup structure Data Structures Type and Constants
+* Data structures, types, and constants
+*/
+/** \defgroup file File Functions
+* Functions used to access individual file contents
+*/
+/** \defgroup directory Directory Functions
+* Functions used to access directory entries
+*/
+/** \defgroup attribute Attributes Functions
+* Functions used to view or change file and directory attributes
+*/
+/** \defgroup print Print Functions
+* Functions used to access printing functionality
+*/
+/** \defgroup attribute Miscellaneous Functions
+* Functions that don't fit in to other categories
+*/
+/*-------------------------------------------------------------------*/
+
+/* Make sure we have the following includes for now ... */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define SMBC_MAX_NAME 1023
+#define SMBC_WORKGROUP 1
+#define SMBC_SERVER 2
+#define SMBC_FILE_SHARE 3
+#define SMBC_PRINTER_SHARE 4
+#define SMBC_COMMS_SHARE 5
+#define SMBC_IPC_SHARE 6
+#define SMBC_DIR 7
+#define SMBC_FILE 8
+#define SMBC_LINK 9
+
+#define SMBC_FILE_MODE (S_IFREG | 0444)
+#define SMBC_DIR_MODE (S_IFDIR | 0555)
+
+/**@ingroup structure
+ * Structure that represents a directory entry.
+ *
+*/
+struct smbc_dirent
+{
+ /** Type of entity.
+ SMBC_WORKGROUP=1,
+ SMBC_SERVER=2,
+ SMBC_FILE_SHARE=3,
+ SMBC_PRINTER_SHARE=4,
+ SMBC_COMMS_SHARE=5,
+ SMBC_IPC_SHARE=6,
+ SMBC_DIR=7,
+ SMBC_FILE=8,
+ SMBC_LINK=9,*/
+ uint smbc_type;
+
+ /** Length of this smbc_dirent in bytes
+ */
+ uint dirlen;
+ /** The length of the comment string in bytes (includes null
+ * terminator)
+ */
+ uint commentlen;
+ /** Points to the null terminated comment string
+ */
+ char *comment;
+ /** The length of the name string in bytes (includes null
+ * terminator)
+ */
+ uint namelen;
+ /** Points to the null terminated name string
+ */
+ char name[1];
+};
+
+
+#ifndef _CLIENT_H
+typedef unsigned short uint16;
+
+/**@ingroup structure
+ * Structure that represents a print job.
+ *
+ */
+struct print_job_info
+{
+ /** numeric ID of the print job
+ */
+ uint16 id;
+
+ /** represents print job priority (lower numbers mean higher priority)
+ */
+ uint16 priority;
+
+ /** Size of the print job
+ */
+ size_t size;
+
+ /** Name of the user that owns the print job
+ */
+ char user[128];
+
+ /** Name of the print job. This will have no name if an anonymous print
+ * file was opened. Ie smb://server/printer
+ */
+ char name[128];
+
+ /** Time the print job was spooled
+ */
+ time_t t;
+};
+#endif
+
+
+/**@ingroup structure
+ * Authentication callback function type.
+ *
+ * Type for the the authentication function called by the library to
+ * obtain authentication credentals
+ *
+ * @param srv Server being authenticated to
+ *
+ * @param shr Share being authenticated to
+ *
+ * @param wg Pointer to buffer containing a "hint" for the
+ * workgroup to be authenticated. Should be filled in
+ * with the correct workgroup if the hint is wrong.
+ *
+ * @param wglen The size of the workgroup buffer in bytes
+ *
+ * @param un Pointer to buffer containing a "hint" for the
+ * user name to be use for authentication. Should be
+ * filled in with the correct workgroup if the hint is
+ * wrong.
+ *
+ * @param unlen The size of the username buffer in bytes
+ *
+ * @param pw Pointer to buffer containing to which password
+ * copied
+ *
+ * @param pwlen The size of the password buffer in bytes
+ *
+ */
+typedef void (*smbc_get_auth_data_fn)(const char *srv,
+ const char *shr,
+ char *wg, int wglen,
+ char *un, int unlen,
+ char *pw, int pwlen);
+
+
+/**@ingroup structure
+ * Print job info callback function type.
+ *
+ * @param i pointer to print job information structure
+ *
+ */
+typedef void (*smbc_get_print_job_info)(struct print_job_info *i);
+
+
+/**@ingroup misc
+ * Initialize the samba client library.
+ *
+ * Must be called before using any of the smbclient API function
+ *
+ * @param fn The function that will be called to obtaion
+ * authentication credentials.
+ *
+ * @param debug Allows caller to set the debug level. Can be
+ * changed in smb.conf file. Allows caller to set
+ * debugging if no smb.conf.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - ENOMEM Out of memory
+ * - ENOENT The smb.conf file would not load
+ *
+ */
+int smbc_init(smbc_get_auth_data_fn fn, int debug);
+
+
+/**@ingroup file
+ * Open a file on an SMB server.
+ *
+ * @param furl The smb url of the file to be opened.
+ *
+ * @param flags Is one of O_RDONLY, O_WRONLY or O_RDWR which
+ * request opening the file read-only,write-only
+ * or read/write. flags may also be bitwise-or'd with
+ * one or more of the following:
+ * O_CREAT - If the file does not exist it will be
+ * created.
+ * O_EXCL - When used with O_CREAT, if the file
+ * already exists it is an error and the open will
+ * fail.
+ * O_TRUNC - If the file already exists it will be
+ * truncated.
+ * O_APPEND The file is opened in append mode
+ *
+ * @param mode mode specifies the permissions to use if a new
+ * file is created. It is modified by the
+ * process's umask in the usual way: the permissions
+ * of the created file are (mode & ~umask)
+ *
+ * Not currently use, but there for future use.
+ * We will map this to SYSTEM, HIDDEN, etc bits
+ * that reverses the mapping that smbc_fstat does.
+ *
+ * @return Valid file handle, < 0 on error with errno set:
+ * - ENOMEM Out of memory
+ * - EINVAL if an invalid parameter passed, like no
+ * file, or smbc_init not called.
+ * - EEXIST pathname already exists and O_CREAT and
+ * O_EXCL were used.
+ * - EISDIR pathname refers to a directory and
+ * the access requested involved writing.
+ * - EACCES The requested access to the file is not
+ * allowed
+ * - ENODEV The requested share does not exist
+ * - ENOTDIR A file on the path is not a directory
+ * - ENOENT A directory component in pathname does
+ * not exist.
+ *
+ * @see smbc_creat()
+ *
+ * @note This call uses an underlying routine that may create
+ * a new connection to the server specified in the URL.
+ * If the credentials supplied in the URL, or via the
+ * auth_fn in the smbc_init call, fail, this call will
+ * try again with an empty username and password. This
+ * often gets mapped to the guest account on some machines.
+*/
+int smbc_open(const char *furl, int flags, mode_t mode);
+
+
+/**@ingroup file
+ * Create a file on an SMB server.
+ *
+ * Same as calling smbc_open() with flags = O_CREAT|O_WRONLY|O_TRUNC
+ *
+ * @param furl The smb url of the file to be created
+ *
+ * @param mode mode specifies the permissions to use if a new
+ * file is created. It is modified by the
+ * process's umask in the usual way: the permissions
+ * of the created file are (mode & ~umask)
+ *
+ * NOTE, the above is not true. We are dealing with
+ * an SMB server, which has no concept of a umask!
+ *
+ * @return Valid file handle, < 0 on error with errno set:
+ * - ENOMEM Out of memory
+ * - EINVAL if an invalid parameter passed, like no
+ * file, or smbc_init not called.
+ * - EEXIST pathname already exists and O_CREAT and
+ * O_EXCL were used.
+ * - EISDIR pathname refers to a directory and
+ * the access requested involved writing.
+ * - EACCES The requested access to the file is not
+ * allowed
+ * - ENOENT A directory component in pathname does
+ * not exist.
+ * - ENODEV The requested share does not exist.
+ * @see smbc_open()
+ *
+*/
+int smbc_creat(const char *furl, mode_t mode);
+
+
+/**@ingroup file
+ * Read from a file using an opened file handle.
+ *
+ * @param fd Open file handle from smbc_open() or smbc_creat()
+ *
+ * @param buf Pointer to buffer to recieve read data
+ *
+ * @param bufsize Size of buf in bytes
+ *
+ * @return Number of bytes read, < 0 on error with errno set:
+ * - EISDIR fd refers to a directory
+ * - EBADF fd is not a valid file descriptor or
+ * is not open for reading.
+ * - EINVAL fd is attached to an object which is
+ * unsuitable for reading, or no buffer passed or
+ * smbc_init not called.
+ *
+ * @see smbc_open(), smbc_write()
+ *
+ */
+ssize_t smbc_read(int fd, void *buf, size_t bufsize);
+
+
+/**@ingroup file
+ * Write to a file using an opened file handle.
+ *
+ * @param fd Open file handle from smbc_open() or smbc_creat()
+ *
+ * @param buf Pointer to buffer to recieve read data
+ *
+ * @param bufsize Size of buf in bytes
+ *
+ * @return Number of bytes written, < 0 on error with errno set:
+ * - EISDIR fd refers to a directory.
+ * - EBADF fd is not a valid file descriptor or
+ * is not open for reading.
+ * - EINVAL fd is attached to an object which is
+ * unsuitable for reading, or no buffer passed or
+ * smbc_init not called.
+ *
+ * @see smbc_open(), smbc_read()
+ *
+ */
+ssize_t smbc_write(int fd, void *buf, size_t bufsize);
+
+
+/**@ingroup file
+ * Seek to a specific location in a file.
+ *
+ * @param fd Open file handle from smbc_open() or smbc_creat()
+ *
+ * @param offset Offset in bytes from whence
+ *
+ * @param whence A location in the file:
+ * - SEEK_SET The offset is set to offset bytes from
+ * the beginning of the file
+ * - SEEK_CUR The offset is set to current location
+ * plus offset bytes.
+ * - SEEK_END The offset is set to the size of the
+ * file plus offset bytes.
+ *
+ * @return Upon successful completion, lseek returns the
+ * resulting offset location as measured in bytes
+ * from the beginning of the file. Otherwise, a value
+ * of (off_t)-1 is returned and errno is set to
+ * indicate the error:
+ * - EBADF Fildes is not an open file descriptor.
+ * - EINVAL Whence is not a proper value or smbc_init
+ * not called.
+ *
+ * @todo Are all the whence values really supported?
+ *
+ * @todo Are errno values complete and correct?
+*/
+off_t smbc_lseek(int fd, off_t offset, int whence);
+
+
+/**@ingroup file
+ * Close an open file handle.
+ *
+ * @param fd The file handle to close
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EBADF fd isn't a valid open file descriptor
+ * - EINVAL smbc_init() failed or has not been called
+ *
+ * @see smbc_open(), smbc_creat()
+*/
+int smbc_close(int fd);
+
+
+/**@ingroup directory
+ * Unlink (delete) a file or directory.
+ *
+ * @param furl The smb url of the file to delete
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EACCES or EPERM Write access to the directory
+ * containing pathname is not allowed or one
+ * of the directories in pathname did not allow
+ * search (execute) permission
+ * - ENOENT A directory component in pathname does
+ * not exist
+ * - EINVAL NULL was passed in the file param or
+ * smbc_init not called.
+ * - EACCES You do not have access to the file
+ * - ENOMEM Insufficient kernel memory was available
+ *
+ * @see smbc_rmdir()s
+ *
+ * @todo Are errno values complete and correct?
+*/
+int smbc_unlink(const char *furl);
+
+
+/**@ingroup directory
+ * Rename or move a file or directory.
+ *
+ * @param ourl The original smb url (source url) of file or
+ * directory to be moved
+ *
+ * @param nurl The new smb url (destination url) of the file
+ * or directory after the move. Currently nurl must
+ * be on the same share as ourl.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EISDIR nurl is an existing directory, but ourl is
+ * not a directory.
+ * - EEXIST nurl is a non-empty directory,
+ * i.e., contains entries other than "." and ".."
+ * - EINVAL The new url contained a path prefix
+ * of the old, or, more generally, an attempt was
+ * made to make a directory a subdirectory of itself
+ * or smbc_init not called.
+ * - ENOTDIR A component used as a directory in ourl
+ * or nurl path is not, in fact, a directory. Or,
+ * ourl is a directory, and newpath exists but is not
+ * a directory.
+ * - EACCES or EPERM Write access to the directory
+ * containing ourl or nurl is not allowed for the
+ * process's effective uid, or one of the
+ * directories in ourl or nurl did not allow search
+ * (execute) permission, or ourl was a directory
+ * and did not allow write permission.
+ * - ENOENT A directory component in ourl or nurl
+ * does not exist.
+ * - EXDEV Rename across shares not supported.
+ * - ENOMEM Insufficient kernel memory was available.
+ * - EEXIST The target file, nurl, already exists.
+ *
+ *
+ * @todo Are we going to support copying when urls are not on the same
+ * share? I say no... NOTE. I agree for the moment.
+ *
+*/
+int smbc_rename(const char *ourl, const char *nurl);
+
+
+/**@ingroup directory
+ * Open a directory used to obtain directory entries.
+ *
+ * @param durl The smb url of the directory to open
+ *
+ * @return Valid directory handle. < 0 on error with errno set:
+ * - EACCES Permission denied.
+ * - EINVAL A NULL file/URL was passed, or the URL would
+ * not parse, or was of incorrect form or smbc_init not
+ * called.
+ * - ENOENT durl does not exist, or name is an
+ * - ENOMEM Insufficient memory to complete the
+ * operation.
+ * - ENOTDIR name is not a directory.
+ * - EPERM the workgroup could not be found.
+ * - ENODEV the workgroup or server could not be found.
+ *
+ * @see smbc_getdents(), smbc_readdir(), smbc_closedir()
+ *
+*/
+int smbc_opendir(const char *durl);
+
+
+/**@ingroup directory
+ * Close a directory handle opened by smbc_opendir().
+ *
+ * @param dh Directory handle to close
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EBADF dh is an invalid directory handle
+ *
+ * @see smbc_opendir()
+*/
+int smbc_closedir(int dh);
+
+
+/**@ingroup directory
+ * Get multiple directory entries.
+ *
+ * smbc_getdents() reads as many dirent structures from the an open
+ * directory handle into a specified memory area as will fit.
+ *
+ * @param dh Valid directory as returned by smbc_opendir()
+ *
+ * @param dirp pointer to buffer that will receive the directory
+ * entries.
+ *
+ * @param count The size of the dirp buffer in bytes
+ *
+ * @returns If any dirents returned, return will indicate the
+ * total size. If there were no more dirents available,
+ * 0 is returned. < 0 indicates an error.
+ * - EBADF Invalid directory handle
+ * - EINVAL Result buffer is too small or smbc_init
+ * not called.
+ * - ENOENT No such directory.
+ * @see , smbc_dirent, smbc_readdir(), smbc_open()
+ *
+ * @todo Are errno values complete and correct?
+ *
+ * @todo Add example code so people know how to parse buffers.
+ */
+int smbc_getdents(unsigned int dh, struct smbc_dirent *dirp, int count);
+
+
+/**@ingroup directory
+ * Get a single directory entry.
+ *
+ * @param dh Valid directory as returned by smbc_opendir()
+ *
+ * @return A pointer to a smbc_dirent structure, or NULL if an
+ * error occurs or end-of-directory is reached:
+ * - EBADF Invalid directory handle
+ * - EINVAL smbc_init() failed or has not been called
+ *
+ * @see smbc_dirent, smbc_getdents(), smbc_open()
+*/
+struct smbc_dirent* smbc_readdir(unsigned int dh);
+
+
+/**@ingroup directory
+ * Get the current directory offset.
+ *
+ * smbc_telldir() may be used in conjunction with smbc_readdir() and
+ * smbc_lseekdir().
+ *
+ * @param dh Valid directory as returned by smbc_opendir()
+ *
+ * @return The current location in the directory stream or -1
+ * if an error occur. The current location is not
+ * an offset. Becuase of the implementation, it is a
+ * handle that allows the library to find the entry
+ * later.
+ * - EBADF dh is not a valid directory handle
+ * - EINVAL smbc_init() failed or has not been called
+ * - ENOTDIR if dh is not a directory
+ *
+ * @see smbc_readdir()
+ *
+*/
+off_t smbc_telldir(int dh);
+
+
+/**@ingroup directory
+ * lseek on directories.
+ *
+ * smbc_lseekdir() may be used in conjunction with smbc_readdir() and
+ * smbc_telldir(). (rewind by smbc_lseekdir(fd, NULL))
+ *
+ * @param fd Valid directory as returned by smbc_opendir()
+ *
+ * @param offset The offset (as returned by smbc_telldir). Can be
+ * NULL, in which case we will rewind
+ *
+ * @return 0 on success, -1 on failure
+ * - EBADF dh is not a valid directory handle
+ * - ENOTDIR if dh is not a directory
+ * - EINVAL offset did not refer to a valid dirent or
+ * smbc_init not called.
+ *
+ * @see smbc_telldir()
+ *
+ *
+ * @todo In what does the reture and errno values mean?
+ */
+int smbc_lseekdir(int fd, off_t offset);
+
+/**@ingroup directory
+ * Create a directory.
+ *
+ * @param durl The url of the directory to create
+ *
+ * @param mode Specifies the permissions to use. It is modified
+ * by the process's umask in the usual way: the
+ * permissions of the created file are (mode & ~umask).
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EEXIST directory url already exists
+ * - EACCES The parent directory does not allow write
+ * permission to the process, or one of the directories
+ * - ENOENT A directory component in pathname does not
+ * exist.
+ * - EINVAL NULL durl passed or smbc_init not called.
+ * - ENOMEM Insufficient memory was available.
+ *
+ * @see smbc_rmdir()
+ *
+*/
+int smbc_mkdir(const char *durl, mode_t mode);
+
+
+/**@ingroup directory
+ * Remove a directory.
+ *
+ * @param durl The smb url of the directory to remove
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EACCES or EPERM Write access to the directory
+ * containing pathname was not allowed.
+ * - EINVAL durl is NULL or smbc_init not called.
+ * - ENOENT A directory component in pathname does not
+ * exist.
+ * - ENOTEMPTY directory contains entries.
+ * - ENOMEM Insufficient kernel memory was available.
+ *
+ * @see smbc_mkdir(), smbc_unlink()
+ *
+ * @todo Are errno values complete and correct?
+ */
+int smbc_rmdir(const char *durl);
+
+
+/**@ingroup attribute
+ * Get information about a file or directory.
+ *
+ * @param url The smb url to get information for
+ *
+ * @param st pointer to a buffer that will be filled with
+ * standard Unix struct stat information.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - ENOENT A component of the path file_name does not
+ * exist.
+ * - EINVAL a NULL url was passed or smbc_init not called.
+ * - EACCES Permission denied.
+ * - ENOMEM Out of memory
+ * - ENOTDIR The target dir, url, is not a directory.
+ *
+ * @see Unix stat()
+ *
+ */
+int smbc_stat(const char *url, struct stat *st);
+
+
+/**@ingroup attribute
+ * Get file information via an file descriptor.
+ *
+ * @param fd Open file handle from smbc_open() or smbc_creat()
+ *
+ * @param st pointer to a buffer that will be filled with
+ * standard Unix struct stat information.
+ *
+ * @return EBADF filedes is bad.
+ * - EACCES Permission denied.
+ * - EBADF fd is not a valid file descriptor
+ * - EINVAL Problems occurred in the underlying routines
+ * or smbc_init not called.
+ * - ENOMEM Out of memory
+ *
+ * @see smbc_stat(), Unix stat()
+ *
+ */
+int smbc_fstat(int fd, struct stat *st);
+
+
+/**@ingroup attribue
+ * Change the ownership of a file or directory.
+ *
+ * @param url The smb url of the file or directory to change
+ * ownership of.
+ *
+ * @param owner I have no idea?
+ *
+ * @param group I have not idea?
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EPERM The effective UID does not match the owner
+ * of the file, and is not zero; or the owner or group
+ * were specified incorrectly.
+ * - ENOENT The file does not exist.
+ * - ENOMEM Insufficient was available.
+ * - ENOENT file or directory does not exist
+ *
+ * @todo Are we actually going to be able to implement this function
+ *
+ * @todo How do we abstract owner and group uid and gid?
+ *
+ */
+int smbc_chown(const char *url, uid_t owner, gid_t group);
+
+
+/**@ingroup attribute
+ * Change the permissions of a file.
+ *
+ * @param url The smb url of the file or directory to change
+ * permissions of
+ *
+ * @param mode The permissions to set:
+ * - Put good explaination of permissions here!
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EPERM The effective UID does not match the owner
+ * of the file, and is not zero
+ * - ENOENT The file does not exist.
+ * - ENOMEM Insufficient was available.
+ * - ENOENT file or directory does not exist
+ *
+ * @todo Actually implement this fuction?
+ *
+ * @todo Are errno values complete and correct?
+ */
+int smbc_chmod(const char *url, mode_t mode);
+
+
+/**@ingroup print
+ * Print a file given the name in fname. It would be a URL ...
+ *
+ * @param fname The URL of a file on a remote SMB server that the
+ * caller wants printed
+ *
+ * @param printq The URL of the print share to print the file to.
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ *
+ * - EINVAL fname or printq was NULL or smbc_init not
+ * not called.
+ * and errors returned by smbc_open
+ *
+*/
+int smbc_print_file(const char *fname, const char *printq);
+
+/**@ingroup print
+ * Open a print file that can be written to by other calls. This simply
+ * does an smbc_open call after checking if there is a file name on the
+ * URI. If not, a temporary name is added ...
+ *
+ * @param fname The URL of the print share to print to?
+ *
+ * @returns A file handle for the print file if successful.
+ * Returns -1 if an error ocurred and errno has the values
+ * - EINVAL fname was NULL or smbc_init not called.
+ * - all errors returned by smbc_open
+ *
+ */
+int smbc_open_print_job(const char *fname);
+
+/**@ingroup print
+ * List the print jobs on a print share, for the moment, pass a callback
+ *
+ * @param purl The url of the print share to list the jobs of
+ *
+ * @param fn Callback function the receives printjob info
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EINVAL fname was NULL or smbc_init not called
+ * - EACCES ???
+ */
+int smbc_list_print_jobs(const char *purl, smbc_get_print_job_info fn);
+
+/**@ingroup print
+ * Delete a print job
+ *
+ * @param purl Url of the print share
+ *
+ * @param id The id of the job to delete
+ *
+ * @return 0 on success, < 0 on error with errno set:
+ * - EINVAL fname was NULL or smbc_init not called
+ *
+ * @todo what errno values are possible here?
+ */
+int smbc_unlink_print_job(const char *purl, int id);
+
+
+#endif /* SMBCLIENT_H_INCLUDED */
diff --git a/source/lib/util_getent.c b/source/lib/util_getent.c
new file mode 100644
index 00000000000..5c1652f6bf5
--- /dev/null
+++ b/source/lib/util_getent.c
@@ -0,0 +1,239 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ Samba utility functions
+ Copyright (C) Simo Sorce 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"
+
+#if 0
+static void print_grent_list(struct sys_grent *glist)
+{
+ DEBUG(100, ("print_grent_list: %x\n", glist ));
+ while (glist) {
+ DEBUG(100,("glist: %x ", glist));
+ if (glist->gr_name)
+ DEBUG(100,(": gr_name = (%x) %s ", glist->gr_name, glist->gr_name));
+ if (glist->gr_passwd)
+ DEBUG(100,(": gr_passwd = (%x) %s ", glist->gr_passwd, glist->gr_passwd));
+ if (glist->gr_mem) {
+ int i;
+ for (i = 0; glist->gr_mem[i]; i++)
+ DEBUG(100,(" : gr_mem[%d] = (%x) %s ", i, glist->gr_mem[i], glist->gr_mem[i]));
+ }
+ DEBUG(100,(": gr_next = %x\n", glist->next ));
+ glist = glist->next;
+ }
+ DEBUG(100,("FINISHED !\n\n"));
+}
+#endif
+
+/****************************************************************
+ Returns a single linked list of group entries.
+ Use grent_free() to free it after use.
+****************************************************************/
+
+struct sys_grent * getgrent_list(void)
+{
+ struct sys_grent *glist;
+ struct sys_grent *gent;
+ struct group *grp;
+
+ gent = (struct sys_grent *) malloc(sizeof(struct sys_grent));
+ if (gent == NULL) {
+ DEBUG (0, ("Out of memory in getgrent_list!\n"));
+ return NULL;
+ }
+ memset(gent, '\0', sizeof(struct sys_grent));
+ glist = gent;
+
+ setgrent();
+ grp = getgrent();
+ if (grp == NULL) {
+ endgrent();
+ free(glist);
+ return NULL;
+ }
+
+ while (grp != NULL) {
+ int i,num;
+
+ if (grp->gr_name) {
+ if ((gent->gr_name = strdup(grp->gr_name)) == NULL)
+ goto err;
+ }
+ if (grp->gr_passwd) {
+ if ((gent->gr_passwd = strdup(grp->gr_passwd)) == NULL)
+ goto err;
+ }
+ gent->gr_gid = grp->gr_gid;
+
+ /* number of strings in gr_mem */
+ for (num = 0; grp->gr_mem[num]; num++)
+ ;
+
+ /* alloc space for gr_mem string pointers */
+ if ((gent->gr_mem = (char **) malloc((num+1) * sizeof(char *))) == NULL)
+ goto err;
+
+ memset(gent->gr_mem, '\0', (num+1) * sizeof(char *));
+
+ for (i=0; i < num; i++) {
+ if ((gent->gr_mem[i] = strdup(grp->gr_mem[i])) == NULL)
+ goto err;
+ }
+ gent->gr_mem[num] = NULL;
+
+ grp = getgrent();
+ if (grp) {
+ gent->next = (struct sys_grent *) malloc(sizeof(struct sys_grent));
+ if (gent->next == NULL)
+ goto err;
+ gent = gent->next;
+ memset(gent, '\0', sizeof(struct sys_grent));
+ }
+ }
+
+ endgrent();
+ return glist;
+
+ err:
+
+ endgrent();
+ DEBUG(0, ("Out of memory in getgrent_list!\n"));
+ grent_free(glist);
+ return NULL;
+}
+
+/****************************************************************
+ Free the single linked list of group entries made by
+ getgrent_list()
+****************************************************************/
+
+void grent_free (struct sys_grent *glist)
+{
+ while (glist) {
+ struct sys_grent *prev;
+
+ if (glist->gr_name)
+ free(glist->gr_name);
+ if (glist->gr_passwd)
+ free(glist->gr_passwd);
+ if (glist->gr_mem) {
+ int i;
+ for (i = 0; glist->gr_mem[i]; i++)
+ free(glist->gr_mem[i]);
+ free(glist->gr_mem);
+ }
+ prev = glist;
+ glist = glist->next;
+ free(prev);
+ }
+}
+
+/****************************************************************
+ Returns a single linked list of passwd entries.
+ Use pwent_free() to free it after use.
+****************************************************************/
+
+struct sys_pwent * getpwent_list(void)
+{
+ struct sys_pwent *plist;
+ struct sys_pwent *pent;
+ struct passwd *pwd;
+
+ pent = (struct sys_pwent *) malloc(sizeof(struct sys_pwent));
+ if (pent == NULL) {
+ DEBUG (0, ("Out of memory in getpwent_list!\n"));
+ return NULL;
+ }
+ plist = pent;
+
+ setpwent();
+ pwd = getpwent();
+ while (pwd != NULL) {
+ memset(pent, '\0', sizeof(struct sys_pwent));
+ if (pwd->pw_name) {
+ if ((pent->pw_name = strdup(pwd->pw_name)) == NULL)
+ goto err;
+ }
+ if (pwd->pw_passwd) {
+ if ((pent->pw_passwd = strdup(pwd->pw_passwd)) == NULL)
+ goto err;
+ }
+ pent->pw_uid = pwd->pw_uid;
+ pent->pw_gid = pwd->pw_gid;
+ if (pwd->pw_gecos) {
+ if ((pent->pw_name = strdup(pwd->pw_gecos)) == NULL)
+ goto err;
+ }
+ if (pwd->pw_dir) {
+ if ((pent->pw_name = strdup(pwd->pw_dir)) == NULL)
+ goto err;
+ }
+ if (pwd->pw_shell) {
+ if ((pent->pw_name = strdup(pwd->pw_shell)) == NULL)
+ goto err;
+ }
+
+ pwd = getpwent();
+ if (pwd) {
+ pent->next = (struct sys_pwent *) malloc(sizeof(struct sys_pwent));
+ if (pent->next == NULL)
+ goto err;
+ pent = pent->next;
+ }
+ }
+
+ endpwent();
+ return plist;
+
+ err:
+
+ endpwent();
+ DEBUG(0, ("Out of memory in getpwent_list!\n"));
+ pwent_free(plist);
+ return NULL;
+}
+
+/****************************************************************
+ Free the single linked list of passwd entries made by
+ getpwent_list()
+****************************************************************/
+
+void pwent_free (struct sys_pwent *plist)
+{
+ while (plist) {
+ struct sys_pwent *prev;
+
+ if (plist->pw_name)
+ free(plist->pw_name);
+ if (plist->pw_passwd)
+ free(plist->pw_passwd);
+ if (plist->pw_gecos)
+ free(plist->pw_gecos);
+ if (plist->pw_dir)
+ free(plist->pw_dir);
+ if (plist->pw_shell)
+ free(plist->pw_shell);
+
+ prev = plist;
+ plist = plist->next;
+ free(prev);
+ }
+}
diff --git a/source/libsmb/clidgram.c b/source/libsmb/clidgram.c
new file mode 100644
index 00000000000..fc1453dce14
--- /dev/null
+++ b/source/libsmb/clidgram.c
@@ -0,0 +1,272 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ client dgram calls
+ Copyright (C) Andrew Tridgell 1994-1998
+ Copyright (C) Richard Sharpe 2001
+ Copyright (C) John Terpstra 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.
+*/
+
+#define NO_SYSLOG
+
+#include "includes.h"
+
+/*
+ * cli_send_mailslot, send a mailslot for client code ...
+ */
+
+int cli_send_mailslot(int dgram_sock, BOOL unique, char *mailslot,
+ char *buf, int len,
+ const char *srcname, int src_type,
+ const char *dstname, int dest_type,
+ struct in_addr dest_ip, struct in_addr src_ip,
+ int dest_port, int src_port)
+{
+ struct packet_struct p;
+ struct dgram_packet *dgram = &p.packet.dgram;
+ char *ptr, *p2;
+ char tmp[4];
+
+ bzero((char *)&p, sizeof(p));
+
+ /*
+ * Next, build the DGRAM ...
+ */
+
+ /* DIRECT GROUP or UNIQUE datagram. */
+ dgram->header.msg_type = unique ? 0x10 : 0x11;
+ dgram->header.flags.node_type = M_NODE;
+ dgram->header.flags.first = True;
+ dgram->header.flags.more = False;
+ dgram->header.dgm_id = ((unsigned)time(NULL)%(unsigned)0x7FFF) + ((unsigned)sys_getpid()%(unsigned)100);
+ dgram->header.source_ip.s_addr = src_ip.s_addr;
+ /*fprintf(stderr, "Source IP = %0X\n", dgram->header.source_ip); */
+ dgram->header.source_port = ntohs(src_port);
+ fprintf(stderr, "Source Port = %0X\n", dgram->header.source_port);
+ dgram->header.dgm_length = 0; /* Let build_dgram() handle this. */
+ dgram->header.packet_offset = 0;
+
+ make_nmb_name(&dgram->source_name,srcname,src_type);
+ make_nmb_name(&dgram->dest_name,dstname,dest_type);
+
+ ptr = &dgram->data[0];
+
+ /* Setup the smb part. */
+ ptr -= 4; /* XXX Ugliness because of handling of tcp SMB length. */
+ memcpy(tmp,ptr,4);
+ set_message(ptr,17,17 + len,True);
+ memcpy(ptr,tmp,4);
+
+ CVAL(ptr,smb_com) = SMBtrans;
+ SSVAL(ptr,smb_vwv1,len);
+ SSVAL(ptr,smb_vwv11,len);
+ SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
+ SSVAL(ptr,smb_vwv13,3);
+ SSVAL(ptr,smb_vwv14,1);
+ SSVAL(ptr,smb_vwv15,1);
+ SSVAL(ptr,smb_vwv16,2);
+ p2 = smb_buf(ptr);
+ pstrcpy(p2,mailslot);
+ p2 = skip_string(p2,1);
+
+ memcpy(p2,buf,len);
+ p2 += len;
+
+ dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length. */
+
+ p.ip = dest_ip;
+ p.port = dest_port;
+ p.fd = dgram_sock;
+ p.timestamp = time(NULL);
+ p.packet_type = DGRAM_PACKET;
+
+ DEBUG(4,("send_mailslot: Sending to mailslot %s from %s IP %s ", mailslot,
+ nmb_namestr(&dgram->source_name), inet_ntoa(src_ip)));
+ DEBUG(4,("to %s IP %s\n", nmb_namestr(&dgram->dest_name), inet_ntoa(dest_ip)));
+
+ return send_packet(&p);
+
+}
+
+/*
+ * cli_get_response: Get a response ...
+ */
+int cli_get_response(int dgram_sock, BOOL unique, char *mailslot, char *buf, int bufsiz)
+{
+ struct packet_struct *packet;
+
+ packet = receive_dgram_packet(dgram_sock, 5, mailslot);
+
+ if (packet) { /* We got one, pull what we want out of the SMB data ... */
+
+ struct dgram_packet *dgram = &packet->packet.dgram;
+
+ /*
+ * We should probably parse the SMB, but for now, we will pull what
+ * from fixed, known locations ...
+ */
+
+ /* Copy the data to buffer, respecting sizes ... */
+
+ bcopy(&dgram->data[92], buf, MIN(bufsiz, (dgram->datasize - 92)));
+
+ }
+ else
+ return -1;
+
+ return 0;
+
+}
+
+/*
+ * cli_get_backup_list: Send a get backup list request ...
+ */
+
+static char cli_backup_list[1024];
+
+int cli_get_backup_list(const char *myname, const char *send_to_name)
+{
+ char outbuf[15];
+ char *p;
+ struct in_addr sendto_ip, my_ip;
+ int dgram_sock;
+ struct sockaddr_in sock_out;
+ socklen_t name_size;
+
+ if (!resolve_name(send_to_name, &sendto_ip, 0x1d)) {
+
+ DEBUG(0, ("Could not resolve name: %s<1D>\n", send_to_name));
+ return False;
+
+ }
+
+ my_ip.s_addr = inet_addr("0.0.0.0");
+
+ if (!resolve_name(myname, &my_ip, 0x00)) { /* FIXME: Call others here */
+
+ DEBUG(0, ("Could not resolve name: %s<00>\n", myname));
+
+ }
+
+ if ((dgram_sock = open_socket_out(SOCK_DGRAM, &sendto_ip, 138, LONG_CONNECT_TIMEOUT)) < 0) {
+
+ DEBUG(4, ("open_sock_out failed ..."));
+ return False;
+
+ }
+
+ /* Make it a broadcast socket ... */
+
+ set_socket_options(dgram_sock, "SO_BROADCAST");
+
+ /* Make it non-blocking??? */
+
+ if (fcntl(dgram_sock, F_SETFL, O_NONBLOCK) < 0) {
+
+ DEBUG(0, ("Unable to set non blocking on dgram sock\n"));
+
+ }
+
+ /* Now, bind a local addr to it ... Try port 138 first ... */
+
+ bzero((char *)&sock_out, sizeof(sock_out));
+ sock_out.sin_addr.s_addr = INADDR_ANY;
+ sock_out.sin_port = htons(138);
+ sock_out.sin_family = AF_INET;
+
+ if (bind(dgram_sock, (struct sockaddr *)&sock_out, sizeof(sock_out)) < 0) {
+
+ /* Try again on any port ... */
+
+ sock_out.sin_port = INADDR_ANY;
+
+ if (bind(dgram_sock, (struct sockaddr *)&sock_out, sizeof(sock_out)) < 0) {
+
+ DEBUG(4, ("failed to bind socket to address ...\n"));
+ return False;
+
+ }
+
+ }
+
+ /* Now, figure out what socket name we were bound to. We want the port */
+
+ name_size = sizeof(sock_out);
+
+ getsockname(dgram_sock, (struct sockaddr *)&sock_out, &name_size);
+
+ DEBUG(5, ("Socket bound to IP:%s, port: %d\n", inet_ntoa(sock_out.sin_addr), ntohs(sock_out.sin_port)));
+
+ /* Now, build the request */
+
+ bzero(cli_backup_list, sizeof(cli_backup_list));
+ bzero(outbuf, sizeof(outbuf));
+
+ p = outbuf;
+
+ SCVAL(p, 0, ANN_GetBackupListReq);
+ p++;
+
+ SCVAL(p, 0, 1); /* Count pointer ... */
+ p++;
+
+ SIVAL(p, 0, 1); /* The sender's token ... */
+ p += 4;
+
+ cli_send_mailslot(dgram_sock, True, "\\MAILSLOT\\BROWSE", outbuf,
+ PTR_DIFF(p, outbuf), myname, 0, send_to_name,
+ 0x1d, sendto_ip, my_ip, 138, sock_out.sin_port);
+
+ /* We should check the error and return if we got one */
+
+ /* Now, get the response ... */
+
+ cli_get_response(dgram_sock, True, "\\MAILSLOT\\BROWSE", cli_backup_list, sizeof(cli_backup_list));
+
+ /* Should check the response here ... FIXME */
+
+ close(dgram_sock);
+
+ return True;
+
+}
+
+/*
+ * cli_get_backup_server: Get the backup list and retrieve a server from it
+ */
+
+int cli_get_backup_server(char *my_name, char *target, char *servername, int namesize)
+{
+
+ /* Get the backup list first. We could pull this from the cache later */
+
+ cli_get_backup_list(my_name, target); /* FIXME: Check the response */
+
+ if (!cli_backup_list[0]) { /* Empty list ... try again */
+
+ cli_get_backup_list(my_name, target);
+
+ }
+
+ strncpy(servername, cli_backup_list, MIN(16, namesize));
+
+ return True;
+
+}
+
+
+
diff --git a/source/libsmb/clistr.c b/source/libsmb/clistr.c
new file mode 100644
index 00000000000..baec3e5da8d
--- /dev/null
+++ b/source/libsmb/clistr.c
@@ -0,0 +1,44 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 3.0
+ client string routines
+ Copyright (C) Andrew Tridgell 2001
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+int clistr_push(struct cli_state *cli, void *dest, const char *src, int dest_len, int flags)
+{
+ return push_string(cli->outbuf, dest, src, dest_len, flags);
+}
+
+int clistr_pull(struct cli_state *cli, char *dest, const void *src, int dest_len, int src_len,
+ int flags)
+{
+ return pull_string(cli->inbuf, dest, src, dest_len, src_len, flags);
+}
+
+
+int clistr_align_out(struct cli_state *cli, const void *p, int flags)
+{
+ return align_string(cli->outbuf, p, flags);
+}
+
+int clistr_align_in(struct cli_state *cli, const void *p, int flags)
+{
+ return align_string(cli->inbuf, p, flags);
+}
diff --git a/source/libsmb/libsmbclient.c b/source/libsmb/libsmbclient.c
new file mode 100644
index 00000000000..b9441746651
--- /dev/null
+++ b/source/libsmb/libsmbclient.c
@@ -0,0 +1,2515 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ SMB client library implementation
+ Copyright (C) Andrew Tridgell 1998
+ Copyright (C) Richard Sharpe 2000
+ Copyright (C) John Terpstra 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "libsmbclient.h"
+
+/* Structure for servers ... Held here so we don't need an include ...
+ * May be better to put in an include file
+ */
+
+struct smbc_server {
+ struct smbc_server *next, *prev;
+ struct cli_state cli;
+ dev_t dev;
+ char *server_name;
+ char *share_name;
+ char *workgroup;
+ char *username;
+ BOOL no_pathinfo2;
+};
+
+/* Keep directory entries in a list */
+struct smbc_dir_list {
+ struct smbc_dir_list *next;
+ struct smbc_dirent *dirent;
+};
+
+struct smbc_file {
+ int cli_fd;
+ int smbc_fd;
+ char *fname;
+ off_t offset;
+ struct smbc_server *srv;
+ BOOL file;
+ struct smbc_dir_list *dir_list, *dir_end, *dir_next;
+ int dir_type, dir_error;
+};
+
+int smbc_fstatdir(int fd, struct stat *st); /* Forward decl */
+BOOL smbc_getatr(struct smbc_server *srv, char *path,
+ uint16 *mode, size_t *size,
+ time_t *c_time, time_t *a_time, time_t *m_time,
+ SMB_INO_T *ino);
+
+extern BOOL in_client;
+static int smbc_initialized = 0;
+static smbc_get_auth_data_fn smbc_auth_fn = NULL;
+/*static int smbc_debug;*/
+static int smbc_start_fd;
+static int smbc_max_fd = 10000;
+static struct smbc_file **smbc_file_table;
+static struct smbc_server *smbc_srvs;
+static pstring my_netbios_name;
+static pstring smbc_user;
+
+/*
+ * Function to parse a path and turn it into components
+ *
+ * We accept smb://[[[domain;]user[:password@]]server[/share[/path[/file]]]]
+ *
+ * smb:// means show all the workgroups
+ * smb://name/ means, if name<1D> exists, list servers in workgroup,
+ * else, if name<20> exists, list all shares for server ...
+ */
+
+static const char *smbc_prefix = "smb:";
+
+static int
+smbc_parse_path(const char *fname, char *server, char *share, char *path,
+ char *user, char *password) /* FIXME, lengths of strings */
+{
+ static pstring s;
+ pstring userinfo;
+ char *p;
+ int len;
+
+ server[0] = share[0] = path[0] = user[0] = password[0] = (char)0;
+ pstrcpy(s, fname);
+
+ /* clean_fname(s); causing problems ... */
+
+ /* see if it has the right prefix */
+ len = strlen(smbc_prefix);
+ if (strncmp(s,smbc_prefix,len) ||
+ (s[len] != '/' && s[len] != 0)) return -1; /* What about no smb: ? */
+
+ p = s + len;
+
+ /* Watch the test below, we are testing to see if we should exit */
+
+ if (strncmp(p, "//", 2) && strncmp(p, "\\\\", 2)) {
+
+ return -1;
+
+ }
+
+ p += 2; /* Skip the // or \\ */
+
+ if (*p == (char)0)
+ return 0;
+
+ if (*p == '/') {
+
+ strncpy(server, (char *)lp_workgroup(), 16); /* FIXME: Danger here */
+ return 0;
+
+ }
+
+ /*
+ * ok, its for us. Now parse out the server, share etc.
+ *
+ * However, we want to parse out [[domain;]user[:password]@] if it
+ * exists ...
+ */
+
+ if (strchr_m(p, '@')) {
+ pstring username, passwd, domain;
+ char *u = userinfo;
+
+ next_token(&p, userinfo, "@", sizeof(fstring));
+
+ username[0] = passwd[0] = domain[0] = 0;
+
+ if (strchr_m(u, ';')) {
+
+ next_token(&u, domain, ";", sizeof(fstring));
+
+ }
+
+ if (strchr_m(u, ':')) {
+
+ next_token(&u, username, ":", sizeof(fstring));
+
+ pstrcpy(passwd, u);
+
+ }
+ else {
+
+ pstrcpy(username, u);
+
+ }
+
+ if (username[0])
+ strncpy(user, username, sizeof(fstring)); /* FIXME, size and domain */
+
+ if (passwd[0])
+ strncpy(password, passwd, sizeof(fstring)); /* FIXME, size */
+
+ }
+
+ if (!next_token(&p, server, "/", sizeof(fstring))) {
+
+ return -1;
+
+ }
+
+ if (*p == (char)0) return 0; /* That's it ... */
+
+ if (!next_token(&p, share, "/", sizeof(fstring))) {
+
+ return -1;
+
+ }
+
+ pstrcpy(path, p);
+
+ all_string_sub(path, "/", "\\", 0);
+
+ return 0;
+}
+
+/*
+ * Convert an SMB error into a UNIX error ...
+ */
+
+int smbc_errno(struct cli_state *c)
+{
+ uint8 eclass;
+ uint32 ecode;
+ int ret;
+
+ ret = cli_error(c, &eclass, &ecode, NULL);
+
+ if (ret) {
+ DEBUG(3,("smbc_error %d %d (0x%x) -> %d\n",
+ (int)eclass, (int)ecode, (int)ecode, ret));
+ }
+ return ret;
+}
+
+/*
+ * Connect to a server, possibly on an existing connection
+ *
+ * Here, what we want to do is: If the server and username
+ * match an existing connection, reuse that, otherwise, establish a
+ * new connection.
+ *
+ * If we have to create a new connection, call the auth_fn to get the
+ * info we need, unless the username and password were passed in.
+ */
+
+struct smbc_server *smbc_server(char *server, char *share,
+ char *workgroup, char *username,
+ char *password)
+{
+ struct smbc_server *srv=NULL;
+ struct cli_state c;
+ struct nmb_name called, calling;
+ char *p, *server_n = server;
+ fstring group;
+ pstring ipenv;
+ struct in_addr ip;
+ extern struct in_addr ipzero;
+
+ ip = ipzero;
+ ZERO_STRUCT(c);
+
+ /* try to use an existing connection */
+ for (srv=smbc_srvs;srv;srv=srv->next) {
+ if (strcmp(server,srv->server_name)==0 &&
+ strcmp(share,srv->share_name)==0 &&
+ strcmp(workgroup,srv->workgroup)==0 &&
+ strcmp(username, srv->username) == 0)
+ return srv;
+ }
+
+ if (server[0] == 0) {
+ errno = EPERM;
+ return NULL;
+ }
+
+ /*
+ * Pick up the auth info here, once we know we need to connect
+ * But only if we do not have a username and password ...
+ */
+
+ if (!username[0] || !password[0])
+ smbc_auth_fn(server, share, workgroup, sizeof(fstring),
+ username, sizeof(fstring), password, sizeof(fstring));
+
+ /*
+ * However, smbc_auth_fn may have picked up info relating to an
+ * existing connection, so try for an existing connection again ...
+ */
+
+ for (srv=smbc_srvs;srv;srv=srv->next) {
+ if (strcmp(server,srv->server_name)==0 &&
+ strcmp(share,srv->share_name)==0 &&
+ strcmp(workgroup,srv->workgroup)==0 &&
+ strcmp(username, srv->username) == 0)
+ return srv;
+ }
+
+ make_nmb_name(&calling, my_netbios_name, 0x0);
+ make_nmb_name(&called , server, 0x20);
+
+ DEBUG(4,("smbc_server: server_n=[%s] server=[%s]\n", server_n, server));
+
+ if ((p=strchr_m(server_n,'#')) &&
+ (strcmp(p+1,"1D")==0 || strcmp(p+1,"01")==0)) {
+
+ fstrcpy(group, server_n);
+ p = strchr_m(group,'#');
+ *p = 0;
+
+ }
+
+ DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));
+
+ again:
+ slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n);
+
+ ip = ipzero;
+
+ /* have to open a new connection */
+ if (!cli_initialise(&c) || !cli_connect(&c, server_n, &ip)) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ if (!cli_session_request(&c, &calling, &called)) {
+ cli_shutdown(&c);
+ if (strcmp(called.name, "*SMBSERVER")) {
+ make_nmb_name(&called , "*SMBSERVER", 0x20);
+ goto again;
+ }
+ errno = ENOENT;
+ return NULL;
+ }
+
+ DEBUG(4,(" session request ok\n"));
+
+ if (!cli_negprot(&c)) {
+ cli_shutdown(&c);
+ errno = ENOENT;
+ return NULL;
+ }
+
+ if (!cli_session_setup(&c, username,
+ password, strlen(password),
+ password, strlen(password),
+ workgroup) &&
+ /* try an anonymous login if it failed */
+ !cli_session_setup(&c, "", "", 1,"", 0, workgroup)) {
+ cli_shutdown(&c);
+ errno = EPERM;
+ return NULL;
+ }
+
+ DEBUG(4,(" session setup ok\n"));
+
+ if (!cli_send_tconX(&c, share, "?????",
+ password, strlen(password)+1)) {
+ errno = smbc_errno(&c);
+ cli_shutdown(&c);
+ return NULL;
+ }
+
+ DEBUG(4,(" tconx ok\n"));
+
+ srv = (struct smbc_server *)malloc(sizeof(*srv));
+ if (!srv) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ ZERO_STRUCTP(srv);
+
+ srv->cli = c;
+
+ srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
+
+ srv->server_name = strdup(server);
+ if (!srv->server_name) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ srv->share_name = strdup(share);
+ if (!srv->share_name) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ srv->workgroup = strdup(workgroup);
+ if (!srv->workgroup) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ srv->username = strdup(username);
+ if (!srv->username) {
+ errno = ENOMEM;
+ goto failed;
+ }
+
+ DLIST_ADD(smbc_srvs, srv);
+
+ return srv;
+
+ failed:
+ cli_shutdown(&c);
+ if (!srv) return NULL;
+
+ if (srv->server_name) free(srv->server_name);
+ if (srv->share_name) free(srv->share_name);
+ free(srv);
+ return NULL;
+}
+
+/*
+ *Initialise the library etc
+ *
+ * We accept valiv values for debug from 0 to 100,
+ * and insist that fn must be non-null.
+ */
+
+int smbc_init(smbc_get_auth_data_fn fn, int debug)
+{
+ pstring conf;
+ int p, pid;
+ char *user = NULL, *home = NULL, *pname="libsmbclient";
+
+ /*
+ * Next lot ifdef'd out until test suite fixed ...
+ */
+
+ if (!fn || debug < 0 || debug > 100) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (smbc_initialized) { /* Don't go through this if we have already done it */
+
+ return 0;
+
+ }
+
+ smbc_initialized = 1;
+ smbc_auth_fn = fn;
+ /* smbc_debug = debug; */
+
+ DEBUGLEVEL = -1;
+
+ setup_logging(pname, False);
+
+ /*
+ * We try to construct our netbios name from our hostname etc
+ */
+
+ user = getenv("USER");
+ if (!user) user = ""; /* FIXME: What to do about this? */
+
+ /*
+ * FIXME: Is this the best way to get the user info? */
+
+ pstrcpy(smbc_user, user); /* Save for use elsewhere */
+
+ pid = getpid();
+
+ /*
+ * Hmmm, I want to get hostname as well, but I am too lazy for the moment
+ */
+
+ slprintf(my_netbios_name, 16, "smbc%s%d", user, pid);
+
+ /* Here we would open the smb.conf file if needed ... */
+
+ home = getenv("HOME");
+
+ slprintf(conf, sizeof(conf), "%s/.smb/smb.conf", home);
+
+ load_interfaces(); /* Load the list of interfaces ... */
+
+ in_client = True; /* FIXME, make a param */
+
+ if (!lp_load(conf, True, False, False)) {
+
+ /*
+ * Hmmm, what the hell do we do here ... we could not parse the
+ * config file ... We must return an error ... and keep info around
+ * about why we failed
+ */
+
+ errno = ENOENT; /* FIXME: Figure out the correct error response */
+ return -1;
+
+ }
+
+ reopen_logs(); /* Get logging working ... */
+
+ name_register_wins(my_netbios_name, 0);
+
+ /*
+ * Now initialize the file descriptor array and figure out what the
+ * max open files is, so we can return FD's that are above the max
+ * open file, and separated by a guard band
+ */
+
+#if (defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE))
+ do {
+ struct rlimit rlp;
+
+ if (getrlimit(RLIMIT_NOFILE, &rlp)) {
+
+ DEBUG(0, ("smbc_init: getrlimit(1) for RLIMIT_NOFILE failed with error %s\n", strerror(errno)));
+
+ smbc_start_fd = 1000000;
+ smbc_max_fd = 10000; /* FIXME, should be a define ... */
+
+ }
+ else {
+
+ smbc_start_fd = rlp.rlim_max + 10000; /* Leave a guard space of 10,000 */
+ smbc_max_fd = 10000;
+
+ }
+ } while ( 0 );
+#else /* !defined(HAVE_GETRLIMIT) || !defined(RLIMIT_NOFILE) */
+
+ smbc_start_fd = 1000000;
+ smbc_max_fd = 10000; /* FIXME, should be a define ... */
+
+#endif
+
+ smbc_file_table = malloc(smbc_max_fd * sizeof(struct smbc_file *));
+
+ for (p = 0; p < smbc_max_fd; p++)
+ smbc_file_table[p] = NULL;
+
+ if (!smbc_file_table)
+ return ENOMEM;
+
+ return 0; /* Success */
+
+}
+
+/*
+ * Routine to open() a file ...
+ */
+
+int smbc_open(const char *fname, int flags, mode_t mode)
+{
+ fstring server, share, user, password;
+ pstring path;
+ struct smbc_server *srv = NULL;
+ int fd;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ smbc_parse_path(fname, server, share, path, user, password); /* FIXME, check errors */
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ srv = smbc_server(server, share, lp_workgroup(), user, password);
+
+ if (!srv) {
+
+ if (errno == EPERM) errno = EACCES;
+ return -1; /* smbc_server sets errno */
+
+ }
+
+ /* Hmmm, the test for a directory is suspect here ... FIXME */
+
+ if (strlen(path) > 0 && path[strlen(path) - 1] == '\\') {
+
+ fd = -1;
+
+ }
+ else {
+
+ int slot = 0;
+
+ /* Find a free slot first */
+
+ while (smbc_file_table[slot])
+ slot++;
+
+ if (slot > smbc_max_fd) {
+
+ errno = ENOMEM; /* FIXME, is this best? */
+ return -1;
+
+ }
+
+ smbc_file_table[slot] = malloc(sizeof(struct smbc_file));
+
+ if (!smbc_file_table[slot]) {
+
+ errno = ENOMEM;
+ return -1;
+
+ }
+
+ if ((fd = cli_open(&srv->cli, path, flags, DENY_NONE)) < 0) {
+
+ /* Handle the error ... */
+
+ free(smbc_file_table[slot]);
+ smbc_file_table[slot] = NULL;
+ errno = smbc_errno(&srv->cli);
+ return -1;
+
+ }
+
+ /* Fill in file struct */
+
+ smbc_file_table[slot]->cli_fd = fd;
+ smbc_file_table[slot]->smbc_fd = slot + smbc_start_fd;
+ smbc_file_table[slot]->fname = strdup(fname);
+ smbc_file_table[slot]->srv = srv;
+ smbc_file_table[slot]->offset = 0;
+ smbc_file_table[slot]->file = True;
+
+ return smbc_file_table[slot]->smbc_fd;
+
+ }
+
+ /* Check if opendir needed ... */
+
+ if (fd == -1) {
+ int eno = 0;
+
+ eno = smbc_errno(&srv->cli);
+ fd = smbc_opendir(fname);
+ if (fd < 0) errno = eno;
+ return fd;
+
+ }
+
+ return 1; /* Success, with fd ... */
+
+}
+
+/*
+ * Routine to create a file
+ */
+
+static int creat_bits = O_WRONLY | O_CREAT | O_TRUNC; /* FIXME: Do we need this */
+
+int smbc_creat(const char *path, mode_t mode)
+{
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ return smbc_open(path, creat_bits, mode);
+}
+
+/*
+ * Routine to read() a file ...
+ */
+
+ssize_t smbc_read(int fd, void *buf, size_t count)
+{
+ struct smbc_file *fe;
+ int ret;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_read(%d, %d)\n", fd, (int)count));
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + smbc_max_fd)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ /* Check that the buffer exists ... */
+
+ if (buf == NULL) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe || !fe->file) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ ret = cli_read(&fe->srv->cli, fe->cli_fd, buf, fe->offset, count);
+
+ if (ret < 0) {
+
+ errno = smbc_errno(&fe->srv->cli);
+ return -1;
+
+ }
+
+ fe->offset += ret;
+
+ DEBUG(4, (" --> %d\n", ret));
+
+ return ret; /* Success, ret bytes of data ... */
+
+}
+
+/*
+ * Routine to write() a file ...
+ */
+
+ssize_t smbc_write(int fd, void *buf, size_t count)
+{
+ int ret;
+ struct smbc_file *fe;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + smbc_max_fd)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ /* Check that the buffer exists ... */
+
+ if (buf == NULL) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe || !fe->file) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ ret = cli_write(&fe->srv->cli, fe->cli_fd, 0, buf, fe->offset, count);
+
+ if (ret <= 0) {
+
+ errno = smbc_errno(&fe->srv->cli);
+ return -1;
+
+ }
+
+ fe->offset += ret;
+
+ return ret; /* Success, 0 bytes of data ... */
+}
+
+/*
+ * Routine to close() a file ...
+ */
+
+int smbc_close(int fd)
+{
+ struct smbc_file *fe;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + smbc_max_fd)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ if (!fe->file) {
+
+ return smbc_closedir(fd);
+
+ }
+
+ if (!cli_close(&fe->srv->cli, fe->cli_fd)) {
+
+ errno = smbc_errno(&fe->srv->cli); /* FIXME, should we deallocate slot? */
+ return -1;
+
+ }
+
+ if (fe->fname) free(fe->fname);
+ free(fe);
+ smbc_file_table[fd - smbc_start_fd] = NULL;
+
+ return 0;
+}
+
+/*
+ * Routine to unlink() a file
+ */
+
+int smbc_unlink(const char *fname)
+{
+ fstring server, share, user, password;
+ pstring path;
+ struct smbc_server *srv = NULL;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ smbc_parse_path(fname, server, share, path, user, password); /* FIXME, check errors */
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ srv = smbc_server(server, share, lp_workgroup(), user, password);
+
+ if (!srv) {
+
+ return -1; /* smbc_server sets errno */
+
+ }
+
+ /* if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
+
+ int job = smbc_stat_printjob(srv, path, NULL, NULL);
+ if (job == -1) {
+
+ return -1;
+
+ }
+ if ((err = cli_printjob_del(&srv->cli, job)) != 0) {
+
+
+ return -1;
+
+ }
+ } else */
+
+ if (!cli_unlink(&srv->cli, path)) {
+
+ errno = smbc_errno(&srv->cli);
+
+ if (errno == EACCES) { /* Check if the file is a directory */
+
+ int saverr = errno;
+ size_t size = 0;
+ uint16 mode = 0;
+ time_t m_time = 0, a_time = 0, c_time = 0;
+ SMB_INO_T ino = 0;
+
+ if (!smbc_getatr(srv, path, &mode, &size,
+ &c_time, &a_time, &m_time, &ino)) {
+
+ /* Hmmm, bad error ... What? */
+
+ errno = smbc_errno(&srv->cli);
+ return -1;
+
+ }
+ else {
+
+ if (IS_DOS_DIR(mode))
+ errno = EISDIR;
+ else
+ errno = saverr; /* Restore this */
+
+ }
+ }
+
+ return -1;
+
+ }
+
+ return 0; /* Success ... */
+
+}
+
+/*
+ * Routine to rename() a file
+ */
+
+int smbc_rename(const char *oname, const char *nname)
+{
+ fstring server1, share1, server2, share2, user1, user2, password1, password2;
+ pstring path1, path2;
+ struct smbc_server *srv = NULL;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ return -1;
+
+ }
+
+ if (!oname || !nname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_rename(%s,%s)\n", oname, nname));
+
+ smbc_parse_path(oname, server1, share1, path1, user1, password1);
+
+ if (user1[0] == (char)0) pstrcpy(user1, smbc_user);
+
+ smbc_parse_path(nname, server2, share2, path2, user2, password2);
+
+ if (user2[0] == (char)0) pstrcpy(user2, smbc_user);
+
+ if (strcmp(server1, server2) || strcmp(share1, share2) ||
+ strcmp(user1, user2)) {
+
+ /* Can't rename across file systems, or users?? */
+
+ errno = EXDEV;
+ return -1;
+
+ }
+
+ srv = smbc_server(server1, share1, lp_workgroup(), user1, password1);
+ if (!srv) {
+
+ return -1;
+
+ }
+
+ if (!cli_rename(&srv->cli, path1, path2)) {
+ int eno = smbc_errno(&srv->cli);
+
+ if (eno != EEXIST ||
+ !cli_unlink(&srv->cli, path2) ||
+ !cli_rename(&srv->cli, path1, path2)) {
+
+ errno = eno;
+ return -1;
+
+ }
+ }
+
+ return 0; /* Success */
+
+}
+
+/*
+ * A routine to lseek() a file
+ */
+
+off_t smbc_lseek(int fd, off_t offset, int whence)
+{
+ struct smbc_file *fe;
+ size_t size;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + smbc_max_fd)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ if (!fe->file) {
+
+ errno = EINVAL;
+ return -1; /* Can't lseek a dir ... */
+
+ }
+
+ switch (whence) {
+ case SEEK_SET:
+ fe->offset = offset;
+ break;
+
+ case SEEK_CUR:
+ fe->offset += offset;
+ break;
+
+ case SEEK_END:
+ if (!cli_qfileinfo(&fe->srv->cli, fe->cli_fd, NULL, &size, NULL, NULL,
+ NULL, NULL, NULL) &&
+ !cli_getattrE(&fe->srv->cli, fe->cli_fd, NULL, &size, NULL, NULL,
+ NULL)) {
+
+ errno = EINVAL;
+ return -1;
+ }
+ fe->offset = size + offset;
+ break;
+
+ default:
+ errno = EINVAL;
+ break;
+
+ }
+
+ return fe->offset;
+
+}
+
+/*
+ * Generate an inode number from file name for those things that need it
+ */
+
+static
+ino_t smbc_inode(const char *name)
+{
+
+ if (!*name) return 2; /* FIXME, why 2 ??? */
+ return (ino_t)str_checksum(name);
+
+}
+
+/*
+ * Routine to put basic stat info into a stat structure ... Used by stat and
+ * fstat below.
+ */
+
+static
+int smbc_setup_stat(struct stat *st, char *fname, size_t size, int mode)
+{
+
+ st->st_mode = 0;
+
+ if (IS_DOS_DIR(mode)) {
+ st->st_mode = SMBC_DIR_MODE;
+ } else {
+ st->st_mode = SMBC_FILE_MODE;
+ }
+
+ if (IS_DOS_ARCHIVE(mode)) st->st_mode |= S_IXUSR;
+ if (IS_DOS_SYSTEM(mode)) st->st_mode |= S_IXGRP;
+ if (IS_DOS_HIDDEN(mode)) st->st_mode |= S_IXOTH;
+ if (!IS_DOS_READONLY(mode)) st->st_mode |= S_IWUSR;
+
+ st->st_size = size;
+ st->st_blksize = 512;
+ st->st_blocks = (size+511)/512;
+ st->st_uid = getuid();
+ st->st_gid = getgid();
+
+ if (IS_DOS_DIR(mode)) {
+ st->st_nlink = 2;
+ } else {
+ st->st_nlink = 1;
+ }
+
+ if (st->st_ino == 0) {
+ st->st_ino = smbc_inode(fname);
+ }
+
+ return True; /* FIXME: Is this needed ? */
+
+}
+
+/*
+ * Get info from an SMB server on a file. Use a qpathinfo call first
+ * and if that fails, use getatr, as Win95 sometimes refuses qpathinfo
+ */
+
+BOOL smbc_getatr(struct smbc_server *srv, char *path,
+ uint16 *mode, size_t *size,
+ time_t *c_time, time_t *a_time, time_t *m_time,
+ SMB_INO_T *ino)
+{
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4,("smbc_getatr: sending qpathinfo\n"));
+
+ if (!srv->no_pathinfo2 &&
+ cli_qpathinfo2(&srv->cli, path, c_time, a_time, m_time, NULL,
+ size, mode, ino)) return True;
+
+ /* if this is NT then don't bother with the getatr */
+ if (srv->cli.capabilities & CAP_NT_SMBS) return False;
+
+ if (cli_getatr(&srv->cli, path, mode, size, m_time)) {
+ a_time = c_time = m_time;
+ srv->no_pathinfo2 = True;
+ return True;
+ }
+ return False;
+}
+
+/*
+ * Routine to stat a file given a name
+ */
+
+int smbc_stat(const char *fname, struct stat *st)
+{
+ struct smbc_server *srv;
+ fstring server, share, user, password;
+ pstring path;
+ time_t m_time = 0, a_time = 0, c_time = 0;
+ size_t size = 0;
+ uint16 mode = 0;
+ SMB_INO_T ino = 0;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL; /* Best I can think of ... */
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_stat(%s)\n", fname));
+
+ smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ srv = smbc_server(server, share, lp_workgroup(), user, password);
+
+ if (!srv) {
+
+ return -1; /* errno set by smbc_server */
+
+ }
+
+ /* if (strncmp(srv->cli.dev, "IPC", 3) == 0) {
+
+ mode = aDIR | aRONLY;
+
+ }
+ else if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
+
+ if (strcmp(path, "\\") == 0) {
+
+ mode = aDIR | aRONLY;
+
+ }
+ else {
+
+ mode = aRONLY;
+ smbc_stat_printjob(srv, path, &size, &m_time);
+ c_time = a_time = m_time;
+
+ }
+ else { */
+
+ if (!smbc_getatr(srv, path, &mode, &size,
+ &c_time, &a_time, &m_time, &ino)) {
+
+ errno = smbc_errno(&srv->cli);
+ return -1;
+
+ }
+
+ /* } */
+
+ st->st_ino = ino;
+
+ smbc_setup_stat(st, path, size, mode);
+
+ st->st_atime = a_time;
+ st->st_ctime = c_time;
+ st->st_mtime = m_time;
+ st->st_dev = srv->dev;
+
+ return 0;
+
+}
+
+/*
+ * Routine to stat a file given an fd
+ */
+
+int smbc_fstat(int fd, struct stat *st)
+{
+ struct smbc_file *fe;
+ time_t c_time, a_time, m_time;
+ size_t size;
+ uint16 mode;
+ SMB_INO_T ino = 0;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + smbc_max_fd)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ if (!fe->file) {
+
+ return smbc_fstatdir(fd, st);
+
+ }
+
+ if (!cli_qfileinfo(&fe->srv->cli, fe->cli_fd,
+ &mode, &size, &c_time, &a_time, &m_time, NULL, &ino) &&
+ !cli_getattrE(&fe->srv->cli, fe->cli_fd,
+ &mode, &size, &c_time, &a_time, &m_time)) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ st->st_ino = ino;
+
+ smbc_setup_stat(st, fe->fname, size, mode);
+
+ st->st_atime = a_time;
+ st->st_ctime = c_time;
+ st->st_mtime = m_time;
+ st->st_dev = fe->srv->dev;
+
+ return 0;
+
+}
+
+/*
+ * Routine to open a directory
+ *
+ * We want to allow:
+ *
+ * smb: which should list all the workgroups available
+ * smb:workgroup
+ * smb:workgroup//server
+ * smb://server
+ * smb://server/share
+ */
+
+static void smbc_remove_dir(struct smbc_file *dir)
+{
+ struct smbc_dir_list *d,*f;
+
+ d = dir->dir_list;
+ while (d) {
+
+ f = d; d = d->next;
+
+ if (f->dirent) free(f->dirent);
+ free(f);
+
+ }
+
+ dir->dir_list = dir->dir_end = dir->dir_next = NULL;
+
+}
+
+static int add_dirent(struct smbc_file *dir, const char *name, const char *comment, uint32 type)
+{
+ struct smbc_dirent *dirent;
+ int size;
+
+ /*
+ * Allocate space for the dirent, which must be increased by the
+ * size of the name and the comment and 1 for the null on the comment.
+ * The null on the name is already accounted for.
+ */
+
+ size = sizeof(struct smbc_dirent) + (name?strlen(name):0) +
+ (comment?strlen(comment):0) + 1;
+
+ dirent = malloc(size);
+
+ if (!dirent) {
+
+ dir->dir_error = ENOMEM;
+ return -1;
+
+ }
+
+ if (dir->dir_list == NULL) {
+
+ dir->dir_list = malloc(sizeof(struct smbc_dir_list));
+ if (!dir->dir_list) {
+
+ free(dirent);
+ dir->dir_error = ENOMEM;
+ return -1;
+
+ }
+
+ dir->dir_end = dir->dir_next = dir->dir_list;
+
+ }
+ else {
+
+ dir->dir_end->next = malloc(sizeof(struct smbc_dir_list));
+
+ if (!dir->dir_end) {
+
+ free(dirent);
+ dir->dir_error = ENOMEM;
+ return -1;
+
+ }
+
+ dir->dir_end = dir->dir_end->next;
+
+ }
+
+ dir->dir_end->next = NULL;
+ dir->dir_end->dirent = dirent;
+
+ dirent->smbc_type = type;
+ dirent->namelen = (name?strlen(name):0);
+ dirent->commentlen = (comment?strlen(comment):0);
+ dirent->dirlen = size;
+
+ strncpy(dirent->name, (name?name:""), dirent->namelen + 1);
+
+ dirent->comment = (char *)(&dirent->name + dirent->namelen + 1);
+ strncpy(dirent->comment, (comment?comment:""), dirent->commentlen + 1);
+
+ return 0;
+
+}
+
+static void
+list_fn(const char *name, uint32 type, const char *comment, void *state)
+{
+ struct smbc_file *dir = (struct smbc_file *)state;
+ int dirent_type;
+
+ /* We need to process the type a little ... */
+
+ if (dir->dir_type == SMBC_FILE_SHARE) {
+
+ switch (type) {
+ case 0: /* Directory tree */
+ dirent_type = SMBC_FILE_SHARE;
+ break;
+
+ case 1:
+ dirent_type = SMBC_PRINTER_SHARE;
+ break;
+
+ case 2:
+ dirent_type = SMBC_COMMS_SHARE;
+ break;
+
+ case 3:
+ dirent_type = SMBC_IPC_SHARE;
+ break;
+
+ default:
+ dirent_type = SMBC_FILE_SHARE; /* FIXME, error? */
+ break;
+ }
+
+ }
+ else dirent_type = dir->dir_type;
+
+ if (add_dirent(dir, name, comment, dirent_type) < 0) {
+
+ /* An error occurred, what do we do? */
+
+ }
+
+}
+
+static void
+dir_list_fn(file_info *finfo, const char *mask, void *state)
+{
+
+ /* fprintf(stderr, "Finfo->name=%s, mask=%s, mode=%0X\n", finfo->name, mask, finfo->mode);*/
+ if (add_dirent((struct smbc_file *)state, finfo->name, "",
+ (finfo->mode&aDIR?SMBC_DIR:SMBC_FILE)) < 0) {
+
+ /* Handle an error ... */
+
+ }
+
+}
+
+int smbc_opendir(const char *fname)
+{
+ fstring server, share, user, password;
+ pstring path;
+ struct smbc_server *srv = NULL;
+ struct in_addr rem_ip;
+ int slot = 0;
+ uint8 eclass;
+ uint32 ecode;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (smbc_parse_path(fname, server, share, path, user, password)) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ /* Get a file entry ... */
+
+ slot = 0;
+
+ while (smbc_file_table[slot])
+ slot++;
+
+ if (slot > smbc_max_fd) {
+
+ errno = ENOMEM;
+ return -1; /* FIXME, ... move into a func */
+
+ }
+
+ smbc_file_table[slot] = malloc(sizeof(struct smbc_file));
+
+ if (!smbc_file_table[slot]) {
+
+ errno = ENOMEM;
+ return -1;
+
+ }
+
+ smbc_file_table[slot]->cli_fd = 0;
+ smbc_file_table[slot]->smbc_fd = slot + smbc_start_fd;
+ smbc_file_table[slot]->fname = strdup(fname);
+ smbc_file_table[slot]->srv = NULL;
+ smbc_file_table[slot]->offset = 0;
+ smbc_file_table[slot]->file = False;
+ smbc_file_table[slot]->dir_list =
+ smbc_file_table[slot]->dir_next =
+ smbc_file_table[slot]->dir_end = NULL;
+
+ if (server[0] == (char)0) {
+
+ if (share[0] != (char)0 || path[0] != (char)0) {
+
+ errno = EINVAL;
+ if (smbc_file_table[slot]) {
+ if (smbc_file_table[slot]->fname) free(smbc_file_table[slot]->fname);
+ free(smbc_file_table[slot]);
+ }
+ smbc_file_table[slot] = NULL;
+ return -1;
+
+ }
+
+ /* We have server and share and path empty ... so list the workgroups */
+
+ /*cli_get_backup_server(my_netbios_name, lp_workgroup(), server, sizeof(server));*/
+
+ if (!resolve_name(lp_workgroup(), &rem_ip, 0x1d)) {
+
+ errno = EINVAL; /* Something wrong with smb.conf? */
+ return -1;
+
+ }
+
+ smbc_file_table[slot]->dir_type = SMBC_WORKGROUP;
+
+ /* find the name of the server ... */
+
+ if (!name_status_find(0, rem_ip, server)) {
+
+ fprintf(stderr, "Could not get the name of local master browser ...\n");
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ /*
+ * Get a connection to IPC$ on the server if we do not already have one
+ */
+
+ srv = smbc_server(server, "IPC$", lp_workgroup(), user, password);
+
+ if (!srv) {
+
+ if (smbc_file_table[slot]) {
+ if (smbc_file_table[slot]->fname) free(smbc_file_table[slot]->fname);
+ free(smbc_file_table[slot]);
+ }
+ smbc_file_table[slot] = NULL;
+ return -1;
+
+ }
+
+ smbc_file_table[slot]->srv = srv;
+
+ /* Now, list the stuff ... */
+
+ if (!cli_NetServerEnum(&srv->cli, lp_workgroup(), 0x80000000, list_fn,
+ (void *)smbc_file_table[slot])) {
+
+ if (smbc_file_table[slot]) {
+ if (smbc_file_table[slot]->fname) free(smbc_file_table[slot]->fname);
+ free(smbc_file_table[slot]);
+ }
+ smbc_file_table[slot] = NULL;
+ errno = cli_error(&srv->cli, &eclass, &ecode, NULL);
+ return -1;
+
+ }
+ }
+ else { /* Server not an empty string ... Check the rest and see what gives */
+
+ if (share[0] == (char)0) {
+
+ if (path[0] != (char)0) { /* Should not have empty share with path */
+
+ errno = EINVAL;
+ if (smbc_file_table[slot]) {
+ if (smbc_file_table[slot]->fname) free(smbc_file_table[slot]->fname);
+ free(smbc_file_table[slot]);
+ }
+ smbc_file_table[slot] = NULL;
+ return -1;
+
+ }
+
+ /* Check to see if <server><1D> translates, or <server><20> translates */
+
+ if (resolve_name(server, &rem_ip, 0x1d)) { /* Found LMB */
+ pstring buserver;
+
+ smbc_file_table[slot]->dir_type = SMBC_SERVER;
+
+ /*
+ * Get the backup list ...
+ */
+
+ /*cli_get_backup_server(my_netbios_name, server, buserver, sizeof(buserver)); */
+
+ if (!name_status_find(0, rem_ip, buserver)) {
+
+ fprintf(stderr, "Could not get name of local master browser ...\n");
+ errno = EPERM; /* FIXME, is this correct */
+ return -1;
+
+ }
+
+ /*
+ * Get a connection to IPC$ on the server if we do not already have one
+ */
+
+ srv = smbc_server(buserver, "IPC$", lp_workgroup(), user, password);
+
+ if (!srv) {
+
+ if (smbc_file_table[slot]) {
+ if (smbc_file_table[slot]->fname) free(smbc_file_table[slot]->fname);
+ free(smbc_file_table[slot]);
+ }
+ smbc_file_table[slot] = NULL; /* FIXME: Memory leaks ... */
+ return -1;
+
+ }
+
+ smbc_file_table[slot]->srv = srv;
+
+ /* Now, list the servers ... */
+
+ if (!cli_NetServerEnum(&srv->cli, server, 0x0000FFFE, list_fn,
+ (void *)smbc_file_table[slot])) {
+
+ if (smbc_file_table[slot]) {
+ if (smbc_file_table[slot]->fname) free(smbc_file_table[slot]->fname);
+ free(smbc_file_table[slot]);
+ }
+ smbc_file_table[slot] = NULL;
+ errno = cli_error(&srv->cli, &eclass, &ecode, NULL);
+ return -1;
+
+ }
+
+ }
+ else {
+
+ if (resolve_name(server, &rem_ip, 0x20)) {
+
+ /* Now, list the shares ... */
+
+ smbc_file_table[slot]->dir_type = SMBC_FILE_SHARE;
+
+ srv = smbc_server(server, "IPC$", lp_workgroup(), user, password);
+
+ if (!srv) {
+
+ if (smbc_file_table[slot]) {
+ if (smbc_file_table[slot]->fname) free(smbc_file_table[slot]->fname);
+ free(smbc_file_table[slot]);
+ }
+ smbc_file_table[slot] = NULL;
+ return -1;
+
+ }
+
+ smbc_file_table[slot]->srv = srv;
+
+ /* Now, list the servers ... */
+
+ if (cli_RNetShareEnum(&srv->cli, list_fn,
+ (void *)smbc_file_table[slot]) < 0) {
+
+ errno = cli_error(&srv->cli, &eclass, &ecode, NULL);
+ if (smbc_file_table[slot]) {
+ if (smbc_file_table[slot]->fname) free(smbc_file_table[slot]->fname);
+ free(smbc_file_table[slot]);
+ }
+ smbc_file_table[slot] = NULL;
+ return -1;
+
+ }
+
+ }
+ else {
+
+ errno = ENODEV; /* Neither the workgroup nor server exists */
+ if (smbc_file_table[slot]) {
+ if (smbc_file_table[slot]->fname) free(smbc_file_table[slot]->fname);
+ free(smbc_file_table[slot]);
+ }
+ smbc_file_table[slot] = NULL;
+ return -1;
+
+ }
+
+ }
+
+ }
+ else { /* The server and share are specified ... work from there ... */
+
+ /* Well, we connect to the server and list the directory */
+
+ smbc_file_table[slot]->dir_type = SMBC_FILE_SHARE;
+
+ srv = smbc_server(server, share, lp_workgroup(), user, password);
+
+ if (!srv) {
+
+ if (smbc_file_table[slot]) {
+ if (smbc_file_table[slot]->fname) free(smbc_file_table[slot]->fname);
+ free(smbc_file_table[slot]);
+ }
+ smbc_file_table[slot] = NULL;
+ return -1;
+
+ }
+
+ smbc_file_table[slot]->srv = srv;
+
+ /* Now, list the files ... */
+
+ pstrcat(path, "\\*");
+
+ if (cli_list(&srv->cli, path, aDIR | aSYSTEM | aHIDDEN, dir_list_fn,
+ (void *)smbc_file_table[slot]) < 0) {
+
+ if (smbc_file_table[slot]) {
+ if (smbc_file_table[slot]->fname) free(smbc_file_table[slot]->fname);
+ free(smbc_file_table[slot]);
+ }
+ smbc_file_table[slot] = NULL;
+ errno = smbc_errno(&srv->cli);
+ return -1;
+
+ }
+ }
+
+ }
+
+ return smbc_file_table[slot]->smbc_fd;
+
+}
+
+/*
+ * Routine to close a directory
+ */
+
+int smbc_closedir(int fd)
+{
+ struct smbc_file *fe;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + smbc_max_fd)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ smbc_remove_dir(fe); /* Clean it up */
+
+ if (fe) {
+
+ if (fe->fname) free(fe->fname);
+ free(fe); /* Free the space too */
+
+ }
+
+ smbc_file_table[fd - smbc_start_fd] = NULL;
+
+ return 0;
+
+}
+
+/*
+ * Routine to get a directory entry
+ */
+
+static char smbc_local_dirent[512]; /* Make big enough */
+
+struct smbc_dirent *smbc_readdir(unsigned int fd)
+{
+ struct smbc_file *fe;
+ struct smbc_dirent *dirp, *dirent;
+
+ /* Check that all is ok first ... */
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return NULL;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + smbc_max_fd)) {
+
+ errno = EBADF;
+ return NULL;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return NULL;
+
+ }
+
+ if (fe->file != False) { /* FIXME, should be dir, perhaps */
+
+ errno = ENOTDIR;
+ return NULL;
+
+ }
+
+ if (!fe->dir_next)
+ return NULL;
+ else {
+
+ dirent = fe->dir_next->dirent;
+
+ if (!dirent) {
+
+ errno = ENOENT;
+ return NULL;
+
+ }
+
+ /* Hmmm, do I even need to copy it? */
+
+ bcopy(dirent, smbc_local_dirent, dirent->dirlen); /* Copy the dirent */
+
+ dirp = (struct smbc_dirent *)smbc_local_dirent;
+
+ dirp->comment = (char *)(&dirp->name + dirent->namelen + 1);
+
+ fe->dir_next = fe->dir_next->next;
+
+ return (struct smbc_dirent *)smbc_local_dirent;
+ }
+
+}
+
+/*
+ * Routine to get directory entries
+ */
+
+int smbc_getdents(unsigned int fd, struct smbc_dirent *dirp, int count)
+{
+ struct smbc_file *fe;
+ struct smbc_dir_list *dir;
+ int rem = count, reqd;
+ char *ndir = (char *)dirp;
+
+ /* Check that all is ok first ... */
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + smbc_max_fd)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ if (fe->file != False) { /* FIXME, should be dir, perhaps */
+
+ errno = ENOTDIR;
+ return -1;
+
+ }
+
+ /*
+ * Now, retrieve the number of entries that will fit in what was passed
+ * We have to figure out if the info is in the list, or we need to
+ * send a request to the server to get the info.
+ */
+
+ while ((dir = fe->dir_next)) {
+ struct smbc_dirent *dirent;
+
+ if (!dir->dirent) {
+
+ errno = ENOENT; /* Bad error */
+ return -1;
+
+ }
+
+ if (rem < (reqd = (sizeof(struct smbc_dirent) + dir->dirent->namelen +
+ dir->dirent->commentlen + 1))) {
+
+ if (rem < count) { /* We managed to copy something */
+
+ errno = 0;
+ return count - rem;
+
+ }
+ else { /* Nothing copied ... */
+
+ errno = EINVAL; /* Not enough space ... */
+ return -1;
+
+ }
+
+ }
+
+ dirent = dir->dirent;
+
+ bcopy(dirent, ndir, reqd); /* Copy the data in ... */
+
+ ((struct smbc_dirent *)ndir)->comment =
+ (char *)(&((struct smbc_dirent *)ndir)->name + dirent->namelen + 1);
+
+ ndir += reqd;
+
+ rem -= reqd;
+
+ fe->dir_next = dir = dir -> next;
+ }
+
+ if (rem == count)
+ return 0;
+ else
+ return count - rem;
+
+}
+
+/*
+ * Routine to create a directory ...
+ */
+
+int smbc_mkdir(const char *fname, mode_t mode)
+{
+ struct smbc_server *srv;
+ fstring server, share, user, password;
+ pstring path;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_mkdir(%s)\n", fname));
+
+ smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ srv = smbc_server(server, share, lp_workgroup(), user, password);
+
+ if (!srv) {
+
+ return -1; /* errno set by smbc_server */
+
+ }
+
+ /* if (strncmp(srv->cli.dev, "IPC", 3) == 0) {
+
+ mode = aDIR | aRONLY;
+
+ }
+ else if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
+
+ if (strcmp(path, "\\") == 0) {
+
+ mode = aDIR | aRONLY;
+
+ }
+ else {
+
+ mode = aRONLY;
+ smbc_stat_printjob(srv, path, &size, &m_time);
+ c_time = a_time = m_time;
+
+ }
+ else { */
+
+ if (!cli_mkdir(&srv->cli, path)) {
+
+ errno = smbc_errno(&srv->cli);
+ return -1;
+
+ }
+
+ return 0;
+
+}
+
+/*
+ * Our list function simply checks to see if a directory is not empty
+ */
+
+static int smbc_rmdir_dirempty = True;
+
+static void rmdir_list_fn(file_info *finfo, const char *mask, void *state)
+{
+
+ if (strncmp(finfo->name, ".", 1) != 0 && strncmp(finfo->name, "..", 2) != 0)
+ smbc_rmdir_dirempty = False;
+
+}
+
+/*
+ * Routine to remove a directory
+ */
+
+int smbc_rmdir(const char *fname)
+{
+ struct smbc_server *srv;
+ fstring server, share, user, password;
+ pstring path;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_rmdir(%s)\n", fname));
+
+ smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ srv = smbc_server(server, share, lp_workgroup(), user, password);
+
+ if (!srv) {
+
+ return -1; /* errno set by smbc_server */
+
+ }
+
+ /* if (strncmp(srv->cli.dev, "IPC", 3) == 0) {
+
+ mode = aDIR | aRONLY;
+
+ }
+ else if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
+
+ if (strcmp(path, "\\") == 0) {
+
+ mode = aDIR | aRONLY;
+
+ }
+ else {
+
+ mode = aRONLY;
+ smbc_stat_printjob(srv, path, &size, &m_time);
+ c_time = a_time = m_time;
+
+ }
+ else { */
+
+ if (!cli_rmdir(&srv->cli, path)) {
+
+ errno = smbc_errno(&srv->cli);
+
+ if (errno == EACCES) { /* Check if the dir empty or not */
+
+ pstring lpath; /* Local storage to avoid buffer overflows */
+
+ smbc_rmdir_dirempty = True; /* Make this so ... */
+
+ pstrcpy(lpath, path);
+ pstrcat(lpath, "\\*");
+
+ if (cli_list(&srv->cli, lpath, aDIR | aSYSTEM | aHIDDEN, rmdir_list_fn,
+ NULL) < 0) {
+
+ /* Fix errno to ignore latest error ... */
+
+ DEBUG(5, ("smbc_rmdir: cli_list returned an error: %d\n",
+ smbc_errno(&srv->cli)));
+ errno = EACCES;
+
+ }
+
+ if (smbc_rmdir_dirempty)
+ errno = EACCES;
+ else
+ errno = ENOTEMPTY;
+
+ }
+
+ return -1;
+
+ }
+
+ return 0;
+
+}
+
+/*
+ * Routine to return the current directory position
+ */
+
+off_t smbc_telldir(int fd)
+{
+ struct smbc_file *fe;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + smbc_max_fd)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ if (fe->file != False) { /* FIXME, should be dir, perhaps */
+
+ errno = ENOTDIR;
+ return -1;
+
+ }
+
+ return (off_t) fe->dir_next;
+
+}
+
+/*
+ * A routine to run down the list and see if the entry is OK
+ */
+
+struct smbc_dir_list *smbc_check_dir_ent(struct smbc_dir_list *list,
+ struct smbc_dirent *dirent)
+{
+
+ /* Run down the list looking for what we want */
+
+ if (dirent) {
+
+ struct smbc_dir_list *tmp = list;
+
+ while (tmp) {
+
+ if (tmp->dirent == dirent)
+ return tmp;
+
+ tmp = tmp->next;
+
+ }
+
+ }
+
+ return NULL; /* Not found, or an error */
+
+}
+
+
+/*
+ * Routine to seek on a directory
+ */
+
+int smbc_lseekdir(int fd, off_t offset)
+{
+ struct smbc_file *fe;
+ struct smbc_dirent *dirent = (struct smbc_dirent *)offset;
+ struct smbc_dir_list *list_ent = NULL;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (fd < smbc_start_fd || fd >= (smbc_start_fd + smbc_max_fd)) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ fe = smbc_file_table[fd - smbc_start_fd];
+
+ if (!fe) {
+
+ errno = EBADF;
+ return -1;
+
+ }
+
+ if (fe->file != False) { /* FIXME, should be dir, perhaps */
+
+ errno = ENOTDIR;
+ return -1;
+
+ }
+
+ /* Now, check what we were passed and see if it is OK ... */
+
+ if (dirent == NULL) { /* Seek to the begining of the list */
+
+ fe->dir_next = fe->dir_list;
+ return 0;
+
+ }
+
+ /* Now, run down the list and make sure that the entry is OK */
+ /* This may need to be changed if we change the format of the list */
+
+ if ((list_ent = smbc_check_dir_ent(fe->dir_list, dirent)) == NULL) {
+
+ errno = EINVAL; /* Bad entry */
+ return -1;
+
+ }
+
+ fe->dir_next = list_ent;
+
+ return 0;
+
+}
+
+/*
+ * Routine to fstat a dir
+ */
+
+int smbc_fstatdir(int fd, struct stat *st)
+{
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ /* No code yet ... */
+
+ return 0;
+
+}
+
+/*
+ * Routine to print a file on a remote server ...
+ *
+ * We open the file, which we assume to be on a remote server, and then
+ * copy it to a print file on the share specified by printq.
+ */
+
+int smbc_print_file(const char *fname, const char *printq)
+{
+ int fid1, fid2, bytes, saverr, tot_bytes = 0;
+ char buf[4096];
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname && !printq) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ /* Try to open the file for reading ... */
+
+ if ((fid1 = smbc_open(fname, O_RDONLY, 0666)) < 0) {
+
+ fprintf(stderr, "Error, fname=%s, errno=%i\n", fname, errno);
+ return -1; /* smbc_open sets errno */
+
+ }
+
+ /* Now, try to open the printer file for writing */
+
+ if ((fid2 = smbc_open_print_job(printq)) < 0) {
+
+ saverr = errno; /* Save errno */
+ smbc_close(fid1);
+ errno = saverr;
+ return -1;
+
+ }
+
+ while ((bytes = smbc_read(fid1, buf, sizeof(buf))) > 0) {
+
+ tot_bytes += bytes;
+
+ if ((smbc_write(fid2, buf, bytes)) < 0) {
+
+ saverr = errno;
+ smbc_close(fid1);
+ smbc_close(fid2);
+ errno = saverr;
+
+ }
+
+ }
+
+ saverr = errno;
+
+ smbc_close(fid1); /* We have to close these anyway */
+ smbc_close(fid2);
+
+ if (bytes < 0) {
+
+ errno = saverr;
+ return -1;
+
+ }
+
+ return tot_bytes;
+
+}
+
+/*
+ * Open a print file to be written to by other calls
+ */
+
+int smbc_open_print_job(const char *fname)
+{
+ fstring server, share, user, password;
+ pstring path;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_open_print_job(%s)\n", fname));
+
+ smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
+
+ /* What if the path is empty, or the file exists? */
+
+ return smbc_open(fname, O_WRONLY, 666);
+
+}
+
+/*
+ * Routine to list print jobs on a printer share ...
+ */
+
+int smbc_list_print_jobs(const char *fname, void (*fn)(struct print_job_info *))
+{
+ struct smbc_server *srv;
+ fstring server, share, user, password;
+ pstring path;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_list_print_jobs(%s)\n", fname));
+
+ smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ srv = smbc_server(server, share, lp_workgroup(), user, password);
+
+ if (!srv) {
+
+ return -1; /* errno set by smbc_server */
+
+ }
+
+ if (cli_print_queue(&srv->cli, fn) < 0) {
+
+ errno = smbc_errno(&srv->cli);
+ return -1;
+
+ }
+
+ return 0;
+
+}
+
+/*
+ * Delete a print job from a remote printer share
+ */
+
+int smbc_unlink_print_job(const char *fname, int id)
+{
+ struct smbc_server *srv;
+ fstring server, share, user, password;
+ pstring path;
+ int err;
+
+ if (!smbc_initialized) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ if (!fname) {
+
+ errno = EINVAL;
+ return -1;
+
+ }
+
+ DEBUG(4, ("smbc_unlink_print_job(%s)\n", fname));
+
+ smbc_parse_path(fname, server, share, path, user, password); /*FIXME, errors*/
+
+ if (user[0] == (char)0) pstrcpy(user, smbc_user);
+
+ srv = smbc_server(server, share, lp_workgroup(), user, password);
+
+ if (!srv) {
+
+ return -1; /* errno set by smbc_server */
+
+ }
+
+ if ((err = cli_printjob_del(&srv->cli, id)) != 0) {
+
+ if (err < 0)
+ errno = smbc_errno(&srv->cli);
+ else if (err == ERRnosuchprintjob)
+ errno = EINVAL;
+ return -1;
+
+
+ }
+
+ return 0;
+
+}
+
diff --git a/source/pam_smbpass/pam_smb_acct.c b/source/pam_smbpass/pam_smb_acct.c
new file mode 100644
index 00000000000..94a4f226130
--- /dev/null
+++ b/source/pam_smbpass/pam_smb_acct.c
@@ -0,0 +1,112 @@
+/* Unix NT password database implementation, version 0.7.5.
+ *
+ * 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.
+*/
+
+/* indicate the following groups are defined */
+#define PAM_SM_ACCT
+
+#include "includes.h"
+
+#ifndef LINUX
+
+/* This is only used in the Sun implementation. */
+#include <security/pam_appl.h>
+
+#endif /* LINUX */
+
+#include <security/pam_modules.h>
+
+#include "general.h"
+
+#include "support.h"
+
+/*
+ * pam_sm_acct_mgmt() verifies whether or not the account is disabled.
+ *
+ */
+
+int pam_sm_acct_mgmt( pam_handle_t *pamh, int flags,
+ int argc, const char **argv )
+{
+ unsigned int ctrl;
+ int retval;
+
+ const char *name;
+ const char *p;
+ struct smb_passwd *smb_pwent = NULL;
+
+ extern BOOL in_client;
+
+ /* Samba initialization. */
+ setup_logging( "pam_smbpass", False );
+ in_client = True;
+
+ ctrl = set_ctrl( flags, argc, argv );
+
+ /* get the username */
+
+ retval = pam_get_user( pamh, &name, "Username: " );
+ if (retval != PAM_SUCCESS) {
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_DEBUG, "acct: could not identify user" );
+ }
+ return retval;
+ }
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_DEBUG, "acct: username [%s] obtained", name );
+ }
+
+ if (!initialize_password_db()) {
+ _log_err( LOG_ALERT, "Cannot access samba password database" );
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+
+ /* Get the user's record. */
+ smb_pwent = getsmbpwnam( name );
+
+ if (!smb_pwent)
+ return PAM_USER_UNKNOWN;
+
+ if (smb_pwent->acct_ctrl & ACB_DISABLED) {
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_DEBUG
+ , "acct: account %s is administratively disabled", name );
+ }
+ make_remark( pamh, ctrl, PAM_ERROR_MSG
+ , "Your account has been disabled; "
+ "please see your system administrator." );
+
+ return PAM_ACCT_EXPIRED;
+ }
+
+ /* TODO: support for expired passwords. */
+
+ return PAM_SUCCESS;
+}
+
+/* static module data */
+#ifdef PAM_STATIC
+struct pam_module _pam_smbpass_acct_modstruct = {
+ "pam_smbpass",
+ NULL,
+ NULL,
+ pam_sm_acct_mgmt,
+ NULL,
+ NULL,
+ NULL
+};
+#endif
+
diff --git a/source/pam_smbpass/pam_smb_auth.c b/source/pam_smbpass/pam_smb_auth.c
new file mode 100644
index 00000000000..ee4d68dcc35
--- /dev/null
+++ b/source/pam_smbpass/pam_smb_auth.c
@@ -0,0 +1,245 @@
+/* Unix NT password database implementation, version 0.7.5.
+ *
+ * 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.
+*/
+
+/* indicate the following groups are defined */
+#define PAM_SM_AUTH
+
+#include "includes.h"
+#include "debug.h"
+
+#ifndef LINUX
+
+/* This is only used in the Sun implementation. */
+#include <security/pam_appl.h>
+
+#endif /* LINUX */
+
+#include <security/pam_modules.h>
+
+#include "general.h"
+
+#include "support.h"
+
+#define AUTH_RETURN \
+do { \
+ if(ret_data) { \
+ *ret_data = retval; \
+ pam_set_data( pamh, "smb_setcred_return" \
+ , (void *) ret_data, NULL ); \
+ } \
+ return retval; \
+} while (0)
+
+static int _smb_add_user(pam_handle_t *pamh, unsigned int ctrl,
+ const char *name, struct smb_passwd *smb_pwent);
+
+/*
+ * pam_sm_authenticate() authenticates users against the samba password file.
+ *
+ * First, obtain the password from the user. Then use a
+ * routine in 'support.c' to authenticate the user.
+ */
+
+#define _SMB_AUTHTOK "-SMB-PASS"
+
+int pam_sm_authenticate(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ unsigned int ctrl;
+ int retval, *ret_data = NULL;
+
+ const char *name;
+
+ /* Points to memory managed by the PAM library. Do not free. */
+ const char *p = NULL;
+
+ struct smb_passwd *smb_pwent = NULL;
+
+ extern BOOL in_client;
+
+ /* Samba initialization. */
+ setup_logging("pam_smbpass",False);
+ in_client = True;
+
+ ctrl = set_ctrl(flags, argc, argv);
+
+ /* Get a few bytes so we can pass our return value to
+ pam_sm_setcred(). */
+ ret_data = malloc(sizeof(int));
+
+ /* get the username */
+ retval = pam_get_user( pamh, &name, "Username: " );
+ if ( retval != PAM_SUCCESS ) {
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err(LOG_DEBUG, "auth: could not identify user");
+ }
+ AUTH_RETURN;
+ }
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_DEBUG, "username [%s] obtained", name );
+ }
+
+ if (!initialize_password_db()) {
+ _log_err( LOG_ALERT, "Cannot access samba password database" );
+ retval = PAM_AUTHINFO_UNAVAIL;
+ AUTH_RETURN;
+ }
+
+ smb_pwent = getsmbpwnam( name );
+
+ if (on( SMB_MIGRATE, ctrl )) {
+ retval = _smb_add_user(pamh, ctrl, name, smb_pwent);
+ AUTH_RETURN;
+ }
+
+ if (smb_pwent == NULL) {
+ _log_err(LOG_ALERT, "Failed to find entry for user %s.", name);
+ retval = PAM_USER_UNKNOWN;
+ AUTH_RETURN;
+ }
+
+ /* if this user does not have a password... */
+
+ if (_smb_blankpasswd( ctrl, smb_pwent )) {
+ smb_pwent = NULL;
+ retval = PAM_SUCCESS;
+ AUTH_RETURN;
+ }
+
+ /* get this user's authentication token */
+
+ retval = _smb_read_password(pamh, ctrl, NULL, "Password: ", NULL
+ , _SMB_AUTHTOK, &p);
+ if (retval != PAM_SUCCESS ) {
+ _log_err(LOG_CRIT, "auth: no password provided for [%s]"
+ , name);
+ smb_pwent = NULL;
+ AUTH_RETURN;
+ }
+
+ /* verify the password of this user */
+
+ retval = _smb_verify_password( pamh, smb_pwent, p, ctrl );
+ smb_pwent = NULL;
+ p = NULL;
+ AUTH_RETURN;
+}
+
+/*
+ * This function is for setting samba credentials. If anyone comes up
+ * with any credentials they think should be set, let me know.
+ */
+
+int pam_sm_setcred(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ int retval, *pretval = NULL;
+
+ retval = PAM_SUCCESS;
+
+ pam_get_data(pamh, "smb_setcred_return", (const void **) &pretval);
+ if(pretval) {
+ retval = *pretval;
+ free(pretval);
+ }
+ pam_set_data(pamh, "smb_setcred_return", NULL, NULL);
+
+ return retval;
+}
+
+
+/* Helper function for adding a user to the db. */
+static int _smb_add_user(pam_handle_t *pamh, unsigned int ctrl,
+ const char *name, struct smb_passwd *smb_pwent)
+{
+ pstring err_str;
+ pstring msg_str;
+ const char *pass = NULL;
+ int retval;
+
+ err_str[0] = '\0';
+ msg_str[0] = '\0';
+
+ /* Get the authtok; if we don't have one, silently fail. */
+ retval = pam_get_item( pamh, PAM_AUTHTOK, (const void **) &pass );
+
+ if (retval != PAM_SUCCESS) {
+ _log_err( LOG_ALERT
+ , "pam_get_item returned error to pam_sm_authenticate" );
+ return PAM_AUTHTOK_RECOVER_ERR;
+ } else if (pass == NULL) {
+ return PAM_AUTHTOK_RECOVER_ERR;
+ }
+
+ /* Add the user to the db if they aren't already there. */
+ if (smb_pwent == NULL) {
+ retval = local_password_change( name, LOCAL_ADD_USER,
+ pass, err_str,
+ sizeof(err_str),
+ msg_str, sizeof(msg_str) );
+ if (!retval && *err_str)
+ {
+ err_str[PSTRING_LEN-1] = '\0';
+ make_remark( pamh, ctrl, PAM_ERROR_MSG, err_str );
+ }
+ else if (*msg_str)
+ {
+ msg_str[PSTRING_LEN-1] = '\0';
+ make_remark( pamh, ctrl, PAM_TEXT_INFO, msg_str );
+ }
+ pass = NULL;
+
+ return PAM_IGNORE;
+ }
+
+ /* Change the user's password IFF it's null. */
+ if (smb_pwent->smb_passwd == NULL && (smb_pwent->acct_ctrl & ACB_PWNOTREQ))
+ {
+ retval = local_password_change( name, 0,
+ pass, err_str,
+ sizeof(err_str),
+ msg_str, sizeof(msg_str) );
+ if (!retval && *err_str)
+ {
+ err_str[PSTRING_LEN-1] = '\0';
+ make_remark( pamh, ctrl, PAM_ERROR_MSG, err_str );
+ }
+ else if (*msg_str)
+ {
+ msg_str[PSTRING_LEN-1] = '\0';
+ make_remark( pamh, ctrl, PAM_TEXT_INFO, msg_str );
+ }
+ }
+ pass = NULL;
+
+ return PAM_IGNORE;
+}
+
+
+/* static module data */
+#ifdef PAM_STATIC
+struct pam_module _pam_smbpass_auth_modstruct = {
+ "pam_smbpass",
+ pam_sm_authenticate,
+ pam_sm_setcred,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+#endif
+
diff --git a/source/pam_smbpass/pam_smb_passwd.c b/source/pam_smbpass/pam_smb_passwd.c
new file mode 100644
index 00000000000..3a987684f16
--- /dev/null
+++ b/source/pam_smbpass/pam_smb_passwd.c
@@ -0,0 +1,313 @@
+/* Unix NT password database implementation, version 0.7.5.
+ *
+ * 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.
+*/
+
+/* indicate the following groups are defined */
+#define PAM_SM_PASSWORD
+
+#include "includes.h"
+
+#ifndef LINUX
+
+/* This is only used in the Sun implementation. */
+#include <security/pam_appl.h>
+
+#endif /* LINUX */
+
+#include <security/pam_modules.h>
+
+#include "general.h"
+
+#include "support.h"
+
+int smb_update_db( pam_handle_t *pamh, int ctrl, const char *user
+ , const char *pass_new )
+{
+ char c;
+ int retval, i;
+ pstring err_str;
+ pstring msg_str;
+
+ err_str[0] = '\0';
+ msg_str[0] = '\0';
+
+ retval = local_password_change( user, 0, pass_new, err_str, sizeof(err_str),
+ msg_str, sizeof(msg_str) );
+
+ if (!retval) {
+ if (*err_str) {
+ err_str[PSTRING_LEN-1] = '\0';
+ make_remark( pamh, ctrl, PAM_ERROR_MSG, err_str );
+ }
+
+ /* FIXME: what value is appropriate here? */
+ retval = PAM_AUTHTOK_ERR;
+ } else {
+ if (*msg_str) {
+ msg_str[PSTRING_LEN-1] = '\0';
+ make_remark( pamh, ctrl, PAM_TEXT_INFO, msg_str );
+ }
+ retval = PAM_SUCCESS;
+ }
+
+ return retval;
+
+}
+
+
+/* data tokens */
+
+#define _SMB_OLD_AUTHTOK "-SMB-OLD-PASS"
+#define _SMB_NEW_AUTHTOK "-SMB-NEW-PASS"
+
+/*
+ * FUNCTION: pam_sm_chauthtok()
+ *
+ * This function is called twice by the PAM library, once with
+ * PAM_PRELIM_CHECK set, and then again with PAM_UPDATE_AUTHTOK set. With
+ * Linux-PAM, these two passes generally involve first checking the old
+ * token and then changing the token. This is what we do here.
+ *
+ * Having obtained a new password. The function updates the
+ * SMB_PASSWD_FILE file (normally, $(LIBDIR)/smbpasswd).
+ */
+
+int pam_sm_chauthtok(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ unsigned int ctrl;
+ int retval;
+
+ extern BOOL in_client;
+
+ struct smb_passwd *smb_pwent=NULL;
+ const char *user;
+ const char *pass_old, *pass_new;
+
+ /* Samba initialization. */
+ setup_logging( "pam_smbpass", False );
+ in_client = True;
+
+ ctrl = set_ctrl(flags, argc, argv);
+
+ /*
+ * First get the name of a user. No need to do anything if we can't
+ * determine this.
+ */
+
+ retval = pam_get_user( pamh, &user, "Username: " );
+ if (retval != PAM_SUCCESS) {
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_DEBUG, "password: could not identify user" );
+ }
+ return retval;
+ }
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_DEBUG, "username [%s] obtained", user );
+ }
+
+ if (!initialize_password_db()) {
+ _log_err( LOG_ALERT, "Cannot access samba password database" );
+ return PAM_AUTHINFO_UNAVAIL;
+ }
+
+ /* obtain user record */
+ smb_pwent = getsmbpwnam(user);
+
+ if (smb_pwent == NULL) {
+ _log_err( LOG_ALERT, "Failed to find entry for user %s.", user );
+ return PAM_USER_UNKNOWN;
+ }
+
+ if (flags & PAM_PRELIM_CHECK) {
+ /*
+ * obtain and verify the current password (OLDAUTHTOK) for
+ * the user.
+ */
+
+ char *Announce;
+
+ if (_smb_blankpasswd( ctrl, smb_pwent )) {
+
+ return PAM_SUCCESS;
+
+ }
+
+ /* Password change by root, or for an expired token, doesn't
+ require authentication. Is this a good choice? */
+ if (getuid() != 0 && !(flags & PAM_CHANGE_EXPIRED_AUTHTOK)) {
+
+ /* tell user what is happening */
+#define greeting "Changing password for "
+ Announce = (char *) malloc(sizeof(greeting)+strlen(user));
+ if (Announce == NULL) {
+ _log_err(LOG_CRIT, "password: out of memory");
+ return PAM_BUF_ERR;
+ }
+ strncpy( Announce, greeting, sizeof(greeting) );
+ strncpy( Announce+sizeof(greeting)-1, user, strlen(user)+1 );
+#undef greeting
+
+ set( SMB__OLD_PASSWD, ctrl );
+ retval = _smb_read_password( pamh, ctrl
+ , Announce
+ , "Current SMB password: "
+ , NULL
+ , _SMB_OLD_AUTHTOK
+ , &pass_old );
+ free( Announce );
+
+ if (retval != PAM_SUCCESS) {
+ _log_err( LOG_NOTICE
+ , "password - (old) token not obtained" );
+ return retval;
+ }
+
+ /* verify that this is the password for this user */
+
+ retval = _smb_verify_password( pamh, smb_pwent, pass_old, ctrl );
+
+ } else {
+ pass_old = NULL;
+ retval = PAM_SUCCESS; /* root doesn't have to */
+ }
+
+ pass_old = NULL;
+ return retval;
+
+ } else if (flags & PAM_UPDATE_AUTHTOK) {
+
+ if (flags & PAM_CHANGE_EXPIRED_AUTHTOK) {
+ /* NOTE: there is currently no support for password expiring
+ under Samba. Support will be added here when it becomes
+ available. */
+ return PAM_SUCCESS;
+ }
+ /*
+ * obtain the proposed password
+ */
+
+ /*
+ * get the old token back. NULL was ok only if root [at this
+ * point we assume that this has already been enforced on a
+ * previous call to this function].
+ */
+
+ if (off( SMB_NOT_SET_PASS, ctrl )) {
+ retval = pam_get_item( pamh, PAM_OLDAUTHTOK,
+ (const void **)&pass_old );
+ } else {
+ retval = pam_get_data( pamh, _SMB_OLD_AUTHTOK,
+ (const void **)&pass_old );
+ if (retval == PAM_NO_MODULE_DATA) {
+ pass_old = NULL;
+ retval = PAM_SUCCESS;
+ }
+ }
+
+ if (retval != PAM_SUCCESS) {
+ _log_err( LOG_NOTICE, "password: user not authenticated" );
+ return retval;
+ }
+
+ /*
+ * use_authtok is to force the use of a previously entered
+ * password -- needed for pluggable password strength checking
+ * or other module stacking
+ */
+
+ if (on( SMB_USE_AUTHTOK, ctrl )) {
+ set( SMB_USE_FIRST_PASS, ctrl );
+ }
+
+ retval = _smb_read_password( pamh, ctrl
+ , NULL
+ , "Enter new SMB password: "
+ , "Retype new SMB password: "
+ , _SMB_NEW_AUTHTOK
+ , &pass_new );
+
+ if (retval != PAM_SUCCESS) {
+ if (on( SMB_DEBUG, ctrl )) {
+ _log_err( LOG_ALERT
+ , "password: new password not obtained" );
+ }
+ pass_old = NULL; /* tidy up */
+ return retval;
+ }
+
+ /*
+ * At this point we know who the user is and what they
+ * propose as their new password. Verify that the new
+ * password is acceptable.
+ */
+
+ if (pass_new[0] == '\0') { /* "\0" password = NULL */
+ pass_new = NULL;
+ }
+
+ retval = _pam_smb_approve_pass(pamh, ctrl, pass_old, pass_new);
+
+ if (retval != PAM_SUCCESS) {
+ _log_err(LOG_NOTICE, "new password not acceptable");
+ pass_new = pass_old = NULL; /* tidy up */
+ return retval;
+ }
+
+ /*
+ * By reaching here we have approved the passwords and must now
+ * rebuild the smb password file.
+ */
+
+ /* update the password database */
+
+ retval = smb_update_db(pamh, ctrl, user, pass_new);
+ if (retval == PAM_SUCCESS) {
+ /* password updated */
+ _log_err( LOG_NOTICE, "password for (%s/%d) changed by (%s/%d)"
+ , user, smb_pwent->smb_userid, uidtoname( getuid() )
+ , getuid() );
+ } else {
+ _log_err( LOG_ERR, "password change failed for user %s"
+ , user );
+ }
+
+ pass_old = pass_new = NULL;
+ smb_pwent = NULL;
+
+ } else { /* something has broken with the library */
+
+ _log_err( LOG_ALERT, "password received unknown request" );
+ retval = PAM_ABORT;
+
+ }
+
+ return retval;
+}
+
+/* static module data */
+#ifdef PAM_STATIC
+struct pam_module _pam_smbpass_passwd_modstruct = {
+ "pam_smbpass",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ pam_sm_chauthtok
+};
+#endif
+
diff --git a/source/rpcclient/cmd_netlogon.c b/source/rpcclient/cmd_netlogon.c
new file mode 100644
index 00000000000..93f6f1c3957
--- /dev/null
+++ b/source/rpcclient/cmd_netlogon.c
@@ -0,0 +1,108 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ RPC pipe client
+
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+static uint32 cmd_netlogon_logon_ctrl2(struct cli_state *cli, int argc,
+ char **argv)
+{
+ uint32 query_level = 1;
+ TALLOC_CTX *mem_ctx;
+ uint32 result = NT_STATUS_UNSUCCESSFUL;
+
+ if (argc > 1) {
+ printf("Usage: %s\n", argv[0]);
+ return 0;
+ }
+
+ if (!(mem_ctx = talloc_init())) {
+ DEBUG(0,("cmd_srvsvc_srv_query_info: talloc_init failed\n"));
+ goto done;
+ }
+
+ /* Initialise RPC connection */
+
+ if (!cli_nt_session_open (cli, PIPE_NETLOGON)) {
+ DEBUG(0, ("Could not initialize srvsvc pipe!\n"));
+ goto done;
+ }
+
+ if ((result = cli_netlogon_logon_ctrl2(cli, mem_ctx, query_level))
+ != NT_STATUS_NOPROBLEMO) {
+ goto done;
+ }
+
+ /* Display results */
+
+ done:
+ return result;
+}
+
+static uint32 cmd_netlogon_logon_ctrl(struct cli_state *cli, int argc,
+ char **argv)
+{
+#if 0
+ uint32 query_level = 1;
+#endif
+ TALLOC_CTX *mem_ctx;
+ uint32 result = NT_STATUS_UNSUCCESSFUL;
+
+ if (argc > 1) {
+ printf("Usage: %s\n", argv[0]);
+ return 0;
+ }
+
+ if (!(mem_ctx = talloc_init())) {
+ DEBUG(0,("cmd_srvsvc_srv_query_info: talloc_init failed\n"));
+ goto done;
+ }
+
+ /* Initialise RPC connection */
+
+ if (!cli_nt_session_open (cli, PIPE_NETLOGON)) {
+ DEBUG(0, ("Could not initialize srvsvc pipe!\n"));
+ goto done;
+ }
+
+#if 0
+ if ((result = cli_netlogon_logon_ctrl(cli, mem_ctx, query_level))
+ != NT_STATUS_NOPROBLEMO) {
+ goto done;
+ }
+#endif
+
+ /* Display results */
+
+ done:
+ return result;
+}
+
+/* List of commands exported by this module */
+
+struct cmd_set netlogon_commands[] = {
+ { "NETLOGON", NULL, "" },
+ { "logonctrl2", cmd_netlogon_logon_ctrl2, "Logon Control 2" },
+ { "logonctrl", cmd_netlogon_logon_ctrl, "Logon Control" },
+ { NULL, NULL, NULL }
+};
diff --git a/source/rpcclient/cmd_srvsvc.c b/source/rpcclient/cmd_srvsvc.c
new file mode 100644
index 00000000000..b804cc383db
--- /dev/null
+++ b/source/rpcclient/cmd_srvsvc.c
@@ -0,0 +1,243 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.2
+ RPC pipe client
+
+ Copyright (C) Andrew Tridgell 1992-1999
+ Copyright (C) Luke Kenneth Casson Leighton 1996 - 1999
+ Copyright (C) Tim Potter 2000
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+/* Display server query info */
+
+static char *get_server_type_str(uint32 type)
+{
+ static fstring typestr;
+ int i;
+
+ if (type == SV_TYPE_ALL) {
+ fstrcpy(typestr, "All");
+ return typestr;
+ }
+
+ typestr[0] = 0;
+
+ for (i = 0; i < 32; i++) {
+ if (type & (1 << i)) {
+ switch (1 << i) {
+ case SV_TYPE_WORKSTATION:
+ fstrcat(typestr, "Wk ");
+ break;
+ case SV_TYPE_SERVER:
+ fstrcat(typestr, "Sv ");
+ break;
+ case SV_TYPE_SQLSERVER:
+ fstrcat(typestr, "Sql ");
+ break;
+ case SV_TYPE_DOMAIN_CTRL:
+ fstrcat(typestr, "PDC ");
+ break;
+ case SV_TYPE_DOMAIN_BAKCTRL:
+ fstrcat(typestr, "BDC ");
+ break;
+ case SV_TYPE_TIME_SOURCE:
+ fstrcat(typestr, "Tim ");
+ break;
+ case SV_TYPE_AFP:
+ fstrcat(typestr, "AFP ");
+ break;
+ case SV_TYPE_NOVELL:
+ fstrcat(typestr, "Nov ");
+ break;
+ case SV_TYPE_DOMAIN_MEMBER:
+ fstrcat(typestr, "Dom ");
+ break;
+ case SV_TYPE_PRINTQ_SERVER:
+ fstrcat(typestr, "PrQ ");
+ break;
+ case SV_TYPE_DIALIN_SERVER:
+ fstrcat(typestr, "Din ");
+ break;
+ case SV_TYPE_SERVER_UNIX:
+ fstrcat(typestr, "Unx ");
+ break;
+ case SV_TYPE_NT:
+ fstrcat(typestr, "NT ");
+ break;
+ case SV_TYPE_WFW:
+ fstrcat(typestr, "Wfw ");
+ break;
+ case SV_TYPE_SERVER_MFPN:
+ fstrcat(typestr, "Mfp ");
+ break;
+ case SV_TYPE_SERVER_NT:
+ fstrcat(typestr, "SNT ");
+ break;
+ case SV_TYPE_POTENTIAL_BROWSER:
+ fstrcat(typestr, "PtB ");
+ break;
+ case SV_TYPE_BACKUP_BROWSER:
+ fstrcat(typestr, "BMB ");
+ break;
+ case SV_TYPE_MASTER_BROWSER:
+ fstrcat(typestr, "LMB ");
+ break;
+ case SV_TYPE_DOMAIN_MASTER:
+ fstrcat(typestr, "DMB ");
+ break;
+ case SV_TYPE_SERVER_OSF:
+ fstrcat(typestr, "OSF ");
+ break;
+ case SV_TYPE_SERVER_VMS:
+ fstrcat(typestr, "VMS ");
+ break;
+ case SV_TYPE_WIN95_PLUS:
+ fstrcat(typestr, "W95 ");
+ break;
+ case SV_TYPE_ALTERNATE_XPORT:
+ fstrcat(typestr, "Xpt ");
+ break;
+ case SV_TYPE_LOCAL_LIST_ONLY:
+ fstrcat(typestr, "Dom ");
+ break;
+ case SV_TYPE_DOMAIN_ENUM:
+ fstrcat(typestr, "Loc ");
+ break;
+ }
+ }
+ }
+
+ i = strlen(typestr) - 1;
+
+ if (typestr[i] == ' ')
+ typestr[i] = 0;
+
+ return typestr;
+}
+
+static void display_server(char *sname, uint32 type, const char *comment)
+{
+ printf("\t%-15.15s%-20s %s\n", sname, get_server_type_str(type),
+ comment);
+}
+
+static void display_srv_info_101(SRV_INFO_101 *sv101)
+{
+ fstring name;
+ fstring comment;
+
+ unistr2_to_ascii(name, &sv101->uni_name, sizeof(name) - 1);
+ unistr2_to_ascii(comment, &sv101->uni_comment, sizeof(comment) - 1);
+
+ display_server(name, sv101->srv_type, comment);
+
+ printf("\tplatform_id :\t%d\n", sv101->platform_id);
+ printf("\tos version :\t%d.%d\n", sv101->ver_major,
+ sv101->ver_minor);
+
+ printf("\tserver type :\t0x%x\n", sv101->srv_type);
+}
+
+static void display_srv_info_102(SRV_INFO_102 *sv102)
+{
+ fstring name;
+ fstring comment;
+ fstring usr_path;
+
+ unistr2_to_ascii(name, &sv102->uni_name, sizeof(name) - 1);
+ unistr2_to_ascii(comment, &sv102->uni_comment, sizeof(comment) - 1);
+ unistr2_to_ascii(usr_path, &sv102->uni_usr_path, sizeof(usr_path) - 1);
+
+ display_server(name, sv102->srv_type, comment);
+
+ printf("\tplatform_id :\t%d\n", sv102->platform_id);
+ printf("\tos version :\t%d.%d\n", sv102->ver_major,
+ sv102->ver_minor);
+
+ printf("\tusers :\t%x\n", sv102->users);
+ printf("\tdisc, hidden :\t%x, %x\n", sv102->disc, sv102->hidden);
+ printf("\tannounce, delta :\t%d, %d\n", sv102->announce,
+ sv102->ann_delta);
+ printf("\tlicenses :\t%d\n", sv102->licenses);
+ printf("\tuser path :\t%s\n", usr_path);
+}
+
+/* Server query info */
+
+static uint32 cmd_srvsvc_srv_query_info(struct cli_state *cli, int argc,
+ char **argv)
+{
+ uint32 info_level = 101;
+ SRV_INFO_CTR ctr;
+ TALLOC_CTX *mem_ctx;
+ uint32 result = NT_STATUS_UNSUCCESSFUL;
+
+ if (argc > 2) {
+ printf("Usage: %s [infolevel]\n", argv[0]);
+ return 0;
+ }
+
+ if (argc == 2)
+ info_level = atoi(argv[1]);
+
+ if (!(mem_ctx = talloc_init())) {
+ DEBUG(0,("cmd_srvsvc_srv_query_info: talloc_init failed\n"));
+ goto done;
+ }
+
+ /* Initialise RPC connection */
+
+ if (!cli_nt_session_open (cli, PIPE_SRVSVC)) {
+ DEBUG(0, ("Could not initialize srvsvc pipe!\n"));
+ goto done;
+ }
+
+ if ((result = cli_srvsvc_net_srv_get_info(cli, mem_ctx, info_level,
+ &ctr)
+ != NT_STATUS_NOPROBLEMO)) {
+ goto done;
+ }
+
+ /* Display results */
+
+ switch (info_level) {
+ case 101:
+ display_srv_info_101(&ctr.srv.sv101);
+ break;
+ case 102:
+ display_srv_info_102(&ctr.srv.sv102);
+ break;
+ default:
+ printf("unsupported info level %d\n", info_level);
+ break;
+ }
+
+ done:
+ return result;
+}
+
+/* List of commands exported by this module */
+
+struct cmd_set srvsvc_commands[] = {
+ { "SRVSVC", NULL, "" },
+ { "srvinfo", cmd_srvsvc_srv_query_info, "Server query info" },
+ { NULL, NULL, NULL }
+};
diff --git a/source/smbd/session.c b/source/smbd/session.c
new file mode 100644
index 00000000000..8f6907c5378
--- /dev/null
+++ b/source/smbd/session.c
@@ -0,0 +1,179 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ session handling for utmp and PAM
+ Copyright (C) tridge@samba.org 2001
+ Copyright (C) abartlet@pcug.org.au 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.
+*/
+
+/* a "session" is claimed when we do a SessionSetupX operation
+ and is yielded when the corresponding vuid is destroyed.
+
+ sessions are used to populate utmp and PAM session structures
+*/
+
+#include "includes.h"
+
+#if defined(WITH_PAM) || defined(WITH_UTMP)
+
+static TDB_CONTEXT *tdb;
+struct sessionid {
+ fstring username;
+ fstring hostname;
+ fstring id_str;
+ uint32 id_num;
+ uint32 pid;
+};
+
+/* called when a session is created */
+BOOL session_claim(uint16 vuid)
+{
+ user_struct *vuser = get_valid_user_struct(vuid);
+ int i;
+ TDB_DATA data;
+ struct sessionid sessionid;
+ pstring dbuf;
+ int dlen;
+ uint32 pid = (uint32)sys_getpid();
+ TDB_DATA key;
+ fstring keystr;
+ char * hostname;
+
+ vuser->session_id = 0;
+
+ /* don't register sessions for the guest user - its just too
+ expensive to go through pam session code for browsing etc */
+ if (strequal(vuser->user.unix_name,lp_guestaccount(-1))) {
+ return True;
+ }
+
+ if (!tdb) {
+ tdb = tdb_open_log(lock_path("sessionid.tdb"), 0, TDB_CLEAR_IF_FIRST,
+ O_RDWR | O_CREAT, 0644);
+ if (!tdb) {
+ DEBUG(1,("session_claim: failed to open sessionid tdb\n"));
+ return False;
+ }
+ }
+
+ ZERO_STRUCT(sessionid);
+
+ data.dptr = NULL;
+ data.dsize = 0;
+
+ for (i=1;i<MAX_SESSION_ID;i++) {
+ slprintf(keystr, sizeof(keystr)-1, "ID/%d", i);
+ key.dptr = keystr;
+ key.dsize = strlen(keystr)+1;
+
+ if (tdb_store(tdb, key, data, TDB_INSERT) == 0) break;
+ }
+
+ if (i == MAX_SESSION_ID) {
+ DEBUG(1,("session_claim: out of session IDs (max is %d)\n",
+ MAX_SESSION_ID));
+ return False;
+ }
+
+ hostname = client_name();
+ if (strequal(hostname,"UNKNOWN"))
+ hostname = client_addr();
+
+ fstrcpy(sessionid.username, vuser->user.unix_name);
+ fstrcpy(sessionid.hostname, hostname);
+ slprintf(sessionid.id_str, sizeof(sessionid.id_str)-1, SESSION_TEMPLATE, i);
+ sessionid.id_num = i;
+ sessionid.pid = pid;
+
+ if (!smb_pam_claim_session(sessionid.username, sessionid.id_str, sessionid.hostname)) {
+ DEBUG(1,("pam_session rejected the session for %s [%s]\n",
+ sessionid.username, sessionid.id_str));
+ tdb_delete(tdb, key);
+ return False;
+ }
+
+ dlen = tdb_pack(dbuf, sizeof(dbuf), "fffdd",
+ sessionid.username, sessionid.hostname, sessionid.id_str,
+ sessionid.id_num, sessionid.pid);
+
+ data.dptr = dbuf;
+ data.dsize = dlen;
+ if (tdb_store(tdb, key, data, TDB_MODIFY) != 0) {
+ DEBUG(1,("session_claim: unable to create session id record\n"));
+ return False;
+ }
+
+#if WITH_UTMP
+ if (lp_utmp()) {
+ sys_utmp_claim(sessionid.username, sessionid.hostname,
+ sessionid.id_str, sessionid.id_num);
+ }
+#endif
+
+ vuser->session_id = i;
+ return True;
+}
+
+/* called when a session is destroyed */
+void session_yield(uint16 vuid)
+{
+ user_struct *vuser = get_valid_user_struct(vuid);
+ TDB_DATA data;
+ struct sessionid sessionid;
+ TDB_DATA key;
+ fstring keystr;
+
+ if (!tdb) return;
+
+ if (vuser->session_id == 0) {
+ return;
+ }
+
+ slprintf(keystr, sizeof(keystr)-1, "ID/%d", vuser->session_id);
+
+ key.dptr = keystr;
+ key.dsize = strlen(keystr)+1;
+
+ data = tdb_fetch(tdb, key);
+ if (data.dptr == NULL) {
+ return;
+ }
+
+ tdb_unpack(data.dptr, data.dsize, "fffdd",
+ &sessionid.username, &sessionid.hostname, &sessionid.id_str,
+ &sessionid.id_num, &sessionid.pid);
+
+ safe_free(data.dptr);
+ data.dptr = NULL;
+
+#if WITH_UTMP
+ if (lp_utmp()) {
+ sys_utmp_yield(sessionid.username, sessionid.hostname,
+ sessionid.id_str, sessionid.id_num);
+ }
+#endif
+
+ smb_pam_close_session(sessionid.username, sessionid.id_str, sessionid.hostname);
+
+ tdb_delete(tdb, key);
+}
+
+#else
+ /* null functions - no session support needed */
+ BOOL session_claim(uint16 vuid) { return True; }
+ void session_yield(uint16 vuid) {}
+#endif
diff --git a/source/smbd/utmp.c b/source/smbd/utmp.c
new file mode 100644
index 00000000000..f79cd43c5b1
--- /dev/null
+++ b/source/smbd/utmp.c
@@ -0,0 +1,576 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 2.0
+ utmp routines
+ Copyright (C) T.D.Lee@durham.ac.uk 1999
+ Heavily modified by Andrew Bartlett and Tridge, April 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"
+
+#ifdef WITH_UTMP
+
+/****************************************************************************
+Reflect connection status in utmp/wtmp files.
+ T.D.Lee@durham.ac.uk September 1999
+
+ With grateful thanks since then to many who have helped port it to
+ different operating systems. The variety of OS quirks thereby
+ uncovered is amazing...
+
+Hints for porting:
+ o Always attempt to use programmatic interface (pututline() etc.)
+ Indeed, at present only programmatic use is supported.
+ o The only currently supported programmatic interface to "wtmp{,x}"
+ is through "updwtmp*()" routines.
+ o The "x" (utmpx/wtmpx; HAVE_UTMPX_H) seems preferable.
+ o The HAVE_* items should identify supported features.
+ o If at all possible, avoid "if defined(MY-OS)" constructions.
+
+OS observations and status:
+ Almost every OS seems to have its own quirks.
+
+ Solaris 2.x:
+ Tested on 2.6 and 2.7; should be OK on other flavours.
+ AIX:
+ Apparently has utmpx.h but doesn't implement.
+ OSF:
+ Has utmpx.h, but (e.g.) no "getutmpx()". (Is this like AIX ?)
+ Redhat 6:
+ utmpx.h seems not to set default filenames. non-x better.
+ IRIX 6.5:
+ Not tested. Appears to have "x".
+ HP-UX 9.x:
+ Not tested. Appears to lack "x".
+ HP-UX 10.x:
+ Not tested.
+ "updwtmp*()" routines seem absent, so no current wtmp* support.
+ Has "ut_addr": probably trivial to implement (although remember
+ that IPv6 is coming...).
+
+ FreeBSD:
+ No "putut*()" type of interface.
+ No "ut_type" and associated defines.
+ Write files directly. Alternatively use its login(3)/logout(3).
+ SunOS 4:
+ Not tested. Resembles FreeBSD, but no login()/logout().
+
+lastlog:
+ Should "lastlog" files, if any, be updated?
+ BSD systems (SunOS 4, FreeBSD):
+ o Prominent mention on man pages.
+ System-V (e.g. Solaris 2):
+ o No mention on man pages, even under "man -k".
+ o Has a "/var/adm/lastlog" file, but pututxline() etc. seem
+ not to touch it.
+ o Despite downplaying (above), nevertheless has <lastlog.h>.
+ So perhaps UN*X "lastlog" facility is intended for tty/terminal only?
+
+Notes:
+ Each connection requires a small number (starting at 0, working up)
+ to represent the line (unum). This must be unique within and across
+ all smbd processes.
+
+ The 4 byte 'ut_id' component is vital to distinguish connections,
+ of which there could be several hundered or even thousand.
+ Entries seem to be printable characters, with optional NULL pads.
+
+ We need to be distinct from other entries in utmp/wtmp.
+
+ Observed things: therefore avoid them. Add to this list please.
+ From Solaris 2.x (because that's what I have):
+ 'sN' : run-levels; N: [0-9]
+ 'co' : console
+ 'CC' : arbitrary things; C: [a-z]
+ 'rXNN' : rlogin; N: [0-9]; X: [0-9a-z]
+ 'tXNN' : rlogin; N: [0-9]; X: [0-9a-z]
+ '/NNN' : Solaris CDE
+ 'ftpZ' : ftp (Z is the number 255, aka 0377, aka 0xff)
+ Mostly a record uses the same 'ut_id' in both "utmp" and "wtmp",
+ but differences have been seen.
+
+ Arbitrarily I have chosen to use a distinctive 'SM' for the
+ first two bytes.
+
+ The remaining two encode the "unum" (see above).
+
+ For "utmp consolidate" the suggestion was made to encode the pid into
+ those remaining two bytes (16 bits). But recent UNIX (e.g Solaris 8)
+ is migrating to pids > 16 bits, so we ought not to do this.
+
+****************************************************************************/
+
+#include <utmp.h>
+
+#ifdef HAVE_UTMPX_H
+#include <utmpx.h>
+#endif
+
+/* BSD systems: some may need lastlog.h (SunOS 4), some may not (FreeBSD) */
+/* Some System-V systems (e.g. Solaris 2) declare this too. */
+#ifdef HAVE_LASTLOG_H
+#include <lastlog.h>
+#endif
+
+/****************************************************************************
+obtain/release a small number (0 upwards) unique within and across smbds
+****************************************************************************/
+/*
+ * Need a "small" number to represent this connection, unique within this
+ * smbd and across all smbds.
+ *
+ * claim:
+ * Start at 0, hunt up for free, unique number "unum" by attempting to
+ * store it as a key in a tdb database:
+ * key: unum data: pid+conn
+ * Also store its inverse, ready for yield function:
+ * key: pid+conn data: unum
+ *
+ * yield:
+ * Find key: pid+conn; data is unum; delete record
+ * Find key: unum ; delete record.
+ *
+ * Comment:
+ * The claim algorithm (a "for" loop attempting to store numbers in a tdb
+ * database) will be increasingly inefficient with larger numbers of
+ * connections. Is it possible to write a suitable primitive within tdb?
+ *
+ * However, by also storing the inverse key/data pair, we at least make
+ * the yield algorithm efficient.
+ */
+
+/****************************************************************************
+Default paths to various {u,w}tmp{,x} files
+****************************************************************************/
+#ifdef HAVE_UTMPX_H
+
+static const char *ux_pathname =
+# if defined (UTMPX_FILE)
+ UTMPX_FILE ;
+# elif defined (_UTMPX_FILE)
+ _UTMPX_FILE ;
+# elif defined (_PATH_UTMPX)
+ _PATH_UTMPX ;
+# else
+ "" ;
+# endif
+
+static const char *wx_pathname =
+# if defined (WTMPX_FILE)
+ WTMPX_FILE ;
+# elif defined (_WTMPX_FILE)
+ _WTMPX_FILE ;
+# elif defined (_PATH_WTMPX)
+ _PATH_WTMPX ;
+# else
+ "" ;
+# endif
+
+#endif /* HAVE_UTMPX_H */
+
+static const char *ut_pathname =
+# if defined (UTMP_FILE)
+ UTMP_FILE ;
+# elif defined (_UTMP_FILE)
+ _UTMP_FILE ;
+# elif defined (_PATH_UTMP)
+ _PATH_UTMP ;
+# else
+ "" ;
+# endif
+
+static const char *wt_pathname =
+# if defined (WTMP_FILE)
+ WTMP_FILE ;
+# elif defined (_WTMP_FILE)
+ _WTMP_FILE ;
+# elif defined (_PATH_WTMP)
+ _PATH_WTMP ;
+# else
+ "" ;
+# endif
+
+/* BSD-like systems might want "lastlog" support. */
+/* *** Not yet implemented */
+#ifndef HAVE_PUTUTLINE /* see "pututline_my()" */
+static const char *ll_pathname =
+# if defined (_PATH_LASTLOG) /* what other names (if any?) */
+ _PATH_LASTLOG ;
+# else
+ "" ;
+# endif /* _PATH_LASTLOG */
+#endif /* HAVE_PUTUTLINE */
+
+/*
+ * Get name of {u,w}tmp{,x} file.
+ * return: fname contains filename
+ * Possibly empty if this code not yet ported to this system.
+ *
+ * utmp{,x}: try "utmp dir", then default (a define)
+ * wtmp{,x}: try "wtmp dir", then "utmp dir", then default (a define)
+ */
+static void uw_pathname(pstring fname, const char *uw_name, const char *uw_default)
+{
+ pstring dirname;
+
+ pstrcpy(dirname, "");
+
+ /* For w-files, first look for explicit "wtmp dir" */
+ if (uw_name[0] == 'w') {
+ pstrcpy(dirname,lp_wtmpdir());
+ trim_string(dirname,"","/");
+ }
+
+ /* For u-files and non-explicit w-dir, look for "utmp dir" */
+ if (dirname == 0 || strlen(dirname) == 0) {
+ pstrcpy(dirname,lp_utmpdir());
+ trim_string(dirname,"","/");
+ }
+
+ /* If explicit directory above, use it */
+ if (dirname != 0 && strlen(dirname) != 0) {
+ pstrcpy(fname, dirname);
+ pstrcat(fname, "/");
+ pstrcat(fname, uw_name);
+ return;
+ }
+
+ /* No explicit directory: attempt to use default paths */
+ if (strlen(uw_default) == 0) {
+ /* No explicit setting, no known default.
+ * Has it yet been ported to this OS?
+ */
+ DEBUG(2,("uw_pathname: unable to determine pathname\n"));
+ }
+ pstrcpy(fname, uw_default);
+}
+
+#ifndef HAVE_PUTUTLINE
+/****************************************************************************
+Update utmp file directly. No subroutine interface: probably a BSD system.
+****************************************************************************/
+static void pututline_my(pstring uname, struct utmp *u, BOOL claim)
+{
+ DEBUG(1,("pututline_my: not yet implemented\n"));
+ /* BSD implementor: may want to consider (or not) adjusting "lastlog" */
+}
+#endif /* HAVE_PUTUTLINE */
+
+#ifndef HAVE_UPDWTMP
+/****************************************************************************
+Update wtmp file directly. No subroutine interface: probably a BSD system.
+Credit: Michail Vidiassov <master@iaas.msu.ru>
+****************************************************************************/
+static void updwtmp_my(pstring wname, struct utmp *u, BOOL claim)
+{
+ int fd;
+ struct stat buf;
+
+ if (! claim) {
+ /*
+ * BSD-like systems:
+ * may use empty ut_name to distinguish a logout record.
+ *
+ * May need "if defined(SUNOS4)" etc. around some of these,
+ * but try to avoid if possible.
+ *
+ * SunOS 4:
+ * man page indicates ut_name and ut_host both NULL
+ * FreeBSD 4.0:
+ * man page appears not to specify (hints non-NULL)
+ * A correspondent suggest at least ut_name should be NULL
+ */
+ memset((char *)&(u->ut_name), '\0', sizeof(u->ut_name));
+ memset((char *)&(u->ut_host), '\0', sizeof(u->ut_host));
+ }
+ /* Stolen from logwtmp function in libutil.
+ * May be more locking/blocking is needed?
+ */
+ if ((fd = open(wname, O_WRONLY|O_APPEND, 0)) < 0)
+ return;
+ if (fstat(fd, &buf) == 0) {
+ if (write(fd, (char *)u, sizeof(struct utmp)) != sizeof(struct utmp))
+ (void) ftruncate(fd, buf.st_size);
+ }
+ (void) close(fd);
+}
+#endif /* HAVE_UPDWTMP */
+
+/****************************************************************************
+Update via utmp/wtmp (not utmpx/wtmpx)
+****************************************************************************/
+static void utmp_nox_update(struct utmp *u, const char *host, BOOL claim)
+{
+ pstring uname, wname;
+#if defined(PUTUTLINE_RETURNS_UTMP)
+ struct utmp *urc;
+#endif /* PUTUTLINE_RETURNS_UTMP */
+
+ uw_pathname(uname, "utmp", ut_pathname);
+ DEBUG(2,("utmp_nox_update: uname:%s\n", uname));
+
+#ifdef HAVE_PUTUTLINE
+ if (strlen(uname) != 0) {
+ utmpname(uname);
+ }
+
+# if defined(PUTUTLINE_RETURNS_UTMP)
+ setutent();
+ urc = pututline(u);
+ endutent();
+ if (urc == NULL) {
+ DEBUG(2,("utmp_nox_update: pututline() failed\n"));
+ return;
+ }
+# else /* PUTUTLINE_RETURNS_UTMP */
+ setutent();
+ pututline(u);
+ endutent();
+# endif /* PUTUTLINE_RETURNS_UTMP */
+
+#else /* HAVE_PUTUTLINE */
+ if (strlen(uname) != 0) {
+ pututline_my(uname, u, claim);
+ }
+#endif /* HAVE_PUTUTLINE */
+
+ uw_pathname(wname, "wtmp", wt_pathname);
+ DEBUG(2,("utmp_nox_update: wname:%s\n", wname));
+ if (strlen(wname) != 0) {
+#ifdef HAVE_UPDWTMP
+ updwtmp(wname, u);
+ /*
+ * updwtmp() and the newer updwtmpx() may be unsymmetrical.
+ * At least one OS, Solaris 2.x declares the former in the
+ * "utmpx" (latter) file and context.
+ * In the Solaris case this is irrelevant: it has both and
+ * we always prefer the "x" case, so doesn't come here.
+ * But are there other systems, with no "x", which lack
+ * updwtmp() perhaps?
+ */
+#else
+ updwtmp_my(wname, u, claim);
+#endif /* HAVE_UPDWTMP */
+ }
+}
+
+/****************************************************************************
+Update via utmpx/wtmpx (preferred) or via utmp/wtmp
+****************************************************************************/
+static void sys_utmp_update(struct utmp *u, const char *hostname, BOOL claim)
+{
+#if !defined(HAVE_UTMPX_H)
+ /* No utmpx stuff. Drop to non-x stuff */
+ utmp_nox_update(u, hostname, claim);
+#elif !defined(HAVE_PUTUTXLINE)
+ /* Odd. Have utmpx.h but no "pututxline()". Drop to non-x stuff */
+ DEBUG(1,("utmp_update: have utmpx.h but no pututxline() function\n"));
+ utmp_nox_update(u, hostname, claim);
+#elif !defined(HAVE_GETUTMPX)
+ /* Odd. Have utmpx.h but no "getutmpx()". Drop to non-x stuff */
+ DEBUG(1,("utmp_update: have utmpx.h but no getutmpx() function\n"));
+ utmp_nox_update(u, hostname, claim);
+#else
+ pstring uname, wname;
+ struct utmpx ux, *uxrc;
+
+ getutmpx(u, &ux);
+
+#if defined(HAVE_UX_UT_SYSLEN)
+ if (hostname) ux.ut_syslen = strlen(hostname) + 1; /* include end NULL */
+ else ux.ut_syslen = 0;
+#endif
+ safe_strcpy(ux.ut_host, hostname, sizeof(ux.ut_host)-1);
+
+ uw_pathname(uname, "utmpx", ux_pathname);
+ uw_pathname(wname, "wtmpx", wx_pathname);
+ DEBUG(2,("utmp_update: uname:%s wname:%s\n", uname, wname));
+ /*
+ * Check for either uname or wname being empty.
+ * Some systems, such as Redhat 6, have a "utmpx.h" which doesn't
+ * define default filenames.
+ * Also, our local installation has not provided an override.
+ * Drop to non-x method. (E.g. RH6 has good defaults in "utmp.h".)
+ */
+ if ((strlen(uname) == 0) || (strlen(wname) == 0)) {
+ utmp_nox_update(u, hostname, claim);
+ } else {
+ utmpxname(uname);
+ setutxent();
+ uxrc = pututxline(&ux);
+ endutxent();
+ if (uxrc == NULL) {
+ DEBUG(2,("utmp_update: pututxline() failed\n"));
+ return;
+ }
+ updwtmpx(wname, &ux);
+ }
+#endif /* HAVE_UTMPX_H */
+}
+
+#if defined(HAVE_UT_UT_ID)
+/****************************************************************************
+encode the unique connection number into "ut_id"
+****************************************************************************/
+static int ut_id_encode(int i, char *fourbyte)
+{
+ int nbase;
+ char *ut_id_encstr = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ fourbyte[0] = 'S';
+ fourbyte[1] = 'M';
+
+/*
+ * Encode remaining 2 bytes from 'i'.
+ * 'ut_id_encstr' is the character set on which modulo arithmetic is done.
+ * Example: digits would produce the base-10 numbers from '001'.
+ */
+ nbase = strlen(ut_id_encstr);
+
+ fourbyte[3] = ut_id_encstr[i % nbase];
+ i /= nbase;
+ fourbyte[2] = ut_id_encstr[i % nbase];
+ i /= nbase;
+
+ return(i); /* 0: good; else overflow */
+}
+#endif /* defined(HAVE_UT_UT_ID) */
+
+
+/*
+ fill a system utmp structure given all the info we can gather
+*/
+static BOOL sys_utmp_fill(struct utmp *u,
+ const char *username, const char *hostname,
+ const char *id_str, int id_num)
+{
+ struct timeval timeval;
+
+ /*
+ * ut_name, ut_user:
+ * Several (all?) systems seems to define one as the other.
+ * It is easier and clearer simply to let the following take its course,
+ * rather than to try to detect and optimise.
+ */
+#if defined(HAVE_UT_UT_USER)
+ safe_strcpy(u->ut_user, username, sizeof(u->ut_user)-1);
+#elif defined(HAVE_UT_UT_NAME)
+ safe_strcpy(u->ut_name, username, sizeof(u->ut_name)-1);
+#endif
+
+ /*
+ * ut_line:
+ * If size limit proves troublesome, then perhaps use "ut_id_encode()".
+ *
+ * Temporary variable "line_tmp" avoids trouble:
+ * o with unwanted trailing NULL if ut_line full;
+ * o with overflow if ut_line would be more than full.
+ */
+ if (strlen(id_str) > sizeof(u->ut_line)) {
+ DEBUG(1,("id_str [%s] is too long for %d char utmp field\n",
+ id_str, sizeof(u->ut_line)));
+ return False;
+ }
+ memcpy(u->ut_line, id_str, sizeof(u->ut_line));
+
+#if defined(HAVE_UT_UT_PID)
+ u->ut_pid = sys_getpid();
+#endif
+
+/*
+ * ut_time, ut_tv:
+ * Some have one, some the other. Many have both, but defined (aliased).
+ * It is easier and clearer simply to let the following take its course.
+ * But note that we do the more precise ut_tv as the final assignment.
+ */
+#if defined(HAVE_UT_UT_TIME)
+ gettimeofday(&timeval, NULL);
+ u->ut_time = timeval.tv_sec;
+#elif defined(HAVE_UT_UT_TV)
+ gettimeofday(&timeval, NULL);
+ u->ut_tv = timeval;
+#else
+#error "with-utmp must have UT_TIME or UT_TV"
+#endif
+
+#if defined(HAVE_UT_UT_HOST)
+ safe_strcpy(u->ut_host, hostname, sizeof(u->ut_host)-1);
+#endif
+
+#if defined(HAVE_UT_UT_ADDR)
+ /*
+ * "(unsigned long) ut_addr" apparently exists on at least HP-UX 10.20.
+ * Volunteer to implement, please ...
+ */
+#endif
+
+#if defined(HAVE_UT_UT_ID)
+ if (ut_id_encode(id_num, u->ut_id) != 0) {
+ DEBUG(1,("utmp_fill: cannot encode id %d\n", id_num));
+ return False;
+ }
+#endif
+
+ return True;
+}
+
+/****************************************************************************
+close a connection
+****************************************************************************/
+void sys_utmp_yield(const char *username, const char *hostname,
+ const char *id_str, int id_num)
+{
+ struct utmp u;
+
+ ZERO_STRUCT(u);
+
+#if defined(HAVE_UT_UT_EXIT)
+ u.ut_exit.e_termination = 0;
+ u.ut_exit.e_exit = 0;
+#endif
+
+#if defined(HAVE_UT_UT_TYPE)
+ u.ut_type = DEAD_PROCESS;
+#endif
+
+ if (!sys_utmp_fill(&u, username, hostname, id_str, id_num)) return;
+
+ sys_utmp_update(&u, NULL, False);
+}
+
+/****************************************************************************
+claim a entry in whatever utmp system the OS uses
+****************************************************************************/
+void sys_utmp_claim(const char *username, const char *hostname,
+ const char *id_str, int id_num)
+{
+ struct utmp u;
+
+ ZERO_STRUCT(u);
+
+#if defined(HAVE_UT_UT_TYPE)
+ u.ut_type = USER_PROCESS;
+#endif
+
+ if (!sys_utmp_fill(&u, username, hostname, id_str, id_num)) return;
+
+ sys_utmp_update(&u, hostname, True);
+}
+
+#else /* WITH_UTMP */
+ void dummy_utmp(void) {}
+#endif
diff --git a/testsuite/build_farm/basicsmb.fns b/testsuite/build_farm/basicsmb.fns
new file mode 100644
index 00000000000..592cb62de48
--- /dev/null
+++ b/testsuite/build_farm/basicsmb.fns
@@ -0,0 +1,64 @@
+test_smb_conf_setup() {
+ cat basicsmb.smb.conf.template | \
+ sed "s|PREFIX|$prefix|g" | \
+ sed "s|BUILD_FARM|$pwd|g" | \
+ sed "s|WHOAMI|$whoami|g" | \
+ sed "s|LOGLEVEL|$loglevel|g" \
+ > $prefix/lib/smb.conf
+
+ echo "127.0.0.1 localhost">$prefix/lib/lmhosts
+ echo "127.0.0.1 SHARE">>$prefix/lib/lmhosts
+ echo "127.0.0.1 USER">>$prefix/lib/lmhosts
+ echo "127.0.0.1 SERVER">>$prefix/lib/lmhosts
+ echo "127.0.0.1 DOMAIN">>$prefix/lib/lmhosts
+ cp basicsmb.smb.conf.share $prefix/lib/smb.conf.share
+ cp basicsmb.smb.conf.user $prefix/lib/smb.conf.user
+ cp basicsmb.smb.conf.server $prefix/lib/smb.conf.server
+ cp basicsmb.smb.conf.domain $prefix/lib/smb.conf.domain
+ touch $prefix/lib/smb.conf.
+ touch $prefix/lib/smb.conf.localhost
+}
+
+test_smbpasswd() {
+ test_smbpasswd_password="$1"
+ rm -f $prefix/private/smbpasswd
+ echo "( echo $test_smbpasswd_password ; echo $test_smbpasswd_password; ) | $prefix/bin/smbpasswd -L -s -a $whoami"
+ ( echo $password ; echo $password; ) | $prefix/bin/smbpasswd -L -s -a $whoami
+ status=$?
+ if [ $status = 0 ]; then
+ echo "smbpasswd correctly set inital password ($test_smbpasswd_password)"
+ else
+ echo "smbpasswd failed to set inital password ($test_smbpasswd_password)! (status $status)"
+ return 1
+ fi
+ return 0
+}
+
+test_listfilesauth() {
+ remote_name="$1"
+ echo $prefix/bin/smbclient//$remote_name/samba -n buildclient -U$whoami%$password -c 'ls'
+ $prefix/bin/smbclient //$remote_name/samba -n buildclient -U$whoami%$password -c 'ls'
+ status=$?
+ if [ $status = 0 ]; then
+ echo "listed files OK"
+ else
+ echo "listing files with smbd failed with status $status"
+ return 1
+ fi
+ return 0
+}
+
+test_listfilesnpw() {
+ remote_name="$1"
+ echo $prefix/bin/smbclient //$remote_name/samba -n buildclient -U$whoami% -c 'ls'
+ $prefix/bin/smbclient //$remote_name/samba -n buildclient -U$whoami% -c 'ls'
+ status=$?
+ if [ $status = 0 ]; then
+ echo "smbd listed files with NO PASSWORD on an authenticated share!"
+ return 1
+ else
+ echo "listing files with smbd failed with status $status (correct)"
+ fi
+ return 0
+}
+
diff --git a/testsuite/build_farm/basicsmb.smb.conf.server b/testsuite/build_farm/basicsmb.smb.conf.server
new file mode 100644
index 00000000000..0b50144119f
--- /dev/null
+++ b/testsuite/build_farm/basicsmb.smb.conf.server
@@ -0,0 +1,3 @@
+security=server
+password server=user
+smb password file=/dev/null
diff --git a/testsuite/build_farm/basicsmb.smb.conf.template b/testsuite/build_farm/basicsmb.smb.conf.template
new file mode 100644
index 00000000000..6785866fc10
--- /dev/null
+++ b/testsuite/build_farm/basicsmb.smb.conf.template
@@ -0,0 +1,39 @@
+[global]
+ netbios name = BUILDFARM
+ workgroup = TESTWG
+ log level = LOGLEVEL
+ debug timestamp = no
+ encrypt passwords = yes
+ server string = Samba %v Build Farm Tests
+ name resolve order = lmhosts
+ guest account = WHOAMI
+ domain logons = yes
+
+ strict locking = yes
+
+ include = PREFIX/lib/smb.conf.%L
+
+[test]
+ path = PREFIX/testdir
+ read only = no
+
+[samba]
+ path = BUILD_FARM/samba
+ read only = yes
+ comment = Samba HEAD Sources
+
+[samba_2_2]
+ path = BUILD_FARM/samba_2_2
+ read only = yes
+ comment = Samba 2.2. Sources
+
+[rsync]
+ path = BUILD_FARM/rsync
+ read only = yes
+ comment = Rsync Sources
+
+[guest_share]
+ path = PREFIX
+ guest ok = yes
+ read only = yes
+ comment = Unauthenticated share for use in share level test
diff --git a/testsuite/build_farm/basicsmb.smb.conf.user b/testsuite/build_farm/basicsmb.smb.conf.user
new file mode 100644
index 00000000000..9d294b9c396
--- /dev/null
+++ b/testsuite/build_farm/basicsmb.smb.conf.user
@@ -0,0 +1 @@
+ security = user
diff --git a/testsuite/build_farm/runlist b/testsuite/build_farm/runlist
new file mode 100644
index 00000000000..aac41215aa2
--- /dev/null
+++ b/testsuite/build_farm/runlist
@@ -0,0 +1,3 @@
+TEST_ALL="basicsmb-sharelist basicsmb-sharesec basicsmb-usersec basicsmb-shareguest torture-FDPASS torture-LOCK1 torture-LOCK2 torture-LOCK3 torture-LOCK4 torture-LOCK5 torture-UNLINK torture-BROWSE torture-ATTR torture-TRANS2 torture-TORTURE torture-OPLOCK1 torture-OPLOCK3 torture-DIR torture-DENY1 torture-DENY2 torture-TCON torture-RW1 torture-RW2 torture-OPEN torture-DELETE"
+
+#basicsmb-serversec