diff options
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<codepage>.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.<codepage></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;/\</g; + $buf =~ s/\&\#62;/\>/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 -- 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<codepage>.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.<codepage></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 |