summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 17:20:00 +0000
commit8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch)
tree4099e8021376c7d8c05bdf8503093d80e9c7bad0 /examples
parentInitial commit. (diff)
downloadsamba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz
samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'examples')
-rw-r--r--examples/LDAP/README74
-rwxr-xr-xexamples/LDAP/get_next_oid15
-rwxr-xr-xexamples/LDAP/ol-schema-migrate.pl384
-rw-r--r--examples/LDAP/samba-nds.schema440
-rw-r--r--examples/LDAP/samba-schema-FDS.ldif190
-rw-r--r--examples/LDAP/samba-schema-netscapeds5.x.README2
-rw-r--r--examples/LDAP/samba-schema.IBMSecureWay43
-rw-r--r--examples/LDAP/samba.ldif224
-rw-r--r--examples/LDAP/samba.schema649
-rw-r--r--examples/LDAP/samba.schema.at.IBM-DS116
-rw-r--r--examples/LDAP/samba.schema.oc.IBM-DS23
-rw-r--r--examples/README11
-rw-r--r--examples/VFS/README20
-rw-r--r--examples/VFS/shadow_copy_test.c92
-rw-r--r--examples/VFS/skel_opaque.c1099
-rw-r--r--examples/VFS/skel_transparent.c1410
-rw-r--r--examples/VFS/wscript_build25
-rw-r--r--examples/ad-bench/README42
-rwxr-xr-xexamples/ad-bench/ad-bench.sh38
-rw-r--r--examples/ad-bench/settings.sh40
-rw-r--r--examples/ad-bench/test_utils.sh29
-rw-r--r--examples/ad-bench/time_group.sh131
-rw-r--r--examples/ad-bench/time_join.sh89
-rw-r--r--examples/ad-bench/time_kinit.sh65
-rw-r--r--examples/ad-bench/time_ldap.sh144
-rw-r--r--examples/ad-bench/time_user.sh131
-rw-r--r--examples/ad-bench/utils.sh130
-rw-r--r--examples/auth/crackcheck/Makefile25
-rw-r--r--examples/auth/crackcheck/crackcheck.c141
-rw-r--r--examples/autofs/auto.smb11
-rw-r--r--examples/dce-dfs/README4
-rw-r--r--examples/dce-dfs/smb.conf41
-rw-r--r--examples/fuse/README7
-rw-r--r--examples/fuse/clifuse.c1591
-rw-r--r--examples/fuse/clifuse.h27
-rw-r--r--examples/fuse/smb2mount.c160
-rw-r--r--examples/fuse/wscript14
-rw-r--r--examples/fuse/wscript_build7
-rw-r--r--examples/libsmbclient/Makefile116
-rw-r--r--examples/libsmbclient/Makefile.internal.in138
-rw-r--r--examples/libsmbclient/README17
-rw-r--r--examples/libsmbclient/get_auth_data_fn.h92
-rw-r--r--examples/libsmbclient/testacl.c333
-rw-r--r--examples/libsmbclient/testacl2.c73
-rw-r--r--examples/libsmbclient/testacl3.c59
-rw-r--r--examples/libsmbclient/testbrowse.c281
-rw-r--r--examples/libsmbclient/testbrowse2.c169
-rw-r--r--examples/libsmbclient/testchmod.c62
-rw-r--r--examples/libsmbclient/testctx.c33
-rw-r--r--examples/libsmbclient/testfstatvfs.c134
-rw-r--r--examples/libsmbclient/testnotify.c82
-rw-r--r--examples/libsmbclient/testread.c66
-rw-r--r--examples/libsmbclient/testsmbc.c291
-rw-r--r--examples/libsmbclient/teststat.c110
-rw-r--r--examples/libsmbclient/teststat2.c70
-rw-r--r--examples/libsmbclient/teststat3.c74
-rw-r--r--examples/libsmbclient/teststatvfs.c106
-rw-r--r--examples/libsmbclient/testtruncate.c80
-rw-r--r--examples/libsmbclient/testutime.c75
-rw-r--r--examples/libsmbclient/testwrite.c72
-rw-r--r--examples/libsmbclient/tree.c812
-rw-r--r--examples/libsmbclient/wscript_build26
-rw-r--r--examples/logon/genlogon/genlogon.pl71
-rw-r--r--examples/logon/mklogon/mklogon.conf78
-rw-r--r--examples/logon/mklogon/mklogon.pl392
-rw-r--r--examples/logon/ntlogon/README160
-rw-r--r--examples/logon/ntlogon/ntlogon.conf44
-rwxr-xr-xexamples/logon/ntlogon/ntlogon.py375
-rwxr-xr-xexamples/misc/adssearch.pl1897
-rwxr-xr-xexamples/misc/check_multiple_LDAP_entries.pl201
-rwxr-xr-xexamples/misc/cldap.pl491
-rw-r--r--examples/misc/extra_smbstatus50
-rw-r--r--examples/misc/wall.perl69
-rw-r--r--examples/nss/nss_winbind.c422
-rw-r--r--examples/nss/nss_winbind.h97
-rw-r--r--examples/nss/wbtest.c111
-rw-r--r--examples/pam_winbind/pam_winbind.conf39
-rw-r--r--examples/pcap2nbench/COPYING674
-rw-r--r--examples/pcap2nbench/Makefile33
-rw-r--r--examples/pcap2nbench/README24
-rw-r--r--examples/pcap2nbench/closerequest.cpp45
-rw-r--r--examples/pcap2nbench/closerequest.hpp43
-rw-r--r--examples/pcap2nbench/ethernet.cpp61
-rw-r--r--examples/pcap2nbench/ethernet.hpp36
-rw-r--r--examples/pcap2nbench/ip.cpp65
-rw-r--r--examples/pcap2nbench/ip.hpp46
-rw-r--r--examples/pcap2nbench/main.cpp738
-rw-r--r--examples/pcap2nbench/ntcreateandxrequest.cpp73
-rw-r--r--examples/pcap2nbench/ntcreateandxrequest.hpp57
-rw-r--r--examples/pcap2nbench/ntcreateandxresponse.cpp42
-rw-r--r--examples/pcap2nbench/ntcreateandxresponse.hpp57
-rw-r--r--examples/pcap2nbench/readandxrequest.cpp60
-rw-r--r--examples/pcap2nbench/readandxrequest.hpp51
-rw-r--r--examples/pcap2nbench/readandxresponse.hpp47
-rw-r--r--examples/pcap2nbench/smb.cpp71
-rw-r--r--examples/pcap2nbench/smb.hpp48
-rw-r--r--examples/pcap2nbench/tcp.cpp59
-rw-r--r--examples/pcap2nbench/tcp.hpp42
-rw-r--r--examples/pcap2nbench/writeandxrequest.cpp65
-rw-r--r--examples/pcap2nbench/writeandxrequest.hpp53
-rw-r--r--examples/pdb/Makefile31
-rw-r--r--examples/pdb/README20
-rw-r--r--examples/pdb/test.c115
-rw-r--r--examples/pdb/wscript_build10
-rw-r--r--examples/perfcounter/Makefile38
-rw-r--r--examples/perfcounter/perf.h210
-rw-r--r--examples/perfcounter/perf_writer.c213
-rw-r--r--examples/perfcounter/perf_writer_cpu.c189
-rw-r--r--examples/perfcounter/perf_writer_disk.c224
-rw-r--r--examples/perfcounter/perf_writer_mem.c124
-rw-r--r--examples/perfcounter/perf_writer_process.c85
-rw-r--r--examples/perfcounter/perf_writer_util.c235
-rwxr-xr-xexamples/perfcounter/perfcountd.init65
-rw-r--r--examples/printer-accounting/README63
-rw-r--r--examples/printer-accounting/acct-all9
-rw-r--r--examples/printer-accounting/acct-sum29
-rw-r--r--examples/printer-accounting/hp5-redir40
-rw-r--r--examples/printer-accounting/lp-acct35
-rw-r--r--examples/printer-accounting/printcap22
-rw-r--r--examples/printing/VampireDriversFunctions1656
-rw-r--r--examples/printing/prtpub.c237
-rw-r--r--examples/printing/readme.prtpub12
-rw-r--r--examples/printing/smbprint.sysv52
-rw-r--r--examples/scripts/debugging/linux/backtrace41
-rwxr-xr-xexamples/scripts/debugging/smbXsrvdump87
-rw-r--r--examples/scripts/debugging/solaris/README28
-rw-r--r--examples/scripts/debugging/solaris/solaris-oops.sh57
-rw-r--r--examples/scripts/eventlog/parselog.pl32
-rw-r--r--examples/scripts/idmap/README168
-rwxr-xr-xexamples/scripts/idmap/idmap_nis.sh120
-rw-r--r--examples/scripts/mount/mount.smbfs115
-rwxr-xr-xexamples/scripts/nmb/findsmb160
-rw-r--r--examples/scripts/nmb/findsmb.1.xml145
-rwxr-xr-xexamples/scripts/printing/cups/smbaddprinter.pl39
-rwxr-xr-xexamples/scripts/printing/cups/smbdelprinter.pl25
-rwxr-xr-xexamples/scripts/users_and_groups/adduserstogroups.pl166
-rwxr-xr-xexamples/scripts/users_and_groups/createdomobj.pl159
-rwxr-xr-xexamples/scripts/vfs/media_harmony/trigger_avid_update.py106
-rw-r--r--examples/scripts/vfs/virusfilter/virusfilter-notify.ksh284
-rw-r--r--examples/scripts/wins_hook/README8
-rw-r--r--examples/scripts/wins_hook/dns_update92
-rw-r--r--examples/smb.conf.default223
-rwxr-xr-xexamples/systemtap/gencache.stp147
-rwxr-xr-xexamples/systemtap/generate-winbindd.stp.sh310
-rw-r--r--examples/systemtap/winbindd.stp2879
-rw-r--r--examples/winexe/README18
-rw-r--r--examples/winexe/winexe.c1918
-rw-r--r--examples/winexe/winexesvc.c745
-rw-r--r--examples/winexe/winexesvc.h42
-rw-r--r--examples/winexe/wscript31
-rw-r--r--examples/winexe/wscript_build118
151 files changed, 30019 insertions, 0 deletions
diff --git a/examples/LDAP/README b/examples/LDAP/README
new file mode 100644
index 0000000..f6ce3a9
--- /dev/null
+++ b/examples/LDAP/README
@@ -0,0 +1,74 @@
+!==
+!== README File for various LDAP examples
+!==
+!== written by Gerald Carter <jerry@samba.org>
+!==
+
+OpenLDAP 2.x
+------------
+
+A sample schema file (samba.schema) has been included for use
+with OpenLDAP 2.0.x. The OIDs used in this file are owned by
+the Samba team and generated from its own Enterprise number
+of 7165 (as issued by IANA).
+
+Copy the samba.schema file into your /etc/openldap/schema directory,
+and add an include for it in the /etc/openldap/slapd.conf file.
+Note that samba.schema relies upon the uid and uidNumber attributes
+from the RFC2307 schema (i.e. nis.schema)
+
+If you choose to import /etc/passwd, nis, or nisplus tables
+into ldap, you can use migration tools provided by PADL Software
+which are located at
+
+ http://www.padl.com/tools.html
+
+It is not a requirement that a user's /etc/passwd account
+is stored in LDAP for the samba.schema file to work (although
+the whole point of storing smbpasswd in LDAP is to have a
+single location for user accounts, right?)
+
+The padl tools will leave you with LDIF files which you can import
+into OpenLDAP. Before you can import them, you need to include
+nis.schema and cosine.schema in your slapd.conf file.
+
+You must restart the LDAP server for these new included schema files
+to become active.
+
+SunOne/Netscape DS
+------------------
+
+The schema file has not been updated for the sambaSamAccount
+objectclass.
+
+
+Novell eDirectory
+-----------------
+
+The schema file has not been updated for the sambaSamAccount
+objectclass.
+
+Fedora Directory Server /
+RedHat Directory Server /
+Netscape Directory Server
+-------------------------
+
+An *updated* schema file has been provided, plus a very useful script from
+Mike Jackson and Alyseo is available.
+ol-schema-migrate.pl can be used to migrate OpenLDAP schema files to FDS
+schema ldif files, it can also be used to validate the schema files to
+make sure no duplicate OIDs or malformed entries are found.
+
+smbldap-tools/
+--------------
+
+The smbldap-tools have been removed from the samba svn
+tree. The latest version will continue to be included
+in Samba releases.
+
+The smbldap-tools package can be downloaded individually from
+https://gna.org/projects/smbldap-tools/
+
+!==
+!== end of README
+!==
diff --git a/examples/LDAP/get_next_oid b/examples/LDAP/get_next_oid
new file mode 100755
index 0000000..bc3d6fc
--- /dev/null
+++ b/examples/LDAP/get_next_oid
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+nextattrib=$(cat samba.schema | grep -i attributetype.*\(.*1.3.6.1.4.1.7165. | grep -v '^#' |
+ awk '{print $3}' | cut -d. -f 10 | sort -n | tail -1)
+
+netattrib=$((netattrib + 1))
+
+echo "attributetype ( 1.3.6.1.4.1.7165.2.1.$nextattrib NAME ...."
+
+nextoc=$(cat samba.schema | grep -i objectclass.*\(.*1.3.6.1.4.1.7165. | grep -v '^#' |
+ awk '{print $3}' | cut -d. -f 10 | sort -n | tail -1)
+
+nextoc=$((nextoc + 1))
+
+echo "objectclass ( 1.3.6.1.4.1.7165.2.2.$nextoc NAME ...."
diff --git a/examples/LDAP/ol-schema-migrate.pl b/examples/LDAP/ol-schema-migrate.pl
new file mode 100755
index 0000000..c0a6f01
--- /dev/null
+++ b/examples/LDAP/ol-schema-migrate.pl
@@ -0,0 +1,384 @@
+#!/usr/bin/perl -w
+#
+# Convert OpenLDAP schema files into Fedora DS format with RFC2252 compliant printing
+#
+# First Release : Mike Jackson <mj@sci.fi> 14 June 2005
+# http://www.netauth.com/~jacksonm/ldap/ol-schema-migrate.pl
+# Professional LDAP consulting for large and small projects
+#
+# - 6 Dec 2005
+# - objectclass element ordering
+#
+# Second Release : Alyseo <info@alyseo.com> 05 Februrary 2006
+# Francois Billard <francois@alyseo.com>
+# Yacine Kheddache <yacine@alyseo.com>
+# http://www.alyseo.com/
+#
+# - 05 Februrary 2006
+# - parsing improvement to accept non-RFC compliant schemas (like ISPMAN)
+# - adding RFC element : Usage, No-user-modification, collective keywords
+# - 08 Februrary 2006
+# - adding help & usage
+# - now this script can also beautify your schemas: "-b"
+# - count attributes and objects class: "-c"
+# - display items that can not be converted (empty OID...): "-d"
+# - 15 February 2006
+# - adding workaround for Fedora DS bug 181465:
+# https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=181465
+# - adding duplicated OID check: "-d"
+# Useful to manually correct nasty schemas like:
+# https://sourceforge.net/tracker/?func=detail&atid=108390&aid=1429276&group_id=8390
+# - 13 September 2007
+# Based on Samba Team GPL Compliance Officer request, license has been updated from
+# GPL to GPLv3+
+#
+# - Fedora DS bug you need to correct by hand :
+# https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=179956
+#
+# GPLv3+ license
+#
+
+my $optionCount = 0;
+my $optionPrint = 0;
+my $optionBadEntries = 0;
+my $optionHelp = 0;
+my $filename = "" ;
+
+foreach (@ARGV) {
+ $optionHelp = 1 if ( /^-h$/);
+ $optionCount = 1 if ( /^-c$/);
+ $optionPrint = 1 if ( /^-b$/);
+ $optionBadEntries = 1 if ( /^-d$/);
+ $filename = $_ if ( ! /^-b$/ && ! /^-c$/ && ! /^-d$/);
+}
+
+die "Usage : ol-schema-migrate-v2.pl [ -c ] [ -b ] [ -d ] schema\n" .
+ " -c\tcount attribute and object class\n" .
+ " -b\tconvert and beautify your schema\n" .
+ " -d\tdisplay unrecognized elements, find empty and duplicated OID\n" .
+ " -h\tthis help\n" if ($filename eq "" || ($optionHelp || (!$optionCount && !$optionPrint && !$optionBadEntries)));
+
+if($optionCount) {
+ print "Schema verification counters:\n";
+ my $ldapdata = &getSourceFile($filename);
+ print "".(defined($ldapdata->{attributes}) ? @{$ldapdata->{attributes}} : 0) . " attributes\n";
+ print "".(defined($ldapdata->{objectclass}) ? @{$ldapdata->{objectclass}} : 0) . " object classes\n\n"
+}
+
+if($optionPrint) {
+ my $ldapdata = &getSourceFile($filename);
+ &printit($ldapdata);
+}
+
+if($optionBadEntries) {
+ print "Display unrecognized entries:\n";
+ my $ldapdata = &getSourceFile($filename);
+ my $errorsAttr = 0;
+ my $errorsObjc = 0;
+ my $errorsDup = 0;
+ my $emptyOid = 0;
+ my %dup;
+
+ foreach (@{$ldapdata->{attributes}}) {
+ my $attr = $_;
+
+ push @{$dup{$attr->{OID}}{attr}}, {NAME => $attr->{NAME}, LINENUMBER => $attr->{LINENUMBER}};
+
+ $attr->{DATA} =~ s/\n/ /g;
+ $attr->{DATA} =~ s/\r//g;
+ $attr->{DATA} =~ s/attribute[t|T]ypes?:?\s*\(//;
+ $attr->{DATA} =~ s/\Q$attr->{OID}// if(defined $attr->{OID});
+ $attr->{DATA} =~ s/NAME\s*\Q$attr->{NAME}// if(defined $attr->{NAME});
+ $attr->{DATA} =~ s/DESC\s*'\Q$attr->{DESC}'// if(defined $attr->{DESC});
+ $attr->{DATA} =~ s/$attr->{OBSOLETE}// if(defined $attr->{OBSOLETE});
+ $attr->{DATA} =~ s/SUP\s*\Q$attr->{SUP}// if(defined $attr->{SUP});
+ $attr->{DATA} =~ s/EQUALITY\s*\Q$attr->{EQUALITY}// if(defined $attr->{EQUALITY});
+ $attr->{DATA} =~ s/ORDERING\s*\Q$attr->{ORDERING}// if(defined $attr->{ORDERING});
+ $attr->{DATA} =~ s/SUBSTR\s*\Q$attr->{SUBSTR}// if(defined $attr->{SUBSTR});
+ $attr->{DATA} =~ s/SYNTAX\s*\Q$attr->{SYNTAX}// if(defined $attr->{SYNTAX});
+ $attr->{DATA} =~ s/SINGLE-VALUE// if(defined $attr->{SINGLEVALUE});
+ $attr->{DATA} =~ s/NO-USER-MODIFICATION// if(defined $attr->{NOUSERMOD});
+ $attr->{DATA} =~ s/COLLECTIVE// if(defined $attr->{COLLECTIVE});
+ $attr->{DATA} =~ s/USAGE\s*\Q$attr->{USAGE}// if(defined $attr->{USAGE});
+ $attr->{DATA} =~ s/\)\s$//;
+ $attr->{DATA} =~ s/^\s+(\S)/\n$1/ ;
+ $attr->{DATA} =~ s/(\S)\s+$/$1\n/;
+ do {
+ $errorsAttr ++;
+ do { $emptyOid ++;
+ print "Warning : no OID for attributes element at line $attr->{LINENUMBER} \n";
+ } if( !defined($attr->{OID}));
+ print "### Unknown element embedded in ATTRIBUTE at line $attr->{LINENUMBER} :\n$attr->{DATA}\n"
+ } if($attr->{DATA} =~ /\w/);
+ }
+
+ foreach (@{$ldapdata->{objectclass}}) {
+ my $objc = $_;
+ push @{$dup{$objc->{OID}}{objc}} , {NAME => $objc->{NAME}, LINENUMBER => $objc->{LINENUMBER}};
+ $objc->{DATA} =~ s/\n/ /g;
+ $objc->{DATA} =~ s/\r//g;
+ $objc->{DATA} =~ s/^object[c|C]lasse?s?:?\s*\(?//;
+ $objc->{DATA} =~ s/\Q$objc->{OID}// if(defined $objc->{OID});
+ $objc->{DATA} =~ s/NAME\s*\Q$objc->{NAME}\E// if(defined $objc->{NAME});
+ $objc->{DATA} =~ s/DESC\s*'\Q$objc->{DESC}\E'// if(defined $objc->{DESC});
+ $objc->{DATA} =~ s/OBSOLETE// if(defined $objc->{OBSOLETE});
+ $objc->{DATA} =~ s/SUP\s*\Q$objc->{SUP}// if(defined $objc->{SUP});
+ $objc->{DATA} =~ s/\Q$objc->{TYPE}// if(defined $objc->{TYPE});
+ $objc->{DATA} =~ s/MUST\s*\Q$objc->{MUST}\E\s*// if(defined $objc->{MUST});
+ $objc->{DATA} =~ s/MUST\s*\(?\s*\Q$objc->{MUST}\E\s*\)?// if(defined $objc->{MUST});
+ $objc->{DATA} =~ s/MAY\s*\Q$objc->{MAY}\E// if(defined $objc->{MAY});
+ $objc->{DATA} =~ s/\)\s$//;
+ $objc->{DATA} =~ s/^\s+(\S)/\n$1/ ;
+ $objc->{DATA} =~ s/(\S)\s+$/$1\n/;
+
+ do {
+ print "#" x 80 ."\n";
+ $errorsObjc ++;
+ do { $emptyOid++ ;
+ print "Warning : no OID for object class element at line $objc->{LINENUMBER} \n";
+ } if( $objc->{OID} eq "");
+ print "### Unknown element embedded in OBJECT CLASS at line $objc->{LINENUMBER} :\n$objc->{DATA}\n"
+ } if($objc->{DATA} =~ /\w/);
+ }
+
+ my $nbDup = 0;
+ foreach (keys %dup) {
+ my $sumOid = 0;
+ $sumOid += @{$dup{$_}{attr}} if(defined (@{$dup{$_}{attr}}));
+ $sumOid += @{$dup{$_}{objc}} if(defined (@{$dup{$_}{objc}}));
+ if( $sumOid > 1 && $_ ne "") {
+ $nbDup ++;
+ print "#" x 80 ."\n";
+ print "Duplicate OID founds : $_\n";
+ foreach (@{$dup{$_}{attr}}) {
+
+ print "Attribute : $_->{NAME} (line : $_->{LINENUMBER})\n";
+ }
+ foreach (@{$dup{$_}{objc}}) {
+ print "Object class : $_->{NAME} (line : $_->{LINENUMBER})\n";
+ }
+
+ }
+ }
+
+ print "\n$errorsAttr errors detected in ATTRIBUTES list\n";
+ print "$errorsObjc errors detected in OBJECT CLASS list\n";
+ print "$nbDup duplicate OID founds\n";
+ print "$emptyOid empty OID fields founds\n\n";
+
+}
+
+
+sub printit {
+ my $ldapdata = shift;
+ &printSeparator;
+ print "dn: cn=schema\n";
+ &printSeparator;
+
+ # print elements in RFC2252 order
+
+ foreach (@{$ldapdata->{attributes}}) {
+ my $attr = $_;
+ print "attributeTypes: (\n";
+ print " $attr->{OID}\n";
+ print " NAME $attr->{NAME}\n";
+ print " DESC '$attr->{DESC}'\n" if(defined $attr->{DESC});
+ print " OBSOLETE\n" if(defined $attr->{OBSOLETE});
+ print " SUP $attr->{SUP}\n" if(defined $attr->{SUP});
+ print " EQUALITY $attr->{EQUALITY}\n" if(defined $attr->{EQUALITY});
+ print " ORDERING $attr->{ORDERING}\n" if(defined $attr->{ORDERING});
+ print " SUBSTR $attr->{SUBSTR}\n" if(defined $attr->{SUBSTR});
+ print " SYNTAX $attr->{SYNTAX}\n" if(defined $attr->{SYNTAX});
+ print " SINGLE-VALUE\n" if(defined $attr->{SINGLEVALUE});
+ print " NO-USER-MODIFICATION\n" if(defined $attr->{NOUSERMOD});
+ print " COLLECTIVE\n" if(defined $attr->{COLLECTIVE});
+ print " USAGE $attr->{USAGE}\n" if(defined $attr->{USAGE});
+ print " )\n";
+ &printSeparator;
+ }
+
+ foreach (@{$ldapdata->{objectclass}}) {
+ my $objc = $_;
+ # next 3 lines : Fedora DS space sensitive bug workaround
+ $objc->{SUP} =~ s/^\(\s*(.*?)\s*\)$/\( $1 \)/ if (defined $objc->{SUP});
+ $objc->{MUST} =~ s/^\(\s*(.*?)\s*\)$/\( $1 \)/ if (defined $objc->{MUST});
+ $objc->{MAY} =~ s/^\(\s*(.*?)\s*\)$/\( $1 \)/ if (defined $objc->{MAY});
+
+ print "objectClasses: (\n";
+ print " $objc->{OID}\n";
+ print " NAME $objc->{NAME}\n";
+ print " DESC '$objc->{DESC}'\n" if(defined $objc->{DESC});
+ print " OBSOLETE\n" if(defined $objc->{OBSOLETE});
+ print " SUP $objc->{SUP}\n" if(defined $objc->{SUP});
+ print " $objc->{TYPE}\n" if(defined $objc->{TYPE});
+ print " MUST $objc->{MUST}\n" if(defined $objc->{MUST});
+ print " MAY $objc->{MAY}\n" if(defined $objc->{MAY});
+ print " )\n";
+ &printSeparator;
+ }
+}
+
+sub printSeparator {
+ print "#\n";
+ print "#" x 80 . "\n";
+ print "#\n";
+}
+
+sub getSourceFile {
+ my @data = &getFile(shift);
+ my %result;
+ my $result = \%result;
+ my @allattrs;
+ my @allattrsLineNumber;
+ my @allobjc;
+ my @allobjcLineNumber;
+ my $at = 0;
+ my $oc = 0;
+ my $at_string;
+ my $oc_string;
+ my $idx = 0;
+ my $beginParenthesis = 0;
+ my $endParenthesis = 0;
+ my $lineNumber = 0;
+ for(@data) {
+ $lineNumber++;
+ next if (/^\s*\#/); # skip comments
+
+ if($at) {
+ s/ +/ /; # remove embedded tabs
+ s/\t/ /; # remove multiple spaces after the $ sign
+
+ $at_string .= $_;
+ $beginParenthesis = 0; # Use best matching elements
+ $endParenthesis = 0;
+ for(my $i=0;$ i < length($at_string); $i++) {
+ $beginParenthesis++ if(substr ($at_string,$i,1) eq "(");
+ $endParenthesis++ if(substr ($at_string,$i,1) eq ")");
+ }
+ if($beginParenthesis == $endParenthesis) {
+ push @allattrs, $at_string;
+ $at = 0;
+ $at_string = "";
+ $endParenthesis = 0;
+ $beginParenthesis = 0;
+ }
+ }
+
+ if (/^attribute[t|T]ype/) {
+ my $line = $_;
+ push @allattrsLineNumber, $lineNumber; # keep starting line number
+ for(my $i=0;$ i < length($line); $i++) {
+ $beginParenthesis++ if(substr ($line, $i, 1) eq "(");
+ $endParenthesis++ if(substr ($line, $i, 1) eq ")");
+ }
+ if($beginParenthesis == $endParenthesis && $beginParenthesis != 0) {
+ push @allattrs, $line;
+ $endParenthesis = 0;
+ $beginParenthesis = 0;
+ } else {
+ $at_string = $line;
+ $at = 1;
+ }
+ }
+
+ #####################################
+
+ if($oc) {
+ s/ +/ /;
+ s/\t/ /;
+
+ $oc_string .= $_;
+ $endParenthesis = 0; # best method to accept an elements :
+ $beginParenthesis = 0; # left parenthesis sum == right parenthesis sum, so we are sure to
+ for(my $i=0;$ i < length($oc_string); $i++) { # have an element.
+ $beginParenthesis++ if(substr ($oc_string, $i, 1) eq "(");
+ $endParenthesis++ if(substr ($oc_string, $i, 1) eq ")");
+ }
+ if($beginParenthesis == $endParenthesis) {
+ push @allobjc, $oc_string;
+ $oc = 0;
+ $oc_string = "";
+ $endParenthesis = 0;
+ $beginParenthesis = 0;
+ }
+ }
+
+ if (/^object[c|C]lass/) {
+ my $line = $_;
+ push @allobjcLineNumber, $lineNumber; # keep starting line number
+ for(my $i=0;$ i < length($line); $i++) {
+ $beginParenthesis++ if(substr ($line, $i, 1) eq "(");
+ $endParenthesis++ if(substr ($line, $i, 1) eq ")");
+ }
+ if($beginParenthesis == $endParenthesis && $beginParenthesis != 0) {
+ push @allobjc, $line;
+ $endParenthesis = 0;
+ $beginParenthesis = 0;
+ } else {
+ $oc_string = $line;
+ $oc = 1;
+ }
+ }
+ }
+
+ # Parsing attribute elements
+
+ for(@allattrs) {
+ s/\n/ /g;
+ s/\r//g;
+ s/ +/ /g;
+ s/\t/ /g;
+ $result->{attributes}->[$idx]->{DATA} = $_ if($optionBadEntries); # keep original data
+ $result->{attributes}->[$idx]->{LINENUMBER} = $allattrsLineNumber[$idx];
+ $result->{attributes}->[$idx]->{OID} = $1 if (m/^attribute[t|T]ypes?:?\s*\(?\s*([\.\d]*?)\s+/);
+ $result->{attributes}->[$idx]->{NAME} = $1 if (m/NAME\s+('.*?')\s*/ || m/NAME\s+(\(.*?\))/);
+ $result->{attributes}->[$idx]->{DESC} = $1 if (m/DESC\s+'(.*?)'\s*/);
+ $result->{attributes}->[$idx]->{OBSOLETE} = "OBSOLETE" if (m/OBSOLETE/);
+ $result->{attributes}->[$idx]->{SUP} = $1 if (m/SUP\s+(.*?)\s/);
+ $result->{attributes}->[$idx]->{EQUALITY} = $1 if (m/EQUALITY\s+(.*?)\s/);
+ $result->{attributes}->[$idx]->{ORDERING} = $1 if (m/ORDERING\s+(.*?)\s/);
+ $result->{attributes}->[$idx]->{SUBSTR} = $1 if (m/SUBSTR\s+(.*?)\s/);
+ $result->{attributes}->[$idx]->{SYNTAX} = $1 if (m/SYNTAX\s+(.*?)(\s|\))/);
+ $result->{attributes}->[$idx]->{SINGLEVALUE} = "SINGLE-VALUE" if (m/SINGLE-VALUE/);
+ $result->{attributes}->[$idx]->{COLLECTIVE} = "COLLECTIVE" if (m/COLLECTIVE/);
+ $result->{attributes}->[$idx]->{USAGE} = $1 if (m/USAGE\s+(.*?)\s/);
+ $result->{attributes}->[$idx]->{NOUSERMOD} = "NO-USER-MODIFICATION" if (m/NO-USER-MODIFICATION/);
+ $idx ++;
+ }
+
+ $idx = 0;
+
+ # Parsing object class elements
+
+ for(@allobjc) {
+ s/\n/ /g;
+ s/\r//g;
+ s/ +/ /g;
+ s/\t/ /g;
+ $result->{objectclass}->[$idx]->{DATA} = $_ if($optionBadEntries); # keep original data
+ $result->{objectclass}->[$idx]->{LINENUMBER} = $allobjcLineNumber[$idx];
+ $result->{objectclass}->[$idx]->{OID} = $1 if (m/^object[c|C]lasse?s?:?\s*\(?\s*([\.\d]*?)\s+/);
+ $result->{objectclass}->[$idx]->{NAME} = $1 if (m/NAME\s+('.*?')\s*/ || m/NAME\s+(\(.*?\))/);
+ $result->{objectclass}->[$idx]->{DESC} = $1 if (m/DESC\s+'(.*?)'\s*/);
+ $result->{objectclass}->[$idx]->{OBSOLETE} = "OBSOLETE" if (m/OBSOLETE/);
+ $result->{objectclass}->[$idx]->{SUP} = $1 if (m/SUP\s+([^()]+?)\s/ || m/SUP\s+(\(.+?\))\s/);
+ $result->{objectclass}->[$idx]->{TYPE} = $1 if (m/((?:STRUCTURAL)|(?:AUXILIARY)|(?:ABSTRACT))/);
+ $result->{objectclass}->[$idx]->{MUST} = $1 if (m/MUST\s+(\w+)\)?/ || m/MUST\s+(\(.*?\))(\s|\))/s);
+ $result->{objectclass}->[$idx]->{MAY} = $1 if (m/MAY\s+(\w+)\)?/ || m/MAY\s+(\(.*?\))(\s|\))/s);
+
+ $idx++;
+ }
+
+ return $result;
+}
+
+sub getFile {
+ my @data;
+ my $file = shift;
+ die "File not found : $file\n" if(! -e $file);
+ open FH, $file;
+ @data = <FH>;
+ close FH;
+ @data;
+}
+
diff --git a/examples/LDAP/samba-nds.schema b/examples/LDAP/samba-nds.schema
new file mode 100644
index 0000000..8b427b5
--- /dev/null
+++ b/examples/LDAP/samba-nds.schema
@@ -0,0 +1,440 @@
+##
+## Schema file for Novell eDirectory by Uli Iske
+## Schema for storing Samba user accounts and group maps in LDAP
+## OIDs are owned by the Samba Team
+##
+## Prerequisite schemas rfc2307-usergroup.ldif
+##
+## 1.3.6.1.4.1.7165.2.1.x - attributetypes
+## 1.3.6.1.4.1.7165.2.2.x - objectclasses
+##
+## OIDs are owned by the Samba Team
+##
+#######################################################################
+## Attributes used by Samba 3.0 schema ##
+#######################################################################
+
+##
+## Password hashes
+##
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.24 NAME 'sambaLMPassword' DESC 'LanManager Password' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.25 NAME 'sambaNTPassword' DESC 'MD4 hash of the unicode password' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )
+
+##
+## Account flags in string format ((UWDX ])
+##
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.26 NAME 'sambaAcctFlags' DESC 'Account Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} SINGLE-VALUE )
+
+##
+## Password timestamps & policies
+##
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.27 NAME 'sambaPwdLastSet' DESC 'Timestamp of the last password update' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.28 NAME 'sambaPwdCanChange' DESC 'Timestamp of when the user is allowed to update the password' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.29 NAME 'sambaPwdMustChange' DESC 'Timestamp of when the password will expire' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.30 NAME 'sambaLogonTime' DESC 'Timestamp of last logon' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.31 NAME 'sambaLogoffTime' DESC 'Timestamp of last logoff' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.32 NAME 'sambaKickoffTime' DESC 'Timestamp of when the user will be logged off automatically' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.48 NAME 'sambaBadPasswordCount' DESC 'Bad password attempt count' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.49 NAME 'sambaBadPasswordTime' DESC 'Time of the last bad password attempt' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.55 NAME 'sambaLogonHours' DESC 'Logon Hours' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+##
+## String settings
+##
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.33 NAME 'sambaHomeDrive' DESC 'Driver letter of home directory mapping' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{4} SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.34 NAME 'sambaLogonScript' DESC 'Logon script path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.35 NAME 'sambaProfilePath' DESC 'Roaming profile path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.36 NAME 'sambaUserWorkstations' DESC 'List of user workstations the user is allowed to logon to' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.37 NAME 'sambaHomePath' DESC 'Home directory UNC path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.38 NAME 'sambaDomainName' DESC 'Windows NT domain to which the user belongs' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.47 NAME 'sambaMungedDial' DESC 'Base64 encoded user parameter string' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.54 NAME 'sambaPasswordHistory' DESC 'Concatenated MD5 hashes of the salted NT passwords used on this account' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{1024} )
+
+##
+## SID, of any type
+##
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.20 NAME 'sambaSID' DESC 'Security ID' EQUALITY caseIgnoreIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
+
+##
+## Primary group SID, compatible with ntSid
+##
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.23 NAME 'sambaPrimaryGroupSID' DESC 'Primary Group Security ID' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.51 NAME 'sambaSIDList' DESC 'Security ID List' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} )
+
+##
+## group mapping attributes
+##
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.19 NAME 'sambaGroupType' DESC 'NT Group Type' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+##
+## Store info on domain
+##
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.21 NAME 'sambaNextUserRid' DESC 'Next NT rid to give our for users' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.22 NAME 'sambaNextGroupRid' DESC 'Next NT rid to give out for groups' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.39 NAME 'sambaNextRid' DESC 'Next NT rid to give out for anything' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.40 NAME 'sambaAlgorithmicRidBase' DESC 'Base at which the samba RID generation algorithm should operate' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.41 NAME 'sambaShareName' DESC 'Share Name' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.42 NAME 'sambaOptionName' DESC 'Option Name' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.43 NAME 'sambaBoolOption' DESC 'A boolean option' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.44 NAME 'sambaIntegerOption' DESC 'An integer option' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.45 NAME 'sambaStringOption' DESC 'A string option' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.46 NAME 'sambaStringListOption' DESC 'A string list option' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+##
+## unused
+##
+## dn: cn=schema
+## changetype: modify
+## add: attributetypes
+## attributeTypes: ( 1.3.6.1.4.1.7165.2.1.50 NAME 'sambaPrivName' SUP name )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.52 NAME 'sambaPrivilegeList' DESC 'Privileges List' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.53 NAME 'sambaTrustFlags' DESC 'Trust Password Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.58 NAME 'sambaMinPwdLength' DESC 'Minimal password length (default: 5)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.59 NAME 'sambaPwdHistoryLength' DESC 'Length of Password History Entries (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.60 NAME 'sambaLogonToChgPwd' DESC 'Force Users to logon for password change (default: 0 => off, 2 => on)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.61 NAME 'sambaMaxPwdAge' DESC 'Maximum password age, in seconds (default: -1 => never expire passwords)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.62 NAME 'sambaMinPwdAge' DESC 'Minimum password age, in seconds (default: 0 => allow immediate password change)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.63 NAME 'sambaLockoutDuration' DESC 'Lockout duration in minutes (default: 30, -1 => forever)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.64 NAME 'sambaLockoutObservationWindow' DESC 'Reset time after lockout in minutes (default: 30)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.65 NAME 'sambaLockoutThreshold' DESC 'Lockout users after bad logon attempts (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.66 NAME 'sambaForceLogoff' DESC 'Disconnect Users outside logon hours (default: -1 => off, 0 => on)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.67 NAME 'sambaRefuseMachinePwdChange' DESC 'Allow Machine Password changes (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.68 NAME 'sambaClearTextPassword' DESC 'Clear text password (used for trusted domain passwords)' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.69 NAME 'sambaPreviousClearTextPassword' DESC 'Previous clear text password (used for trusted domain passwords)' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.70 NAME 'sambaTrustType' DESC 'Type of trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.71 NAME 'sambaTrustAttributes' DESC 'Trust attributes for a trusted domain' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.72 NAME 'sambaTrustDirection' DESC 'Direction of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.73 NAME 'sambaTrustPartner' DESC 'Fully qualified name of the domain with which a trust exists' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.74 NAME 'sambaFlatName' DESC 'NetBIOS name of a domain' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.75 NAME 'sambaTrustAuthOutgoing' DESC 'Authentication information for the outgoing portion of a trust' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.76 NAME 'sambaTrustAuthIncoming' DESC 'Authentication information for the incoming portion of a trust' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.77 NAME 'sambaSecurityIdentifier' DESC 'SID of a trusted domain' EQUALITY caseIgnoreIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.78 NAME 'sambaTrustForestTrustInfo' DESC 'Forest trust information for a trusted domain object' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.79 NAME 'sambaTrustPosixOffset' DESC 'POSIX offset of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+dn: cn=schema
+changetype: modify
+add: attributetypes
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.80 NAME 'sambaSupportedEncryptionTypes' DESC 'Supported encryption types of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+#######################################################################
+## objectClasses used by Samba 3.0 schema ##
+#######################################################################
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.6 NAME 'sambaSamAccount' DESC 'Samba 3.0 Auxilary SAM Account' SUP top AUXILIARY MUST ( uid $ sambaSID ) MAY ( cn $ sambaLMPassword $ sambaNTPassword $ sambaPwdLastSet $ sambaLogonTime $ sambaLogoffTime $ sambaKickoffTime $ sambaPwdCanChange $ sambaPwdMustChange $ sambaAcctFlags $ displayName $ sambaHomePath $ sambaHomeDrive $ sambaLogonScript $ sambaProfilePath $ description $ sambaUserWorkstations $ sambaPrimaryGroupSID $ sambaDomainName $ sambaMungedDial $ sambaBadPasswordCount $ sambaBadPasswordTime $ sambaPasswordHistory $ sambaLogonHours))
+
+##
+## Group mapping info
+##
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.4 NAME 'sambaGroupMapping' DESC 'Samba Group Mapping' SUP top AUXILIARY MUST ( gidNumber $ sambaSID $ sambaGroupType ) MAY ( displayName $ description $ sambaSIDList))
+
+##
+## Trust password for trust relationships (any kind)
+##
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.14 NAME 'sambaTrustPassword' DESC 'Samba Trust Password' SUP top STRUCTURAL MUST ( sambaDomainName $ sambaNTPassword $ sambaTrustFlags ) MAY ( sambaSID $ sambaPwdLastSet ))
+
+##
+## Trust password for trusted domains
+## (to be stored beneath the trusting sambaDomain object in the DIT)
+##
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.15 NAME 'sambaTrustedDomainPassword' SUP top STRUCTURAL DESC 'Samba Trusted Domain Password' MUST ( sambaDomainName $ sambaSID $ sambaClearTextPassword $ sambaPwdLastSet ) MAY ( sambaPreviousClearTextPassword ))
+
+##
+## Whole-of-domain info
+##
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.5 NAME 'sambaDomain' DESC 'Samba Domain Information' SUP top STRUCTURAL MUST ( sambaDomainName $ sambaSID ) MAY ( sambaNextRid $ sambaNextGroupRid $ sambaNextUserRid $ sambaAlgorithmicRidBase $ sambaMinPwdLength $ sambaPwdHistoryLength $ sambaLogonToChgPwd $ sambaMaxPwdAge $ sambaMinPwdAge $ sambaLockoutDuration $ sambaLockoutObservationWindow $ sambaLockoutThreshold $ sambaForceLogoff $ sambaRefuseMachinePwdChange ))
+
+##
+## used for idmap_ldap module
+##
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( 1.3.6.1.4.1.7165.1.2.2.7 NAME 'sambaUnixIdPool' DESC 'Pool for allocating UNIX uids/gids' SUP top AUXILIARY MUST ( uidNumber $ gidNumber ))
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( 1.3.6.1.4.1.7165.1.2.2.8 NAME 'sambaIdmapEntry' DESC 'Mapping from a SID to an ID' SUP top AUXILIARY MUST ( sambaSID ) MAY ( uidNumber $ gidNumber ))
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( 1.3.6.1.4.1.7165.1.2.2.9 NAME 'sambaSidEntry' DESC 'Structural Class for a SID' SUP top STRUCTURAL MUST ( sambaSID ))
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( 1.3.6.1.4.1.7165.1.2.2.10 NAME 'sambaConfig' DESC 'Samba Configuration Section' SUP top AUXILIARY MAY ( description ))
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.11 NAME 'sambaShare' DESC 'Samba Share Section' SUP top STRUCTURAL MUST ( sambaShareName ) MAY ( description ))
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.12 NAME 'sambaConfigOption' DESC 'Samba Configuration Option' SUP top STRUCTURAL MUST ( sambaOptionName ) MAY ( sambaBoolOption $ sambaIntegerOption $ sambaStringOption $ sambaStringListoption $ description ))
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.13 NAME 'sambaPrivilege' DESC 'Samba Privilege' SUP top AUXILIARY MUST ( sambaSID ) MAY ( sambaPrivilegeList ))
+
+dn: cn=schema
+changetype: modify
+add: objectClasses
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.16 NAME 'sambaTrustedDomain' SUP top STRUCTURAL DESC 'Samba Trusted Domain Object' MUST ( cn ) MAY ( sambaTrustType $ sambaTrustAttributes $ sambaTrustDirection $ sambaTrustPartner $ sambaFlatName $ sambaTrustAuthOutgoing $ sambaTrustAuthIncoming $ sambaSecurityIdentifier $ sambaTrustForestTrustInfo $ sambaTrustPosixOffset $ sambaSupportedEncryptionTypes ) )
diff --git a/examples/LDAP/samba-schema-FDS.ldif b/examples/LDAP/samba-schema-FDS.ldif
new file mode 100644
index 0000000..fdfdab6
--- /dev/null
+++ b/examples/LDAP/samba-schema-FDS.ldif
@@ -0,0 +1,190 @@
+## schema file for Fedora/RedHat Directory Server
+##
+## NOTE: this file can be copied as 60samba.ldif into your instance schema
+## directory:
+## cp samba-schema-FDS.ldif /etc/dirsrv/slapd-<instance-name>/schema/60schema.ldif
+##
+## Schema for storing Samba user accounts and group maps in LDAP
+## OIDs are owned by the Samba Team
+##
+## Prerequisite schemas - uid (cosine.schema)
+## - displayName (inetorgperson.schema)
+## - gidNumber (nis.schema)
+##
+## 1.3.6.1.4.1.7165.2.1.x - attributeTypess
+## 1.3.6.1.4.1.7165.2.2.x - objectClasseses
+##
+## Printer support
+## 1.3.6.1.4.1.7165.2.3.1.x - attributeTypess
+## 1.3.6.1.4.1.7165.2.3.2.x - objectClasseses
+##
+## Samba4
+## 1.3.6.1.4.1.7165.4.1.x - attributeTypess
+## 1.3.6.1.4.1.7165.4.2.x - objectClasseses
+## 1.3.6.1.4.1.7165.4.3.x - LDB/LDAP Controls
+## 1.3.6.1.4.1.7165.4.4.x - LDB/LDAP Extended Operations
+## 1.3.6.1.4.1.7165.4.255.x - mapped OIDs due to conflicts between AD and standards-track
+##
+dn: cn=schema
+##
+#######################################################################
+## Attributes used by Samba 3.0 schema ##
+#######################################################################
+##
+## Password hashes##
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.24 NAME 'sambaLMPassword' DESC 'LanManager Password' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.25 NAME 'sambaNTPassword' DESC 'MD4 hash of the unicode password' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )
+##
+## Account flags in string format ([UWDX ])
+##
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.26 NAME 'sambaAcctFlags' DESC 'Account Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} SINGLE-VALUE )
+##
+## Password timestamps & policies
+##
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.27 NAME 'sambaPwdLastSet' DESC 'Timestamp of the last password update' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.28 NAME 'sambaPwdCanChange' DESC 'Timestamp of when the user is allowed to update the password' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.29 NAME 'sambaPwdMustChange' DESC 'Timestamp of when the password will expire' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.30 NAME 'sambaLogonTime' DESC 'Timestamp of last logon' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.31 NAME 'sambaLogoffTime' DESC 'Timestamp of last logoff' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.32 NAME 'sambaKickoffTime' DESC 'Timestamp of when the user will be logged off automatically' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.48 NAME 'sambaBadPasswordCount' DESC 'Bad password attempt count' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.49 NAME 'sambaBadPasswordTime' DESC 'Time of the last bad password attempt' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.55 NAME 'sambaLogonHours' DESC 'Logon Hours' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{42} SINGLE-VALUE )
+##
+## string settings
+##
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.33 NAME 'sambaHomeDrive' DESC 'Driver letter of home directory mapping' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{4} SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.34 NAME 'sambaLogonScript' DESC 'Logon script path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.35 NAME 'sambaProfilePath' DESC 'Roaming profile path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.36 NAME 'sambaUserWorkstations' DESC 'List of user workstations the user is allowed to logon to' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.37 NAME 'sambaHomePath' DESC 'Home directory UNC path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.38 NAME 'sambaDomainName' DESC 'Windows NT domain to which the user belongs' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.47 NAME 'sambaMungedDial' DESC 'Base64 encoded user parameter string' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.54 NAME 'sambaPasswordHistory' DESC 'Concatenated MD5 hashes of the salted NT passwords used on this account' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} )
+##
+## SID, of any type
+##
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.20 NAME 'sambaSID' DESC 'Security ID' EQUALITY caseIgnoreIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
+##
+## Primary group SID, compatible with ntSid
+##
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.23 NAME 'sambaPrimaryGroupSID' DESC 'Primary Group Security ID' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.51 NAME 'sambaSIDList' DESC 'Security ID List' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} )
+##
+## group mapping attributes
+##
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.19 NAME 'sambaGroupType' DESC 'NT Group Type' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+##
+## Store info on the domain
+##
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.21 NAME 'sambaNextUserRid' DESC 'Next NT rid to give our for users' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.22 NAME 'sambaNextGroupRid' DESC 'Next NT rid to give out for groups' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.39 NAME 'sambaNextRid' DESC 'Next NT rid to give out for anything' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.40 NAME 'sambaAlgorithmicRidBase' DESC 'Base at which the samba RID generation algorithm should operate' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.41 NAME 'sambaShareName' DESC 'Share Name' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.42 NAME 'sambaOptionName' DESC 'Option Name' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.43 NAME 'sambaBoolOption' DESC 'A boolean option' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.44 NAME 'sambaIntegerOption' DESC 'An integer option' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.45 NAME 'sambaStringOption' DESC 'A string option' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.46 NAME 'sambaStringListOption' DESC 'A string list option' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+##attributeTypes: ( 1.3.6.1.4.1.7165.2.1.50 NAME 'sambaPrivName'
+## SUP name )
+##
+##attributeTypes: ( 1.3.6.1.4.1.7165.2.1.52 NAME 'sambaPrivilegeList'
+## DESC 'Privileges List'
+## EQUALITY caseIgnoreIA5Match
+## SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} )
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.53 NAME 'sambaTrustFlags' DESC 'Trust Password Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+# "min password length"
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.58 NAME 'sambaMinPwdLength' DESC 'Minimal password length (default: 5)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+# "password history"
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.59 NAME 'sambaPwdHistoryLength' DESC 'Length of Password History Entries (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+# "user must logon to change password"
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.60 NAME 'sambaLogonToChgPwd' DESC 'Force Users to logon for password change (default: 0 => off, 2 => on)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+# "maximum password age"
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.61 NAME 'sambaMaxPwdAge' DESC 'Maximum password age, in seconds (default: -1 => never expire passwords)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+# "minimum password age"
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.62 NAME 'sambaMinPwdAge' DESC 'Minimum password age, in seconds (default: 0 => allow immediate password change)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+# "lockout duration"
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.63 NAME 'sambaLockoutDuration' DESC 'Lockout duration in minutes (default: 30, -1 => forever)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+# "reset count minutes"
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.64 NAME 'sambaLockoutObservationWindow' DESC 'Reset time after lockout in minutes (default: 30)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+# "bad lockout attempt"
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.65 NAME 'sambaLockoutThreshold' DESC 'Lockout users after bad logon attempts (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+# "disconnect time"
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.66 NAME 'sambaForceLogoff' DESC 'Disconnect Users outside logon hours (default: -1 => off, 0 => on)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+# "refuse machine password change"
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.67 NAME 'sambaRefuseMachinePwdChange' DESC 'Allow Machine Password changes (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+#
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.68 NAME 'sambaClearTextPassword' DESC 'Clear text password (used for trusted domain passwords)' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
+#
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.69 NAME 'sambaPreviousClearTextPassword' DESC 'Previous clear text password (used for trusted domain passwords)' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
+#
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.70 NAME 'sambaTrustType' DESC 'Type of trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+#
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.71 NAME 'sambaTrustAttributes' DESC 'Trust attributes for a trusted domain' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+#
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.72 NAME 'sambaTrustDirection' DESC 'Direction of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+#
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.73 NAME 'sambaTrustPartner' DESC 'Fully qualified name of the domain with which a trust exists' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+#
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.74 NAME 'sambaFlatName' DESC 'NetBIOS name of a domain' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+#
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.75 NAME 'sambaTrustAuthOutgoing' DESC 'Authentication information for the outgoing portion of a trust' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
+#
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.76 NAME 'sambaTrustAuthIncoming' DESC 'Authentication information for the incoming portion of a trust' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
+#
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.77 NAME 'sambaSecurityIdentifier' DESC 'SID of a trusted domain' EQUALITY caseIgnoreIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
+#
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.78 NAME 'sambaTrustForestTrustInfo' DESC 'Forest trust information for a trusted domain object' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
+#
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.79 NAME 'sambaTrustPosixOffset' DESC 'POSIX offset of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+#
+attributeTypes: ( 1.3.6.1.4.1.7165.2.1.80 NAME 'sambaSupportedEncryptionTypes' DESC 'Supported encryption types of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+##
+#######################################################################
+## objectClasses: used by Samba 3.0 schema ##
+#######################################################################
+##
+## The X.500 data model (and therefore LDAPv3) says that each entry can
+## only have one structural objectClasses. OpenLDAP 2.0 does not enforce
+## this currently but will in v2.1
+##
+## added new objectClasses: (and OID) for 3.0 to help us deal with backwards
+## compatibility with 2.2 installations (e.g. ldapsam_compat) --jerry
+##
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.6 NAME 'sambaSamAccount' SUP top AUXILIARY DESC 'Samba 3.0 Auxilary SAM Account' MUST ( uid $ sambaSID ) MAY ( cn $ sambaLMPassword $ sambaNTPassword $ sambaPwdLastSet $ sambaLogonTime $ sambaLogoffTime $ sambaKickoffTime $ sambaPwdCanChange $ sambaPwdMustChange $ sambaAcctFlags $ displayName $ sambaHomePath $ sambaHomeDrive $ sambaLogonScript $ sambaProfilePath $ description $ sambaUserWorkstations $ sambaPrimaryGroupSID $ sambaDomainName $ sambaMungedDial $ sambaBadPasswordCount $ sambaBadPasswordTime $ sambaPasswordHistory $ sambaLogonHours))
+##
+## Group mapping info
+##
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.4 NAME 'sambaGroupMapping' SUP top AUXILIARY DESC 'Samba Group Mapping' MUST ( gidNumber $ sambaSID $ sambaGroupType ) MAY ( displayName $ description $ sambaSIDList ))
+##
+## Trust password for trust relationships (any kind)
+##
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.14 NAME 'sambaTrustPassword' SUP top STRUCTURAL DESC 'Samba Trust Password' MUST ( sambaDomainName $ sambaNTPassword $ sambaTrustFlags ) MAY ( sambaSID $ sambaPwdLastSet ))
+##
+## Whole-of-domain info
+##
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.5 NAME 'sambaDomain' SUP top STRUCTURAL DESC 'Samba Domain Information' MUST ( sambaDomainName $ sambaSID ) MAY ( sambaNextRid $ sambaNextGroupRid $ sambaNextUserRid $ sambaAlgorithmicRidBase $ sambaMinPwdLength $ sambaPwdHistoryLength $ sambaLogonToChgPwd $ sambaMaxPwdAge $ sambaMinPwdAge $ sambaLockoutDuration $ sambaLockoutObservationWindow $ sambaLockoutThreshold $ sambaForceLogoff $ sambaRefuseMachinePwdChange ))
+##
+## used for idmap_ldap module
+##
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.7 NAME 'sambaUnixIdPool' SUP top AUXILIARY DESC 'Pool for allocating UNIX uids/gids' MUST ( uidNumber $ gidNumber ) )
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.8 NAME 'sambaIdmapEntry' SUP top AUXILIARY DESC 'Mapping from a SID to an ID' MUST ( sambaSID ) MAY ( uidNumber $ gidNumber ) )
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.9 NAME 'sambaSidEntry' SUP top STRUCTURAL DESC 'Structural Class for a SID' MUST ( sambaSID ) )
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.10 NAME 'sambaConfig' SUP top AUXILIARY DESC 'Samba Configuration Section' MAY ( description ) )
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.11 NAME 'sambaShare' SUP top STRUCTURAL DESC 'Samba Share Section' MUST ( sambaShareName ) MAY ( description ) )
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.12 NAME 'sambaConfigOption' SUP top STRUCTURAL DESC 'Samba Configuration Option' MUST ( sambaOptionName ) MAY ( sambaBoolOption $ sambaIntegerOption $ sambaStringOption $ sambaStringListoption $ description ) )
+## retired during privilege rewrite
+##objectClasses: ( 1.3.6.1.4.1.7165.2.2.13 NAME 'sambaPrivilege' SUP top AUXILIARY
+## DESC 'Samba Privilege'
+## MUST ( sambaSID )
+## MAY ( sambaPrivilegeList ) )
+##
+## Trusted Domain Relationships
+##
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.15 NAME 'sambaTrustedDomainPassword' SUP top STRUCTURAL DESC 'Samba Trusted Domain Password' MUST ( sambaDomainName $ sambaSID $ sambaClearTextPassword $ sambaPwdLastSet ) MAY ( sambaPreviousClearTextPassword ) )
+##
+## used for IPA_ldapsam
+##
+objectClasses: ( 1.3.6.1.4.1.7165.2.2.16 NAME 'sambaTrustedDomain' SUP top STRUCTURAL DESC 'Samba Trusted Domain Object' MUST ( cn ) MAY ( sambaTrustType $ sambaTrustAttributes $ sambaTrustDirection $ sambaTrustPartner $ sambaFlatName $ sambaTrustAuthOutgoing $ sambaTrustAuthIncoming $ sambaSecurityIdentifier $ sambaTrustForestTrustInfo $ sambaTrustPosixOffset $ sambaSupportedEncryptionTypes) )
diff --git a/examples/LDAP/samba-schema-netscapeds5.x.README b/examples/LDAP/samba-schema-netscapeds5.x.README
new file mode 100644
index 0000000..78c9073
--- /dev/null
+++ b/examples/LDAP/samba-schema-netscapeds5.x.README
@@ -0,0 +1,2 @@
+The LDAP schema file for the Netscape DS 5 has been outdated since years.
+Please use the LDIF based FDS schema file instead.
diff --git a/examples/LDAP/samba-schema.IBMSecureWay b/examples/LDAP/samba-schema.IBMSecureWay
new file mode 100644
index 0000000..c45a334
--- /dev/null
+++ b/examples/LDAP/samba-schema.IBMSecureWay
@@ -0,0 +1,43 @@
+##
+## Submitted by Dirk Kastens <Dirk.Kastens@Uni-Osnabrueck.de>
+##
+## I translated the samba.schema to be used with IBM
+## SecureWay directory server 3.2.2. You have to load
+## it in your slapd32.conf with:
+##
+## dn: cn=IBM SecureWay, cn=Schemas, cn=Configuration
+## cn: IBM SecureWay
+## ibm-slapdIncludeSchema: /etc/lapschema/samba.schema
+##
+objectClasses {
+( 1.3.1.5.1.4.1.7165.2.2.2 NAME 'sambaAccount' DESC 'Samba Account' SUP top MUST uid $ rid MAY ( acctFlags $ cn $ description $ displayName $ homeDrive $ kickoffTime $ lmPassword $ logoffTime $ logonTime $ ntPassword $ primaryGroupID $ profilePath $ pwdCanChange $ pwdLastSet $ pwdMustChange $ scriptPath $ smbHome $ userWorkstations ) )
+}
+
+attributeTypes {
+( 1.3.6.1.4.1.7165.2.1.1 NAME 'lmPassword' DESC 'LanManager Passwd' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )
+( 1.3.6.1.4.1.7165.2.1.10 NAME 'homeDrive' DESC 'NT homeDrive' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{4} SINGLE-VALUE )
+( 1.3.6.1.4.1.7165.2.1.11 NAME 'scriptPath' DESC 'NT scriptPath' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} SINGLE-VALUE )
+( 1.3.6.1.4.1.7165.2.1.12 NAME 'profilePath' DESC 'NT profilePath' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} SINGLE-VALUE )
+( 1.3.6.1.4.1.7165.2.1.13 NAME 'userWorkstations' DESC 'userWorkstations' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} SINGLE-VALUE )
+( 1.3.6.1.4.1.7165.2.1.14 NAME 'rid' DESC 'NT rid' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} SINGLE-VALUE )
+( 1.3.6.1.4.1.7165.2.1.15 NAME 'primaryGroupID' DESC 'NT Group RID' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} SINGLE-VALUE )
+( 1.3.6.1.4.1.7165.2.1.17 NAME 'smbHome' DESC 'smbHome' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )
+( 1.3.6.1.4.1.7165.2.1.2 NAME 'ntPassword' DESC 'NT Passwd' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )
+( 1.3.6.1.4.1.7165.2.1.3 NAME 'pwdLastSet' DESC 'NT pwdLastSet' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )
+( 1.3.6.1.4.1.7165.2.1.4 NAME 'acctFlags' DESC 'Account Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} SINGLE-VALUE )
+( 1.3.6.1.4.1.7165.2.1.5 NAME 'logonTime' DESC 'NT logonTime' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )
+( 1.3.6.1.4.1.7165.2.1.6 NAME 'logoffTime' DESC 'NT logoffTime' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )
+( 1.3.6.1.4.1.7165.2.1.7 NAME 'kickoffTime' DESC 'NT kickoffTime' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )
+( 1.3.6.1.4.1.7165.2.1.8 NAME 'pwdCanChange' DESC 'NT pwdCanChange' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )
+( 1.3.6.1.4.1.7165.2.1.9 NAME 'pwdMustChange' DESC 'NT pwdMustChange' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )
+}
+
+IBMattributeTypes {
+}
+
+ldapSyntaxes {
+}
+
+matchingRules {
+}
+
diff --git a/examples/LDAP/samba.ldif b/examples/LDAP/samba.ldif
new file mode 100644
index 0000000..5106e5f
--- /dev/null
+++ b/examples/LDAP/samba.ldif
@@ -0,0 +1,224 @@
+dn: cn=samba,cn=schema,cn=config
+objectClass: olcSchemaConfig
+cn: samba
+olcAttributeTypes: {0}( 1.3.6.1.4.1.7165.2.1.24 NAME 'sambaLMPassword' DESC 'L
+ anManager Password' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.1
+ 21.1.26{32} SINGLE-VALUE )
+olcAttributeTypes: {1}( 1.3.6.1.4.1.7165.2.1.25 NAME 'sambaNTPassword' DESC 'M
+ D4 hash of the unicode password' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4
+ .1.1466.115.121.1.26{32} SINGLE-VALUE )
+olcAttributeTypes: {2}( 1.3.6.1.4.1.7165.2.1.26 NAME 'sambaAcctFlags' DESC 'Ac
+ count Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ {16} SINGLE-VALUE )
+olcAttributeTypes: {3}( 1.3.6.1.4.1.7165.2.1.27 NAME 'sambaPwdLastSet' DESC 'T
+ imestamp of the last password update' EQUALITY integerMatch SYNTAX 1.3.6.1.4.
+ 1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {4}( 1.3.6.1.4.1.7165.2.1.28 NAME 'sambaPwdCanChange' DESC
+ 'Timestamp of when the user is allowed to update the password' EQUALITY integ
+ erMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {5}( 1.3.6.1.4.1.7165.2.1.29 NAME 'sambaPwdMustChange' DESC
+ 'Timestamp of when the password will expire' EQUALITY integerMatch SYNTAX 1.
+ 3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {6}( 1.3.6.1.4.1.7165.2.1.30 NAME 'sambaLogonTime' DESC 'Ti
+ mestamp of last logon' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.
+ 1.27 SINGLE-VALUE )
+olcAttributeTypes: {7}( 1.3.6.1.4.1.7165.2.1.31 NAME 'sambaLogoffTime' DESC 'T
+ imestamp of last logoff' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.12
+ 1.1.27 SINGLE-VALUE )
+olcAttributeTypes: {8}( 1.3.6.1.4.1.7165.2.1.32 NAME 'sambaKickoffTime' DESC '
+ Timestamp of when the user will be logged off automatically' EQUALITY integer
+ Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {9}( 1.3.6.1.4.1.7165.2.1.48 NAME 'sambaBadPasswordCount' D
+ ESC 'Bad password attempt count' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.146
+ 6.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {10}( 1.3.6.1.4.1.7165.2.1.49 NAME 'sambaBadPasswordTime' D
+ ESC 'Time of the last bad password attempt' EQUALITY integerMatch SYNTAX 1.3.
+ 6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {11}( 1.3.6.1.4.1.7165.2.1.55 NAME 'sambaLogonHours' DESC '
+ Logon Hours' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+ {42} SINGLE-VALUE )
+olcAttributeTypes: {12}( 1.3.6.1.4.1.7165.2.1.33 NAME 'sambaHomeDrive' DESC 'D
+ river letter of home directory mapping' EQUALITY caseIgnoreIA5Match SYNTAX 1.
+ 3.6.1.4.1.1466.115.121.1.26{4} SINGLE-VALUE )
+olcAttributeTypes: {13}( 1.3.6.1.4.1.7165.2.1.34 NAME 'sambaLogonScript' DESC
+ 'Logon script path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.
+ 1.15{255} SINGLE-VALUE )
+olcAttributeTypes: {14}( 1.3.6.1.4.1.7165.2.1.35 NAME 'sambaProfilePath' DESC
+ 'Roaming profile path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.1
+ 21.1.15{255} SINGLE-VALUE )
+olcAttributeTypes: {15}( 1.3.6.1.4.1.7165.2.1.36 NAME 'sambaUserWorkstations'
+ DESC 'List of user workstations the user is allowed to logon to' EQUALITY cas
+ eIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE )
+olcAttributeTypes: {16}( 1.3.6.1.4.1.7165.2.1.37 NAME 'sambaHomePath' DESC 'Ho
+ me directory UNC path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.1
+ 21.1.15{128} )
+olcAttributeTypes: {17}( 1.3.6.1.4.1.7165.2.1.38 NAME 'sambaDomainName' DESC '
+ Windows NT domain to which the user belongs' EQUALITY caseIgnoreMatch SYNTAX
+ 1.3.6.1.4.1.1466.115.121.1.15{128} )
+olcAttributeTypes: {18}( 1.3.6.1.4.1.7165.2.1.47 NAME 'sambaMungedDial' DESC '
+ Base64 encoded user parameter string' EQUALITY caseExactMatch SYNTAX 1.3.6.1.
+ 4.1.1466.115.121.1.15{1050} )
+olcAttributeTypes: {19}( 1.3.6.1.4.1.7165.2.1.54 NAME 'sambaPasswordHistory' D
+ ESC 'Concatenated MD5 hashes of the salted NT passwords used on this account'
+ EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} )
+olcAttributeTypes: {20}( 1.3.6.1.4.1.7165.2.1.20 NAME 'sambaSID' DESC 'Securit
+ y ID' EQUALITY caseIgnoreIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1
+ .3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
+olcAttributeTypes: {21}( 1.3.6.1.4.1.7165.2.1.23 NAME 'sambaPrimaryGroupSID' D
+ ESC 'Primary Group Security ID' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.
+ 1.1466.115.121.1.26{64} SINGLE-VALUE )
+olcAttributeTypes: {22}( 1.3.6.1.4.1.7165.2.1.51 NAME 'sambaSIDList' DESC 'Sec
+ urity ID List' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.
+ 26{64} )
+olcAttributeTypes: {23}( 1.3.6.1.4.1.7165.2.1.19 NAME 'sambaGroupType' DESC 'N
+ T Group Type' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SING
+ LE-VALUE )
+olcAttributeTypes: {24}( 1.3.6.1.4.1.7165.2.1.21 NAME 'sambaNextUserRid' DESC
+ 'Next NT rid to give our for users' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.
+ 1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {25}( 1.3.6.1.4.1.7165.2.1.22 NAME 'sambaNextGroupRid' DESC
+ 'Next NT rid to give out for groups' EQUALITY integerMatch SYNTAX 1.3.6.1.4.
+ 1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {26}( 1.3.6.1.4.1.7165.2.1.39 NAME 'sambaNextRid' DESC 'Nex
+ t NT rid to give out for anything' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1
+ 466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {27}( 1.3.6.1.4.1.7165.2.1.40 NAME 'sambaAlgorithmicRidBase
+ ' DESC 'Base at which the samba RID generation algorithm should operate' EQUA
+ LITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {28}( 1.3.6.1.4.1.7165.2.1.41 NAME 'sambaShareName' DESC 'S
+ hare Name' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SING
+ LE-VALUE )
+olcAttributeTypes: {29}( 1.3.6.1.4.1.7165.2.1.42 NAME 'sambaOptionName' DESC '
+ Option Name' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX
+ 1.3.6.1.4.1.1466.115.121.1.15{256} )
+olcAttributeTypes: {30}( 1.3.6.1.4.1.7165.2.1.43 NAME 'sambaBoolOption' DESC '
+ A boolean option' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 S
+ INGLE-VALUE )
+olcAttributeTypes: {31}( 1.3.6.1.4.1.7165.2.1.44 NAME 'sambaIntegerOption' DES
+ C 'An integer option' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1
+ .27 SINGLE-VALUE )
+olcAttributeTypes: {32}( 1.3.6.1.4.1.7165.2.1.45 NAME 'sambaStringOption' DESC
+ 'A string option' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121
+ .1.26 SINGLE-VALUE )
+olcAttributeTypes: {33}( 1.3.6.1.4.1.7165.2.1.46 NAME 'sambaStringListOption'
+ DESC 'A string list option' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.
+ 115.121.1.15 )
+olcAttributeTypes: {34}( 1.3.6.1.4.1.7165.2.1.53 NAME 'sambaTrustFlags' DESC '
+ Trust Password Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115
+ .121.1.26 )
+olcAttributeTypes: {35}( 1.3.6.1.4.1.7165.2.1.58 NAME 'sambaMinPwdLength' DESC
+ 'Minimal password length (default: 5)' EQUALITY integerMatch SYNTAX 1.3.6.1.
+ 4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {36}( 1.3.6.1.4.1.7165.2.1.59 NAME 'sambaPwdHistoryLength'
+ DESC 'Length of Password History Entries (default: 0 => off)' EQUALITY intege
+ rMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {37}( 1.3.6.1.4.1.7165.2.1.60 NAME 'sambaLogonToChgPwd' DES
+ C 'Force Users to logon for password change (default: 0 => off, 2 => on)' EQU
+ ALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {38}( 1.3.6.1.4.1.7165.2.1.61 NAME 'sambaMaxPwdAge' DESC 'M
+ aximum password age, in seconds (default: -1 => never expire passwords)' EQUA
+ LITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {39}( 1.3.6.1.4.1.7165.2.1.62 NAME 'sambaMinPwdAge' DESC 'M
+ inimum password age, in seconds (default: 0 => allow immediate password chang
+ e)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {40}( 1.3.6.1.4.1.7165.2.1.63 NAME 'sambaLockoutDuration' D
+ ESC 'Lockout duration in minutes (default: 30, -1 => forever)' EQUALITY integ
+ erMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {41}( 1.3.6.1.4.1.7165.2.1.64 NAME 'sambaLockoutObservation
+ Window' DESC 'Reset time after lockout in minutes (default: 30)' EQUALITY int
+ egerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {42}( 1.3.6.1.4.1.7165.2.1.65 NAME 'sambaLockoutThreshold'
+ DESC 'Lockout users after bad logon attempts (default: 0 => off)' EQUALITY in
+ tegerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {43}( 1.3.6.1.4.1.7165.2.1.66 NAME 'sambaForceLogoff' DESC
+ 'Disconnect Users outside logon hours (default: -1 => off, 0 => on)' EQUALITY
+ integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {44}( 1.3.6.1.4.1.7165.2.1.67 NAME 'sambaRefuseMachinePwdCh
+ ange' DESC 'Allow Machine Password changes (default: 0 => off)' EQUALITY inte
+ gerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {45}( 1.3.6.1.4.1.7165.2.1.68 NAME 'sambaClearTextPassword'
+ DESC 'Clear text password (used for trusted domain passwords)' EQUALITY octe
+ tStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
+olcAttributeTypes: {46}( 1.3.6.1.4.1.7165.2.1.69 NAME 'sambaPreviousClearTextP
+ assword' DESC 'Previous clear text password (used for trusted domain password
+ s)' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
+olcAttributeTypes: {47}( 1.3.6.1.4.1.7165.2.1.70 NAME 'sambaTrustType' DESC 'T
+ ype of trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SING
+ LE-VALUE )
+olcAttributeTypes: {48}( 1.3.6.1.4.1.7165.2.1.71 NAME 'sambaTrustAttributes' D
+ ESC 'Trust attributes for a trusted domain' EQUALITY integerMatch SYNTAX 1.3.
+ 6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {49}( 1.3.6.1.4.1.7165.2.1.72 NAME 'sambaTrustDirection' DE
+ SC 'Direction of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.1
+ 21.1.27 SINGLE-VALUE )
+olcAttributeTypes: {50}( 1.3.6.1.4.1.7165.2.1.73 NAME 'sambaTrustPartner' DESC
+ 'Fully qualified name of the domain with which a trust exists' EQUALITY case
+ IgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+olcAttributeTypes: {51}( 1.3.6.1.4.1.7165.2.1.74 NAME 'sambaFlatName' DESC 'Ne
+ tBIOS name of a domain' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.
+ 121.1.15{128} )
+olcAttributeTypes: {52}( 1.3.6.1.4.1.7165.2.1.75 NAME 'sambaTrustAuthOutgoing'
+ DESC 'Authentication information for the outgoing portion of a trust' EQUALIT
+ Y caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
+olcAttributeTypes: {53}( 1.3.6.1.4.1.7165.2.1.76 NAME 'sambaTrustAuthIncoming'
+ DESC 'Authentication information for the incoming portion of a trust' EQUALIT
+ Y caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
+olcAttributeTypes: {54}( 1.3.6.1.4.1.7165.2.1.77 NAME 'sambaSecurityIdentifier
+ ' DESC 'SID of a trusted domain' EQUALITY caseIgnoreIA5Match SUBSTR caseExact
+ IA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
+olcAttributeTypes: {55}( 1.3.6.1.4.1.7165.2.1.78 NAME 'sambaTrustForestTrustIn
+ fo' DESC 'Forest trust information for a trusted domain object' EQUALITY case
+ ExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
+olcAttributeTypes: {56}( 1.3.6.1.4.1.7165.2.1.79 NAME 'sambaTrustPosixOffset'
+ DESC 'POSIX offset of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.
+ 115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {57}( 1.3.6.1.4.1.7165.2.1.80 NAME 'sambaSupportedEncryptio
+ nTypes' DESC 'Supported encryption types of a trust' EQUALITY integerMatch SY
+ NTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcObjectClasses: {0}( 1.3.6.1.4.1.7165.2.2.6 NAME 'sambaSamAccount' DESC 'Sam
+ ba 3.0 Auxilary SAM Account' SUP top AUXILIARY MUST ( uid $ sambaSID ) MAY (
+ cn $ sambaLMPassword $ sambaNTPassword $ sambaPwdLastSet $ sambaLogonTime $ s
+ ambaLogoffTime $ sambaKickoffTime $ sambaPwdCanChange $ sambaPwdMustChange $
+ sambaAcctFlags $ displayName $ sambaHomePath $ sambaHomeDrive $ sambaLogonScr
+ ipt $ sambaProfilePath $ description $ sambaUserWorkstations $ sambaPrimaryGr
+ oupSID $ sambaDomainName $ sambaMungedDial $ sambaBadPasswordCount $ sambaBad
+ PasswordTime $ sambaPasswordHistory $ sambaLogonHours ) )
+olcObjectClasses: {1}( 1.3.6.1.4.1.7165.2.2.4 NAME 'sambaGroupMapping' DESC 'S
+ amba Group Mapping' SUP top AUXILIARY MUST ( gidNumber $ sambaSID $ sambaGrou
+ pType ) MAY ( displayName $ description $ sambaSIDList ) )
+olcObjectClasses: {2}( 1.3.6.1.4.1.7165.2.2.14 NAME 'sambaTrustPassword' DESC
+ 'Samba Trust Password' SUP top STRUCTURAL MUST ( sambaDomainName $ sambaNTPas
+ sword $ sambaTrustFlags ) MAY ( sambaSID $ sambaPwdLastSet ) )
+olcObjectClasses: {3}( 1.3.6.1.4.1.7165.2.2.15 NAME 'sambaTrustedDomainPasswor
+ d' DESC 'Samba Trusted Domain Password' SUP top STRUCTURAL MUST ( sambaDomain
+ Name $ sambaSID $ sambaClearTextPassword $ sambaPwdLastSet ) MAY sambaPreviou
+ sClearTextPassword )
+olcObjectClasses: {4}( 1.3.6.1.4.1.7165.2.2.5 NAME 'sambaDomain' DESC 'Samba D
+ omain Information' SUP top STRUCTURAL MUST ( sambaDomainName $ sambaSID ) MAY
+ ( sambaNextRid $ sambaNextGroupRid $ sambaNextUserRid $ sambaAlgorithmicRidB
+ ase $ sambaMinPwdLength $ sambaPwdHistoryLength $ sambaLogonToChgPwd $ sambaM
+ axPwdAge $ sambaMinPwdAge $ sambaLockoutDuration $ sambaLockoutObservationWin
+ dow $ sambaLockoutThreshold $ sambaForceLogoff $ sambaRefuseMachinePwdChange
+ ) )
+olcObjectClasses: {5}( 1.3.6.1.4.1.7165.2.2.7 NAME 'sambaUnixIdPool' DESC 'Poo
+ l for allocating UNIX uids/gids' SUP top AUXILIARY MUST ( uidNumber $ gidNumb
+ er ) )
+olcObjectClasses: {6}( 1.3.6.1.4.1.7165.2.2.8 NAME 'sambaIdmapEntry' DESC 'Map
+ ping from a SID to an ID' SUP top AUXILIARY MUST sambaSID MAY ( uidNumber $ g
+ idNumber ) )
+olcObjectClasses: {7}( 1.3.6.1.4.1.7165.2.2.9 NAME 'sambaSidEntry' DESC 'Struc
+ tural Class for a SID' SUP top STRUCTURAL MUST sambaSID )
+olcObjectClasses: {8}( 1.3.6.1.4.1.7165.2.2.10 NAME 'sambaConfig' DESC 'Samba
+ Configuration Section' SUP top AUXILIARY MAY description )
+olcObjectClasses: {9}( 1.3.6.1.4.1.7165.2.2.11 NAME 'sambaShare' DESC 'Samba S
+ hare Section' SUP top STRUCTURAL MUST sambaShareName MAY description )
+olcObjectClasses: {10}( 1.3.6.1.4.1.7165.2.2.12 NAME 'sambaConfigOption' DESC
+ 'Samba Configuration Option' SUP top STRUCTURAL MUST sambaOptionName MAY ( sa
+ mbaBoolOption $ sambaIntegerOption $ sambaStringOption $ sambaStringListoptio
+ n $ description ) )
+olcObjectClasses: {11}( 1.3.6.1.4.1.7165.2.2.16 NAME 'sambaTrustedDomain' DESC
+ 'Samba Trusted Domain Object' SUP top STRUCTURAL MUST cn MAY ( sambaTrustTyp
+ e $ sambaTrustAttributes $ sambaTrustDirection $ sambaTrustPartner $ sambaFla
+ tName $ sambaTrustAuthOutgoing $ sambaTrustAuthIncoming $ sambaSecurityIdenti
+ fier $ sambaTrustForestTrustInfo $ sambaTrustPosixOffset $ sambaSupportedEncr
+ yptionTypes) )
diff --git a/examples/LDAP/samba.schema b/examples/LDAP/samba.schema
new file mode 100644
index 0000000..58d7a82
--- /dev/null
+++ b/examples/LDAP/samba.schema
@@ -0,0 +1,649 @@
+##
+## schema file for OpenLDAP 2.x
+## Schema for storing Samba user accounts and group maps in LDAP
+## OIDs are owned by the Samba Team
+##
+## Prerequisite schemas - uid (cosine.schema)
+## - displayName (inetorgperson.schema)
+## - gidNumber (nis.schema)
+##
+## 1.3.6.1.4.1.7165.2.1.x - attributetypes
+## 1.3.6.1.4.1.7165.2.2.x - objectclasses
+##
+## Printer support
+## 1.3.6.1.4.1.7165.2.3.1.x - attributetypes
+## 1.3.6.1.4.1.7165.2.3.2.x - objectclasses
+##
+## Samba4 - see source4/setup/schema_samba4.ldif
+## 1.3.6.1.4.1.7165.4.1.x - attributetypes
+## 1.3.6.1.4.1.7165.4.2.x - objectclasses
+## 1.3.6.1.4.1.7165.4.3.x - LDB/LDAP Controls
+## 1.3.6.1.4.1.7165.4.4.x - LDB/LDAP Extended Operations
+## 1.3.6.1.4.1.7165.4.5.x - ldap extended matches
+## 1.3.6.1.4.1.7165.4.6.1.x - SELFTEST random attributes
+## 1.3.6.1.4.1.7165.4.255.x - mapped OIDs due to conflicts between AD and standards-track
+##
+## Out of tree use allocated in the wiki
+## 1.3.6.1.4.1.7165.777.x - https://wiki.samba.org/index.php/Samba_AD_schema_extensions#OID
+##
+## External projects
+## 1.3.6.1.4.1.7165.655.x
+## 1.3.6.1.4.1.7165.655.1.x - GSS-NTLMSSP
+##
+## ----- READ THIS WHEN ADDING A NEW ATTRIBUTE OR OBJECT CLASS ------
+##
+## Run the 'get_next_oid' bash script in this directory to find the
+## next available OID for attribute type and object classes.
+##
+## $ ./get_next_oid
+## attributetype ( 1.3.6.1.4.1.7165.2.1.XX NAME ....
+## objectclass ( 1.3.6.1.4.1.7165.2.2.XX NAME ....
+##
+## Also ensure that new entries adhere to the declaration style
+## used throughout this file
+##
+## <attributetype|objectclass> ( 1.3.6.1.4.1.7165.2.XX.XX NAME ....
+## ^ ^ ^
+##
+## The spaces are required for the get_next_oid script (and for
+## readability).
+##
+## ------------------------------------------------------------------
+
+# objectIdentifier SambaRoot 1.3.6.1.4.1.7165
+# objectIdentifier Samba3 SambaRoot:2
+# objectIdentifier Samba3Attrib Samba3:1
+# objectIdentifier Samba3ObjectClass Samba3:2
+# objectIdentifier Samba4 SambaRoot:4
+
+########################################################################
+## HISTORICAL ##
+########################################################################
+
+##
+## Password hashes
+##
+#attributetype ( 1.3.6.1.4.1.7165.2.1.1 NAME 'lmPassword'
+# DESC 'LanManager Passwd'
+# EQUALITY caseIgnoreIA5Match
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )
+
+#attributetype ( 1.3.6.1.4.1.7165.2.1.2 NAME 'ntPassword'
+# DESC 'NT Passwd'
+# EQUALITY caseIgnoreIA5Match
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )
+
+##
+## Account flags in string format ([UWDX ])
+##
+#attributetype ( 1.3.6.1.4.1.7165.2.1.4 NAME 'acctFlags'
+# DESC 'Account Flags'
+# EQUALITY caseIgnoreIA5Match
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} SINGLE-VALUE )
+
+##
+## Password timestamps & policies
+##
+#attributetype ( 1.3.6.1.4.1.7165.2.1.3 NAME 'pwdLastSet'
+# DESC 'NT pwdLastSet'
+# EQUALITY integerMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+#attributetype ( 1.3.6.1.4.1.7165.2.1.5 NAME 'logonTime'
+# DESC 'NT logonTime'
+# EQUALITY integerMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+#attributetype ( 1.3.6.1.4.1.7165.2.1.6 NAME 'logoffTime'
+# DESC 'NT logoffTime'
+# EQUALITY integerMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+#attributetype ( 1.3.6.1.4.1.7165.2.1.7 NAME 'kickoffTime'
+# DESC 'NT kickoffTime'
+# EQUALITY integerMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+#attributetype ( 1.3.6.1.4.1.7165.2.1.8 NAME 'pwdCanChange'
+# DESC 'NT pwdCanChange'
+# EQUALITY integerMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+#attributetype ( 1.3.6.1.4.1.7165.2.1.9 NAME 'pwdMustChange'
+# DESC 'NT pwdMustChange'
+# EQUALITY integerMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+##
+## string settings
+##
+#attributetype ( 1.3.6.1.4.1.7165.2.1.10 NAME 'homeDrive'
+# DESC 'NT homeDrive'
+# EQUALITY caseIgnoreIA5Match
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{4} SINGLE-VALUE )
+
+#attributetype ( 1.3.6.1.4.1.7165.2.1.11 NAME 'scriptPath'
+# DESC 'NT scriptPath'
+# EQUALITY caseIgnoreIA5Match
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} SINGLE-VALUE )
+
+#attributetype ( 1.3.6.1.4.1.7165.2.1.12 NAME 'profilePath'
+# DESC 'NT profilePath'
+# EQUALITY caseIgnoreIA5Match
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} SINGLE-VALUE )
+
+#attributetype ( 1.3.6.1.4.1.7165.2.1.13 NAME 'userWorkstations'
+# DESC 'userWorkstations'
+# EQUALITY caseIgnoreIA5Match
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} SINGLE-VALUE )
+
+#attributetype ( 1.3.6.1.4.1.7165.2.1.17 NAME 'smbHome'
+# DESC 'smbHome'
+# EQUALITY caseIgnoreIA5Match
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )
+
+#attributetype ( 1.3.6.1.4.1.7165.2.1.18 NAME 'domain'
+# DESC 'Windows NT domain to which the user belongs'
+# EQUALITY caseIgnoreIA5Match
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{128} )
+
+##
+## user and group RID
+##
+#attributetype ( 1.3.6.1.4.1.7165.2.1.14 NAME 'rid'
+# DESC 'NT rid'
+# EQUALITY integerMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+#attributetype ( 1.3.6.1.4.1.7165.2.1.15 NAME 'primaryGroupID'
+# DESC 'NT Group RID'
+# EQUALITY integerMatch
+# SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+##
+## The smbPasswordEntry objectclass has been depreciated in favor of the
+## sambaAccount objectclass
+##
+#objectclass ( 1.3.6.1.4.1.7165.2.2.1 NAME 'smbPasswordEntry' SUP top AUXILIARY
+# DESC 'Samba smbpasswd entry'
+# MUST ( uid $ uidNumber )
+# MAY ( lmPassword $ ntPassword $ pwdLastSet $ acctFlags ))
+
+#objectclass ( 1.3.6.1.4.1.7165.2.2.2 NAME 'sambaAccount' SUP top STRUCTURAL
+# DESC 'Samba Account'
+# MUST ( uid $ rid )
+# MAY ( cn $ lmPassword $ ntPassword $ pwdLastSet $ logonTime $
+# logoffTime $ kickoffTime $ pwdCanChange $ pwdMustChange $ acctFlags $
+# displayName $ smbHome $ homeDrive $ scriptPath $ profilePath $
+# description $ userWorkstations $ primaryGroupID $ domain ))
+
+#objectclass ( 1.3.6.1.4.1.7165.2.2.3 NAME 'sambaAccount' SUP top AUXILIARY
+# DESC 'Samba Auxiliary Account'
+# MUST ( uid $ rid )
+# MAY ( cn $ lmPassword $ ntPassword $ pwdLastSet $ logonTime $
+# logoffTime $ kickoffTime $ pwdCanChange $ pwdMustChange $ acctFlags $
+# displayName $ smbHome $ homeDrive $ scriptPath $ profilePath $
+# description $ userWorkstations $ primaryGroupID $ domain ))
+
+########################################################################
+## END OF HISTORICAL ##
+########################################################################
+
+#######################################################################
+## Attributes used by Samba 3.0 schema ##
+#######################################################################
+
+##
+## Password hashes
+##
+attributetype ( 1.3.6.1.4.1.7165.2.1.24 NAME 'sambaLMPassword'
+ DESC 'LanManager Password'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.25 NAME 'sambaNTPassword'
+ DESC 'MD4 hash of the unicode password'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )
+
+##
+## Account flags in string format ([UWDX ])
+##
+attributetype ( 1.3.6.1.4.1.7165.2.1.26 NAME 'sambaAcctFlags'
+ DESC 'Account Flags'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} SINGLE-VALUE )
+
+##
+## Password timestamps & policies
+##
+attributetype ( 1.3.6.1.4.1.7165.2.1.27 NAME 'sambaPwdLastSet'
+ DESC 'Timestamp of the last password update'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.28 NAME 'sambaPwdCanChange'
+ DESC 'Timestamp of when the user is allowed to update the password'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.29 NAME 'sambaPwdMustChange'
+ DESC 'Timestamp of when the password will expire'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.30 NAME 'sambaLogonTime'
+ DESC 'Timestamp of last logon'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.31 NAME 'sambaLogoffTime'
+ DESC 'Timestamp of last logoff'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.32 NAME 'sambaKickoffTime'
+ DESC 'Timestamp of when the user will be logged off automatically'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.48 NAME 'sambaBadPasswordCount'
+ DESC 'Bad password attempt count'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.49 NAME 'sambaBadPasswordTime'
+ DESC 'Time of the last bad password attempt'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.55 NAME 'sambaLogonHours'
+ DESC 'Logon Hours'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{42} SINGLE-VALUE )
+
+##
+## string settings
+##
+attributetype ( 1.3.6.1.4.1.7165.2.1.33 NAME 'sambaHomeDrive'
+ DESC 'Driver letter of home directory mapping'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{4} SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.34 NAME 'sambaLogonScript'
+ DESC 'Logon script path'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.35 NAME 'sambaProfilePath'
+ DESC 'Roaming profile path'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.36 NAME 'sambaUserWorkstations'
+ DESC 'List of user workstations the user is allowed to logon to'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.37 NAME 'sambaHomePath'
+ DESC 'Home directory UNC path'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.38 NAME 'sambaDomainName'
+ DESC 'Windows NT domain to which the user belongs'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.47 NAME 'sambaMungedDial'
+ DESC 'Base64 encoded user parameter string'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.54 NAME 'sambaPasswordHistory'
+ DESC 'Concatenated MD5 hashes of the salted NT passwords used on this account'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} )
+
+##
+## SID, of any type
+##
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.20 NAME 'sambaSID'
+ DESC 'Security ID'
+ EQUALITY caseIgnoreIA5Match
+ SUBSTR caseExactIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
+
+##
+## Primary group SID, compatible with ntSid
+##
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.23 NAME 'sambaPrimaryGroupSID'
+ DESC 'Primary Group Security ID'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.51 NAME 'sambaSIDList'
+ DESC 'Security ID List'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} )
+
+##
+## group mapping attributes
+##
+attributetype ( 1.3.6.1.4.1.7165.2.1.19 NAME 'sambaGroupType'
+ DESC 'NT Group Type'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+##
+## Store info on the domain
+##
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.21 NAME 'sambaNextUserRid'
+ DESC 'Next NT rid to give our for users'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.22 NAME 'sambaNextGroupRid'
+ DESC 'Next NT rid to give out for groups'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.39 NAME 'sambaNextRid'
+ DESC 'Next NT rid to give out for anything'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.40 NAME 'sambaAlgorithmicRidBase'
+ DESC 'Base at which the samba RID generation algorithm should operate'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.41 NAME 'sambaShareName'
+ DESC 'Share Name'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.42 NAME 'sambaOptionName'
+ DESC 'Option Name'
+ EQUALITY caseIgnoreMatch
+ SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.43 NAME 'sambaBoolOption'
+ DESC 'A boolean option'
+ EQUALITY booleanMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.44 NAME 'sambaIntegerOption'
+ DESC 'An integer option'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.45 NAME 'sambaStringOption'
+ DESC 'A string option'
+ EQUALITY caseExactIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.46 NAME 'sambaStringListOption'
+ DESC 'A string list option'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+
+##attributetype ( 1.3.6.1.4.1.7165.2.1.50 NAME 'sambaPrivName'
+## SUP name )
+
+##attributetype ( 1.3.6.1.4.1.7165.2.1.52 NAME 'sambaPrivilegeList'
+## DESC 'Privileges List'
+## EQUALITY caseIgnoreIA5Match
+## SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.53 NAME 'sambaTrustFlags'
+ DESC 'Trust Password Flags'
+ EQUALITY caseIgnoreIA5Match
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+# "min password length"
+attributetype ( 1.3.6.1.4.1.7165.2.1.58 NAME 'sambaMinPwdLength'
+ DESC 'Minimal password length (default: 5)'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+# "password history"
+attributetype ( 1.3.6.1.4.1.7165.2.1.59 NAME 'sambaPwdHistoryLength'
+ DESC 'Length of Password History Entries (default: 0 => off)'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+# "user must logon to change password"
+attributetype ( 1.3.6.1.4.1.7165.2.1.60 NAME 'sambaLogonToChgPwd'
+ DESC 'Force Users to logon for password change (default: 0 => off, 2 => on)'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+# "maximum password age"
+attributetype ( 1.3.6.1.4.1.7165.2.1.61 NAME 'sambaMaxPwdAge'
+ DESC 'Maximum password age, in seconds (default: -1 => never expire passwords)'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+# "minimum password age"
+attributetype ( 1.3.6.1.4.1.7165.2.1.62 NAME 'sambaMinPwdAge'
+ DESC 'Minimum password age, in seconds (default: 0 => allow immediate password change)'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+# "lockout duration"
+attributetype ( 1.3.6.1.4.1.7165.2.1.63 NAME 'sambaLockoutDuration'
+ DESC 'Lockout duration in minutes (default: 30, -1 => forever)'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+# "reset count minutes"
+attributetype ( 1.3.6.1.4.1.7165.2.1.64 NAME 'sambaLockoutObservationWindow'
+ DESC 'Reset time after lockout in minutes (default: 30)'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+# "bad lockout attempt"
+attributetype ( 1.3.6.1.4.1.7165.2.1.65 NAME 'sambaLockoutThreshold'
+ DESC 'Lockout users after bad logon attempts (default: 0 => off)'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+# "disconnect time"
+attributetype ( 1.3.6.1.4.1.7165.2.1.66 NAME 'sambaForceLogoff'
+ DESC 'Disconnect Users outside logon hours (default: -1 => off, 0 => on)'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+# "refuse machine password change"
+attributetype ( 1.3.6.1.4.1.7165.2.1.67 NAME 'sambaRefuseMachinePwdChange'
+ DESC 'Allow Machine Password changes (default: 0 => off)'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+#
+attributetype ( 1.3.6.1.4.1.7165.2.1.68 NAME 'sambaClearTextPassword'
+ DESC 'Clear text password (used for trusted domain passwords)'
+ EQUALITY octetStringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
+
+#
+attributetype ( 1.3.6.1.4.1.7165.2.1.69 NAME 'sambaPreviousClearTextPassword'
+ DESC 'Previous clear text password (used for trusted domain passwords)'
+ EQUALITY octetStringMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.70 NAME 'sambaTrustType'
+ DESC 'Type of trust'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.71 NAME 'sambaTrustAttributes'
+ DESC 'Trust attributes for a trusted domain'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.72 NAME 'sambaTrustDirection'
+ DESC 'Direction of a trust'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.73 NAME 'sambaTrustPartner'
+ DESC 'Fully qualified name of the domain with which a trust exists'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.74 NAME 'sambaFlatName'
+ DESC 'NetBIOS name of a domain'
+ EQUALITY caseIgnoreMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.75 NAME 'sambaTrustAuthOutgoing'
+ DESC 'Authentication information for the outgoing portion of a trust'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.76 NAME 'sambaTrustAuthIncoming'
+ DESC 'Authentication information for the incoming portion of a trust'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.77 NAME 'sambaSecurityIdentifier'
+ DESC 'SID of a trusted domain'
+ EQUALITY caseIgnoreIA5Match SUBSTR caseExactIA5SubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.78 NAME 'sambaTrustForestTrustInfo'
+ DESC 'Forest trust information for a trusted domain object'
+ EQUALITY caseExactMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.79 NAME 'sambaTrustPosixOffset'
+ DESC 'POSIX offset of a trust'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetype ( 1.3.6.1.4.1.7165.2.1.80 NAME 'sambaSupportedEncryptionTypes'
+ DESC 'Supported encryption types of a trust'
+ EQUALITY integerMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+#######################################################################
+## objectClasses used by Samba 3.0 schema ##
+#######################################################################
+
+## The X.500 data model (and therefore LDAPv3) says that each entry can
+## only have one structural objectclass. OpenLDAP 2.0 does not enforce
+## this currently but will in v2.1
+
+##
+## added new objectclass (and OID) for 3.0 to help us deal with backwards
+## compatibility with 2.2 installations (e.g. ldapsam_compat) --jerry
+##
+objectclass ( 1.3.6.1.4.1.7165.2.2.6 NAME 'sambaSamAccount' SUP top AUXILIARY
+ DESC 'Samba 3.0 Auxilary SAM Account'
+ MUST ( uid $ sambaSID )
+ MAY ( cn $ sambaLMPassword $ sambaNTPassword $ sambaPwdLastSet $
+ sambaLogonTime $ sambaLogoffTime $ sambaKickoffTime $
+ sambaPwdCanChange $ sambaPwdMustChange $ sambaAcctFlags $
+ displayName $ sambaHomePath $ sambaHomeDrive $ sambaLogonScript $
+ sambaProfilePath $ description $ sambaUserWorkstations $
+ sambaPrimaryGroupSID $ sambaDomainName $ sambaMungedDial $
+ sambaBadPasswordCount $ sambaBadPasswordTime $
+ sambaPasswordHistory $ sambaLogonHours))
+
+##
+## Group mapping info
+##
+objectclass ( 1.3.6.1.4.1.7165.2.2.4 NAME 'sambaGroupMapping' SUP top AUXILIARY
+ DESC 'Samba Group Mapping'
+ MUST ( gidNumber $ sambaSID $ sambaGroupType )
+ MAY ( displayName $ description $ sambaSIDList ))
+
+##
+## Trust password for trust relationships (any kind)
+##
+objectclass ( 1.3.6.1.4.1.7165.2.2.14 NAME 'sambaTrustPassword' SUP top STRUCTURAL
+ DESC 'Samba Trust Password'
+ MUST ( sambaDomainName $ sambaNTPassword $ sambaTrustFlags )
+ MAY ( sambaSID $ sambaPwdLastSet ))
+
+##
+## Trust password for trusted domains
+## (to be stored beneath the trusting sambaDomain object in the DIT)
+##
+objectclass ( 1.3.6.1.4.1.7165.2.2.15 NAME 'sambaTrustedDomainPassword' SUP top STRUCTURAL
+ DESC 'Samba Trusted Domain Password'
+ MUST ( sambaDomainName $ sambaSID $
+ sambaClearTextPassword $ sambaPwdLastSet )
+ MAY ( sambaPreviousClearTextPassword ))
+
+##
+## Whole-of-domain info
+##
+objectclass ( 1.3.6.1.4.1.7165.2.2.5 NAME 'sambaDomain' SUP top STRUCTURAL
+ DESC 'Samba Domain Information'
+ MUST ( sambaDomainName $
+ sambaSID )
+ MAY ( sambaNextRid $ sambaNextGroupRid $ sambaNextUserRid $
+ sambaAlgorithmicRidBase $
+ sambaMinPwdLength $ sambaPwdHistoryLength $ sambaLogonToChgPwd $
+ sambaMaxPwdAge $ sambaMinPwdAge $
+ sambaLockoutDuration $ sambaLockoutObservationWindow $ sambaLockoutThreshold $
+ sambaForceLogoff $ sambaRefuseMachinePwdChange ))
+
+##
+## used for idmap_ldap module
+##
+objectclass ( 1.3.6.1.4.1.7165.2.2.7 NAME 'sambaUnixIdPool' SUP top AUXILIARY
+ DESC 'Pool for allocating UNIX uids/gids'
+ MUST ( uidNumber $ gidNumber ) )
+
+
+objectclass ( 1.3.6.1.4.1.7165.2.2.8 NAME 'sambaIdmapEntry' SUP top AUXILIARY
+ DESC 'Mapping from a SID to an ID'
+ MUST ( sambaSID )
+ MAY ( uidNumber $ gidNumber ) )
+
+objectclass ( 1.3.6.1.4.1.7165.2.2.9 NAME 'sambaSidEntry' SUP top STRUCTURAL
+ DESC 'Structural Class for a SID'
+ MUST ( sambaSID ) )
+
+objectclass ( 1.3.6.1.4.1.7165.2.2.10 NAME 'sambaConfig' SUP top AUXILIARY
+ DESC 'Samba Configuration Section'
+ MAY ( description ) )
+
+objectclass ( 1.3.6.1.4.1.7165.2.2.11 NAME 'sambaShare' SUP top STRUCTURAL
+ DESC 'Samba Share Section'
+ MUST ( sambaShareName )
+ MAY ( description ) )
+
+objectclass ( 1.3.6.1.4.1.7165.2.2.12 NAME 'sambaConfigOption' SUP top STRUCTURAL
+ DESC 'Samba Configuration Option'
+ MUST ( sambaOptionName )
+ MAY ( sambaBoolOption $ sambaIntegerOption $ sambaStringOption $
+ sambaStringListoption $ description ) )
+
+
+## retired during privilege rewrite
+##objectclass ( 1.3.6.1.4.1.7165.2.2.13 NAME 'sambaPrivilege' SUP top AUXILIARY
+## DESC 'Samba Privilege'
+## MUST ( sambaSID )
+## MAY ( sambaPrivilegeList ) )
+
+##
+## used for IPA_ldapsam
+##
+objectclass ( 1.3.6.1.4.1.7165.2.2.16 NAME 'sambaTrustedDomain' SUP top STRUCTURAL
+ DESC 'Samba Trusted Domain Object'
+ MUST ( cn )
+ MAY ( sambaTrustType $ sambaTrustAttributes $ sambaTrustDirection $
+ sambaTrustPartner $ sambaFlatName $ sambaTrustAuthOutgoing $
+ sambaTrustAuthIncoming $ sambaSecurityIdentifier $
+ sambaTrustForestTrustInfo $ sambaTrustPosixOffset $
+ sambaSupportedEncryptionTypes) )
diff --git a/examples/LDAP/samba.schema.at.IBM-DS b/examples/LDAP/samba.schema.at.IBM-DS
new file mode 100644
index 0000000..77ddef8
--- /dev/null
+++ b/examples/LDAP/samba.schema.at.IBM-DS
@@ -0,0 +1,116 @@
+## Samba 3.0 schema for IBM Directory Server 5.1 - attribute Types only
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.24 NAME 'sambaLMPassword' DESC 'LanManager Password' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )
+IBMAttributetypes=( 1.3.6.1.4.1.7165.2.1.24 DBNAME( 'sambaLMPassword' 'sambaLMPassword' ) ACCESS-CLASS critical )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.25 NAME 'sambaNTPassword' DESC 'MD4 hash of the unicode password'EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{32} SINGLE-VALUE )
+IBMAttributetypes=( 1.3.6.1.4.1.7165.2.1.25 DBNAME( 'sambaNTPassword' 'sambaNTPassword' ) ACCESS-CLASS critical )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.26 NAME 'sambaAcctFlags' DESC 'Account Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{16} SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.27 NAME 'sambaPwdLastSet' DESC 'Timestamp of the last password update' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.28 NAME 'sambaPwdCanChange' DESC 'Timestamp of when the user is allowed to update the password' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.29 NAME 'sambaPwdMustChange' DESC 'Timestamp of when the password will expire' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.30 NAME 'sambaLogonTime' DESC 'Timestamp of last logon' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.31 NAME 'sambaLogoffTime' DESC 'Timestamp of last logoff' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.32 NAME 'sambaKickoffTime' DESC 'Timestamp of when the user will be logged off automatically' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.33 NAME 'sambaHomeDrive' DESC 'Driver letter of home directory mapping' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{4} SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.34 NAME 'sambaLogonScript' DESC 'Logon script path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.35 NAME 'sambaProfilePath' DESC 'Roaming profile path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.36 NAME 'sambaUserWorkstations' DESC 'List of user workstations the user is allowed to logon to' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{255} SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.37 NAME 'sambaHomePath' DESC 'Home directory UNC path' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.38 NAME 'sambaDomainName' DESC 'Windows NT domain to which the user belongs' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.20 NAME 'sambaSID' DESC 'Security ID' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.23 NAME 'sambaPrimaryGroupSID' DESC 'Primary Group Security ID' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.19 NAME 'sambaGroupType' DESC 'NT Group Type' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.21 NAME 'sambaNextUserRid' DESC 'Next NT rid to give our for users' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.22 NAME 'sambaNextGroupRid' DESC 'Next NT rid to give out for groups' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.39 NAME 'sambaNextRid' DESC 'Next NT rid to give out for anything' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.40 NAME 'sambaAlgorithmicRidBase' DESC 'Base at which the samba RID generation algorithm should operate' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.41 NAME 'sambaShareName' DESC 'Share Name' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.42 NAME 'sambaOptionName' DESC 'Option Name' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.43 NAME 'sambaBoolOption' DESC 'A boolean option' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.44 NAME 'sambaIntegerOption' DESC 'An integer option' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.45 NAME 'sambaStringOption' DESC 'A string option' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.46 NAME 'sambaStringListOption' DESC 'A string list option' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.47 NAME 'sambaMungedDial' DESC 'Base64 encoded user parameter string' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.48 NAME 'sambaBadPasswordCount' DESC 'Bad password attempt count' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.49 NAME 'sambaBadPasswordTime' DESC 'Time of the last bad password attempt' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.51 NAME 'sambaSIDList' DESC 'Security ID List' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.53 NAME 'sambaTrustFlags' DESC 'Trust Password Flags' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.54 NAME 'sambaPasswordHistory' DESC 'Concatenated MD4 hashes of the unicode passwords used on this account' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} )
+IBMAttributetypes=( 1.3.6.1.4.1.7165.2.1.54 DBNAME( 'sambaPasswordHistory' 'sambaPasswordHistory' ) ACCESS-CLASS critical )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.55 NAME 'sambaLogonHours' DESC 'Logon Hours' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{42} SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.58 NAME 'sambaMinPwdLength' DESC 'Minimal password length (default: 5)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.59 NAME 'sambaPwdHistoryLength' DESC 'Length of Password History Entries (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.60 NAME 'sambaLogonToChgPwd' DESC 'Force Users to logon for password change (default: 0 => off, 2 => on)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.61 NAME 'sambaMaxPwdAge' DESC 'Maximum password age, in seconds (default: -1 => never expire passwords)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.62 NAME 'sambaMinPwdAge' DESC 'Minimum password age, in seconds (default: 0 => allow immediate password change)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.63 NAME 'sambaLockoutDuration' DESC 'Lockout duration in minutes (default: 30, -1 => forever)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.64 NAME 'sambaLockoutObservationWindow' DESC 'Reset time after lockout in minutes (default: 30)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.65 NAME 'sambaLockoutThreshold' DESC 'Lockout users after bad logon attempts (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.66 NAME 'sambaForceLogoff' DESC 'Disconnect Users outside logon hours (default: -1 => off, 0 => on)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.67 NAME 'sambaRefuseMachinePwdChange' DESC 'Allow Machine Password changes (default: 0 => off)' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.70 NAME 'sambaTrustType' DESC 'Type of trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.71 NAME 'sambaTrustAttributes' DESC 'Trust attributes for a trusted domain' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.72 NAME 'sambaTrustDirection' DESC 'Direction of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.73 NAME 'sambaTrustPartner' DESC 'Fully qualified name of the domain with which a trust exists' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.74 NAME 'sambaFlatName' DESC 'NetBIOS name of a domain' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.75 NAME 'sambaTrustAuthOutgoing' DESC 'Authentication information for the outgoing portion of a trust' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.76 NAME 'sambaTrustAuthIncoming' DESC 'Authentication information for the incoming portion of a trust' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.77 NAME 'sambaSecurityIdentifier' DESC 'SID of a trusted domain' EQUALITY caseIgnoreIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{64} SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.78 NAME 'sambaTrustForestTrustInfo' DESC 'Forest trust information for a trusted domain object' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1050} )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.79 NAME 'sambaTrustPosixOffset' DESC 'POSIX offset of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+
+attributetypes=( 1.3.6.1.4.1.7165.2.1.80 NAME 'sambaSupportedEncryptionTypes' DESC 'Supported encryption types of a trust' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
diff --git a/examples/LDAP/samba.schema.oc.IBM-DS b/examples/LDAP/samba.schema.oc.IBM-DS
new file mode 100644
index 0000000..c3ed05b
--- /dev/null
+++ b/examples/LDAP/samba.schema.oc.IBM-DS
@@ -0,0 +1,23 @@
+## Samba 3.0 schema for IBM Directory Server 5.1 - object classes only
+
+objectclasses=( 1.3.6.1.4.1.7165.2.2.6 NAME 'sambaSamAccount' SUP top AUXILIARY DESC 'Samba 3.0 Auxilary SAM Account' MUST ( uid $ sambaSID ) MAY ( cn $ sambaLMPassword $ sambaNTPassword $ sambaPwdLastSet $ sambaLogonTime $ sambaLogoffTime $ sambaKickoffTime $ sambaPwdCanChange $ sambaPwdMustChange $ sambaAcctFlags $ displayName $ sambaHomePath $ sambaHomeDrive $ sambaLogonScript $ sambaProfilePath $ description $ sambaUserWorkstations $ sambaPrimaryGroupSID $ sambaDomainName $ sambaMungedDial $ sambaBadPasswordCount $ sambaBadPasswordTime $ sambaPasswordHistory $ sambaLogonHours))
+
+objectclasses=( 1.3.6.1.4.1.7165.2.2.4 NAME 'sambaGroupMapping' SUP top AUXILIARY DESC 'Samba Group Mapping' MUST ( gidNumber $ sambaSID $ sambaGroupType ) MAY ( displayName $ description $ sambaSIDList ))
+
+objectclasses=( 1.3.6.1.4.1.7165.2.2.5 NAME 'sambaDomain' SUP top STRUCTURAL DESC 'Samba Domain Information' MUST ( sambaDomainName $ sambaSID ) MAY ( sambaNextRid $ sambaNextGroupRid $ sambaNextUserRid $ sambaAlgorithmicRidBase $ sambaMinPwdLength $ sambaPwdHistoryLength $ sambaLogonToChgPwd $ sambaMaxPwdAge $ sambaMinPwdAge $ sambaLockoutDuration $ sambaLockoutObservationWindow $ sambaLockoutThreshold $ sambaForceLogoff $ sambaRefuseMachinePwdChange ) )
+
+objectclasses=( 1.3.6.1.4.1.7165.2.2.7 NAME 'sambaUnixIdPool' SUP top AUXILIARY DESC 'Pool for allocating UNIX uids/gids' MUST ( uidNumber $ gidNumber ) )
+
+objectclasses=( 1.3.6.1.4.1.7165.2.2.8 NAME 'sambaIdmapEntry' SUP top AUXILIARY DESC 'Mapping from a SID to an ID' MUST ( sambaSID ) MAY ( uidNumber $ gidNumber ) )
+
+objectclasses=( 1.3.6.1.4.1.7165.2.2.9 NAME 'sambaSidEntry' SUP top STRUCTURAL DESC 'Structural Class for a SID' MUST ( sambaSID ) )
+
+objectclasses=( 1.3.6.1.4.1.7165.2.2.10 NAME 'sambaConfig' SUP top AUXILIARY DESC 'Samba Configuration Section' MAY ( description ) )
+
+objectclasses=( 1.3.6.1.4.1.7165.2.2.11 NAME 'sambaShare' SUP top STRUCTURAL DESC 'Samba Share Section' MUST ( sambaShareName ) MAY ( description ) )
+
+objectclasses=( 1.3.6.1.4.1.7165.2.2.12 NAME 'sambaConfigOption' SUP top STRUCTURAL DESC 'Samba Configuration Option' MUST ( sambaOptionName ) MAY ( sambaBoolOption $ sambaIntegerOption $ sambaStringOption $ sambaStringListoption $ description ) )
+
+objectclasses=( 1.3.6.1.4.1.7165.2.2.14 NAME 'sambaTrustPassword' SUP top STRUCTURAL DESC 'Samba Trust Password' MUST ( sambaDomainName $ sambaNTPassword $ sambaTrustFlags ) MAY ( sambaSID $ sambaPwdLastSet ))
+
+objectclasses=( 1.3.6.1.4.1.7165.2.2.16 NAME 'sambaTrustedDomain' SUP top STRUCTURAL DESC 'Samba Trusted Domain Object' MUST ( cn ) MAY ( sambaTrustType $ sambaTrustAttributes $ sambaTrustDirection $ sambaTrustPartner $ sambaFlatName $ sambaTrustAuthOutgoing $ sambaTrustAuthIncoming $ sambaSecurityIdentifier $ sambaTrustForestTrustInfo $ sambaTrustPosixOffset $ sambaSupportedEncryptionTypes ) )
diff --git a/examples/README b/examples/README
new file mode 100644
index 0000000..950baf1
--- /dev/null
+++ b/examples/README
@@ -0,0 +1,11 @@
+Copyright(C) Samba-Team 1993-2001
+
+This directory contains example config files and related material for
+Samba.
+
+At a minimum please refer to the smb.conf.default file for current
+information regarding global and share parameter settings.
+
+To contribute to Samba see: https://wiki.samba.org/index.php/Contribute
+
+
diff --git a/examples/VFS/README b/examples/VFS/README
new file mode 100644
index 0000000..dc99e20
--- /dev/null
+++ b/examples/VFS/README
@@ -0,0 +1,20 @@
+README for Samba Virtual File System (VFS) Example
+===================================================
+
+This directory contains skeleton VFS modules. When used,
+this module simply passes all requests back to the disk functions
+(i.e it operates as a passthrough filter). It should be
+useful as a starting point for developing new VFS
+modules.
+
+Please look at skel_opaque.c when you want your module to provide
+final functions, like a database filesystem.
+
+Please look at skel_transparent.c when you want your module to provide
+passthrough functions, like audit modules.
+
+Please read the VFS chapter in the HOWTO collection for general help
+on the usage of VFS modules.
+
+Further documentation on writing VFS modules for Samba can be found in
+Samba Developers Guide.
diff --git a/examples/VFS/shadow_copy_test.c b/examples/VFS/shadow_copy_test.c
new file mode 100644
index 0000000..157e576
--- /dev/null
+++ b/examples/VFS/shadow_copy_test.c
@@ -0,0 +1,92 @@
+/*
+ * TEST implementation of an Shadow Copy module
+ *
+ * Copyright (C) Stefan Metzmacher 2003
+ * Copyright (C) Jeremy Allison 2009.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "../source3/include/includes.h"
+#include "ntioctl.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+/* USE THIS MODULE ONLY FOR TESTING!!!! */
+
+/*
+ For this share
+ Z:\
+
+ the ShadowCopies are in these directories
+
+ Z:\@GMT-2003.08.05-12.00.00\
+ Z:\@GMT-2003.08.05-12.01.00\
+ Z:\@GMT-2003.08.05-12.02.00\
+
+ e.g.
+
+ Z:\testfile.txt
+ Z:\@GMT-2003.08.05-12.02.00\testfile.txt
+
+ or:
+
+ Z:\testdir\testfile.txt
+ Z:\@GMT-2003.08.05-12.02.00\testdir\testfile.txt
+
+
+ Note: Files must differ to be displayed via Windows Explorer!
+ Directories are always displayed...
+*/
+
+static int test_get_shadow_copy_data(vfs_handle_struct *handle,
+ files_struct *fsp,
+ struct shadow_copy_data *shadow_copy_data,
+ bool labels)
+{
+ uint32_t num = 3;
+ uint32_t i;
+
+ shadow_copy_data->num_volumes = num;
+
+ if (labels) {
+ if (num) {
+ shadow_copy_data->labels = talloc_zero_array(shadow_copy_data,SHADOW_COPY_LABEL,num);
+ } else {
+ shadow_copy_data->labels = NULL;
+ }
+ for (i=0;i<num;i++) {
+ snprintf(shadow_copy_data->labels[i], sizeof(SHADOW_COPY_LABEL), "@GMT-2003.08.05-12.%02u.00",i);
+ }
+ } else {
+ shadow_copy_data->labels = NULL;
+ }
+
+ return 0;
+}
+
+/* VFS operations structure */
+
+static struct vfs_fn_pointers vfs_test_shadow_copy_fns = {
+ .get_shadow_copy_data_fn = test_get_shadow_copy_data
+};
+
+static_decl_vfs;
+NTSTATUS vfs_shadow_copy_test_init(TALLOC_CTX *ctx)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
+ "shadow_copy_test",
+ &vfs_test_shadow_copy_fns);
+}
diff --git a/examples/VFS/skel_opaque.c b/examples/VFS/skel_opaque.c
new file mode 100644
index 0000000..255fa83
--- /dev/null
+++ b/examples/VFS/skel_opaque.c
@@ -0,0 +1,1099 @@
+/*
+ * Skeleton VFS module. Implements dummy versions of all VFS
+ * functions.
+ *
+ * Copyright (C) Tim Potter, 1999-2000
+ * Copyright (C) Alexander Bokovoy, 2002
+ * Copyright (C) Stefan (metze) Metzmacher, 2003
+ * Copyright (C) Jeremy Allison 2009
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "../source3/include/includes.h"
+#include "lib/util/tevent_unix.h"
+#include "lib/util/tevent_ntstatus.h"
+
+/* PLEASE,PLEASE READ THE VFS MODULES CHAPTER OF THE
+ SAMBA DEVELOPERS GUIDE!!!!!!
+ */
+
+/* If you take this file as template for your module
+ * you must re-implement every function.
+ */
+
+static int skel_connect(vfs_handle_struct *handle, const char *service,
+ const char *user)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static void skel_disconnect(vfs_handle_struct *handle)
+{
+ ;
+}
+
+static uint64_t skel_disk_free(vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname,
+ uint64_t *bsize,
+ uint64_t *dfree,
+ uint64_t *dsize)
+{
+ *bsize = 0;
+ *dfree = 0;
+ *dsize = 0;
+ return 0;
+}
+
+static int skel_get_quota(vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname,
+ enum SMB_QUOTA_TYPE qtype,
+ unid_t id,
+ SMB_DISK_QUOTA *dq)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_set_quota(vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype,
+ unid_t id, SMB_DISK_QUOTA *dq)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_get_shadow_copy_data(vfs_handle_struct *handle,
+ files_struct *fsp,
+ struct shadow_copy_data *shadow_copy_data,
+ bool labels)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_statvfs(struct vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname,
+ struct vfs_statvfs_struct *statbuf)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static uint32_t skel_fs_capabilities(struct vfs_handle_struct *handle,
+ enum timestamp_set_resolution *p_ts_res)
+{
+ return 0;
+}
+
+static NTSTATUS skel_get_dfs_referrals(struct vfs_handle_struct *handle,
+ struct dfs_GetDFSReferral *r)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS skel_create_dfs_pathat(struct vfs_handle_struct *handle,
+ struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ const struct referral *reflist,
+ size_t referral_count)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS skel_read_dfs_pathat(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct files_struct *dirfsp,
+ struct smb_filename *smb_fname,
+ struct referral **ppreflist,
+ size_t *preferral_count)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS skel_snap_check_path(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ const char *service_path,
+ char **base_volume)
+{
+ return NT_STATUS_NOT_SUPPORTED;
+}
+
+static NTSTATUS skel_snap_create(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ const char *base_volume,
+ time_t *tstamp,
+ bool rw,
+ char **base_path,
+ char **snap_path)
+{
+ return NT_STATUS_NOT_SUPPORTED;
+}
+
+static NTSTATUS skel_snap_delete(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ char *base_path,
+ char *snap_path)
+{
+ return NT_STATUS_NOT_SUPPORTED;
+}
+
+static DIR *skel_fdopendir(vfs_handle_struct *handle, files_struct *fsp,
+ const char *mask, uint32_t attr)
+{
+ return NULL;
+}
+
+static struct dirent *skel_readdir(vfs_handle_struct *handle,
+ struct files_struct *dirfsp,
+ DIR *dirp)
+{
+ return NULL;
+}
+
+static void skel_rewind_dir(vfs_handle_struct *handle, DIR *dirp)
+{
+ ;
+}
+
+static int skel_mkdirat(vfs_handle_struct *handle,
+ struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ mode_t mode)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_closedir(vfs_handle_struct *handle, DIR *dir)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_openat(struct vfs_handle_struct *handle,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ struct files_struct *fsp,
+ const struct vfs_open_how *how)
+{
+ if (how->resolve != 0) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ errno = ENOSYS;
+ return -1;
+}
+
+static NTSTATUS skel_create_file(struct vfs_handle_struct *handle,
+ struct smb_request *req,
+ struct files_struct *dirfsp,
+ struct smb_filename *smb_fname,
+ uint32_t access_mask,
+ uint32_t share_access,
+ uint32_t create_disposition,
+ uint32_t create_options,
+ uint32_t file_attributes,
+ uint32_t oplock_request,
+ const struct smb2_lease *lease,
+ uint64_t allocation_size,
+ uint32_t private_flags,
+ struct security_descriptor *sd,
+ struct ea_list *ea_list,
+ files_struct **result, int *pinfo,
+ const struct smb2_create_blobs *in_context_blobs,
+ struct smb2_create_blobs *out_context_blobs)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static int skel_close_fn(vfs_handle_struct *handle, files_struct *fsp)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static ssize_t skel_pread(vfs_handle_struct *handle, files_struct *fsp,
+ void *data, size_t n, off_t offset)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static struct tevent_req *skel_pread_send(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct files_struct *fsp,
+ void *data, size_t n, off_t offset)
+{
+ return NULL;
+}
+
+static ssize_t skel_pread_recv(struct tevent_req *req,
+ struct vfs_aio_state *vfs_aio_state)
+{
+ vfs_aio_state->error = ENOSYS;
+ return -1;
+}
+
+static ssize_t skel_pwrite(vfs_handle_struct *handle, files_struct *fsp,
+ const void *data, size_t n, off_t offset)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static struct tevent_req *skel_pwrite_send(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct files_struct *fsp,
+ const void *data,
+ size_t n, off_t offset)
+{
+ return NULL;
+}
+
+static ssize_t skel_pwrite_recv(struct tevent_req *req,
+ struct vfs_aio_state *vfs_aio_state)
+{
+ vfs_aio_state->error = ENOSYS;
+ return -1;
+}
+
+static off_t skel_lseek(vfs_handle_struct *handle, files_struct *fsp,
+ off_t offset, int whence)
+{
+ errno = ENOSYS;
+ return (off_t) - 1;
+}
+
+static ssize_t skel_sendfile(vfs_handle_struct *handle, int tofd,
+ files_struct *fromfsp, const DATA_BLOB *hdr,
+ off_t offset, size_t n)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static ssize_t skel_recvfile(vfs_handle_struct *handle, int fromfd,
+ files_struct *tofsp, off_t offset, size_t n)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_renameat(vfs_handle_struct *handle,
+ files_struct *srcfsp,
+ const struct smb_filename *smb_fname_src,
+ files_struct *dstfsp,
+ const struct smb_filename *smb_fname_dst)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static struct tevent_req *skel_fsync_send(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct files_struct *fsp)
+{
+ return NULL;
+}
+
+static int skel_fsync_recv(struct tevent_req *req,
+ struct vfs_aio_state *vfs_aio_state)
+{
+ vfs_aio_state->error = ENOSYS;
+ return -1;
+}
+
+static int skel_stat(vfs_handle_struct *handle, struct smb_filename *smb_fname)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_fstat(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_STRUCT_STAT *sbuf)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_lstat(vfs_handle_struct *handle,
+ struct smb_filename *smb_fname)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_fstatat(
+ struct vfs_handle_struct *handle,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ SMB_STRUCT_STAT *sbuf,
+ int flags)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static uint64_t skel_get_alloc_size(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const SMB_STRUCT_STAT *sbuf)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_unlinkat(vfs_handle_struct *handle,
+ struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ int flags)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_fchmod(vfs_handle_struct *handle, files_struct *fsp,
+ mode_t mode)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_fchown(vfs_handle_struct *handle, files_struct *fsp,
+ uid_t uid, gid_t gid)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_lchown(vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname,
+ uid_t uid,
+ gid_t gid)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_chdir(vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static struct smb_filename *skel_getwd(vfs_handle_struct *handle,
+ TALLOC_CTX *ctx)
+{
+ errno = ENOSYS;
+ return NULL;
+}
+
+static int skel_fntimes(vfs_handle_struct *handle,
+ files_struct *fsp,
+ struct smb_file_time *ft)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_ftruncate(vfs_handle_struct *handle, files_struct *fsp,
+ off_t offset)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_fallocate(vfs_handle_struct *handle, files_struct *fsp,
+ uint32_t mode, off_t offset, off_t len)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static bool skel_lock(vfs_handle_struct *handle, files_struct *fsp, int op,
+ off_t offset, off_t count, int type)
+{
+ errno = ENOSYS;
+ return false;
+}
+
+static int skel_filesystem_sharemode(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ uint32_t share_mode,
+ uint32_t access_mask)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_fcntl(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, int cmd, va_list cmd_arg)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_linux_setlease(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, int leasetype)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static bool skel_getlock(vfs_handle_struct *handle, files_struct *fsp,
+ off_t *poffset, off_t *pcount, int *ptype,
+ pid_t *ppid)
+{
+ errno = ENOSYS;
+ return false;
+}
+
+static int skel_symlinkat(vfs_handle_struct *handle,
+ const struct smb_filename *link_contents,
+ struct files_struct *dirfsp,
+ const struct smb_filename *new_smb_fname)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_vfs_readlinkat(vfs_handle_struct *handle,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ char *buf,
+ size_t bufsiz)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_linkat(vfs_handle_struct *handle,
+ files_struct *srcfsp,
+ const struct smb_filename *old_smb_fname,
+ files_struct *dstfsp,
+ const struct smb_filename *new_smb_fname,
+ int flags)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_mknodat(vfs_handle_struct *handle,
+ files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ mode_t mode,
+ SMB_DEV_T dev)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static struct smb_filename *skel_realpath(vfs_handle_struct *handle,
+ TALLOC_CTX *ctx,
+ const struct smb_filename *smb_fname)
+{
+ errno = ENOSYS;
+ return NULL;
+}
+
+static int skel_fchflags(vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ uint flags)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static struct file_id skel_file_id_create(vfs_handle_struct *handle,
+ const SMB_STRUCT_STAT *sbuf)
+{
+ struct file_id id;
+ ZERO_STRUCT(id);
+ errno = ENOSYS;
+ return id;
+}
+
+static uint64_t skel_fs_file_id(vfs_handle_struct *handle,
+ const SMB_STRUCT_STAT *sbuf)
+{
+ errno = ENOSYS;
+ return 0;
+}
+
+struct skel_offload_read_state {
+ bool dummy;
+};
+
+static struct tevent_req *skel_offload_read_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ uint32_t fsctl,
+ uint32_t ttl,
+ off_t offset,
+ size_t to_copy)
+{
+ struct tevent_req *req = NULL;
+ struct skel_offload_read_state *state = NULL;
+
+ req = tevent_req_create(mem_ctx, &state, struct skel_offload_read_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
+ return tevent_req_post(req, ev);
+}
+
+static NTSTATUS skel_offload_read_recv(struct tevent_req *req,
+ struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *flags,
+ uint64_t *xferlen,
+ DATA_BLOB *_token_blob)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+ tevent_req_received(req);
+
+ return NT_STATUS_OK;
+}
+
+struct skel_cc_state {
+ uint64_t unused;
+};
+static struct tevent_req *skel_offload_write_send(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ uint32_t fsctl,
+ DATA_BLOB *token,
+ off_t transfer_offset,
+ struct files_struct *dest_fsp,
+ off_t dest_off,
+ off_t num)
+{
+ struct tevent_req *req;
+ struct skel_cc_state *cc_state;
+
+ req = tevent_req_create(mem_ctx, &cc_state, struct skel_cc_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
+ return tevent_req_post(req, ev);
+}
+
+static NTSTATUS skel_offload_write_recv(struct vfs_handle_struct *handle,
+ struct tevent_req *req,
+ off_t *copied)
+{
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+ tevent_req_received(req);
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS skel_fget_compression(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct files_struct *fsp,
+ uint16_t *_compression_fmt)
+{
+ return NT_STATUS_INVALID_DEVICE_REQUEST;
+}
+
+static NTSTATUS skel_set_compression(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct files_struct *fsp,
+ uint16_t compression_fmt)
+{
+ return NT_STATUS_INVALID_DEVICE_REQUEST;
+}
+
+static NTSTATUS skel_fstreaminfo(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ TALLOC_CTX *mem_ctx,
+ unsigned int *num_streams,
+ struct stream_struct **streams)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS skel_get_real_filename_at(struct vfs_handle_struct *handle,
+ struct files_struct *dirfsp,
+ const char *name,
+ TALLOC_CTX *mem_ctx,
+ char **found_name)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static const char *skel_connectpath(
+ struct vfs_handle_struct *handle,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname)
+{
+ errno = ENOSYS;
+ return NULL;
+}
+
+static NTSTATUS skel_brl_lock_windows(struct vfs_handle_struct *handle,
+ struct byte_range_lock *br_lck,
+ struct lock_struct *plock)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static bool skel_brl_unlock_windows(struct vfs_handle_struct *handle,
+ struct byte_range_lock *br_lck,
+ const struct lock_struct *plock)
+{
+ errno = ENOSYS;
+ return false;
+}
+
+static bool skel_strict_lock_check(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ struct lock_struct *plock)
+{
+ errno = ENOSYS;
+ return false;
+}
+
+static NTSTATUS skel_translate_name(struct vfs_handle_struct *handle,
+ const char *mapped_name,
+ enum vfs_translate_direction direction,
+ TALLOC_CTX *mem_ctx, char **pmapped_name)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS skel_parent_pathname(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ const struct smb_filename *smb_fname_in,
+ struct smb_filename **parent_dir_out,
+ struct smb_filename **atname_out)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS skel_fsctl(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ TALLOC_CTX *ctx,
+ uint32_t function,
+ uint16_t req_flags, /* Needed for UNICODE ... */
+ const uint8_t *_in_data,
+ uint32_t in_len,
+ uint8_t **_out_data,
+ uint32_t max_out_len, uint32_t *out_len)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS skel_freaddir_attr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ TALLOC_CTX *mem_ctx,
+ struct readdir_attr_data **pattr_data)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+struct skel_get_dos_attributes_state {
+ struct vfs_aio_state aio_state;
+ uint32_t dosmode;
+};
+
+static struct tevent_req *skel_get_dos_attributes_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct vfs_handle_struct *handle,
+ files_struct *dir_fsp,
+ struct smb_filename *smb_fname)
+{
+ struct tevent_req *req = NULL;
+ struct skel_get_dos_attributes_state *state = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct skel_get_dos_attributes_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ tevent_req_nterror(req, NT_STATUS_NOT_IMPLEMENTED);
+ return tevent_req_post(req, ev);
+}
+
+static NTSTATUS skel_get_dos_attributes_recv(struct tevent_req *req,
+ struct vfs_aio_state *aio_state,
+ uint32_t *dosmode)
+{
+ struct skel_get_dos_attributes_state *state =
+ tevent_req_data(req,
+ struct skel_get_dos_attributes_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ *aio_state = state->aio_state;
+ *dosmode = state->dosmode;
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS skel_fget_dos_attributes(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ uint32_t *dosmode)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS skel_fset_dos_attributes(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ uint32_t dosmode)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS skel_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
+ uint32_t security_info,
+ TALLOC_CTX *mem_ctx,
+ struct security_descriptor **ppdesc)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS skel_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
+ uint32_t security_info_sent,
+ const struct security_descriptor *psd)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static SMB_ACL_T skel_sys_acl_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SMB_ACL_TYPE_T type,
+ TALLOC_CTX *mem_ctx)
+{
+ errno = ENOSYS;
+ return (SMB_ACL_T) NULL;
+}
+
+static int skel_sys_acl_blob_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp, TALLOC_CTX *mem_ctx,
+ char **blob_description, DATA_BLOB *blob)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_sys_acl_set_fd(vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ SMB_ACL_TYPE_T type,
+ SMB_ACL_T theacl)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_sys_acl_delete_def_fd(vfs_handle_struct *handle,
+ struct files_struct *fsp)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+struct skel_getxattrat_state {
+ struct vfs_aio_state aio_state;
+ ssize_t xattr_size;
+ uint8_t *xattr_value;
+};
+
+static struct tevent_req *skel_getxattrat_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct vfs_handle_struct *handle,
+ files_struct *dir_fsp,
+ const struct smb_filename *smb_fname,
+ const char *xattr_name,
+ size_t alloc_hint)
+{
+ struct tevent_req *req = NULL;
+ struct skel_getxattrat_state *state = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct skel_getxattrat_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ tevent_req_error(req, ENOSYS);
+ return tevent_req_post(req, ev);
+}
+
+static ssize_t skel_getxattrat_recv(struct tevent_req *req,
+ struct vfs_aio_state *aio_state,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **xattr_value)
+{
+ struct skel_getxattrat_state *state = tevent_req_data(
+ req, struct skel_getxattrat_state);
+ ssize_t xattr_size;
+
+ if (tevent_req_is_unix_error(req, &aio_state->error)) {
+ tevent_req_received(req);
+ return -1;
+ }
+
+ *aio_state = state->aio_state;
+ xattr_size = state->xattr_size;
+ if (xattr_value != NULL) {
+ *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
+ }
+
+ tevent_req_received(req);
+ return xattr_size;
+}
+
+static ssize_t skel_fgetxattr(vfs_handle_struct *handle,
+ struct files_struct *fsp, const char *name,
+ void *value, size_t size)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static ssize_t skel_flistxattr(vfs_handle_struct *handle,
+ struct files_struct *fsp, char *list,
+ size_t size)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_fremovexattr(vfs_handle_struct *handle,
+ struct files_struct *fsp, const char *name)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static int skel_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp,
+ const char *name, const void *value, size_t size,
+ int flags)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+static bool skel_aio_force(struct vfs_handle_struct *handle,
+ struct files_struct *fsp)
+{
+ errno = ENOSYS;
+ return false;
+}
+
+static NTSTATUS skel_audit_file(struct vfs_handle_struct *handle,
+ struct smb_filename *file,
+ struct security_acl *sacl,
+ uint32_t access_requested,
+ uint32_t access_denied)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS skel_durable_cookie(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *cookie)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS skel_durable_disconnect(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const DATA_BLOB old_cookie,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *new_cookie)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS skel_durable_reconnect(struct vfs_handle_struct *handle,
+ struct smb_request *smb1req,
+ struct smbXsrv_open *op,
+ const DATA_BLOB old_cookie,
+ TALLOC_CTX *mem_ctx,
+ struct files_struct **fsp,
+ DATA_BLOB *new_cookie)
+{
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/* VFS operations structure */
+
+static struct vfs_fn_pointers skel_opaque_fns = {
+ /* Disk operations */
+
+ .connect_fn = skel_connect,
+ .disconnect_fn = skel_disconnect,
+ .disk_free_fn = skel_disk_free,
+ .get_quota_fn = skel_get_quota,
+ .set_quota_fn = skel_set_quota,
+ .get_shadow_copy_data_fn = skel_get_shadow_copy_data,
+ .statvfs_fn = skel_statvfs,
+ .fs_capabilities_fn = skel_fs_capabilities,
+ .get_dfs_referrals_fn = skel_get_dfs_referrals,
+ .create_dfs_pathat_fn = skel_create_dfs_pathat,
+ .read_dfs_pathat_fn = skel_read_dfs_pathat,
+ .snap_check_path_fn = skel_snap_check_path,
+ .snap_create_fn = skel_snap_create,
+ .snap_delete_fn = skel_snap_delete,
+
+ /* Directory operations */
+
+ .fdopendir_fn = skel_fdopendir,
+ .readdir_fn = skel_readdir,
+ .rewind_dir_fn = skel_rewind_dir,
+ .mkdirat_fn = skel_mkdirat,
+ .closedir_fn = skel_closedir,
+
+ /* File operations */
+
+ .openat_fn = skel_openat,
+ .create_file_fn = skel_create_file,
+ .close_fn = skel_close_fn,
+ .pread_fn = skel_pread,
+ .pread_send_fn = skel_pread_send,
+ .pread_recv_fn = skel_pread_recv,
+ .pwrite_fn = skel_pwrite,
+ .pwrite_send_fn = skel_pwrite_send,
+ .pwrite_recv_fn = skel_pwrite_recv,
+ .lseek_fn = skel_lseek,
+ .sendfile_fn = skel_sendfile,
+ .recvfile_fn = skel_recvfile,
+ .renameat_fn = skel_renameat,
+ .fsync_send_fn = skel_fsync_send,
+ .fsync_recv_fn = skel_fsync_recv,
+ .stat_fn = skel_stat,
+ .fstat_fn = skel_fstat,
+ .lstat_fn = skel_lstat,
+ .fstatat_fn = skel_fstatat,
+ .get_alloc_size_fn = skel_get_alloc_size,
+ .unlinkat_fn = skel_unlinkat,
+ .fchmod_fn = skel_fchmod,
+ .fchown_fn = skel_fchown,
+ .lchown_fn = skel_lchown,
+ .chdir_fn = skel_chdir,
+ .getwd_fn = skel_getwd,
+ .fntimes_fn = skel_fntimes,
+ .ftruncate_fn = skel_ftruncate,
+ .fallocate_fn = skel_fallocate,
+ .lock_fn = skel_lock,
+ .filesystem_sharemode_fn = skel_filesystem_sharemode,
+ .fcntl_fn = skel_fcntl,
+ .linux_setlease_fn = skel_linux_setlease,
+ .getlock_fn = skel_getlock,
+ .symlinkat_fn = skel_symlinkat,
+ .readlinkat_fn = skel_vfs_readlinkat,
+ .linkat_fn = skel_linkat,
+ .mknodat_fn = skel_mknodat,
+ .realpath_fn = skel_realpath,
+ .fchflags_fn = skel_fchflags,
+ .file_id_create_fn = skel_file_id_create,
+ .fs_file_id_fn = skel_fs_file_id,
+ .offload_read_send_fn = skel_offload_read_send,
+ .offload_read_recv_fn = skel_offload_read_recv,
+ .offload_write_send_fn = skel_offload_write_send,
+ .offload_write_recv_fn = skel_offload_write_recv,
+ .fget_compression_fn = skel_fget_compression,
+ .set_compression_fn = skel_set_compression,
+
+ .fstreaminfo_fn = skel_fstreaminfo,
+ .get_real_filename_at_fn = skel_get_real_filename_at,
+ .connectpath_fn = skel_connectpath,
+ .brl_lock_windows_fn = skel_brl_lock_windows,
+ .brl_unlock_windows_fn = skel_brl_unlock_windows,
+ .strict_lock_check_fn = skel_strict_lock_check,
+ .translate_name_fn = skel_translate_name,
+ .parent_pathname_fn = skel_parent_pathname,
+ .fsctl_fn = skel_fsctl,
+ .freaddir_attr_fn = skel_freaddir_attr,
+ .audit_file_fn = skel_audit_file,
+
+ /* DOS attributes. */
+ .get_dos_attributes_send_fn = skel_get_dos_attributes_send,
+ .get_dos_attributes_recv_fn = skel_get_dos_attributes_recv,
+ .fget_dos_attributes_fn = skel_fget_dos_attributes,
+ .fset_dos_attributes_fn = skel_fset_dos_attributes,
+
+ /* NT ACL operations. */
+
+ .fget_nt_acl_fn = skel_fget_nt_acl,
+ .fset_nt_acl_fn = skel_fset_nt_acl,
+
+ /* POSIX ACL operations. */
+
+ .sys_acl_get_fd_fn = skel_sys_acl_get_fd,
+ .sys_acl_blob_get_fd_fn = skel_sys_acl_blob_get_fd,
+ .sys_acl_set_fd_fn = skel_sys_acl_set_fd,
+ .sys_acl_delete_def_fd_fn = skel_sys_acl_delete_def_fd,
+
+ /* EA operations. */
+ .getxattrat_send_fn = skel_getxattrat_send,
+ .getxattrat_recv_fn = skel_getxattrat_recv,
+ .fgetxattr_fn = skel_fgetxattr,
+ .flistxattr_fn = skel_flistxattr,
+ .fremovexattr_fn = skel_fremovexattr,
+ .fsetxattr_fn = skel_fsetxattr,
+
+ /* aio operations */
+ .aio_force_fn = skel_aio_force,
+
+ /* durable handle operations */
+ .durable_cookie_fn = skel_durable_cookie,
+ .durable_disconnect_fn = skel_durable_disconnect,
+ .durable_reconnect_fn = skel_durable_reconnect,
+};
+
+static_decl_vfs;
+NTSTATUS vfs_skel_opaque_init(TALLOC_CTX *ctx)
+{
+ /*
+ * smb_vfs_assert_all_fns() makes sure every
+ * call is implemented.
+ *
+ * An opaque module requires this!
+ */
+ smb_vfs_assert_all_fns(&skel_opaque_fns, "skel_opaque");
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "skel_opaque",
+ &skel_opaque_fns);
+}
diff --git a/examples/VFS/skel_transparent.c b/examples/VFS/skel_transparent.c
new file mode 100644
index 0000000..461228f
--- /dev/null
+++ b/examples/VFS/skel_transparent.c
@@ -0,0 +1,1410 @@
+/*
+ * Skeleton VFS module. Implements passthrough operation of all VFS
+ * calls to disk functions.
+ *
+ * Copyright (C) Tim Potter, 1999-2000
+ * Copyright (C) Alexander Bokovoy, 2002
+ * Copyright (C) Stefan (metze) Metzmacher, 2003
+ * Copyright (C) Jeremy Allison 2009
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "../source3/include/includes.h"
+#include "lib/util/tevent_unix.h"
+#include "lib/util/tevent_ntstatus.h"
+
+/* PLEASE,PLEASE READ THE VFS MODULES CHAPTER OF THE
+ SAMBA DEVELOPERS GUIDE!!!!!!
+ */
+
+/* If you take this file as template for your module
+ * please make sure that you remove all skel_XXX() functions you don't
+ * want to implement!! The passthrough operations are not
+ * necessary in a real module.
+ *
+ * --metze
+ */
+
+static int skel_connect(vfs_handle_struct *handle, const char *service,
+ const char *user)
+{
+ return SMB_VFS_NEXT_CONNECT(handle, service, user);
+}
+
+static void skel_disconnect(vfs_handle_struct *handle)
+{
+ SMB_VFS_NEXT_DISCONNECT(handle);
+}
+
+static uint64_t skel_disk_free(vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname,
+ uint64_t *bsize,
+ uint64_t *dfree,
+ uint64_t *dsize)
+{
+ return SMB_VFS_NEXT_DISK_FREE(handle, smb_fname, bsize, dfree, dsize);
+}
+
+static int skel_get_quota(vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname,
+ enum SMB_QUOTA_TYPE qtype,
+ unid_t id,
+ SMB_DISK_QUOTA *dq)
+{
+ return SMB_VFS_NEXT_GET_QUOTA(handle, smb_fname, qtype, id, dq);
+}
+
+static int skel_set_quota(vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype,
+ unid_t id, SMB_DISK_QUOTA *dq)
+{
+ return SMB_VFS_NEXT_SET_QUOTA(handle, qtype, id, dq);
+}
+
+static int skel_get_shadow_copy_data(vfs_handle_struct *handle,
+ files_struct *fsp,
+ struct shadow_copy_data *shadow_copy_data,
+ bool labels)
+{
+ return SMB_VFS_NEXT_GET_SHADOW_COPY_DATA(handle, fsp, shadow_copy_data,
+ labels);
+}
+
+static int skel_statvfs(struct vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname,
+ struct vfs_statvfs_struct *statbuf)
+{
+ return SMB_VFS_NEXT_STATVFS(handle, smb_fname, statbuf);
+}
+
+static uint32_t skel_fs_capabilities(struct vfs_handle_struct *handle,
+ enum timestamp_set_resolution *p_ts_res)
+{
+ return SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res);
+}
+
+static NTSTATUS skel_get_dfs_referrals(struct vfs_handle_struct *handle,
+ struct dfs_GetDFSReferral *r)
+{
+ return SMB_VFS_NEXT_GET_DFS_REFERRALS(handle, r);
+}
+
+static NTSTATUS skel_create_dfs_pathat(struct vfs_handle_struct *handle,
+ struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ const struct referral *reflist,
+ size_t referral_count)
+{
+ return SMB_VFS_NEXT_CREATE_DFS_PATHAT(handle,
+ dirfsp,
+ smb_fname,
+ reflist,
+ referral_count);
+}
+
+static NTSTATUS skel_read_dfs_pathat(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct files_struct *dirfsp,
+ struct smb_filename *smb_fname,
+ struct referral **ppreflist,
+ size_t *preferral_count)
+{
+ return SMB_VFS_NEXT_READ_DFS_PATHAT(handle,
+ mem_ctx,
+ dirfsp,
+ smb_fname,
+ ppreflist,
+ preferral_count);
+}
+
+static NTSTATUS skel_snap_check_path(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ const char *service_path,
+ char **base_volume)
+{
+ return SMB_VFS_NEXT_SNAP_CHECK_PATH(handle, mem_ctx, service_path,
+ base_volume);
+}
+
+static NTSTATUS skel_snap_create(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ const char *base_volume,
+ time_t *tstamp,
+ bool rw,
+ char **base_path,
+ char **snap_path)
+{
+ return SMB_VFS_NEXT_SNAP_CREATE(handle, mem_ctx, base_volume, tstamp,
+ rw, base_path, snap_path);
+}
+
+static NTSTATUS skel_snap_delete(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ char *base_path,
+ char *snap_path)
+{
+ return SMB_VFS_NEXT_SNAP_DELETE(handle, mem_ctx, base_path, snap_path);
+}
+
+static DIR *skel_fdopendir(vfs_handle_struct *handle, files_struct *fsp,
+ const char *mask, uint32_t attr)
+{
+ return SMB_VFS_NEXT_FDOPENDIR(handle, fsp, mask, attr);
+}
+
+static struct dirent *
+skel_readdir(vfs_handle_struct *handle, struct files_struct *dirfsp, DIR *dirp)
+{
+ return SMB_VFS_NEXT_READDIR(handle, dirfsp, dirp);
+}
+
+static void skel_rewind_dir(vfs_handle_struct *handle, DIR *dirp)
+{
+ SMB_VFS_NEXT_REWINDDIR(handle, dirp);
+}
+
+static int skel_mkdirat(vfs_handle_struct *handle,
+ struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ mode_t mode)
+{
+ return SMB_VFS_NEXT_MKDIRAT(handle,
+ dirfsp,
+ smb_fname,
+ mode);
+}
+
+static int skel_closedir(vfs_handle_struct *handle, DIR *dir)
+{
+ return SMB_VFS_NEXT_CLOSEDIR(handle, dir);
+}
+
+static int skel_openat(struct vfs_handle_struct *handle,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ struct files_struct *fsp,
+ const struct vfs_open_how *how)
+{
+ return SMB_VFS_NEXT_OPENAT(handle, dirfsp, smb_fname, fsp, how);
+}
+
+static NTSTATUS skel_create_file(struct vfs_handle_struct *handle,
+ struct smb_request *req,
+ struct files_struct *dirfsp,
+ struct smb_filename *smb_fname,
+ uint32_t access_mask,
+ uint32_t share_access,
+ uint32_t create_disposition,
+ uint32_t create_options,
+ uint32_t file_attributes,
+ uint32_t oplock_request,
+ const struct smb2_lease *lease,
+ uint64_t allocation_size,
+ uint32_t private_flags,
+ struct security_descriptor *sd,
+ struct ea_list *ea_list,
+ files_struct ** result, int *pinfo,
+ const struct smb2_create_blobs *in_context_blobs,
+ struct smb2_create_blobs *out_context_blobs)
+{
+ return SMB_VFS_NEXT_CREATE_FILE(handle,
+ req,
+ dirfsp,
+ smb_fname,
+ access_mask,
+ share_access,
+ create_disposition,
+ create_options,
+ file_attributes,
+ oplock_request,
+ lease,
+ allocation_size,
+ private_flags,
+ sd, ea_list, result, pinfo,
+ in_context_blobs, out_context_blobs);
+}
+
+static int skel_close_fn(vfs_handle_struct *handle, files_struct *fsp)
+{
+ return SMB_VFS_NEXT_CLOSE(handle, fsp);
+}
+
+static ssize_t skel_pread(vfs_handle_struct *handle, files_struct *fsp,
+ void *data, size_t n, off_t offset)
+{
+ return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
+}
+
+struct skel_pread_state {
+ ssize_t ret;
+ struct vfs_aio_state vfs_aio_state;
+};
+
+static void skel_pread_done(struct tevent_req *subreq);
+
+static struct tevent_req *skel_pread_send(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct files_struct *fsp,
+ void *data, size_t n, off_t offset)
+{
+ struct tevent_req *req, *subreq;
+ struct skel_pread_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct skel_pread_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ subreq = SMB_VFS_NEXT_PREAD_SEND(state, ev, handle, fsp, data,
+ n, offset);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, skel_pread_done, req);
+ return req;
+}
+
+static void skel_pread_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct skel_pread_state *state =
+ tevent_req_data(req, struct skel_pread_state);
+
+ state->ret = SMB_VFS_PREAD_RECV(subreq, &state->vfs_aio_state);
+ TALLOC_FREE(subreq);
+ tevent_req_done(req);
+}
+
+static ssize_t skel_pread_recv(struct tevent_req *req,
+ struct vfs_aio_state *vfs_aio_state)
+{
+ struct skel_pread_state *state =
+ tevent_req_data(req, struct skel_pread_state);
+
+ if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+ return -1;
+ }
+ *vfs_aio_state = state->vfs_aio_state;
+ return state->ret;
+}
+
+static ssize_t skel_pwrite(vfs_handle_struct *handle, files_struct *fsp,
+ const void *data, size_t n, off_t offset)
+{
+ return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
+}
+
+struct skel_pwrite_state {
+ ssize_t ret;
+ struct vfs_aio_state vfs_aio_state;
+};
+
+static void skel_pwrite_done(struct tevent_req *subreq);
+
+static struct tevent_req *skel_pwrite_send(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct files_struct *fsp,
+ const void *data,
+ size_t n, off_t offset)
+{
+ struct tevent_req *req, *subreq;
+ struct skel_pwrite_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct skel_pwrite_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ subreq = SMB_VFS_NEXT_PWRITE_SEND(state, ev, handle, fsp, data,
+ n, offset);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, skel_pwrite_done, req);
+ return req;
+}
+
+static void skel_pwrite_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct skel_pwrite_state *state =
+ tevent_req_data(req, struct skel_pwrite_state);
+
+ state->ret = SMB_VFS_PWRITE_RECV(subreq, &state->vfs_aio_state);
+ TALLOC_FREE(subreq);
+ tevent_req_done(req);
+}
+
+static ssize_t skel_pwrite_recv(struct tevent_req *req,
+ struct vfs_aio_state *vfs_aio_state)
+{
+ struct skel_pwrite_state *state =
+ tevent_req_data(req, struct skel_pwrite_state);
+
+ if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+ return -1;
+ }
+ *vfs_aio_state = state->vfs_aio_state;
+ return state->ret;
+}
+
+static off_t skel_lseek(vfs_handle_struct *handle, files_struct *fsp,
+ off_t offset, int whence)
+{
+ return SMB_VFS_NEXT_LSEEK(handle, fsp, offset, whence);
+}
+
+static ssize_t skel_sendfile(vfs_handle_struct *handle, int tofd,
+ files_struct *fromfsp, const DATA_BLOB *hdr,
+ off_t offset, size_t n)
+{
+ return SMB_VFS_NEXT_SENDFILE(handle, tofd, fromfsp, hdr, offset, n);
+}
+
+static ssize_t skel_recvfile(vfs_handle_struct *handle, int fromfd,
+ files_struct *tofsp, off_t offset, size_t n)
+{
+ return SMB_VFS_NEXT_RECVFILE(handle, fromfd, tofsp, offset, n);
+}
+
+static int skel_renameat(vfs_handle_struct *handle,
+ files_struct *srcfsp,
+ const struct smb_filename *smb_fname_src,
+ files_struct *dstfsp,
+ const struct smb_filename *smb_fname_dst)
+{
+ return SMB_VFS_NEXT_RENAMEAT(handle,
+ srcfsp,
+ smb_fname_src,
+ dstfsp,
+ smb_fname_dst);
+}
+
+struct skel_fsync_state {
+ int ret;
+ struct vfs_aio_state vfs_aio_state;
+};
+
+static void skel_fsync_done(struct tevent_req *subreq);
+
+static struct tevent_req *skel_fsync_send(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct files_struct *fsp)
+{
+ struct tevent_req *req, *subreq;
+ struct skel_fsync_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct skel_fsync_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ subreq = SMB_VFS_NEXT_FSYNC_SEND(state, ev, handle, fsp);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, skel_fsync_done, req);
+ return req;
+}
+
+static void skel_fsync_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+ struct skel_fsync_state *state =
+ tevent_req_data(req, struct skel_fsync_state);
+
+ state->ret = SMB_VFS_FSYNC_RECV(subreq, &state->vfs_aio_state);
+ TALLOC_FREE(subreq);
+ tevent_req_done(req);
+}
+
+static int skel_fsync_recv(struct tevent_req *req,
+ struct vfs_aio_state *vfs_aio_state)
+{
+ struct skel_fsync_state *state =
+ tevent_req_data(req, struct skel_fsync_state);
+
+ if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+ return -1;
+ }
+ *vfs_aio_state = state->vfs_aio_state;
+ return state->ret;
+}
+
+static int skel_stat(vfs_handle_struct *handle, struct smb_filename *smb_fname)
+{
+ return SMB_VFS_NEXT_STAT(handle, smb_fname);
+}
+
+static int skel_fstat(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_STRUCT_STAT *sbuf)
+{
+ return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+}
+
+static int skel_lstat(vfs_handle_struct *handle,
+ struct smb_filename *smb_fname)
+{
+ return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
+}
+
+static int skel_fstatat(
+ struct vfs_handle_struct *handle,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ SMB_STRUCT_STAT *sbuf,
+ int flags)
+{
+ return SMB_VFS_NEXT_FSTATAT(handle, dirfsp, smb_fname, sbuf, flags);
+}
+
+static uint64_t skel_get_alloc_size(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const SMB_STRUCT_STAT *sbuf)
+{
+ return SMB_VFS_NEXT_GET_ALLOC_SIZE(handle, fsp, sbuf);
+}
+
+static int skel_unlinkat(vfs_handle_struct *handle,
+ struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ int flags)
+{
+ return SMB_VFS_NEXT_UNLINKAT(handle,
+ dirfsp,
+ smb_fname,
+ flags);
+}
+
+static int skel_fchmod(vfs_handle_struct *handle, files_struct *fsp,
+ mode_t mode)
+{
+ return SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
+}
+
+static int skel_fchown(vfs_handle_struct *handle, files_struct *fsp,
+ uid_t uid, gid_t gid)
+{
+ return SMB_VFS_NEXT_FCHOWN(handle, fsp, uid, gid);
+}
+
+static int skel_lchown(vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname,
+ uid_t uid,
+ gid_t gid)
+{
+ return SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid);
+}
+
+static int skel_chdir(vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname)
+{
+ return SMB_VFS_NEXT_CHDIR(handle, smb_fname);
+}
+
+static struct smb_filename *skel_getwd(vfs_handle_struct *handle,
+ TALLOC_CTX *ctx)
+{
+ return SMB_VFS_NEXT_GETWD(handle, ctx);
+}
+
+static int skel_fntimes(vfs_handle_struct *handle,
+ files_struct *fsp,
+ struct smb_file_time *ft)
+{
+ return SMB_VFS_NEXT_FNTIMES(handle, fsp, ft);
+}
+
+static int skel_ftruncate(vfs_handle_struct *handle, files_struct *fsp,
+ off_t offset)
+{
+ return SMB_VFS_NEXT_FTRUNCATE(handle, fsp, offset);
+}
+
+static int skel_fallocate(vfs_handle_struct *handle, files_struct *fsp,
+ uint32_t mode, off_t offset, off_t len)
+{
+ return SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len);
+}
+
+static bool skel_lock(vfs_handle_struct *handle, files_struct *fsp, int op,
+ off_t offset, off_t count, int type)
+{
+ return SMB_VFS_NEXT_LOCK(handle, fsp, op, offset, count, type);
+}
+
+static int skel_filesystem_sharemode(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ uint32_t share_mode,
+ uint32_t access_mask)
+{
+ return SMB_VFS_NEXT_FILESYSTEM_SHAREMODE(handle,
+ fsp,
+ share_mode,
+ access_mask);
+}
+
+static int skel_fcntl(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, int cmd, va_list cmd_arg)
+{
+ void *arg;
+ va_list dup_cmd_arg;
+ int result;
+
+ va_copy(dup_cmd_arg, cmd_arg);
+ arg = va_arg(dup_cmd_arg, void *);
+ result = SMB_VFS_NEXT_FCNTL(handle, fsp, cmd, arg);
+ va_end(dup_cmd_arg);
+
+ return result;
+}
+
+static int skel_linux_setlease(struct vfs_handle_struct *handle,
+ struct files_struct *fsp, int leasetype)
+{
+ return SMB_VFS_NEXT_LINUX_SETLEASE(handle, fsp, leasetype);
+}
+
+static bool skel_getlock(vfs_handle_struct *handle, files_struct *fsp,
+ off_t *poffset, off_t *pcount, int *ptype,
+ pid_t *ppid)
+{
+ return SMB_VFS_NEXT_GETLOCK(handle, fsp, poffset, pcount, ptype, ppid);
+}
+
+static int skel_symlinkat(vfs_handle_struct *handle,
+ const struct smb_filename *link_contents,
+ struct files_struct *dirfsp,
+ const struct smb_filename *new_smb_fname)
+{
+ return SMB_VFS_NEXT_SYMLINKAT(handle,
+ link_contents,
+ dirfsp,
+ new_smb_fname);
+}
+
+static int skel_vfs_readlinkat(vfs_handle_struct *handle,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ char *buf,
+ size_t bufsiz)
+{
+ return SMB_VFS_NEXT_READLINKAT(handle,
+ dirfsp,
+ smb_fname,
+ buf,
+ bufsiz);
+}
+
+static int skel_linkat(vfs_handle_struct *handle,
+ files_struct *srcfsp,
+ const struct smb_filename *old_smb_fname,
+ files_struct *dstfsp,
+ const struct smb_filename *new_smb_fname,
+ int flags)
+{
+ return SMB_VFS_NEXT_LINKAT(handle,
+ srcfsp,
+ old_smb_fname,
+ dstfsp,
+ new_smb_fname,
+ flags);
+}
+
+static int skel_mknodat(vfs_handle_struct *handle,
+ files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ mode_t mode,
+ SMB_DEV_T dev)
+{
+ return SMB_VFS_NEXT_MKNODAT(handle,
+ dirfsp,
+ smb_fname,
+ mode,
+ dev);
+}
+
+static struct smb_filename *skel_realpath(vfs_handle_struct *handle,
+ TALLOC_CTX *ctx,
+ const struct smb_filename *smb_fname)
+{
+ return SMB_VFS_NEXT_REALPATH(handle, ctx, smb_fname);
+}
+
+static int skel_fchflags(vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ uint flags)
+{
+ return SMB_VFS_NEXT_FCHFLAGS(handle, fsp, flags);
+}
+
+static struct file_id skel_file_id_create(vfs_handle_struct *handle,
+ const SMB_STRUCT_STAT *sbuf)
+{
+ return SMB_VFS_NEXT_FILE_ID_CREATE(handle, sbuf);
+}
+
+static uint64_t skel_fs_file_id(vfs_handle_struct *handle,
+ const SMB_STRUCT_STAT *sbuf)
+{
+ return SMB_VFS_NEXT_FS_FILE_ID(handle, sbuf);
+}
+
+struct skel_offload_read_state {
+ struct vfs_handle_struct *handle;
+ uint32_t flags;
+ uint64_t xferlen;
+ DATA_BLOB token;
+};
+
+static void skel_offload_read_done(struct tevent_req *subreq);
+
+static struct tevent_req *skel_offload_read_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ uint32_t fsctl,
+ uint32_t ttl,
+ off_t offset,
+ size_t to_copy)
+{
+ struct tevent_req *req = NULL;
+ struct skel_offload_read_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+
+ req = tevent_req_create(mem_ctx, &state, struct skel_offload_read_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ *state = (struct skel_offload_read_state) {
+ .handle = handle,
+ };
+
+ subreq = SMB_VFS_NEXT_OFFLOAD_READ_SEND(mem_ctx, ev, handle, fsp,
+ fsctl, ttl, offset, to_copy);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, skel_offload_read_done, req);
+ return req;
+}
+
+static void skel_offload_read_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct skel_offload_read_state *state = tevent_req_data(
+ req, struct skel_offload_read_state);
+ NTSTATUS status;
+
+ status = SMB_VFS_NEXT_OFFLOAD_READ_RECV(subreq,
+ state->handle,
+ state,
+ &state->flags,
+ &state->xferlen,
+ &state->token);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+ return;
+}
+
+static NTSTATUS skel_offload_read_recv(struct tevent_req *req,
+ struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ uint32_t *flags,
+ uint64_t *xferlen,
+ DATA_BLOB *_token)
+{
+ struct skel_offload_read_state *state = tevent_req_data(
+ req, struct skel_offload_read_state);
+ DATA_BLOB token;
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ token = data_blob_talloc(mem_ctx,
+ state->token.data,
+ state->token.length);
+
+ tevent_req_received(req);
+
+ if (token.data == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *flags = state->flags;
+ *xferlen = state->xferlen;
+ *_token = token;
+ return NT_STATUS_OK;
+}
+
+struct skel_offload_write_state {
+ struct vfs_handle_struct *handle;
+ off_t copied;
+};
+static void skel_offload_write_done(struct tevent_req *subreq);
+
+static struct tevent_req *skel_offload_write_send(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ uint32_t fsctl,
+ DATA_BLOB *token,
+ off_t transfer_offset,
+ struct files_struct *dest_fsp,
+ off_t dest_off,
+ off_t num)
+{
+ struct tevent_req *req;
+ struct tevent_req *subreq;
+ struct skel_offload_write_state *state;
+
+ req = tevent_req_create(mem_ctx, &state, struct skel_offload_write_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ state->handle = handle;
+ subreq = SMB_VFS_NEXT_OFFLOAD_WRITE_SEND(handle, state, ev,
+ fsctl, token, transfer_offset,
+ dest_fsp, dest_off, num);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ tevent_req_set_callback(subreq, skel_offload_write_done, req);
+ return req;
+}
+
+static void skel_offload_write_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct skel_offload_write_state *state
+ = tevent_req_data(req, struct skel_offload_write_state);
+ NTSTATUS status;
+
+ status = SMB_VFS_NEXT_OFFLOAD_WRITE_RECV(state->handle,
+ subreq,
+ &state->copied);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static NTSTATUS skel_offload_write_recv(struct vfs_handle_struct *handle,
+ struct tevent_req *req,
+ off_t *copied)
+{
+ struct skel_offload_write_state *state
+ = tevent_req_data(req, struct skel_offload_write_state);
+ NTSTATUS status;
+
+ *copied = state->copied;
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS skel_fget_compression(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct files_struct *fsp,
+ uint16_t *_compression_fmt)
+{
+ return SMB_VFS_NEXT_FGET_COMPRESSION(handle, mem_ctx, fsp,
+ _compression_fmt);
+}
+
+static NTSTATUS skel_set_compression(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct files_struct *fsp,
+ uint16_t compression_fmt)
+{
+ return SMB_VFS_NEXT_SET_COMPRESSION(handle, mem_ctx, fsp,
+ compression_fmt);
+}
+
+static NTSTATUS skel_fstreaminfo(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ TALLOC_CTX *mem_ctx,
+ unsigned int *num_streams,
+ struct stream_struct **streams)
+{
+ return SMB_VFS_NEXT_FSTREAMINFO(handle,
+ fsp,
+ mem_ctx,
+ num_streams,
+ streams);
+}
+
+static NTSTATUS skel_get_real_filename_at(struct vfs_handle_struct *handle,
+ struct files_struct *dirfsp,
+ const char *name,
+ TALLOC_CTX *mem_ctx,
+ char **found_name)
+{
+ return SMB_VFS_NEXT_GET_REAL_FILENAME_AT(
+ handle, dirfsp, name, mem_ctx, found_name);
+}
+
+static const char *skel_connectpath(
+ struct vfs_handle_struct *handle,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname)
+{
+ return SMB_VFS_NEXT_CONNECTPATH(handle, dirfsp, smb_fname);
+}
+
+static NTSTATUS skel_brl_lock_windows(struct vfs_handle_struct *handle,
+ struct byte_range_lock *br_lck,
+ struct lock_struct *plock)
+{
+ return SMB_VFS_NEXT_BRL_LOCK_WINDOWS(handle, br_lck, plock);
+}
+
+static bool skel_brl_unlock_windows(struct vfs_handle_struct *handle,
+ struct byte_range_lock *br_lck,
+ const struct lock_struct *plock)
+{
+ return SMB_VFS_NEXT_BRL_UNLOCK_WINDOWS(handle, br_lck, plock);
+}
+
+static bool skel_strict_lock_check(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ struct lock_struct *plock)
+{
+ return SMB_VFS_NEXT_STRICT_LOCK_CHECK(handle, fsp, plock);
+}
+
+static NTSTATUS skel_translate_name(struct vfs_handle_struct *handle,
+ const char *mapped_name,
+ enum vfs_translate_direction direction,
+ TALLOC_CTX *mem_ctx, char **pmapped_name)
+{
+ return SMB_VFS_NEXT_TRANSLATE_NAME(handle, mapped_name, direction,
+ mem_ctx, pmapped_name);
+}
+
+static NTSTATUS skel_parent_pathname(struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ const struct smb_filename *smb_fname_in,
+ struct smb_filename **parent_dir_out,
+ struct smb_filename **atname_out)
+{
+ return SMB_VFS_NEXT_PARENT_PATHNAME(handle,
+ mem_ctx,
+ smb_fname_in,
+ parent_dir_out,
+ atname_out);
+}
+
+static NTSTATUS skel_fsctl(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ TALLOC_CTX *ctx,
+ uint32_t function,
+ uint16_t req_flags, /* Needed for UNICODE ... */
+ const uint8_t *_in_data,
+ uint32_t in_len,
+ uint8_t ** _out_data,
+ uint32_t max_out_len, uint32_t *out_len)
+{
+ return SMB_VFS_NEXT_FSCTL(handle,
+ fsp,
+ ctx,
+ function,
+ req_flags,
+ _in_data,
+ in_len, _out_data, max_out_len, out_len);
+}
+
+static NTSTATUS skel_freaddir_attr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ TALLOC_CTX *mem_ctx,
+ struct readdir_attr_data **pattr_data)
+{
+ return SMB_VFS_NEXT_FREADDIR_ATTR(handle, fsp, mem_ctx, pattr_data);
+}
+
+struct skel_get_dos_attributes_state {
+ struct vfs_aio_state aio_state;
+ uint32_t dosmode;
+};
+
+static void skel_get_dos_attributes_done(struct tevent_req *subreq);
+
+static struct tevent_req *skel_get_dos_attributes_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct vfs_handle_struct *handle,
+ files_struct *dir_fsp,
+ struct smb_filename *smb_fname)
+{
+ struct tevent_req *req = NULL;
+ struct skel_get_dos_attributes_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct skel_get_dos_attributes_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ subreq = SMB_VFS_NEXT_GET_DOS_ATTRIBUTES_SEND(mem_ctx,
+ ev,
+ handle,
+ dir_fsp,
+ smb_fname);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, skel_get_dos_attributes_done, req);
+
+ return req;
+}
+
+static void skel_get_dos_attributes_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+ struct skel_get_dos_attributes_state *state =
+ tevent_req_data(req,
+ struct skel_get_dos_attributes_state);
+ NTSTATUS status;
+
+ status = SMB_VFS_NEXT_GET_DOS_ATTRIBUTES_RECV(subreq,
+ &state->aio_state,
+ &state->dosmode);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ tevent_req_done(req);
+ return;
+}
+
+static NTSTATUS skel_get_dos_attributes_recv(struct tevent_req *req,
+ struct vfs_aio_state *aio_state,
+ uint32_t *dosmode)
+{
+ struct skel_get_dos_attributes_state *state =
+ tevent_req_data(req,
+ struct skel_get_dos_attributes_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
+ return status;
+ }
+
+ *aio_state = state->aio_state;
+ *dosmode = state->dosmode;
+ tevent_req_received(req);
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS skel_fget_dos_attributes(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ uint32_t *dosmode)
+{
+ return SMB_VFS_NEXT_FGET_DOS_ATTRIBUTES(handle,
+ fsp,
+ dosmode);
+}
+
+static NTSTATUS skel_fset_dos_attributes(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ uint32_t dosmode)
+{
+ return SMB_VFS_NEXT_FSET_DOS_ATTRIBUTES(handle,
+ fsp,
+ dosmode);
+}
+
+static NTSTATUS skel_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
+ uint32_t security_info,
+ TALLOC_CTX *mem_ctx,
+ struct security_descriptor **ppdesc)
+{
+ return SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info, mem_ctx,
+ ppdesc);
+}
+
+static NTSTATUS skel_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
+ uint32_t security_info_sent,
+ const struct security_descriptor *psd)
+{
+ return SMB_VFS_NEXT_FSET_NT_ACL(handle, fsp, security_info_sent, psd);
+}
+
+static SMB_ACL_T skel_sys_acl_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp,
+ SMB_ACL_TYPE_T type,
+ TALLOC_CTX *mem_ctx)
+{
+ return SMB_VFS_NEXT_SYS_ACL_GET_FD(handle, fsp, type, mem_ctx);
+}
+
+static int skel_sys_acl_blob_get_fd(vfs_handle_struct *handle,
+ files_struct *fsp, TALLOC_CTX *mem_ctx,
+ char **blob_description, DATA_BLOB *blob)
+{
+ return SMB_VFS_NEXT_SYS_ACL_BLOB_GET_FD(handle, fsp, mem_ctx,
+ blob_description, blob);
+}
+
+static int skel_sys_acl_set_fd(vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ SMB_ACL_TYPE_T type,
+ SMB_ACL_T theacl)
+{
+ return SMB_VFS_NEXT_SYS_ACL_SET_FD(handle, fsp, type, theacl);
+}
+
+static int skel_sys_acl_delete_def_fd(vfs_handle_struct *handle,
+ struct files_struct *fsp)
+{
+ return SMB_VFS_NEXT_SYS_ACL_DELETE_DEF_FD(handle, fsp);
+}
+
+struct skel_getxattrat_state {
+ struct vfs_aio_state aio_state;
+ ssize_t xattr_size;
+ uint8_t *xattr_value;
+};
+
+static void skel_getxattrat_done(struct tevent_req *subreq);
+
+static struct tevent_req *skel_getxattrat_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct vfs_handle_struct *handle,
+ files_struct *dir_fsp,
+ const struct smb_filename *smb_fname,
+ const char *xattr_name,
+ size_t alloc_hint)
+{
+ struct tevent_req *req = NULL;
+ struct skel_getxattrat_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct skel_getxattrat_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ subreq = SMB_VFS_NEXT_GETXATTRAT_SEND(state,
+ ev,
+ handle,
+ dir_fsp,
+ smb_fname,
+ xattr_name,
+ alloc_hint);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, skel_getxattrat_done, req);
+
+ return req;
+}
+
+static void skel_getxattrat_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct skel_getxattrat_state *state = tevent_req_data(
+ req, struct skel_getxattrat_state);
+
+ state->xattr_size = SMB_VFS_NEXT_GETXATTRAT_RECV(subreq,
+ &state->aio_state,
+ state,
+ &state->xattr_value);
+ TALLOC_FREE(subreq);
+ if (state->xattr_size == -1) {
+ tevent_req_error(req, state->aio_state.error);
+ return;
+ }
+
+ tevent_req_done(req);
+}
+
+static ssize_t skel_getxattrat_recv(struct tevent_req *req,
+ struct vfs_aio_state *aio_state,
+ TALLOC_CTX *mem_ctx,
+ uint8_t **xattr_value)
+{
+ struct skel_getxattrat_state *state = tevent_req_data(
+ req, struct skel_getxattrat_state);
+ ssize_t xattr_size;
+
+ if (tevent_req_is_unix_error(req, &aio_state->error)) {
+ tevent_req_received(req);
+ return -1;
+ }
+
+ *aio_state = state->aio_state;
+ xattr_size = state->xattr_size;
+ if (xattr_value != NULL) {
+ *xattr_value = talloc_move(mem_ctx, &state->xattr_value);
+ }
+
+ tevent_req_received(req);
+ return xattr_size;
+}
+
+static ssize_t skel_fgetxattr(vfs_handle_struct *handle,
+ struct files_struct *fsp, const char *name,
+ void *value, size_t size)
+{
+ return SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, value, size);
+}
+
+static ssize_t skel_flistxattr(vfs_handle_struct *handle,
+ struct files_struct *fsp, char *list,
+ size_t size)
+{
+ return SMB_VFS_NEXT_FLISTXATTR(handle, fsp, list, size);
+}
+
+static int skel_fremovexattr(vfs_handle_struct *handle,
+ struct files_struct *fsp, const char *name)
+{
+ return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, name);
+}
+
+static int skel_fsetxattr(vfs_handle_struct *handle, struct files_struct *fsp,
+ const char *name, const void *value, size_t size,
+ int flags)
+{
+ return SMB_VFS_NEXT_FSETXATTR(handle, fsp, name, value, size, flags);
+}
+
+static bool skel_aio_force(struct vfs_handle_struct *handle,
+ struct files_struct *fsp)
+{
+ return SMB_VFS_NEXT_AIO_FORCE(handle, fsp);
+}
+
+static NTSTATUS skel_audit_file(struct vfs_handle_struct *handle,
+ struct smb_filename *file,
+ struct security_acl *sacl,
+ uint32_t access_requested,
+ uint32_t access_denied)
+{
+ return SMB_VFS_NEXT_AUDIT_FILE(handle,
+ file,
+ sacl,
+ access_requested,
+ access_denied);
+}
+
+static NTSTATUS skel_durable_cookie(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *cookie)
+{
+ return SMB_VFS_NEXT_DURABLE_COOKIE(handle,
+ fsp,
+ mem_ctx,
+ cookie);
+}
+
+static NTSTATUS skel_durable_disconnect(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const DATA_BLOB old_cookie,
+ TALLOC_CTX *mem_ctx,
+ DATA_BLOB *new_cookie)
+{
+ return SMB_VFS_NEXT_DURABLE_DISCONNECT(handle,
+ fsp,
+ old_cookie,
+ mem_ctx,
+ new_cookie);
+}
+
+static NTSTATUS skel_durable_reconnect(struct vfs_handle_struct *handle,
+ struct smb_request *smb1req,
+ struct smbXsrv_open *op,
+ const DATA_BLOB old_cookie,
+ TALLOC_CTX *mem_ctx,
+ struct files_struct **fsp,
+ DATA_BLOB *new_cookie)
+{
+ return SMB_VFS_NEXT_DURABLE_RECONNECT(handle,
+ smb1req,
+ op,
+ old_cookie,
+ mem_ctx,
+ fsp,
+ new_cookie);
+}
+
+/* VFS operations structure */
+
+static struct vfs_fn_pointers skel_transparent_fns = {
+ /* Disk operations */
+
+ .connect_fn = skel_connect,
+ .disconnect_fn = skel_disconnect,
+ .disk_free_fn = skel_disk_free,
+ .get_quota_fn = skel_get_quota,
+ .set_quota_fn = skel_set_quota,
+ .get_shadow_copy_data_fn = skel_get_shadow_copy_data,
+ .statvfs_fn = skel_statvfs,
+ .fs_capabilities_fn = skel_fs_capabilities,
+ .get_dfs_referrals_fn = skel_get_dfs_referrals,
+ .create_dfs_pathat_fn = skel_create_dfs_pathat,
+ .read_dfs_pathat_fn = skel_read_dfs_pathat,
+ .snap_check_path_fn = skel_snap_check_path,
+ .snap_create_fn = skel_snap_create,
+ .snap_delete_fn = skel_snap_delete,
+
+ /* Directory operations */
+
+ .fdopendir_fn = skel_fdopendir,
+ .readdir_fn = skel_readdir,
+ .rewind_dir_fn = skel_rewind_dir,
+ .mkdirat_fn = skel_mkdirat,
+ .closedir_fn = skel_closedir,
+
+ /* File operations */
+
+ .openat_fn = skel_openat,
+ .create_file_fn = skel_create_file,
+ .close_fn = skel_close_fn,
+ .pread_fn = skel_pread,
+ .pread_send_fn = skel_pread_send,
+ .pread_recv_fn = skel_pread_recv,
+ .pwrite_fn = skel_pwrite,
+ .pwrite_send_fn = skel_pwrite_send,
+ .pwrite_recv_fn = skel_pwrite_recv,
+ .lseek_fn = skel_lseek,
+ .sendfile_fn = skel_sendfile,
+ .recvfile_fn = skel_recvfile,
+ .renameat_fn = skel_renameat,
+ .fsync_send_fn = skel_fsync_send,
+ .fsync_recv_fn = skel_fsync_recv,
+ .stat_fn = skel_stat,
+ .fstat_fn = skel_fstat,
+ .lstat_fn = skel_lstat,
+ .fstatat_fn = skel_fstatat,
+ .get_alloc_size_fn = skel_get_alloc_size,
+ .unlinkat_fn = skel_unlinkat,
+ .fchmod_fn = skel_fchmod,
+ .fchown_fn = skel_fchown,
+ .lchown_fn = skel_lchown,
+ .chdir_fn = skel_chdir,
+ .getwd_fn = skel_getwd,
+ .fntimes_fn = skel_fntimes,
+ .ftruncate_fn = skel_ftruncate,
+ .fallocate_fn = skel_fallocate,
+ .lock_fn = skel_lock,
+ .filesystem_sharemode_fn = skel_filesystem_sharemode,
+ .fcntl_fn = skel_fcntl,
+ .linux_setlease_fn = skel_linux_setlease,
+ .getlock_fn = skel_getlock,
+ .symlinkat_fn = skel_symlinkat,
+ .readlinkat_fn = skel_vfs_readlinkat,
+ .linkat_fn = skel_linkat,
+ .mknodat_fn = skel_mknodat,
+ .realpath_fn = skel_realpath,
+ .fchflags_fn = skel_fchflags,
+ .file_id_create_fn = skel_file_id_create,
+ .fs_file_id_fn = skel_fs_file_id,
+ .offload_read_send_fn = skel_offload_read_send,
+ .offload_read_recv_fn = skel_offload_read_recv,
+ .offload_write_send_fn = skel_offload_write_send,
+ .offload_write_recv_fn = skel_offload_write_recv,
+ .fget_compression_fn = skel_fget_compression,
+ .set_compression_fn = skel_set_compression,
+
+ .fstreaminfo_fn = skel_fstreaminfo,
+ .get_real_filename_at_fn = skel_get_real_filename_at,
+ .connectpath_fn = skel_connectpath,
+ .brl_lock_windows_fn = skel_brl_lock_windows,
+ .brl_unlock_windows_fn = skel_brl_unlock_windows,
+ .strict_lock_check_fn = skel_strict_lock_check,
+ .translate_name_fn = skel_translate_name,
+ .parent_pathname_fn = skel_parent_pathname,
+ .fsctl_fn = skel_fsctl,
+ .freaddir_attr_fn = skel_freaddir_attr,
+ .audit_file_fn = skel_audit_file,
+
+ /* DOS attributes. */
+ .get_dos_attributes_send_fn = skel_get_dos_attributes_send,
+ .get_dos_attributes_recv_fn = skel_get_dos_attributes_recv,
+ .fget_dos_attributes_fn = skel_fget_dos_attributes,
+ .fset_dos_attributes_fn = skel_fset_dos_attributes,
+
+ /* NT ACL operations. */
+
+ .fget_nt_acl_fn = skel_fget_nt_acl,
+ .fset_nt_acl_fn = skel_fset_nt_acl,
+
+ /* POSIX ACL operations. */
+
+ .sys_acl_get_fd_fn = skel_sys_acl_get_fd,
+ .sys_acl_blob_get_fd_fn = skel_sys_acl_blob_get_fd,
+ .sys_acl_set_fd_fn = skel_sys_acl_set_fd,
+ .sys_acl_delete_def_fd_fn = skel_sys_acl_delete_def_fd,
+
+ /* EA operations. */
+ .getxattrat_send_fn = skel_getxattrat_send,
+ .getxattrat_recv_fn = skel_getxattrat_recv,
+ .fgetxattr_fn = skel_fgetxattr,
+ .flistxattr_fn = skel_flistxattr,
+ .fremovexattr_fn = skel_fremovexattr,
+ .fsetxattr_fn = skel_fsetxattr,
+
+ /* aio operations */
+ .aio_force_fn = skel_aio_force,
+
+ /* durable handle operations */
+ .durable_cookie_fn = skel_durable_cookie,
+ .durable_disconnect_fn = skel_durable_disconnect,
+ .durable_reconnect_fn = skel_durable_reconnect,
+};
+
+static_decl_vfs;
+NTSTATUS vfs_skel_transparent_init(TALLOC_CTX *ctx)
+{
+ /*
+ * smb_vfs_assert_all_fns() is only needed in
+ * order to have a complete example.
+ *
+ * A transparent vfs module typically don't
+ * need to implement every calls.
+ */
+ smb_vfs_assert_all_fns(&skel_transparent_fns, "skel_transparent");
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "skel_transparent",
+ &skel_transparent_fns);
+}
diff --git a/examples/VFS/wscript_build b/examples/VFS/wscript_build
new file mode 100644
index 0000000..92fea70
--- /dev/null
+++ b/examples/VFS/wscript_build
@@ -0,0 +1,25 @@
+#!/usr/bin/env python
+
+bld.SAMBA3_MODULE('vfs_skel_opaque',
+ subsystem='vfs',
+ source='skel_opaque.c',
+ deps='samba-util',
+ init_function='',
+ internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_skel_opaque'),
+ enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_skel_opaque'))
+
+bld.SAMBA3_MODULE('vfs_skel_transparent',
+ subsystem='vfs',
+ source='skel_transparent.c',
+ deps='samba-util',
+ init_function='',
+ internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_skel_transparent'),
+ enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_skel_transparent'))
+
+bld.SAMBA3_MODULE('vfs_shadow_copy_test',
+ subsystem='vfs',
+ source='shadow_copy_test.c',
+ deps='samba-util',
+ init_function='',
+ internal_module=bld.SAMBA3_IS_STATIC_MODULE('vfs_shadow_copy_test'),
+ enabled=bld.SAMBA3_IS_ENABLED_MODULE('vfs_shadow_copy_test'))
diff --git a/examples/ad-bench/README b/examples/ad-bench/README
new file mode 100644
index 0000000..de6235f
--- /dev/null
+++ b/examples/ad-bench/README
@@ -0,0 +1,42 @@
+==========================
+Active Directory benchmark
+==========================
+
+Setup
+=====
+
+You need to modify settings.sh to point to the correct binaries for your
+platform. One thing you might want to do in order to be able to run the
+benchmark as a non-root user is to compile your own samba version with the
+--prefix configure option set to some location writeable by the user who will be
+running the benchmark. You then need to point the NET variable to the correct
+location.
+
+Most likely, you will also want to put the realm to kdc hostname mappings into
+krb5.conf and the hostname to IP address mappings for the kdcs to test into the
+hosts file, so you actually benchmark the AD speed, not DNS lookup speed.
+
+Running the benchmarks
+======================
+
+Per default, the benchmark looks for a file called runs.txt in the directory the
+benchmark is run from. (This is configurable in the settings.sh file)
+runs.txt contains the credentials and server names to connect to, one set of
+credentials/server per line. The format is as follows:
+
+user@REALM.EXAMPLE.COM%password:domain_controller_host_name
+
+License
+=======
+AD-Bench 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 3 of the License, or
+(at your option) any later version.
+
+AD-Bench 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 AD-Bench. If not, see <http://www.gnu.org/licenses/>.
diff --git a/examples/ad-bench/ad-bench.sh b/examples/ad-bench/ad-bench.sh
new file mode 100755
index 0000000..c4c2a4a
--- /dev/null
+++ b/examples/ad-bench/ad-bench.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+# AD-Bench main program, runs all the benchmarks
+#
+# Copyright (C) 2009 Kai Blin <kai@samba.org>
+#
+# This file is part of AD-Bench, an Active Directory benchmark tool
+#
+# AD-Bench 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 3 of the License, or
+# (at your option) any later version.
+#
+# AD-Bench 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 AD-Bench. If not, see <http://www.gnu.org/licenses/>.
+
+source $(dirname $0)/utils.sh
+
+if [ ! -f $RUNS ]; then
+ echo "Error: please fill in $RUNS"
+ echo "Sambple entries are"
+ echo "user@REALM.EXAMPLE.COM%password:domain_controller"
+ exit 1
+fi
+
+for run in $(cat $RUNS); do
+ echo "START RUN"
+ bash $(dirname $0)/time_kinit.sh $(echo $run | cut -d ":" -f 1)
+ bash $(dirname $0)/time_join.sh $(echo $run | cut -d ":" -f 1) $(echo $run | cut -d ":" -f 2)
+ bash $(dirname $0)/time_user.sh $(echo $run | cut -d ":" -f 1) $(echo $run | cut -d ":" -f 2)
+ bash $(dirname $0)/time_group.sh $(echo $run | cut -d ":" -f 1) $(echo $run | cut -d ":" -f 2)
+ bash $(dirname $0)/time_ldap.sh $(echo $run | cut -d ":" -f 1) $(echo $run | cut -d ":" -f 2)
+ echo "END RUN"
+done
diff --git a/examples/ad-bench/settings.sh b/examples/ad-bench/settings.sh
new file mode 100644
index 0000000..b4a68ae
--- /dev/null
+++ b/examples/ad-bench/settings.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+# AD-Bench settings
+#
+# Copyright (C) 2009 Kai Blin <kai@samba.org>
+#
+# This file is part of AD-Bench, an Active Directory benchmark tool
+#
+# AD-Bench 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 3 of the License, or
+# (at your option) any later version.
+#
+# AD-Bench 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 AD-Bench. If not, see <http://www.gnu.org/licenses/>.
+
+DATE=date
+BC=bc
+SED=sed
+DATE_FORMATSTR="+%s.%N"
+
+KINIT=kinit
+# MIT krb < 1.6
+KINIT_PARAM_OLD="--password-file=STDIN"
+# MIT krb >= 1.6
+KINIT_PARAM_NEW=""
+
+KDESTROY=kdestroy
+SEQ=seq
+
+NEW_KRB5CCNAME=/tmp/ad_test_ccname
+
+NET="${HOME}/samba/bin/net"
+CONFIG_FILE=$(dirname $0)/smb.conf
+
+RUNS=$(dirname $0)/runs.txt
diff --git a/examples/ad-bench/test_utils.sh b/examples/ad-bench/test_utils.sh
new file mode 100644
index 0000000..2580c9d
--- /dev/null
+++ b/examples/ad-bench/test_utils.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+# AD-Bench utility function tests
+#
+# Copyright (C) 2009 Kai Blin <kai@samba.org>
+#
+# This file is part of AD-Bench, an Active Directory benchmark tool
+#
+# AD-Bench 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 3 of the License, or
+# (at your option) any later version.
+#
+# AD-Bench 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 AD-Bench. If not, see <http://www.gnu.org/licenses/>.
+
+source $(dirname $0)/utils.sh
+
+INPUT="administrator@AD.EXAMPLE.COM%secret"
+echo "Principal for $INPUT is " $(get_principal $INPUT)
+echo "Password for $INPUT is " $(get_password $INPUT)
+echo "Realm for $INPUT is " $(get_realm $INPUT)
+echo "NT_DOM for $INPUT is " $(get_nt_dom $INPUT)
+
+echo "Padding 2: " $(pad_number 1 2) " 4: " $(pad_number 23 4)
diff --git a/examples/ad-bench/time_group.sh b/examples/ad-bench/time_group.sh
new file mode 100644
index 0000000..be47aac
--- /dev/null
+++ b/examples/ad-bench/time_group.sh
@@ -0,0 +1,131 @@
+#!/bin/bash
+# AD-Bench group add/remove benchmark
+#
+# Copyright (C) 2009 Kai Blin <kai@samba.org>
+#
+# This file is part of AD-Bench, an Active Directory benchmark tool
+#
+# AD-Bench 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 3 of the License, or
+# (at your option) any later version.
+#
+# AD-Bench 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 AD-Bench. If not, see <http://www.gnu.org/licenses/>.
+
+ITERATIONS=100
+
+source $(dirname $0)/utils.sh
+
+PRINCIPAL=$(get_principal $1)
+PASSWORD=$(get_password $1)
+REALM=$(get_realm $1)
+NT_DOM=$(get_nt_dom $1)
+SERVER=$2
+
+add_group()
+{
+ GROUP=$1
+ ${NET} ads group add "${GROUP}" -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null
+ RET=$?
+ if [ $RET -ne 0 ]; then
+ echo "${NET} ads group add returned error: $RET"
+ exit 1
+ fi
+}
+
+del_group()
+{
+ GROUP=$1
+ ${NET} ads group delete "${GROUP}" -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null
+ RET=$?
+ if [ $RET -ne 0 ]; then
+ echo "${NET} returned error: $RET"
+ exit 1
+ fi
+}
+
+enum_group()
+{
+ ${NET} ads group -k --configfile=$CONFIG_FILE -S $SERVER >/dev/null
+ RET=$?
+ if [ $RET -ne 0 ]; then
+ echo "${NET} returned error: $RET"
+ exit 1
+ fi
+}
+
+info_group()
+{
+ GROUP=$1
+ ${NET} ads group info "${GROUP}" -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null
+ RET=$?
+ if [ $RET -ne 0 ]; then
+ echo "${NET} returned error: $RET"
+ exit 1
+ fi
+}
+
+set_up()
+{
+ set_krb_env
+ setup_kinit
+ call_kinit "${PRINCIPAL}" "${PASSWORD}"
+ write_configfile "${REALM}" "${NT_DOM}"
+}
+
+tear_down()
+{
+ ${KDESTROY}
+ restore_krb_env
+}
+
+set_up
+
+echo -e "\tGROUP $SERVER"
+
+START_TIME=$(start_timer)
+
+echo -en "\t"
+for i in $(${SEQ} 1 $ITERATIONS); do
+ GROUP=$(echo "ad_test_$(pad_number $i 3)")
+ add_group $GROUP
+ echo -n "."
+done
+echo "done"
+
+enum_group
+
+# Requires winbind, which requires root perms to start. Skip this for now
+#echo -en "\t"
+#for i in $( ${SEQ} 1 $ITERATIONS ); do
+# GROUP=$( echo "ad_test_$(pad_number $i 3)" )
+# info_group $GROUP
+# echo -n "."
+#done
+#echo "done"
+
+echo -en "\t"
+for i in $(${SEQ} 1 $ITERATIONS); do
+ GROUP=$(echo "ad_test_$(pad_number $i 3)")
+ del_group $GROUP
+ echo -n "."
+done
+echo "done"
+
+STOP_TIME=$(stop_timer)
+
+TOTAL_TIME=$(total_time $START_TIME $STOP_TIME)
+
+echo -e "\t\ttotal time:\t\t${TOTAL_TIME}s"
+
+LOGINS_PER_MINUTE=$(iterations_per_minute $START_TIME $STOP_TIME $ITERATIONS)
+
+echo -e "\t\titerations/min:\t\t$LOGINS_PER_MINUTE"
+
+tear_down
diff --git a/examples/ad-bench/time_join.sh b/examples/ad-bench/time_join.sh
new file mode 100644
index 0000000..2545a9f
--- /dev/null
+++ b/examples/ad-bench/time_join.sh
@@ -0,0 +1,89 @@
+#!/bin/bash
+# AD-Bench Machine join/part benchmark
+#
+# Copyright (C) 2009 Kai Blin <kai@samba.org>
+#
+# This file is part of AD-Bench, an Active Directory benchmark tool
+#
+# AD-Bench 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 3 of the License, or
+# (at your option) any later version.
+#
+# AD-Bench 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 AD-Bench. If not, see <http://www.gnu.org/licenses/>.
+
+ITERATIONS=100
+
+source $(dirname $0)/utils.sh
+
+PRINCIPAL=$(get_principal $1)
+PASSWORD=$(get_password $1)
+REALM=$(get_realm $1)
+NT_DOM=$(get_nt_dom $1)
+
+join_domain()
+{
+ SERVER=$1
+ ${NET} ads join -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null
+ RET=$?
+ if [ $RET -ne 0 ]; then
+ echo "${NET} returned error: $RET"
+ exit 1
+ fi
+}
+
+leave_domain()
+{
+ SERVER=$1
+ ${NET} ads leave -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null
+ if [ $RET -ne 0 ]; then
+ echo "${NET} returned error: $RET"
+ exit 1
+ fi
+}
+
+set_up()
+{
+ set_krb_env
+ setup_kinit
+ call_kinit "${PRINCIPAL}" "${PASSWORD}"
+ write_configfile "${REALM}" "${NT_DOM}"
+}
+
+tear_down()
+{
+ ${KDESTROY}
+ restore_krb_env
+}
+
+set_up
+
+echo -e "\tJOIN $2"
+
+START_TIME=$(start_timer)
+
+echo -en "\t"
+for i in $(${SEQ} 1 $ITERATIONS); do
+ join_domain $2
+ leave_domain $2
+ echo -n "."
+done
+echo "done"
+
+STOP_TIME=$(stop_timer)
+
+TOTAL_TIME=$(total_time $START_TIME $STOP_TIME)
+
+echo -e "\t\ttotal time:\t\t${TOTAL_TIME}s"
+
+LOGINS_PER_MINUTE=$(iterations_per_minute $START_TIME $STOP_TIME $ITERATIONS)
+
+echo -e "\t\titerations/min:\t\t$LOGINS_PER_MINUTE"
+
+tear_down
diff --git a/examples/ad-bench/time_kinit.sh b/examples/ad-bench/time_kinit.sh
new file mode 100644
index 0000000..b2e0030
--- /dev/null
+++ b/examples/ad-bench/time_kinit.sh
@@ -0,0 +1,65 @@
+#!/bin/bash
+# AD-Bench Kerberos ticket benchmark
+#
+# Copyright (C) 2009 Kai Blin <kai@samba.org>
+#
+# This file is part of AD-Bench, an Active Directory benchmark tool.
+#
+# AD-Bench 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 3 of the License, or
+# (at your option) any later version.
+#
+# AD-Bench 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 AD-Bench. If not, see <http://www.gnu.org/licenses/>.
+
+# Iterations are set per test, so more time-consuming tests can be run less
+# often
+ITERATIONS=100
+
+source $(dirname $0)/utils.sh
+
+set_up()
+{
+ set_krb_env
+ setup_kinit
+}
+
+tear_down()
+{
+ restore_krb_env
+}
+
+set_up
+
+PRINCIPAL=$(get_principal $1)
+PASSWORD=$(get_password $1)
+
+echo -e "\tKINIT ${PRINCIPAL}"
+
+START_TIME=$(start_timer)
+
+echo -en "\t"
+for i in $(${SEQ} 1 $ITERATIONS); do
+ call_kinit "${PRINCIPAL}" "${PASSWORD}"
+ ${KDESTROY}
+ echo -n "."
+done
+echo "done"
+
+STOP_TIME=$(stop_timer)
+
+TOTAL_TIME=$(total_time $START_TIME $STOP_TIME)
+
+echo -e "\t\ttotal time:\t\t${TOTAL_TIME}s"
+
+LOGINS_PER_MINUTE=$(iterations_per_minute $START_TIME $STOP_TIME $ITERATIONS)
+
+echo -e "\t\titerations/min:\t\t$LOGINS_PER_MINUTE"
+
+tear_down
diff --git a/examples/ad-bench/time_ldap.sh b/examples/ad-bench/time_ldap.sh
new file mode 100644
index 0000000..4af6ef1
--- /dev/null
+++ b/examples/ad-bench/time_ldap.sh
@@ -0,0 +1,144 @@
+#!/bin/bash
+
+ITERATIONS=100
+
+source $(dirname $0)/utils.sh
+
+PRINCIPAL=$(get_principal $1)
+PASSWORD=$(get_password $1)
+REALM=$(get_realm $1)
+NT_DOM=$(get_nt_dom $1)
+SERVER=$2
+
+search_users()
+{
+ ${NET} ads search '(objectCategory=user)' sAMAccountName -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null
+ RET=$?
+ if [ $RET -ne 0 ]; then
+ echo "${NET} returned error: $RET"
+ exit 1
+ fi
+}
+
+search_groups()
+{
+ ${NET} ads search '(objectCategory=group)' sAMAccountName -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null
+ if [ $RET -ne 0 ]; then
+ echo "${NET} returned error: $RET"
+ exit 1
+ fi
+}
+
+search_computers()
+{
+ ${NET} ads search '(objectCategory=computer)' sAMAccountName -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null
+ if [ $RET -ne 0 ]; then
+ echo "${NET} returned error: $RET"
+ exit 1
+ fi
+}
+
+search_wildcard()
+{
+ ${NET} ads search '(objectCategory=*)' sAMAccountName -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null
+ if [ $RET -ne 0 ]; then
+ echo "${NET} returned error: $RET"
+ exit 1
+ fi
+}
+
+search_unindexed()
+{
+ ${NET} ads search '(description=Built-in account for adminstering the computer/domain)' sAMAccountName -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null
+ if [ $RET -ne 0 ]; then
+ echo "${NET} returned error: $RET"
+ exit 1
+ fi
+}
+
+set_up()
+{
+ set_krb_env
+ setup_kinit
+ call_kinit "${PRINCIPAL}" "${PASSWORD}"
+ write_configfile "${REALM}" "${NT_DOM}"
+}
+
+tear_down()
+{
+ ${KDESTROY}
+ restore_krb_env
+}
+
+set_up
+
+echo -e "\tSEARCH INDEXED $2"
+
+START_TIME=$(start_timer)
+
+echo -en "\t"
+for i in $(${SEQ} 1 $ITERATIONS); do
+ search_users
+ search_groups
+ search_computers
+ echo -n "."
+done
+echo "done"
+
+STOP_TIME=$(stop_timer)
+
+TOTAL_TIME=$(total_time $START_TIME $STOP_TIME)
+
+echo -e "\t\ttotal time:\t\t${TOTAL_TIME}s"
+
+LOGINS_PER_MINUTE=$(iterations_per_minute $START_TIME $STOP_TIME $ITERATIONS)
+
+echo -e "\t\titerations/min:\t\t$LOGINS_PER_MINUTE"
+
+########################
+
+echo -e "\tSEARCH WILDCARD $2"
+
+START_TIME=$(start_timer)
+
+echo -en "\t"
+for i in $(${SEQ} 1 $ITERATIONS); do
+ search_wildcard
+ echo -n "."
+done
+echo "done"
+
+STOP_TIME=$(stop_timer)
+
+TOTAL_TIME=$(total_time $START_TIME $STOP_TIME)
+
+echo -e "\t\ttotal time:\t\t${TOTAL_TIME}s"
+
+LOGINS_PER_MINUTE=$(iterations_per_minute $START_TIME $STOP_TIME $ITERATIONS)
+
+echo -e "\t\titerations/min:\t\t$LOGINS_PER_MINUTE"
+
+########################
+
+echo -e "\tSEARCH UNINDEXED $2"
+
+START_TIME=$(start_timer)
+
+echo -en "\t"
+for i in $(${SEQ} 1 $ITERATIONS); do
+ search_unindexed
+ echo -n "."
+done
+echo "done"
+
+STOP_TIME=$(stop_timer)
+
+TOTAL_TIME=$(total_time $START_TIME $STOP_TIME)
+
+echo -e "\t\ttotal time:\t\t${TOTAL_TIME}s"
+
+LOGINS_PER_MINUTE=$(iterations_per_minute $START_TIME $STOP_TIME $ITERATIONS)
+
+echo -e "\t\titerations/min:\t\t$LOGINS_PER_MINUTE"
+
+tear_down
diff --git a/examples/ad-bench/time_user.sh b/examples/ad-bench/time_user.sh
new file mode 100644
index 0000000..5fedb7a
--- /dev/null
+++ b/examples/ad-bench/time_user.sh
@@ -0,0 +1,131 @@
+#!/bin/bash
+# AD-Bench user add/remove benchmark
+#
+# Copyright (C) 2009 Kai Blin <kai@samba.org>
+#
+# This file is part of AD-Bench, an Active Directory benchmark tool
+#
+# AD-Bench 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 3 of the License, or
+# (at your option) any later version.
+#
+# AD-Bench 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 AD-Bench. If not, see <http://www.gnu.org/licenses/>.
+
+ITERATIONS=100
+
+source $(dirname $0)/utils.sh
+
+PRINCIPAL=$(get_principal $1)
+PASSWORD=$(get_password $1)
+REALM=$(get_realm $1)
+NT_DOM=$(get_nt_dom $1)
+SERVER=$2
+
+add_user()
+{
+ USER=$1
+ ${NET} ads user add "${USER}" 'Sup3rS3cr3T!' -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null
+ RET=$?
+ if [ $RET -ne 0 ]; then
+ echo "${NET} ads user add returned error: $RET"
+ exit 1
+ fi
+}
+
+del_user()
+{
+ USER=$1
+ ${NET} ads user delete "${USER}" -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null
+ RET=$?
+ if [ $RET -ne 0 ]; then
+ echo "${NET} returned error: $RET"
+ exit 1
+ fi
+}
+
+enum_user()
+{
+ ${NET} ads user -k --configfile=$CONFIG_FILE -S $SERVER >/dev/null
+ RET=$?
+ if [ $RET -ne 0 ]; then
+ echo "${NET} returned error: $RET"
+ exit 1
+ fi
+}
+
+info_user()
+{
+ USER=$1
+ ${NET} ads user info "${USER}" -k --configfile=$CONFIG_FILE -S ${SERVER} >/dev/null
+ RET=$?
+ if [ $RET -ne 0 ]; then
+ echo "${NET} returned error: $RET"
+ exit 1
+ fi
+}
+
+set_up()
+{
+ set_krb_env
+ setup_kinit
+ call_kinit "${PRINCIPAL}" "${PASSWORD}"
+ write_configfile "${REALM}" "${NT_DOM}"
+}
+
+tear_down()
+{
+ ${KDESTROY}
+ restore_krb_env
+}
+
+set_up
+
+echo -e "\tUSER $SERVER"
+
+START_TIME=$(start_timer)
+
+echo -en "\t"
+for i in $(${SEQ} 1 $ITERATIONS); do
+ USER=$(echo "ad_test_$(pad_number $i 3)")
+ add_user $USER
+ echo -n "."
+done
+echo "done"
+
+enum_user
+
+# Requires winbind, which requires root perms to start. Skip this for now
+#echo -en "\t"
+#for i in $( ${SEQ} 1 $ITERATIONS ); do
+# USER=$( echo "ad_test_$(pad_number $i 3)" )
+# info_user $USER
+# echo -n "."
+#done
+#echo "done"
+
+echo -en "\t"
+for i in $(${SEQ} 1 $ITERATIONS); do
+ USER=$(echo "ad_test_$(pad_number $i 3)")
+ del_user $USER
+ echo -n "."
+done
+echo "done"
+
+STOP_TIME=$(stop_timer)
+
+TOTAL_TIME=$(total_time $START_TIME $STOP_TIME)
+
+echo -e "\t\ttotal time:\t\t${TOTAL_TIME}s"
+
+LOGINS_PER_MINUTE=$(iterations_per_minute $START_TIME $STOP_TIME $ITERATIONS)
+
+echo -e "\t\titerations/min:\t\t$LOGINS_PER_MINUTE"
+
+tear_down
diff --git a/examples/ad-bench/utils.sh b/examples/ad-bench/utils.sh
new file mode 100644
index 0000000..5a7c015
--- /dev/null
+++ b/examples/ad-bench/utils.sh
@@ -0,0 +1,130 @@
+#!/bin/bash
+# AD-Bench utility functions
+#
+# Copyright (C) 2009 Kai Blin <kai@samba.org>
+#
+# This file is part of AD-Bench, an Active Directory benchmark tool
+#
+# AD-Bench 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 3 of the License, or
+# (at your option) any later version.
+#
+# AD-Bench 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 AD-Bench. If not, see <http://www.gnu.org/licenses/>.
+
+source $(dirname $0)/settings.sh
+
+start_timer()
+{
+ START_TIME=$(${DATE} ${DATE_FORMATSTR})
+ echo "$START_TIME"
+}
+
+stop_timer()
+{
+ STOP_TIME=$(${DATE} ${DATE_FORMATSTR})
+ echo "$STOP_TIME"
+}
+
+total_time()
+{
+ START_TIME=$1
+ END_TIME=$2
+ TOTAL_TIME=$(echo "scale=9;$STOP_TIME - $START_TIME" | ${BC})
+ echo "$TOTAL_TIME"
+}
+
+iterations_per_minute()
+{
+ START_TIME=$1
+ STOP_TIME=$2
+ TOTAL_RUNS=$3
+
+ TOTAL_TIME=$(total_time $START_TIME $STOP_TIME)
+
+ ITER_PER_MIN=$(echo "scale=2; 60 * $TOTAL_RUNS / $TOTAL_TIME" | ${BC})
+ echo "$ITER_PER_MIN"
+}
+
+get_principal()
+{
+ PRINCIPAL=$(echo $1 | ${SED} -e "s/\(.*\)%.*/\1/")
+ echo "$PRINCIPAL"
+}
+
+get_password()
+{
+ PASSWORD=$(echo $1 | ${SED} -e "s/.*%\(.*\)/\1/")
+ echo "$PASSWORD"
+}
+
+get_realm()
+{
+ REALM=$(echo $1 | ${SED} -e "s/.*@\(.*\)%.*/\1/")
+ echo "$REALM"
+}
+
+get_nt_dom()
+{
+ NT_DOM=$(echo $1 | ${SED} -e "s/.*@\([A-Z1-9-]*\)\..*/\1/")
+ echo "$NT_DOM"
+}
+
+set_krb_env()
+{
+ OLD_KRB5CCNAME="${KRB5CCNAME}"
+ KRB5CCNAME="${NEW_KRB5CCNAME}"
+ export KRB5CCNAME
+}
+
+restore_krb_env()
+{
+ KRB5CCNAME="${OLD_KRB5CCNAME}"
+ export KRB5CCNAME
+}
+
+setup_kinit()
+{
+ ${KINIT} --invalid 2>&1 | grep -q "password-file"
+ if [ $? -eq 0 ]; then
+ KINIT="${KINIT} ${KINIT_PARAM_OLD}"
+ else
+ KINIT="${KINIT} ${KINIT_PARAM_NEW}"
+ fi
+}
+
+write_configfile()
+{
+ REALM=$1
+ NT_DOM=$2
+ echo -e "[global]" >$CONFIG_FILE
+ echo -e "\trealm = $REALM" >>$CONFIG_FILE
+ echo -e "\tworkgroup = $NT_DOM" >>$CONFIG_FILE
+ echo -e "\tsecurity = ADS" >>$CONFIG_FILE
+}
+
+call_kinit()
+{
+ PRINCIPAL=$1
+ PASSWORD=$2
+ echo "${PASSWORD}" | ${KINIT} ${PRINCIPAL} >/dev/null
+ RET=$?
+ if [ $RET -ne 0 ]; then
+ echo "kinit returned an error: $RET"
+ exit 1
+ fi
+}
+
+pad_number()
+{
+ NUMBER=$1
+ DIGITS=$2
+ PADDED_NO=$(printf "%0${DIGITS}d" $NUMBER)
+ echo $PADDED_NO
+}
diff --git a/examples/auth/crackcheck/Makefile b/examples/auth/crackcheck/Makefile
new file mode 100644
index 0000000..edc7645
--- /dev/null
+++ b/examples/auth/crackcheck/Makefile
@@ -0,0 +1,25 @@
+# C compiler
+#CC=cc
+CC=gcc
+
+# Uncomment the following to add symbols to the code for debugging
+#DEBUG=-g -Wall
+
+# Optimization for the compiler
+#OPTIMIZE=
+OPTIMIZE=-O2
+
+CFLAGS= $(DEBUG) $(OPTIMIZE)
+
+OBJS = crackcheck.o
+LIBS = -lcrack
+
+crackcheck: $(OBJS)
+ $(CC) $(CFLAGS) -o crackcheck $(OBJS) $(LIBS)
+
+clean:
+ rm -f core *.o crackcheck
+
+install: crackcheck
+ install -m 555 crackcheck $(PREFIX)/sbin/crackcheck
+
diff --git a/examples/auth/crackcheck/crackcheck.c b/examples/auth/crackcheck/crackcheck.c
new file mode 100644
index 0000000..c303775
--- /dev/null
+++ b/examples/auth/crackcheck/crackcheck.c
@@ -0,0 +1,141 @@
+#include <memory.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <crack.h>
+#include <unistd.h>
+
+void usage(char *command) {
+ char *c, *comm;
+
+ comm = command;
+ while ((c = strrchr(comm, '/')) != NULL) {
+ comm = c + 1;
+ }
+
+ fprintf(stderr, "Usage: %s [-c] [-s] [-d <dictionary>]\n\n", comm);
+ fprintf(stderr, " -c enables NT like complexity checks\n");
+ fprintf(stderr, " -d <dictionary file> for cracklib\n");
+ fprintf(stderr, " -s simple check use NT like checks ONLY\n\n");
+ fprintf(stderr, "The password is read via stdin.\n\n");
+ exit(-1);
+}
+
+int complexity(char* passwd)
+{
+ /* TG 26.10.2005
+ * check password for complexity like MS Windows NT
+ */
+
+ int c_upper = 0;
+ int c_lower = 0;
+ int c_digit = 0;
+ int c_punct = 0;
+ int c_tot = 0;
+ int i, len;
+
+ if (!passwd) goto fail;
+ len = strlen(passwd);
+
+ for (i = 0; i < len; i++) {
+
+ if (c_tot >= 3) break;
+
+ if (isupper(passwd[i])) {
+ if (!c_upper) {
+ c_upper = 1;
+ c_tot += 1;
+ }
+ continue;
+ }
+ if (islower(passwd[i])) {
+ if (!c_lower) {
+ c_lower = 1;
+ c_tot += 1;
+ }
+ continue;
+ }
+ if (isdigit(passwd[i])) {
+ if (!c_digit) {
+ c_digit = 1;
+ c_tot += 1;
+ }
+ continue;
+ }
+ if (ispunct(passwd[i])) {
+ if (!c_punct) {
+ c_punct = 1;
+ c_tot += 1;
+ }
+ continue;
+ }
+ }
+
+ if ((c_tot) < 3) goto fail;
+ return 0;
+
+fail:
+ fprintf(stderr, "ERR Complexity check failed\n\n");
+ return -4;
+}
+
+int main(int argc, char **argv) {
+ extern char *optarg;
+ int c, ret, complex_check = 0, simplex_check = 0;
+
+ char f[256];
+ char *dictionary = NULL;
+ char *password;
+ const char *reply;
+
+ while ( (c = getopt(argc, argv, "d:cs")) != EOF){
+ switch(c) {
+ case 'd':
+ dictionary = strdup(optarg);
+ break;
+ case 'c':
+ complex_check = 1;
+ break;
+ case 's':
+ complex_check = 1;
+ simplex_check = 1;
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+
+ if (!simplex_check && dictionary == NULL) {
+ fprintf(stderr, "ERR - Missing cracklib dictionary\n\n");
+ usage(argv[0]);
+ }
+
+ fflush(stdin);
+ password = fgets(f, sizeof(f), stdin);
+
+ if (password == NULL) {
+ fprintf(stderr, "ERR - Failed to read password\n\n");
+ exit(-2);
+ }
+
+ if (complex_check) {
+ ret = complexity(password);
+ if (ret) {
+ exit(ret);
+ }
+ }
+
+ if (simplex_check) {
+ exit(0);
+ }
+
+ reply = FascistCheck(password, dictionary);
+ if (reply != NULL) {
+ fprintf(stderr, "ERR - %s\n\n", reply);
+ exit(-3);
+ }
+
+ exit(0);
+}
+
diff --git a/examples/autofs/auto.smb b/examples/autofs/auto.smb
new file mode 100644
index 0000000..eb24cfa
--- /dev/null
+++ b/examples/autofs/auto.smb
@@ -0,0 +1,11 @@
+# automount points below /smb
+
+# This is an automounter map and it has the following format
+# key [ -mount-options-separated-by-comma ] location
+# Details may be found in the autofs(5) manpage
+
+# smb-servers
+supra_andreas -fstype=smb,username=andreas,password=foo ://supra/aheinrich
+supra_cspiel -fstype=smb,username=cspiel ://supra/cspiel
+phonon_andreas -fstype=smb,username=andreas ://phonon/andreas
+helium_cspiel -fstype=smb,username=cspiel ://helium/cspiel
diff --git a/examples/dce-dfs/README b/examples/dce-dfs/README
new file mode 100644
index 0000000..4aaba8b
--- /dev/null
+++ b/examples/dce-dfs/README
@@ -0,0 +1,4 @@
+this is a sample configuration file from Jim Doyle <doyle@oec.com> who
+did the DCE/DFS patches for Samba. It shows how to make DCE/DFS shares
+available.
+
diff --git a/examples/dce-dfs/smb.conf b/examples/dce-dfs/smb.conf
new file mode 100644
index 0000000..4221753
--- /dev/null
+++ b/examples/dce-dfs/smb.conf
@@ -0,0 +1,41 @@
+[global]
+ printing = bsd
+ printcap name = /etc/printcap
+ load printers = no
+ guest account = guest
+ log file = /usr/local/samba/var/log.%m
+ log level = 8
+
+[homes]
+ comment = Home Directories
+ browsable = no
+ read only = no
+ create mode = 0750
+
+[test]
+ comment = test stuff
+ path = /dept/home/testacct
+ valid users = testacct
+ public = no
+ writable = yes
+
+[namespace]
+ comment = DCE-DFS Global Root
+ path = /...
+ public = no
+ writable = yes
+
+[oecdfs]
+ comment = Corporate Cell
+ path = /.../corp.boston.oec.com/fs
+ browsable = no
+ read only = no
+ create mode = 0750
+
+[develdfs]
+ comment = Technology Development Cell
+ path = /.../devel.boston.oec.com/fs
+ browsable = no
+ read only = no
+ create mode = 0750
+
diff --git a/examples/fuse/README b/examples/fuse/README
new file mode 100644
index 0000000..a1f311d
--- /dev/null
+++ b/examples/fuse/README
@@ -0,0 +1,7 @@
+WARNING:
+
+This is experimental work-in-progress code, don't expect it to do
+anything sensible.
+
+Eventually this *might* turn into a fuse client filesystem. This is
+not a promise for anything.
diff --git a/examples/fuse/clifuse.c b/examples/fuse/clifuse.c
new file mode 100644
index 0000000..59af160
--- /dev/null
+++ b/examples/fuse/clifuse.c
@@ -0,0 +1,1591 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * fusermount smb2 client
+ * Copyright (C) Volker Lendecke 2016
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#define FUSE_USE_VERSION 26
+#define _FILE_OFFSET_BITS 64
+#include "fuse/fuse_lowlevel.h"
+
+#include "source3/include/includes.h"
+#include "client.h"
+#include "trans2.h"
+#include "libsmb/proto.h"
+#include "libsmb/clirap.h"
+#include "libsmb/cli_smb2_fnum.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "libcli/smb/smbXcli_base.h"
+#include "libcli/security/security.h"
+#include "clifuse.h"
+#include "lib/util/idtree.h"
+
+struct mount_state {
+ struct tevent_context *ev;
+ struct cli_state *cli;
+ bool done;
+
+ struct tevent_fd *fde;
+ struct tevent_signal *signal_ev;
+
+ struct fuse_chan *ch;
+ struct fuse_session *se;
+
+ size_t bufsize;
+ char *buf;
+
+ struct idr_context *ino_ctx;
+ TALLOC_CTX *ino_parent;
+};
+
+struct inode_state {
+ struct idr_context *ino_ctx;
+ fuse_ino_t ino;
+ char path[];
+};
+
+static int inode_state_destructor(struct inode_state *s);
+
+static struct inode_state *inode_state_init(TALLOC_CTX *mem_ctx,
+ struct idr_context *ino_ctx,
+ const char *path)
+{
+ struct inode_state *state;
+ size_t pathlen;
+ int ino;
+
+ pathlen = strlen(path);
+ state = talloc_size(
+ mem_ctx, offsetof(struct inode_state, path) + pathlen + 1);
+ if (state == NULL) {
+ return NULL;
+ }
+ talloc_set_name_const(state, "struct inode_state");
+
+ ino = idr_get_new_above(ino_ctx, state, 1, INT32_MAX);
+ if (ino == -1) {
+ TALLOC_FREE(state);
+ return NULL;
+ }
+
+ state->ino = ino;
+ state->ino_ctx = ino_ctx;
+ memcpy(state->path, path, pathlen + 1);
+
+ DBG_DEBUG("Creating ino %d for path %s\n", ino, path);
+
+ talloc_set_destructor(state, inode_state_destructor);
+
+ return state;
+}
+
+static struct inode_state *inode_state_new(struct mount_state *mstate,
+ const char *path)
+{
+ return inode_state_init(mstate->ino_parent, mstate->ino_ctx, path);
+}
+
+static int inode_state_destructor(struct inode_state *s)
+{
+ DBG_DEBUG("destroying inode %ju\n", (uintmax_t)s->ino);
+ idr_remove(s->ino_ctx, s->ino);
+ return 0;
+}
+
+struct ll_create_state {
+ struct mount_state *mstate;
+ fuse_req_t freq;
+ struct fuse_file_info fi;
+ char *path;
+};
+
+static void cli_ll_create_done(struct tevent_req *req);
+
+static void cli_ll_create(fuse_req_t freq, fuse_ino_t parent, const char *name,
+ mode_t mode, struct fuse_file_info *fi)
+{
+ struct mount_state *mstate = talloc_get_type_abort(
+ fuse_req_userdata(freq), struct mount_state);
+ struct ll_create_state *state;
+ struct inode_state *istate;
+ struct tevent_req *req;
+
+ DBG_DEBUG("parent=%ju, name=%s, mode=%x\n", (uintmax_t)parent,
+ name, (unsigned)mode);
+
+ istate = idr_find(mstate->ino_ctx, parent);
+ if (istate == NULL) {
+ fuse_reply_err(freq, ENOENT);
+ return;
+ }
+
+ state = talloc(mstate, struct ll_create_state);
+ if (state == NULL) {
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+ state->mstate = mstate;
+ state->freq = freq;
+ state->fi = *fi;
+
+ state->path = talloc_asprintf(state, "%s%s%s", istate->path,
+ strlen(istate->path) ? "\\": "",
+ name);
+ if (state->path == NULL) {
+ TALLOC_FREE(state);
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+
+ req = cli_smb2_create_fnum_send(
+ state,
+ mstate->ev,
+ mstate->cli, state->path,
+ (struct cli_smb2_create_flags){0},
+ SMB2_IMPERSONATION_IMPERSONATION,
+ FILE_GENERIC_READ|FILE_GENERIC_WRITE,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_CREATE,
+ FILE_NON_DIRECTORY_FILE,
+ NULL);
+ if (req == NULL) {
+ TALLOC_FREE(state);
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(req, cli_ll_create_done, state);
+}
+
+static void cli_ll_create_done(struct tevent_req *req)
+{
+ struct ll_create_state *state = tevent_req_callback_data(
+ req, struct ll_create_state);
+ struct fuse_entry_param e;
+ struct inode_state *ino;
+ uint16_t fnum;
+ NTSTATUS status;
+
+ status = cli_smb2_create_fnum_recv(req, &fnum, NULL, NULL, NULL, NULL);
+ TALLOC_FREE(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ fuse_reply_err(state->freq, map_errno_from_nt_status(status));
+ return;
+ }
+
+ state->fi.fh = fnum;
+ state->fi.direct_io = 0;
+ state->fi.keep_cache = 0;
+
+ ino = inode_state_new(state->mstate, state->path);
+ if (ino == NULL) {
+ fuse_reply_err(state->freq, ENOMEM);
+ return;
+ }
+
+ e = (struct fuse_entry_param) {
+ .ino = ino->ino,
+ .generation = 1, /* FIXME */
+ .attr_timeout = 1.0,
+ .entry_timeout = 1.0
+ };
+
+ fuse_reply_create(state->freq, &e, &state->fi);
+
+ TALLOC_FREE(state);
+}
+
+struct cli_get_unixattr_state {
+ struct tevent_context *ev;
+ struct cli_state *cli;
+ uint64_t fid_persistent;
+ uint64_t fid_volatile;
+
+ struct timespec create_time;
+ struct timespec access_time;
+ struct timespec write_time;
+ struct timespec change_time;
+ uint32_t mode;
+ uint64_t ino;
+ uint64_t size;
+};
+
+static void cli_get_unixattr_opened(struct tevent_req *subreq);
+static void cli_get_unixattr_gotinfo(struct tevent_req *subreq);
+static void cli_get_unixattr_closed(struct tevent_req *subreq);
+
+
+static struct tevent_req *cli_get_unixattr_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ const char *path)
+{
+ struct tevent_req *req, *subreq;
+ struct cli_get_unixattr_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_get_unixattr_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->cli = cli;
+
+ subreq = smb2cli_create_send(
+ state, ev, cli->conn, cli->timeout, cli->smb2.session,
+ cli->smb2.tcon, path, SMB2_OPLOCK_LEVEL_NONE,
+ SMB2_IMPERSONATION_IMPERSONATION,
+ SYNCHRONIZE_ACCESS|FILE_READ_ATTRIBUTES, 0,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_OPEN, 0, NULL);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_get_unixattr_opened, req);
+
+ return req;
+}
+
+static void cli_get_unixattr_opened(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_get_unixattr_state *state = tevent_req_data(
+ req, struct cli_get_unixattr_state);
+ struct cli_state *cli = state->cli;
+ NTSTATUS status;
+
+ status = smb2cli_create_recv(
+ subreq,
+ &state->fid_persistent,
+ &state->fid_volatile,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ DBG_DEBUG("smb2cli_create_recv returned %s\n",
+ nt_errstr(status));
+ return;
+ }
+
+ subreq = smb2cli_query_info_send(
+ state,
+ state->ev,
+ cli->conn,
+ 0,
+ cli->smb2.session,
+ cli->smb2.tcon,
+ 1, /* in_info_type */
+ FSCC_FILE_ALL_INFORMATION, /* in_file_info_class */
+ 0xFFFF, /* in_max_output_length */
+ NULL, /* in_input_buffer */
+ 0, /* in_additional_info */
+ 0, /* in_flags */
+ state->fid_persistent,
+ state->fid_volatile);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, cli_get_unixattr_gotinfo, req);
+}
+
+static void cli_get_unixattr_gotinfo(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_get_unixattr_state *state = tevent_req_data(
+ req, struct cli_get_unixattr_state);
+ struct cli_state *cli = state->cli;
+ NTSTATUS status;
+ DATA_BLOB outbuf;
+
+ status = smb2cli_query_info_recv(subreq, state, &outbuf);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ DBG_DEBUG("smb2cli_query_info_recv returned %s\n",
+ nt_errstr(status));
+ return;
+ }
+
+ if (outbuf.length < 0x60) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ state->create_time = interpret_long_date(BVAL(outbuf.data, 0));
+ state->access_time = interpret_long_date(BVAL(outbuf.data, 0x8));
+ state->write_time = interpret_long_date(BVAL(outbuf.data, 0x10));
+ state->change_time = interpret_long_date(BVAL(outbuf.data, 0x18));
+ state->mode = IVAL(outbuf.data, 0x20);
+ state->size = BVAL(outbuf.data, 0x30);
+ state->ino = BVAL(outbuf.data, 0x40);
+
+ subreq = smb2cli_close_send(state, state->ev, cli->conn, 0,
+ cli->smb2.session, cli->smb2.tcon, 0,
+ state->fid_persistent,
+ state->fid_volatile);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, cli_get_unixattr_closed, req);
+}
+
+static void cli_get_unixattr_closed(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ NTSTATUS status;
+
+ status = smb2cli_close_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static NTSTATUS cli_get_unixattr_recv(struct tevent_req *req,
+ struct stat *st)
+{
+ struct cli_get_unixattr_state *state = tevent_req_data(
+ req, struct cli_get_unixattr_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+
+ if (state->mode & FILE_ATTRIBUTE_DIRECTORY) {
+ st->st_mode = (S_IFDIR | 0555);
+ st->st_nlink = 2;
+ } else {
+ st->st_mode = (S_IFREG | 0444);
+ st->st_nlink = 1;
+ }
+
+ st->st_size = state->size;
+ st->st_uid = getuid();
+ st->st_gid = getgid();
+ st->st_ino = state->ino;
+ st->st_atime = convert_timespec_to_time_t(state->access_time);
+ st->st_ctime = convert_timespec_to_time_t(state->change_time);
+ st->st_mtime = convert_timespec_to_time_t(state->write_time);
+
+ return NT_STATUS_OK;
+}
+
+struct cli_smb2_listdir_state {
+ struct tevent_context *ev;
+ struct smbXcli_conn *conn;
+ uint32_t timeout_msec;
+ struct smbXcli_session *session;
+ struct smbXcli_tcon *tcon;
+ uint8_t level;
+ uint8_t flags;
+ uint32_t file_index;
+ uint64_t fid_persistent;
+ uint64_t fid_volatile;
+ const char *mask;
+ uint32_t outbuf_len;
+
+ uint16_t attribute;
+ const char *mntpoint;
+ const char *pathname;
+ NTSTATUS (*fn)(const char *mntpoint, struct file_info *f,
+ const char *mask, void *private_data);
+ void *private_data;
+ bool processed_file;
+};
+
+static void cli_smb2_listdir_done(struct tevent_req *subreq);
+
+static struct tevent_req *cli_smb2_listdir_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXcli_conn *conn,
+ uint32_t timeout_msec,
+ struct smbXcli_session *session,
+ struct smbXcli_tcon *tcon,
+ uint8_t level,
+ uint8_t flags,
+ uint32_t file_index,
+ uint64_t fid_persistent,
+ uint64_t fid_volatile,
+ const char *mask,
+ uint32_t outbuf_len,
+ uint16_t attribute,
+ const char *mntpoint,
+ const char *pathname,
+ NTSTATUS (*fn)(const char *mntpoint, struct file_info *f,
+ const char *mask, void *private_data),
+ void *private_data)
+{
+ struct tevent_req *req, *subreq;
+ struct cli_smb2_listdir_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_smb2_listdir_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->conn = conn;
+ state->timeout_msec = timeout_msec;
+ state->session = session;
+ state->tcon = tcon;
+ state->level = level;
+ state->flags = flags;
+ state->file_index = file_index;
+ state->fid_persistent = fid_persistent;
+ state->fid_volatile = fid_volatile;
+ state->mask = mask;
+ state->outbuf_len = outbuf_len;
+ state->attribute = attribute;
+ state->mntpoint = mntpoint;
+ state->pathname = pathname;
+ state->fn = fn;
+ state->private_data = private_data;
+
+ subreq = smb2cli_query_directory_send(
+ state, state->ev, state->conn, state->timeout_msec,
+ state->session, state->tcon, state->level,
+ state->flags, state->file_index,
+ state->fid_persistent, state->fid_volatile,
+ state->mask, state->outbuf_len);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, cli_smb2_listdir_done, req);
+ return req;
+}
+
+static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data,
+ uint32_t dir_data_length,
+ struct file_info *finfo,
+ uint32_t *next_offset)
+{
+ size_t namelen = 0;
+ size_t slen = 0;
+ size_t ret = 0;
+
+ if (dir_data_length < 4) {
+ return NT_STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ *next_offset = IVAL(dir_data, 0);
+
+ if (*next_offset > dir_data_length) {
+ return NT_STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ if (*next_offset != 0) {
+ /* Ensure we only read what in this record. */
+ dir_data_length = *next_offset;
+ }
+
+ if (dir_data_length < 105) {
+ return NT_STATUS_INFO_LENGTH_MISMATCH;
+ }
+
+ finfo->btime_ts = interpret_long_date(BVAL(dir_data, 8));
+ finfo->atime_ts = interpret_long_date(BVAL(dir_data, 16));
+ finfo->mtime_ts = interpret_long_date(BVAL(dir_data, 24));
+ finfo->ctime_ts = interpret_long_date(BVAL(dir_data, 32));
+ finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0);
+ finfo->attr = IVAL(dir_data + 56, 0);
+ namelen = IVAL(dir_data + 60,0);
+ if (namelen > (dir_data_length - 104)) {
+ return NT_STATUS_INFO_LENGTH_MISMATCH;
+ }
+ slen = CVAL(dir_data + 68, 0);
+ if (slen > 24) {
+ return NT_STATUS_INFO_LENGTH_MISMATCH;
+ }
+ ret = pull_string_talloc(finfo,
+ dir_data,
+ FLAGS2_UNICODE_STRINGS,
+ &finfo->short_name,
+ dir_data + 70,
+ slen,
+ STR_UNICODE);
+ if (ret == (size_t)-1) {
+ /* Bad conversion. */
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ ret = pull_string_talloc(finfo,
+ dir_data,
+ FLAGS2_UNICODE_STRINGS,
+ &finfo->name,
+ dir_data + 104,
+ namelen,
+ STR_UNICODE);
+ if (ret == (size_t)-1) {
+ /* Bad conversion. */
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ return NT_STATUS_OK;
+}
+
+static void cli_smb2_listdir_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_smb2_listdir_state *state = tevent_req_data(
+ req, struct cli_smb2_listdir_state);
+ uint8_t *data;
+ uint32_t data_len;
+ uint32_t next_offset = 0;
+ NTSTATUS status;
+
+ status = smb2cli_query_directory_recv(subreq, state, &data,
+ &data_len);
+ TALLOC_FREE(subreq);
+ if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) {
+ tevent_req_done(req);
+ return;
+ }
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ do {
+ struct file_info *finfo;
+ bool ok;
+
+ finfo = talloc_zero(state, struct file_info);
+ if (tevent_req_nomem(finfo, req)) {
+ return;
+ }
+
+ status = parse_finfo_id_both_directory_info(
+ data, data_len, finfo, &next_offset);
+
+ DEBUG(10, ("%s: parse_finfo_id_both_directory_info returned "
+ "%s\n", __func__, nt_errstr(status)));
+
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ ok = dir_check_ftype(finfo->attr, state->attribute);
+
+ DEBUG(10, ("%s: dir_check_ftype(%u,%u) returned %u\n",
+ __func__, (unsigned)finfo->attr,
+ (unsigned)state->attribute, (unsigned)ok));
+
+ if (ok) {
+ /*
+ * Only process if attributes match. On SMB1 server
+ * does this, so on SMB2 we need to emulate in the
+ * client.
+ *
+ * https://bugzilla.samba.org/show_bug.cgi?id=10260
+ */
+ state->processed_file = true;
+
+ status = state->fn(state->mntpoint, finfo,
+ state->pathname,
+ state->private_data);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ }
+
+ TALLOC_FREE(finfo);
+
+ if (next_offset != 0) {
+ data += next_offset;
+ data_len -= next_offset;
+ }
+ } while (next_offset != 0);
+
+ subreq = smb2cli_query_directory_send(
+ state, state->ev, state->conn, state->timeout_msec,
+ state->session, state->tcon, state->level,
+ state->flags, state->file_index,
+ state->fid_persistent, state->fid_volatile,
+ state->mask, state->outbuf_len);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, cli_smb2_listdir_done, req);
+}
+
+static NTSTATUS cli_smb2_listdir_recv(struct tevent_req *req)
+{
+ struct cli_smb2_listdir_state *state = tevent_req_data(
+ req, struct cli_smb2_listdir_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+
+ if (!state->processed_file) {
+ /*
+ * In SMB1 findfirst returns NT_STATUS_NO_SUCH_FILE
+ * if no files match. Emulate this in the client.
+ */
+ return NT_STATUS_NO_SUCH_FILE;
+ }
+
+ return NT_STATUS_OK;
+}
+
+struct ll_lookup_state {
+ struct mount_state *mstate;
+ fuse_req_t freq;
+ char *path;
+};
+
+static void cli_ll_lookup_done(struct tevent_req *req);
+
+static void cli_ll_lookup(fuse_req_t freq, fuse_ino_t parent_ino,
+ const char *name)
+{
+ struct mount_state *mstate = talloc_get_type_abort(
+ fuse_req_userdata(freq), struct mount_state);
+ struct ll_lookup_state *state;
+ struct tevent_req *req;
+ struct inode_state *parent;
+
+ DBG_DEBUG("parent_ino=%ju, name=%s\n", (uintmax_t)parent_ino, name);
+
+ parent = idr_find(mstate->ino_ctx, parent_ino);
+ if (parent == NULL) {
+ DBG_WARNING("could not find parent\n");
+ fuse_reply_err(freq, ENOENT);
+ return;
+ }
+
+ state = talloc(mstate, struct ll_lookup_state);
+ if (state == NULL) {
+ DBG_WARNING("talloc failed\n");
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+ state->mstate = mstate;
+ state->freq = freq;
+
+ state->path = talloc_asprintf(state, "%s%s%s", parent->path,
+ strlen(parent->path) ? "\\": "",
+ name);
+ if (state->path == NULL) {
+ TALLOC_FREE(state);
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+
+ req = cli_get_unixattr_send(state, mstate->ev, mstate->cli,
+ state->path);
+ if (req == NULL) {
+ TALLOC_FREE(state);
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(req, cli_ll_lookup_done, state);
+}
+
+static void cli_ll_lookup_done(struct tevent_req *req)
+{
+ struct ll_lookup_state *state = tevent_req_callback_data(
+ req, struct ll_lookup_state);
+ struct stat sbuf = {0};
+ struct fuse_entry_param e;
+ struct inode_state *ino;
+ NTSTATUS status;
+
+ status = cli_get_unixattr_recv(req, &sbuf);
+ TALLOC_FREE(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ fuse_reply_err(state->freq, map_errno_from_nt_status(status));
+ return;
+ }
+
+ ino = inode_state_new(state->mstate, state->path);
+ if (ino == NULL) {
+ fuse_reply_err(state->freq, ENOMEM);
+ return;
+ }
+
+ e = (struct fuse_entry_param) {
+ .ino = ino->ino,
+ .attr = sbuf,
+ .generation = 1, /* FIXME */
+ .attr_timeout = 1.0,
+ .entry_timeout = 1.0
+ };
+
+ fuse_reply_entry(state->freq, &e);
+ TALLOC_FREE(state);
+}
+
+static void
+cli_ll_forget(fuse_req_t freq, fuse_ino_t ino, unsigned long nlookup)
+{
+ struct mount_state *mstate =
+ talloc_get_type_abort(fuse_req_userdata(freq),
+ struct mount_state);
+ struct inode_state *istate = NULL;
+
+ DBG_DEBUG("ino=%ju, nlookup=%lu\n", (uintmax_t)ino, nlookup);
+
+ istate = idr_find(mstate->ino_ctx, ino);
+ if (istate == NULL) {
+ fuse_reply_err(freq, ENOENT);
+ return;
+ }
+ TALLOC_FREE(istate);
+ fuse_reply_none(freq);
+}
+
+struct ll_getattr_state {
+ struct mount_state *mstate;
+ fuse_req_t freq;
+ struct fuse_file_info fi;
+};
+
+static void cli_ll_getattr_done(struct tevent_req *req);
+
+static void cli_ll_getattr(fuse_req_t freq, fuse_ino_t ino,
+ struct fuse_file_info *fi)
+{
+ struct mount_state *mstate = talloc_get_type_abort(
+ fuse_req_userdata(freq), struct mount_state);
+ struct ll_getattr_state *state;
+ struct inode_state *istate;
+ struct tevent_req *req;
+
+ DBG_DEBUG("ino=%ju\n", (uintmax_t)ino);
+
+ istate = idr_find(mstate->ino_ctx, ino);
+ if (istate == NULL) {
+ fuse_reply_err(freq, ENOENT);
+ return;
+ }
+
+ state = talloc(mstate, struct ll_getattr_state);
+ if (state == NULL) {
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+ state->mstate = mstate;
+ state->freq = freq;
+
+ req = cli_get_unixattr_send(state, mstate->ev, mstate->cli,
+ istate->path);
+ if (req == NULL) {
+ TALLOC_FREE(state);
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(req, cli_ll_getattr_done, state);
+}
+
+static void cli_ll_getattr_done(struct tevent_req *req)
+{
+ struct ll_getattr_state *state = tevent_req_callback_data(
+ req, struct ll_getattr_state);
+ struct stat st;
+ NTSTATUS status;
+ int ret;
+
+ status = cli_get_unixattr_recv(req, &st);
+ TALLOC_FREE(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ fuse_reply_err(state->freq, map_errno_from_nt_status(status));
+ return;
+ }
+
+ ret = fuse_reply_attr(state->freq, &st, 1);
+ if (ret != 0) {
+ DBG_NOTICE("fuse_reply_attr failed: %s\n",
+ strerror(-errno));
+ }
+}
+
+
+struct ll_open_state {
+ struct mount_state *mstate;
+ fuse_req_t freq;
+ struct fuse_file_info fi;
+};
+
+static void cli_ll_open_done(struct tevent_req *req);
+
+static void cli_ll_open(fuse_req_t freq, fuse_ino_t ino,
+ struct fuse_file_info *fi)
+{
+ struct mount_state *mstate = talloc_get_type_abort(
+ fuse_req_userdata(freq), struct mount_state);
+ struct ll_open_state *state;
+ struct inode_state *istate;
+ struct tevent_req *req;
+ uint32_t acc;
+
+ DBG_DEBUG("ino=%ju\n", (uintmax_t)ino);
+
+ istate = idr_find(mstate->ino_ctx, ino);
+ if (istate == NULL) {
+ fuse_reply_err(freq, ENOENT);
+ return;
+ }
+
+ state = talloc(mstate, struct ll_open_state);
+ if (state == NULL) {
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+ state->mstate = mstate;
+ state->freq = freq;
+ state->fi = *fi;
+
+ switch (fi->flags & O_ACCMODE) {
+ case O_RDONLY:
+ acc = FILE_GENERIC_READ;
+ break;
+ case O_WRONLY:
+ acc = FILE_GENERIC_WRITE;
+ break;
+ case O_RDWR:
+ acc = FILE_GENERIC_READ|FILE_GENERIC_WRITE;
+ break;
+ default:
+ fuse_reply_err(freq, EACCES);
+ return;
+ }
+
+ req = cli_smb2_create_fnum_send(
+ state,
+ mstate->ev,
+ mstate->cli,
+ istate->path,
+ (struct cli_smb2_create_flags){0},
+ SMB2_IMPERSONATION_IMPERSONATION,
+ acc,
+ FILE_ATTRIBUTE_NORMAL,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_OPEN,
+ FILE_NON_DIRECTORY_FILE,
+ NULL);
+ if (req == NULL) {
+ TALLOC_FREE(state);
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(req, cli_ll_open_done, state);
+}
+
+static void cli_ll_open_done(struct tevent_req *req)
+{
+ struct ll_open_state *state = tevent_req_callback_data(
+ req, struct ll_open_state);
+ uint16_t fnum;
+ NTSTATUS status;
+
+ status = cli_smb2_create_fnum_recv(req, &fnum, NULL, NULL, NULL, NULL);
+ TALLOC_FREE(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ fuse_reply_err(state->freq, map_errno_from_nt_status(status));
+ return;
+ }
+
+ state->fi.fh = fnum;
+ state->fi.direct_io = 0;
+ state->fi.keep_cache = 0;
+
+ fuse_reply_open(state->freq, &state->fi);
+
+ TALLOC_FREE(state);
+}
+
+struct ll_release_state {
+ struct mount_state *mstate;
+ fuse_req_t freq;
+ fuse_ino_t ino;
+};
+
+static void cli_ll_release_done(struct tevent_req *req);
+
+static void cli_ll_release(fuse_req_t freq, fuse_ino_t ino,
+ struct fuse_file_info *fi)
+{
+ struct mount_state *mstate = talloc_get_type_abort(
+ fuse_req_userdata(freq), struct mount_state);
+ struct ll_release_state *state;
+ struct inode_state *istate;
+ struct tevent_req *req;
+ uint16_t fnum;
+
+ DBG_DEBUG("ino=%ju\n", (uintmax_t)ino);
+
+ istate = idr_find(mstate->ino_ctx, ino);
+ if (istate == NULL) {
+ fuse_reply_err(freq, ENOENT);
+ return;
+ }
+
+ state = talloc(mstate, struct ll_release_state);
+ if (state == NULL) {
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+ state->mstate = mstate;
+ state->freq = freq;
+ state->ino = ino;
+
+ fnum = fi->fh;
+
+ req = cli_smb2_close_fnum_send(state, mstate->ev, mstate->cli, fnum, 0);
+ if (req == NULL) {
+ TALLOC_FREE(state);
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(req, cli_ll_release_done, state);
+}
+
+static void cli_ll_release_done(struct tevent_req *req)
+{
+ struct ll_release_state *state = tevent_req_callback_data(
+ req, struct ll_release_state);
+ struct inode_state *istate;
+ NTSTATUS status;
+
+ status = cli_smb2_close_fnum_recv(req);
+ TALLOC_FREE(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ fuse_reply_err(state->freq, map_errno_from_nt_status(status));
+ return;
+ }
+
+ istate = idr_find(state->mstate->ino_ctx, state->ino);
+ if (istate == NULL) {
+ DEBUG(1, ("%s: inode %ju vanished!\n", __func__,
+ (uintmax_t)state->ino));
+ }
+ TALLOC_FREE(istate);
+
+ fuse_reply_err(state->freq, 0);
+ TALLOC_FREE(state);
+}
+
+struct ll_read_state {
+ struct mount_state *mstate;
+ fuse_req_t freq;
+};
+
+static void cli_ll_read_done(struct tevent_req *req);
+
+static void cli_ll_read(fuse_req_t freq, fuse_ino_t ino,
+ size_t size, off_t off,
+ struct fuse_file_info *fi)
+{
+ struct mount_state *mstate = talloc_get_type_abort(
+ fuse_req_userdata(freq), struct mount_state);
+ struct ll_read_state *state;
+ struct tevent_req *req;
+ uint16_t fnum;
+
+ DBG_DEBUG("ino=%ju, size=%zu, off=%ju\n", (uintmax_t)ino,
+ size, (uintmax_t)off);
+
+ state = talloc(mstate, struct ll_read_state);
+ if (state == NULL) {
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+ state->mstate = mstate;
+ state->freq = freq;
+
+ fnum = fi->fh;
+
+ req = cli_smb2_read_send(state, mstate->ev, mstate->cli,
+ fnum, off, size);
+ if (req == NULL) {
+ TALLOC_FREE(state);
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(req, cli_ll_read_done, state);
+}
+
+static void cli_ll_read_done(struct tevent_req *req)
+{
+ struct ll_read_state *state = tevent_req_callback_data(
+ req, struct ll_read_state);
+ ssize_t received;
+ uint8_t *rcvbuf;
+ NTSTATUS status;
+
+ status = cli_smb2_read_recv(req, &received, &rcvbuf);
+ /* no talloc_free here yet */
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
+ received = 0;
+ rcvbuf = NULL;
+ status = NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ fuse_reply_err(state->freq, map_errno_from_nt_status(status));
+ return;
+ }
+ fuse_reply_buf(state->freq, (char *)rcvbuf, received);
+ TALLOC_FREE(state);
+}
+
+struct ll_write_state {
+ struct mount_state *mstate;
+ fuse_req_t freq;
+};
+
+static void cli_ll_write_done(struct tevent_req *req);
+
+static void cli_ll_write(fuse_req_t freq, fuse_ino_t ino, const char *buf,
+ size_t size, off_t off, struct fuse_file_info *fi)
+{
+ struct mount_state *mstate = talloc_get_type_abort(
+ fuse_req_userdata(freq), struct mount_state);
+ struct ll_write_state *state;
+ struct tevent_req *req;
+ uint16_t fnum;
+
+ DBG_DEBUG("ino=%ju, size=%zu, off=%ju\n", (uintmax_t)ino,
+ size, (uintmax_t)off);
+
+ state = talloc(mstate, struct ll_write_state);
+ if (state == NULL) {
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+ state->mstate = mstate;
+ state->freq = freq;
+
+ fnum = fi->fh;
+
+ req = cli_smb2_write_send(state, mstate->ev, mstate->cli, fnum, 0,
+ (const uint8_t *)buf, off, size);
+ if (req == NULL) {
+ TALLOC_FREE(state);
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(req, cli_ll_write_done, state);
+}
+
+static void cli_ll_write_done(struct tevent_req *req)
+{
+ struct ll_write_state *state = tevent_req_callback_data(
+ req, struct ll_write_state);
+ size_t written;
+ NTSTATUS status;
+
+ status = cli_smb2_write_recv(req, &written);
+ /* no talloc_free here yet */
+ if (!NT_STATUS_IS_OK(status)) {
+ fuse_reply_err(state->freq, map_errno_from_nt_status(status));
+ return;
+ }
+ fuse_reply_write(state->freq, written);
+ TALLOC_FREE(state);
+}
+
+
+struct ll_dir_state {
+ uint64_t fid_persistent;
+ uint64_t fid_volatile;
+
+ struct file_info *finfos;
+ unsigned num_finfos, num_sent;
+};
+
+static bool ll_dir_state_add(struct ll_dir_state *dir_state,
+ const char *name)
+{
+ struct file_info *tmp, *finfo;
+
+ tmp = talloc_realloc(dir_state, dir_state->finfos,
+ struct file_info, dir_state->num_finfos+1);
+ if (tmp == NULL) {
+ return false;
+ }
+ dir_state->finfos = tmp;
+ finfo = &dir_state->finfos[dir_state->num_finfos];
+
+ ZERO_STRUCTP(finfo);
+
+ finfo->name = talloc_strdup(dir_state->finfos, name);
+ if (finfo->name == NULL) {
+ return false;
+ }
+ dir_state->num_finfos += 1;
+
+ return true;
+}
+
+struct ll_opendir_state {
+ struct mount_state *mstate;
+ fuse_req_t freq;
+ struct fuse_file_info fi;
+ struct ll_dir_state *dir_state;
+};
+
+static void cli_ll_opendir_done(struct tevent_req *req);
+
+static void cli_ll_opendir(fuse_req_t freq, fuse_ino_t ino,
+ struct fuse_file_info *fi)
+{
+ struct mount_state *mstate = talloc_get_type_abort(
+ fuse_req_userdata(freq), struct mount_state);
+ struct cli_state *cli = mstate->cli;
+ struct ll_opendir_state *state;
+ struct inode_state *istate;
+ struct tevent_req *req;
+
+ DBG_DEBUG("ino=%ju\n", (uintmax_t)ino);
+
+ istate = idr_find(mstate->ino_ctx, ino);
+ if (istate == NULL) {
+ fuse_reply_err(freq, ENOENT);
+ return;
+ }
+
+ state = talloc(mstate, struct ll_opendir_state);
+ if (state == NULL) {
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+ state->mstate = mstate;
+ state->freq = freq;
+ state->fi = *fi;
+
+ state->dir_state = talloc_zero(state, struct ll_dir_state);
+ if (state->dir_state == NULL) {
+ TALLOC_FREE(state);
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+
+ req = smb2cli_create_send(
+ state, mstate->ev, cli->conn, cli->timeout,
+ cli->smb2.session, cli->smb2.tcon, istate->path,
+ 0, SMB2_IMPERSONATION_IMPERSONATION,
+ FILE_GENERIC_READ, FILE_ATTRIBUTE_DIRECTORY,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_OPEN, FILE_DIRECTORY_FILE, NULL);
+ if (req == NULL) {
+ TALLOC_FREE(state);
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(req, cli_ll_opendir_done, state);
+}
+
+static void cli_ll_opendir_done(struct tevent_req *req)
+{
+ struct ll_opendir_state *state = tevent_req_callback_data(
+ req, struct ll_opendir_state);
+ NTSTATUS status;
+
+ status = smb2cli_create_recv(
+ req,
+ &state->dir_state->fid_persistent,
+ &state->dir_state->fid_volatile,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ TALLOC_FREE(req);
+
+ DEBUG(10, ("%s: smbcli_create_recv returned %s\n", __func__,
+ nt_errstr(status)));
+
+ if (!NT_STATUS_IS_OK(status)) {
+ fuse_reply_err(state->freq, map_errno_from_nt_status(status));
+ return;
+ }
+
+ state->fi.fh = (uint64_t)talloc_move(state->mstate, &state->dir_state);
+ state->fi.direct_io = 0;
+ state->fi.keep_cache = 0;
+
+ fuse_reply_open(state->freq, &state->fi);
+
+ TALLOC_FREE(state);
+}
+
+struct ll_readdir_state {
+ fuse_req_t freq;
+ struct ll_dir_state *dir_state;
+};
+
+static void cli_ll_readdir_done(struct tevent_req *subreq);
+static NTSTATUS cli_ll_readdir_one(const char *mnt, struct file_info *finfo,
+ const char *path, void *private_data);
+static void cli_ll_readdir_reply_one(fuse_req_t freq,
+ struct ll_dir_state *dir_state);
+
+static void cli_ll_readdir(fuse_req_t freq, fuse_ino_t ino, size_t size,
+ off_t off, struct fuse_file_info *fi)
+{
+ struct mount_state *mstate = talloc_get_type_abort(
+ fuse_req_userdata(freq), struct mount_state);
+ struct cli_state *cli = mstate->cli;
+ struct ll_dir_state *dir_state;
+ struct ll_readdir_state *state;
+ struct tevent_req *req;
+
+ DBG_DEBUG("ino=%ju, size=%zu, off=%ju\n", (uintmax_t)ino, size,
+ (uintmax_t)off);
+
+ dir_state = talloc_get_type_abort((void *)fi->fh, struct ll_dir_state);
+
+ if (dir_state->finfos != NULL) {
+ DBG_DEBUG("finfos=%p\n", dir_state->finfos);
+ cli_ll_readdir_reply_one(freq, dir_state);
+ return;
+ }
+
+ if (!ll_dir_state_add(dir_state, ".") ||
+ !ll_dir_state_add(dir_state, "..")) {
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+
+ state = talloc(mstate, struct ll_readdir_state);
+ if (state == NULL) {
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+ state->freq = freq;
+ state->dir_state = dir_state;
+
+ req = cli_smb2_listdir_send(
+ state, mstate->ev, cli->conn, cli->timeout,
+ cli->smb2.session, cli->smb2.tcon,
+ SMB2_FIND_ID_BOTH_DIRECTORY_INFO, 0, 0,
+ dir_state->fid_persistent, dir_state->fid_volatile,
+ "*", 0xffff,
+ FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_SYSTEM |
+ FILE_ATTRIBUTE_HIDDEN,
+ NULL, NULL, cli_ll_readdir_one, dir_state);
+ if (req == NULL) {
+ TALLOC_FREE(state);
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(req, cli_ll_readdir_done, state);
+}
+
+static void cli_ll_readdir_reply_one(fuse_req_t freq,
+ struct ll_dir_state *dir_state)
+{
+ struct file_info *finfo;
+ char buf[1024];
+ struct stat sbuf = {};
+ size_t buflen;
+
+ if (dir_state->num_finfos == dir_state->num_sent) {
+ DEBUG(10, ("%s: Done\n", __func__));
+ fuse_reply_buf(freq, NULL, 0);
+ return;
+ }
+
+ sbuf.st_mode = S_IFREG | 0755;
+ sbuf.st_ino = random(); /* FIXME :-) */
+ finfo = &dir_state->finfos[dir_state->num_sent];
+
+ DBG_DEBUG("Adding %s\n", finfo->name);
+
+ buflen = fuse_add_direntry(freq, buf, sizeof(buf),
+ finfo->name, &sbuf, 0);
+ fuse_reply_buf(freq, buf, buflen);
+ dir_state->num_sent += 1;
+ return;
+}
+
+static NTSTATUS cli_ll_readdir_one(const char *mnt, struct file_info *finfo,
+ const char *path, void *private_data)
+{
+ struct ll_dir_state *dir_state = talloc_get_type_abort(
+ private_data, struct ll_dir_state);
+
+ if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) {
+ DEBUG(10, ("%s: Ignoring %s\n", __func__, finfo->name));
+ return NT_STATUS_OK;
+ }
+
+ DBG_DEBUG("Got entry %s\n", finfo->name);
+
+ if (!ll_dir_state_add(dir_state, finfo->name)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ return NT_STATUS_OK;
+}
+
+static void cli_ll_readdir_done(struct tevent_req *req)
+{
+ struct ll_readdir_state *state = tevent_req_callback_data(
+ req, struct ll_readdir_state);
+ NTSTATUS status;
+
+ status = cli_smb2_listdir_recv(req);
+ TALLOC_FREE(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ fuse_reply_err(state->freq, map_errno_from_nt_status(status));
+ return;
+ }
+ cli_ll_readdir_reply_one(state->freq, state->dir_state);
+ TALLOC_FREE(state);
+}
+
+
+struct ll_releasedir_state {
+ struct mount_state *mstate;
+ fuse_req_t freq;
+ struct ll_dir_state *dir_state;
+};
+
+static void cli_ll_releasedir_done(struct tevent_req *req);
+
+static void cli_ll_releasedir(fuse_req_t freq, fuse_ino_t ino,
+ struct fuse_file_info *fi)
+{
+ struct mount_state *mstate = talloc_get_type_abort(
+ fuse_req_userdata(freq), struct mount_state);
+ struct cli_state *cli = mstate->cli;
+ struct ll_releasedir_state *state;
+ struct tevent_req *req;
+
+ DBG_DEBUG("ino=%ju\n", (uintmax_t)ino);
+
+ state = talloc(mstate, struct ll_releasedir_state);
+ if (state == NULL) {
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+ state->mstate = mstate;
+ state->freq = freq;
+
+ state->dir_state = talloc_get_type_abort(
+ (void *)fi->fh, struct ll_dir_state);
+
+ req = smb2cli_close_send(state, mstate->ev, cli->conn, cli->timeout,
+ cli->smb2.session, cli->smb2.tcon, 0,
+ state->dir_state->fid_persistent,
+ state->dir_state->fid_volatile);
+ if (req == NULL) {
+ TALLOC_FREE(state);
+ fuse_reply_err(freq, ENOMEM);
+ return;
+ }
+ tevent_req_set_callback(req, cli_ll_releasedir_done, state);
+}
+
+static void cli_ll_releasedir_done(struct tevent_req *req)
+{
+ struct ll_releasedir_state *state = tevent_req_callback_data(
+ req, struct ll_releasedir_state);
+ NTSTATUS status;
+
+ status = smb2cli_close_recv(req);
+ TALLOC_FREE(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ fuse_reply_err(state->freq, map_errno_from_nt_status(status));
+ return;
+ }
+ TALLOC_FREE(state->dir_state);
+ fuse_reply_err(state->freq, 0);
+ TALLOC_FREE(state);
+}
+
+static struct fuse_lowlevel_ops cli_ll_ops = {
+ .lookup = cli_ll_lookup,
+ .forget = cli_ll_forget,
+ .getattr = cli_ll_getattr,
+ .open = cli_ll_open,
+ .create = cli_ll_create,
+ .release = cli_ll_release,
+ .read = cli_ll_read,
+ .write = cli_ll_write,
+ .opendir = cli_ll_opendir,
+ .readdir = cli_ll_readdir,
+ .releasedir = cli_ll_releasedir,
+};
+
+static void fuse_chan_fd_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data);
+static void fuse_chan_signal_handler(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data);
+
+static int mount_state_destructor(struct mount_state *s);
+
+int do_mount(struct cli_state *cli, const char *mountpoint)
+{
+ struct mount_state *state;
+ struct inode_state *ino;
+ struct fuse_args args = { 0 };
+ int fd;
+ int ret = 1;
+
+ state = talloc_zero(talloc_tos(), struct mount_state);
+ if (state == NULL) {
+ fprintf(stderr, "talloc failed\n");
+ return 1;
+ }
+
+ state->ev = tevent_context_init(state);
+ if (state->ev == NULL) {
+ fprintf(stderr, "tevent_context_init failed\n");
+ TALLOC_FREE(state);
+ return 1;
+ }
+
+ state->ino_ctx = idr_init(state);
+ if (state->ino_ctx == NULL) {
+ fprintf(stderr, "idr_init failed\n");
+ TALLOC_FREE(state);
+ return 1;
+ }
+
+ state->ino_parent = talloc_new(state);
+ if (state->ino_parent == NULL) {
+ fprintf(stderr, "talloc_new failed\n");
+ TALLOC_FREE(state);
+ return 1;
+ }
+
+ talloc_set_destructor(state, mount_state_destructor);
+
+ ino = inode_state_new(state, "");
+ if (ino == NULL) {
+ fprintf(stderr, "inode_state_new failed\n");
+ TALLOC_FREE(state);
+ return 1;
+ }
+ if (ino->ino != FUSE_ROOT_ID) {
+ fprintf(stderr, "first inode gave %d, expected %d\n",
+ (int)ino->ino, FUSE_ROOT_ID);
+ TALLOC_FREE(state);
+ return 1;
+ }
+
+ state->cli = cli;
+
+ state->ch = fuse_mount(mountpoint, &args);
+ if (state->ch == NULL) {
+ perror("fuse_mount failed");
+ goto fail_free;
+ }
+
+ state->bufsize = fuse_chan_bufsize(state->ch);
+ state->buf = talloc_array(state, char, state->bufsize);
+ if (state->buf == NULL) {
+ fprintf(stderr, "talloc failed\n");
+ goto fail_unmount;
+ }
+
+ fd = fuse_chan_fd(state->ch);
+
+ state->fde = tevent_add_fd(state->ev, state, fd, TEVENT_FD_READ,
+ fuse_chan_fd_handler, state);
+ if (state->fde == NULL) {
+ fprintf(stderr, "tevent_add_fd failed\n");
+ goto fail_unmount;
+ }
+
+ state->signal_ev = tevent_add_signal(state->ev, state, SIGINT, 0,
+ fuse_chan_signal_handler, state);
+ if (state->signal_ev == NULL) {
+ fprintf(stderr, "tevent_add_signal failed\n");
+ goto fail_unmount;
+ }
+
+ state->se = fuse_lowlevel_new(&args, &cli_ll_ops, sizeof(cli_ll_ops),
+ state);
+ if (state->se == NULL) {
+ perror("fuse_lowlevel_new failed");
+ goto fail_unmount;
+ }
+
+ fuse_session_add_chan(state->se, state->ch);
+
+ while (!state->done) {
+ ret = tevent_loop_once(state->ev);
+ if (ret == -1) {
+ perror("tevent_loop_once failed");
+ break;
+ }
+ }
+
+ fuse_session_remove_chan(state->ch);
+ fuse_session_destroy(state->se);
+fail_unmount:
+ fuse_unmount(mountpoint, state->ch);
+fail_free:
+ TALLOC_FREE(state);
+ return ret;
+}
+
+static int mount_state_destructor(struct mount_state *s)
+{
+ TALLOC_FREE(s->ino_parent);
+ return 0;
+}
+
+
+static void fuse_chan_fd_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct mount_state *state = talloc_get_type_abort(
+ private_data, struct mount_state);
+ int recvd;
+
+ if ((flags & TEVENT_FD_READ) == 0) {
+ return;
+ }
+
+ recvd = fuse_chan_recv(&state->ch, state->buf, state->bufsize);
+ if (recvd <= 0) {
+ state->done = true;
+ return;
+ }
+ fuse_session_process(state->se, state->buf, recvd, state->ch);
+}
+
+static void fuse_chan_signal_handler(struct tevent_context *ev,
+ struct tevent_signal *se,
+ int signum,
+ int count,
+ void *siginfo,
+ void *private_data)
+{
+ struct mount_state *state = talloc_get_type_abort(
+ private_data, struct mount_state);
+ state->done = true;
+}
diff --git a/examples/fuse/clifuse.h b/examples/fuse/clifuse.h
new file mode 100644
index 0000000..62a2666
--- /dev/null
+++ b/examples/fuse/clifuse.h
@@ -0,0 +1,27 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * fusermount smb2 client
+ * Copyright (C) Volker Lendecke 2016
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __EXAMPLES_FUSE_CLIFUSE_H__
+#define __EXAMPLES_FUSE_CLIFUSE_H__
+
+struct cli_state;
+
+int do_mount(struct cli_state *cli, const char *mountpoint);
+
+#endif
diff --git a/examples/fuse/smb2mount.c b/examples/fuse/smb2mount.c
new file mode 100644
index 0000000..0594ced
--- /dev/null
+++ b/examples/fuse/smb2mount.c
@@ -0,0 +1,160 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * fusermount smb2 client
+ *
+ * Copyright (C) Volker Lendecke 2016
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "source3/include/includes.h"
+#include "popt.h"
+#include "lib/cmdline/cmdline.h"
+#include "lib/param/param.h"
+#include "client.h"
+#include "libsmb/proto.h"
+#include "clifuse.h"
+
+static struct cli_state *connect_one(struct cli_credentials *creds,
+ const char *server, int port,
+ const char *share)
+{
+ struct cli_state *c = NULL;
+ NTSTATUS nt_status;
+ uint32_t flags = 0;
+
+ nt_status = cli_full_connection_creds(&c, lp_netbios_name(), server,
+ NULL, port,
+ share, "?????",
+ creds,
+ flags);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ DBG_ERR("cli_full_connection failed! (%s)\n",
+ nt_errstr(nt_status));
+ return NULL;
+ }
+
+ return c;
+}
+
+int main(int argc, char *argv[])
+{
+ const char **argv_const = discard_const_p(const char *, argv);
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct loadparm_context *lp_ctx = NULL;
+ poptContext pc;
+ int opt, ret;
+ int port = 0;
+ char *unc, *mountpoint, *server, *share;
+ struct cli_state *cli;
+ struct cli_credentials *creds = NULL;
+ bool ok;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ POPT_COMMON_SAMBA
+ POPT_COMMON_CREDENTIALS
+ { "port", 'p', POPT_ARG_INT, &port, 'p', "Port to connect to",
+ "PORT" },
+ POPT_TABLEEND
+ };
+
+ smb_init_locale();
+
+ ok = samba_cmdline_init(frame,
+ SAMBA_CMDLINE_CONFIG_CLIENT,
+ false /* require_smbconf */);
+ if (!ok) {
+ DBG_ERR("Failed to init cmdline parser!\n");
+ TALLOC_FREE(frame);
+ exit(1);
+ }
+ lp_ctx = samba_cmdline_get_lp_ctx();
+ lpcfg_set_cmdline(lp_ctx, "client min protocol", "SMB2");
+ lpcfg_set_cmdline(lp_ctx, "client max protocol", "SMB3_11");
+
+ pc = samba_popt_get_context(getprogname(),
+ argc,
+ argv_const,
+ long_options,
+ 0);
+ if (pc == NULL) {
+ DBG_ERR("Failed to setup popt context!\n");
+ TALLOC_FREE(frame);
+ exit(1);
+ }
+
+ poptSetOtherOptionHelp(pc, "//server1/share1 mountpoint");
+
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch(opt) {
+ case 'p':
+ break;
+ default:
+ fprintf(stderr, "Unknown Option: %c\n", opt);
+ exit(1);
+ }
+ }
+
+ if (!poptPeekArg(pc)) {
+ poptPrintUsage(pc, stderr, 0);
+ return -1;
+ }
+ unc = talloc_strdup(frame, poptGetArg(pc));
+ if (unc == NULL) {
+ return -1;
+ }
+ string_replace(unc,'/','\\');
+
+ if (!poptPeekArg(pc)) {
+ poptPrintUsage(pc, stderr, 0);
+ return -1;
+ }
+ mountpoint = talloc_strdup(frame, poptGetArg(pc));
+ if (mountpoint == NULL) {
+ return -1;
+ }
+
+ poptFreeContext(pc);
+ samba_cmdline_burn(argc, argv);
+
+ server = talloc_strdup(frame, unc+2);
+ if (!server) {
+ return -1;
+ }
+ share = strchr_m(server,'\\');
+ if (!share) {
+ fprintf(stderr, "Invalid argument: %s\n", server);
+ return -1;
+ }
+
+ *share = 0;
+ share++;
+
+ creds = samba_cmdline_get_creds();
+
+ cli = connect_one(creds, server, port, share);
+ if (cli == NULL) {
+ return -1;
+ }
+
+ ret = do_mount(cli, mountpoint);
+ if (ret != 0) {
+ fprintf(stderr, "mount failed\n");
+ return -1;
+ }
+
+ TALLOC_FREE(frame);
+ return 0;
+}
diff --git a/examples/fuse/wscript b/examples/fuse/wscript
new file mode 100644
index 0000000..1c85139
--- /dev/null
+++ b/examples/fuse/wscript
@@ -0,0 +1,14 @@
+#!/usr/bin/env python
+
+def configure(conf):
+ # Check for fuse support
+ if conf.CHECK_CODE('''
+ #define FUSE_USE_VERSION 26
+ #define _FILE_OFFSET_BITS 64
+ #include "fuse/fuse_lowlevel.h"
+ int main(void) { return 0; }
+ ''', 'HAVE_FUSE_FUSE_LOWLEVEL_H',
+ addmain=False,
+ execute=False) and conf.CHECK_FUNCS_IN('fuse_mount',
+ 'fuse'):
+ conf.DEFINE('HAVE_FUSE', 1)
diff --git a/examples/fuse/wscript_build b/examples/fuse/wscript_build
new file mode 100644
index 0000000..ceef925
--- /dev/null
+++ b/examples/fuse/wscript_build
@@ -0,0 +1,7 @@
+#!/usr/bin/env python
+
+if bld.env.HAVE_FUSE:
+ bld.SAMBA_BINARY('smb2mount',
+ source='smb2mount.c clifuse.c',
+ deps='smbconf CMDLINE_S3 libsmb fuse',
+ install=False)
diff --git a/examples/libsmbclient/Makefile b/examples/libsmbclient/Makefile
new file mode 100644
index 0000000..08ff19a
--- /dev/null
+++ b/examples/libsmbclient/Makefile
@@ -0,0 +1,116 @@
+#
+CC = gcc
+
+SAMBA_INCL = -I/usr/local/samba/include
+EXTLIB_INCL = -I/usr/include/gtk-1.2 \
+ -I/usr/include/glib-1.2 \
+ -I/usr/lib/glib/include
+EXTLIB_INCL = `gtk-config --cflags`
+
+DEFS = -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
+CFLAGS = -O0 -g $(SAMBA_INCL) $(EXTLIB_INCL) $(DEFS)
+
+LDFLAGS = -L/usr/local/samba/lib \
+ -lldap -lkrb5 -lgssapi_krb5
+#LIBSMBCLIENT = /usr/local/samba/lib/libsmbclient.so
+LIBSMBCLIENT = -lwbclient -lsmbclient -ltalloc -ltdb -ldl -lresolv
+
+TESTS= testsmbc \
+ testacl \
+ testacl2 \
+ testacl3 \
+ testbrowse \
+ testbrowse2 \
+ teststat \
+ teststat2 \
+ teststat3 \
+ teststatvfs \
+ testfstatvfs \
+ testtruncate \
+ testchmod \
+ testutime \
+ testread \
+ testwrite
+
+# tree \
+
+all: $(TESTS) smbsh
+
+testsmbc: testsmbc.o
+ @echo Linking testsmbc
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT)
+
+tree: tree.o
+ @echo Linking tree
+ $(CC) `gtk-config --cflags` $(CFLAGS) $(LDFLAGS) -o $@ $< `gtk-config --libs` $(LIBSMBCLIENT)
+
+testacl: testacl.o
+ @echo Linking testacl
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt
+
+testacl2: testacl2.o
+ @echo Linking testacl2
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt
+
+testacl3: testacl3.o
+ @echo Linking testacl3
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt
+
+testbrowse: testbrowse.o
+ @echo Linking testbrowse
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt
+
+testbrowse2: testbrowse2.o
+ @echo Linking testbrowse2
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt
+
+teststat: teststat.o
+ @echo Linking teststat
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt
+
+teststat2: teststat2.o
+ @echo Linking teststat2
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt
+
+teststat3: teststat3.o
+ @echo Linking teststat3
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt
+
+teststatvfs: teststatvfs.o
+ @echo Linking teststatvfs
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt
+
+testfstatvfs: testfstatvfs.o
+ @echo Linking testfstatvfs
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt
+
+testtruncate: testtruncate.o
+ @echo Linking testtruncate
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt
+
+testchmod: testchmod.o
+ @echo Linking testchmod
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt
+
+testutime: testutime.o
+ @echo Linking testutime
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt
+
+testread: testread.o
+ @echo Linking testread
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt
+
+testwrite: testwrite.o
+ @echo Linking testwrite
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt
+
+testctx: testctx.o
+ @echo Linking testctx
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBSMBCLIENT) -lpopt
+
+smbsh:
+ make -C smbwrapper
+
+clean:
+ @rm -f *.o *~ $(TESTS)
+ @make -C smbwrapper clean
diff --git a/examples/libsmbclient/Makefile.internal.in b/examples/libsmbclient/Makefile.internal.in
new file mode 100644
index 0000000..d9f0fd3
--- /dev/null
+++ b/examples/libsmbclient/Makefile.internal.in
@@ -0,0 +1,138 @@
+# Makefile.internal.in for building the libsmbclient examples
+# from within a samba build.
+#
+# Use Makfile for building the examples with a libsmbclient
+# installed to /usr/local/samba
+
+CC = @CC@
+
+SAMBA_DIR = ../../source3
+SAMBA_INCLUDES = -I$(SAMBA_DIR)/include
+SAMBA_LIBPATH = -L$(SAMBA_DIR)/bin
+
+GTK_CFLAGS = `gtk-config --cflags`
+GTK_LIBS = `gtk-config --libs`
+
+#GTK_CFLAGS = `pkg-config gtk+-2.0 --cflags`
+#GTK_LIBS = `pkg-config gtk+-2.0 --libs`
+
+CCFLAGS = @CPPFLAGS@ @CFLAGS@ $(GTK_CFLAGS) $(SAMBA_INCLUDES)
+
+PICFLAG=@PICFLAG@
+LDFLAGS= $(SAMBA_LIBPATH) @PIE_LDFLAGS@ @LDFLAGS@
+
+EXTERNAL_LIBS = @LIBS@ @LDAP_LIBS@ @KRB5_LIBS@ @NSCD_LIBS@
+LIBSMBCLIENT_LIBS = -lwbclient -lsmbclient -ltalloc -ltdb -ldl -lresolv
+CMDLINE_LIBS = @POPTLIBS@
+LIBS = $(EXTERNAL_LIBS) $(LIBSMBCLIENT_LIBS)
+
+# Compile a source file. (.c --> .o)
+COMPILE_CC = $(CC) -I. $(CCFLAGS) $(PICFLAG) -c $< -o $@
+COMPILE = $(COMPILE_CC)
+
+MAKEDIR = || exec false; \
+ if test -d "$$dir"; then :; else \
+ echo mkdir "$$dir"; \
+ mkdir -p "$$dir" >/dev/null 2>&1 || \
+ test -d "$$dir" || \
+ mkdir "$$dir" || \
+ exec false; fi || exec false
+
+TESTS= testsmbc \
+ testacl \
+ testacl2 \
+ testacl3 \
+ testbrowse \
+ testbrowse2 \
+ teststat \
+ teststat2 \
+ teststat3 \
+ testtruncate \
+ testchmod \
+ testutime \
+ testread \
+ testwrite
+
+# tree \
+
+all: $(TESTS) smbsh
+
+.c.o:
+ @if (: >> $@ || : > $@) >/dev/null 2>&1; then rm -f $@; else \
+ dir=`echo $@ | sed 's,/[^/]*$$,,;s,^$$,.,'` $(MAKEDIR); fi
+ @echo Compiling $*.c
+ @$(COMPILE) && exit 0;\
+ echo "The following command failed:" 1>&2;\
+ echo "$(COMPILE_CC)" 1>&2;\
+ $(COMPILE_CC) >/dev/null 2>&1
+
+testsmbc: testsmbc.o
+ @echo Linking testsmbc
+ @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS)
+
+tree: tree.o
+ @echo Linking tree
+ @$(CC) $(GTK_CFLAGS) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(GTK_LIBS) $(LIBS)
+
+testacl: testacl.o
+ @echo Linking testacl
+ @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS)
+
+testacl2: testacl2.o
+ @echo Linking testacl2
+ @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS)
+
+testacl3: testacl3.o
+ @echo Linking testacl3
+ @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS)
+
+testbrowse: testbrowse.o
+ @echo Linking testbrowse
+ @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS)
+
+testbrowse2: testbrowse2.o
+ @echo Linking testbrowse2
+ @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS)
+
+teststat: teststat.o
+ @echo Linking teststat
+ @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS)
+
+teststat2: teststat2.o
+ @echo Linking teststat2
+ @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS)
+
+teststat3: teststat3.o
+ @echo Linking teststat3
+ @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS)
+
+testtruncate: testtruncate.o
+ @echo Linking testtruncate
+ @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS)
+
+testchmod: testchmod.o
+ @echo Linking testchmod
+ @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS)
+
+testutime: testutime.o
+ @echo Linking testutime
+ @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS)
+
+testread: testread.o
+ @echo Linking testread
+ @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS)
+
+testwrite: testwrite.o
+ @echo Linking testwrite
+ @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS)
+
+testctx: testctx.o
+ @echo Linking testctx
+ @$(CC) $(CCFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) $(CMDLINE_LIBS)
+
+smbsh:
+ make -C smbwrapper
+
+clean:
+ @rm -f *.o *~ $(TESTS)
+ @make -C smbwrapper clean
diff --git a/examples/libsmbclient/README b/examples/libsmbclient/README
new file mode 100644
index 0000000..c45dd8b
--- /dev/null
+++ b/examples/libsmbclient/README
@@ -0,0 +1,17 @@
+Some simple example programs for libsmbclient ...
+
+testsmbc.c is kinda broken as it has many hardcoded bits in it
+
+testbrowse.c opens a remote folder and displays its contents
+
+teststat.c allows comparing the results of smbc_stat() against a local stat() of
+the same file.
+
+tree.c is an example of how you might do some of these things with GTK+
+It needs lots of work but shows you some ways to use libsmbclient.
+
+smbwrapper implements the old smbsh/smbwrapper mechanism using libsmbclient, in
+such a way that it works on Linux
+
+Richard Sharpe, 17 May 2001
+Derrell Lipman, 30 Mar 2005
diff --git a/examples/libsmbclient/get_auth_data_fn.h b/examples/libsmbclient/get_auth_data_fn.h
new file mode 100644
index 0000000..9adb745
--- /dev/null
+++ b/examples/libsmbclient/get_auth_data_fn.h
@@ -0,0 +1,92 @@
+#include <stdlib.h>
+
+static void
+get_auth_data_fn(const char * pServer,
+ const char * pShare,
+ char * pWorkgroup,
+ int maxLenWorkgroup,
+ char * pUsername,
+ int maxLenUsername,
+ char * pPassword,
+ int maxLenPassword)
+{
+ char temp[128];
+ char server[256] = { '\0' };
+ char share[256] = { '\0' };
+ char workgroup[256] = { '\0' };
+ char username[256] = { '\0' };
+ char password[256] = { '\0' };
+ char *ret;
+
+ static int krb5_set = 1;
+
+ if (strcmp(server, pServer) == 0 &&
+ strcmp(share, pShare) == 0 &&
+ *workgroup != '\0' &&
+ *username != '\0')
+ {
+ strncpy(pWorkgroup, workgroup, maxLenWorkgroup - 1);
+ strncpy(pUsername, username, maxLenUsername - 1);
+ strncpy(pPassword, password, maxLenPassword - 1);
+ return;
+ }
+
+ if (krb5_set && getenv("KRB5CCNAME")) {
+ krb5_set = 0;
+ return;
+ }
+
+ fprintf(stdout, "Workgroup: [%s] ", pWorkgroup);
+ ret = fgets(temp, sizeof(temp), stdin);
+ if (ret == NULL) {
+ return;
+ }
+
+ if (temp[strlen(temp) - 1] == '\n') /* A new line? */
+ {
+ temp[strlen(temp) - 1] = '\0';
+ }
+
+ if (temp[0] != '\0')
+ {
+ strncpy(pWorkgroup, temp, maxLenWorkgroup - 1);
+ }
+
+ fprintf(stdout, "Username: [%s] ", pUsername);
+ ret = fgets(temp, sizeof(temp), stdin);
+ if (ret == NULL) {
+ return;
+ }
+
+ if (temp[strlen(temp) - 1] == '\n') /* A new line? */
+ {
+ temp[strlen(temp) - 1] = '\0';
+ }
+
+ if (temp[0] != '\0')
+ {
+ strncpy(pUsername, temp, maxLenUsername - 1);
+ }
+
+ fprintf(stdout, "Password: ");
+ ret = fgets(temp, sizeof(temp), stdin);
+ if (ret == NULL) {
+ return;
+ }
+
+ if (temp[strlen(temp) - 1] == '\n') /* A new line? */
+ {
+ temp[strlen(temp) - 1] = '\0';
+ }
+
+ if (temp[0] != '\0')
+ {
+ strncpy(pPassword, temp, maxLenPassword - 1);
+ }
+
+ strncpy(workgroup, pWorkgroup, sizeof(workgroup) - 1);
+ strncpy(username, pUsername, sizeof(username) - 1);
+ strncpy(password, pPassword, sizeof(password) - 1);
+
+ krb5_set = 1;
+}
diff --git a/examples/libsmbclient/testacl.c b/examples/libsmbclient/testacl.c
new file mode 100644
index 0000000..e0e4eeb
--- /dev/null
+++ b/examples/libsmbclient/testacl.c
@@ -0,0 +1,333 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <popt.h>
+#include "libsmbclient.h"
+#include "get_auth_data_fn.h"
+
+enum acl_mode
+{
+ SMB_ACL_LIST,
+ SMB_ACL_GET,
+ SMB_ACL_SET,
+ SMB_ACL_DELETE,
+ SMB_ACL_MODIFY,
+ SMB_ACL_ADD,
+ SMB_ACL_CHOWN,
+ SMB_ACL_CHGRP
+};
+
+
+int main(int argc, const char *argv[])
+{
+ int opt;
+ int flags = 0;
+ int debug = 0;
+ int numeric = 0;
+ int stat_and_retry = 0;
+ int full_time_names = 0;
+ enum acl_mode mode = SMB_ACL_LIST;
+ static const char *the_acl = NULL;
+ int ret;
+ char *p;
+ const char *debugstr;
+ char path[1024];
+ char value[1024];
+ poptContext pc;
+ struct stat st;
+ struct poptOption long_options[] =
+ {
+ POPT_AUTOHELP
+ {
+ .longName = "numeric",
+ .shortName = 'n',
+ .argInfo = POPT_ARG_NONE,
+ .arg = &numeric,
+ .val = 1,
+ .descrip = "Don't resolve sids or masks to names"
+ },
+ {
+ .longName = "debug",
+ .shortName = 'd',
+ .argInfo = POPT_ARG_INT,
+ .arg = &debug,
+ .val = 0,
+ .descrip = "Set debug level (0-100)"
+ },
+ {
+ .longName = "full_time_names",
+ .shortName = 'f',
+ .argInfo = POPT_ARG_NONE,
+ .arg = &full_time_names,
+ .val = 1,
+ .descrip = "Use new style xattr names, which include CREATE_TIME"
+ },
+ {
+ .longName = "delete",
+ .shortName = 'D',
+ .argInfo = POPT_ARG_STRING,
+ .arg = NULL,
+ .val = 'D',
+ .descrip = "Delete an acl",
+ .argDescrip = "ACL"
+ },
+ {
+ .longName = "modify",
+ .shortName = 'M',
+ .argInfo = POPT_ARG_STRING,
+ .arg = NULL,
+ .val = 'M',
+ .descrip = "Modify an acl",
+ .argDescrip = "ACL"
+ },
+ {
+ .longName = "add",
+ .shortName = 'a',
+ .argInfo = POPT_ARG_STRING,
+ .arg = NULL,
+ .val = 'a',
+ .descrip = "Add an acl",
+ .argDescrip = "ACL"
+ },
+ {
+ .longName = "set",
+ .shortName = 'S',
+ .argInfo = POPT_ARG_STRING,
+ .arg = NULL,
+ .val = 'S',
+ .descrip = "Set acls",
+ .argDescrip = "ACLS"
+ },
+ {
+ .longName = "chown",
+ .shortName = 'C',
+ .argInfo = POPT_ARG_STRING,
+ .arg = NULL,
+ .val = 'C',
+ .descrip = "Change ownership of a file",
+ .argDescrip = "USERNAME"
+ },
+ {
+ .longName = "chgrp",
+ .shortName = 'G',
+ .argInfo = POPT_ARG_STRING,
+ .arg = NULL,
+ .val = 'G',
+ .descrip = "Change group ownership of a file",
+ .argDescrip = "GROUPNAME"
+ },
+ {
+ .longName = "get",
+ .shortName = 'g',
+ .argInfo = POPT_ARG_STRING,
+ .arg = NULL,
+ .val = 'g',
+ .descrip = "Get a specific acl attribute",
+ .argDescrip = "ACL"
+ },
+ {
+ .longName = "stat_and_retry",
+ .shortName = 'R',
+ .argInfo = POPT_ARG_NONE,
+ .arg = &stat_and_retry,
+ .val = 1,
+ .descrip = "After 'get' do 'stat' and another 'get'"
+ },
+ POPT_TABLEEND
+ };
+
+ setbuf(stdout, NULL);
+
+ pc = poptGetContext("smbcacls", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "smb://server1/share1/filename");
+
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ switch (opt) {
+ case 'S':
+ the_acl = strdup(poptGetOptArg(pc));
+ mode = SMB_ACL_SET;
+ break;
+
+ case 'D':
+ the_acl = strdup(poptGetOptArg(pc));
+ mode = SMB_ACL_DELETE;
+ break;
+
+ case 'M':
+ the_acl = strdup(poptGetOptArg(pc));
+ mode = SMB_ACL_MODIFY;
+ break;
+
+ case 'a':
+ the_acl = strdup(poptGetOptArg(pc));
+ mode = SMB_ACL_ADD;
+ break;
+
+ case 'g':
+ the_acl = strdup(poptGetOptArg(pc));
+ mode = SMB_ACL_GET;
+ break;
+
+ case 'C':
+ the_acl = strdup(poptGetOptArg(pc));
+ mode = SMB_ACL_CHOWN;
+ break;
+
+ case 'G':
+ the_acl = strdup(poptGetOptArg(pc));
+ mode = SMB_ACL_CHGRP;
+ break;
+ }
+ }
+
+ /* Make connection to server */
+ if(!poptPeekArg(pc)) {
+ poptPrintUsage(pc, stderr, 0);
+ return 1;
+ }
+
+ strncpy(path, poptGetArg(pc), sizeof(path));
+ path[sizeof(path)-1] = '\0';
+
+ if (smbc_init(get_auth_data_fn, debug) != 0)
+ {
+ printf("Could not initialize smbc_ library\n");
+ return 1;
+ }
+
+ if (full_time_names) {
+ SMBCCTX *context = smbc_set_context(NULL);
+ smbc_setOptionFullTimeNames(context, 1);
+ }
+
+ /* Perform requested action */
+
+ switch(mode)
+ {
+ case SMB_ACL_LIST:
+ ret = smbc_listxattr(path, value, sizeof(value)-2);
+ if (ret < 0)
+ {
+ printf("Could not get attribute list for [%s] %d: %s\n",
+ path, errno, strerror(errno));
+ return 1;
+ }
+
+ /*
+ * The list of attributes has a series of null-terminated strings.
+ * The list of strings terminates with an extra null byte, thus two in
+ * a row. Ensure that our buffer, which is conceivably shorter than
+ * the list of attributes, actually ends with two null bytes in a row.
+ */
+ value[sizeof(value) - 2] = '\0';
+ value[sizeof(value) - 1] = '\0';
+ printf("Supported attributes:\n");
+ for (p = value; *p; p += strlen(p) + 1)
+ {
+ printf("\t%s\n", p);
+ }
+ break;
+
+ case SMB_ACL_GET:
+ do
+ {
+ if (the_acl == NULL)
+ {
+ if (numeric)
+ {
+ the_acl = "system.*";
+ }
+ else
+ {
+ the_acl = "system.*+";
+ }
+ }
+ ret = smbc_getxattr(path, the_acl, value, sizeof(value));
+ if (ret < 0)
+ {
+ printf("Could not get attributes for [%s] %d: %s\n",
+ path, errno, strerror(errno));
+ return 1;
+ }
+
+ printf("Attributes for [%s] are:\n%s\n", path, value);
+
+ if (stat_and_retry)
+ {
+ if (smbc_stat(path, &st) < 0)
+ {
+ perror("smbc_stat");
+ return 1;
+ }
+ }
+
+ --stat_and_retry;
+ } while (stat_and_retry >= 0);
+ break;
+
+ case SMB_ACL_ADD:
+ flags = SMBC_XATTR_FLAG_CREATE;
+ debugstr = "add attributes";
+ goto do_set;
+
+ case SMB_ACL_MODIFY:
+ flags = SMBC_XATTR_FLAG_REPLACE;
+ debugstr = "modify attributes";
+ goto do_set;
+
+ case SMB_ACL_CHOWN:
+ snprintf(value, sizeof(value),
+ "system.nt_sec_desc.owner%s:%s",
+ numeric ? "" : "+", the_acl);
+ the_acl = value;
+ debugstr = "chown owner";
+ goto do_set;
+
+ case SMB_ACL_CHGRP:
+ snprintf(value, sizeof(value),
+ "system.nt_sec_desc.group%s:%s",
+ numeric ? "" : "+", the_acl);
+ the_acl = value;
+ debugstr = "change group";
+ goto do_set;
+
+ case SMB_ACL_SET:
+ flags = 0;
+ debugstr = "set attributes";
+
+ do_set:
+ if ((p = strchr(the_acl, ':')) == NULL)
+ {
+ printf("Missing value. ACL must be name:value pair\n");
+ return 1;
+ }
+
+ *p++ = '\0';
+
+ ret = smbc_setxattr(path, the_acl, p, strlen(p), flags);
+ if (ret < 0)
+ {
+ printf("Could not %s for [%s] %d: %s\n",
+ debugstr, path, errno, strerror(errno));
+ return 1;
+ }
+ break;
+
+ case SMB_ACL_DELETE:
+ ret = smbc_removexattr(path, the_acl);
+ if (ret < 0)
+ {
+ printf("Could not remove attribute %s for [%s] %d:%s\n",
+ the_acl, path, errno, strerror(errno));
+ return 1;
+ }
+ break;
+
+ default:
+ printf("operation not yet implemented\n");
+ break;
+ }
+
+ return 0;
+}
diff --git a/examples/libsmbclient/testacl2.c b/examples/libsmbclient/testacl2.c
new file mode 100644
index 0000000..ee48b7b
--- /dev/null
+++ b/examples/libsmbclient/testacl2.c
@@ -0,0 +1,73 @@
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <popt.h>
+#include "libsmbclient.h"
+#include "get_auth_data_fn.h"
+
+enum acl_mode
+{
+ SMB_ACL_GET,
+ SMB_ACL_SET,
+ SMB_ACL_DELETE,
+ SMB_ACL_MODIFY,
+ SMB_ACL_ADD,
+ SMB_ACL_CHOWN,
+ SMB_ACL_CHGRP
+};
+
+
+int main(int argc, const char *argv[])
+{
+ int flags;
+ int debug = 0;
+ static char *the_acl = NULL;
+ int ret;
+ const char *debugstr;
+ char value[1024];
+ SMBCCTX *context;
+
+ if (smbc_init(get_auth_data_fn, debug) != 0)
+ {
+ printf("Could not initialize smbc_ library\n");
+ return 1;
+ }
+
+ context = smbc_set_context(NULL);
+ smbc_setOptionFullTimeNames(context, 1);
+
+ the_acl = strdup("system.nt_sec_desc.*");
+ ret = smbc_getxattr(argv[1], the_acl, value, sizeof(value));
+ if (ret < 0)
+ {
+ printf("Could not get attributes for [%s] %d: %s\n",
+ argv[1], errno, strerror(errno));
+ return 1;
+ }
+
+ printf("Attributes for [%s] are:\n%s\n", argv[1], value);
+
+ flags = 0;
+ debugstr = "set attributes (1st time)";
+
+ ret = smbc_setxattr(argv[1], the_acl, value, strlen(value), flags);
+ if (ret < 0)
+ {
+ printf("Could not %s for [%s] %d: %s\n",
+ debugstr, argv[1], errno, strerror(errno));
+ return 1;
+ }
+
+ flags = 0;
+ debugstr = "set attributes (2nd time)";
+
+ ret = smbc_setxattr(argv[1], the_acl, value, strlen(value), flags);
+ if (ret < 0)
+ {
+ printf("Could not %s for [%s] %d: %s\n",
+ debugstr, argv[1], errno, strerror(errno));
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/examples/libsmbclient/testacl3.c b/examples/libsmbclient/testacl3.c
new file mode 100644
index 0000000..e5ec2c8
--- /dev/null
+++ b/examples/libsmbclient/testacl3.c
@@ -0,0 +1,59 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <libsmbclient.h>
+#include "get_auth_data_fn.h"
+
+
+int main(int argc, char * argv[])
+{
+ int ret;
+ int debug = 0;
+ char value[2048];
+ char path[2048];
+ char * the_acl;
+ char * p;
+ SMBCCTX * context;
+
+ smbc_init(get_auth_data_fn, debug);
+
+ context = smbc_set_context(NULL);
+ smbc_setOptionFullTimeNames(context, 1);
+
+ for (;;)
+ {
+ fprintf(stdout, "Path: ");
+ *path = '\0';
+ p = fgets(path, sizeof(path) - 1, stdin);
+ if (p == NULL) {
+ printf("Error reading from stdin\n");
+ return 1;
+ }
+ if (strlen(path) == 0)
+ {
+ return 0;
+ }
+
+ p = path + strlen(path) - 1;
+ if (*p == '\n')
+ {
+ *p = '\0';
+ }
+
+ the_acl = strdup("system.nt_sec_desc.*+");
+ ret = smbc_getxattr(path, the_acl, value, sizeof(value));
+ if (ret < 0)
+ {
+ printf("Could not get attributes for [%s] %d: %s\n",
+ path, errno, strerror(errno));
+ return 1;
+ }
+
+ printf("Attributes for [%s] are:\n%s\n", path, value);
+ }
+
+ return 0;
+}
diff --git a/examples/libsmbclient/testbrowse.c b/examples/libsmbclient/testbrowse.c
new file mode 100644
index 0000000..2f2f54e
--- /dev/null
+++ b/examples/libsmbclient/testbrowse.c
@@ -0,0 +1,281 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <popt.h>
+#include <stdlib.h>
+#include <libsmbclient.h>
+#include "get_auth_data_fn.h"
+
+static void browse(char * path,
+ int scan,
+ int indent);
+
+
+static void
+get_auth_data_with_context_fn(SMBCCTX * context,
+ const char * pServer,
+ const char * pShare,
+ char * pWorkgroup,
+ int maxLenWorkgroup,
+ char * pUsername,
+ int maxLenUsername,
+ char * pPassword,
+ int maxLenPassword);
+
+int main(int argc, const char *argv[])
+{
+ int debug = 0;
+ int debug_stderr = 0;
+ int no_auth = 0;
+ int context_auth = 0;
+ int scan = 0;
+ int iterations = -1;
+ int opt;
+ char * p;
+ char buf[1024];
+ poptContext pc;
+ SMBCCTX * context;
+ struct poptOption long_options[] =
+ {
+ POPT_AUTOHELP
+ {
+ "debug", 'd', POPT_ARG_INT, &debug,
+ 0, "Set debug level", "integer"
+ },
+ {
+ "stderr", 'e', POPT_ARG_NONE, &debug_stderr,
+ 0, "Debug log to stderr instead of stdout", "integer"
+ },
+ {
+ "scan", 's', POPT_ARG_NONE, &scan,
+ 0, "Scan for servers and shares", "integer"
+ },
+ {
+ "iterations", 'i', POPT_ARG_INT, &iterations,
+ 0, "Iterations", "integer"
+ },
+ {
+ "noauth", 'A', POPT_ARG_NONE, &no_auth,
+ 0, "Do not request authentication data", "integer"
+ },
+ {
+ "contextauth", 'C', POPT_ARG_NONE, &context_auth,
+ 0, "Use new authentication function with context", "integer"
+ },
+ {0}
+ };
+
+ setbuf(stdout, NULL);
+
+ pc = poptGetContext("opendir", argc, argv, long_options, 0);
+
+ poptSetOtherOptionHelp(pc, "");
+
+ while ((opt = poptGetNextOpt(pc)) != -1) {
+ printf("Got option %d = %c\n", opt, opt);
+ switch (opt) {
+ }
+ }
+
+ /* Allocate a new context */
+ context = smbc_new_context();
+ if (!context) {
+ printf("Could not allocate new smbc context\n");
+ return 1;
+ }
+
+ /* If we're scanning, do no requests for authentication data */
+ if (scan) {
+ no_auth = 1;
+ }
+
+ /* Set mandatory options (is that a contradiction in terms?) */
+ smbc_setDebug(context, debug);
+ if (context_auth) {
+ smbc_setFunctionAuthDataWithContext(context,
+ get_auth_data_with_context_fn);
+ smbc_setOptionUserData(context, strdup("hello world"));
+ } else {
+ smbc_setFunctionAuthData(context, get_auth_data_fn);
+ }
+
+ smbc_setOptionUseKerberos(context, 1);
+ smbc_setOptionFallbackAfterKerberos(context, 1);
+
+ /* If we've been asked to log to stderr instead of stdout, ... */
+ if (debug_stderr) {
+ /* ... then set the option to do so */
+ smbc_setOptionDebugToStderr(context, 1);
+ }
+
+ /* Initialize the context using the previously specified options */
+ if (!smbc_init_context(context)) {
+ smbc_free_context(context, 0);
+ printf("Could not initialize smbc context\n");
+ return 1;
+ }
+
+ /* Tell the compatibility layer to use this context */
+ smbc_set_context(context);
+
+ if (scan)
+ {
+ for (; iterations != 0;) {
+ if (iterations > 0) {
+ iterations--;
+ }
+
+ snprintf(buf, sizeof(buf), "smb://");
+ browse(buf, scan, 0);
+ }
+ }
+ else
+ {
+ for (; iterations != 0;) {
+ if (iterations > 0) {
+ iterations--;
+ }
+
+ fputs("url: ", stdout);
+ p = fgets(buf, sizeof(buf), stdin);
+ if (! p)
+ {
+ break;
+ }
+
+ if ((p = strchr(buf, '\n')) != NULL)
+ {
+ *p = '\0';
+ }
+
+ browse(buf, scan, 0);
+ }
+ }
+
+ exit(0);
+}
+
+static void
+get_auth_data_with_context_fn(SMBCCTX * context,
+ const char * pServer,
+ const char * pShare,
+ char * pWorkgroup,
+ int maxLenWorkgroup,
+ char * pUsername,
+ int maxLenUsername,
+ char * pPassword,
+ int maxLenPassword)
+{
+ printf("Authenticating with context %p", context);
+ if (context != NULL) {
+ char *user_data = smbc_getOptionUserData(context);
+ printf(" with user data %s", user_data);
+ }
+ printf("\n");
+
+ get_auth_data_fn(pServer, pShare, pWorkgroup, maxLenWorkgroup,
+ pUsername, maxLenUsername, pPassword, maxLenPassword);
+}
+
+static void browse(char * path, int scan, int indent)
+{
+ char * p;
+ char buf[1024];
+ int dir;
+ struct stat st;
+ struct smbc_dirent * dirent;
+
+ if (! scan)
+ {
+ printf("Opening (%s)...\n", path);
+ }
+
+ if ((dir = smbc_opendir(path)) < 0)
+ {
+ printf("Could not open directory [%s] (%d:%s)\n",
+ path, errno, strerror(errno));
+ return;
+ }
+
+ while ((dirent = smbc_readdir(dir)) != NULL)
+ {
+ printf("%*.*s%-30s", indent, indent, "", dirent->name);
+
+ switch(dirent->smbc_type)
+ {
+ case SMBC_WORKGROUP:
+ printf("WORKGROUP");
+ break;
+
+ case SMBC_SERVER:
+ printf("SERVER");
+ break;
+
+ case SMBC_FILE_SHARE:
+ printf("FILE_SHARE");
+ break;
+
+ case SMBC_PRINTER_SHARE:
+ printf("PRINTER_SHARE");
+ break;
+
+ case SMBC_COMMS_SHARE:
+ printf("COMMS_SHARE");
+ break;
+
+ case SMBC_IPC_SHARE:
+ printf("IPC_SHARE");
+ break;
+
+ case SMBC_DIR:
+ printf("DIR");
+ break;
+
+ case SMBC_FILE:
+ printf("FILE");
+
+ p = path + strlen(path);
+ strcat(p, "/");
+ strcat(p+1, dirent->name);
+ if (smbc_stat(path, &st) < 0)
+ {
+ printf(" unknown size (reason %d: %s)",
+ errno, strerror(errno));
+ }
+ else
+ {
+ printf(" size %lu", (unsigned long) st.st_size);
+ }
+ *p = '\0';
+
+ break;
+
+ case SMBC_LINK:
+ printf("LINK");
+ break;
+ }
+
+ printf("\n");
+
+ if (scan &&
+ (dirent->smbc_type == SMBC_WORKGROUP ||
+ dirent->smbc_type == SMBC_SERVER))
+ {
+ /*
+ * don't append server name to workgroup; what we want is:
+ *
+ * smb://workgroup_name
+ * or
+ * smb://server_name
+ *
+ */
+ snprintf(buf, sizeof(buf), "smb://%s", dirent->name);
+ browse(buf, scan, indent + 2);
+ }
+ }
+
+ smbc_closedir(dir);
+}
diff --git a/examples/libsmbclient/testbrowse2.c b/examples/libsmbclient/testbrowse2.c
new file mode 100644
index 0000000..c1d5644
--- /dev/null
+++ b/examples/libsmbclient/testbrowse2.c
@@ -0,0 +1,169 @@
+/*
+ * Alternate testbrowse utility provided by Mikhail Kshevetskiy.
+ * This version tests use of multiple contexts.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libsmbclient.h>
+
+int debuglevel = 0;
+const char *workgroup = "NT";
+const char *username = "guest";
+const char *password = "";
+
+typedef struct smbitem smbitem;
+typedef int(*qsort_cmp)(const void *, const void *);
+
+struct smbitem{
+ smbitem *next;
+ int type;
+ char name[1];
+};
+
+static void smbc_auth_fn(
+ const char *server,
+ const char *share,
+ char *wrkgrp, int wrkgrplen,
+ char *user, int userlen,
+ char *passwd, int passwdlen){
+
+ (void) server;
+ (void) share;
+ (void) wrkgrp;
+ (void) wrkgrplen;
+
+ strncpy(wrkgrp, workgroup, wrkgrplen - 1); wrkgrp[wrkgrplen - 1] = 0;
+ strncpy(user, username, userlen - 1); user[userlen - 1] = 0;
+ strncpy(passwd, password, passwdlen - 1); passwd[passwdlen - 1] = 0;
+}
+
+static SMBCCTX* create_smbctx(void){
+ SMBCCTX *ctx;
+
+ if ((ctx = smbc_new_context()) == NULL) return NULL;
+
+ smbc_setDebug(ctx, debuglevel);
+ smbc_setFunctionAuthData(ctx, smbc_auth_fn);
+
+ if (smbc_init_context(ctx) == NULL){
+ smbc_free_context(ctx, 1);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+static void delete_smbctx(SMBCCTX* ctx){
+ smbc_getFunctionPurgeCachedServers(ctx)(ctx);
+ smbc_free_context(ctx, 1);
+}
+
+static smbitem* get_smbitem_list(SMBCCTX *ctx, char *smb_path){
+ SMBCFILE *fd;
+ struct smbc_dirent *dirent;
+ smbitem *list = NULL, *item;
+
+ if ((fd = smbc_getFunctionOpendir(ctx)(ctx, smb_path)) == NULL)
+ return NULL;
+ while((dirent = smbc_getFunctionReaddir(ctx)(ctx, fd)) != NULL){
+ size_t slen;
+ if (strcmp(dirent->name, "") == 0) continue;
+ if (strcmp(dirent->name, ".") == 0) continue;
+ if (strcmp(dirent->name, "..") == 0) continue;
+
+ slen = strlen(dirent->name)+1;
+ if ((item = malloc(sizeof(smbitem) + slen)) == NULL)
+ continue;
+
+ item->next = list;
+ item->type = dirent->smbc_type;
+ memcpy(item->name, dirent->name, slen);
+ list = item;
+ }
+ smbc_getFunctionClose(ctx)(ctx, fd);
+ return /* smbitem_list_sort */ (list);
+}
+
+static void print_smb_path(const char *group, const char *path){
+ if ((strlen(group) == 0) && (strlen(path) == 0)) printf("/\n");
+ else if (strlen(path) == 0) printf("/%s\n", group);
+ else{
+ if (strlen(group) == 0) group = "(unknown_group)";
+ printf("/%s/%s\n", group, path);
+ }
+}
+
+static void recurse(SMBCCTX *ctx, const char *smb_group, char *smb_path, int maxlen){
+ int len;
+ smbitem *list, *item;
+ SMBCCTX *ctx1;
+
+ len = strlen(smb_path);
+
+ list = get_smbitem_list(ctx, smb_path);
+ while(list != NULL){
+ switch(list->type){
+ case SMBC_WORKGROUP:
+ case SMBC_SERVER:
+ if (list->type == SMBC_WORKGROUP){
+ print_smb_path(list->name, "");
+ smb_group = list->name;
+ }
+ else print_smb_path(smb_group, list->name);
+
+ if (maxlen < 7 + strlen(list->name)) break;
+ strncpy(smb_path + 6, list->name, maxlen - 6);
+ smb_path[maxlen-1] = '\0';
+ if ((ctx1 = create_smbctx()) != NULL){
+ recurse(ctx1, smb_group, smb_path, maxlen);
+ delete_smbctx(ctx1);
+ }else{
+ recurse(ctx, smb_group, smb_path, maxlen);
+ smbc_getFunctionPurgeCachedServers(ctx)(ctx);
+ }
+ break;
+ case SMBC_FILE_SHARE:
+ case SMBC_DIR:
+ case SMBC_FILE:
+ if (maxlen < len + strlen(list->name) + 2) break;
+
+ smb_path[len] = '/';
+ strncpy(smb_path + len + 1, list->name, maxlen - len - 1);
+ smb_path[maxlen-1] = '\0';
+ print_smb_path(smb_group, smb_path + 6);
+ if (list->type != SMBC_FILE){
+ recurse(ctx, smb_group, smb_path, maxlen);
+ if (list->type == SMBC_FILE_SHARE)
+ smbc_getFunctionPurgeCachedServers(ctx)(ctx);
+ }
+ break;
+ }
+ item = list;
+ list = list->next;
+ free(item);
+ }
+ smb_path[len] = '\0';
+}
+
+int main(int argc, char *argv[]){
+ int i;
+ SMBCCTX *ctx;
+ char smb_path[32768] = "smb://";
+
+ if ((ctx = create_smbctx()) == NULL){
+ perror("Can't create samba context.");
+ return 1;
+ }
+
+ if (argc == 1) recurse(ctx, "", smb_path, sizeof(smb_path));
+ else for(i = 1; i < argc; i++){
+ strncpy(smb_path + 6, argv[i], sizeof(smb_path) - 7);
+ smb_path[sizeof(smb_path) - 1] = '\0';
+ recurse(ctx, "", smb_path, sizeof(smb_path));
+ }
+
+ delete_smbctx(ctx);
+ return 0;
+}
diff --git a/examples/libsmbclient/testchmod.c b/examples/libsmbclient/testchmod.c
new file mode 100644
index 0000000..2341e81
--- /dev/null
+++ b/examples/libsmbclient/testchmod.c
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <libsmbclient.h>
+#include "get_auth_data_fn.h"
+
+
+int main(int argc, char * argv[])
+{
+ int debug = 0;
+ int mode = 0666;
+ const char * pSmbPath = NULL;
+ struct stat st;
+
+ if (argc == 1)
+ {
+ pSmbPath = "smb://RANDOM/Public/small";
+ }
+ else if (argc == 2)
+ {
+ pSmbPath = argv[1];
+ }
+ else if (argc == 3)
+ {
+ pSmbPath = argv[1];
+ mode = (int) strtol(argv[2], NULL, 8);
+ }
+ else
+ {
+ printf("usage: "
+ "%s [ smb://path/to/file [ octal_mode ] ]\n",
+ argv[0]);
+ return 1;
+ }
+
+ smbc_init(get_auth_data_fn, debug);
+
+ if (smbc_stat(pSmbPath, &st) < 0)
+ {
+ perror("smbc_stat");
+ return 1;
+ }
+
+ printf("\nBefore chmod: mode = %04o\n", (unsigned int)st.st_mode);
+
+ if (smbc_chmod(pSmbPath, mode) < 0)
+ {
+ perror("smbc_chmod");
+ return 1;
+ }
+
+ if (smbc_stat(pSmbPath, &st) < 0)
+ {
+ perror("smbc_stat");
+ return 1;
+ }
+
+ printf("After chmod: mode = %04o\n", (unsigned int)st.st_mode);
+
+ return 0;
+}
diff --git a/examples/libsmbclient/testctx.c b/examples/libsmbclient/testctx.c
new file mode 100644
index 0000000..e410731
--- /dev/null
+++ b/examples/libsmbclient/testctx.c
@@ -0,0 +1,33 @@
+#include <libsmbclient.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+static void create_and_destroy_context (void)
+{
+ int i;
+ SMBCCTX *ctx;
+ ctx = smbc_new_context ();
+ /* Both should do the same thing */
+ smbc_setOptionDebugToStderr(ctx, 1);
+ smbc_option_set(ctx, strdup("debug_to_stderr"), 1);
+ smbc_setDebug(ctx, 1);
+ i = smbc_getDebug(ctx);
+ if (i != 1) {
+ printf("smbc_getDebug() did not return debug level set\n");
+ exit(1);
+ }
+ if (!smbc_getOptionDebugToStderr(ctx)) {
+ printf("smbc_setOptionDebugToStderr() did not stick\n");
+ exit(1);
+ }
+ smbc_init_context (ctx);
+ smbc_free_context (ctx, 1);
+}
+
+int main (int argc, char **argv)
+{
+ create_and_destroy_context ();
+ create_and_destroy_context ();
+ return 0;
+}
diff --git a/examples/libsmbclient/testfstatvfs.c b/examples/libsmbclient/testfstatvfs.c
new file mode 100644
index 0000000..9a4063e
--- /dev/null
+++ b/examples/libsmbclient/testfstatvfs.c
@@ -0,0 +1,134 @@
+#include <sys/types.h>
+#include <sys/statvfs.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <libsmbclient.h>
+#include "get_auth_data_fn.h"
+
+
+int main(int argc, char * argv[])
+{
+ int fd;
+ int ret;
+ int debug = 0;
+ char * p;
+ char path[2048];
+ struct stat statbuf;
+ struct statvfs statvfsbuf;
+
+ smbc_init(get_auth_data_fn, debug);
+
+ for (;;)
+ {
+ fprintf(stdout, "Path: ");
+ *path = '\0';
+ p = fgets(path, sizeof(path) - 1, stdin);
+ if (p == NULL) {
+ fprintf(stderr, "failed to read from stdin\n");
+ return 1;
+ }
+ if (strlen(path) == 0)
+ {
+ return 0;
+ }
+
+ p = path + strlen(path) - 1;
+ if (*p == '\n')
+ {
+ *p = '\0';
+ }
+
+ /* Determine if it's a file or a folder */
+ if (smbc_stat(path, &statbuf) < 0)
+ {
+ perror("smbc_stat");
+ continue;
+ }
+
+ if (S_ISREG(statbuf.st_mode))
+ {
+ if ((fd = smbc_open(path, O_RDONLY, 0)) < 0)
+ {
+ perror("smbc_open");
+ continue;
+ }
+ }
+ else
+ {
+ if ((fd = smbc_opendir(path)) < 0)
+ {
+ perror("smbc_opendir");
+ continue;
+ }
+ }
+
+ ret = smbc_fstatvfs(fd, &statvfsbuf);
+
+ smbc_close(fd);
+
+ if (ret < 0)
+ {
+ perror("fstatvfs");
+ }
+ else
+ {
+ printf("\n");
+ printf("Block Size: %lu\n", statvfsbuf.f_bsize);
+ printf("Fragment Size: %lu\n", statvfsbuf.f_frsize);
+ printf("Blocks: %llu\n",
+ (unsigned long long) statvfsbuf.f_blocks);
+ printf("Free Blocks: %llu\n",
+ (unsigned long long) statvfsbuf.f_bfree);
+ printf("Available Blocks: %llu\n",
+ (unsigned long long) statvfsbuf.f_bavail);
+ printf("Files : %llu\n",
+ (unsigned long long) statvfsbuf.f_files);
+ printf("Free Files: %llu\n",
+ (unsigned long long) statvfsbuf.f_ffree);
+ printf("Available Files: %llu\n",
+ (unsigned long long) statvfsbuf.f_favail);
+#ifdef HAVE_FSID_INT
+ printf("File System ID: %lu\n",
+ (unsigned long) statvfsbuf.f_fsid);
+#endif
+ printf("\n");
+
+ printf("Flags: 0x%lx\n", statvfsbuf.f_flag);
+ printf("Extended Features: ");
+
+ if (statvfsbuf.f_flag & SMBC_VFS_FEATURE_NO_UNIXCIFS)
+ {
+ printf("NO_UNIXCIFS ");
+ }
+ else
+ {
+ printf("unixcifs ");
+ }
+
+ if (statvfsbuf.f_flag & SMBC_VFS_FEATURE_CASE_INSENSITIVE)
+ {
+ printf("CASE_INSENSITIVE ");
+ }
+ else
+ {
+ printf("case_sensitive ");
+ }
+
+ if (statvfsbuf.f_flag & SMBC_VFS_FEATURE_DFS)
+ {
+ printf("DFS ");
+ }
+ else
+ {
+ printf("no_dfs ");
+ }
+
+ printf("\n");
+ }
+ }
+
+ return 0;
+}
diff --git a/examples/libsmbclient/testnotify.c b/examples/libsmbclient/testnotify.c
new file mode 100644
index 0000000..8760cf0
--- /dev/null
+++ b/examples/libsmbclient/testnotify.c
@@ -0,0 +1,82 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <libsmbclient.h>
+#include <inttypes.h>
+#include "get_auth_data_fn.h"
+
+static int notify_cb(const struct smbc_notify_callback_action *actions,
+ size_t num_actions, void *private_data)
+{
+ int *count = private_data;
+ size_t i;
+
+ printf("%zu\n", num_actions);
+
+ for (i=0; i<num_actions; i++) {
+ const struct smbc_notify_callback_action *a = &actions[i];
+ printf("%s: %"PRIu32"\n", a->filename, a->action);
+ }
+
+ *count -= 1;
+ if (*count < 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+int main(int argc, char * argv[])
+{
+ int fd;
+ int ret;
+ int debug = 0;
+ int saved_errno;
+ char path[2048];
+ char * p;
+ int count = 1000;
+
+ smbc_init(get_auth_data_fn, debug);
+
+ fprintf(stdout, "Path: ");
+ *path = '\0';
+ p = fgets(path, sizeof(path) - 1, stdin);
+ if (p == NULL) {
+ fprintf(stderr, "error reading from stdin\n");
+ return 1;
+ }
+ if (strlen(path) == 0) {
+ return 0;
+ }
+
+ p = path + strlen(path) - 1;
+ if (*p == '\n') {
+ *p = '\0';
+ }
+
+ fd = smbc_opendir(path);
+ if (fd < 0) {
+ perror("smbc_open");
+ return 1;
+ }
+
+ ret = smbc_notify(fd, 1,
+ SMBC_NOTIFY_CHANGE_SECURITY|
+ SMBC_NOTIFY_CHANGE_FILE_NAME,
+ 1000, notify_cb, &count);
+ if (ret < 0) {
+ saved_errno = errno;
+ }
+
+ smbc_close(fd);
+
+ if (ret < 0) {
+ errno = saved_errno;
+ perror("notify");
+ }
+
+ return 0;
+}
diff --git a/examples/libsmbclient/testread.c b/examples/libsmbclient/testread.c
new file mode 100644
index 0000000..d9722ad
--- /dev/null
+++ b/examples/libsmbclient/testread.c
@@ -0,0 +1,66 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <libsmbclient.h>
+#include "get_auth_data_fn.h"
+
+
+int main(int argc, char * argv[])
+{
+ int fd;
+ int ret;
+ int debug = 0;
+ int savedErrno;
+ char buffer[2048];
+ char path[2048];
+ char * p;
+
+ smbc_init(get_auth_data_fn, debug);
+
+ for (;;)
+ {
+ fprintf(stdout, "Path: ");
+ *path = '\0';
+ p = fgets(path, sizeof(path) - 1, stdin);
+ if (p == NULL) {
+ fprintf(stderr, "failed to read from stdin\n");
+ return 1;
+ }
+ if (strlen(path) == 0)
+ {
+ return 0;
+ }
+
+ p = path + strlen(path) - 1;
+ if (*p == '\n')
+ {
+ *p = '\0';
+ }
+
+ if ((fd = smbc_open(path, O_RDONLY, 0)) < 0)
+ {
+ perror("smbc_open");
+ continue;
+ }
+
+ do
+ {
+ ret = smbc_read(fd, buffer, sizeof(buffer));
+ savedErrno = errno;
+ if (ret > 0) fwrite(buffer, 1, ret, stdout);
+ } while (ret > 0);
+
+ smbc_close(fd);
+
+ if (ret < 0)
+ {
+ errno = savedErrno;
+ perror("read");
+ }
+ }
+
+ return 0;
+}
diff --git a/examples/libsmbclient/testsmbc.c b/examples/libsmbclient/testsmbc.c
new file mode 100644
index 0000000..a61d38e
--- /dev/null
+++ b/examples/libsmbclient/testsmbc.c
@@ -0,0 +1,291 @@
+/*
+ Unix SMB/CIFS implementation.
+ 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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/time.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "libsmbclient.h"
+#include "get_auth_data_fn.h"
+
+int main(int argc, char *argv[])
+{
+ int err, fd, dh1, 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(get_auth_data_fn, 10); /* Initialize things */
+
+ if (err < 0) {
+
+ fprintf(stderr, "Initializing the smbclient library ...: %s\n", strerror(errno));
+
+ }
+
+ if (argc > 1) {
+
+ if ((dh1 = smbc_opendir(argv[1]))<1) {
+
+ fprintf(stderr, "Could not open directory: %s: %s\n",
+ argv[1], strerror(errno));
+
+ exit(1);
+
+ }
+
+ fprintf(stdout, "Directory handle: %u\n", dh1);
+
+ /* 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;
+ dirc -= dsize;
+
+ }
+
+ dirp = (char *)dirbuf;
+
+ 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 ... */
+
+ memset(buff, '\0', sizeof(buff));
+ snprintf(buff, sizeof(buff), "%s", "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 %lu bytes to file: %s\n",
+ (unsigned long) 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, (unsigned int)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, (unsigned int)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/teststat.c b/examples/libsmbclient/teststat.c
new file mode 100644
index 0000000..079ac89
--- /dev/null
+++ b/examples/libsmbclient/teststat.c
@@ -0,0 +1,110 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <libsmbclient.h>
+#include <stdbool.h>
+#include "get_auth_data_fn.h"
+
+static const char *filetypestr(mode_t mode)
+{
+ if (S_ISREG(mode)) {
+ return "regular file";
+ }
+ if (S_ISDIR(mode)) {
+ return "directory";
+ }
+ if (S_ISFIFO(mode)) {
+ return "fifo";
+ }
+ if (S_ISLNK(mode)) {
+ return "symbolic link";
+ }
+ if (S_ISSOCK(mode)) {
+ return "socket";
+ }
+ if (S_ISCHR(mode)) {
+ return "character special file";
+ }
+ if (S_ISBLK(mode)) {
+ return "block special file";
+ }
+ return "unknown file type";
+}
+
+int main(int argc, char * argv[])
+{
+ SMBCCTX *ctx = NULL;
+ int debug = 0;
+ char m_time[32];
+ char c_time[32];
+ char a_time[32];
+ const char * pSmbPath = NULL;
+ const char * pLocalPath = NULL;
+ struct stat st;
+ int ret;
+
+ if (argc == 1) {
+ pSmbPath = "smb://RANDOM/Public/small";
+ pLocalPath = "/random/home/samba/small";
+ }
+ else if (argc == 2) {
+ pSmbPath = argv[1];
+ pLocalPath = NULL;
+ }
+ else if (argc == 3) {
+ pSmbPath = argv[1];
+ pLocalPath = argv[2];
+ } else {
+ printf("usage: %s [ smb://path/to/file "
+ "[ /nfs/or/local/path/to/file ] ]\n",
+ argv[0]);
+ return 1;
+ }
+
+ ctx = smbc_new_context();
+ if (ctx == NULL) {
+ perror("smbc_new_context failed");
+ return 1;
+ }
+
+ smbc_setOptionDebugToStderr(ctx, 1);
+ smbc_setDebug(ctx, debug);
+ smbc_init_context(ctx);
+ smbc_setFunctionAuthData(ctx, get_auth_data_fn);
+ smbc_setOptionPosixExtensions(ctx, true);
+
+ ret = smbc_getFunctionStat(ctx)(ctx, pSmbPath, &st);
+ if (ret < 0) {
+ perror("smbc_stat");
+ return 1;
+ }
+
+ printf("\nSAMBA\n mtime:%jd/%s ctime:%jd/%s atime:%jd/%s %s\n",
+ (intmax_t)st.st_mtime,
+ ctime_r(&st.st_mtime, m_time),
+ (intmax_t)st.st_ctime,
+ ctime_r(&st.st_ctime, c_time),
+ (intmax_t)st.st_atime,
+ ctime_r(&st.st_atime, a_time),
+ filetypestr(st.st_mode));
+
+ if (pLocalPath != NULL) {
+ ret = stat(pLocalPath, &st);
+ if (ret < 0) {
+ perror("stat");
+ return 1;
+ }
+
+ printf("LOCAL\n mtime:%jd/%s ctime:%jd/%s atime:%jd/%s %s\n",
+ (intmax_t)st.st_mtime,
+ ctime_r(&st.st_mtime, m_time),
+ (intmax_t)st.st_ctime,
+ ctime_r(&st.st_ctime, c_time),
+ (intmax_t)st.st_atime,
+ ctime_r(&st.st_atime, a_time),
+ filetypestr(st.st_mode));
+ }
+
+ return 0;
+}
diff --git a/examples/libsmbclient/teststat2.c b/examples/libsmbclient/teststat2.c
new file mode 100644
index 0000000..04994b7
--- /dev/null
+++ b/examples/libsmbclient/teststat2.c
@@ -0,0 +1,70 @@
+#include <libsmbclient.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include "get_auth_data_fn.h"
+
+/*
+ * This test is intended to ensure that the timestamps returned by
+ * libsmbclient are the same as timestamps returned by the local system. To
+ * test this, we assume a working Samba environment, and access the same
+ * file via SMB and locally (or NFS).
+ *
+ */
+
+
+static int gettime(const char * pUrl,
+ const char * pLocalPath);
+
+
+int main(int argc, char* argv[])
+{
+ if(argc != 3)
+ {
+ printf("usage: %s <file_url> <file_localpath>\n", argv[0]);
+ return 1;
+ }
+
+ gettime(argv[1], argv[2]);
+ return 0;
+}
+
+
+static int gettime(const char * pUrl,
+ const char * pLocalPath)
+{
+ struct stat st;
+ char m_time[32];
+ char c_time[32];
+ char a_time[32];
+
+ smbc_init(get_auth_data_fn, 0);
+
+ if (smbc_stat(pUrl, &st) < 0)
+ {
+ perror("smbc_stat");
+ return 1;
+ }
+
+ printf("SAMBA\n mtime:%lld/%s ctime:%lld/%s atime:%lld/%s\n",
+ (long long)st.st_mtime, ctime_r(&st.st_mtime, m_time),
+ (long long)st.st_ctime, ctime_r(&st.st_ctime, c_time),
+ (long long)st.st_atime, ctime_r(&st.st_atime, a_time));
+
+
+ /* check the stat on this file */
+ if (stat(pLocalPath, &st) < 0)
+ {
+ perror("stat");
+ return 1;
+ }
+
+ printf("LOCAL\n mtime:%lld/%s ctime:%lld/%s atime:%lld/%s\n",
+ (long long)st.st_mtime, ctime_r(&st.st_mtime, m_time),
+ (long long)st.st_ctime, ctime_r(&st.st_ctime, c_time),
+ (long long)st.st_atime, ctime_r(&st.st_atime, a_time));
+
+
+ return 0;
+}
diff --git a/examples/libsmbclient/teststat3.c b/examples/libsmbclient/teststat3.c
new file mode 100644
index 0000000..3669d70
--- /dev/null
+++ b/examples/libsmbclient/teststat3.c
@@ -0,0 +1,74 @@
+#include <libsmbclient.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include "get_auth_data_fn.h"
+
+/*
+ * This test is intended to ensure that the timestamps returned by
+ * libsmbclient using smbc_stat() are the same as those returned by
+ * smbc_fstat().
+ */
+
+
+int main(int argc, char* argv[])
+{
+ int fd;
+ struct stat st1;
+ struct stat st2;
+ char * pUrl = argv[1];
+
+ if(argc != 2)
+ {
+ printf("usage: %s <file_url>\n", argv[0]);
+ return 1;
+ }
+
+
+ smbc_init(get_auth_data_fn, 0);
+
+ if (smbc_stat(pUrl, &st1) < 0)
+ {
+ perror("smbc_stat");
+ return 1;
+ }
+
+ if ((fd = smbc_open(pUrl, O_RDONLY, 0)) < 0)
+ {
+ perror("smbc_open");
+ return 1;
+ }
+
+ if (smbc_fstat(fd, &st2) < 0)
+ {
+ perror("smbc_fstat");
+ return 1;
+ }
+
+ smbc_close(fd);
+
+#define COMPARE(name, field) \
+ if (st1.field != st2.field) \
+ { \
+ printf("Field " name " MISMATCH: st1=%lu, st2=%lu\n", \
+ (unsigned long) st1.field, \
+ (unsigned long) st2.field); \
+ }
+
+ COMPARE("st_dev", st_dev);
+ COMPARE("st_ino", st_ino);
+ COMPARE("st_mode", st_mode);
+ COMPARE("st_nlink", st_nlink);
+ COMPARE("st_uid", st_uid);
+ COMPARE("st_gid", st_gid);
+ COMPARE("st_rdev", st_rdev);
+ COMPARE("st_size", st_size);
+ COMPARE("st_blksize", st_blksize);
+ COMPARE("st_blocks", st_blocks);
+ COMPARE("st_atime", st_atime);
+ COMPARE("st_mtime", st_mtime);
+ COMPARE("st_ctime", st_ctime);
+
+ return 0;
+}
diff --git a/examples/libsmbclient/teststatvfs.c b/examples/libsmbclient/teststatvfs.c
new file mode 100644
index 0000000..44d4ed2
--- /dev/null
+++ b/examples/libsmbclient/teststatvfs.c
@@ -0,0 +1,106 @@
+#include <sys/types.h>
+#include <sys/statvfs.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <libsmbclient.h>
+#include "get_auth_data_fn.h"
+
+
+int main(int argc, char * argv[])
+{
+ int ret;
+ int debug = 0;
+ char * p;
+ char path[2048];
+ struct statvfs statvfsbuf;
+
+ smbc_init(get_auth_data_fn, debug);
+
+ for (;;)
+ {
+ fprintf(stdout, "Path: ");
+ *path = '\0';
+ p = fgets(path, sizeof(path) - 1, stdin);
+ if (p == NULL) {
+ fprintf(stderr, "failed to read from stdin\n");
+ return 1;
+ }
+ if (strlen(path) == 0)
+ {
+ return 0;
+ }
+
+ p = path + strlen(path) - 1;
+ if (*p == '\n')
+ {
+ *p = '\0';
+ }
+
+ ret = smbc_statvfs(path, &statvfsbuf);
+
+ if (ret < 0)
+ {
+ perror("fstatvfs");
+ }
+ else
+ {
+ printf("\n");
+ printf("Block Size: %lu\n", statvfsbuf.f_bsize);
+ printf("Fragment Size: %lu\n", statvfsbuf.f_frsize);
+ printf("Blocks: %llu\n",
+ (unsigned long long) statvfsbuf.f_blocks);
+ printf("Free Blocks: %llu\n",
+ (unsigned long long) statvfsbuf.f_bfree);
+ printf("Available Blocks: %llu\n",
+ (unsigned long long) statvfsbuf.f_bavail);
+ printf("Files : %llu\n",
+ (unsigned long long) statvfsbuf.f_files);
+ printf("Free Files: %llu\n",
+ (unsigned long long) statvfsbuf.f_ffree);
+ printf("Available Files: %llu\n",
+ (unsigned long long) statvfsbuf.f_favail);
+#ifdef HAVE_FSID_INT
+ printf("File System ID: %lu\n",
+ (unsigned long) statvfsbuf.f_fsid);
+#endif
+ printf("\n");
+
+ printf("Flags: 0x%lx\n", statvfsbuf.f_flag);
+ printf("Extended Features: ");
+
+ if (statvfsbuf.f_flag & SMBC_VFS_FEATURE_NO_UNIXCIFS)
+ {
+ printf("NO_UNIXCIFS ");
+ }
+ else
+ {
+ printf("unixcifs ");
+ }
+
+ if (statvfsbuf.f_flag & SMBC_VFS_FEATURE_CASE_INSENSITIVE)
+ {
+ printf("CASE_INSENSITIVE ");
+ }
+ else
+ {
+ printf("case_sensitive ");
+ }
+
+ if (statvfsbuf.f_flag & SMBC_VFS_FEATURE_DFS)
+ {
+ printf("DFS ");
+ }
+ else
+ {
+ printf("no_dfs ");
+ }
+
+ printf("\n");
+ }
+ }
+
+ return 0;
+}
diff --git a/examples/libsmbclient/testtruncate.c b/examples/libsmbclient/testtruncate.c
new file mode 100644
index 0000000..bbc70e9
--- /dev/null
+++ b/examples/libsmbclient/testtruncate.c
@@ -0,0 +1,80 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <libsmbclient.h>
+#include "get_auth_data_fn.h"
+
+
+int main(int argc, char * argv[])
+{
+ int fd;
+ int ret;
+ int debug = 0;
+ int savedErrno;
+ char buffer[128];
+ struct stat st;
+
+ if (argc != 2)
+ {
+ printf("usage: "
+ "%s smb://path/to/file\n",
+ argv[0]);
+ return 1;
+ }
+
+ smbc_init(get_auth_data_fn, debug);
+
+ if ((fd = smbc_open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0)) < 0)
+ {
+ perror("smbc_open");
+ return 1;
+ }
+
+ snprintf(buffer, sizeof(buffer), "%s", "Hello world.\nThis is a test.\n");
+
+ ret = smbc_write(fd, buffer, strlen(buffer));
+ savedErrno = errno;
+ smbc_close(fd);
+
+ if (ret < 0)
+ {
+ errno = savedErrno;
+ perror("write");
+ }
+
+ if (smbc_stat(argv[1], &st) < 0)
+ {
+ perror("smbc_stat");
+ return 1;
+ }
+
+ printf("Original size: %lu\n", (unsigned long) st.st_size);
+
+ if ((fd = smbc_open(argv[1], O_WRONLY, 0)) < 0)
+ {
+ perror("smbc_open");
+ return 1;
+ }
+
+ ret = smbc_ftruncate(fd, 13);
+ savedErrno = errno;
+ smbc_close(fd);
+ if (ret < 0)
+ {
+ errno = savedErrno;
+ perror("smbc_ftruncate");
+ return 1;
+ }
+
+ if (smbc_stat(argv[1], &st) < 0)
+ {
+ perror("smbc_stat");
+ return 1;
+ }
+
+ printf("New size: %lu\n", (unsigned long) st.st_size);
+
+ return 0;
+}
diff --git a/examples/libsmbclient/testutime.c b/examples/libsmbclient/testutime.c
new file mode 100644
index 0000000..378b0e9
--- /dev/null
+++ b/examples/libsmbclient/testutime.c
@@ -0,0 +1,75 @@
+#include "config.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <libsmbclient.h>
+#include "get_auth_data_fn.h"
+
+
+int main(int argc, char * argv[])
+{
+ int debug = 0;
+ char m_time[32];
+ char c_time[32];
+ char a_time[32];
+ const char * pSmbPath = NULL;
+ time_t t = time(NULL);
+ struct stat st;
+ struct utimbuf utimbuf;
+
+ if (argc == 1)
+ {
+ pSmbPath = "smb://RANDOM/Public/small";
+ }
+ else if (argc == 2)
+ {
+ pSmbPath = argv[1];
+ }
+ else if (argc == 3)
+ {
+ pSmbPath = argv[1];
+ t = (time_t) strtol(argv[2], NULL, 10);
+ }
+ else
+ {
+ printf("usage: "
+ "%s [ smb://path/to/file [ mtime ] ]\n",
+ argv[0]);
+ return 1;
+ }
+
+ smbc_init(get_auth_data_fn, debug);
+
+ if (smbc_stat(pSmbPath, &st) < 0)
+ {
+ perror("smbc_stat");
+ return 1;
+ }
+
+ printf("Before\n mtime:%lld/%s ctime:%lld/%s atime:%lld/%s\n",
+ (long long)st.st_mtime, ctime_r(&st.st_mtime, m_time),
+ (long long)st.st_ctime, ctime_r(&st.st_ctime, c_time),
+ (long long)st.st_atime, ctime_r(&st.st_atime, a_time));
+
+ utimbuf.actime = t; /* unchangeable (won't change) */
+ utimbuf.modtime = t; /* this one should succeed */
+ if (smbc_utime(pSmbPath, &utimbuf) < 0)
+ {
+ perror("smbc_utime");
+ return 1;
+ }
+
+ if (smbc_stat(pSmbPath, &st) < 0)
+ {
+ perror("smbc_stat");
+ return 1;
+ }
+
+ printf("After\n mtime:%lld/%s ctime:%lld/%s atime:%lld/%s\n",
+ (long long)st.st_mtime, ctime_r(&st.st_mtime, m_time),
+ (long long)st.st_ctime, ctime_r(&st.st_ctime, c_time),
+ (long long)st.st_atime, ctime_r(&st.st_atime, a_time));
+
+ return 0;
+}
diff --git a/examples/libsmbclient/testwrite.c b/examples/libsmbclient/testwrite.c
new file mode 100644
index 0000000..0e728e0
--- /dev/null
+++ b/examples/libsmbclient/testwrite.c
@@ -0,0 +1,72 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <libsmbclient.h>
+#include "get_auth_data_fn.h"
+
+
+int main(int argc, char * argv[])
+{
+ int fd;
+ int ret;
+ int debug = 0;
+ int savedErrno;
+ char buffer[2048];
+ char path[2048];
+ char * p;
+
+ smbc_init(get_auth_data_fn, debug);
+
+ printf("CAUTION: This program will overwrite a file. "
+ "Press ENTER to continue.");
+ p = fgets(buffer, sizeof(buffer), stdin);
+ if (p == NULL) {
+ fprintf(stderr, "failed to read from stdin\n");
+ return 1;
+ }
+
+
+ for (;;)
+ {
+ fprintf(stdout, "\nPath: ");
+ *path = '\0';
+ p = fgets(path, sizeof(path) - 1, stdin);
+ if (p == NULL) {
+ fprintf(stderr, "failed to read from stdin\n");
+ return 1;
+ }
+ if (strlen(path) == 0)
+ {
+ return 0;
+ }
+
+ p = path + strlen(path) - 1;
+ if (*p == '\n')
+ {
+ *p = '\0';
+ }
+
+ if ((fd = smbc_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0)) < 0)
+ {
+ perror("smbc_open");
+ continue;
+ }
+
+ snprintf(buffer, sizeof(buffer), "%s", "Hello world\n");
+
+ ret = smbc_write(fd, buffer, strlen(buffer));
+ savedErrno = errno;
+ smbc_close(fd);
+
+ if (ret < 0)
+ {
+ errno = savedErrno;
+ perror("write");
+ }
+ }
+
+ return 0;
+}
diff --git a/examples/libsmbclient/tree.c b/examples/libsmbclient/tree.c
new file mode 100644
index 0000000..07847c8
--- /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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+/* example-gtk+ application, ripped off from the gtk+ tree.c sample */
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.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),
+ GTK_OBJECT(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);
+
+ dirp = (struct smbc_dirent *) ((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);
+
+ }
+
+ dirp = (struct smbc_dirent *) ((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);
+
+ dirp = (struct smbc_dirent *) ((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 workgroups: 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 */
+
+ 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);
+
+ }
+
+ dirp = (struct smbc_dirent *)dirbuf;
+
+ 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);
+
+ dirp = (struct smbc_dirent *) ((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/examples/libsmbclient/wscript_build b/examples/libsmbclient/wscript_build
new file mode 100644
index 0000000..c58a5b9
--- /dev/null
+++ b/examples/libsmbclient/wscript_build
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+
+names = ['testsmbc',
+ 'testacl',
+ 'testacl2',
+ 'testacl3',
+ 'testbrowse',
+ 'testbrowse2',
+ 'testnotify',
+ 'teststat',
+ 'teststat2',
+ 'teststat3',
+ 'teststatvfs',
+ 'testfstatvfs',
+ 'testtruncate',
+ 'testchmod',
+ 'testutime',
+ 'testread',
+ 'testwrite',
+ 'testctx']
+
+for name in names:
+ bld.SAMBA_BINARY(name,
+ source='%s.c' % name,
+ deps='popt smbclient',
+ install=False)
diff --git a/examples/logon/genlogon/genlogon.pl b/examples/logon/genlogon/genlogon.pl
new file mode 100644
index 0000000..4799ac8
--- /dev/null
+++ b/examples/logon/genlogon/genlogon.pl
@@ -0,0 +1,71 @@
+#!/usr/bin/perl
+#
+# genlogon.pl
+#
+# Perl script to generate user logon scripts on the fly, when users
+# connect from a Windows client. This script should be called from smb.conf
+# with the %U, %G and %L parameters. I.e:
+#
+# root preexec = genlogon.pl %U %G %L
+#
+# The script generated will perform
+# the following:
+#
+# 1. Log the user connection to /var/log/samba/netlogon.log
+# 2. Set the PC's time to the Linux server time (which is maintained
+# daily to the National Institute of Standard's Atomic clock on the
+# internet.
+# 3. Connect the user's home drive to H: (H for Home).
+# 4. Connect common drives that everyone uses.
+# 5. Connect group-specific drives for certain user groups.
+# 6. Connect user-specific drives for certain users.
+# 7. Connect network printers.
+
+# Log client connection
+#($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
+($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
+open LOG, ">>/var/log/samba/netlogon.log";
+print LOG "$mon/$mday/$year $hour:$min:$sec - User $ARGV[0] logged into $ARGV[1]\n";
+close LOG;
+
+# Start generating logon script
+open LOGON, ">/shared/netlogon/$ARGV[0].bat";
+print LOGON "\@ECHO OFF\r\n";
+
+# Connect shares just use by Software Development group
+if ($ARGV[1] eq "SOFTDEV" || $ARGV[0] eq "softdev")
+{
+ print LOGON "NET USE M: \\\\$ARGV[2]\\SOURCE\r\n";
+}
+
+# Connect shares just use by Technical Support staff
+if ($ARGV[1] eq "SUPPORT" || $ARGV[0] eq "support")
+{
+ print LOGON "NET USE S: \\\\$ARGV[2]\\SUPPORT\r\n";
+}
+
+# Connect shares just used by Administration staff
+if ($ARGV[1] eq "ADMIN" || $ARGV[0] eq "admin")
+{
+ print LOGON "NET USE L: \\\\$ARGV[2]\\ADMIN\r\n";
+ print LOGON "NET USE K: \\\\$ARGV[2]\\MKTING\r\n";
+}
+
+# Now connect Printers. We handle just two or three users a little
+# differently, because they are the exceptions that have desktop
+# printers on LPT1: - all other user's go to the LaserJet on the
+# server.
+if ($ARGV[0] eq 'jim'
+ || $ARGV[0] eq 'yvonne')
+{
+ print LOGON "NET UsE LPT2: \\\\$ARGV[2]\\LJET3\r\n";
+ print LOGON "NET USE LPT3: \\\\$ARGV[2]\\FAXQ\r\n";
+}
+else
+{
+ print LOGON "NET USE LPT1: \\\\$ARGV[2]\\LJET3\r\n";
+ print LOGON "NET USE LPT3: \\\\$ARGV[2]\\FAXQ\r\n";
+}
+
+# All done! Close the output file.
+close LOGON;
diff --git a/examples/logon/mklogon/mklogon.conf b/examples/logon/mklogon/mklogon.conf
new file mode 100644
index 0000000..9e585c5
--- /dev/null
+++ b/examples/logon/mklogon/mklogon.conf
@@ -0,0 +1,78 @@
+# Mapping should be kept in the form
+# username(USER) or groupname(WEBUSERS) = driveletter (W:), samba share name (WEB)
+# ie. user = W:,WEB or webusers = W:,WEB
+# Problem found when testing, if there is a duplicate entry only the last one is used,
+# not the first or both, another problem is that when testing I found a bug in Config::Simple, if you have a tab
+# infront of your # on a comment it breaks ...
+# logging = yes # Should Logging be enabled (YES,ON,1 or NO,OFF,0)(if not specified defaults to no)
+# logdir = "/root/perl" # What is the base directory the logs should be stored.
+# logfile = "userlist.txt" # What should the file be named.
+# VERY IMPORTANT anything that has a "\" (backslash) in it ex. "C:\" MUST be changed to a double "\\" for
+# it to be used in the script. ex. "C:\\"
+
+[global]
+logging = yes
+logdir = "/home/samba/netlogon"
+logfile = "UserLogs.txt"
+mkprofile = 1
+timesync = yes
+sambaconf = "/etc/samba/smb.conf"
+logtype = file
+
+# Change and uncomment the below value to force the servername, some clients occasionally
+# have trouble picking up the right servername so it may need to be set. It CANNOT be left blank AND uncommented.
+servername = "TIGER"
+
+[common]
+public = P:, public
+home = H:, /home
+
+[groupmap]
+adm = R:, NETLOGON, Y:, ARCHIVES
+teachers = S:, RECORDS, X:, SIS
+plato = T:, PLATO
+webpage = W:, WEB
+hsoffice = N:, HSOFFICE, Q:, COMMON, X:, SIS
+suoffice = N:, super, Q:, COMMON, X:, SIS
+emoffice = N:, emOFFICE, Q:, COMMON, X:, SIS
+tech = O:, utils
+yearbook = Y:, yearbook
+
+[usermap]
+rnance = G:, GHOST, I:, TTL, Y:, ARCHIVES, R:, NETLOGON, X:, SIS
+lwatts = G:, GHOST, I:, TTL, Y:, ARCHIVES, R:, NETLOGON, X:, SIS
+droot = U:, stuhomes
+2007mbk = Y:, yearbook
+2008mll = Y:, yearbook
+2008jtj = Y:, yearbook
+2007tja = Y:, yearbook
+2007hms = Y:, yearbook
+2006dpv = Y:, yearbook
+2006jwb2 = Y:, yearbook
+2007npd = Y:, yearbook
+astewart = Y:, yearbook
+
+
+
+# Here is where things get confusing, you can assign a computer, or make a group of computers.
+# The same context will go for ip address's as well, however you can also specify ip ranges,
+# but I have not yet figured out how to do multiple ranges.
+# Use the following examples for help.
+# To define a single computer to do commands
+# mymachinename = command1, command2
+# To define a group of computers to do commands
+# mymachinegroup = machinename1, machinename2
+# [performcommands]
+# mymachinegroup = command1,command2
+# iprangegroup1 = 10.1.2.1 - 10.1.3.1
+
+
+
+[machines]
+
+[ip]
+sixthemints = 10.1.5.201 - 10.1.5.215
+
+[performcommands]
+common = "XCOPY P:\\TYPEN32.INI C:\\WINDOWS\\ /Y \>NUL", "XCOPY P:\\ARPROGRAMS\\DBLOCATION\\\*\.\* C:\\WINDOWS\\ /Y \>NUL", "XCOPY P:\\EMACTIVITIES\\EMGAMESPREFS.INI C:\\WINDOWS\\ /Y \>NUL", "PATH\=\%PATH\%;p:\\PXPerl\parrot\\bin;p:\\PXPerl\\bin"
+sixthemints = "start \\\\10.1.5.20\\printer"
diff --git a/examples/logon/mklogon/mklogon.pl b/examples/logon/mklogon/mklogon.pl
new file mode 100644
index 0000000..870abd1
--- /dev/null
+++ b/examples/logon/mklogon/mklogon.pl
@@ -0,0 +1,392 @@
+#!/usr/bin/perl -w
+
+# 05/01/2005 - 18:07:10
+#
+# mklogon.pl - Login Script Generator
+# Copyright (C) 2005 Ricky Nance
+# ricky.nance@gmail.com
+# http://www.weaubleau.k12.mo.us/~rnance/samba/mklogon.txt
+#
+# 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 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, see <http://www.gnu.org/licenses/>.
+#
+
+# Version: 1.0 (Stable)
+# Revised: 07/28/2005
+
+# Comments...
+# Working on logging to the system logs, Logs user activity, but not errors yet.
+
+use strict;
+use Getopt::Long;
+
+eval { require Config::Simple; };
+if ($@) {
+ print("\n");
+ print( "It appears as though you don't have the Config Simple perl module installed.\n" );
+ print("The package is typically called 'Config::Simple' \n");
+ print("and it needs to be installed, before you can use this utility\n");
+ print("Most PERL installations will allow you to use a command like\n");
+ print("\ncpan -i Config::Simple\n");
+ print("from the command line while logged in as the root user.\n");
+ print("\n");
+ exit(1);
+}
+
+# use Data::Dumper; #Used for debugging purposes
+
+# This variable should point to the external conf file, personally I would set
+# it to /etc/samba/mklogon.conf
+my $configfile;
+
+foreach my $dir ( ( '/etc', '/etc/samba', '/usr/local/samba/lib' ) ) {
+ if ( -e "$dir/mklogon.conf" ) {
+ $configfile = "$dir/mklogon.conf";
+ last;
+ }
+}
+
+# This section will come directly from the samba server. Basically it just makes the script easier to read.
+my $getopts = GetOptions(
+ 'u|username=s' => \my $user,
+ 'm|machine=s' => \my $machine,
+ 's|servername=s' => \my $server,
+ 'o|ostype=s' => \my $os,
+ 'i|ip=s' => \my $ip,
+ 'd|date=s' => \my $smbdate,
+ 'h|help|?' => \my $help
+);
+
+if ($help) {
+ help();
+ exit(0);
+}
+
+# We want the program to error out if its missing an argument.
+if ( !defined($user) ) { error("username"); }
+if ( !defined($machine) ) { error("machine name") }
+if ( !defined($server) ) { error("server name") }
+if ( !defined($os) ) { error("operating system") }
+if ( !defined($ip) ) { error("ip address") }
+if ( !defined($smbdate) ) { error("date") }
+
+# This section will be read from the external config file
+my $cfg = new Config::Simple($configfile) or die "Could not find $configfile";
+
+# Read this part from the samba config
+my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime(time);
+my $sambaconf = $cfg->param("global.sambaconf") or die "Couldn't find your samba config! \n";
+my $smbcfg = new Config::Simple( filename => $sambaconf, syntax => "ini" );
+my $smbprof = $smbcfg->param("profiles.path");
+my $smbnetlogdir = $smbcfg->param("netlogon.path");
+my $logging = lc( $cfg->param("global.logging") );
+my $mkprofile = lc( $cfg->param("global.mkprofile") );
+my $logdir = $cfg->param("global.logdir");
+my $logfile = $cfg->param("global.logfile");
+my $logs = "$logdir\/$logfile";
+my $logtype = $cfg->param("global.logtype");
+my $usermap = "usermap.$user";
+my $osmap = "os.$os";
+my @ostype = $cfg->param($osmap);
+my @username = $cfg->param($usermap);
+my $compname = $cfg->param( -block => "machines" );
+my $ipname = $cfg->param( -block => "ip" );
+my $timesync = $cfg->param("global.timesync");
+my $altserver = $cfg->param("global.servername");
+if ( defined($altserver) ) { $server = $altserver; }
+$server = uc($server);
+
+# Lets start logging stuff if it is turned on in the config
+if ( $logging =~ m/on|yes|1/i ) {
+ if ($logtype =~ m/file/i) {
+ print "----- Logging is turned on in the config. -----\n";
+ print "----- Location of the logfile is \"$logs\" -----\n";
+ open LOG, ">>$logs";
+ printf LOG "Date: $smbdate Time: ";
+ printf LOG '%02d', $hour;
+ print LOG ":";
+ printf LOG '%02d', $min;
+ print LOG ".";
+ printf LOG '%02d', $sec;
+ print LOG " -- User: $user - Machine: $machine - IP: $ip -- \n";
+ close(LOG);
+ } elsif ($logtype =~ m/syslog|system/i){
+ use Sys::Syslog;
+ my $alert = "User: $user Logged into $machine ($ip) at $hour:$min.$sec on $smbdate.";
+ openlog($0, 'cons', 'user');
+ syslog('alert', $alert);
+ closelog();
+
+ }
+} else {
+ print "----- Logging is turned off in the config. -----\n";
+}
+
+# If the user wants to make profiles with this script lets go
+if ( defined($smbprof) ) {
+ if ( $mkprofile =~ m/on|yes|1/i ) {
+ print "----- Automatic making of user profiles is turned on in the config. ----- \n";
+ ( my $login, my $pass, my $uid, my $gid ) = getpwnam($user)
+ or die "$user not in passwd file \n";
+ $smbprof =~ s/\%U/$user/g;
+ my $dir2 = "$smbprof\/$user";
+ print "$smbprof \n";
+ print "$dir2 \n";
+ if ( !-e $dir2 ) {
+ print "Creating " . $user . "'s profile with a uid of $uid\n";
+ mkdir $smbprof;
+ mkdir $dir2;
+ chomp($user);
+# chown $uid, $gid, $smbprof;
+ chown $uid, $gid, $dir2;
+ } else {
+ print $user . "'s profile already exists \n";
+ }
+ } else {
+ print "----- Automatic making of user profiles is turned off in the config. ----- \n";
+ }
+}
+
+# Lets start making the batch files.
+open LOGON, ">$smbnetlogdir\/$user.bat" or die "Unable to create userfile $smbnetlogdir\/$user.bat";
+print LOGON "\@ECHO OFF \r\n";
+
+if ( $timesync =~ m/on|yes|1/i ) {
+ print LOGON "NET TIME /SET /YES \\\\$server \r\n";
+} else {
+ print "----- Time syncing to the client is turned off in the config. -----\n";
+}
+
+# Mapping from the common section
+my $common = $cfg->param( -block => "common" );
+for my $key ( keys %$common ) {
+ drive_map( @{ $common->{$key} } );
+}
+
+my @perform_common = $cfg->param("performcommands.common");
+if ( defined( $perform_common[0] ) ) {
+ foreach (@perform_common) {
+ print LOGON "$_ \r\n";
+ }
+}
+
+# Map shares on a per user basis.
+drive_map(@username);
+
+# Map shares based on the Operating System.
+drive_map(@ostype);
+
+# Map shares only if they are in a group
+# This line checks against the unix "groups" command, to see the secondary groups of a user.
+my @usergroups = split( /\s/, do { open my $groups, "-|", groups => $user; <$groups> } );
+foreach (@usergroups) {
+ my $groupmap = "groupmap.$_";
+ my @groupname = $cfg->param($groupmap);
+ drive_map(@groupname);
+}
+
+#Here is where we check the machine name against the config...
+for my $key ( keys %$compname ) {
+ my $test = $compname->{$key};
+ if ( ref $test eq 'ARRAY' ) {
+ foreach (@$test) {
+ if ( $_ eq $machine ) {
+ my $performit = $cfg->param("performcommands.$key");
+ if ( defined($performit) ) {
+ if ( ref $performit ) {
+ foreach (@$performit) { print LOGON "$_ \r\n"; }
+ } else {
+ print LOGON "$performit \r\n";
+ }
+ }
+ }
+ }
+ }
+ elsif ( $test eq $machine ) {
+ my $performit = $cfg->param("performcommands.$key");
+ if ( defined($performit) ) {
+ if ( ref $performit ) {
+ foreach (@$performit) { print LOGON "$_ \r\n"; }
+ } else {
+ print LOGON "$performit \r\n";
+ }
+ }
+ }
+}
+
+# Here is where we test the ip address against the client to see if they have "Special Mapping"
+# A huge portion of the ip matching code was made by
+# Carsten Schaub (rcsu in the #samba chan on freenode.net)
+
+my $val;
+for my $key ( sort keys %$ipname ) {
+ if ( ref $ipname->{$key} eq 'ARRAY' ) {
+ foreach ( @{ $ipname->{$key} } ) {
+ getipval( $_, $key );
+ }
+ } else {
+ getipval( $ipname->{$key}, $key );
+ }
+}
+
+sub getipval {
+ my ( $range, $rangename ) = @_;
+ if ( parse( $ip, ipmap($range) ) ) {
+ if ( $val eq 'true' ) {
+ my $performit = $cfg->param("performcommands.$rangename");
+ if ( defined($performit) ) {
+ if ( ref $performit ) {
+ foreach (@$performit) { print LOGON "$_ \r\n"; }
+ } else {
+ print LOGON "$performit \r\n";
+ }
+ }
+ } elsif ( $val eq 'false' ) {
+ }
+ } else {
+ }
+}
+
+sub ipmap {
+ my $pattern = shift;
+ my ( $iprange, $iprange2, $ipmask );
+ if ( $pattern =~ m/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\/(\d{1,2})$/ ) {
+ # 1.1.1.1/3 notation
+ $iprange = pack( "U4", $1, $2, $3, $4 );
+ $ipmask = pack( "U4", 0, 0, 0, 0 );
+ my $numbits = $5;
+ for ( my $i = 0 ; $i < $numbits ; $i++ ) {
+ vec( $ipmask, int( $i / 8 ) * 8 + ( 8 - ( $i % 8 ) ) - 1, 1 ) = 1;
+ }
+ $iprange &= "$ipmask";
+ } elsif ( $pattern =~ m/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\/(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/ ) {
+ # 1.1.1.1/255.255.255.255 notation
+ $iprange = pack( "U4", $1, $2, $3, $4 );
+ $ipmask = pack( "U4", $5, $6, $7, $8 );
+ $iprange &= "$ipmask";
+ } elsif ( $pattern =~ m/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/ ) {
+ # 1.1.1.1 notation
+ $iprange = pack( "U4", $1, $2, $3, $4 );
+ $ipmask = pack( "U4", 255, 255, 255, 255 );
+ } elsif ( $pattern =~ m/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\s*\-\s*(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/ ) {
+ # 1.1.1.1 - 2.2.2.2 notation
+ $iprange = pack( "U4", $1, $2, $3, $4 );
+ $iprange2 = pack( "U4", $5, $6, $7, $8 );
+ $ipmask = pack( "U4", 255, 255, 255, 255 );
+ } else {
+ return;
+ }
+ return $iprange, $ipmask, $iprange2;
+}
+
+sub parse {
+ my ( $origip, $ipbase, $ipmask, $iprange2 ) = @_;
+ $origip =~ m/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
+ $origip = pack( "U4", $1, $2, $3, $4 );
+ if ( defined($iprange2) ) {
+ if ( $ipbase le $origip && $origip le $iprange2 ) {
+ return $val = 'true';
+ } else {
+ return $val = 'false';
+ }
+ } elsif ( ( "$origip" & "$ipmask" ) eq $ipbase ) {
+ return $val = 'true';
+ } else {
+ return $val = 'false';
+ }
+}
+
+# This sub will distinguish the drive mappings
+sub drive_map {
+ my @data = @_;
+ for ( my $i = 0 ; $i < scalar(@data) ; ) {
+ if ( $data[$i] =~ m/^[a-z]\:$/i ) {
+ my $driveletter = $data[$i];
+ $i++;
+ my $sharename = $data[$i];
+ $i++;
+ if ( $sharename eq '/home' ) {
+ print LOGON uc("NET USE $driveletter \\\\$server\\$user \/Y \r\n");
+ } else {
+ print LOGON
+ uc("NET USE $driveletter \\\\$server\\$sharename \/Y \r\n");
+ }
+ } else {
+ print LOGON uc("$data[$i] \r\n");
+ $i++;
+ }
+ }
+}
+
+close(LOGON);
+
+sub error {
+ my $var = shift(@_);
+ help();
+ print "\n\tCritical!!! \n\n\tNo $var specified\n\n\tYou must specify a $var.\n\n";
+ exit(0);
+}
+
+sub help {
+
+ print << "EOF" ;
+
+ Usage: $0 [options]
+
+ Options:
+
+ -h,--help This help screen.
+
+ -u,--username The name of the user from the samba server.
+
+ -m,--machinename The name of the client connecting to the server.
+
+ -s,--server The name of the server this script is running in.
+
+ -o,--os The clients OS -- Windows 95/98/ME (Win95), Windows NT (WinNT),
+ Windows 2000 (Win2K), Windows XP (WinXP), and Windows 2003
+ (Win2K3). Anything else will be known as ``UNKNOWN''
+ That snippet is directly from man smb.conf.
+
+ -i,--ip The clients IP address.
+
+ -d,--date Time and Date returned from the samba server.
+
+
+
+ --IMPORTANT--
+
+
+ All options MUST be specified.
+
+ The mklogon.conf file MUST be located in /etc, /etc/samba, or
+ /usr/local/samba/lib.
+
+ To use this file from the command line:
+ $0 -u User -m machine -s servername -o ostype -i X.X.X.X -d MM/DD/YY
+
+ To use this file from the samba server add these lines to your /etc/samba/smb.conf:
+
+
+ This line goes in the [global] section
+ login script = %U.bat
+
+ This line should be at the end of the [netlogon] section.
+ root preexec = /path/to/mklogon.pl -u %U -m %m -s %L -o %a -i %I -d %t
+
+
+EOF
+
+ print "\n\n";
+
+}
diff --git a/examples/logon/ntlogon/README b/examples/logon/ntlogon/README
new file mode 100644
index 0000000..da52562
--- /dev/null
+++ b/examples/logon/ntlogon/README
@@ -0,0 +1,160 @@
+ntlogon.py v0.8b Copyright 2002 by Timothy (rhacer) Grant
+This programme is released under the terms of the GNU Public License
+This programme has NO WARRANTY of any kind, use at your own risk.
+
+===================
+CHANGES SINCE v0.7b
+===================
+included patch that made machine name %m a macro substitution value.
+Thanks to: Nick Lopez <kimo_sabe@atdot.org>
+
+==================
+CHANGES SINCE v0.6
+==================
+PLEASE NOT THAT I AM CONSIDERING THIS A BETA UNTIL I GET SOME FEEDBACK
+FROM USERS ON WHETHER THE MACRO FEATURE WORKS FOR THEM.
+
+added the ability to define substitution macros: see the usage section
+
+removed the large docstring from the file and moved the information to
+the USAGE section of this file
+
+cleaned up the code and made more flexible
+
+improved the code comments
+
+==================
+CHANGES SINCE v0.5
+==================
+added a -v --version switch
+
+added a --pause switch which will put a pause statement between each
+non-blank line of the script.
+
+===============
+A PERSONAL NOTE
+===============
+When I originally posted v0.5 on Freshmeat, I really expected *some*
+feedback. To date this little script has been downloaded over 700 times, but
+absolutely nobody has sent me an e-mail to tell me if it is useful, or if
+it is absolutely the stupidest waste of bandwidth they have ever seen.
+I'd really love to know if even one person other than me and the other techs
+here at Avalon have found it useful.
+
+Thanks.
+ rhacer (rhacer@craigelachie.org)
+
+September 27, 2000
+Thanks to those that did respond to my plea! I'd still love to hear from
+any other users!
+
+============
+INTRODUCTION
+============
+As my experience with Linux and Samba increased, I had no trouble whipping up
+a custom Perl, Python or Bash script to create Samba Logon Scripts, but I
+noticed that I changed things from place to place, and that my users had *no*
+chance of ever figuring out how to modify those scripts themselves.
+
+In an attempt to create a company wide standard that both my co-workers and my
+customers could *easily* modify I hit upon the scheme I used here.
+
+I settled on an INI file feel, because most who have experience with Win boxes
+have some concept of INI files.
+
+============
+INSTALLATION
+============
+The distribution archive contains three files:
+
+README This file
+ntlogon.py The actual Python script (place in /usr/local/samba/bin)
+ntlogon.conf A sample configuration file (place in /etc)
+
+This script was created using Python v1.5.2, and I believe it uses only
+standard libraries.
+
+Your smb.conf file needs to contain a netlogon section similar to the
+following (These settings *are not* normal on a RH box. These settings
+are all based on the excellent book that I learned Samba from: Samba
+Integrating Unix and Windows by John D. Blair. It is somewhat out of
+date now, but that's the history of the strange file locations):
+
+[netlogon]
+ path = /usr/local/samba/netlogon
+ writeable = no
+ guest ok = no
+ root preexec = /usr/local/samba/bin/ntlogon --user=%U --os=%m
+ root postexec = rm /usr/local/samba/netlogon/%U.bat
+
+======
+USAGE
+======
+PLEASE SEE NTLOGON.CONF FOR A DETAILED CONFIGURATION EXAMPLE
+
+This programme will build a Windows NT logon script for users connecting
+to a Samba server. Samba macros that are currently understood:
+
+ %U user name
+ %G group name
+ %a machine architecture
+ %m machine netbios name
+
+This programme reads a configuration that looks strikingly similar to both
+the Samba configuration file, and a DOS "boot menu" AUTOEXEC.BAT file.
+
+The default file name is /etc/ntlogon.conf (though I really think it ought
+to be called ntlogon.batch!) You may change the filename by using the -f
+or --templatefile startup option.
+
+The default netlogon directory is /usr/local/samba/netlogon though this
+can be changed with the -d or --dir startup option.
+
+The default batch file name generated is username.bat if no username is
+specified the default value is logon.bat (e.g., if --user=fred is specified
+on the command line then the logon script generated will be stored in
+fred.bat)
+
+Use the --debug option to print the logon script to screen instead of the
+output file
+
+Use the --pause option to place a pause statement between each line of the
+script to assist in debugging a logon script.
+
+The file is divided into sections that have headers in square brackets
+
+[Global]
+[User-username]
+[Group-groupname]
+[OS-osname]
+
+The file may also contain user defined substitution macros. They are
+defined by placing the macro name on the left side of an equal sign,
+and the substitution text on the right side of the equal sign. They
+are also case sensitive:
+
+MAINDRIVE = G:
+USERDRIVE = U:
+SERVERNAME = myservername
+
+They are referenced by prepending a "%" sign to the variable name:
+
+NET USE %MAINDRIVE \\\\servername\\mainshare /YES
+NET USE %USERDRIVE \\\\%SERVERNAME\\usershare /YES
+
+==============
+SPECIAL THANKS
+==============
+Nick Lopez <kimo_sabe@atdot.org> for the net bios name patch.
+
+===================
+CONTACT INFORMATION
+===================
+Author : Timothy (rhacer) Grant
+
+I can be reached at tjg@craigelachie.org
+ntlogon website www.craigelachie.org/rhacer/ntlogon
+
+Please feel free to contact me with any suggestions, improvements, bugs you
+might find.
+
diff --git a/examples/logon/ntlogon/ntlogon.conf b/examples/logon/ntlogon/ntlogon.conf
new file mode 100644
index 0000000..e1573a6
--- /dev/null
+++ b/examples/logon/ntlogon/ntlogon.conf
@@ -0,0 +1,44 @@
+# Everything in the Global section applies to all users logging on to the
+# network
+[Global]
+
+#Some substitution macro definitions
+MAINDRIVE = G:
+USERDRIVE = U:
+SERVERNAME = myservername
+
+@ECHO "Welcome to our network!!!"
+NET TIME \\servername /SET /YES
+NET USE %MAINDRIVE \\%SERVERNAME\globalshare /YES
+
+# Map the private user area in the global section so we don't have to
+# create individual user entries for each user!
+NET USE %USERDRIVE \\servername\%U /YES
+
+# Group entries, User entries and OS entries each start with the
+# keyword followed by a dash followed by--appropriately enough the Group
+# name, the User name, or the OS name.
+[Group-admin]
+@ECHO "Welcome administrators!"
+NET USE G: \\servername\adminshare1 /YES
+NET USE I: \\servername\adminshare2 /YES
+
+[Group-peons]
+@ECHO "Be grateful we let you use computers!"
+NET USE G: \\servername\peonshare1 /YES
+
+[Group-hackers]
+@ECHO "What can I do for you today great one?"
+NET USE G: \\servername\hackershare1 /YES
+NET USE I: \\servername\adminshare2 /YES
+
+[User-fred]
+@ECHO "Hello there Fred!"
+NET USE F: \\servername\fredsspecialshare /YES
+
+[OS-WfWg]
+@ECHO "Time to upgrade isn't it?"
+
+# End configuration file
+
+X = Will this break?
diff --git a/examples/logon/ntlogon/ntlogon.py b/examples/logon/ntlogon/ntlogon.py
new file mode 100755
index 0000000..7213012
--- /dev/null
+++ b/examples/logon/ntlogon/ntlogon.py
@@ -0,0 +1,375 @@
+#!/usr/bin/env python3
+"""
+ntlogon.py written by Timothy (rhacer) Grant
+
+Copyright 1999 - 2002 by Timothy Grant
+
+is distributed under the terms of the GNU Public License.
+
+The format for the configuration file is as follows:
+
+While there is some room for confusion, we attempt to process things in
+order of specificity: Global first, Group second, User third, OS Type
+forth. This order can be debated forever, but it seems to make the most
+sense.
+
+# Everything in the Global section applies to all users logging on to the
+# network
+[Global]
+@ECHO "Welcome to our network!!!"
+NET TIME \\\\servername /SET /YES
+NET USE F: \\\\servername\\globalshare /YES
+
+# Map the private user area in the global section so we don't have to
+# create individual user entries for each user!
+NET USE U: \\\\servername\\%U /YES
+
+# Group entries, User entries and OS entries each start with the
+# keyword followed by a dash followed by--appropriately enough the Group
+# name, the User name, or the OS name.
+[Group-admin]
+@ECHO "Welcome administrators!"
+NET USE G: \\\\servername\\adminshare1 /YES
+NET USE I: \\\\servername\\adminshare2 /YES
+
+[Group-peons]
+@ECHO "Be grateful we let you use computers!"
+NET USE G: \\\\servername\\peonshare1 /YES
+
+[Group-hackers]
+@ECHO "What can I do for you today great one?"
+NET USE G: \\\\servername\\hackershare1 /YES
+NET USE I: \\\\servername\\adminshare2 /YES
+
+[User-fred]
+@ECHO "Hello there Fred!"
+NET USE F: \\\\servername\\fredsspecialshare /YES
+
+[OS-WfWg]
+@ECHO "Time to upgrade it?"
+
+# End configuration file
+
+usage: ntlogon [-g | --group=groupname]
+ [-u | --user=username]
+ [-o | --os=osname]
+ [-m | --machine=netbiosname]
+ [-f | --templatefile=filename]
+ [-d | --dir=netlogon directory]
+ [-v | --version]
+ [-h | --help]
+ [--pause]
+ [--debug]
+"""
+#
+#" This quote mark is an artifact of the inability of my editor to
+# correctly colour code anything after the triple-quoted docstring.
+# if your editor does not have this flaw, feel free to remove it.
+
+
+import sys
+import getopt
+import re
+import string
+import os
+
+version = "ntlogon.py v0.8"
+
+def buildScript(buf, sections, group, user, ostype, machine, debug, pause):
+ """
+ buildScript() Takes the contents of the template file and builds
+ a DOS batch file to be executed as an NT logon script. It does this
+ by determining which sections of the configuration file should be included
+ and creating a list object that contains each line contained in each
+ included section. The list object is then returned to the calling
+ routine.
+
+ All comments (#) are removed. A REM is inserted to show
+ which section of the configuration file each line comes from.
+ We leave blanklines as they are sometimes useful for debugging
+
+ We also replace all of the Samba macros (e.g., %U, %G, %a, %m) with their
+ expanded versions which have been passed to us by smbd
+ """
+ hdrstring = ''
+ script = []
+
+ #
+ # These are the Samba macros that we currently know about.
+ # any user defined macros will also be added to this dictionary.
+ # We do not store the % sign as part of the macro name.
+ # The replace routine will prepend the % sign to all possible
+ # replacements.
+ #
+ macros = {
+ 'U': user,
+ 'G': group,
+ 'a': ostype,
+ 'm': machine
+ }
+
+ #
+ # Process each section defined in the list sections
+ #
+ for s in sections:
+ # print 'searching for: ' + s
+
+ idx = 0
+
+ while idx < len(buf):
+ ln = buf[idx]
+
+ #
+ # We need to set up a regex for each possible section we
+ # know about. This is slightly complicated due to the fact
+ # that section headers contain user defined text.
+ #
+ if s == 'Global':
+ hdrstring = r'\[ *' + s + r' *\]'
+ elif s == 'Group':
+ hdrstring = r'\[ *' + s + ' *- *' + group + r' *\]'
+ elif s == 'User':
+ hdrstring = r'\[ *' + s + ' *- *' + user + r' *\]'
+ elif s == 'OS':
+ hdrstring = r'\[ *' + s + ' *- *' + ostype + r' *\]'
+ elif s == 'Machine':
+ hdrstring = r'\[ *' + s + ' *- *' + machine + r' *\]'
+
+ #
+ # See if we have found a section header
+ #
+ if re.search(r'(?i)' + hdrstring, ln):
+ idx = idx + 1 # increment the counter to move to the next
+ # line.
+
+ x = re.match(r'([^#\r\n]*)', ln) # Determine the section
+ # name and strip out CR/LF
+ # and comment information
+
+ if debug:
+ print 'rem ' + x.group(1) + ' commands'
+ else:
+ # create the rem at the beginning of each section of the
+ # logon script.
+ script.append('rem ' + x.group(1) + ' commands')
+
+ #
+ # process each line until we have found another section
+ # header
+ #
+ while not re.search(r'.*\[.*\].*', buf[idx]):
+
+ #
+ # strip comments and line endings
+ #
+ x = re.match(r'([^#\r\n]*)', buf[idx])
+
+ if string.strip(x.group(1)) != '' :
+ # if there is still content after stripping comments and
+ # line endings then this is a line to process
+
+ line = x.group(1)
+
+ #
+ # Check to see if this is a macro definition line
+ #
+ vardef = re.match(r'(.*)=(.*)', line)
+
+ if vardef:
+ varname = string.strip(vardef.group(1)) # Strip leading and
+ varsub = string.strip(vardef.group(2)) # and trailing spaces
+
+ if varname == '':
+ print "Error: No substitution name specified line: %d" % idx
+ sys.exit(1)
+
+ if varsub == '':
+ print "Error: No substitution text provided line: %d" % idx
+ sys.exit(1)
+
+ if varname in macros:
+ print "Warning: macro %s redefined line: %d" % (varname, idx)
+
+ macros[varname] = varsub
+ idx = idx + 1
+ continue
+
+ #
+ # Replace all the macros that we currently
+ # know about.
+ #
+ # Iterate over the dictionary that contains all known
+ # macro substitutions.
+ #
+ # We test for a macro name by prepending % to each dictionary
+ # key.
+ #
+ for varname in macros.keys():
+ line = re.sub(r'%' + varname + r'(\W)',
+ macros[varname] + r'\1', line)
+
+ if debug:
+ print line
+ if pause:
+ print 'pause'
+ else:
+ script.append(line)
+
+ idx = idx + 1
+
+ if idx == len(buf):
+ break # if we have reached the end of the file
+ # stop processing.
+
+ idx = idx + 1 # increment the line counter
+
+ if debug:
+ print ''
+ else:
+ script.append('')
+
+ return script
+
+# End buildScript()
+
+def run():
+ """
+ run() everything starts here. The main routine reads the command line
+ arguments, opens and reads the configuration file.
+ """
+ configfile = '/etc/ntlogon.conf' # Default configuration file
+ group = '' # Default group
+ user = '' # Default user
+ ostype = '' # Default os
+ machine = '' # Default machine type
+ outfile = 'logon.bat' # Default batch file name
+ # this file name WILL take on the form
+ # username.bat if a username is specified
+ debug = 0 # Default debugging mode
+ pause = 0 # Default pause mode
+ outdir = '/usr/local/samba/netlogon/' # Default netlogon directory
+
+ sections = ['Global', 'Machine', 'OS', 'Group', 'User'] # Currently supported
+ # configuration file
+ # sections
+
+ options, args = getopt.getopt(sys.argv[1:], 'd:f:g:ho:u:m:v',
+ ['templatefile=',
+ 'group=',
+ 'help',
+ 'os=',
+ 'user=',
+ 'machine=',
+ 'dir=',
+ 'version',
+ 'pause',
+ 'debug'])
+
+ #
+ # Process the command line arguments
+ #
+ for i in options:
+ # template file to process
+ if (i[0] == '-f') or (i[0] == '--templatefile'):
+ configfile = i[1]
+ # print 'configfile = ' + configfile
+
+ # define the group to be used
+ elif (i[0] == '-g') or (i[0] == '--group'):
+ group = i[1]
+ # print 'group = ' + group
+
+ # define the os type
+ elif (i[0] == '-o') or (i[0] == '--os'):
+ ostype = i[1]
+ # print 'os = ' + os
+
+ # define the user
+ elif (i[0] == '-u') or (i[0] == '--user'):
+ user = i[1]
+ outfile = user + '.bat' # Setup the output file name
+ # print 'user = ' + user
+
+ # define the machine
+ elif (i[0] == '-m') or (i[0] == '--machine'):
+ machine = i[1]
+
+ # define the netlogon directory
+ elif (i[0] == '-d') or (i[0] == '--dir'):
+ outdir = i[1]
+ # print 'outdir = ' + outdir
+
+ # if we are asked to turn on debug info, do so.
+ elif (i[0] == '--debug'):
+ debug = 1
+ # print 'debug = ' + debug
+
+ # if we are asked to turn on the automatic pause functionality, do so
+ elif (i[0] == '--pause'):
+ pause = 1
+ # print 'pause = ' + pause
+
+ # if we are asked for the version number, print it.
+ elif (i[0] == '-v') or (i[0] == '--version'):
+ print version
+ sys.exit(0)
+
+ # if we are asked for help print the docstring.
+ elif (i[0] == '-h') or (i[0] == '--help'):
+ print __doc__
+ sys.exit(0)
+
+ #
+ # open the configuration file
+ #
+ try:
+ iFile = open(configfile, 'r')
+ except IOError:
+ print 'Unable to open configuration file: ' + configfile
+ sys.exit(1)
+
+ #
+ # open the output file
+ #
+ if not debug:
+ try:
+ oFile = open(outdir + outfile, 'w')
+ except IOError:
+ print 'Unable to open logon script file: ' + outdir + outfile
+ sys.exit(1)
+
+ buf = iFile.readlines() # read in the entire configuration file
+
+ #
+ # call the script building routine
+ #
+ script = buildScript(buf, sections, group, user, ostype, machine, debug, pause)
+
+ #
+ # write out the script file
+ #
+ if not debug:
+ for ln in script:
+ oFile.write(ln + '\r\n')
+ if pause:
+ if string.strip(ln) != '': # Because whitespace
+ oFile.write('pause' + '\r\n') # is a useful tool, we
+ # don't put pauses after
+ # an empty line.
+
+
+# End run()
+
+#
+# immediate-mode commands, for drag-and-drop or execfile() execution
+#
+if __name__ == '__main__':
+ run()
+else:
+ print "Module ntlogon.py imported."
+ print "To run, type: ntlogon.run()"
+ print "To reload after changes to the source, type: reload(ntlogon)"
+
+#
+# End NTLogon.py
+#
diff --git a/examples/misc/adssearch.pl b/examples/misc/adssearch.pl
new file mode 100755
index 0000000..fc24811
--- /dev/null
+++ b/examples/misc/adssearch.pl
@@ -0,0 +1,1897 @@
+#!/usr/bin/perl -w
+#
+# adssearch.pl - query an Active Directory server and
+# display objects in a human readable format
+#
+# Copyright (C) Guenther Deschner <gd@samba.org> 2003-2008
+#
+# TODO: add range retrieval
+# write sddl-converter, decode userParameters
+# apparently only win2k3 allows simple-binds with machine-accounts.
+# make sasl support independent from Authen::SASL::Cyrus v >0.11
+use strict;
+
+use Net::LDAP;
+use Net::LDAP::Control;
+use Net::LDAP::Constant qw(LDAP_REFERRAL);
+use Convert::ASN1;
+use Time::Local;
+use POSIX qw(strftime);
+use Getopt::Long;
+
+my $have_sasl;
+my $works_sasl;
+my $pref_version;
+BEGIN {
+ my $class = 'Authen::SASL';
+ $pref_version = "0.32";
+ if ( eval "require $class;" ) {
+ $have_sasl = 1;
+ }
+ if ( eval "Net::LDAP->VERSION($pref_version);" ) {
+ $works_sasl = 1;
+ }
+}
+
+# users may set defaults here
+my $base = "";
+my $binddn = "";
+my $password = "";
+my $server = "";
+my $rebind_url;
+
+
+my $tdbdump = "/usr/bin/tdbdump";
+my $ntdbdump = "/usr/bin/ntdbdump";
+my $testparm = "/usr/bin/testparm";
+my $net = "/usr/bin/net";
+my $dig = "/usr/bin/dig";
+my $nmblookup = "/usr/bin/nmblookup";
+my $secrets_tdb = "/etc/samba/secrets.tdb";
+my $secrets_ntdb = "/etc/samba/secrets.ntdb";
+my $klist = "/usr/bin/klist";
+my $kinit = "/usr/bin/kinit";
+my $workgroup = "";
+my $machine = "";
+my $realm = "";
+
+# parse input
+my (
+ $opt_asq,
+ $opt_base,
+ $opt_binddn,
+ $opt_debug,
+ $opt_display_extendeddn,
+ $opt_display_metadata,
+ $opt_display_raw,
+ $opt_domain_scope,
+ $opt_dump_rootdse,
+ $opt_dump_schema,
+ $opt_dump_wknguid,
+ $opt_fastbind,
+ $opt_help,
+ $opt_host,
+ $opt_machine,
+ $opt_notify,
+ $opt_notify_nodiffs,
+ $opt_paging,
+ $opt_password,
+ $opt_port,
+ $opt_realm,
+ $opt_saslmech,
+ $opt_search_opt,
+ $opt_scope,
+ $opt_simpleauth,
+ $opt_starttls,
+ $opt_user,
+ $opt_verbose,
+ $opt_workgroup,
+);
+
+GetOptions(
+ 'asq=s' => \$opt_asq,
+ 'base|b=s' => \$opt_base,
+ 'D|DN=s' => \$opt_binddn,
+ 'debug=i' => \$opt_debug,
+ 'domain_scope' => \$opt_domain_scope,
+ 'extendeddn|e:i' => \$opt_display_extendeddn,
+ 'fastbind' => \$opt_fastbind,
+ 'help' => \$opt_help,
+ 'host|h=s' => \$opt_host,
+ 'machine|P' => \$opt_machine,
+ 'metadata|m' => \$opt_display_metadata,
+ 'nodiffs' => \$opt_notify_nodiffs,
+ 'notify|n' => \$opt_notify,
+ 'paging:i' => \$opt_paging,
+ 'password|w=s' => \$opt_password,
+ 'port=i' => \$opt_port,
+ 'rawdisplay' => \$opt_display_raw,
+ 'realm|R=s' => \$opt_realm,
+ 'rootDSE' => \$opt_dump_rootdse,
+ 'saslmech|Y=s' => \$opt_saslmech,
+ 'schema|c' => \$opt_dump_schema,
+ 'scope|s=s' => \$opt_scope,
+ 'searchopt:i' => \$opt_search_opt,
+ 'simpleauth|x' => \$opt_simpleauth,
+ 'tls|Z' => \$opt_starttls,
+ 'user|U=s' => \$opt_user,
+ 'verbose|v' => \$opt_verbose,
+ 'wknguid' => \$opt_dump_wknguid,
+ 'workgroup|k=s' => \$opt_workgroup,
+ );
+
+
+if (!@ARGV && !$opt_dump_schema && !$opt_dump_rootdse && !$opt_notify || $opt_help) {
+ usage();
+ exit 1;
+}
+
+if ($opt_fastbind && !$opt_simpleauth) {
+ printf("LDAP fast bind can only be performed with simple binds\n");
+ exit 1;
+}
+
+if ($opt_notify) {
+ $opt_paging = undef;
+}
+
+# get the query
+my $query = shift;
+my @attrs = @ARGV;
+
+# some global vars
+my $filter = "";
+my ($dse, $uri);
+my ($attr, $value);
+my (@ctrls, @ctrls_s);
+my ($ctl_paged, $cookie);
+my ($page_count, $total_entry_count);
+my ($sasl_hd, $async_ldap_hd, $sync_ldap_hd);
+my ($mesg, $usn);
+my (%entry_store);
+my $async_search;
+
+# fixed values and vars
+my $set = "X";
+my $unset = "-";
+my $tabsize = "\t\t\t";
+
+# get defaults
+my $scope = $opt_scope || "sub";
+my $port = $opt_port;
+
+my %ads_controls = (
+"LDAP_SERVER_NOTIFICATION_OID" => "1.2.840.113556.1.4.528",
+"LDAP_SERVER_EXTENDED_DN_OID" => "1.2.840.113556.1.4.529",
+"LDAP_PAGED_RESULT_OID_STRING" => "1.2.840.113556.1.4.319",
+"LDAP_SERVER_SD_FLAGS_OID" => "1.2.840.113556.1.4.801",
+"LDAP_SERVER_SORT_OID" => "1.2.840.113556.1.4.473",
+"LDAP_SERVER_RESP_SORT_OID" => "1.2.840.113556.1.4.474",
+"LDAP_CONTROL_VLVREQUEST" => "2.16.840.1.113730.3.4.9",
+"LDAP_CONTROL_VLVRESPONSE" => "2.16.840.1.113730.3.4.10",
+"LDAP_SERVER_RANGE_RETRIEVAL" => "1.2.840.113556.1.4.802", #unsure
+"LDAP_SERVER_SHOW_DELETED_OID" => "1.2.840.113556.1.4.417",
+"LDAP_SERVER_CROSSDOM_MOVE_TARGET_OID" => "1.2.840.113556.1.4.521",
+"LDAP_SERVER_LAZY_COMMIT_OID" => "1.2.840.113556.1.4.619",
+"LDAP_SERVER_TREE_DELETE_OID" => "1.2.840.113556.1.4.805",
+"LDAP_SERVER_DIRSYNC_OID" => "1.2.840.113556.1.4.841",
+"LDAP_SERVER_VERIFY_NAME_OID" => "1.2.840.113556.1.4.1338",
+"LDAP_SERVER_DOMAIN_SCOPE_OID" => "1.2.840.113556.1.4.1339",
+"LDAP_SERVER_SEARCH_OPTIONS_OID" => "1.2.840.113556.1.4.1340",
+"LDAP_SERVER_PERMISSIVE_MODIFY_OID" => "1.2.840.113556.1.4.1413",
+"LDAP_SERVER_ASQ_OID" => "1.2.840.113556.1.4.1504",
+"NONE (Get stats control)" => "1.2.840.113556.1.4.970",
+"LDAP_SERVER_QUOTA_CONTROL_OID" => "1.2.840.113556.1.4.1852",
+"LDAP_SERVER_SHUTDOWN_NOTIFY_OID" => "1.2.840.113556.1.4.1907",
+);
+
+my %ads_capabilities = (
+"LDAP_CAP_ACTIVE_DIRECTORY_OID" => "1.2.840.113556.1.4.800",
+"LDAP_CAP_ACTIVE_DIRECTORY_V51_OID" => "1.2.840.113556.1.4.1670",
+"LDAP_CAP_ACTIVE_DIRECTORY_LDAP_INTEG_OID" => "1.2.840.113556.1.4.1791",
+);
+
+my %ads_extensions = (
+"LDAP_START_TLS_OID" => "1.3.6.1.4.1.1466.20037",
+"LDAP_TTL_EXTENDED_OP_OID" => "1.3.6.1.4.1.1466.101.119.1",
+"LDAP_SERVER_FAST_BIND_OID" => "1.2.840.113556.1.4.1781",
+"NONE (TTL refresh extended op)" => "1.3.6.1.4.1.1466.101.119.1",
+);
+
+my %ads_matching_rules = (
+"LDAP_MATCHING_RULE_BIT_AND" => "1.2.840.113556.1.4.803",
+"LDAP_MATCHING_RULE_BIT_OR" => "1.2.840.113556.1.4.804",
+);
+
+my %wknguids = (
+"WELL_KNOWN_GUID_COMPUTERS" => "AA312825768811D1ADED00C04FD8D5CD",
+"WELL_KNOWN_GUID_DOMAIN_CONTROLLERS" => "A361B2FFFFD211D1AA4B00C04FD7D83A",
+"WELL_KNOWN_GUID_SYSTEM" => "AB1D30F3768811D1ADED00C04FD8D5CD",
+"WELL_KNOWN_GUID_USERS" => "A9D1CA15768811D1ADED00C04FD8D5CD",
+);
+
+my %ads_systemflags = (
+"FLAG_DONT_REPLICATE" => 0x00000001, # 1
+"FLAG_REPLICATE_TO_GC" => 0x00000002, # 2
+"FLAG_ATTRIBUTE_CONSTRUCT" => 0x00000004, # 4
+"FLAG_CATEGORY_1_OBJECT" => 0x00000010, # 16
+"FLAG_DELETE_WITHOUT_TOMBSTONE" => 0x02000000, # 33554432
+"FLAG_DOMAIN_DISALLOW_MOVE" => 0x04000000, # 67108864
+"FLAG_DOMAIN_DISALLOW_RENAME" => 0x08000000, # 134217728
+#"FLAG_CONFIG_CAN_MOVE_RESTRICTED" => 0x10000000, # 268435456 # only setable on creation
+#"FLAG_CONFIG_CAN_MOVE" => 0x20000000, # 536870912 # only setable on creation
+#"FLAG_CONFIG_CAN_RENAME" => 0x40000000, # 1073741824 # only setable on creation
+"FLAG_DISALLOW_DELETE" => 0x80000000, # 2147483648
+);
+
+my %ads_mixed_domain = (
+"NATIVE_LEVEL_DOMAIN" => 0,
+"MIXED_LEVEL_DOMAIN" => 1,
+);
+
+my %ads_ds_func = (
+"DS_BEHAVIOR_WIN2000" => 0, # untested
+"DS_BEHAVIOR_WIN2003" => 2,
+"DS_BEHAVIOR_WIN2008" => 3,
+);
+
+my %ads_instance_type = (
+"DS_INSTANCETYPE_IS_NC_HEAD" => 0x1,
+"IT_WRITE" => 0x4,
+"IT_NC_ABOVE" => 0x8,
+);
+
+my %ads_uacc = (
+ "ACCOUNT_NEVER_EXPIRES" => 0x000000, # 0
+ "ACCOUNT_OK" => 0x800000, # 8388608
+ "ACCOUNT_LOCKED_OUT" => 0x800010, # 8388624
+);
+
+my %ads_enctypes = (
+ "DES-CBC-CRC" => 0x01,
+ "DES-CBC-MD5" => 0x02,
+ "RC4_HMAC_MD5" => 0x04,
+ "AES128_CTS_HMAC_SHA1_96" => 0x08,
+ "AES128_CTS_HMAC_SHA1_128" => 0x10,
+);
+
+my %ads_gpoptions = (
+ "GPOPTIONS_INHERIT" => 0,
+ "GPOPTIONS_BLOCK_INHERITANCE" => 1,
+);
+
+my %ads_gplink_opts = (
+ "GPLINK_OPT_NONE" => 0,
+ "GPLINK_OPT_DISABLED" => 1,
+ "GPLINK_OPT_ENFORCED" => 2,
+);
+
+my %ads_gpflags = (
+ "GPFLAGS_ALL_ENABLED" => 0,
+ "GPFLAGS_USER_SETTINGS_DISABLED" => 1,
+ "GPFLAGS_MACHINE_SETTINGS_DISABLED" => 2,
+ "GPFLAGS_ALL_DISABLED" => 3,
+);
+
+my %ads_serverstate = (
+ "SERVER_ENABLED" => 1,
+ "SERVER_DISABLED" => 2,
+);
+
+my %ads_sdeffective = (
+ "OWNER_SECURITY_INFORMATION" => 0x01,
+ "DACL_SECURITY_INFORMATION" => 0x04,
+ "SACL_SECURITY_INFORMATION" => 0x10,
+);
+
+my %ads_trustattrs = (
+ "TRUST_ATTRIBUTE_NON_TRANSITIVE" => 0x00000001,
+ "TRUST_ATTRIBUTE_UPLEVEL_ONLY" => 0x00000002,
+ "TRUST_ATTRIBUTE_QUARANTINED_DOMAIN" => 0x00000004,
+ "TRUST_ATTRIBUTE_FOREST_TRANSITIVE" => 0x00000008,
+ "TRUST_ATTRIBUTE_CROSS_ORGANIZATION" => 0x00000010,
+ "TRUST_ATTRIBUTE_WITHIN_FOREST" => 0x00000020,
+ "TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL" => 0x00000040,
+ "TRUST_ATTRIBUTE_USES_RC4_ENCRYPTION" => 0x00000080,
+ "TRUST_ATTRIBUTE_CROSS_ORGANIZATION_NO_TGT_DELEGATION" => 0x00000200,
+ "TRUST_ATTRIBUTE_PIM_TRUST" => 0x00000400,
+ "TRUST_ATTRIBUTE_CROSS_ORGANIZATION_ENABLE_TGT_DELEGATION" => 0x00000800,
+);
+
+my %ads_trustdirection = (
+ "TRUST_DIRECTION_INBOUND" => 1,
+ "TRUST_DIRECTION_OUTBOUND" => 2,
+ "TRUST_DIRECTION_BIDIRECTIONAL" => 3,
+);
+
+my %ads_trusttype = (
+ "TRUST_TYPE_DOWNLEVEL" => 1,
+ "TRUST_TYPE_UPLEVEL" => 2,
+ "TRUST_TYPE_KERBEROS" => 3,
+ "TRUST_TYPE_DCE" => 4,
+);
+
+my %ads_pwdproperties = (
+ "DOMAIN_PASSWORD_COMPLEX" => 1,
+ "DOMAIN_PASSWORD_NO_ANON_CHANGE" => 2,
+ "DOMAIN_PASSWORD_NO_CLEAR_CHANGE" => 4,
+ "DOMAIN_LOCKOUT_ADMINS" => 8,
+ "DOMAIN_PASSWORD_STORE_CLEARTEXT" => 16,
+ "DOMAIN_REFUSE_PASSWORD_CHANGE" => 32,
+);
+
+my %ads_uascompat = (
+ "LANMAN_USER_ACCOUNT_SYSTEM_NOLIMITS" => 0,
+ "LANMAN_USER_ACCOUNT_SYSTEM_COMPAT" => 1,
+);
+
+my %ads_frstypes = (
+ "REPLICA_SET_SYSVOL" => 2, # unsure
+ "REPLICA_SET_DFS" => 1, # unsure
+ "REPLICA_SET_OTHER" => 0, # unsure
+);
+
+my %ads_gp_cse_extensions = (
+"Administrative Templates Extension" => "35378EAC-683F-11D2-A89A-00C04FBBCFA2",
+"Disk Quotas" => "3610EDA5-77EF-11D2-8DC5-00C04FA31A66",
+"EFS Recovery" => "B1BE8D72-6EAC-11D2-A4EA-00C04F79F83A",
+"Folder Redirection" => "25537BA6-77A8-11D2-9B6C-0000F8080861",
+"IP Security" => "E437BC1C-AA7D-11D2-A382-00C04F991E27",
+"Internet Explorer Maintenance" => "A2E30F80-D7DE-11d2-BBDE-00C04F86AE3B",
+"QoS Packet Scheduler" => "426031c0-0b47-4852-b0ca-ac3d37bfcb39",
+"Scripts" => "42B5FAAE-6536-11D2-AE5A-0000F87571E3",
+"Security" => "827D319E-6EAC-11D2-A4EA-00C04F79F83A",
+"Software Installation" => "C6DC5466-785A-11D2-84D0-00C04FB169F7",
+);
+
+# guess work
+my %ads_gpcextensions = (
+"Administrative Templates" => "0F6B957D-509E-11D1-A7CC-0000F87571E3",
+"Certificates" => "53D6AB1D-2488-11D1-A28C-00C04FB94F17",
+"EFS recovery policy processing" => "B1BE8D72-6EAC-11D2-A4EA-00C04F79F83A",
+"Folder Redirection policy processing" => "25537BA6-77A8-11D2-9B6C-0000F8080861",
+"Folder Redirection" => "88E729D6-BDC1-11D1-BD2A-00C04FB9603F",
+"Registry policy processing" => "35378EAC-683F-11D2-A89A-00C04FBBCFA2",
+"Remote Installation Services" => "3060E8CE-7020-11D2-842D-00C04FA372D4",
+"Security Settings" => "803E14A0-B4FB-11D0-A0D0-00A0C90F574B",
+"Security policy processing" => "827D319E-6EAC-11D2-A4EA-00C04F79F83A",
+"unknown" => "3060E8D0-7020-11D2-842D-00C04FA372D4",
+"unknown2" => "53D6AB1B-2488-11D1-A28C-00C04FB94F17",
+);
+
+my %ads_gpo_default_guids = (
+"Default Domain Policy" => "31B2F340-016D-11D2-945F-00C04FB984F9",
+"Default Domain Controllers Policy" => "6AC1786C-016F-11D2-945F-00C04fB984F9",
+"mist" => "61718096-3D3F-4398-8318-203A48976F9E",
+);
+
+my %ads_uf = (
+ "UF_SCRIPT" => 0x00000001,
+ "UF_ACCOUNTDISABLE" => 0x00000002,
+# "UF_UNUSED_1" => 0x00000004,
+ "UF_HOMEDIR_REQUIRED" => 0x00000008,
+ "UF_LOCKOUT" => 0x00000010,
+ "UF_PASSWD_NOTREQD" => 0x00000020,
+ "UF_PASSWD_CANT_CHANGE" => 0x00000040,
+ "UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED" => 0x00000080,
+ "UF_TEMP_DUPLICATE_ACCOUNT" => 0x00000100,
+ "UF_NORMAL_ACCOUNT" => 0x00000200,
+# "UF_UNUSED_2" => 0x00000400,
+ "UF_INTERDOMAIN_TRUST_ACCOUNT" => 0x00000800,
+ "UF_WORKSTATION_TRUST_ACCOUNT" => 0x00001000,
+ "UF_SERVER_TRUST_ACCOUNT" => 0x00002000,
+# "UF_UNUSED_3" => 0x00004000,
+# "UF_UNUSED_4" => 0x00008000,
+ "UF_DONT_EXPIRE_PASSWD" => 0x00010000,
+ "UF_MNS_LOGON_ACCOUNT" => 0x00020000,
+ "UF_SMARTCARD_REQUIRED" => 0x00040000,
+ "UF_TRUSTED_FOR_DELEGATION" => 0x00080000,
+ "UF_NOT_DELEGATED" => 0x00100000,
+ "UF_USE_DES_KEY_ONLY" => 0x00200000,
+ "UF_DONT_REQUIRE_PREAUTH" => 0x00400000,
+ "UF_PASSWORD_EXPIRED" => 0x00800000,
+ "UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION" => 0x01000000,
+ "UF_NO_AUTH_DATA_REQUIRED" => 0x02000000,
+# "UF_UNUSED_8" => 0x04000000,
+# "UF_UNUSED_9" => 0x08000000,
+# "UF_UNUSED_10" => 0x10000000,
+# "UF_UNUSED_11" => 0x20000000,
+# "UF_UNUSED_12" => 0x40000000,
+# "UF_UNUSED_13" => 0x80000000,
+);
+
+my %ads_grouptype = (
+ "GROUP_TYPE_BUILTIN_LOCAL_GROUP" => 0x00000001,
+ "GROUP_TYPE_ACCOUNT_GROUP" => 0x00000002,
+ "GROUP_TYPE_RESOURCE_GROUP" => 0x00000004,
+ "GROUP_TYPE_UNIVERSAL_GROUP" => 0x00000008,
+ "GROUP_TYPE_APP_BASIC_GROUP" => 0x00000010,
+ "GROUP_TYPE_APP_QUERY_GROUP" => 0x00000020,
+ "GROUP_TYPE_SECURITY_ENABLED" => 0x80000000,
+);
+
+my %ads_atype = (
+ "ATYPE_NORMAL_ACCOUNT" => 0x30000000,
+ "ATYPE_WORKSTATION_TRUST" => 0x30000001,
+ "ATYPE_INTERDOMAIN_TRUST" => 0x30000002,
+ "ATYPE_SECURITY_GLOBAL_GROUP" => 0x10000000,
+ "ATYPE_DISTRIBUTION_GLOBAL_GROUP" => 0x10000001,
+ "ATYPE_DISTRIBUTION_UNIVERSAL_GROUP" => 0x10000001, # ATYPE_DISTRIBUTION_GLOBAL_GROUP
+ "ATYPE_SECURITY_LOCAL_GROUP" => 0x20000000,
+ "ATYPE_DISTRIBUTION_LOCAL_GROUP" => 0x20000001,
+ "ATYPE_ACCOUNT" => 0x30000000, # ATYPE_NORMAL_ACCOUNT
+ "ATYPE_GLOBAL_GROUP" => 0x10000000, # ATYPE_SECURITY_GLOBAL_GROUP
+ "ATYPE_LOCAL_GROUP" => 0x20000000, # ATYPE_SECURITY_LOCAL_GROUP
+);
+
+my %ads_gtype = (
+ "GTYPE_SECURITY_BUILTIN_LOCAL_GROUP" => 0x80000005,
+ "GTYPE_SECURITY_DOMAIN_LOCAL_GROUP" => 0x80000004,
+ "GTYPE_SECURITY_GLOBAL_GROUP" => 0x80000002,
+ "GTYPE_SECURITY_UNIVERSAL_GROUP" => 0x80000008,
+ "GTYPE_DISTRIBUTION_GLOBAL_GROUP" => 0x00000002,
+ "GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP" => 0x00000004,
+ "GTYPE_DISTRIBUTION_UNIVERSAL_GROUP" => 0x00000008,
+);
+
+my %munged_dial = (
+ "CtxCfgPresent" => \&dump_int,
+ "CtxCfgFlags1" => \&dump_int,
+ "CtxCallback" => \&dump_string,
+ "CtxShadow" => \&dump_string,
+ "CtxMaxConnectionTime" => \&dump_int,
+ "CtxMaxDisconnectionTime"=> \&dump_int,
+ "CtxMaxIdleTime" => \&dump_int,
+ "CtxKeyboardLayout" => \&dump_int,
+ "CtxMinEncryptionLevel" => \&dump_int,
+ "CtxWorkDirectory" => \&dump_string,
+ "CtxNWLogonServer" => \&dump_string,
+ "CtxWFHomeDir" => \&dump_string,
+ "CtxWFHomeDirDrive" => \&dump_string,
+ "CtxWFProfilePath" => \&dump_string,
+ "CtxInitialProgram" => \&dump_string,
+ "CtxCallbackNumber" => \&dump_string,
+);
+
+$SIG{__WARN__} = sub {
+ use Carp;
+ Carp::cluck (shift);
+};
+
+# if there is data missing, we try to autodetect with samba-tools (if installed)
+# this might fill up workgroup, machine, realm
+get_samba_info();
+
+# get a workgroup
+$workgroup = $workgroup || $opt_workgroup || "";
+
+# get the server
+$server = process_servername($opt_host) ||
+ detect_server($workgroup,$opt_realm) ||
+ die "please define server to query with -h host\n";
+
+
+# get the base
+$base = defined($opt_base)? $opt_base : "" ||
+ get_base_from_rootdse($server,$dse);
+
+# get the realm
+$realm = $opt_realm ||
+ get_realm_from_rootdse($server,$dse);
+
+# get sasl mechs
+my @sasl_mechs = get_sasl_mechs_from_rootdse($server,$dse);
+my $sasl_mech = "GSSAPI";
+if ($opt_saslmech) {
+ $sasl_mech = sprintf("%s", (check_sasl_mech($opt_saslmech) == 0)?uc($opt_saslmech):"");
+}
+
+# set bind type
+my $sasl_bind = 1 if (!$opt_simpleauth);
+
+# get username
+my $user = check_user($opt_user) || $ENV{'USER'} || "";
+
+# gen upn
+my $upn = sprintf("%s", gen_upn($opt_machine ? "$machine\$" : $user, $realm));
+
+# get binddn
+$binddn = $opt_binddn || $upn;
+
+# get the password
+$password = $password || $opt_password;
+if (!$password) {
+ $password = $opt_machine ? get_machine_password($workgroup) : get_password();
+}
+
+my %attr_handler = (
+ "Token-Groups-No-GC-Acceptable" => \&dump_sid, #wrong name
+ "accountExpires" => \&dump_nttime,
+ "attributeSecurityGUID" => \&dump_guid,
+ "badPasswordTime" => \&dump_nttime,
+ "creationTime" => \&dump_nttime,
+ "currentTime" => \&dump_timestr,
+ "domainControllerFunctionality" => \&dump_ds_func,
+ "domainFunctionality" => \&dump_ds_func,
+ "fRSReplicaSetGUID" => \&dump_guid,
+ "fRSReplicaSetType" => \&dump_frstype,
+ "fRSVersionGUID" => \&dump_guid,
+ "flags" => \&dump_gpflags, # fixme: possibly only on gpos!
+ "forceLogoff" => \&dump_nttime_abs,
+ "forestFunctionality" => \&dump_ds_func,
+# "gPCMachineExtensionNames" => \&dump_gpcextensions,
+# "gPCUserExtensionNames" => \&dump_gpcextensions,
+ "gPLink" => \&dump_gplink,
+ "gPOptions" => \&dump_gpoptions,
+ "groupType" => \&dump_gtype,
+ "instanceType" => \&dump_instance_type,
+ "lastLogon" => \&dump_nttime,
+ "lastLogonTimestamp" => \&dump_nttime,
+ "lastSetTime" => \&dump_nttime,
+ "lockOutObservationWindow" => \&dump_nttime_abs,
+ "lockoutDuration" => \&dump_nttime_abs,
+ "lockoutTime" => \&dump_nttime,
+# "logonHours" => \&dump_logonhours,
+ "maxPwdAge" => \&dump_nttime_abs,
+ "minPwdAge" => \&dump_nttime_abs,
+ "modifyTimeStamp" => \&dump_timestr,
+ "msDS-Behavior-Version" => \&dump_ds_func, #unsure
+ "msDS-User-Account-Control-Computed" => \&dump_uacc,
+ "msDS-SupportedEncryptionTypes" => \&dump_enctypes,
+ "mS-DS-CreatorSID" => \&dump_sid,
+# "msRADIUSFramedIPAddress" => \&dump_ipaddr,
+# "msRASSavedFramedIPAddress" => \&dump_ipaddr,
+ "netbootGUID" => \&dump_guid,
+ "nTMixedDomain" => \&dump_mixed_domain,
+ "nTSecurityDescriptor" => \&dump_secdesc,
+ "objectGUID" => \&dump_guid,
+ "objectSid" => \&dump_sid,
+ "pKT" => \&dump_pkt,
+ "pKTGuid" => \&dump_guid,
+ "priorSetTime" => \&dump_nttime,
+ "pwdLastSet" => \&dump_nttime,
+ "pwdProperties" => \&dump_pwdproperties,
+ "sAMAccountType" => \&dump_atype,
+ "schemaIDGUID" => \&dump_guid,
+ "sDRightsEffective" => \&dump_sdeffective,
+ "securityIdentifier" => \&dump_sid,
+ "serverState" => \&dump_serverstate,
+ "supportedCapabilities", => \&dump_capabilities,
+ "supportedControl", => \&dump_controls,
+ "supportedExtension", => \&dump_extension,
+ "systemFlags" => \&dump_systemflags,
+ "tokenGroups", => \&dump_sid,
+ "tokenGroupsGlobalAndUniversal" => \&dump_sid,
+ "tokenGroupsNoGCAcceptable" => \&dump_sid,
+ "trustAttributes" => \&dump_trustattr,
+ "trustDirection" => \&dump_trustdirection,
+ "trustType" => \&dump_trusttype,
+ "uASCompat" => \&dump_uascompat,
+ "userAccountControl" => \&dump_uac,
+ "userCertificate" => \&dump_cert,
+ "userFlags" => \&dump_uf,
+ "userParameters" => \&dump_munged_dial,
+ "whenChanged" => \&dump_timestr,
+ "whenCreated" => \&dump_timestr,
+# "dSCorePropagationData" => \&dump_timestr,
+);
+
+
+
+################
+# subfunctions #
+################
+
+sub usage {
+ print "usage: $0 [--asq] [--base|-b base] [--debug level] [--debug level] [--DN|-D binddn] [--extendeddn|-e] [--help] [--host|-h host] [--machine|-P] [--metadata|-m] [--nodiffs] [--notify|-n] [--password|-w password] [--port port] [--rawdisplay] [--realm|-R realm] [--rootdse] [--saslmech|-Y saslmech] [--schema|-c] [--scope|-s scope] [--simpleauth|-x] [--starttls|-Z] [--user|-U user] [--wknguid] [--workgroup|-k workgroup] filter [attrs]\n";
+ print "\t--asq [attribute]\n\t\tAttribute to use for a attribute scoped query (LDAP_SERVER_ASQ_OID)\n";
+ print "\t--base|-b [base]\n\t\tUse base [base]\n";
+ print "\t--debug [level]\n\t\tUse debuglevel (for Net::LDAP)\n";
+ print "\t--domain_scope\n\t\tLimit LDAP search to local domain (LDAP_SERVER_DOMAIN_SCOPE_OID)\n";
+ print "\t--DN|-D [binddn]\n\t\tUse binddn or principal\n";
+ print "\t--extendeddn|-e [value]\n\t\tDisplay extended dn (LDAP_SERVER_EXTENDED_DN_OID)\n";
+ print "\t--fastbind\n\t\tDo LDAP fast bind using LDAP_SERVER_FAST_BIND_OID extension\n";
+ print "\t--help\n\t\tDisplay help page\n";
+ print "\t--host|-h [host]\n\t\tQuery Host [host] (either a hostname or an LDAP uri)\n";
+ print "\t--machine|-P\n\t\tUse samba3 machine account stored in $secrets_tdb (needs root access)\n";
+ print "\t--metdata|-m\n\t\tDisplay replication metadata\n";
+ print "\t--nodiffs\n\t\tDisplay no diffs but full entry dump when running in notify mode\n";
+ print "\t--notify|-n\n\t\tActivate asynchronous change notification (LDAP_SERVER_NOTIFICATION_OID)\n";
+ print "\t--paging [pagesize]\n\t\tUse paged results when searching\n";
+ print "\t--password|-w [password]\n\t\tUse [password] for binddn\n";
+ print "\t--port [port]\n\t\tUse [port] when connecting ADS\n";
+ print "\t--rawdisplay\n\t\tDo not interpret values\n";
+ print "\t--realm|-R [realm]\n\t\tUse [realm] when trying to construct bind-principal\n";
+ print "\t--rootdse\n\t\tDisplay RootDSE (anonymously)\n";
+ print "\t--saslmech|-Y [saslmech]\n\t\tUse SASL Mechanism [saslmech] when binding\n";
+ print "\t--schema|-c\n\t\tDisplay DSE-Schema\n";
+ print "\t--scope|-s [scope]\n\t\tUse scope [scope] (sub, base, one)\n";
+ print "\t--simpleauth|-x\n\t\tUse simple bind (otherwise SASL binds are performed)\n";
+ print "\t--starttls|-Z\n\t\tUse Start TLS extended operation to secure LDAP traffic\n";
+ print "\t--user|-U [user]\n\t\tUse [user]\n";
+ print "\t--wknguid\n\t\tDisplay well known guids\n";
+ print "\t--workgroup|-k [workgroup]\n\t\tWhen LDAP-Server is not known try to find a Domain-Controller for [workgroup]\n";
+}
+
+sub write_ads_list {
+ my ($mod,$attr,$value) = @_;
+ my $ofh = select(STDOUT);
+ $~ = "ADS_LIST";
+ select($ofh);
+ write();
+
+format ADS_LIST =
+@<<<< @>>>>>>>>>>>>>>>>>>>>>>>: @*
+$mod, $attr, $value
+.
+}
+
+sub write_ads {
+ my ($mod,$attr,$value) = @_;
+ my $ofh = select(STDOUT);
+ $~ = "ADS";
+ select($ofh);
+ write();
+
+format ADS =
+@<<<< @>>>>>>>>>>>>>>>>>>>>>>>: ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+$mod, $attr, $value
+~~ ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+ $value
+.
+}
+
+sub detect_server {
+
+ my $workgroup = shift;
+ my $realm = shift;
+ my $result;
+ my $found;
+
+ # try net cache (nbt records)
+ if ( -x $net && $workgroup ) {
+ my $key = sprintf("NBT/%s#1C", uc($workgroup));
+ chomp($result = `$net cache search $key 2>&1 /dev/null`);
+ $result =~ s/^.*Value: //;
+ $result =~ s/:.*//;
+ return $result if $result;
+ printf("%10s query failed for [%s]\n", "net cache", $key);
+ }
+
+ # try dns SRV entries
+ if ( -x $dig && $realm ) {
+ my $key = sprintf("_ldap._tcp.%s", lc($realm));
+ chomp($result = `$dig $key SRV +short +search | egrep "^[0-9]" | head -1`);
+ $result =~ s/.* //g;
+ $result =~ s/.$//g;
+ return $result if $result;
+ printf("%10s query failed for [%s]\n", "dns", $key);
+ }
+
+ # try netbios broadcast query
+ if ( -x $nmblookup && $workgroup ) {
+ my $key = sprintf("%s#1C", uc($workgroup));
+ my $pattern = sprintf("%s<1c>", uc($workgroup));
+ chomp($result = `$nmblookup $key -d 0 | grep '$pattern'`);
+ $result =~ s/\s.*//;
+ return $result if $result;
+ printf("%10s query failed for [%s]\n", "nmblookup", $key);
+ }
+
+ return "";
+}
+
+sub get_samba_info {
+
+ if (! -x $testparm) { return -1; }
+
+ my $tmp;
+ open(TESTPARM, "$testparm -s -v 2> /dev/null |");
+ while (my $line = <TESTPARM>) {
+ chomp($line);
+ if ($line =~ /netbios name/) {
+ ($tmp, $machine) = split(/=/, $line);
+ $machine =~ s/\s+|\t+//g;
+ }
+ if ($line =~ /realm/) {
+ ($tmp, $realm) = split(/=/, $line);
+ $realm =~ s/\s+|\t+//g;
+ }
+ if ($line =~ /workgroup/) {
+ ($tmp, $workgroup) = split(/=/, $line);
+ $workgroup =~ s/\s+|\t+//g;
+ }
+ }
+ close(TESTPARM);
+ return 0;
+}
+
+sub gen_upn {
+ my $machine = shift;
+ my $realm = shift;
+ if ($machine && $realm) {
+ return sprintf("%s\@%s", lc($machine), uc($realm));
+ };
+ return undef;
+}
+
+sub get_password {
+ if (!$password && $opt_simpleauth && check_ticket($user)) {
+ return prompt_password($user);
+ }
+ return "";
+}
+
+sub get_user {
+ my $user = shift || prompt_user();
+ return $user;
+}
+
+sub get_machine_password {
+
+ my $workgroup = shift || "";
+ $workgroup = uc($workgroup);
+
+ my ($found, $tmp, $dbdump, $db);
+ if (-r $secrets_ntdb) {
+ -x $ntdbdump || die "ntdbdump is not installed. cannot proceed autodetection\n";
+ $dbdump = $ntdbdump;
+ $db = $secrets_ntdb;
+ } else {
+ -x $tdbdump || die "tdbdump is not installed. cannot proceed autodetection\n";
+ -r $secrets_tdb || die "cannot read $secrets_tdb. cannot proceed autodetection\n";
+ $dbdump = $tdbdump;
+ $db = $secrets_tdb;
+ }
+
+ # get machine-password
+ my $key = sprintf("SECRETS/MACHINE_PASSWORD/%s", $workgroup);
+ open(SECRETS,"$dbdump $db |");
+ while(my $line = <SECRETS>) {
+ chomp($line);
+ if ($found) {
+ $line =~ s/\\00//;
+ ($line,$password) = split(/"/, $line);
+ last;
+ }
+ if ($line =~ /\"$key\"/) {
+ $found = 1;
+ }
+ }
+ close(SECRETS);
+
+ if ($found) {
+ print "Successfully autodetected machine password for workgroup: $workgroup\n";
+ return $password;
+ } else {
+ warn "No machine password available for $workgroup\n";
+ }
+ return "";
+}
+
+sub prompt_password {
+
+ my $acct = shift || "";
+ if ($acct =~ /\%/) {
+ ($acct, $password) = split(/\%/, $acct);
+ return $password;
+ }
+ system "stty -echo";
+ print "Enter password for $acct:";
+ my $password = <STDIN>;
+ chomp($password);
+ print "\n";
+ system "stty echo";
+ return $password;
+}
+
+sub prompt_user {
+
+ print "Enter Username:";
+ my $user = <STDIN>;
+ chomp($user);
+ print "\n";
+ return $user;
+}
+
+sub check_ticket {
+ return 0;
+ # works only for heimdal
+ return system("$klist -t");
+}
+
+sub get_ticket {
+
+ my $KRB5_CONFIG = "/tmp/.krb5.conf.telads-$<";
+
+ open(KRB5CONF, "> $KRB5_CONFIG") || die "cannot write $KRB5_CONFIG";
+ printf KRB5CONF "# autogenerated by $0\n";
+ printf KRB5CONF "[libdefaults]\n\tdefault_realm = %s\n\tclockskew = %d\n", uc($realm), 60*60;
+ printf KRB5CONF "[realms]\n\t%s = {\n\t\tkdc = %s\n\t}\n", uc($realm), $server;
+ close(KRB5CONF);
+
+ if ( system("KRB5_CONFIG=$KRB5_CONFIG $kinit $user") != 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+sub check_user {
+ my $acct = shift || "";
+ if ($acct =~ /\%/) {
+ ($acct, $password) = split(/\%/, $acct);
+ }
+ return $acct;
+}
+
+sub check_root_dse($$$@) {
+
+ # bogus function??
+ my $server = shift || "";
+ $dse = shift || get_dse($server) || return -1;
+ my $attr = shift || die "unknown query";
+ my @array = @_;
+
+ my $dse_list = $dse->get_value($attr, asref => '1');
+ my @dse_array = @$dse_list;
+
+ foreach my $i (@array) {
+ # we could use -> supported_control but this
+ # is only available in newer versions of perl-ldap
+# if ( ! $dse->supported_control( $i ) ) {
+ if ( grep(/$i->type()/, @dse_array) ) {
+ printf("required \"$attr\": %s is not supported by ADS-server.\n", $i->type());
+ return -1;
+ }
+ }
+ return 0;
+}
+
+sub check_ctrls ($$@) {
+ my $server = shift;
+ my $dse = shift;
+ my @array = @_;
+ return check_root_dse($server, $dse, "supportedControl", @array);
+}
+
+sub check_exts ($$@) {
+ my $server = shift;
+ my $dse = shift;
+ my @array = @_;
+ return check_root_dse($server, $dse, "supportedExtension", @array);
+}
+
+sub get_base_from_rootdse {
+
+ my $server = shift || "";
+ $dse = shift || get_dse($server,$async_ldap_hd) || return -1;
+ return $dse->get_value($opt_dump_schema ? 'schemaNamingContext':
+ 'defaultNamingContext');
+}
+
+sub get_realm_from_rootdse {
+
+ my $server = shift || "";
+ $dse = shift || get_dse($server,$async_ldap_hd) || return -1;
+ my $service = $dse->get_value('ldapServiceName') || "";
+ if ($service) {
+ my ($t,$realm) = split(/\@/, $service);
+ return $realm;
+ } else {
+ die "very odd: could not get realm";
+ }
+}
+
+sub get_sasl_mechs_from_rootdse {
+
+ my $server = shift || "";
+ $dse = shift || get_dse($server,$async_ldap_hd) || return -1;
+ my $mechs = $dse->get_value('supportedSASLMechanisms', asref => 1);
+ return @$mechs;
+}
+
+sub get_dse {
+
+ my $server = shift || return undef;
+ $async_ldap_hd = shift || get_ldap_hd($server,1);
+ if (!$async_ldap_hd) {
+ print "oh, no connection\n";
+ return undef;
+ }
+ my $mesg = $async_ldap_hd->bind() || die "cannot bind\n";
+ if ($mesg->code) { die "failed to bind\n"; };
+ my $dse = $async_ldap_hd->root_dse( attrs => ['*', "supportedExtension", "supportedFeatures" ] );
+
+ return $dse;
+}
+
+sub process_servername {
+
+ my $name = shift || return "";
+ if ($name =~ /^ldaps:\/\//i ) {
+ $name =~ s#^ldaps://##i;
+ $uri = sprintf("%s://%s", "ldaps", $name);
+ } else {
+ $name =~ s#^ldap://##i;
+ $uri = sprintf("%s://%s", "ldap", $name);
+ }
+ return $name;
+}
+
+sub get_ldap_hd {
+
+ my $server = shift || return undef;
+ my $async = shift || "0";
+ my $hd;
+ die "uri unavailable" if (!$uri);
+ if ($uri =~ /^ldaps:\/\//i ) {
+ $port = $port || 636;
+ use Net::LDAPS;
+ $hd = Net::LDAPS->new( $server, async => $async, port => $port ) ||
+ die "host $server not available: $!";
+ } else {
+ $port = $port || 389;
+ $hd = Net::LDAP->new( $server, async => $async, port => $port ) ||
+ die "host $server not available: $!";
+ }
+ $hd->debug($opt_debug);
+ if ($opt_starttls) {
+ $hd->start_tls( verify => 'none' );
+ }
+
+ return $hd;
+}
+
+sub get_sasl_hd {
+
+ if (!$have_sasl) {
+ print "no sasl support\n";
+ return undef;
+ }
+
+ my $hd;
+ if ($sasl_mech && $sasl_mech eq "GSSAPI") {
+ my $user = sprintf("%s\@%s", $user, uc($realm));
+ if (check_ticket($user) != 0 && get_ticket($user) != 0) {
+ print "Could not get Kerberos ticket for user [$user]\n";
+ return undef;
+ }
+
+ $hd = Authen::SASL->new( mechanism => 'GSSAPI' ) || die "nope";
+ my $conn = $hd->client_new("ldap", $server);
+
+ if ($conn->code == -1) {
+ printf "%s\n", $conn->error();
+ return undef;
+ };
+
+ } elsif ($sasl_mech) {
+
+ # here comes generic sasl code
+ $hd = Authen::SASL->new( mechanism => $sasl_mech,
+ callback => {
+ user => \&get_user,
+ pass => \&get_password
+ }
+ ) || die "nope";
+ } else {
+ $sasl_bind = 0;
+ print "no supported SASL mechanism found (@sasl_mechs).\n";
+ print "falling back to simple bind.\n";
+ return undef;
+ }
+
+ return $hd;
+}
+
+sub check_sasl_mech {
+ my $mech_check = shift;
+ my $have_mech = 0;
+ foreach my $mech (@sasl_mechs) {
+ $have_mech = 1 if ($mech eq uc($mech_check));
+ }
+ if (!$have_mech) {
+ return -1;
+ }
+ return 0;
+}
+
+sub store_result ($) {
+
+ my $entry = shift;
+ return if (!$entry);
+ $entry_store{$entry->dn} = $entry;
+}
+
+sub display_result_diff ($) {
+
+ my $entry_new = shift;
+ return if ( !$entry_new);
+
+ if ( !exists $entry_store{$entry_new->dn}) {
+ print "can't display any differences yet. full dump...\n";
+ display_entry_generic($entry_new);
+ return;
+ }
+
+ my $entry_old = $entry_store{$entry_new->dn};
+
+ foreach my $attr (sort $entry_new->attributes) {
+ if ( $entry_new->exists($attr) && ! $entry_old->exists($attr)) {
+ display_attr_generic("add:\t", $entry_new, $attr);
+ next;
+ }
+ }
+
+ foreach my $attr (sort $entry_old->attributes) {
+ if (! $entry_new->exists($attr) && $entry_old->exists($attr)) {
+ display_attr_generic("del:\t", $entry_old, $attr);
+ next;
+ }
+
+ # now check for all values if they have changed, display changes
+ my ($old_vals, $new_vals, @old_vals, @new_vals, %old, %new);
+
+ $old_vals = $entry_old->get_value($attr, asref => 1);
+ @old_vals = @$old_vals;
+ $new_vals = $entry_new->get_value($attr, asref => 1);
+ @new_vals = @$new_vals;
+
+ if (scalar(@old_vals) == 1 && scalar(@new_vals) == 1) {
+ if ($old_vals[0] ne $new_vals[0]) {
+ display_attr_generic("old:\t", $entry_old, $attr);
+ display_attr_generic("new:\t", $entry_new, $attr);
+ }
+ next;
+ }
+
+ # handle multivalued diffs
+ foreach my $val (@old_vals) { $old{$val} = "dummy"; };
+ foreach my $val (@new_vals) { $new{$val} = "dummy"; };
+ foreach my $val (sort keys %new) {
+ if (!exists $old{$val}) {
+ display_value_generic("add:\t", $attr, $val);
+ }
+ }
+ foreach my $val (sort keys %old) {
+ if (!exists $new{$val}) {
+ display_value_generic("del:\t", $attr, $val);
+ }
+ }
+ }
+ print "\n";
+
+}
+
+sub sid2string ($) {
+
+ # Fix from Michael James <michael@james.st>
+ my $binary_sid = shift;
+ my($sid_rev, $num_auths, $id1, $id2, @ids) = unpack("H2 H2 n N V*", $binary_sid);
+ my $sid_string = join("-", "S", hex($sid_rev), ($id1<<32)+$id2, @ids);
+ return $sid_string;
+
+}
+
+sub string_to_guid {
+ my $string = shift;
+ return undef unless $string =~ /([0-9,a-z]{8})-([0-9,a-z]{4})-([0-9,a-z]{4})-([0-9,a-z]{2})([0-9,a-z]{2})-([0-9,a-z]{2})([0-9,a-z]{2})([0-9,a-z]{2})([0-9,a-z]{2})([0-9,a-z]{2})([0-9,a-z]{2})/i;
+
+ return pack("I", hex $1) .
+ pack("S", hex $2) .
+ pack("S", hex $3) .
+ pack("C", hex $4) .
+ pack("C", hex $5) .
+ pack("C", hex $6) .
+ pack("C", hex $7) .
+ pack("C", hex $8) .
+ pack("C", hex $9) .
+ pack("C", hex $10) .
+ pack("C", hex $11);
+
+# print "$1\n$2\n$3\n$4\n$5\n$6\n$7\n$8\n$9\n$10\n$11\n";
+}
+
+sub bindstring_to_guid {
+ my $str = shift;
+ return pack("H2 H2 H2 H2 H2 H2 H2 H2 H2 H2 H2 H2 H2 H2 H2 H2",
+ substr($str,0,2),
+ substr($str,2,2),
+ substr($str,4,2),
+ substr($str,6,2),
+ substr($str,8,2),
+ substr($str,10,2),
+ substr($str,12,2),
+ substr($str,14,2),
+ substr($str,16,2),
+ substr($str,18,2),
+ substr($str,20,2),
+ substr($str,22,2),
+ substr($str,24,2),
+ substr($str,26,2),
+ substr($str,28,2),
+ substr($str,30,2));
+}
+
+sub guid_to_string {
+ my $guid = shift;
+ my $string = sprintf "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+ unpack("I", $guid),
+ unpack("S", substr($guid, 4, 2)),
+ unpack("S", substr($guid, 6, 2)),
+ unpack("C", substr($guid, 8, 1)),
+ unpack("C", substr($guid, 9, 1)),
+ unpack("C", substr($guid, 10, 1)),
+ unpack("C", substr($guid, 11, 1)),
+ unpack("C", substr($guid, 12, 1)),
+ unpack("C", substr($guid, 13, 1)),
+ unpack("C", substr($guid, 14, 1)),
+ unpack("C", substr($guid, 15, 1));
+ return lc($string);
+}
+
+sub guid_to_bindstring {
+ my $guid = shift;
+ return unpack("H" . 2 * length($guid), $guid),
+}
+
+sub dump_wknguid {
+ print "Dumping Well known GUIDs:\n";
+ foreach my $wknguid (keys %wknguids) {
+
+ my $guid = bindstring_to_guid($wknguids{$wknguid});
+ my $str = guid_to_string($guid);
+ my $back = guid_to_bindstring($guid);
+
+ printf "wkguid: %s\n", $wknguid;
+ printf "bind_string format: %s\n", $wknguids{$wknguid};
+ printf "string format: %s\n", guid_to_string($guid);
+ printf "back to bind_string:%s\n", guid_to_bindstring($guid);
+
+ printf "use base: \"<WKGUID=%s,%s>\"\n", guid_to_bindstring($guid), $base;
+ }
+}
+
+sub gen_bitmask_string_format($%) {
+ my $mod = shift;
+ my (%tmp) = @_;
+ my @list;
+ foreach my $key (sort keys %tmp) {
+ push(@list, sprintf("%s %s", $tmp{$key}, $key));
+ }
+ return join("\n$mod$tabsize",@list);
+}
+
+
+sub nt_to_unixtime ($) {
+ # the number of 100 nanosecond intervals since jan. 1. 1601 (utc)
+ my $t64 = shift;
+ $t64 =~ s/(.+).{7,7}/$1/;
+ $t64 -= 11644473600;
+ return $t64;
+}
+
+sub dump_equal {
+ my $val = shift;
+ my $mod = shift || die "no mod";
+ my (%header) = @_;
+ my %tmp;
+ my $found = 0;
+ foreach my $key (keys %header) {
+ if ($header{$key} eq $val) {
+ $tmp{"($val)"} = $key;
+ $found = 1;
+ last;
+ }
+ }
+ if (!$found) { $tmp{$val} = ""; };
+ return gen_bitmask_string_format($mod,%tmp);
+}
+
+sub dump_bitmask {
+ my $op = shift || die "no op";
+ my $val = shift;
+ my $mod = shift || die "no mod";
+ my (%header) = @_;
+ my %tmp;
+ $tmp{""} = sprintf("%s (0x%08x)", $val, $val);
+ foreach my $key (sort keys %header) { # sort by val !
+ my $val_hex = sprintf("0x%08x", $header{$key});
+ if ($op eq "&") {
+ $tmp{"$key ($val_hex)"} = ( $val & $header{$key} ) ? $set:$unset;
+ } elsif ($op eq "==") {
+ $tmp{"$key ($val_hex)"} = ( $val == $header{$key} ) ? $set:$unset;
+ } else {
+ print "unknown operator: $op\n";
+ return;
+ }
+ }
+ return gen_bitmask_string_format($mod,%tmp);
+}
+
+sub dump_bitmask_and {
+ return dump_bitmask("&",@_);
+}
+
+sub dump_bitmask_equal {
+ return dump_bitmask("==",@_);
+}
+
+sub dump_uac {
+ return dump_bitmask_and(@_,%ads_uf); # ads_uf ?
+}
+
+sub dump_uascompat {
+ return dump_bitmask_equal(@_,%ads_uascompat);
+}
+
+sub dump_gpoptions {
+ return dump_bitmask_equal(@_,%ads_gpoptions);
+}
+
+sub dump_gpflags {
+ return dump_bitmask_equal(@_,%ads_gpflags);
+}
+
+sub dump_uacc {
+ return dump_bitmask_equal(@_,%ads_uacc);
+}
+
+sub dump_enctypes {
+ return dump_bitmask_and(@_,%ads_enctypes);
+}
+
+sub dump_uf {
+ return dump_bitmask_and(@_,%ads_uf);
+}
+
+sub dump_gtype {
+ my $ret = dump_bitmask_and(@_,%ads_grouptype);
+ $ret .= "\n$tabsize\t";
+ $ret .= dump_bitmask_equal(@_,%ads_gtype);
+ return $ret;
+}
+
+sub dump_atype {
+ return dump_bitmask_equal(@_,%ads_atype);
+}
+
+sub dump_controls {
+ return dump_equal(@_,%ads_controls);
+}
+
+sub dump_capabilities {
+ return dump_equal(@_,%ads_capabilities);
+}
+
+sub dump_extension {
+ return dump_equal(@_,%ads_extensions);
+}
+
+sub dump_systemflags {
+ return dump_bitmask_and(@_,%ads_systemflags);
+}
+
+sub dump_instance_type {
+ return dump_bitmask_and(@_,%ads_instance_type);
+}
+
+sub dump_ds_func {
+ return dump_bitmask_equal(@_,%ads_ds_func);
+}
+
+sub dump_serverstate {
+ return dump_bitmask_equal(@_,%ads_serverstate);
+}
+
+sub dump_sdeffective {
+ return dump_bitmask_and(@_,%ads_sdeffective);
+}
+
+sub dump_trustattr {
+ return dump_bitmask_and(@_,%ads_trustattrs);
+}
+
+sub dump_trusttype {
+ return dump_bitmask_equal(@_,%ads_trusttype);
+}
+
+sub dump_trustdirection {
+ return dump_bitmask_equal(@_,%ads_trustdirection);
+}
+
+sub dump_pwdproperties {
+ return dump_bitmask_and(@_,%ads_pwdproperties);
+}
+
+sub dump_frstype {
+ return dump_bitmask_equal(@_,%ads_frstypes)
+}
+
+sub dump_mixed_domain {
+ return dump_bitmask_equal(@_,%ads_mixed_domain);
+}
+
+sub dump_sid {
+ my $bin_sid = shift;
+ return sid2string($bin_sid);
+}
+
+sub dump_guid {
+ my $guid = shift;
+ return guid_to_string($guid);
+}
+
+sub dump_secdesc {
+ my $val = shift;
+ return "FIXME: write sddl-converter!";
+}
+
+sub dump_nttime {
+ my $nttime = shift;
+ if ($nttime == 0) {
+ return sprintf("%s (%s)", "never", $nttime);
+ }
+ my $localtime = localtime(nt_to_unixtime($nttime));
+ return sprintf("%s (%s)", $localtime, $nttime);
+}
+
+sub dump_nttime_abs {
+ if ($_[0] == 9223372036854775807) {
+ return sprintf("%s (%s)", "now", $_[0]);
+ }
+ if ($_[0] == -9223372036854775808 || $_[0] == 0) { # 0x7FFFFFFFFFFFFFFF
+ return sprintf("%s (%s)", "never", $_[0]);
+ }
+ # FIXME: actually *do* abs time !
+ return dump_nttime($_[0]);
+}
+
+sub dump_timestr {
+ my $time = shift;
+ if ($time eq "16010101000010.0Z") {
+ return sprintf("%s (%s)", "never", $time);
+ }
+ my ($year,$mon,$mday,$hour,$min,$sec,$zone) =
+ unpack('a4 a2 a2 a2 a2 a2 a4', $time);
+ $mon -= 1;
+ my $localtime = localtime(timegm($sec,$min,$hour,$mday,$mon,$year));
+ return sprintf("%s (%s)", $localtime, $time);
+}
+
+sub dump_string {
+ return $_[0];
+}
+
+sub dump_int {
+ return sprintf("%d", $_[0]);
+}
+
+sub dump_munged_dial {
+ my $dial = shift;
+ return "FIXME! decode this";
+}
+
+sub dump_cert {
+
+ my $cert = shift;
+ open(OPENSSL, "| /usr/bin/openssl x509 -text -inform der");
+ print OPENSSL $cert;
+ close(OPENSSL);
+ return "";
+}
+
+sub dump_pkt {
+ my $pkt = shift;
+ return "not yet";
+ printf("%s: ", $pkt);
+ printf("%02X", $pkt);
+
+}
+
+sub dump_gplink {
+
+ my $gplink = shift;
+ my $gplink_mod = $gplink;
+ my @links = split("\\]\\[", $gplink_mod);
+ foreach my $link (@links) {
+ $link =~ s/^\[|\]$//g;
+ my ($ldap_link, $opt) = split(";", $link);
+ my @array = ( "$opt", "\t" );
+ printf("%slink: %s, opt: %s\n", $tabsize, $ldap_link, dump_bitmask_and(@array, %ads_gplink_opts));
+ }
+ return $gplink;
+}
+
+sub construct_filter {
+
+ my $tmp = shift;
+
+ if (!$tmp || $opt_notify) {
+ return "(objectclass=*)";
+ }
+
+ if ($tmp && $tmp !~ /^.*\=/) {
+ return "(ANR=$tmp)";
+ }
+
+ return $tmp;
+ # (&(objectCategory=person)
+ # (userAccountControl:$ads_matching_rules{LDAP_MATCHING_RULE_BIT_AND}:=2))
+}
+
+sub construct_attrs {
+
+ my @attrs = @_;
+
+ if (!@attrs) {
+ push(@attrs,"*");
+ }
+
+ if ($opt_notify) {
+ push(@attrs,"uSNChanged");
+ }
+
+ if ($opt_display_metadata) {
+ push(@attrs,"msDS-ReplAttributeMetaData");
+ push(@attrs,"replPropertyMetaData");
+ }
+
+ if ($opt_verbose) {
+ push(@attrs,"nTSecurityDescriptor");
+ push(@attrs,"msDS-KeyVersionNumber");
+ push(@attrs,"msDS-User-Account-Control-Computed");
+ push(@attrs,"modifyTimeStamp");
+ }
+
+ return sort @attrs;
+}
+
+sub print_header {
+
+ print "\n";
+ printf "%10s: %s\n", "uri", $uri;
+ printf "%10s: %s\n", "port", $port;
+ printf "%10s: %s\n", "base", $base;
+ printf "%10s: %s\n", $sasl_bind ? "principal" : "binddn", $sasl_bind ? $upn : $binddn;
+ printf "%10s: %s\n", "password", $password;
+ printf "%10s: %s\n", "bind-type", $sasl_bind ? "SASL" : "simple";
+ printf "%10s: %s\n", "sasl-mech", $sasl_mech if ($sasl_mech);
+ printf "%10s: %s\n", "filter", $filter;
+ printf "%10s: %s\n", "scope", $scope;
+ printf "%10s: %s\n", "attrs", join(", ", @attrs);
+ printf "%10s: %s\n", "controls", join(", ", @ctrls_s);
+ printf "%10s: %s\n", "page_size", $opt_paging if ($opt_paging);
+ printf "%10s: %s\n", "start_tls", $opt_starttls ? "yes" : "no";
+ printf "\n";
+}
+
+sub gen_controls {
+
+ # setup attribute-scoped query control
+ my $asq_asn = Convert::ASN1->new;
+ $asq_asn->prepare(
+ q< asq ::= SEQUENCE {
+ sourceAttribute OCTET_STRING
+ }
+ >
+ );
+ my $ctl_asq_val = $asq_asn->encode( sourceAttribute => $opt_asq);
+ my $ctl_asq = Net::LDAP::Control->new(
+ type => $ads_controls{'LDAP_SERVER_ASQ_OID'},
+ critical => 'true',
+ value => $ctl_asq_val);
+
+
+ # setup extended dn control
+ my $asn_extended_dn = Convert::ASN1->new;
+ $asn_extended_dn->prepare(
+ q< ExtendedDn ::= SEQUENCE {
+ mode INTEGER
+ }
+ >
+ );
+
+ # only w2k3 accepts '1' and needs the ctl_val, w2k does not accept a ctl_val
+ my $ctl_extended_dn_val = $asn_extended_dn->encode( mode => $opt_display_extendeddn);
+ my $ctl_extended_dn = Net::LDAP::Control->new(
+ type => $ads_controls{'LDAP_SERVER_EXTENDED_DN_OID'},
+ critical => 'true',
+ value => $opt_display_extendeddn ? $ctl_extended_dn_val : "");
+
+ # setup search options
+ my $search_opt = Convert::ASN1->new;
+ $search_opt->prepare(
+ q< searchopt ::= SEQUENCE {
+ flags INTEGER
+ }
+ >
+ );
+
+ my $tmp = $search_opt->encode( flags => $opt_search_opt);
+ my $ctl_search_opt = Net::LDAP::Control->new(
+ type => $ads_controls{'LDAP_SERVER_SEARCH_OPTIONS_OID'},
+ critical => 'true',
+ value => $tmp);
+
+ # setup notify control
+ my $ctl_notification = Net::LDAP::Control->new(
+ type => $ads_controls{'LDAP_SERVER_NOTIFICATION_OID'},
+ critical => 'true');
+
+
+ # setup paging control
+ $ctl_paged = Net::LDAP::Control->new(
+ type => $ads_controls{'LDAP_PAGED_RESULT_OID_STRING'},
+ critical => 'true',
+ size => $opt_paging ? $opt_paging : 1000);
+
+ # setup domscope control
+ my $ctl_domscope = Net::LDAP::Control->new(
+ type => $ads_controls{'LDAP_SERVER_DOMAIN_SCOPE_OID'},
+ critical => 'true',
+ value => "");
+
+ if (defined($opt_paging) || $opt_dump_schema) {
+ push(@ctrls, $ctl_paged);
+ push(@ctrls_s, "LDAP_PAGED_RESULT_OID_STRING" );
+ }
+
+ if (defined($opt_display_extendeddn)) {
+ push(@ctrls, $ctl_extended_dn);
+ push(@ctrls_s, "LDAP_SERVER_EXTENDED_DN_OID");
+ }
+ if ($opt_notify) {
+ push(@ctrls, $ctl_notification);
+ push(@ctrls_s, "LDAP_SERVER_NOTIFICATION_OID");
+ }
+
+ if ($opt_asq) {
+ push(@ctrls, $ctl_asq);
+ push(@ctrls_s, "LDAP_SERVER_ASQ_OID");
+ }
+
+ if ($opt_domain_scope) {
+ push(@ctrls, $ctl_domscope);
+ push(@ctrls_s, "LDAP_SERVER_DOMAIN_SCOPE_OID");
+ }
+
+ if ($opt_search_opt) {
+ push(@ctrls, $ctl_search_opt);
+ push(@ctrls_s, "LDAP_SERVER_SEARCH_OPTIONS_OID");
+ }
+
+ return @ctrls;
+}
+
+sub display_value_generic ($$$) {
+
+ my ($mod,$attr,$value) = @_;
+ return unless (defined($value) and defined($attr));
+
+ if ( ! $opt_display_raw && exists $attr_handler{$attr} ) {
+ $value = $attr_handler{$attr}($value,$mod);
+ write_ads_list($mod,$attr,$value);
+ return;
+ }
+ write_ads($mod,$attr,$value);
+}
+
+sub display_attr_generic ($$$) {
+
+ my ($mod,$entry,$attr) = @_;
+ return if (!$attr || !$entry);
+
+ my $ref = $entry->get_value($attr, asref => 1);
+ my @values = @$ref;
+
+ foreach my $value ( sort @values) {
+ display_value_generic($mod,$attr,$value);
+ }
+}
+
+sub display_entry_generic ($) {
+
+ my $entry = shift;
+ return if (!$entry);
+
+ foreach my $attr ( sort $entry->attributes) {
+ display_attr_generic("\t",$entry,$attr);
+ }
+}
+
+sub display_ldap_err ($) {
+
+ my $msg = shift;
+ print_header();
+ my ($package, $filename, $line, $subroutine) = caller(0);
+
+ print "got error from ADS:\n";
+ printf("%s(%d): ERROR (%s): %s\n",
+ $subroutine, $line, $msg->code, $msg->error);
+
+}
+
+sub process_result {
+
+ my ($msg,$entry) = @_;
+
+ if (!defined($msg)) {
+ return;
+ }
+
+ if ($msg->code) {
+ display_ldap_err($msg);
+ exit 1;
+ }
+
+ if (!defined($entry)) {
+ return;
+ }
+
+ if ($entry->isa('Net::LDAP::Reference')) {
+ foreach my $ref ($entry->references) {
+ print "\ngot Reference: [$ref]\n";
+ }
+ return;
+ }
+
+ print "\nfound entry: ".$entry->dn."\n".("-" x 80)."\n";
+
+ display_entry_generic($entry);
+}
+
+sub default_callback {
+
+ my ($res,$obj) = @_;
+
+ if (!$opt_notify && $res->code == LDAP_REFERRAL) {
+ return;
+ }
+
+ if (!$opt_notify) {
+ return process_result($res,$obj);
+ }
+}
+
+sub error_callback {
+
+ my ($msg,$entry) = @_;
+
+ if (!$msg) {
+ return;
+ }
+
+ if ($msg->code) {
+ display_ldap_err($msg);
+ exit(1);
+ }
+ return;
+}
+
+sub notify_callback {
+
+ my ($msg, $obj) = @_;
+
+ if (! defined($obj)) {
+ return;
+ }
+
+ if ($obj->isa('Net::LDAP::Reference')) {
+ foreach my $ref ($obj->references) {
+ print "\ngot Reference: [$ref]\n";
+ }
+ return;
+ }
+
+ while (1) {
+
+ my $async_entry = $async_search->pop_entry;
+
+ if (!$async_entry->dn) {
+ print "very weird. entry has no dn\n";
+ next;
+ }
+
+ printf("\ngot changenotify for dn: [%s]\n%s\n", $async_entry->dn, ("-" x 80));
+
+ my $new_usn = $async_entry->get_value('uSNChanged');
+ if (!$new_usn) {
+ die "odd, no usnChanged attribute???";
+ }
+ if (!$usn || $new_usn > $usn) {
+ $usn = $new_usn;
+ if ($opt_notify_nodiffs) {
+ display_entry_generic($async_entry);
+ } else {
+ display_result_diff($async_entry);
+ }
+ }
+ store_result($async_entry);
+ }
+}
+
+sub do_bind($$) {
+
+ my $async_ldap_hd = shift || return undef;
+ my $sasl_bind = shift;
+
+ if ($sasl_bind) {
+ if (!$works_sasl) {
+ print "this version of Net::LDAP does not have proper SASL support.\n";
+ print "Need at least perl-ldap V. $pref_version\n";
+ }
+ $sasl_hd = get_sasl_hd();
+ if (!$sasl_hd) {
+ print "failed to create SASL handle\n";
+ return -1;
+ }
+ $mesg = $async_ldap_hd->bind(
+ sasl => $sasl_hd,
+ callback => \&error_callback
+ ) || die "doesn't work";
+ } else {
+ $sasl_mech = "";
+ $mesg = $async_ldap_hd->bind(
+ $binddn,
+ password => $password,
+ callback => $opt_fastbind ? undef : \&error_callback
+ ) || die "doesn't work";
+ };
+ if ($mesg->code) {
+ display_ldap_err($mesg) if (!$opt_fastbind);
+ return -1;
+ }
+ return 0;
+}
+
+sub do_fast_bind() {
+
+ do_unbind();
+
+ my $hd = get_ldap_hd($server,1);
+
+ my $mesg = $hd->extension(
+ name => $ads_extensions{'LDAP_SERVER_FAST_BIND_OID'});
+
+ if ($mesg->code) {
+ display_ldap_err($mesg);
+ return -1;
+ }
+
+ my $ret = do_bind($hd, undef);
+ $hd->unbind;
+
+ printf("bind using 'LDAP_SERVER_FAST_BIND_OID' %s\n",
+ $ret == 0 ? "succeeded" : "failed");
+
+ return $ret;
+}
+
+sub do_unbind() {
+ if ($async_ldap_hd) {
+ $async_ldap_hd->unbind;
+ }
+ if ($sync_ldap_hd) {
+ $sync_ldap_hd->unbind;
+ }
+}
+
+###############################################################################
+
+sub main () {
+
+ if ($opt_fastbind) {
+
+ if (check_exts($server,$dse,"LDAP_SERVER_FAST_BIND_OID") == -1) {
+ print "LDAP_SERVER_FAST_BIND_OID not supported by this server\n";
+ exit 1;
+ }
+
+ # fast bind can only bind, not search
+ exit do_fast_bind();
+ }
+
+ $filter = construct_filter($query);
+ @attrs = construct_attrs(@attrs);
+ @ctrls = gen_controls();
+
+ if (check_ctrls($server,$dse,@ctrls) == -1) {
+ print "not all required LDAP Controls are supported by this server\n";
+ exit 1;
+ }
+
+ if ($opt_dump_rootdse) {
+ print "Dumping Root-DSE:\n";
+ display_entry_generic($dse);
+ exit 0;
+ }
+
+ if ($opt_dump_wknguid) {
+ dump_wknguid();
+ exit 0;
+ }
+
+ if (do_bind($async_ldap_hd, $sasl_bind) == -1) {
+ exit 1;
+ }
+
+ print_header();
+
+ if ($opt_dump_schema) {
+ print "Dumping Schema:\n";
+# my $ads_schema = $async_ldap_hd->schema;
+# $ads_schema->dump;
+# exit 0;
+ }
+
+ while (1) {
+
+ $async_search = $async_ldap_hd->search(
+ base => $base,
+ filter => $filter,
+ attrs => [ @attrs ],
+ control => [ @ctrls ],
+ callback => \&default_callback,
+ scope => $scope,
+ ) || die "cannot search";
+
+ if (!$opt_notify && ($async_search->code == LDAP_REFERRAL)) {
+ foreach my $ref ($async_search->referrals) {
+ print "\ngot Referral: [$ref]\n";
+ my ($prot, $host, $base) = split(/\/+/, $ref);
+ $async_ldap_hd->unbind();
+ $async_ldap_hd = get_ldap_hd($host, 1);
+ if (do_bind($async_ldap_hd, $sasl_bind) == -1) {
+ $async_ldap_hd->unbind();
+ next;
+ }
+ print "\nsuccessful rebind to: [$ref]\n";
+ last;
+ }
+ next; # repeat the query
+ }
+
+ if ($opt_notify) {
+
+ print "Base [$base] is registered now for change-notify\n";
+ print "\nWaiting for change-notify...\n";
+
+ my $sync_ldap_hd = get_ldap_hd($server,0);
+ if (do_bind($sync_ldap_hd, $sasl_bind) == -1) {
+ exit 2;
+ }
+
+ my $sync_search = $sync_ldap_hd->search(
+ base => $base,
+ filter => $filter,
+ attrs => [ @attrs ],
+ callback => \&notify_callback,
+ scope => $scope,
+ ) || die "cannot search";
+
+ }
+
+ $total_entry_count += $async_search->count;
+ ++$page_count;
+ print "-" x 80 . "\n";
+ printf("Got %d Entries in Page %d \n\n",
+ $async_search->count, $page_count);
+ my ($resp) = $async_search->control(
+ $ads_controls{'LDAP_PAGED_RESULT_OID_STRING'} ) or last;
+ last unless ref $resp && $ctl_paged->cookie($resp->cookie);
+ }
+
+ if ($async_search->entries == 0) {
+ print "No entries found with filter $filter\n";
+ } else {
+ print "Got $total_entry_count Entries in $page_count Pages\n" if ($opt_paging);
+ }
+
+ do_unbind()
+}
+
+main();
+
+exit 0;
diff --git a/examples/misc/check_multiple_LDAP_entries.pl b/examples/misc/check_multiple_LDAP_entries.pl
new file mode 100755
index 0000000..00c197a
--- /dev/null
+++ b/examples/misc/check_multiple_LDAP_entries.pl
@@ -0,0 +1,201 @@
+#!/usr/bin/perl -w
+# Guenther Deschner <gd@samba.org>
+#
+# check for multiple LDAP entries
+
+use strict;
+
+use Net::LDAP;
+use Getopt::Std;
+
+my %opts;
+
+if (!@ARGV) {
+ print "usage: $0 -h host -b base -D admindn -w password [-l]\n";
+ print "\tperforms checks for multiple sid, uid and gid-entries on your LDAP server\n";
+ print "\t-l adds additional checks against the local /etc/passwd and /etc/group file\n";
+ exit 1;
+}
+
+getopts('b:h:D:w:l', \%opts);
+
+my $host = $opts{h} || "localhost";
+my $suffix = $opts{b} || die "please set base with -b";
+my $binddn = $opts{D} || die "please set basedn with -D";
+my $bindpw = $opts{w} || die "please set password with -w";
+my $check_local_files = $opts{l} || 0;
+
+########################
+
+
+my ($ldap, $res);
+my (%passwd_h, %group_h);
+my $bad_uids = 0;
+my $bad_gids = 0;
+my $bad_sids = 0;
+my $ret = 0;
+
+if ($check_local_files) {
+ my @uids = `cut -d ':' -f 3 /etc/passwd`;
+ my @gids = `cut -d ':' -f 3 /etc/group`;
+
+ foreach my $uid (@uids) {
+ chomp($uid);
+ $passwd_h{$uid} = $uid;
+ }
+
+ foreach my $gid (@gids) {
+ chomp($gid);
+ $group_h{$gid} = $gid;
+ }
+}
+
+########
+# bind #
+########
+
+$ldap = Net::LDAP->new($host, version => '3');
+
+$res = $ldap->bind( $binddn, password => $bindpw);
+$res->code && die "failed to bind: ", $res->error;
+
+
+
+###########################
+# check for double sids #
+###########################
+
+print "\ntesting for multiple sambaSids\n";
+
+$res = $ldap->search(
+ base => $suffix,
+ filter => "(objectclass=sambaSamAccount)");
+
+$res->code && die "failed to search: ", $res->error;
+
+foreach my $entry ($res->all_entries) {
+
+ my $sid = $entry->get_value('sambaSid');
+
+ my $local_res = $ldap->search(
+ base => $suffix,
+ filter => "(&(objectclass=sambaSamAccount)(sambaSid=$sid))");
+
+ $local_res->code && die "failed to search: ", $local_res->error;
+ if ($local_res->count > 1) {
+ print "A SambaSamAccount with sambaSid [$sid] must exactly exist once\n";
+ print "You have ", $local_res->count, " entries:\n";
+ foreach my $loc_entry ($local_res->all_entries) {
+ printf "\t%s\n", $loc_entry->dn;
+ }
+ ++$bad_sids;
+ }
+}
+
+if ($bad_sids) {
+ $ret = -1;
+ print "You have $bad_sids bad sambaSids in your system. You might need to repair them\n";
+} else {
+ print "No multiple sambaSids found in your system\n";
+}
+
+print "-" x 80, "\n";
+
+###########################
+# check for double groups #
+###########################
+
+print "\ntesting for multiple gidNumbers\n";
+
+$res = $ldap->search(
+ base => $suffix,
+ filter => "(objectclass=posixGroup)");
+
+$res->code && die "failed to search: ", $res->error;
+
+foreach my $entry ($res->all_entries) {
+
+ my $gid = $entry->get_value('gidNumber');
+ my $dn = $entry->dn;
+
+ my $local_res = $ldap->search(
+ base => $suffix,
+ filter => "(&(objectclass=posixGroup)(gidNumber=$gid))");
+
+ $local_res->code && die "failed to search: ", $local_res->error;
+ if ($local_res->count > 1) {
+ print "A PosixGroup with gidNumber [$gid] must exactly exist once\n";
+ print "You have ", $local_res->count, " entries:\n";
+ foreach my $loc_entry ($local_res->all_entries) {
+ printf "\t%s\n", $loc_entry->dn;
+ }
+ ++$bad_gids;
+ next;
+ }
+
+ if ($check_local_files && exists $group_h{$gid}) {
+ print "Warning: There is a group in /etc/group that has gidNumber [$gid] as well\n";
+ print "This entry may conflict with $dn\n";
+ ++$bad_gids;
+ }
+}
+
+if ($bad_gids) {
+ $ret = -1;
+ print "You have $bad_gids bad gidNumbers in your system. You might need to repair them\n";
+} else {
+ print "No multiple gidNumbers found in your system\n";
+}
+
+print "-" x 80, "\n";
+
+
+###########################
+# check for double users #
+###########################
+
+print "\ntesting for multiple uidNumbers\n";
+
+$res = $ldap->search(
+ base => $suffix,
+ filter => "(objectclass=posixAccount)");
+
+$res->code && die "failed to search: ", $res->error;
+
+
+foreach my $entry ($res->all_entries) {
+
+ my $uid = $entry->get_value('uidNumber');
+ my $dn = $entry->dn;
+
+ my $local_res = $ldap->search(
+ base => $suffix,
+ filter => "(&(objectclass=posixAccount)(uidNumber=$uid))");
+
+ $local_res->code && die "failed to search: ", $local_res->error;
+ if ($local_res->count > 1) {
+ print "A PosixAccount with uidNumber [$uid] must exactly exist once\n";
+ print "You have ", $local_res->count, " entries:\n";
+ foreach my $loc_entry ($local_res->all_entries) {
+ printf "\t%s\n", $loc_entry->dn;
+ }
+ ++$bad_uids;
+ next;
+ }
+ if ($check_local_files && exists $passwd_h{$uid}) {
+ print "Warning: There is a user in /etc/passwd that has uidNumber [$uid] as well\n";
+ print "This entry may conflict with $dn\n";
+ ++$bad_uids;
+ }
+}
+
+if ($bad_uids) {
+ $ret = -1;
+ print "You have $bad_uids bad uidNumbers in your system. You might need to repair them\n";
+} else {
+ print "No multiple uidNumbers found in your system\n";
+}
+
+$ldap->unbind;
+
+exit $ret;
diff --git a/examples/misc/cldap.pl b/examples/misc/cldap.pl
new file mode 100755
index 0000000..c33fded
--- /dev/null
+++ b/examples/misc/cldap.pl
@@ -0,0 +1,491 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) Guenther Deschner <gd@samba.org> 2006
+
+use strict;
+use IO::Socket;
+use Convert::ASN1 qw(:debug);
+use Getopt::Long;
+
+# TODO: timeout handling, user CLDAP query
+
+##################################
+
+my $server = "";
+my $domain = "";
+my $host = "";
+
+##################################
+
+my (
+ $opt_debug,
+ $opt_domain,
+ $opt_help,
+ $opt_host,
+ $opt_server,
+);
+
+my %cldap_flags = (
+ ADS_PDC => 0x00000001, # DC is PDC
+ ADS_GC => 0x00000004, # DC is a GC of forest
+ ADS_LDAP => 0x00000008, # DC is an LDAP server
+ ADS_DS => 0x00000010, # DC supports DS
+ ADS_KDC => 0x00000020, # DC is running KDC
+ ADS_TIMESERV => 0x00000040, # DC is running time services
+ ADS_CLOSEST => 0x00000080, # DC is closest to client
+ ADS_WRITABLE => 0x00000100, # DC has writable DS
+ ADS_GOOD_TIMESERV => 0x00000200, # DC has hardware clock (and running time)
+ ADS_NDNC => 0x00000400, # DomainName is non-domain NC serviced by LDAP server
+);
+
+my %cldap_samlogon_types = (
+ SAMLOGON_AD_UNK_R => 23,
+ SAMLOGON_AD_R => 25,
+);
+
+my $MAX_DNS_LABEL = 255 + 1;
+
+my %cldap_netlogon_reply = (
+ type => 0,
+ flags => 0x0,
+ guid => 0,
+ forest => undef,
+ domain => undef,
+ hostname => undef,
+ netbios_domain => undef,
+ netbios_hostname => undef,
+ unk => undef,
+ user_name => undef,
+ server_site_name => undef,
+ client_site_name => undef,
+ version => 0,
+ lmnt_token => 0x0,
+ lm20_token => 0x0,
+);
+
+sub usage {
+ print "usage: $0 [--domain|-d domain] [--help] [--host|-h host] [--server|-s server]\n\n";
+}
+
+sub connect_cldap ($) {
+
+ my $server = shift || return undef;
+
+ return IO::Socket::INET->new(
+ PeerAddr => $server,
+ PeerPort => 389,
+ Proto => 'udp',
+ Type => SOCK_DGRAM,
+ Timeout => 10,
+ );
+}
+
+sub send_cldap_netlogon ($$$$) {
+
+ my ($sock, $domain, $host, $ntver) = @_;
+
+ my $asn_cldap_req = Convert::ASN1->new;
+
+ $asn_cldap_req->prepare(q<
+
+ SEQUENCE {
+ msgid INTEGER,
+ [APPLICATION 3] SEQUENCE {
+ basedn OCTET STRING,
+ scope ENUMERATED,
+ dereference ENUMERATED,
+ sizelimit INTEGER,
+ timelimit INTEGER,
+ attronly BOOLEAN,
+ [CONTEXT 0] SEQUENCE {
+ [CONTEXT 3] SEQUENCE {
+ dnsdom_attr OCTET STRING,
+ dnsdom_val OCTET STRING
+ }
+ [CONTEXT 3] SEQUENCE {
+ host_attr OCTET STRING,
+ host_val OCTET STRING
+ }
+ [CONTEXT 3] SEQUENCE {
+ ntver_attr OCTET STRING,
+ ntver_val OCTET STRING
+ }
+ }
+ SEQUENCE {
+ netlogon OCTET STRING
+ }
+ }
+ }
+ >);
+
+ my $pdu_req = $asn_cldap_req->encode(
+ msgid => 0,
+ basedn => "",
+ scope => 0,
+ dereference => 0,
+ sizelimit => 0,
+ timelimit => 0,
+ attronly => 0,
+ dnsdom_attr => $domain ? 'DnsDomain' : "",
+ dnsdom_val => $domain ? $domain : "",
+ host_attr => 'Host',
+ host_val => $host,
+ ntver_attr => 'NtVer',
+ ntver_val => $ntver,
+ netlogon => 'NetLogon',
+ ) || die "failed to encode pdu: $@";
+
+ if ($opt_debug) {
+ print"------------\n";
+ asn_dump($pdu_req);
+ print"------------\n";
+ }
+
+ return $sock->send($pdu_req) || die "no send: $@";
+}
+
+# from source/libads/cldap.c :
+#
+#/*
+# These seem to be strings as described in RFC1035 4.1.4 and can be:
+#
+# - a sequence of labels ending in a zero octet
+# - a pointer
+# - a sequence of labels ending with a pointer
+#
+# A label is a byte where the first two bits must be zero and the remaining
+# bits represent the length of the label followed by the label itself.
+# Therefore, the length of a label is at max 64 bytes. Under RFC1035, a
+# sequence of labels cannot exceed 255 bytes.
+#
+# A pointer consists of a 14 bit offset from the beginning of the data.
+#
+# struct ptr {
+# unsigned ident:2; // must be 11
+# unsigned offset:14; // from the beginning of data
+# };
+#
+# This is used as a method to compress the packet by eliminated duplicate
+# domain components. Since a UDP packet should probably be < 512 bytes and a
+# DNS name can be up to 255 bytes, this actually makes a lot of sense.
+#*/
+
+sub pull_netlogon_string (\$$$) {
+
+ my ($ret, $ptr, $str) = @_;
+
+ my $pos = $ptr;
+
+ my $followed_ptr = 0;
+ my $ret_len = 0;
+
+ my $retp = pack("x$MAX_DNS_LABEL");
+
+ do {
+
+ $ptr = unpack("c", substr($str, $pos, 1));
+ $pos++;
+
+ if (($ptr & 0xc0) == 0xc0) {
+
+ my $len;
+
+ if (!$followed_ptr) {
+ $ret_len += 2;
+ $followed_ptr = 1;
+ }
+
+ my $tmp0 = $ptr; #unpack("c", substr($str, $pos-1, 1));
+ my $tmp1 = unpack("c", substr($str, $pos, 1));
+
+ if ($opt_debug) {
+ printf("tmp0: 0x%x\n", $tmp0);
+ printf("tmp1: 0x%x\n", $tmp1);
+ }
+
+ $len = (($tmp0 & 0x3f) << 8) | $tmp1;
+ $ptr = unpack("c", substr($str, $len, 1));
+ $pos = $len;
+
+ } elsif ($ptr) {
+
+ my $len = scalar $ptr;
+
+ if ($len + 1 > $MAX_DNS_LABEL) {
+ warn("invalid string size: %d", $len + 1);
+ return 0;
+ }
+
+ $ptr = unpack("a*", substr($str, $pos, $len));
+
+ $retp = sprintf("%s%s\.", $retp, $ptr);
+
+ $pos += $len;
+ if (!$followed_ptr) {
+ $ret_len += $len + 1;
+ }
+ }
+
+ } while ($ptr);
+
+ $retp =~ s/\.$//; #ugly hack...
+
+ $$ret = $retp;
+
+ return $followed_ptr ? $ret_len : $ret_len + 1;
+}
+
+sub dump_cldap_flags ($) {
+
+ my $flags = shift || return;
+ printf("Flags:\n".
+ "\tIs a PDC: %s\n".
+ "\tIs a GC of the forest: %s\n".
+ "\tIs an LDAP server: %s\n".
+ "\tSupports DS: %s\n".
+ "\tIs running a KDC: %s\n".
+ "\tIs running time services: %s\n".
+ "\tIs the closest DC: %s\n".
+ "\tIs writable: %s\n".
+ "\tHas a hardware clock: %s\n".
+ "\tIs a non-domain NC serviced by LDAP server: %s\n",
+ ($flags & $cldap_flags{ADS_PDC}) ? "yes" : "no",
+ ($flags & $cldap_flags{ADS_GC}) ? "yes" : "no",
+ ($flags & $cldap_flags{ADS_LDAP}) ? "yes" : "no",
+ ($flags & $cldap_flags{ADS_DS}) ? "yes" : "no",
+ ($flags & $cldap_flags{ADS_KDC}) ? "yes" : "no",
+ ($flags & $cldap_flags{ADS_TIMESERV}) ? "yes" : "no",
+ ($flags & $cldap_flags{ADS_CLOSEST}) ? "yes" : "no",
+ ($flags & $cldap_flags{ADS_WRITABLE}) ? "yes" : "no",
+ ($flags & $cldap_flags{ADS_GOOD_TIMESERV}) ? "yes" : "no",
+ ($flags & $cldap_flags{ADS_NDNC}) ? "yes" : "no");
+}
+
+sub guid_to_string ($) {
+
+ my $guid = shift || return undef;
+ if ((my $len = length $guid) != 16) {
+ printf("invalid length: %d\n", $len);
+ return undef;
+ }
+ my $string = sprintf "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+ unpack("I", $guid),
+ unpack("S", substr($guid, 4, 2)),
+ unpack("S", substr($guid, 6, 2)),
+ unpack("C", substr($guid, 8, 1)),
+ unpack("C", substr($guid, 9, 1)),
+ unpack("C", substr($guid, 10, 1)),
+ unpack("C", substr($guid, 11, 1)),
+ unpack("C", substr($guid, 12, 1)),
+ unpack("C", substr($guid, 13, 1)),
+ unpack("C", substr($guid, 14, 1)),
+ unpack("C", substr($guid, 15, 1));
+ return lc($string);
+}
+
+sub recv_cldap_netlogon ($\$) {
+
+ my ($sock, $return_string) = @_;
+ my ($ret, $pdu_out);
+
+ $ret = $sock->recv($pdu_out, 8192) || die "failed to read from socket: $@";
+ #$ret = sysread($sock, $pdu_out, 8192);
+
+ if ($opt_debug) {
+ print"------------\n";
+ asn_dump($pdu_out);
+ print"------------\n";
+ }
+
+ my $asn_cldap_rep = Convert::ASN1->new;
+ my $asn_cldap_rep_fail = Convert::ASN1->new;
+
+ $asn_cldap_rep->prepare(q<
+ SEQUENCE {
+ msgid INTEGER,
+ [APPLICATION 4] SEQUENCE {
+ dn OCTET STRING,
+ SEQUENCE {
+ SEQUENCE {
+ attr OCTET STRING,
+ SET {
+ val OCTET STRING
+ }
+ }
+ }
+ }
+ }
+ SEQUENCE {
+ msgid2 INTEGER,
+ [APPLICATION 5] SEQUENCE {
+ error_code ENUMERATED,
+ matched_dn OCTET STRING,
+ error_message OCTET STRING
+ }
+ }
+ >);
+
+ $asn_cldap_rep_fail->prepare(q<
+ SEQUENCE {
+ msgid2 INTEGER,
+ [APPLICATION 5] SEQUENCE {
+ error_code ENUMERATED,
+ matched_dn OCTET STRING,
+ error_message OCTET STRING
+ }
+ }
+ >);
+
+ my $asn1_rep = $asn_cldap_rep->decode($pdu_out) ||
+ $asn_cldap_rep_fail->decode($pdu_out) ||
+ die "failed to decode pdu: $@";
+
+ if ($asn1_rep->{'error_code'} == 0) {
+ $$return_string = $asn1_rep->{'val'};
+ }
+
+ return $ret;
+}
+
+sub parse_cldap_reply ($) {
+
+ my $str = shift || return undef;
+ my %hash;
+ my $p = 0;
+
+ $hash{type} = unpack("L", substr($str, $p, 4)); $p += 4;
+ $hash{flags} = unpack("L", substr($str, $p, 4)); $p += 4;
+ $hash{guid} = unpack("a16", substr($str, $p, 16)); $p += 16;
+
+ $p += pull_netlogon_string($hash{forest}, $p, $str);
+ $p += pull_netlogon_string($hash{domain}, $p, $str);
+ $p += pull_netlogon_string($hash{hostname}, $p, $str);
+ $p += pull_netlogon_string($hash{netbios_domain}, $p, $str);
+ $p += pull_netlogon_string($hash{netbios_hostname}, $p, $str);
+ $p += pull_netlogon_string($hash{unk}, $p, $str);
+
+ if ($hash{type} == $cldap_samlogon_types{SAMLOGON_AD_R}) {
+ $p += pull_netlogon_string($hash{user_name}, $p, $str);
+ } else {
+ $hash{user_name} = "";
+ }
+
+ $p += pull_netlogon_string($hash{server_site_name}, $p, $str);
+ $p += pull_netlogon_string($hash{client_site_name}, $p, $str);
+
+ $hash{version} = unpack("L", substr($str, $p, 4)); $p += 4;
+ $hash{lmnt_token} = unpack("S", substr($str, $p, 2)); $p += 2;
+ $hash{lm20_token} = unpack("S", substr($str, $p, 2)); $p += 2;
+
+ return %hash;
+}
+
+sub display_cldap_reply {
+
+ my $server = shift;
+ my (%hash) = @_;
+
+ my ($name,$aliases,$addrtype,$length,@addrs) = gethostbyname($server);
+
+ printf("Information for Domain Controller: %s\n\n", $name);
+
+ printf("Response Type: ");
+ if ($hash{type} == $cldap_samlogon_types{SAMLOGON_AD_R}) {
+ printf("SAMLOGON_USER\n");
+ } elsif ($hash{type} == $cldap_samlogon_types{SAMLOGON_AD_UNK_R}) {
+ printf("SAMLOGON\n");
+ } else {
+ printf("unknown type 0x%x, please report\n", $hash{type});
+ }
+
+ # guid
+ printf("GUID: %s\n", guid_to_string($hash{guid}));
+
+ # flags
+ dump_cldap_flags($hash{flags});
+
+ # strings
+ printf("Forest:\t\t\t%s\n", $hash{forest});
+ printf("Domain:\t\t\t%s\n", $hash{domain});
+ printf("Domain Controller:\t%s\n", $hash{hostname});
+
+ printf("Pre-Win2k Domain:\t%s\n", $hash{netbios_domain});
+ printf("Pre-Win2k Hostname:\t%s\n", $hash{netbios_hostname});
+
+ if ($hash{unk}) {
+ printf("Unk:\t\t\t%s\n", $hash{unk});
+ }
+ if ($hash{user_name}) {
+ printf("User name:\t%s\n", $hash{user_name});
+ }
+
+ printf("Server Site Name:\t%s\n", $hash{server_site_name});
+ printf("Client Site Name:\t%s\n", $hash{client_site_name});
+
+ # some more int
+ printf("NT Version:\t\t%d\n", $hash{version});
+ printf("LMNT Token:\t\t%.2x\n", $hash{lmnt_token});
+ printf("LM20 Token:\t\t%.2x\n", $hash{lm20_token});
+}
+
+sub main() {
+
+ my ($ret, $sock, $reply);
+
+ GetOptions(
+ 'debug' => \$opt_debug,
+ 'domain|d=s' => \$opt_domain,
+ 'help' => \$opt_help,
+ 'host|h=s' => \$opt_host,
+ 'server|s=s' => \$opt_server,
+ );
+
+ $server = $server || $opt_server;
+ $domain = $domain || $opt_domain || undef;
+ $host = $host || $opt_host;
+ if (!$host) {
+ $host = `/bin/hostname`;
+ chomp($host);
+ }
+
+ if (!$server || !$host || $opt_help) {
+ usage();
+ exit 1;
+ }
+
+ my $ntver = sprintf("%c%c%c%c", 6,0,0,0);
+
+ $sock = connect_cldap($server);
+ if (!$sock) {
+ die("could not connect to $server");
+ }
+
+ $ret = send_cldap_netlogon($sock, $domain, $host, $ntver);
+ if (!$ret) {
+ close($sock);
+ die("failed to send CLDAP request to $server");
+ }
+
+ $ret = recv_cldap_netlogon($sock, $reply);
+ if (!$ret) {
+ close($sock);
+ die("failed to receive CLDAP reply from $server");
+ }
+ close($sock);
+
+ if (!$reply) {
+ printf("no 'NetLogon' attribute received\n");
+ exit 0;
+ }
+
+ %cldap_netlogon_reply = parse_cldap_reply($reply);
+ if (!%cldap_netlogon_reply) {
+ die("failed to parse CLDAP reply from $server");
+ }
+
+ display_cldap_reply($server, %cldap_netlogon_reply);
+
+ exit 0;
+}
+
+main();
diff --git a/examples/misc/extra_smbstatus b/examples/misc/extra_smbstatus
new file mode 100644
index 0000000..7f77d07
--- /dev/null
+++ b/examples/misc/extra_smbstatus
@@ -0,0 +1,50 @@
+Here's something that Paul Blackman sent me that may be useful:
+
+-------------------
+I created this script to do a few things that smbstatus doesn't at the
+moment. Perhaps you might want to include these. Sorry I haven't
+added things at source level, script was quick&easy.
+
+*******
+#!/bin/csh
+if ($1 == "-p") then
+ smbstatus -p |sort -u
+else if ($1 == "-c") then
+ echo There are `smbstatus -p |sort -u |grep -n -v z |grep -c :` unique smbd processes running.
+ else if ($1 == "-l") then
+ echo `date '+ %d/%m/%y %H:%M:%S'` `smbstatus -p |sort -u |grep -n -v z |grep -c :` >>$2
+else if ($1 == "-cs") then
+ echo There are `smbstatus |awk '$1==share {n++;} END {print n}' share=$2` concurrent connections to share: $2
+else if ($1 == "-csl") then
+ echo `date '+ %d/%m/%y %H:%M:%S'` `smbstatus |awk '$1==share {n++;} END {print n}' share=$2` >>$3
+else
+ echo "'smbstat -c' ==> Count unique smbd processes."
+ echo "'smbstat -p' ==> List unique smbd processes."
+ echo "'smbstat -l logfile' ==> Append a log entry for the number of"
+ echo " concurrent and unique processes to logfile."
+ echo "'smbstat -cs sharename'"
+ echo " ==> Count processes connected to sharename (assumed unique)"
+ echo "'smbstat -csl sharename logfile'"
+ echo " ==> Append a log entry for the number of concurrent"
+ echo " processes connected to sharename (assumed unique)"
+endif
+******
+
+Run this script from cron eg.
+
+0,5,10,15,20,25,30,35,40,50,55 * * * * /usr/local/samba/bin/smbstat -l /usr/local/samba/var/smbdcount.log
+
+and you get a good idea of usage over time.
+
+Cheers,
+~^ MIME OK ^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~
+ o | Paul Blackman ictinus@lake.canberra.edu.au
+ o | Co-operative Research ------------------------
+ o _ | Centre For Freshwater Ecology. Ph. (Aus) 06 2012518
+ -- (") o | University of Canberra, Australia. Fax. " 06 2015038
+ \_|_-- |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ | | "Spend a little love and get high"
+ _/ \_ | - Lenny Kravitz
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+~~~~~~~~~~~~~~ SAMBA Web Pages: http://samba.org/samba/ ~~~~~~~~~~~~~~
+
diff --git a/examples/misc/wall.perl b/examples/misc/wall.perl
new file mode 100644
index 0000000..efa4ee5
--- /dev/null
+++ b/examples/misc/wall.perl
@@ -0,0 +1,69 @@
+#! /usr/bin/env perl
+#
+#@(#) smb-wall.pl Description:
+#@(#) A perl script which allows you to announce whatever you choose to
+#@(#) every PC client currently connected to a Samba Server...
+#@(#) ...using "smbclient -M" message to winpopup service.
+#@(#) Default usage is to message every connected PC.
+#@(#) Alternate usage is to message every pc on the argument list.
+#@(#) Hacked up by Keith Farrar <farrar@parc.xerox.com>
+#
+# Cleanup and corrections by
+# Michal Jaegermann <michal@ellpspace.math.ualberta.ca>
+# Message to send can be now also fed (quietly) from stdin; a pipe will do.
+#=============================================================================
+
+$smbstatus = "/usr/local/bin/smbstatus";
+$smbshout = "/usr/local/bin/smbclient -M";
+
+if (@ARGV) {
+ @clients = @ARGV;
+ undef @ARGV;
+}
+else { # no clients specified explicitly
+ open(PCLIST, "$smbstatus |") || die "$smbstatus failed!.\n$!\n";
+ while(<PCLIST>) {
+ last if /^Locked files:/;
+ split(' ', $_, 6);
+ # do not accept this line if less then six fields
+ next unless $_[5];
+ # if you have A LOT of clients you may speed things up by
+ # checking pid - no need to look further if this pid was already
+ # seen; left as an exercise :-)
+ $client = $_[4];
+ next unless $client =~ /^\w+\./; # expect 'dot' in a client name
+ next if grep($_ eq $client, @clients); # we want this name once
+ push(@clients, $client);
+ }
+ close(PCLIST);
+}
+
+if (-t) {
+ print <<'EOT';
+
+Enter message for Samba clients of this host
+(terminated with single '.' or end of file):
+EOT
+
+ while (<>) {
+ last if /^\.$/;
+ push(@message, $_);
+ }
+}
+else { # keep quiet and read message from stdin
+ @message = <>;
+}
+
+foreach(@clients) {
+## print "To $_:\n";
+ if (open(SENDMSG,"|$smbshout $_")) {
+ print SENDMSG @message;
+ close(SENDMSG);
+ }
+ else {
+ warn "Cannot notify $_ with $smbshout:\n$!\n";
+ }
+}
+
+exit 0;
+
diff --git a/examples/nss/nss_winbind.c b/examples/nss/nss_winbind.c
new file mode 100644
index 0000000..968cc7a
--- /dev/null
+++ b/examples/nss/nss_winbind.c
@@ -0,0 +1,422 @@
+/*
+ nss sample code for extended winbindd functionality
+
+ Copyright (C) Andrew Tridgell (tridge@samba.org)
+
+ you are free to use this code in any way you see fit, including
+ without restriction, using this code in your own products. You do
+ not need to give any attribution.
+*/
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <nss.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "nss_winbind.h"
+
+/*
+ find a function in the nss library
+*/
+static void *find_fn(struct nss_state *nss, const char *name)
+{
+ void *res;
+ char *s = NULL;
+
+ asprintf(&s, "_nss_%s_%s", nss->nss_name, name);
+ if (!s) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ res = dlsym(nss->dl_handle, s);
+ free(s);
+ if (!res) {
+ errno = ENOENT;
+ return NULL;
+ }
+ return res;
+}
+
+/*
+ establish a link to the nss library
+ Return 0 on success and -1 on error
+*/
+int nss_open(struct nss_state *nss, const char *nss_path)
+{
+ char *p;
+ p = strrchr(nss_path, '_');
+ if (!p) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ nss->nss_name = strdup(p+1);
+ p = strchr(nss->nss_name, '.');
+ if (p) *p = 0;
+
+ nss->dl_handle = dlopen(nss_path, RTLD_LAZY);
+ if (!nss->dl_handle) {
+ free(nss->nss_name);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ close and cleanup a nss state
+*/
+void nss_close(struct nss_state *nss)
+{
+ free(nss->nss_name);
+ dlclose(nss->dl_handle);
+}
+
+/*
+ make a getpwnam call.
+ Return 0 on success and -1 on error
+*/
+int nss_getpwent(struct nss_state *nss, struct passwd *pwd)
+{
+ enum nss_status (*_nss_getpwent_r)(struct passwd *, char *,
+ size_t , int *);
+ enum nss_status status;
+ int nss_errno = 0;
+
+ _nss_getpwent_r = find_fn(nss, "getpwent_r");
+
+ if (!_nss_getpwent_r) {
+ return -1;
+ }
+
+ status = _nss_getpwent_r(pwd, nss->pwnam_buf, sizeof(nss->pwnam_buf),
+ &nss_errno);
+ if (status == NSS_STATUS_NOTFOUND) {
+ errno = ENOENT;
+ return -1;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ errno = nss_errno;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ make a setpwent call.
+ Return 0 on success and -1 on error
+*/
+int nss_setpwent(struct nss_state *nss)
+{
+ enum nss_status (*_nss_setpwent)(void) = find_fn(nss, "setpwent");
+ enum nss_status status;
+ if (!_nss_setpwent) {
+ return -1;
+ }
+ status = _nss_setpwent();
+ if (status != NSS_STATUS_SUCCESS) {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ make a endpwent call.
+ Return 0 on success and -1 on error
+*/
+int nss_endpwent(struct nss_state *nss)
+{
+ enum nss_status (*_nss_endpwent)(void) = find_fn(nss, "endpwent");
+ enum nss_status status;
+ if (!_nss_endpwent) {
+ return -1;
+ }
+ status = _nss_endpwent();
+ if (status != NSS_STATUS_SUCCESS) {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+
+/*
+ convert a name to a SID
+ caller frees
+ Return 0 on success and -1 on error
+*/
+int nss_nametosid(struct nss_state *nss, const char *name, char **sid)
+{
+ enum nss_status (*_nss_nametosid)(const char *, char **, char *,
+ size_t, int *);
+ enum nss_status status;
+ int nss_errno = 0;
+ char buf[200];
+
+ _nss_nametosid = find_fn(nss, "nametosid");
+
+ if (!_nss_nametosid) {
+ return -1;
+ }
+
+ status = _nss_nametosid(name, sid, buf, sizeof(buf), &nss_errno);
+ if (status == NSS_STATUS_NOTFOUND) {
+ errno = ENOENT;
+ return -1;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ errno = nss_errno;
+ return -1;
+ }
+
+ *sid = strdup(*sid);
+
+ return 0;
+}
+
+/*
+ convert a SID to a name
+ caller frees
+ Return 0 on success and -1 on error
+*/
+int nss_sidtoname(struct nss_state *nss, const char *sid, char **name)
+{
+ enum nss_status (*_nss_sidtoname)(const char *, char **, char *,
+ size_t, int *);
+ enum nss_status status;
+ int nss_errno = 0;
+ char buf[200];
+
+ _nss_sidtoname = find_fn(nss, "sidtoname");
+
+ if (!_nss_sidtoname) {
+ return -1;
+ }
+
+ status = _nss_sidtoname(sid, name, buf, sizeof(buf), &nss_errno);
+ if (status == NSS_STATUS_NOTFOUND) {
+ errno = ENOENT;
+ return -1;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ errno = nss_errno;
+ return -1;
+ }
+
+ *name = strdup(*name);
+
+ return 0;
+}
+
+/*
+ return a list of group SIDs for a user SID
+ the returned list is NULL terminated
+ Return 0 on success and -1 on error
+*/
+int nss_getusersids(struct nss_state *nss, const char *user_sid, char ***sids)
+{
+ enum nss_status (*_nss_getusersids)(const char *, char **, int *,
+ char *, size_t, int *);
+ enum nss_status status;
+ int nss_errno = 0;
+ char *s;
+ int i, num_groups = 0;
+ unsigned bufsize = 10;
+ char *buf;
+
+ _nss_getusersids = find_fn(nss, "getusersids");
+
+ if (!_nss_getusersids) {
+ return -1;
+ }
+
+again:
+ buf = malloc(bufsize);
+ if (!buf) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ status = _nss_getusersids(user_sid, &s, &num_groups, buf, bufsize,
+ &nss_errno);
+
+ if (status == NSS_STATUS_NOTFOUND) {
+ errno = ENOENT;
+ free(buf);
+ return -1;
+ }
+
+ if (status == NSS_STATUS_TRYAGAIN) {
+ bufsize *= 2;
+ free(buf);
+ goto again;
+ }
+
+ if (status != NSS_STATUS_SUCCESS) {
+ free(buf);
+ errno = nss_errno;
+ return -1;
+ }
+
+ if (num_groups == 0) {
+ free(buf);
+ return 0;
+ }
+
+ *sids = (char **)malloc(sizeof(char *) * (num_groups+1));
+ if (! *sids) {
+ errno = ENOMEM;
+ free(buf);
+ return -1;
+ }
+
+ for (i=0;i<num_groups;i++) {
+ (*sids)[i] = strdup(s);
+ s += strlen(s) + 1;
+ }
+ (*sids)[i] = NULL;
+
+ free(buf);
+
+ return 0;
+}
+
+/*
+ convert a sid to a uid
+ Return 0 on success and -1 on error
+*/
+int nss_sidtouid(struct nss_state *nss, const char *sid, uid_t *uid)
+{
+ enum nss_status (*_nss_sidtouid)(const char*, uid_t *, int*);
+
+ enum nss_status status;
+ int nss_errno = 0;
+
+ _nss_sidtouid = find_fn(nss, "sidtouid");
+
+ if (!_nss_sidtouid) {
+ return -1;
+ }
+
+ status = _nss_sidtouid(sid, uid, &nss_errno);
+
+ if (status == NSS_STATUS_NOTFOUND) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (status != NSS_STATUS_SUCCESS) {
+ errno = nss_errno;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ convert a sid to a gid
+ Return 0 on success and -1 on error
+*/
+int nss_sidtogid(struct nss_state *nss, const char *sid, gid_t *gid)
+{
+ enum nss_status (*_nss_sidtogid)(const char*, gid_t *, int*);
+
+ enum nss_status status;
+ int nss_errno = 0;
+
+ _nss_sidtogid = find_fn(nss, "sidtogid");
+
+ if (!_nss_sidtogid) {
+ return -1;
+ }
+
+ status = _nss_sidtogid(sid, gid, &nss_errno);
+
+ if (status == NSS_STATUS_NOTFOUND) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ if (status != NSS_STATUS_SUCCESS) {
+ errno = nss_errno;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ convert a uid to a sid
+ caller frees
+ Return 0 on success and -1 on error
+*/
+int nss_uidtosid(struct nss_state *nss, uid_t uid, char **sid)
+{
+ enum nss_status (*_nss_uidtosid)(uid_t, char **, char *,
+ size_t, int *);
+ enum nss_status status;
+ int nss_errno = 0;
+ char buf[200];
+
+ _nss_uidtosid = find_fn(nss, "uidtosid");
+
+ if (!_nss_uidtosid) {
+ return -1;
+ }
+
+ status = _nss_uidtosid(uid, sid, buf, sizeof(buf), &nss_errno);
+ if (status == NSS_STATUS_NOTFOUND) {
+ errno = ENOENT;
+ return -1;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ errno = nss_errno;
+ return -1;
+ }
+
+ *sid = strdup(*sid);
+
+ return 0;
+}
+
+/*
+ convert a gid to a sid
+ caller frees
+ Return 0 on success and -1 on error
+*/
+int nss_gidtosid(struct nss_state *nss, gid_t gid, char **sid)
+{
+ enum nss_status (*_nss_gidtosid)(gid_t, char **, char *,
+ size_t, int *);
+ enum nss_status status;
+ int nss_errno = 0;
+ char buf[200];
+
+ _nss_gidtosid = find_fn(nss, "gidtosid");
+
+ if (!_nss_gidtosid) {
+ return -1;
+ }
+
+ status = _nss_gidtosid(gid, sid, buf, sizeof(buf), &nss_errno);
+ if (status == NSS_STATUS_NOTFOUND) {
+ errno = ENOENT;
+ return -1;
+ }
+ if (status != NSS_STATUS_SUCCESS) {
+ errno = nss_errno;
+ return -1;
+ }
+
+ *sid = strdup(*sid);
+
+ return 0;
+}
+
diff --git a/examples/nss/nss_winbind.h b/examples/nss/nss_winbind.h
new file mode 100644
index 0000000..5a124a5
--- /dev/null
+++ b/examples/nss/nss_winbind.h
@@ -0,0 +1,97 @@
+/*
+ nss sample code for extended winbindd functionality
+
+ Copyright (C) Andrew Tridgell (tridge@samba.org)
+ Copyright (C) Volker Lendecke (vl@samba.org)
+
+ you are free to use this code in any way you see fit, including
+ without restriction, using this code in your own products. You do
+ not need to give any attribution.
+*/
+
+#define _GNU_SOURCE
+
+#include <pwd.h>
+#include <grp.h>
+
+struct nss_state {
+ void *dl_handle;
+ char *nss_name;
+ char pwnam_buf[512];
+};
+
+/*
+ establish a link to the nss library
+ Return 0 on success and -1 on error
+*/
+int nss_open(struct nss_state *nss, const char *nss_path);
+
+/*
+ close and cleanup a nss state
+*/
+void nss_close(struct nss_state *nss);
+
+/*
+ make a getpwnam call.
+ Return 0 on success and -1 on error
+*/
+int nss_getpwent(struct nss_state *nss, struct passwd *pwd);
+
+/*
+ make a setpwent call.
+ Return 0 on success and -1 on error
+*/
+int nss_setpwent(struct nss_state *nss);
+
+/*
+ make a endpwent call.
+ Return 0 on success and -1 on error
+*/
+int nss_endpwent(struct nss_state *nss);
+
+/*
+ convert a name to a SID
+ caller frees
+ Return 0 on success and -1 on error
+*/
+int nss_nametosid(struct nss_state *nss, const char *name, char **sid);
+
+/*
+ convert a SID to a name
+ caller frees
+ Return 0 on success and -1 on error
+*/
+int nss_sidtoname(struct nss_state *nss, const char *sid, char **name);
+
+/*
+ return a list of group SIDs for a user SID
+ the returned list is NULL terminated
+ Return 0 on success and -1 on error
+*/
+int nss_getusersids(struct nss_state *nss, const char *user_sid, char ***sids);
+
+/*
+ convert a sid to a uid
+ Return 0 on success and -1 on error
+*/
+int nss_sidtouid(struct nss_state *nss, const char *sid, uid_t *uid);
+
+/*
+ convert a sid to a gid
+ Return 0 on success and -1 on error
+*/
+int nss_sidtogid(struct nss_state *nss, const char *sid, gid_t *gid);
+
+/*
+ convert a uid to a sid
+ caller frees
+ Return 0 on success and -1 on error
+*/
+int nss_uidtosid(struct nss_state *nss, uid_t uid, char **sid);
+
+/*
+ convert a gid to a sid
+ caller frees
+ Return 0 on success and -1 on error
+*/
+int nss_gidtosid(struct nss_state *nss, gid_t gid, char **sid);
diff --git a/examples/nss/wbtest.c b/examples/nss/wbtest.c
new file mode 100644
index 0000000..14265bd
--- /dev/null
+++ b/examples/nss/wbtest.c
@@ -0,0 +1,111 @@
+/*
+ nss sample code for extended winbindd functionality
+
+ Copyright (C) Andrew Tridgell (tridge@samba.org)
+
+ you are free to use this code in any way you see fit, including
+ without restriction, using this code in your own products. You do
+ not need to give any attribution.
+*/
+
+/*
+ compile like this:
+
+ cc -o wbtest wbtest.c nss_winbind.c -ldl
+
+ and run like this:
+
+ ./wbtest /lib/libnss_winbind.so
+*/
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <nss.h>
+#include <dlfcn.h>
+#include <pwd.h>
+#include <grp.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "nss_winbind.h"
+
+static int nss_test_users(struct nss_state *nss)
+{
+ struct passwd pwd;
+
+ if (nss_setpwent(nss) != 0) {
+ perror("setpwent");
+ return -1;
+ }
+
+ /* loop over all users */
+ while ((nss_getpwent(nss, &pwd) == 0)) {
+ char *sid, **group_sids, *name2;
+ int i;
+
+ printf("User %s\n", pwd.pw_name);
+ if (nss_nametosid(nss, pwd.pw_name, &sid) != 0) {
+ perror("nametosid");
+ return -1;
+ }
+ printf("\tSID %s\n", sid);
+
+ if (nss_sidtoname(nss, sid, &name2) != 0) {
+ perror("sidtoname");
+ return -1;
+ }
+ printf("\tSID->name %s\n", name2);
+
+ if (nss_getusersids(nss, sid, &group_sids) != 0) {
+ perror("getusersids");
+ return -1;
+ }
+
+ printf("\tGroups:\n");
+ for (i=0; group_sids[i]; i++) {
+ printf("\t\t%s\n", group_sids[i]);
+ free(group_sids[i]);
+ }
+
+ free(sid);
+ free(name2);
+ free(group_sids);
+ }
+
+
+ if (nss_endpwent(nss) != 0) {
+ perror("endpwent");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ main program. It lists all users, listing user SIDs for each user
+ */
+int main(int argc, char *argv[])
+{
+ struct nss_state nss;
+ const char *so_path = "/lib/libnss_winbind.so";
+ int ret;
+
+ if (argc > 1) {
+ so_path = argv[1];
+ }
+
+ if (nss_open(&nss, so_path) != 0) {
+ perror("nss_open");
+ exit(1);
+ }
+
+ ret = nss_test_users(&nss);
+
+ nss_close(&nss);
+
+ return ret;
+}
diff --git a/examples/pam_winbind/pam_winbind.conf b/examples/pam_winbind/pam_winbind.conf
new file mode 100644
index 0000000..85cd513
--- /dev/null
+++ b/examples/pam_winbind/pam_winbind.conf
@@ -0,0 +1,39 @@
+#
+# pam_winbind configuration file
+#
+# /etc/security/pam_winbind.conf
+#
+# For more details see man pam_winbind.conf(5)
+
+[global]
+
+# turn on debugging
+;debug = no
+
+# turn on extended PAM state debugging
+;debug_state = no
+
+# request a cached login if possible
+# (needs "winbind offline logon = yes" in smb.conf)
+;cached_login = no
+
+# authenticate using kerberos
+;krb5_auth = no
+
+# when using kerberos, request a "FILE" or "DIR" krb5 credential cache type
+# (leave empty to just do krb5 authentication but not have a ticket
+# afterwards)
+;krb5_ccache_type =
+
+# make successful authentication dependent on membership of one SID
+# (can also take a name)
+;require_membership_of =
+
+# password expiry warning period in days
+;warn_pwd_expire = 14
+
+# omit pam conversations
+;silent = no
+
+# create homedirectory on the fly
+;mkhomedir = no
diff --git a/examples/pcap2nbench/COPYING b/examples/pcap2nbench/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/examples/pcap2nbench/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 3 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, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/examples/pcap2nbench/Makefile b/examples/pcap2nbench/Makefile
new file mode 100644
index 0000000..c1221b3
--- /dev/null
+++ b/examples/pcap2nbench/Makefile
@@ -0,0 +1,33 @@
+###############################################################################
+##
+## pcap2nbench - Converts libpcap network traces to nbench input
+## Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+##
+## Written by Anthony Liguori <aliguori@us.ibm.com>
+##
+###############################################################################
+
+OBJ=main.o ethernet.o ip.o tcp.o smb.o ntcreateandxrequest.o readandxrequest.o writeandxrequest.o closerequest.o ntcreateandxresponse.o
+PROG=pcap2nbench
+CXXFLAGS=-g -Wall
+LDFLAGS=
+LIB=-lpcap
+
+$(PROG): $(OBJ)
+ $(CXX) -o $(PROG) $(CXXFLAGS) $(OBJ) $(LDFLAGS) $(LIB)
+
+clean:
+ $(RM) $(OBJ) $(PROG)
diff --git a/examples/pcap2nbench/README b/examples/pcap2nbench/README
new file mode 100644
index 0000000..09c30e0
--- /dev/null
+++ b/examples/pcap2nbench/README
@@ -0,0 +1,24 @@
+pcap2nbench
+-----------
+
+About
+
+This program converts a libpcap network trace file (produced by ethereal or
+another pcap-aware network analyzer) into a output suitable for nbench. The
+only option it takes is -i which suppresses any reads/writes/closes that use a
+FID that does not have a corresponding ntcreateandx
+
+Limitations
+
+1) pcap2nbench does not handle ip fragmentation. You should not normally see
+ very much fragmentation so this should not really affect a workload.
+2) unicode on the wire is not supported.
+3) only a limited number of SMBs are supported. Namely: NtCreateAndX,
+ ReadAndX, WriteAndX, and Close. In addition, not all WCTs are supported on
+ each of these SMBs.
+
+Future Work
+
+It would be nice to use Samba or Ethereal's parsing code to handle the SMBs.
+At first glance, this seemed non-trivial. It would also be nice to handle some
+Trans2 SMBs specifically QueryFileInfo and QueryPathInfo.
diff --git a/examples/pcap2nbench/closerequest.cpp b/examples/pcap2nbench/closerequest.cpp
new file mode 100644
index 0000000..b31a1b6
--- /dev/null
+++ b/examples/pcap2nbench/closerequest.cpp
@@ -0,0 +1,45 @@
+/*\
+ * pcap2nbench - Converts libpcap network traces to nbench input
+ * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Anthony Liguori <aliguori@us.ibm.com>
+\*/
+
+#include <netinet/in.h>
+
+#include "closerequest.hpp"
+
+CloseRequest::CloseRequest(const uint8_t *data, size_t size)
+{
+ if (size < 9) {
+ std::cerr << "Invalid Close Request" << std::endl;
+ return;
+ }
+
+ word_count = data[0];
+ memcpy(&fid, data + 1, 2);
+ memcpy(&last_write, data + 3, 4);
+ memcpy(&byte_count, data + 7, 2);
+}
+
+std::ostream &operator<<(std::ostream &lhs, const CloseRequest &rhs)
+{
+ lhs << "Word Count: " << (uint16_t)rhs.word_count << std::endl
+ << "Fid: " << rhs.fid << std::endl
+ << "Last Write: " << rhs.last_write << std::endl
+ << "Byte Count: " << rhs.byte_count << std::endl;
+ return lhs;
+}
diff --git a/examples/pcap2nbench/closerequest.hpp b/examples/pcap2nbench/closerequest.hpp
new file mode 100644
index 0000000..fe8866f
--- /dev/null
+++ b/examples/pcap2nbench/closerequest.hpp
@@ -0,0 +1,43 @@
+/*\
+ * pcap2nbench - Converts libpcap network traces to nbench input
+ * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Anthony Liguori <aliguori@us.ibm.com>
+\*/
+
+#ifndef _CLOSE_REQUEST_HPP
+#define _CLOSE_REQUEST_HPP
+
+#include <iostream>
+#include <stdint.h>
+
+struct CloseRequest {
+ enum {
+ COMMAND = 0x04
+ };
+
+ CloseRequest() {}
+ CloseRequest(const uint8_t *data, size_t size);
+
+ uint8_t word_count;
+ uint16_t fid;
+ uint32_t last_write;
+ uint16_t byte_count;
+};
+
+std::ostream &operator<<(std::ostream &lhs, const CloseRequest &rhs);
+
+#endif
diff --git a/examples/pcap2nbench/ethernet.cpp b/examples/pcap2nbench/ethernet.cpp
new file mode 100644
index 0000000..4d53159
--- /dev/null
+++ b/examples/pcap2nbench/ethernet.cpp
@@ -0,0 +1,61 @@
+/*\
+ * pcap2nbench - Converts libpcap network traces to nbench input
+ * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Anthony Liguori <aliguori@us.ibm.com>
+\*/
+
+#include <netinet/in.h>
+
+#include "ethernet.hpp"
+
+ethernet::ethernet(const uint8_t *data, size_t length) {
+ if (length < 14) {
+ std::cerr << "Invalid ethernet packet" << std::endl;
+ }
+ memcpy(dst, data, sizeof(dst));
+ memcpy(src, data + 6, sizeof(src));
+ memcpy(&type, data + 12, sizeof(type));
+ type = ntohs(type);
+}
+
+std::ostream &operator<<(std::ostream &lhs, const ethernet &rhs)
+{
+ lhs << "Destination: ";
+ for (int i = 0; i < 6; i++) {
+ char buf[3];
+ sprintf(buf, "%.2x", rhs.dst[i]);
+ if (i) lhs << ":";
+ lhs << buf;
+ }
+ lhs << std::endl;
+
+ lhs << "Source: ";
+ for (int i = 0; i < 6; i++) {
+ char buf[3];
+ sprintf(buf, "%.2x", rhs.src[i]);
+ if (i) lhs << ":";
+ lhs << buf;
+ }
+ lhs << std::endl;
+
+ lhs << "Type: ";
+ char buf[7];
+ sprintf(buf, "%.4x", rhs.type);
+ lhs << buf << std::endl;
+
+ return lhs;
+}
diff --git a/examples/pcap2nbench/ethernet.hpp b/examples/pcap2nbench/ethernet.hpp
new file mode 100644
index 0000000..baaca5a
--- /dev/null
+++ b/examples/pcap2nbench/ethernet.hpp
@@ -0,0 +1,36 @@
+/*\
+ * pcap2nbench - Converts libpcap network traces to nbench input
+ * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Anthony Liguori <aliguori@us.ibm.com>
+\*/
+
+#ifndef ETHERNET_HPP
+#define ETHERNET_HPP
+
+#include <stdint.h>
+#include <iostream>
+
+struct ethernet {
+ ethernet(const uint8_t *data, size_t length);
+ uint8_t dst[6];
+ uint8_t src[6];
+ uint16_t type;
+};
+
+std::ostream &operator<<(std::ostream &lhs, const ethernet &rhs);
+
+#endif
diff --git a/examples/pcap2nbench/ip.cpp b/examples/pcap2nbench/ip.cpp
new file mode 100644
index 0000000..8f1d821
--- /dev/null
+++ b/examples/pcap2nbench/ip.cpp
@@ -0,0 +1,65 @@
+/*\
+ * pcap2nbench - Converts libpcap network traces to nbench input
+ * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Anthony Liguori <aliguori@us.ibm.com>
+\*/
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include "ip.hpp"
+
+ip::ip(const uint8_t *data, size_t length)
+{
+ if (length < 20) {
+ std::cerr << "Invalid ip packet" << std::endl;
+ }
+
+ version = (data[0] >> 4) & 0x0F;
+ header_length = (data[0] & 0x0F) * 4;
+ dsfield = data[1];
+ memcpy(&total_length, data + 2, 2);
+ total_length = ntohs(total_length);
+ memcpy(&id, data + 4, 2);
+ id = ntohs(id);
+ flags = (data[6] >> 4) & 0x0F;
+ fragment_offset = ((data[6] & 0x0F) << 4) | data[7];
+ ttl = data[8];
+ protocol = data[9];
+ memcpy(&checksum, data + 10, 2);
+ checksum = ntohs(checksum);
+ memcpy(&source, data + 12, 4);
+ memcpy(&destination, data + 16, 4);
+}
+
+std::ostream &operator<<(std::ostream &lhs, const ip &rhs)
+{
+ lhs << "Version: " << (uint32_t)rhs.version << std::endl
+ << "Header length: " << (uint32_t)rhs.header_length << std::endl
+ << "Differentiated Services Field: " << (uint32_t)rhs.dsfield << std::endl
+ << "Total Length: " << (uint32_t)rhs.total_length << std::endl
+ << "Identification: " << (uint32_t)rhs.id << std::endl
+ << "Flags: " << (uint32_t)rhs.flags << std::endl
+ << "Fragment offset: " << (uint32_t)rhs.fragment_offset << std::endl
+ << "TTL: " << (uint32_t)rhs.ttl << std::endl
+ << "Protocol: " << (uint32_t)rhs.protocol << std::endl
+ << "Checksum: " << (uint32_t)rhs.checksum << std::endl
+ << "Source: " << inet_ntoa(*((in_addr *)&rhs.source)) << std::endl
+ << "Destination: " << inet_ntoa(*((in_addr *)&rhs.destination)) << std::endl;
+
+ return lhs;
+}
diff --git a/examples/pcap2nbench/ip.hpp b/examples/pcap2nbench/ip.hpp
new file mode 100644
index 0000000..da1f0d3
--- /dev/null
+++ b/examples/pcap2nbench/ip.hpp
@@ -0,0 +1,46 @@
+/*\
+ * pcap2nbench - Converts libpcap network traces to nbench input
+ * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Anthony Liguori <aliguori@us.ibm.com>
+\*/
+
+#ifndef IP_HPP
+#define IP_HPP
+
+#include <stdint.h>
+#include <iostream>
+
+struct ip {
+ ip(const uint8_t *data, size_t length);
+
+ uint8_t version;
+ uint8_t header_length;
+ uint8_t dsfield;
+ uint16_t total_length;
+ uint16_t id;
+ uint8_t flags;
+ uint16_t fragment_offset;
+ uint8_t ttl;
+ uint8_t protocol;
+ uint16_t checksum;
+ uint32_t source;
+ uint32_t destination;
+};
+
+std::ostream &operator<<(std::ostream &lhs, const ip &rhs);
+
+#endif
diff --git a/examples/pcap2nbench/main.cpp b/examples/pcap2nbench/main.cpp
new file mode 100644
index 0000000..e07b473
--- /dev/null
+++ b/examples/pcap2nbench/main.cpp
@@ -0,0 +1,738 @@
+/*\
+ * pcap2nbench - Converts libpcap network traces to nbench input
+ * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Anthony Liguori <aliguori@us.ibm.com>
+\*/
+
+#include <iostream>
+#include <pcap.h>
+#include <getopt.h>
+#include <stdint.h>
+#include <netinet/in.h>
+
+#include "ethernet.hpp"
+#include "ip.hpp"
+#include "tcp.hpp"
+#include "smb.hpp"
+#include "ntcreateandxrequest.hpp"
+#include "ntcreateandxresponse.hpp"
+#include "readandxrequest.hpp"
+#include "writeandxrequest.hpp"
+#include "closerequest.hpp"
+
+#include <vector>
+#include <set>
+
+
+/* derived from source/include/nterr.h */
+const char *nt_status_to_string[] = {
+ "NT_STATUS_OK", /* 0x0000 */
+ "NT_STATUS_UNSUCCESSFUL", /* 0x0001 */
+ "NT_STATUS_NOT_IMPLEMENTED", /* 0x0002 */
+ "NT_STATUS_INVALID_INFO_CLASS", /* 0x0003 */
+ "NT_STATUS_INFO_LENGTH_MISMATCH", /* 0x0004 */
+ "NT_STATUS_ACCESS_VIOLATION", /* 0x0005 */
+ "NT_STATUS_IN_PAGE_ERROR", /* 0x0006 */
+ "NT_STATUS_PAGEFILE_QUOTA", /* 0x0007 */
+ "NT_STATUS_INVALID_HANDLE", /* 0x0008 */
+ "NT_STATUS_BAD_INITIAL_STACK", /* 0x0009 */
+ "NT_STATUS_BAD_INITIAL_PC", /* 0x000a */
+ "NT_STATUS_INVALID_CID", /* 0x000b */
+ "NT_STATUS_TIMER_NOT_CANCELED", /* 0x000c */
+ "NT_STATUS_INVALID_PARAMETER", /* 0x000d */
+ "NT_STATUS_NO_SUCH_DEVICE", /* 0x000e */
+ "NT_STATUS_NO_SUCH_FILE", /* 0x000f */
+ "NT_STATUS_INVALID_DEVICE_REQUEST", /* 0x0010 */
+ "NT_STATUS_END_OF_FILE", /* 0x0011 */
+ "NT_STATUS_WRONG_VOLUME", /* 0x0012 */
+ "NT_STATUS_NO_MEDIA_IN_DEVICE", /* 0x0013 */
+ "NT_STATUS_UNRECOGNIZED_MEDIA", /* 0x0014 */
+ "NT_STATUS_NONEXISTENT_SECTOR", /* 0x0015 */
+ "NT_STATUS_MORE_PROCESSING_REQUIRED", /* 0x0016 */
+ "NT_STATUS_NO_MEMORY", /* 0x0017 */
+ "NT_STATUS_CONFLICTING_ADDRESSES", /* 0x0018 */
+ "NT_STATUS_NOT_MAPPED_VIEW", /* 0x0019 */
+ "NT_STATUS_UNABLE_TO_FREE_VM", /* 0x001a */
+ "NT_STATUS_UNABLE_TO_DELETE_SECTION", /* 0x001b */
+ "NT_STATUS_INVALID_SYSTEM_SERVICE", /* 0x001c */
+ "NT_STATUS_ILLEGAL_INSTRUCTION", /* 0x001d */
+ "NT_STATUS_INVALID_LOCK_SEQUENCE", /* 0x001e */
+ "NT_STATUS_INVALID_VIEW_SIZE", /* 0x001f */
+ "NT_STATUS_INVALID_FILE_FOR_SECTION", /* 0x0020 */
+ "NT_STATUS_ALREADY_COMMITTED", /* 0x0021 */
+ "NT_STATUS_ACCESS_DENIED", /* 0x0022 */
+ "NT_STATUS_BUFFER_TOO_SMALL", /* 0x0023 */
+ "NT_STATUS_OBJECT_TYPE_MISMATCH", /* 0x0024 */
+ "NT_STATUS_NONCONTINUABLE_EXCEPTION", /* 0x0025 */
+ "NT_STATUS_INVALID_DISPOSITION", /* 0x0026 */
+ "NT_STATUS_UNWIND", /* 0x0027 */
+ "NT_STATUS_BAD_STACK", /* 0x0028 */
+ "NT_STATUS_INVALID_UNWIND_TARGET", /* 0x0029 */
+ "NT_STATUS_NOT_LOCKED", /* 0x002a */
+ "NT_STATUS_PARITY_ERROR", /* 0x002b */
+ "NT_STATUS_UNABLE_TO_DECOMMIT_VM", /* 0x002c */
+ "NT_STATUS_NOT_COMMITTED", /* 0x002d */
+ "NT_STATUS_INVALID_PORT_ATTRIBUTES", /* 0x002e */
+ "NT_STATUS_PORT_MESSAGE_TOO_LONG", /* 0x002f */
+ "NT_STATUS_INVALID_PARAMETER_MIX", /* 0x0030 */
+ "NT_STATUS_INVALID_QUOTA_LOWER", /* 0x0031 */
+ "NT_STATUS_DISK_CORRUPT_ERROR", /* 0x0032 */
+ "NT_STATUS_OBJECT_NAME_INVALID", /* 0x0033 */
+ "NT_STATUS_OBJECT_NAME_NOT_FOUND", /* 0x0034 */
+ "NT_STATUS_OBJECT_NAME_COLLISION", /* 0x0035 */
+ "NT_STATUS_HANDLE_NOT_WAITABLE", /* 0x0036 */
+ "NT_STATUS_PORT_DISCONNECTED", /* 0x0037 */
+ "NT_STATUS_DEVICE_ALREADY_ATTACHED", /* 0x0038 */
+ "NT_STATUS_OBJECT_PATH_INVALID", /* 0x0039 */
+ "NT_STATUS_OBJECT_PATH_NOT_FOUND", /* 0x003a */
+ "NT_STATUS_OBJECT_PATH_SYNTAX_BAD", /* 0x003b */
+ "NT_STATUS_DATA_OVERRUN", /* 0x003c */
+ "NT_STATUS_DATA_LATE_ERROR", /* 0x003d */
+ "NT_STATUS_DATA_ERROR", /* 0x003e */
+ "NT_STATUS_CRC_ERROR", /* 0x003f */
+ "NT_STATUS_SECTION_TOO_BIG", /* 0x0040 */
+ "NT_STATUS_PORT_CONNECTION_REFUSED", /* 0x0041 */
+ "NT_STATUS_INVALID_PORT_HANDLE", /* 0x0042 */
+ "NT_STATUS_SHARING_VIOLATION", /* 0x0043 */
+ "NT_STATUS_QUOTA_EXCEEDED", /* 0x0044 */
+ "NT_STATUS_INVALID_PAGE_PROTECTION", /* 0x0045 */
+ "NT_STATUS_MUTANT_NOT_OWNED", /* 0x0046 */
+ "NT_STATUS_SEMAPHORE_LIMIT_EXCEEDED", /* 0x0047 */
+ "NT_STATUS_PORT_ALREADY_SET", /* 0x0048 */
+ "NT_STATUS_SECTION_NOT_IMAGE", /* 0x0049 */
+ "NT_STATUS_SUSPEND_COUNT_EXCEEDED", /* 0x004a */
+ "NT_STATUS_THREAD_IS_TERMINATING", /* 0x004b */
+ "NT_STATUS_BAD_WORKING_SET_LIMIT", /* 0x004c */
+ "NT_STATUS_INCOMPATIBLE_FILE_MAP", /* 0x004d */
+ "NT_STATUS_SECTION_PROTECTION", /* 0x004e */
+ "NT_STATUS_EAS_NOT_SUPPORTED", /* 0x004f */
+ "NT_STATUS_EA_TOO_LARGE", /* 0x0050 */
+ "NT_STATUS_NONEXISTENT_EA_ENTRY", /* 0x0051 */
+ "NT_STATUS_NO_EAS_ON_FILE", /* 0x0052 */
+ "NT_STATUS_EA_CORRUPT_ERROR", /* 0x0053 */
+ "NT_STATUS_FILE_LOCK_CONFLICT", /* 0x0054 */
+ "NT_STATUS_LOCK_NOT_GRANTED", /* 0x0055 */
+ "NT_STATUS_DELETE_PENDING", /* 0x0056 */
+ "NT_STATUS_CTL_FILE_NOT_SUPPORTED", /* 0x0057 */
+ "NT_STATUS_UNKNOWN_REVISION", /* 0x0058 */
+ "NT_STATUS_REVISION_MISMATCH", /* 0x0059 */
+ "NT_STATUS_INVALID_OWNER", /* 0x005a */
+ "NT_STATUS_INVALID_PRIMARY_GROUP", /* 0x005b */
+ "NT_STATUS_NO_IMPERSONATION_TOKEN", /* 0x005c */
+ "NT_STATUS_CANT_DISABLE_MANDATORY", /* 0x005d */
+ "NT_STATUS_NO_LOGON_SERVERS", /* 0x005e */
+ "NT_STATUS_NO_SUCH_LOGON_SESSION", /* 0x005f */
+ "NT_STATUS_NO_SUCH_PRIVILEGE", /* 0x0060 */
+ "NT_STATUS_PRIVILEGE_NOT_HELD", /* 0x0061 */
+ "NT_STATUS_INVALID_ACCOUNT_NAME", /* 0x0062 */
+ "NT_STATUS_USER_EXISTS", /* 0x0063 */
+ "NT_STATUS_NO_SUCH_USER", /* 0x0064 */
+ "NT_STATUS_GROUP_EXISTS", /* 0x0065 */
+ "NT_STATUS_NO_SUCH_GROUP", /* 0x0066 */
+ "NT_STATUS_MEMBER_IN_GROUP", /* 0x0067 */
+ "NT_STATUS_MEMBER_NOT_IN_GROUP", /* 0x0068 */
+ "NT_STATUS_LAST_ADMIN", /* 0x0069 */
+ "NT_STATUS_WRONG_PASSWORD", /* 0x006a */
+ "NT_STATUS_ILL_FORMED_PASSWORD", /* 0x006b */
+ "NT_STATUS_PASSWORD_RESTRICTION", /* 0x006c */
+ "NT_STATUS_LOGON_FAILURE", /* 0x006d */
+ "NT_STATUS_ACCOUNT_RESTRICTION", /* 0x006e */
+ "NT_STATUS_INVALID_LOGON_HOURS", /* 0x006f */
+ "NT_STATUS_INVALID_WORKSTATION", /* 0x0070 */
+ "NT_STATUS_PASSWORD_EXPIRED", /* 0x0071 */
+ "NT_STATUS_ACCOUNT_DISABLED", /* 0x0072 */
+ "NT_STATUS_NONE_MAPPED", /* 0x0073 */
+ "NT_STATUS_TOO_MANY_LUIDS_REQUESTED", /* 0x0074 */
+ "NT_STATUS_LUIDS_EXHAUSTED", /* 0x0075 */
+ "NT_STATUS_INVALID_SUB_AUTHORITY", /* 0x0076 */
+ "NT_STATUS_INVALID_ACL", /* 0x0077 */
+ "NT_STATUS_INVALID_SID", /* 0x0078 */
+ "NT_STATUS_INVALID_SECURITY_DESCR", /* 0x0079 */
+ "NT_STATUS_PROCEDURE_NOT_FOUND", /* 0x007a */
+ "NT_STATUS_INVALID_IMAGE_FORMAT", /* 0x007b */
+ "NT_STATUS_NO_TOKEN", /* 0x007c */
+ "NT_STATUS_BAD_INHERITANCE_ACL", /* 0x007d */
+ "NT_STATUS_RANGE_NOT_LOCKED", /* 0x007e */
+ "NT_STATUS_DISK_FULL", /* 0x007f */
+ "NT_STATUS_SERVER_DISABLED", /* 0x0080 */
+ "NT_STATUS_SERVER_NOT_DISABLED", /* 0x0081 */
+ "NT_STATUS_TOO_MANY_GUIDS_REQUESTED", /* 0x0082 */
+ "NT_STATUS_GUIDS_EXHAUSTED", /* 0x0083 */
+ "NT_STATUS_INVALID_ID_AUTHORITY", /* 0x0084 */
+ "NT_STATUS_AGENTS_EXHAUSTED", /* 0x0085 */
+ "NT_STATUS_INVALID_VOLUME_LABEL", /* 0x0086 */
+ "NT_STATUS_SECTION_NOT_EXTENDED", /* 0x0087 */
+ "NT_STATUS_NOT_MAPPED_DATA", /* 0x0088 */
+ "NT_STATUS_RESOURCE_DATA_NOT_FOUND", /* 0x0089 */
+ "NT_STATUS_RESOURCE_TYPE_NOT_FOUND", /* 0x008a */
+ "NT_STATUS_RESOURCE_NAME_NOT_FOUND", /* 0x008b */
+ "NT_STATUS_ARRAY_BOUNDS_EXCEEDED", /* 0x008c */
+ "NT_STATUS_FLOAT_DENORMAL_OPERAND", /* 0x008d */
+ "NT_STATUS_FLOAT_DIVIDE_BY_ZERO", /* 0x008e */
+ "NT_STATUS_FLOAT_INEXACT_RESULT", /* 0x008f */
+ "NT_STATUS_FLOAT_INVALID_OPERATION", /* 0x0090 */
+ "NT_STATUS_FLOAT_OVERFLOW", /* 0x0091 */
+ "NT_STATUS_FLOAT_STACK_CHECK", /* 0x0092 */
+ "NT_STATUS_FLOAT_UNDERFLOW", /* 0x0093 */
+ "NT_STATUS_INTEGER_DIVIDE_BY_ZERO", /* 0x0094 */
+ "NT_STATUS_INTEGER_OVERFLOW", /* 0x0095 */
+ "NT_STATUS_PRIVILEGED_INSTRUCTION", /* 0x0096 */
+ "NT_STATUS_TOO_MANY_PAGING_FILES", /* 0x0097 */
+ "NT_STATUS_FILE_INVALID", /* 0x0098 */
+ "NT_STATUS_ALLOTTED_SPACE_EXCEEDED", /* 0x0099 */
+ "NT_STATUS_INSUFFICIENT_RESOURCES", /* 0x009a */
+ "NT_STATUS_DFS_EXIT_PATH_FOUND", /* 0x009b */
+ "NT_STATUS_DEVICE_DATA_ERROR", /* 0x009c */
+ "NT_STATUS_DEVICE_NOT_CONNECTED", /* 0x009d */
+ "NT_STATUS_DEVICE_POWER_FAILURE", /* 0x009e */
+ "NT_STATUS_FREE_VM_NOT_AT_BASE", /* 0x009f */
+ "NT_STATUS_MEMORY_NOT_ALLOCATED", /* 0x00a0 */
+ "NT_STATUS_WORKING_SET_QUOTA", /* 0x00a1 */
+ "NT_STATUS_MEDIA_WRITE_PROTECTED", /* 0x00a2 */
+ "NT_STATUS_DEVICE_NOT_READY", /* 0x00a3 */
+ "NT_STATUS_INVALID_GROUP_ATTRIBUTES", /* 0x00a4 */
+ "NT_STATUS_BAD_IMPERSONATION_LEVEL", /* 0x00a5 */
+ "NT_STATUS_CANT_OPEN_ANONYMOUS", /* 0x00a6 */
+ "NT_STATUS_BAD_VALIDATION_CLASS", /* 0x00a7 */
+ "NT_STATUS_BAD_TOKEN_TYPE", /* 0x00a8 */
+ "NT_STATUS_BAD_MASTER_BOOT_RECORD", /* 0x00a9 */
+ "NT_STATUS_INSTRUCTION_MISALIGNMENT", /* 0x00aa */
+ "NT_STATUS_INSTANCE_NOT_AVAILABLE", /* 0x00ab */
+ "NT_STATUS_PIPE_NOT_AVAILABLE", /* 0x00ac */
+ "NT_STATUS_INVALID_PIPE_STATE", /* 0x00ad */
+ "NT_STATUS_PIPE_BUSY", /* 0x00ae */
+ "NT_STATUS_ILLEGAL_FUNCTION", /* 0x00af */
+ "NT_STATUS_PIPE_DISCONNECTED", /* 0x00b0 */
+ "NT_STATUS_PIPE_CLOSING", /* 0x00b1 */
+ "NT_STATUS_PIPE_CONNECTED", /* 0x00b2 */
+ "NT_STATUS_PIPE_LISTENING", /* 0x00b3 */
+ "NT_STATUS_INVALID_READ_MODE", /* 0x00b4 */
+ "NT_STATUS_IO_TIMEOUT", /* 0x00b5 */
+ "NT_STATUS_FILE_FORCED_CLOSED", /* 0x00b6 */
+ "NT_STATUS_PROFILING_NOT_STARTED", /* 0x00b7 */
+ "NT_STATUS_PROFILING_NOT_STOPPED", /* 0x00b8 */
+ "NT_STATUS_COULD_NOT_INTERPRET", /* 0x00b9 */
+ "NT_STATUS_FILE_IS_A_DIRECTORY", /* 0x00ba */
+ "NT_STATUS_NOT_SUPPORTED", /* 0x00bb */
+ "NT_STATUS_REMOTE_NOT_LISTENING", /* 0x00bc */
+ "NT_STATUS_DUPLICATE_NAME", /* 0x00bd */
+ "NT_STATUS_BAD_NETWORK_PATH", /* 0x00be */
+ "NT_STATUS_NETWORK_BUSY", /* 0x00bf */
+ "NT_STATUS_DEVICE_DOES_NOT_EXIST", /* 0x00c0 */
+ "NT_STATUS_TOO_MANY_COMMANDS", /* 0x00c1 */
+ "NT_STATUS_ADAPTER_HARDWARE_ERROR", /* 0x00c2 */
+ "NT_STATUS_INVALID_NETWORK_RESPONSE", /* 0x00c3 */
+ "NT_STATUS_UNEXPECTED_NETWORK_ERROR", /* 0x00c4 */
+ "NT_STATUS_BAD_REMOTE_ADAPTER", /* 0x00c5 */
+ "NT_STATUS_PRINT_QUEUE_FULL", /* 0x00c6 */
+ "NT_STATUS_NO_SPOOL_SPACE", /* 0x00c7 */
+ "NT_STATUS_PRINT_CANCELLED", /* 0x00c8 */
+ "NT_STATUS_NETWORK_NAME_DELETED", /* 0x00c9 */
+ "NT_STATUS_NETWORK_ACCESS_DENIED", /* 0x00ca */
+ "NT_STATUS_BAD_DEVICE_TYPE", /* 0x00cb */
+ "NT_STATUS_BAD_NETWORK_NAME", /* 0x00cc */
+ "NT_STATUS_TOO_MANY_NAMES", /* 0x00cd */
+ "NT_STATUS_TOO_MANY_SESSIONS", /* 0x00ce */
+ "NT_STATUS_SHARING_PAUSED", /* 0x00cf */
+ "NT_STATUS_REQUEST_NOT_ACCEPTED", /* 0x00d0 */
+ "NT_STATUS_REDIRECTOR_PAUSED", /* 0x00d1 */
+ "NT_STATUS_NET_WRITE_FAULT", /* 0x00d2 */
+ "NT_STATUS_PROFILING_AT_LIMIT", /* 0x00d3 */
+ "NT_STATUS_NOT_SAME_DEVICE", /* 0x00d4 */
+ "NT_STATUS_FILE_RENAMED", /* 0x00d5 */
+ "NT_STATUS_VIRTUAL_CIRCUIT_CLOSED", /* 0x00d6 */
+ "NT_STATUS_NO_SECURITY_ON_OBJECT", /* 0x00d7 */
+ "NT_STATUS_CANT_WAIT", /* 0x00d8 */
+ "NT_STATUS_PIPE_EMPTY", /* 0x00d9 */
+ "NT_STATUS_CANT_ACCESS_DOMAIN_INFO", /* 0x00da */
+ "NT_STATUS_CANT_TERMINATE_SELF", /* 0x00db */
+ "NT_STATUS_INVALID_SERVER_STATE", /* 0x00dc */
+ "NT_STATUS_INVALID_DOMAIN_STATE", /* 0x00dd */
+ "NT_STATUS_INVALID_DOMAIN_ROLE", /* 0x00de */
+ "NT_STATUS_NO_SUCH_DOMAIN", /* 0x00df */
+ "NT_STATUS_DOMAIN_EXISTS", /* 0x00e0 */
+ "NT_STATUS_DOMAIN_LIMIT_EXCEEDED", /* 0x00e1 */
+ "NT_STATUS_OPLOCK_NOT_GRANTED", /* 0x00e2 */
+ "NT_STATUS_INVALID_OPLOCK_PROTOCOL", /* 0x00e3 */
+ "NT_STATUS_INTERNAL_DB_CORRUPTION", /* 0x00e4 */
+ "NT_STATUS_INTERNAL_ERROR", /* 0x00e5 */
+ "NT_STATUS_GENERIC_NOT_MAPPED", /* 0x00e6 */
+ "NT_STATUS_BAD_DESCRIPTOR_FORMAT", /* 0x00e7 */
+ "NT_STATUS_INVALID_USER_BUFFER", /* 0x00e8 */
+ "NT_STATUS_UNEXPECTED_IO_ERROR", /* 0x00e9 */
+ "NT_STATUS_UNEXPECTED_MM_CREATE_ERR", /* 0x00ea */
+ "NT_STATUS_UNEXPECTED_MM_MAP_ERROR", /* 0x00eb */
+ "NT_STATUS_UNEXPECTED_MM_EXTEND_ERR", /* 0x00ec */
+ "NT_STATUS_NOT_LOGON_PROCESS", /* 0x00ed */
+ "NT_STATUS_LOGON_SESSION_EXISTS", /* 0x00ee */
+ "NT_STATUS_INVALID_PARAMETER_1", /* 0x00ef */
+ "NT_STATUS_INVALID_PARAMETER_2", /* 0x00f0 */
+ "NT_STATUS_INVALID_PARAMETER_3", /* 0x00f1 */
+ "NT_STATUS_INVALID_PARAMETER_4", /* 0x00f2 */
+ "NT_STATUS_INVALID_PARAMETER_5", /* 0x00f3 */
+ "NT_STATUS_INVALID_PARAMETER_6", /* 0x00f4 */
+ "NT_STATUS_INVALID_PARAMETER_7", /* 0x00f5 */
+ "NT_STATUS_INVALID_PARAMETER_8", /* 0x00f6 */
+ "NT_STATUS_INVALID_PARAMETER_9", /* 0x00f7 */
+ "NT_STATUS_INVALID_PARAMETER_10", /* 0x00f8 */
+ "NT_STATUS_INVALID_PARAMETER_11", /* 0x00f9 */
+ "NT_STATUS_INVALID_PARAMETER_12", /* 0x00fa */
+ "NT_STATUS_REDIRECTOR_NOT_STARTED", /* 0x00fb */
+ "NT_STATUS_REDIRECTOR_STARTED", /* 0x00fc */
+ "NT_STATUS_STACK_OVERFLOW", /* 0x00fd */
+ "NT_STATUS_NO_SUCH_PACKAGE", /* 0x00fe */
+ "NT_STATUS_BAD_FUNCTION_TABLE", /* 0x00ff */
+ "NT_STATUS_DIRECTORY_NOT_EMPTY", /* 0x0101 */
+ "NT_STATUS_FILE_CORRUPT_ERROR", /* 0x0102 */
+ "NT_STATUS_NOT_A_DIRECTORY", /* 0x0103 */
+ "NT_STATUS_BAD_LOGON_SESSION_STATE", /* 0x0104 */
+ "NT_STATUS_LOGON_SESSION_COLLISION", /* 0x0105 */
+ "NT_STATUS_NAME_TOO_LONG", /* 0x0106 */
+ "NT_STATUS_FILES_OPEN", /* 0x0107 */
+ "NT_STATUS_CONNECTION_IN_USE", /* 0x0108 */
+ "NT_STATUS_MESSAGE_NOT_FOUND", /* 0x0109 */
+ "NT_STATUS_PROCESS_IS_TERMINATING", /* 0x010a */
+ "NT_STATUS_INVALID_LOGON_TYPE", /* 0x010b */
+ "NT_STATUS_NO_GUID_TRANSLATION", /* 0x010c */
+ "NT_STATUS_CANNOT_IMPERSONATE", /* 0x010d */
+ "NT_STATUS_IMAGE_ALREADY_LOADED", /* 0x010e */
+ "NT_STATUS_ABIOS_NOT_PRESENT", /* 0x010f */
+ "NT_STATUS_ABIOS_LID_NOT_EXIST", /* 0x0110 */
+ "NT_STATUS_ABIOS_LID_ALREADY_OWNED", /* 0x0111 */
+ "NT_STATUS_ABIOS_NOT_LID_OWNER", /* 0x0112 */
+ "NT_STATUS_ABIOS_INVALID_COMMAND", /* 0x0113 */
+ "NT_STATUS_ABIOS_INVALID_LID", /* 0x0114 */
+ "NT_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE", /* 0x0115 */
+ "NT_STATUS_ABIOS_INVALID_SELECTOR", /* 0x0116 */
+ "NT_STATUS_NO_LDT", /* 0x0117 */
+ "NT_STATUS_INVALID_LDT_SIZE", /* 0x0118 */
+ "NT_STATUS_INVALID_LDT_OFFSET", /* 0x0119 */
+ "NT_STATUS_INVALID_LDT_DESCRIPTOR", /* 0x011a */
+ "NT_STATUS_INVALID_IMAGE_NE_FORMAT", /* 0x011b */
+ "NT_STATUS_RXACT_INVALID_STATE", /* 0x011c */
+ "NT_STATUS_RXACT_COMMIT_FAILURE", /* 0x011d */
+ "NT_STATUS_MAPPED_FILE_SIZE_ZERO", /* 0x011e */
+ "NT_STATUS_TOO_MANY_OPENED_FILES", /* 0x011f */
+ "NT_STATUS_CANCELLED", /* 0x0120 */
+ "NT_STATUS_CANNOT_DELETE", /* 0x0121 */
+ "NT_STATUS_INVALID_COMPUTER_NAME", /* 0x0122 */
+ "NT_STATUS_FILE_DELETED", /* 0x0123 */
+ "NT_STATUS_SPECIAL_ACCOUNT", /* 0x0124 */
+ "NT_STATUS_SPECIAL_GROUP", /* 0x0125 */
+ "NT_STATUS_SPECIAL_USER", /* 0x0126 */
+ "NT_STATUS_MEMBERS_PRIMARY_GROUP", /* 0x0127 */
+ "NT_STATUS_FILE_CLOSED", /* 0x0128 */
+ "NT_STATUS_TOO_MANY_THREADS", /* 0x0129 */
+ "NT_STATUS_THREAD_NOT_IN_PROCESS", /* 0x012a */
+ "NT_STATUS_TOKEN_ALREADY_IN_USE", /* 0x012b */
+ "NT_STATUS_PAGEFILE_QUOTA_EXCEEDED", /* 0x012c */
+ "NT_STATUS_COMMITMENT_LIMIT", /* 0x012d */
+ "NT_STATUS_INVALID_IMAGE_LE_FORMAT", /* 0x012e */
+ "NT_STATUS_INVALID_IMAGE_NOT_MZ", /* 0x012f */
+ "NT_STATUS_INVALID_IMAGE_PROTECT", /* 0x0130 */
+ "NT_STATUS_INVALID_IMAGE_WIN_16", /* 0x0131 */
+ "NT_STATUS_LOGON_SERVER_CONFLICT", /* 0x0132 */
+ "NT_STATUS_TIME_DIFFERENCE_AT_DC", /* 0x0133 */
+ "NT_STATUS_SYNCHRONIZATION_REQUIRED", /* 0x0134 */
+ "NT_STATUS_DLL_NOT_FOUND", /* 0x0135 */
+ "NT_STATUS_OPEN_FAILED", /* 0x0136 */
+ "NT_STATUS_IO_PRIVILEGE_FAILED", /* 0x0137 */
+ "NT_STATUS_ORDINAL_NOT_FOUND", /* 0x0138 */
+ "NT_STATUS_ENTRYPOINT_NOT_FOUND", /* 0x0139 */
+ "NT_STATUS_CONTROL_C_EXIT", /* 0x013a */
+ "NT_STATUS_LOCAL_DISCONNECT", /* 0x013b */
+ "NT_STATUS_REMOTE_DISCONNECT", /* 0x013c */
+ "NT_STATUS_REMOTE_RESOURCES", /* 0x013d */
+ "NT_STATUS_LINK_FAILED", /* 0x013e */
+ "NT_STATUS_LINK_TIMEOUT", /* 0x013f */
+ "NT_STATUS_INVALID_CONNECTION", /* 0x0140 */
+ "NT_STATUS_INVALID_ADDRESS", /* 0x0141 */
+ "NT_STATUS_DLL_INIT_FAILED", /* 0x0142 */
+ "NT_STATUS_MISSING_SYSTEMFILE", /* 0x0143 */
+ "NT_STATUS_UNHANDLED_EXCEPTION", /* 0x0144 */
+ "NT_STATUS_APP_INIT_FAILURE", /* 0x0145 */
+ "NT_STATUS_PAGEFILE_CREATE_FAILED", /* 0x0146 */
+ "NT_STATUS_NO_PAGEFILE", /* 0x0147 */
+ "NT_STATUS_INVALID_LEVEL", /* 0x0148 */
+ "NT_STATUS_WRONG_PASSWORD_CORE", /* 0x0149 */
+ "NT_STATUS_ILLEGAL_FLOAT_CONTEXT", /* 0x014a */
+ "NT_STATUS_PIPE_BROKEN", /* 0x014b */
+ "NT_STATUS_REGISTRY_CORRUPT", /* 0x014c */
+ "NT_STATUS_REGISTRY_IO_FAILED", /* 0x014d */
+ "NT_STATUS_NO_EVENT_PAIR", /* 0x014e */
+ "NT_STATUS_UNRECOGNIZED_VOLUME", /* 0x014f */
+ "NT_STATUS_SERIAL_NO_DEVICE_INITED", /* 0x0150 */
+ "NT_STATUS_NO_SUCH_ALIAS", /* 0x0151 */
+ "NT_STATUS_MEMBER_NOT_IN_ALIAS", /* 0x0152 */
+ "NT_STATUS_MEMBER_IN_ALIAS", /* 0x0153 */
+ "NT_STATUS_ALIAS_EXISTS", /* 0x0154 */
+ "NT_STATUS_LOGON_NOT_GRANTED", /* 0x0155 */
+ "NT_STATUS_TOO_MANY_SECRETS", /* 0x0156 */
+ "NT_STATUS_SECRET_TOO_LONG", /* 0x0157 */
+ "NT_STATUS_INTERNAL_DB_ERROR", /* 0x0158 */
+ "NT_STATUS_FULLSCREEN_MODE", /* 0x0159 */
+ "NT_STATUS_TOO_MANY_CONTEXT_IDS", /* 0x015a */
+ "NT_STATUS_LOGON_TYPE_NOT_GRANTED", /* 0x015b */
+ "NT_STATUS_NOT_REGISTRY_FILE", /* 0x015c */
+ "NT_STATUS_NT_CROSS_ENCRYPTION_REQUIRED", /* 0x015d */
+ "NT_STATUS_DOMAIN_CTRLR_CONFIG_ERROR", /* 0x015e */
+ "NT_STATUS_FT_MISSING_MEMBER", /* 0x015f */
+ "NT_STATUS_ILL_FORMED_SERVICE_ENTRY", /* 0x0160 */
+ "NT_STATUS_ILLEGAL_CHARACTER", /* 0x0161 */
+ "NT_STATUS_UNMAPPABLE_CHARACTER", /* 0x0162 */
+ "NT_STATUS_UNDEFINED_CHARACTER", /* 0x0163 */
+ "NT_STATUS_FLOPPY_VOLUME", /* 0x0164 */
+ "NT_STATUS_FLOPPY_ID_MARK_NOT_FOUND", /* 0x0165 */
+ "NT_STATUS_FLOPPY_WRONG_CYLINDER", /* 0x0166 */
+ "NT_STATUS_FLOPPY_UNKNOWN_ERROR", /* 0x0167 */
+ "NT_STATUS_FLOPPY_BAD_REGISTERS", /* 0x0168 */
+ "NT_STATUS_DISK_RECALIBRATE_FAILED", /* 0x0169 */
+ "NT_STATUS_DISK_OPERATION_FAILED", /* 0x016a */
+ "NT_STATUS_DISK_RESET_FAILED", /* 0x016b */
+ "NT_STATUS_SHARED_IRQ_BUSY", /* 0x016c */
+ "NT_STATUS_FT_ORPHANING", /* 0x016d */
+ "NT_STATUS_PARTITION_FAILURE", /* 0x0172 */
+ "NT_STATUS_INVALID_BLOCK_LENGTH", /* 0x0173 */
+ "NT_STATUS_DEVICE_NOT_PARTITIONED", /* 0x0174 */
+ "NT_STATUS_UNABLE_TO_LOCK_MEDIA", /* 0x0175 */
+ "NT_STATUS_UNABLE_TO_UNLOAD_MEDIA", /* 0x0176 */
+ "NT_STATUS_EOM_OVERFLOW", /* 0x0177 */
+ "NT_STATUS_NO_MEDIA", /* 0x0178 */
+ "NT_STATUS_NO_SUCH_MEMBER", /* 0x017a */
+ "NT_STATUS_INVALID_MEMBER", /* 0x017b */
+ "NT_STATUS_KEY_DELETED", /* 0x017c */
+ "NT_STATUS_NO_LOG_SPACE", /* 0x017d */
+ "NT_STATUS_TOO_MANY_SIDS", /* 0x017e */
+ "NT_STATUS_LM_CROSS_ENCRYPTION_REQUIRED", /* 0x017f */
+ "NT_STATUS_KEY_HAS_CHILDREN", /* 0x0180 */
+ "NT_STATUS_CHILD_MUST_BE_VOLATILE", /* 0x0181 */
+ "NT_STATUS_DEVICE_CONFIGURATION_ERROR", /* 0x0182 */
+ "NT_STATUS_DRIVER_INTERNAL_ERROR", /* 0x0183 */
+ "NT_STATUS_INVALID_DEVICE_STATE", /* 0x0184 */
+ "NT_STATUS_IO_DEVICE_ERROR", /* 0x0185 */
+ "NT_STATUS_DEVICE_PROTOCOL_ERROR", /* 0x0186 */
+ "NT_STATUS_BACKUP_CONTROLLER", /* 0x0187 */
+ "NT_STATUS_LOG_FILE_FULL", /* 0x0188 */
+ "NT_STATUS_TOO_LATE", /* 0x0189 */
+ "NT_STATUS_NO_TRUST_LSA_SECRET", /* 0x018a */
+ "NT_STATUS_NO_TRUST_SAM_ACCOUNT", /* 0x018b */
+ "NT_STATUS_TRUSTED_DOMAIN_FAILURE", /* 0x018c */
+ "NT_STATUS_TRUSTED_RELATIONSHIP_FAILURE", /* 0x018d */
+ "NT_STATUS_EVENTLOG_FILE_CORRUPT", /* 0x018e */
+ "NT_STATUS_EVENTLOG_CANT_START", /* 0x018f */
+ "NT_STATUS_TRUST_FAILURE", /* 0x0190 */
+ "NT_STATUS_MUTANT_LIMIT_EXCEEDED", /* 0x0191 */
+ "NT_STATUS_NETLOGON_NOT_STARTED", /* 0x0192 */
+ "NT_STATUS_ACCOUNT_EXPIRED", /* 0x0193 */
+ "NT_STATUS_POSSIBLE_DEADLOCK", /* 0x0194 */
+ "NT_STATUS_NETWORK_CREDENTIAL_CONFLICT", /* 0x0195 */
+ "NT_STATUS_REMOTE_SESSION_LIMIT", /* 0x0196 */
+ "NT_STATUS_EVENTLOG_FILE_CHANGED", /* 0x0197 */
+ "NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT", /* 0x0198 */
+ "NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT", /* 0x0199 */
+ "NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT", /* 0x019a */
+ "NT_STATUS_DOMAIN_TRUST_INCONSISTENT", /* 0x019b */
+ "NT_STATUS_FS_DRIVER_REQUIRED", /* 0x019c */
+ "NT_STATUS_NO_USER_SESSION_KEY", /* 0x0202 */
+ "NT_STATUS_USER_SESSION_DELETED", /* 0x0203 */
+ "NT_STATUS_RESOURCE_LANG_NOT_FOUND", /* 0x0204 */
+ "NT_STATUS_INSUFF_SERVER_RESOURCES", /* 0x0205 */
+ "NT_STATUS_INVALID_BUFFER_SIZE", /* 0x0206 */
+ "NT_STATUS_INVALID_ADDRESS_COMPONENT", /* 0x0207 */
+ "NT_STATUS_INVALID_ADDRESS_WILDCARD", /* 0x0208 */
+ "NT_STATUS_TOO_MANY_ADDRESSES", /* 0x0209 */
+ "NT_STATUS_ADDRESS_ALREADY_EXISTS", /* 0x020a */
+ "NT_STATUS_ADDRESS_CLOSED", /* 0x020b */
+ "NT_STATUS_CONNECTION_DISCONNECTED", /* 0x020c */
+ "NT_STATUS_CONNECTION_RESET", /* 0x020d */
+ "NT_STATUS_TOO_MANY_NODES", /* 0x020e */
+ "NT_STATUS_TRANSACTION_ABORTED", /* 0x020f */
+ "NT_STATUS_TRANSACTION_TIMED_OUT", /* 0x0210 */
+ "NT_STATUS_TRANSACTION_NO_RELEASE", /* 0x0211 */
+ "NT_STATUS_TRANSACTION_NO_MATCH", /* 0x0212 */
+ "NT_STATUS_TRANSACTION_RESPONDED", /* 0x0213 */
+ "NT_STATUS_TRANSACTION_INVALID_ID", /* 0x0214 */
+ "NT_STATUS_TRANSACTION_INVALID_TYPE", /* 0x0215 */
+ "NT_STATUS_NOT_SERVER_SESSION", /* 0x0216 */
+ "NT_STATUS_NOT_CLIENT_SESSION", /* 0x0217 */
+ "NT_STATUS_CANNOT_LOAD_REGISTRY_FILE", /* 0x0218 */
+ "NT_STATUS_DEBUG_ATTACH_FAILED", /* 0x0219 */
+ "NT_STATUS_SYSTEM_PROCESS_TERMINATED", /* 0x021a */
+ "NT_STATUS_DATA_NOT_ACCEPTED", /* 0x021b */
+ "NT_STATUS_NO_BROWSER_SERVERS_FOUND", /* 0x021c */
+ "NT_STATUS_VDM_HARD_ERROR", /* 0x021d */
+ "NT_STATUS_DRIVER_CANCEL_TIMEOUT", /* 0x021e */
+ "NT_STATUS_REPLY_MESSAGE_MISMATCH", /* 0x021f */
+ "NT_STATUS_MAPPED_ALIGNMENT", /* 0x0220 */
+ "NT_STATUS_IMAGE_CHECKSUM_MISMATCH", /* 0x0221 */
+ "NT_STATUS_LOST_WRITEBEHIND_DATA", /* 0x0222 */
+ "NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID", /* 0x0223 */
+ "NT_STATUS_PASSWORD_MUST_CHANGE", /* 0x0224 */
+ "NT_STATUS_NOT_FOUND", /* 0x0225 */
+ "NT_STATUS_NOT_TINY_STREAM", /* 0x0226 */
+ "NT_STATUS_RECOVERY_FAILURE", /* 0x0227 */
+ "NT_STATUS_STACK_OVERFLOW_READ", /* 0x0228 */
+ "NT_STATUS_FAIL_CHECK", /* 0x0229 */
+ "NT_STATUS_DUPLICATE_OBJECTID", /* 0x022a */
+ "NT_STATUS_OBJECTID_EXISTS", /* 0x022b */
+ "NT_STATUS_CONVERT_TO_LARGE", /* 0x022c */
+ "NT_STATUS_RETRY", /* 0x022d */
+ "NT_STATUS_FOUND_OUT_OF_SCOPE", /* 0x022e */
+ "NT_STATUS_ALLOCATE_BUCKET", /* 0x022f */
+ "NT_STATUS_PROPSET_NOT_FOUND", /* 0x0230 */
+ "NT_STATUS_MARSHALL_OVERFLOW", /* 0x0231 */
+ "NT_STATUS_INVALID_VARIANT", /* 0x0232 */
+ "NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND", /* 0x0233 */
+ "NT_STATUS_ACCOUNT_LOCKED_OUT", /* 0x0234 */
+ "NT_STATUS_HANDLE_NOT_CLOSABLE", /* 0x0235 */
+ "NT_STATUS_CONNECTION_REFUSED", /* 0x0236 */
+ "NT_STATUS_GRACEFUL_DISCONNECT", /* 0x0237 */
+ "NT_STATUS_ADDRESS_ALREADY_ASSOCIATED", /* 0x0238 */
+ "NT_STATUS_ADDRESS_NOT_ASSOCIATED", /* 0x0239 */
+ "NT_STATUS_CONNECTION_INVALID", /* 0x023a */
+ "NT_STATUS_CONNECTION_ACTIVE", /* 0x023b */
+ "NT_STATUS_NETWORK_UNREACHABLE", /* 0x023c */
+ "NT_STATUS_HOST_UNREACHABLE", /* 0x023d */
+ "NT_STATUS_PROTOCOL_UNREACHABLE", /* 0x023e */
+ "NT_STATUS_PORT_UNREACHABLE", /* 0x023f */
+ "NT_STATUS_REQUEST_ABORTED", /* 0x0240 */
+ "NT_STATUS_CONNECTION_ABORTED", /* 0x0241 */
+ "NT_STATUS_BAD_COMPRESSION_BUFFER", /* 0x0242 */
+ "NT_STATUS_USER_MAPPED_FILE", /* 0x0243 */
+ "NT_STATUS_AUDIT_FAILED", /* 0x0244 */
+ "NT_STATUS_TIMER_RESOLUTION_NOT_SET", /* 0x0245 */
+ "NT_STATUS_CONNECTION_COUNT_LIMIT", /* 0x0246 */
+ "NT_STATUS_LOGIN_TIME_RESTRICTION", /* 0x0247 */
+ "NT_STATUS_LOGIN_WKSTA_RESTRICTION", /* 0x0248 */
+ "NT_STATUS_IMAGE_MP_UP_MISMATCH", /* 0x0249 */
+ "NT_STATUS_INSUFFICIENT_LOGON_INFO", /* 0x0250 */
+ "NT_STATUS_BAD_DLL_ENTRYPOINT", /* 0x0251 */
+ "NT_STATUS_BAD_SERVICE_ENTRYPOINT", /* 0x0252 */
+ "NT_STATUS_LPC_REPLY_LOST", /* 0x0253 */
+ "NT_STATUS_IP_ADDRESS_CONFLICT1", /* 0x0254 */
+ "NT_STATUS_IP_ADDRESS_CONFLICT2", /* 0x0255 */
+ "NT_STATUS_REGISTRY_QUOTA_LIMIT", /* 0x0256 */
+ "NT_STATUS_PATH_NOT_COVERED", /* 0x0257 */
+ "NT_STATUS_NO_CALLBACK_ACTIVE", /* 0x0258 */
+ "NT_STATUS_LICENSE_QUOTA_EXCEEDED", /* 0x0259 */
+ "NT_STATUS_PWD_TOO_SHORT", /* 0x025a */
+ "NT_STATUS_PWD_TOO_RECENT", /* 0x025b */
+ "NT_STATUS_PWD_HISTORY_CONFLICT", /* 0x025c */
+ "NT_STATUS_PLUGPLAY_NO_DEVICE", /* 0x025e */
+ "NT_STATUS_UNSUPPORTED_COMPRESSION", /* 0x025f */
+ "NT_STATUS_INVALID_HW_PROFILE", /* 0x0260 */
+ "NT_STATUS_INVALID_PLUGPLAY_DEVICE_PATH", /* 0x0261 */
+ "NT_STATUS_DRIVER_ORDINAL_NOT_FOUND", /* 0x0262 */
+ "NT_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND", /* 0x0263 */
+ "NT_STATUS_RESOURCE_NOT_OWNED", /* 0x0264 */
+ "NT_STATUS_TOO_MANY_LINKS", /* 0x0265 */
+ "NT_STATUS_QUOTA_LIST_INCONSISTENT", /* 0x0266 */
+ "NT_STATUS_FILE_IS_OFFLINE" /* 0x0267 */
+};
+
+#define NT_STATUS(a) nt_status_to_string[a & 0x3FFFFFFF]
+
+struct Packet
+{
+ size_t frame;
+
+ uint8_t magic[4];
+
+ bool valid_smb() {
+ return !memcmp(smb_hdr.magic, magic, 4);
+ }
+
+ Packet(const uint8_t *data, size_t size) :
+ ip_hdr(data + 14, size - 14),
+ tcp_hdr(data + 14 + ip_hdr.header_length,
+ size - 14 - ip_hdr.header_length),
+ smb_hdr(data + 14 + ip_hdr.header_length + tcp_hdr.length,
+ size - 14 - ip_hdr.header_length - tcp_hdr.length)
+ {
+ const uint8_t da[] = { 0xFF, 'S', 'M', 'B' };
+
+ memcpy(magic, da, sizeof(da));
+
+ if (valid_smb()) {
+ size_t len = 14 + ip_hdr.header_length + tcp_hdr.length + 36;
+
+ switch (smb_hdr.command) {
+ case NtCreateAndXRequest::COMMAND:
+ if (smb_hdr.flags & 0x80) {
+ ntcreate_resp = NtCreateAndXResponse(data+len, size - len);
+ } else {
+ ntcreate_req = NtCreateAndXRequest(data + len, size - len);
+ }
+ break;
+ case ReadAndXRequest::COMMAND:
+ if (!(smb_hdr.flags & 0x80)) {
+ read_req = ReadAndXRequest(data + len, size - len);
+ }
+ break;
+ case WriteAndXRequest::COMMAND:
+ if (!(smb_hdr.flags & 0x80)) {
+ write_req = WriteAndXRequest(data + len, size - len);
+ }
+ break;
+ case CloseRequest::COMMAND:
+ if (!(smb_hdr.flags & 0x80)) {
+ close_req = CloseRequest(data + len, size - len);
+ }
+ break;
+ }
+ }
+ }
+
+ ip ip_hdr;
+ tcp tcp_hdr;
+ smb smb_hdr;
+
+ NtCreateAndXRequest ntcreate_req;
+ NtCreateAndXResponse ntcreate_resp;
+ ReadAndXRequest read_req;
+ WriteAndXRequest write_req;
+ CloseRequest close_req;
+};
+
+int main(int argc, char **argv)
+{
+ char errbuf[PCAP_ERRBUF_SIZE];
+ pcap_t *cap;
+ struct pcap_pkthdr *pkt_hdr;
+ const uint8_t *data;
+
+ static struct option long_opts[] = {
+ { "show-files", 0, 0, 's' },
+ { "drop-incomplete-sessions", 0, 0, 'i' },
+ { 0, 0, 0, 0 }
+ };
+ const char *short_opts = "si";
+ int opt_ind;
+ char ch;
+ int show_files = 0;
+ int drop_incomplete_sessions = 0;
+
+ while ((ch = getopt_long(argc,argv,short_opts,long_opts,&opt_ind)) != -1) {
+ switch (ch) {
+ case 's':
+ show_files = 1;
+ break;
+ case 'i':
+ drop_incomplete_sessions = 1;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if ((argc - optind) != 1) {
+ std::cout << "Usage: " << argv[0] << " [OPTIONS] FILE" << std::endl;
+ exit(1);
+ }
+
+ cap = pcap_open_offline(argv[optind], errbuf);
+
+ if (!cap) {
+ std::cout << "pcap_open_offline(" << argv[optind] << "): " << errbuf
+ << std::endl;
+ exit(1);
+ }
+
+ std::vector<Packet> packets;
+ size_t frame = 0;
+ std::set<uint16_t> current_fids;
+
+ while (1 == pcap_next_ex(cap, &pkt_hdr, &data)) {
+ Packet packet(data, pkt_hdr->len);
+
+ ++frame;
+
+ if (packet.valid_smb()) {
+ packet.frame = frame;
+ packets.push_back(packet);
+ }
+ }
+
+ pcap_close(cap);
+
+ for (std::vector<Packet>::iterator i = packets.begin();
+ i != packets.end(); ++i) {
+ if (!(i->smb_hdr.flags & 0x80)) {
+ /* we have a request */
+ std::vector<Packet>::iterator j;
+
+ /* look ahead for the response */
+ for (j = i; j != packets.end(); ++j) {
+ if (j->smb_hdr.flags & 0x80 && // response
+ j->smb_hdr.command == i->smb_hdr.command &&
+ j->smb_hdr.tid == i->smb_hdr.tid &&
+ j->smb_hdr.pid == i->smb_hdr.pid &&
+ j->smb_hdr.uid == i->smb_hdr.uid &&
+ j->smb_hdr.mid == i->smb_hdr.mid) {
+ break;
+ }
+ }
+
+ /* no response? guess we can't display this command */
+ if (j == packets.end()) continue;
+
+ size_t len;
+
+ switch (i->smb_hdr.command) {
+ case NtCreateAndXRequest::COMMAND:
+ std::cout << "NTCreateX \"" << i->ntcreate_req.file_name << "\" "
+ << i->ntcreate_req.create_options << " "
+ << i->ntcreate_req.disposition << " "
+ << j->ntcreate_resp.fid << " "
+ << NT_STATUS(j->smb_hdr.nt_status) << std::endl;
+ current_fids.insert(j->ntcreate_resp.fid);
+ break;
+ case ReadAndXRequest::COMMAND:
+ len = i->read_req.max_count_high * 64 * 1024 +
+ i->read_req.max_count_low;
+
+ if (!drop_incomplete_sessions || current_fids.count(i->read_req.fid)) {
+ std::cout << "ReadX " << i->read_req.fid << " "
+ << i->read_req.offset << " "
+ << len << " " << len << " "
+ << NT_STATUS(j->smb_hdr.nt_status) << std::endl;
+ }
+ break;
+ case WriteAndXRequest::COMMAND:
+ len = i->write_req.data_length_hi * 64 * 1024 +
+ i->write_req.data_length_lo;
+
+ if (!drop_incomplete_sessions||current_fids.count(i->write_req.fid)) {
+ std::cout << "WriteX " << i->write_req.fid << " "
+ << i->write_req.offset << " "
+ << len << " " << len << " "
+ << NT_STATUS(j->smb_hdr.nt_status) << std::endl;
+ }
+ break;
+ case CloseRequest::COMMAND:
+ if (!drop_incomplete_sessions||current_fids.count(i->close_req.fid)) {
+ std::cout << "Close " << i->close_req.fid << " "
+ << NT_STATUS(j->smb_hdr.nt_status) << std::endl;
+ }
+ current_fids.erase(i->close_req.fid);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/examples/pcap2nbench/ntcreateandxrequest.cpp b/examples/pcap2nbench/ntcreateandxrequest.cpp
new file mode 100644
index 0000000..5efc256
--- /dev/null
+++ b/examples/pcap2nbench/ntcreateandxrequest.cpp
@@ -0,0 +1,73 @@
+/*\
+ * pcap2nbench - Converts libpcap network traces to nbench input
+ * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Anthony Liguori <aliguori@us.ibm.com>
+\*/
+
+#include <netinet/in.h>
+
+#include "ntcreateandxrequest.hpp"
+
+NtCreateAndXRequest::NtCreateAndXRequest(const uint8_t *data, size_t size)
+{
+ if (size < 52) {
+ std::cerr << "Invalid NtCreateAndX Request" << std::endl;
+ return;
+ }
+
+ word_count = data[0];
+ and_x_command = data[1];
+ reserved = data[2];
+ memcpy(&and_x_offset, data + 3, 2);
+ reserved1 = data[5];
+ memcpy(&file_name_len, data + 6, 2);
+ memcpy(&create_flags, data + 8, 4);
+ memcpy(&root_fid, data + 12, 4);
+ memcpy(&access_mask, data + 16, 4);
+ memcpy(&allocation_size, data + 20, 8);
+ memcpy(&file_attributes, data + 28, 4);
+ memcpy(&share_access, data + 32, 4);
+ memcpy(&disposition, data + 36, 4);
+ memcpy(&create_options, data + 40, 4);
+ memcpy(&impersonation, data + 44, 4);
+ security_flags = data[48];
+ memcpy(&byte_count, data + 49, 2);
+ file_name = (const char *)(data + 51);
+}
+
+std::ostream &operator<<(std::ostream &lhs, const NtCreateAndXRequest &rhs)
+{
+ lhs << "Word Count: " << (uint16_t)rhs.word_count << std::endl
+ << "AndXCommand: " << (uint16_t)rhs.and_x_command << std::endl
+ << "Reserved: " << (uint16_t)rhs.reserved << std::endl
+ << "AndXOffset: " << rhs.and_x_offset << std::endl
+ << "Reserved: " << (uint16_t)rhs.reserved1 << std::endl
+ << "File Name Len: " << rhs.file_name_len << std::endl
+ << "Create Flags: " << rhs.create_flags << std::endl
+ << "Root FID: " << rhs.root_fid << std::endl
+ << "Access Mask: " << rhs.access_mask << std::endl
+ << "Allocation Size: " << rhs.allocation_size << std::endl
+ << "File Attributes: " << rhs.file_attributes << std::endl
+ << "Share Access: " << rhs.share_access << std::endl
+ << "Disposition: " << rhs.disposition << std::endl
+ << "Create Options: " << rhs.create_options << std::endl
+ << "Impersonation: " << rhs.impersonation << std::endl
+ << "Security Flags: " << (uint16_t)rhs.security_flags << std::endl
+ << "Byte Count: " << rhs.byte_count << std::endl
+ << "File Name: " << rhs.file_name << std::endl;
+ return lhs;
+}
diff --git a/examples/pcap2nbench/ntcreateandxrequest.hpp b/examples/pcap2nbench/ntcreateandxrequest.hpp
new file mode 100644
index 0000000..07c19fd
--- /dev/null
+++ b/examples/pcap2nbench/ntcreateandxrequest.hpp
@@ -0,0 +1,57 @@
+/*\
+ * pcap2nbench - Converts libpcap network traces to nbench input
+ * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Anthony Liguori <aliguori@us.ibm.com>
+\*/
+
+#ifndef _NT_CREATE_AND_X_REQUEST_HPP
+#define _NT_CREATE_AND_X_REQUEST_HPP
+
+#include <iostream>
+#include <stdint.h>
+
+struct NtCreateAndXRequest {
+ enum {
+ COMMAND = 0xa2
+ };
+
+ NtCreateAndXRequest() { }
+ NtCreateAndXRequest(const uint8_t *data, size_t size);
+
+ uint8_t word_count;
+ uint8_t and_x_command;
+ uint8_t reserved;
+ uint16_t and_x_offset;
+ uint8_t reserved1;
+ uint16_t file_name_len;
+ uint32_t create_flags;
+ uint32_t root_fid;
+ uint32_t access_mask;
+ uint64_t allocation_size;
+ uint32_t file_attributes;
+ uint32_t share_access;
+ uint32_t disposition;
+ uint32_t create_options;
+ uint32_t impersonation;
+ uint8_t security_flags;
+ uint16_t byte_count;
+ std::string file_name;
+};
+
+std::ostream &operator<<(std::ostream &lhs, const NtCreateAndXRequest &rhs);
+
+#endif
diff --git a/examples/pcap2nbench/ntcreateandxresponse.cpp b/examples/pcap2nbench/ntcreateandxresponse.cpp
new file mode 100644
index 0000000..7e427b9
--- /dev/null
+++ b/examples/pcap2nbench/ntcreateandxresponse.cpp
@@ -0,0 +1,42 @@
+/*\
+ * pcap2nbench - Converts libpcap network traces to nbench input
+ * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Anthony Liguori <aliguori@us.ibm.com>
+\*/
+
+#include <netinet/in.h>
+
+#include "ntcreateandxresponse.hpp"
+
+NtCreateAndXResponse::NtCreateAndXResponse(const uint8_t *data, size_t size)
+{
+ if (size < 71) {
+ return;
+ }
+
+ word_count = data[0];
+ and_x_command = data[1];
+ reserved = data[2];
+ memcpy(&and_x_offset, data + 3, 2);
+ oplock_level = data[5];
+ memcpy(&fid, data + 6, 2);
+}
+
+std::ostream &operator<<(std::ostream &lhs, const NtCreateAndXResponse &rhs)
+{
+ return lhs;
+}
diff --git a/examples/pcap2nbench/ntcreateandxresponse.hpp b/examples/pcap2nbench/ntcreateandxresponse.hpp
new file mode 100644
index 0000000..c17ff21
--- /dev/null
+++ b/examples/pcap2nbench/ntcreateandxresponse.hpp
@@ -0,0 +1,57 @@
+/*\
+ * pcap2nbench - Converts libpcap network traces to nbench input
+ * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Anthony Liguori <aliguori@us.ibm.com>
+\*/
+
+#ifndef _NT_CREATE_AND_X_RESPONSE_HPP
+#define _NT_CREATE_AND_X_RESPONSE_HPP
+
+#include <iostream>
+#include <stdint.h>
+
+struct NtCreateAndXResponse {
+ enum {
+ COMMAND = 0xa2
+ };
+
+ NtCreateAndXResponse() {}
+ NtCreateAndXResponse(const uint8_t *data, size_t size);
+
+ uint8_t word_count;
+ uint8_t and_x_command;
+ uint8_t reserved;
+ uint16_t and_x_offset;
+ uint8_t oplock_level;
+ uint16_t fid;
+ uint32_t create_action;
+ uint64_t create_date;
+ uint64_t access_date;
+ uint64_t write_date;
+ uint64_t change_date;
+ uint32_t file_attributes;
+ uint64_t allocation_size;
+ uint64_t end_of_file;
+ uint16_t file_type;
+ uint16_t ipc_state;
+ uint8_t is_directory;
+ uint16_t byte_count;
+};
+
+std::ostream &operator<<(std::ostream &lhs, const NtCreateAndXResponse &rhs);
+
+#endif
diff --git a/examples/pcap2nbench/readandxrequest.cpp b/examples/pcap2nbench/readandxrequest.cpp
new file mode 100644
index 0000000..87411fc
--- /dev/null
+++ b/examples/pcap2nbench/readandxrequest.cpp
@@ -0,0 +1,60 @@
+/*\
+ * pcap2nbench - Converts libpcap network traces to nbench input
+ * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Anthony Liguori <aliguori@us.ibm.com>
+\*/
+
+#include <netinet/in.h>
+
+#include "readandxrequest.hpp"
+
+ReadAndXRequest::ReadAndXRequest(const uint8_t *data, size_t size)
+{
+ if (size < 27) {
+ std::cerr << "Invalid ReadAndX Request" << std::endl;
+ return;
+ }
+ word_count = data[0];
+ and_x_command = data[1];
+ reserved = data[2];
+ memcpy(&and_x_offset, data + 3, 2);
+ memcpy(&fid, data + 5, 2);
+ memcpy(&offset, data + 7, 4);
+ memcpy(&max_count_low, data + 11, 2);
+ memcpy(&min_count, data + 13, 2);
+ memcpy(&max_count_high, data + 15, 4);
+ memcpy(&remaining, data + 19, 2);
+ memcpy(&high_offset, data + 21, 4);
+ memcpy(&byte_count, data + 25, 2);
+}
+
+std::ostream &operator<<(std::ostream &lhs, const ReadAndXRequest &rhs)
+{
+ lhs << "Word Count: " << (uint16_t)rhs.word_count << std::endl
+ << "AndXCommand: " << (uint16_t)rhs.and_x_command << std::endl
+ << "Reserved: " << (uint16_t)rhs.reserved << std::endl
+ << "AndX Offset: " << rhs.and_x_offset << std::endl
+ << "Fid: " << rhs.fid << std::endl
+ << "Offset: " << rhs.offset << std::endl
+ << "Max Count Low: " << rhs.max_count_low << std::endl
+ << "Min Count: " << rhs.min_count << std::endl
+ << "Max Count High: " << rhs.max_count_high << std::endl
+ << "Remaining: " << rhs.remaining << std::endl
+ << "High Offset: " << rhs.high_offset << std::endl
+ << "Byte Count: " << rhs.byte_count << std::endl;
+ return lhs;
+}
diff --git a/examples/pcap2nbench/readandxrequest.hpp b/examples/pcap2nbench/readandxrequest.hpp
new file mode 100644
index 0000000..21e0bca
--- /dev/null
+++ b/examples/pcap2nbench/readandxrequest.hpp
@@ -0,0 +1,51 @@
+/*\
+ * pcap2nbench - Converts libpcap network traces to nbench input
+ * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Anthony Liguori <aliguori@us.ibm.com>
+\*/
+
+#ifndef _READ_AND_X_REQUEST_HPP
+#define _READ_AND_X_REQUEST_HPP
+
+#include <iostream>
+#include <stdint.h>
+
+struct ReadAndXRequest {
+ enum {
+ COMMAND = 0x2e
+ };
+
+ ReadAndXRequest() {}
+ ReadAndXRequest(const uint8_t *data, size_t size);
+
+ uint8_t word_count;
+ uint8_t and_x_command;
+ uint8_t reserved;
+ uint16_t and_x_offset;
+ uint16_t fid;
+ uint32_t offset;
+ uint16_t max_count_low;
+ uint16_t min_count;
+ uint32_t max_count_high;
+ uint16_t remaining;
+ uint32_t high_offset;
+ uint16_t byte_count;
+};
+
+std::ostream &operator<<(std::ostream &lhs, const ReadAndXRequest &rhs);
+
+#endif
diff --git a/examples/pcap2nbench/readandxresponse.hpp b/examples/pcap2nbench/readandxresponse.hpp
new file mode 100644
index 0000000..8ecb3a3
--- /dev/null
+++ b/examples/pcap2nbench/readandxresponse.hpp
@@ -0,0 +1,47 @@
+/*\
+ * pcap2nbench - Converts libpcap network traces to nbench input
+ * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Anthony Liguori <aliguori@us.ibm.com>
+\*/
+
+#ifndef _READ_AND_X_RESPONSE_HPP
+#define _READ_AND_X_RESPONSE_HPP
+
+class ReadAndXResponse {
+ ReadAndXResponse(const uint8_t *data, size_t size);
+
+ uint8_t word_count;
+ uint8_t and_x_command;
+ uint8_t reserved;
+ uint16_t and_x_offset;
+ uint8_t oplock_level;
+ uint16_t fid;
+ uint32_t create_action;
+ uint64_t created_date;
+ uint64_t access_date;
+ uint64_t write_date;
+ uint64_t change_date;
+ uint32_t file_attributes;
+ uint64_t allocation_size;
+ uint64_t end_of_file;
+ uint16_t file_type;
+ uint16_t ipc_state;
+ uint8_t is_directory;
+ uint16_t byte_count;
+};
+
+#endif
diff --git a/examples/pcap2nbench/smb.cpp b/examples/pcap2nbench/smb.cpp
new file mode 100644
index 0000000..78f8aaf
--- /dev/null
+++ b/examples/pcap2nbench/smb.cpp
@@ -0,0 +1,71 @@
+/*\
+ * pcap2nbench - Converts libpcap network traces to nbench input
+ * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Anthony Liguori <aliguori@us.ibm.com>
+\*/
+
+#include <netinet/in.h>
+
+#include "smb.hpp"
+
+smb::smb(const uint8_t *data, size_t length)
+{
+ if (length < 36) {
+ memset(magic, 0, 4);
+ return;
+ }
+
+ /* This code assumes Little Endian... Don't say I didn't warn you */
+ memcpy(&size, data + 2, 2);
+ memcpy(magic, data + 4, 4);
+
+ command = data[8];
+
+ memcpy(&nt_status, data + 9, 4);
+
+ flags = data[13];
+
+ memcpy(&flags2, data + 14, 2);
+ memcpy(&pid_hi, data + 16, 2);
+ memcpy(signature, data + 18, 8);
+ memcpy(&reserved, data + 26, 2);
+ memcpy(&tid, data + 28, 2);
+ memcpy(&pid, data + 30, 2);
+ memcpy(&uid, data + 32, 2);
+ memcpy(&mid, data + 34, 2);
+}
+
+std::ostream &operator<<(std::ostream &lhs, const smb &rhs)
+{
+ lhs << "Magic: ";
+ for (int i = 1; i < 4; i++) {
+ lhs << rhs.magic[i];
+ }
+ lhs << std::endl;
+
+ lhs << "Command: " << (uint16_t)rhs.command << std::endl
+ << "NT Status: " << rhs.nt_status << std::endl
+ << "Flags: " << (uint16_t)rhs.flags << std::endl
+ << "Flags2: " << rhs.flags2 << std::endl
+ << "Pid Hi: " << rhs.pid_hi << std::endl
+ << "Tid: " << rhs.tid << std::endl
+ << "Pid: " << rhs.pid << std::endl
+ << "Uid: " << rhs.uid << std::endl
+ << "Mid: " << rhs.mid << std::endl;
+
+ return lhs;
+}
diff --git a/examples/pcap2nbench/smb.hpp b/examples/pcap2nbench/smb.hpp
new file mode 100644
index 0000000..79a7f8c
--- /dev/null
+++ b/examples/pcap2nbench/smb.hpp
@@ -0,0 +1,48 @@
+/*\
+ * pcap2nbench - Converts libpcap network traces to nbench input
+ * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Anthony Liguori <aliguori@us.ibm.com>
+\*/
+
+#ifndef _SMB_HPP
+#define _SMB_HPP
+
+#include <iostream>
+#include <stdint.h>
+
+struct smb {
+ smb(const uint8_t *data, size_t length);
+
+ uint16_t size;
+
+ uint8_t magic[4]; /* 0xff, 'S', 'M', 'B' */
+ uint8_t command;
+ uint32_t nt_status;
+ uint8_t flags;
+ uint16_t flags2;
+ uint16_t pid_hi;
+ uint8_t signature[8];
+ uint16_t reserved;
+ uint16_t tid;
+ uint16_t pid;
+ uint16_t uid;
+ uint16_t mid;
+};
+
+std::ostream &operator<<(std::ostream &lhs, const smb &rhs);
+
+#endif
diff --git a/examples/pcap2nbench/tcp.cpp b/examples/pcap2nbench/tcp.cpp
new file mode 100644
index 0000000..8b51060
--- /dev/null
+++ b/examples/pcap2nbench/tcp.cpp
@@ -0,0 +1,59 @@
+/*\
+ * pcap2nbench - Converts libpcap network traces to nbench input
+ * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Anthony Liguori <aliguori@us.ibm.com>
+\*/
+
+#include <netinet/in.h>
+
+#include "tcp.hpp"
+
+tcp::tcp(const uint8_t *data, size_t size)
+{
+ if (size < 18) {
+ std::cerr << "Invalid TCP header" << std::endl;
+ }
+
+ memcpy(&src_port, data, 2);
+ src_port = ntohs(src_port);
+ memcpy(&dst_port, data + 2, 2);
+ dst_port = ntohs(dst_port);
+ memcpy(&seq_number, data + 4, 4);
+ seq_number = ntohl(seq_number);
+ memcpy(&ack_number, data + 8, 4);
+ ack_number = ntohl(ack_number);
+ length = ((data[12] & 0xF0) >> 4) * 4;
+ flags = ((data[12] & 0x0F) << 8) | data[13];
+ memcpy(&window_size, data + 14, 2);
+ window_size = ntohs(window_size);
+ memcpy(&checksum, data + 16, 2);
+ checksum = ntohs(checksum);
+}
+
+std::ostream &operator<<(std::ostream &lhs, const tcp &rhs)
+{
+ lhs << "Source Port: " << rhs.src_port << std::endl
+ << "Destination Port: " << rhs.dst_port << std::endl
+ << "Sequence Number: " << rhs.seq_number << std::endl
+ << "Ack Number: " << rhs.ack_number << std::endl
+ << "Length: " << (uint16_t)(rhs.length) << std::endl
+ << "Flags: " << rhs.flags << std::endl
+ << "Window Size: " << rhs.window_size << std::endl
+ << "Checksum: " << rhs.checksum << std::endl;
+
+ return lhs;
+}
diff --git a/examples/pcap2nbench/tcp.hpp b/examples/pcap2nbench/tcp.hpp
new file mode 100644
index 0000000..5eb7aaa
--- /dev/null
+++ b/examples/pcap2nbench/tcp.hpp
@@ -0,0 +1,42 @@
+/*\
+ * pcap2nbench - Converts libpcap network traces to nbench input
+ * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Anthony Liguori <aliguori@us.ibm.com>
+\*/
+
+#ifndef _TCP_HPP
+#define _TCP_HPP
+
+#include <iostream>
+#include <stdint.h>
+
+struct tcp {
+ tcp(const uint8_t *data, size_t length);
+
+ uint16_t src_port;
+ uint16_t dst_port;
+ uint32_t seq_number;
+ uint32_t ack_number;
+ uint8_t length;
+ uint16_t flags;
+ uint16_t window_size;
+ uint16_t checksum;
+};
+
+std::ostream &operator<<(std::ostream &lhs, const tcp &rhs);
+
+#endif
diff --git a/examples/pcap2nbench/writeandxrequest.cpp b/examples/pcap2nbench/writeandxrequest.cpp
new file mode 100644
index 0000000..f56a031
--- /dev/null
+++ b/examples/pcap2nbench/writeandxrequest.cpp
@@ -0,0 +1,65 @@
+/*\
+ * pcap2nbench - Converts libpcap network traces to nbench input
+ * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Anthony Liguori <aliguori@us.ibm.com>
+\*/
+
+#include <netinet/in.h>
+
+#include "writeandxrequest.hpp"
+
+WriteAndXRequest::WriteAndXRequest(const uint8_t *data, size_t size)
+{
+ if (size < 31) {
+ std::cerr << "Invalid WriteAndX Request" << std::endl;
+ return;
+ }
+ word_count = data[0];
+ and_x_command = data[1];
+ reserved = data[2];
+ memcpy(&and_x_offset, data + 3, 2);
+ memcpy(&fid, data + 5, 2);
+ memcpy(&offset, data + 7, 4);
+ memcpy(&reserved1, data + 11, 4);
+ memcpy(&write_mode, data + 15, 2);
+ memcpy(&remaining, data + 17, 2);
+ memcpy(&data_length_hi, data + 19, 2);
+ memcpy(&data_length_lo, data + 21, 2);
+ memcpy(&data_offset, data + 23, 2);
+ memcpy(&high_offset, data + 25, 4);
+ memcpy(&byte_count, data + 29, 2);
+
+}
+
+std::ostream &operator<<(std::ostream &lhs, const WriteAndXRequest &rhs)
+{
+ lhs << "Word Count: " << (uint16_t)rhs.word_count << std::endl
+ << "AndXCommand: " << (uint16_t)rhs.and_x_command << std::endl
+ << "Reserved: " << (uint16_t)rhs.reserved << std::endl
+ << "AndX Offset: " << rhs.and_x_offset << std::endl
+ << "Fid: " << rhs.fid << std::endl
+ << "Offset: " << rhs.offset << std::endl
+ << "Reserved: " << rhs.reserved1 << std::endl
+ << "Write Mode: " << rhs.write_mode << std::endl
+ << "Remaining: " << rhs.remaining << std::endl
+ << "Data Length Hi: " << rhs.data_length_hi << std::endl
+ << "Data Length Lo: " << rhs.data_length_lo << std::endl
+ << "Data Offset: " << rhs.data_offset << std::endl
+ << "High Offset: " << rhs.high_offset << std::endl
+ << "Byte Count: " << rhs.byte_count << std::endl;
+ return lhs;
+}
diff --git a/examples/pcap2nbench/writeandxrequest.hpp b/examples/pcap2nbench/writeandxrequest.hpp
new file mode 100644
index 0000000..c91bcc3
--- /dev/null
+++ b/examples/pcap2nbench/writeandxrequest.hpp
@@ -0,0 +1,53 @@
+/*\
+ * pcap2nbench - Converts libpcap network traces to nbench input
+ * Copyright (C) 2004 Jim McDonough <jmcd@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Written by Anthony Liguori <aliguori@us.ibm.com>
+\*/
+
+#ifndef _WRITE_AND_X_REQUEST_HPP
+#define _WRITE_AND_X_REQUEST_HPP
+
+#include <iostream>
+#include <stdint.h>
+
+struct WriteAndXRequest {
+ enum {
+ COMMAND = 0x2f
+ };
+
+ WriteAndXRequest() {}
+ WriteAndXRequest(const uint8_t *data, size_t size);
+
+ uint8_t word_count;
+ uint8_t and_x_command;
+ uint8_t reserved;
+ uint16_t and_x_offset;
+ uint16_t fid;
+ uint32_t offset;
+ uint32_t reserved1;
+ uint16_t write_mode;
+ uint16_t remaining;
+ uint16_t data_length_hi;
+ uint16_t data_length_lo;
+ uint16_t data_offset;
+ uint32_t high_offset;
+ uint16_t byte_count;
+};
+
+std::ostream &operator<<(std::ostream &lhs, const WriteAndXRequest &rhs);
+
+#endif
diff --git a/examples/pdb/Makefile b/examples/pdb/Makefile
new file mode 100644
index 0000000..09d901d
--- /dev/null
+++ b/examples/pdb/Makefile
@@ -0,0 +1,31 @@
+# Makefile for samba-pdb examples
+# Variables
+
+CC = gcc
+LIBTOOL = libtool
+
+SAMBA_SRC = ../../source
+SAMBA_INCL = ../../source/include
+UBIQX_SRC = ../../source/ubiqx
+SMBWR_SRC = ../../source/smbwrapper
+CFLAGS = -I$(SAMBA_SRC) -I$(SAMBA_INCL) -I$(UBIQX_SRC) -I$(SMBWR_SRC) -Wall -g -I/usr/include/heimdal -fPIC
+PDB_OBJS = test.la
+
+# Default target
+
+default: $(PDB_OBJS)
+
+# Pattern rules
+
+%.la: %.lo
+ $(LIBTOOL) --mode=link $(CC) -module -o $@ $< $(LDFLAGS) -rpath /usr/lib/samba/pdb/
+
+%.lo: %.c
+ $(LIBTOOL) --mode=compile $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
+
+# Misc targets
+
+clean:
+ rm -rf .libs
+ rm -f core *~ *% *.bak \
+ $(PDB_OBJS) $(PDB_OBJS:.la=.o) $(PDB_OBJS:.la=.lo)
diff --git a/examples/pdb/README b/examples/pdb/README
new file mode 100644
index 0000000..692d322
--- /dev/null
+++ b/examples/pdb/README
@@ -0,0 +1,20 @@
+README for Samba Password Database (PDB) examples
+====================================================
+Jelmer Vernooij <jelmer@nl.linux.org>
+Stefan (metze) Metzmacher <metze@samba.org>
+
+The test.c file in this directory contains a very basic example of
+a pdb plugin. It just prints the name of the function that is executed using
+DEBUG. Maybe it's nice to include some of the arguments to the function in the
+future too..
+
+To debug passdb backends, try to run gdb on the 'pdbedit' executable. That's
+really much easier than restarting smbd constantly and attaching with your
+debugger.
+
+New passdb plugins should go into the samba lib directory, (/usr/lib/samba/pdb/
+for most distributions). An example would be: /usr/lib/samba/pdb/test.so
+
+Be aware that the SQL and XML based passdb modules have been removed since the
+3.0.23 release. More information of external support for SQL passdb modules
+can be found at http://pdbsql.sourceforge.net/.
diff --git a/examples/pdb/test.c b/examples/pdb/test.c
new file mode 100644
index 0000000..a5e7dac
--- /dev/null
+++ b/examples/pdb/test.c
@@ -0,0 +1,115 @@
+/*
+ * Test password backend for samba
+ * Copyright (C) Jelmer Vernooij 2002
+ *
+ * This program is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "includes.h"
+#include "passdb.h"
+
+static int testsam_debug_level = DBGC_ALL;
+
+#undef DBGC_CLASS
+#define DBGC_CLASS testsam_debug_level
+
+/******************************************************************
+ Lookup a name in the SAM database
+******************************************************************/
+
+static NTSTATUS testsam_getsampwnam (struct pdb_methods *methods, struct samu *user, const char *sname)
+{
+ DEBUG(10, ("testsam_getsampwnam called\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/***************************************************************************
+ Search by sid
+ **************************************************************************/
+
+static NTSTATUS testsam_getsampwsid (struct pdb_methods *methods, struct samu *user, const struct dom_sid *sid)
+{
+ DEBUG(10, ("testsam_getsampwsid called\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/***************************************************************************
+ Delete a struct samu
+****************************************************************************/
+
+static NTSTATUS testsam_delete_sam_account(struct pdb_methods *methods, struct samu *sam_pass)
+{
+ DEBUG(10, ("testsam_delete_sam_account called\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/***************************************************************************
+ Modifies an existing struct samu
+****************************************************************************/
+
+static NTSTATUS testsam_update_sam_account (struct pdb_methods *methods, struct samu *newpwd)
+{
+ DEBUG(10, ("testsam_update_sam_account called\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+/***************************************************************************
+ Adds an existing struct samu
+****************************************************************************/
+
+static NTSTATUS testsam_add_sam_account (struct pdb_methods *methods, struct samu *newpwd)
+{
+ DEBUG(10, ("testsam_add_sam_account called\n"));
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS testsam_init(struct pdb_methods **pdb_method, const char *location)
+{
+ NTSTATUS nt_status;
+
+ if (!NT_STATUS_IS_OK(nt_status = make_pdb_method( pdb_method ))) {
+ return nt_status;
+ }
+
+ (*pdb_method)->name = "testsam";
+
+ /* Functions your pdb module doesn't provide should not be
+ set, make_pdb_methods() already provide suitable defaults for missing functions */
+
+ (*pdb_method)->getsampwnam = testsam_getsampwnam;
+ (*pdb_method)->getsampwsid = testsam_getsampwsid;
+ (*pdb_method)->add_sam_account = testsam_add_sam_account;
+ (*pdb_method)->update_sam_account = testsam_update_sam_account;
+ (*pdb_method)->delete_sam_account = testsam_delete_sam_account;
+
+ testsam_debug_level = debug_add_class("testsam");
+ if (testsam_debug_level == -1) {
+ testsam_debug_level = DBGC_ALL;
+ DEBUG(0, ("testsam: Couldn't register custom debugging class!\n"));
+ } else DEBUG(0, ("testsam: Debug class number of 'testsam': %d\n", testsam_debug_level));
+
+ DEBUG(0, ("Initializing testsam\n"));
+ if (location)
+ DEBUG(10, ("Location: %s\n", location));
+
+ return NT_STATUS_OK;
+}
+
+static_decl_pdb;
+NTSTATUS pdb_test_init(TALLOC_CTX *ctx)
+{
+ return smb_register_passdb(PASSDB_INTERFACE_VERSION, "testsam",
+ testsam_init);
+}
diff --git a/examples/pdb/wscript_build b/examples/pdb/wscript_build
new file mode 100644
index 0000000..11d00ba
--- /dev/null
+++ b/examples/pdb/wscript_build
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+
+bld.SAMBA3_MODULE('pdb_test',
+ subsystem='pdb',
+ source='test.c',
+ deps='samba-util',
+ init_function='',
+ internal_module=bld.SAMBA3_IS_STATIC_MODULE('pdb_test'),
+ enabled=bld.SAMBA3_IS_ENABLED_MODULE('pdb_test'))
+
diff --git a/examples/perfcounter/Makefile b/examples/perfcounter/Makefile
new file mode 100644
index 0000000..86e2190
--- /dev/null
+++ b/examples/perfcounter/Makefile
@@ -0,0 +1,38 @@
+#
+# Copyright (C) Marcin Krzysztof Porwit 2005
+#
+# 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 3 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, see <http://www.gnu.org/licenses/>.
+#
+
+SAMBA_SRC_DIR=../../source3
+TDB_SRC_DIR=$(SAMBA_SRC_DIR)/../lib/tdb
+
+CFLAGS = -g -I$(SAMBA_SRC_DIR) -I$(SAMBA_SRC_DIR)/include -I$(TDB_SRC_DIR)/include -I../../
+CC = gcc
+
+PROGS = perfcount
+TDB_OBJ = $(TDB_SRC_DIR)/common/tdb.o $(TDB_SRC_DIR)/common/dump.o \
+ $(TDB_SRC_DIR)/common/error.o $(TDB_SRC_DIR)/common/freelist.o \
+ $(TDB_SRC_DIR)/common/io.o $(TDB_SRC_DIR)/common/lock.o \
+ $(TDB_SRC_DIR)/common/open.o $(TDB_SRC_DIR)/common/transaction.o \
+ $(TDB_SRC_DIR)/common/traverse.o $(TDB_SRC_DIR)/common/hash.o
+PERF_WRITER_OBJ = perf_writer.o perf_writer_mem.o perf_writer_util.o perf_writer_cpu.o perf_writer_process.o perf_writer_disk.o
+
+default: $(PROGS)
+
+perfcount: $(PERF_WRITER_OBJ)
+ $(CC) $(CFLAGS) -o perfcount $(PERF_WRITER_OBJ) $(TDB_OBJ)
+
+clean:
+ rm -f $(PROGS) *.o *~ *% core
diff --git a/examples/perfcounter/perf.h b/examples/perfcounter/perf.h
new file mode 100644
index 0000000..03b5448
--- /dev/null
+++ b/examples/perfcounter/perf.h
@@ -0,0 +1,210 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Performance Counter Daemon
+ *
+ * Copyright (C) Marcin Krzysztof Porwit 2005
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __PERF_H__
+#define __PERF_H__
+
+#define _PUBLIC_
+
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#endif
+
+#if !defined(HAVE_BOOL)
+#ifdef HAVE__Bool
+#define bool _Bool
+#else
+#error Need a real boolean type
+#endif
+#endif
+
+
+#include <stdlib.h>
+#include <time.h>
+#include <math.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <limits.h>
+#include <tdb.h>
+#include "librpc/gen_ndr/perfcount.h"
+#include <sys/statfs.h>
+#include <sys/times.h>
+#include <sys/sysinfo.h>
+
+#define NUM_COUNTERS 10
+
+#define NAME_LEN 256
+#define HELP_LEN 1024
+
+#define PERF_OBJECT 0
+#define PERF_INSTANCE 1
+#define PERF_COUNTER 2
+
+#define FALSE 0
+#define TRUE !FALSE
+
+#define PROC_BUF 256
+#define LARGE_BUF 16384
+
+typedef struct perf_counter
+{
+ int index;
+ char name[NAME_LEN];
+ char help[HELP_LEN];
+ char relationships[NAME_LEN];
+ unsigned int counter_type;
+ int record_type;
+} PerfCounter;
+
+typedef struct mem_data
+{
+ unsigned int availPhysKb;
+ unsigned int availSwapKb;
+ unsigned int totalPhysKb;
+ unsigned int totalSwapKb;
+} MemData;
+
+typedef struct mem_info
+{
+ PerfCounter memObjDesc;
+ PerfCounter availPhysKb;
+ PerfCounter availSwapKb;
+ PerfCounter totalPhysKb;
+ PerfCounter totalSwapKb;
+ MemData *data;
+} MemInfo;
+
+typedef struct cpu_data
+{
+ unsigned long long user;
+ unsigned long long nice;
+ unsigned long long system;
+ unsigned long long idle;
+} CPUData;
+
+typedef struct cpu_info
+{
+ unsigned int numCPUs;
+ PerfCounter cpuObjDesc;
+ PerfCounter userCPU;
+ PerfCounter niceCPU;
+ PerfCounter systemCPU;
+ PerfCounter idleCPU;
+ CPUData *data;
+} CPUInfo;
+
+typedef struct disk_meta_data
+{
+ char name[NAME_LEN];
+ char mountpoint[NAME_LEN];
+} DiskMetaData;
+
+typedef struct disk_data
+{
+ unsigned long long freeMegs;
+ unsigned int writesPerSec;
+ unsigned int readsPerSec;
+} DiskData;
+
+typedef struct disk_info
+{
+ unsigned int numDisks;
+ DiskMetaData *mdata;
+ PerfCounter diskObjDesc;
+ PerfCounter freeMegs;
+ PerfCounter writesPerSec;
+ PerfCounter readsPerSec;
+ DiskData *data;
+} DiskInfo;
+
+typedef struct process_data
+{
+ unsigned int runningProcessCount;
+} ProcessData;
+
+typedef struct process_info
+{
+ PerfCounter processObjDesc;
+ PerfCounter runningProcessCount;
+ ProcessData *data;
+} ProcessInfo;
+
+typedef struct perf_data_block
+{
+ unsigned int counter_id;
+ unsigned int num_counters;
+ unsigned int NumObjectTypes;
+ unsigned long long PerfTime;
+ unsigned long long PerfFreq;
+ unsigned long long PerfTime100nSec;
+ MemInfo memInfo;
+ CPUInfo cpuInfo;
+ ProcessInfo processInfo;
+ DiskInfo diskInfo;
+} PERF_DATA_BLOCK;
+
+typedef struct runtime_settings
+{
+ /* Runtime flags */
+ int dflag;
+ /* DB path names */
+ char dbDir[PATH_MAX];
+ char nameFile[PATH_MAX];
+ char counterFile[PATH_MAX];
+ /* TDB context */
+ TDB_CONTEXT *cnames;
+ TDB_CONTEXT *cdata;
+} RuntimeSettings;
+
+/* perf_writer_ng_util.c function prototypes */
+void fatal(char *msg);
+void add_key(TDB_CONTEXT *db, char *keystring, char *datastring, int flags);
+void add_key_raw(TDB_CONTEXT *db, char *keystring, void *datastring, size_t datasize, int flags);
+void make_key(char *buf, int buflen, int key_part1, char *key_part2);
+void parse_flags(RuntimeSettings *rt, int argc, char **argv);
+void setup_file_paths(RuntimeSettings *rt);
+void daemonize(RuntimeSettings *rt);
+
+/* perf_writer_ng_mem.c function prototypes */
+void get_meminfo(PERF_DATA_BLOCK *data);
+void init_memdata_desc(PERF_DATA_BLOCK *data);
+void init_memdata(PERF_DATA_BLOCK *data);
+void output_mem_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt);
+void output_meminfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags);
+void init_perf_counter(PerfCounter *counter, PerfCounter *parent, unsigned int index, char *name, char *help, int counter_type, int record_type);
+
+/* perf_writer_ng_cpu.c function prototypes */
+unsigned long long get_cpufreq();
+void init_cpudata_desc(PERF_DATA_BLOCK *data);
+void get_cpuinfo(PERF_DATA_BLOCK *data);
+void init_cpu_data(PERF_DATA_BLOCK *data);
+void output_cpu_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt);
+void output_cpuinfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags);
+
+#endif /* __PERF_H__ */
diff --git a/examples/perfcounter/perf_writer.c b/examples/perfcounter/perf_writer.c
new file mode 100644
index 0000000..054d9e8
--- /dev/null
+++ b/examples/perfcounter/perf_writer.c
@@ -0,0 +1,213 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Performance Counter Daemon
+ *
+ * Copyright (C) Marcin Krzysztof Porwit 2005
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "perf.h"
+
+sig_atomic_t keep_running = TRUE;
+
+/* allocates memory and gets numCPUs, total memory, and PerfFreq, number of disks... */
+void get_constants(PERF_DATA_BLOCK *data)
+{
+ data->cpuInfo.numCPUs = sysconf(_SC_NPROCESSORS_ONLN) > 0 ? sysconf(_SC_NPROCESSORS_ONLN) : 1;
+ data->PerfFreq = sysconf(_SC_CLK_TCK);
+ init_mem_data(data);
+ init_cpu_data(data);
+ init_process_data(data);
+ init_disk_data(data);
+
+ return;
+}
+
+void output_num_instances(PerfCounter obj, int numInst, RuntimeSettings rt)
+{
+ char key[NAME_LEN];
+ char sdata[NAME_LEN];
+
+ make_key(key, NAME_LEN, obj.index, "inst");
+ memset(sdata, 0, NAME_LEN);
+ sprintf(sdata, "%d", numInst);
+ add_key(rt.cnames, key, sdata, TDB_INSERT);
+
+ return;
+}
+
+void output_perf_desc(PerfCounter counter, RuntimeSettings rt)
+{
+ char key[NAME_LEN];
+ char sdata[NAME_LEN];
+
+ /* First insert the counter name */
+ make_key(key, NAME_LEN, counter.index, NULL);
+ add_key(rt.cnames, key, counter.name, TDB_INSERT);
+ /* Add the help string */
+ make_key(key, NAME_LEN, counter.index + 1, NULL);
+ add_key(rt.cnames, key, counter.help, TDB_INSERT);
+ /* Add the relationships */
+ make_key(key, NAME_LEN, counter.index, "rel");
+ add_key(rt.cnames, key, counter.relationships, TDB_INSERT);
+ /* Add type data if not PERF_OBJECT or PERF_INSTANCE */
+ if(counter.record_type == PERF_COUNTER)
+ {
+ make_key(key, NAME_LEN, counter.index, "type");
+ memset(sdata, 0, NAME_LEN);
+ sprintf(sdata, "%d", counter.counter_type);
+ add_key(rt.cnames, key, sdata, TDB_INSERT);
+ }
+
+ return;
+}
+
+void initialize(PERF_DATA_BLOCK *data, RuntimeSettings *rt, int argc, char **argv)
+{
+ memset(data, 0, sizeof(*data));
+ memset(rt, 0, sizeof(*rt));
+
+ parse_flags(rt, argc, argv);
+ setup_file_paths(rt);
+
+ get_constants(data);
+
+ if(rt->dflag == TRUE)
+ daemonize(rt);
+
+ output_mem_desc(data, *rt);
+ output_cpu_desc(data, *rt);
+ output_process_desc(data, *rt);
+ output_disk_desc(data, *rt);
+
+ return;
+}
+
+void refresh_perf_data_block(PERF_DATA_BLOCK *data, RuntimeSettings rt)
+{
+ data->PerfTime100nSec = 0;
+ get_meminfo(data);
+ get_cpuinfo(data);
+ get_processinfo(data);
+ get_diskinfo(data);
+ return;
+}
+
+void output_perf_counter(PerfCounter counter, unsigned long long data,
+ RuntimeSettings rt, int tdb_flags)
+{
+ char key[NAME_LEN];
+ char sdata[NAME_LEN];
+ unsigned int size_mask;
+
+ make_key(key, NAME_LEN, counter.index, NULL);
+ memset(sdata, 0, NAME_LEN);
+
+ size_mask = counter.counter_type & PERF_SIZE_VARIABLE_LEN;
+
+ if(size_mask == PERF_SIZE_DWORD)
+ sprintf(sdata, "%d", (unsigned int)data);
+ else if(size_mask == PERF_SIZE_LARGE)
+ sprintf(sdata, "%Lu", data);
+
+ add_key(rt.cdata, key, sdata, tdb_flags);
+
+ return;
+}
+
+void output_perf_instance(int parentObjInd,
+ int instanceInd,
+ void *instData,
+ size_t dsize,
+ char *name,
+ RuntimeSettings rt,
+ int tdb_flags)
+{
+ char key[NAME_LEN];
+ char sdata[NAME_LEN];
+
+ memset(key, 0, NAME_LEN);
+ sprintf(key, "%di%d", parentObjInd, instanceInd);
+ add_key_raw(rt.cdata, key, instData, dsize, tdb_flags);
+
+ /* encode name */
+ memset(key, 0, NAME_LEN);
+ sprintf(key, "%di%dname", parentObjInd, instanceInd);
+ add_key(rt.cnames, key, name, tdb_flags);
+
+ return;
+}
+
+void output_global_data(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags)
+{
+ int i;
+ char key[NAME_LEN];
+ char sdata[NAME_LEN];
+
+ /* Initialize BaseIndex */
+ make_key(key, NAME_LEN, 1, NULL);
+ memset(sdata, 0, NAME_LEN);
+ sprintf(sdata, "%d", data->num_counters);
+ add_key(rt.cnames, key, sdata, tdb_flags);
+ /* Initialize PerfTime, PerfFreq and PerfTime100nSec */
+ memset(sdata, 0, NAME_LEN);
+ make_key(key, NAME_LEN, 0, "PerfTime");
+ sprintf(sdata, "%Lu", data->PerfTime);
+ add_key(rt.cdata, key, sdata, tdb_flags);
+ make_key(key, NAME_LEN, 0, "PerfTime100nSec");
+ memset(sdata, 0, NAME_LEN);
+ sprintf(sdata, "%Lu", data->PerfTime100nSec);
+ add_key(rt.cdata, key, sdata, tdb_flags);
+ memset(sdata, 0, NAME_LEN);
+ make_key(key, NAME_LEN, 0, "PerfFreq");
+ sprintf(sdata, "%Lu", data->PerfFreq);
+ add_key(rt.cnames, key, sdata, tdb_flags);
+
+ return;
+}
+
+void output_perf_data_block(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags)
+{
+ output_global_data(data, rt, tdb_flags);
+ output_meminfo(data, rt, tdb_flags);
+ output_cpuinfo(data, rt, tdb_flags);
+ output_processinfo(data, rt, tdb_flags);
+ output_diskinfo(data, rt, tdb_flags);
+ return;
+}
+
+void update_counters(PERF_DATA_BLOCK *data, RuntimeSettings rt)
+{
+ refresh_perf_data_block(data, rt);
+ output_perf_data_block(data, rt, TDB_REPLACE);
+
+ return;
+}
+
+int main(int argc, char **argv)
+{
+ PERF_DATA_BLOCK data;
+ RuntimeSettings rt;
+
+ initialize(&data, &rt, argc, argv);
+
+ while(keep_running)
+ {
+ update_counters(&data, rt);
+ sleep(1);
+ }
+
+ return 0;
+}
diff --git a/examples/perfcounter/perf_writer_cpu.c b/examples/perfcounter/perf_writer_cpu.c
new file mode 100644
index 0000000..215e073
--- /dev/null
+++ b/examples/perfcounter/perf_writer_cpu.c
@@ -0,0 +1,189 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Performance Counter Daemon
+ *
+ * Copyright (C) Marcin Krzysztof Porwit 2005
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "perf.h"
+
+void init_cpudata_desc(PERF_DATA_BLOCK *data)
+{
+ init_perf_counter(&(data->cpuInfo.cpuObjDesc),
+ &(data->cpuInfo.cpuObjDesc),
+ get_counter_id(data),
+ "Processor",
+ "The Processor object consists of counters that describe the behavior of the CPU.",
+ 0,
+ PERF_OBJECT);
+ init_perf_counter(&(data->cpuInfo.userCPU),
+ &(data->cpuInfo.cpuObjDesc),
+ get_counter_id(data),
+ "\% User CPU Utilization",
+ "\% User CPU Utilization is the percentage of the CPU used by processes executing user code.",
+ PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_PERCENT,
+ PERF_COUNTER);
+ init_perf_counter(&(data->cpuInfo.systemCPU),
+ &(data->cpuInfo.cpuObjDesc),
+ get_counter_id(data),
+ "\% System CPU Utilization",
+ "\% System CPU Utilization is the percentage of the CPU used by processes doing system calls.",
+ PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_PERCENT,
+ PERF_COUNTER);
+ init_perf_counter(&(data->cpuInfo.niceCPU),
+ &(data->cpuInfo.cpuObjDesc),
+ get_counter_id(data),
+ "\% Nice CPU Utilization",
+ "\% Nice CPU Utilization is the percentage of the CPU used by processes running in nice mode.",
+ PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_NOSHOW,
+ PERF_COUNTER);
+ init_perf_counter(&(data->cpuInfo.idleCPU),
+ &(data->cpuInfo.cpuObjDesc),
+ get_counter_id(data),
+ "\% Idle CPU",
+ "\% Idle CPU is the percentage of the CPU not doing any work.",
+ PERF_SIZE_LARGE | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_TIMER_100NS | PERF_DELTA_COUNTER | PERF_DISPLAY_NOSHOW,
+ PERF_COUNTER);
+
+ return;
+}
+
+void get_cpuinfo(PERF_DATA_BLOCK *data)
+{
+ int num, i;
+ unsigned int cpuid;
+ char buf[PROC_BUF];
+ static FILE *fp = NULL;
+
+ if(!fp)
+ {
+ if(!(fp = fopen("/proc/stat", "r")))
+ {
+ perror("get_cpuinfo: fopen");
+ exit(1);
+ }
+ }
+
+ rewind(fp);
+ fflush(fp);
+
+ /* Read in the first line and discard it -- that has the CPU summary */
+ if(!fgets(buf, sizeof(buf), fp))
+ {
+ perror("get_cpuinfo: fgets");
+ exit(1);
+ }
+ for(i = 0; i < data->cpuInfo.numCPUs; i++)
+ {
+ if(!fgets(buf, sizeof(buf), fp))
+ {
+ perror("get_cpuinfo: fgets");
+ exit(1);
+ }
+ num = sscanf(buf, "cpu%u %Lu %Lu %Lu %Lu",
+ &cpuid,
+ &data->cpuInfo.data[i].user,
+ &data->cpuInfo.data[i].nice,
+ &data->cpuInfo.data[i].system,
+ &data->cpuInfo.data[i].idle);
+ if(i != cpuid)
+ {
+ perror("get_cpuinfo: /proc/stat inconsistent?");
+ exit(1);
+ }
+ /*
+ Alternate way of doing things:
+ struct tms buffer;
+ data->PerfTime100nSec = times(&buffer);
+ */
+ data->PerfTime100nSec += data->cpuInfo.data[i].user +
+ data->cpuInfo.data[i].nice +
+ data->cpuInfo.data[i].system +
+ data->cpuInfo.data[i].idle;
+ }
+ data->PerfTime100nSec /= data->cpuInfo.numCPUs;
+ return;
+}
+
+void init_cpu_data(PERF_DATA_BLOCK *data)
+{
+ data->cpuInfo.data = calloc(data->cpuInfo.numCPUs, sizeof(*data->cpuInfo.data));
+ if(!data->cpuInfo.data)
+ {
+ perror("init_cpu_data: out of memory");
+ exit(1);
+ }
+
+ init_cpudata_desc(data);
+
+ get_cpuinfo(data);
+
+ return;
+}
+
+void output_cpu_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt)
+{
+ output_perf_desc(data->cpuInfo.cpuObjDesc, rt);
+ output_perf_desc(data->cpuInfo.userCPU, rt);
+ output_perf_desc(data->cpuInfo.niceCPU, rt);
+ output_perf_desc(data->cpuInfo.systemCPU, rt);
+ output_perf_desc(data->cpuInfo.idleCPU, rt);
+ if(data->cpuInfo.numCPUs > 1)
+ output_num_instances(data->cpuInfo.cpuObjDesc, data->cpuInfo.numCPUs + 1, rt);
+
+ return;
+}
+
+void output_cpuinfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags)
+{
+ int i;
+ char buf[NAME_LEN];
+
+ output_perf_counter(data->cpuInfo.userCPU,
+ data->cpuInfo.data[0].user,
+ rt, tdb_flags);
+ output_perf_counter(data->cpuInfo.systemCPU,
+ data->cpuInfo.data[0].system,
+ rt, tdb_flags);
+ output_perf_counter(data->cpuInfo.niceCPU,
+ data->cpuInfo.data[0].nice,
+ rt, tdb_flags);
+ output_perf_counter(data->cpuInfo.idleCPU,
+ data->cpuInfo.data[0].idle,
+ rt, tdb_flags);
+ if(data->cpuInfo.numCPUs > 1)
+ {
+ for(i = 0; i < data->cpuInfo.numCPUs; i++)
+ {
+ memset(buf, 0, NAME_LEN);
+ sprintf(buf, "cpu%d", i);
+ output_perf_instance(data->cpuInfo.cpuObjDesc.index,
+ i,
+ (void *)&(data->cpuInfo.data[i]),
+ sizeof(data->cpuInfo.data[i]),
+ buf, rt, tdb_flags);
+ }
+
+ memset(buf, 0, NAME_LEN);
+ sprintf(buf, "_Total");
+ output_perf_instance(data->cpuInfo.cpuObjDesc.index,
+ i,
+ (void *)&(data->cpuInfo.data[i]),
+ sizeof(data->cpuInfo.data[i]),
+ buf, rt, tdb_flags);
+ }
+ return;
+}
diff --git a/examples/perfcounter/perf_writer_disk.c b/examples/perfcounter/perf_writer_disk.c
new file mode 100644
index 0000000..18a63a4
--- /dev/null
+++ b/examples/perfcounter/perf_writer_disk.c
@@ -0,0 +1,224 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Performance Counter Daemon
+ *
+ * Copyright (C) Marcin Krzysztof Porwit 2005
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "perf.h"
+
+void init_diskdata_desc(PERF_DATA_BLOCK *data)
+{
+ init_perf_counter(&(data->diskInfo.diskObjDesc),
+ &(data->diskInfo.diskObjDesc),
+ get_counter_id(data),
+ "Logical Disk",
+ "The Logical Disk object consists of counters that show information about disks.",
+ 0,
+ PERF_OBJECT);
+ init_perf_counter(&(data->diskInfo.freeMegs),
+ &(data->diskInfo.diskObjDesc),
+ get_counter_id(data),
+ "Megabytes Free",
+ "The amount of available disk space, in megabytes.",
+ PERF_SIZE_LARGE | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX,
+ PERF_COUNTER);
+ init_perf_counter(&(data->diskInfo.writesPerSec),
+ &(data->diskInfo.diskObjDesc),
+ get_counter_id(data),
+ "Writes/sec",
+ "The number of writes per second to that disk.",
+ PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_DELTA_COUNTER | PERF_DISPLAY_PER_SEC,
+ PERF_COUNTER);
+ init_perf_counter(&(data->diskInfo.readsPerSec),
+ &(data->diskInfo.diskObjDesc),
+ get_counter_id(data),
+ "Reads/sec",
+ "The number of reads of that disk per second.",
+ PERF_SIZE_DWORD | PERF_TYPE_COUNTER | PERF_COUNTER_RATE | PERF_DELTA_COUNTER | PERF_DISPLAY_PER_SEC,
+ PERF_COUNTER);
+
+ return;
+}
+void init_num_disks(PERF_DATA_BLOCK *data)
+{
+ FILE *mtab;
+ char buf[PROC_BUF];
+ char *start, *stop;
+ int i = 0, num;
+
+ if(!(mtab = fopen("/etc/mtab", "r")))
+ {
+ perror("init_disk_names: fopen");
+ exit(1);
+ }
+
+ rewind(mtab);
+ fflush(mtab);
+
+ while(fgets(buf, sizeof(buf), mtab))
+ {
+ if(start = strstr(buf, "/dev/"))
+ {
+ if(start = strstr(start, "da"))
+ {
+ i++;
+ }
+ }
+ }
+
+ data->diskInfo.numDisks = i;
+ fclose(mtab);
+
+ return;
+}
+
+void init_disk_names(PERF_DATA_BLOCK *data)
+{
+ FILE *mtab;
+ char buf[PROC_BUF];
+ char *start, *stop;
+ int i = 0, num;
+
+ if(!(mtab = fopen("/etc/mtab", "r")))
+ {
+ perror("init_disk_names: fopen");
+ exit(1);
+ }
+
+ rewind(mtab);
+ fflush(mtab);
+
+ while(fgets(buf, sizeof(buf), mtab))
+ {
+ if(start = strstr(buf, "/dev/"))
+ {
+ if(start = strstr(start, "da"))
+ {
+ start -=1;
+ stop = strstr(start, " ");
+ memcpy(data->diskInfo.mdata[i].name, start, stop - start);
+ start = stop +1;
+ stop = strstr(start, " ");
+ memcpy(data->diskInfo.mdata[i].mountpoint, start, stop - start);
+ i++;
+ }
+ }
+ }
+
+ fclose(mtab);
+
+ return;
+}
+
+void get_diskinfo(PERF_DATA_BLOCK *data)
+{
+ int i;
+ DiskData *p;
+ struct statfs statfsbuf;
+ int status, num;
+ char buf[LARGE_BUF], *start;
+ FILE *diskstats;
+ unsigned long reads, writes, discard;
+
+ diskstats = fopen("/proc/diskstats", "r");
+ rewind(diskstats);
+ fflush(diskstats);
+ status = fread(buf, sizeof(char), LARGE_BUF, diskstats);
+ fclose(diskstats);
+
+ for(i = 0; i < data->diskInfo.numDisks; i++)
+ {
+ p = &(data->diskInfo.data[i]);
+ status = statfs(data->diskInfo.mdata[i].mountpoint, &statfsbuf);
+ p->freeMegs = (statfsbuf.f_bfree*statfsbuf.f_bsize)/1048576;
+ start = strstr(buf, data->diskInfo.mdata[i].name);
+ start += strlen(data->diskInfo.mdata[i].name) + 1;
+ num = sscanf(start, "%lu %lu %lu %lu",
+ &reads,
+ &discard,
+ &writes,
+ &discard);
+ p->writesPerSec = writes;
+ p->readsPerSec = reads;
+ fprintf(stderr, "%s:\t%u\t%u\n",
+ data->diskInfo.mdata[i].mountpoint,
+ reads, writes);
+ }
+ return;
+}
+void init_disk_data(PERF_DATA_BLOCK *data)
+{
+ init_diskdata_desc(data);
+
+ init_num_disks(data);
+
+ data->diskInfo.mdata = calloc(data->diskInfo.numDisks, sizeof(DiskMetaData));
+ if(!data->diskInfo.mdata)
+ {
+ fatal("init_disk_data: out of memory");
+ }
+
+ init_disk_names(data);
+
+ data->diskInfo.data = calloc(data->diskInfo.numDisks, sizeof(DiskData));
+ if(!data->diskInfo.data)
+ {
+ fatal("init_disk_data: out of memory");
+ }
+
+ get_diskinfo(data);
+
+ return;
+}
+
+void output_disk_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt)
+{
+ output_perf_desc(data->diskInfo.diskObjDesc, rt);
+ output_perf_desc(data->diskInfo.freeMegs, rt);
+ output_perf_desc(data->diskInfo.writesPerSec, rt);
+ output_perf_desc(data->diskInfo.readsPerSec, rt);
+ output_num_instances(data->diskInfo.diskObjDesc, data->diskInfo.numDisks, rt);
+
+ return;
+}
+
+void output_diskinfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags)
+{
+ int i;
+
+ output_perf_counter(data->diskInfo.freeMegs,
+ data->diskInfo.data[0].freeMegs,
+ rt, tdb_flags);
+ output_perf_counter(data->diskInfo.writesPerSec,
+ (unsigned long long)data->diskInfo.data[0].writesPerSec,
+ rt, tdb_flags);
+ output_perf_counter(data->diskInfo.readsPerSec,
+ (unsigned long long)data->diskInfo.data[0].readsPerSec,
+ rt, tdb_flags);
+
+ for(i = 0; i < data->diskInfo.numDisks; i++)
+ {
+ output_perf_instance(data->diskInfo.diskObjDesc.index,
+ i,
+ (void *)&(data->diskInfo.data[i]),
+ sizeof(DiskData),
+ data->diskInfo.mdata[i].mountpoint,
+ rt, tdb_flags);
+ }
+
+ return;
+}
diff --git a/examples/perfcounter/perf_writer_mem.c b/examples/perfcounter/perf_writer_mem.c
new file mode 100644
index 0000000..580207f
--- /dev/null
+++ b/examples/perfcounter/perf_writer_mem.c
@@ -0,0 +1,124 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Performance Counter Daemon
+ *
+ * Copyright (C) Marcin Krzysztof Porwit 2005
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "perf.h"
+
+void get_meminfo(PERF_DATA_BLOCK *data)
+{
+ int status;
+ struct sysinfo info;
+ status = sysinfo(&info);
+
+ data->memInfo.data->availPhysKb = (info.freeram * info.mem_unit)/1024;
+ data->memInfo.data->availSwapKb = (info.freeswap * info.mem_unit)/1024;
+ data->memInfo.data->totalPhysKb = (info.totalram * info.mem_unit)/1024;
+ data->memInfo.data->totalSwapKb = (info.totalswap * info.mem_unit)/1024;
+
+ /* Also get uptime since we have the structure */
+ data->PerfTime = (unsigned long)info.uptime;
+
+ return;
+}
+
+void init_memdata_desc(PERF_DATA_BLOCK *data)
+{
+ init_perf_counter(&(data->memInfo.memObjDesc),
+ &(data->memInfo.memObjDesc),
+ get_counter_id(data),
+ "Memory",
+ "The Memory performance object consists of counters that describe the behavior of physical and virtual memory on the computer.",
+ 0,
+ PERF_OBJECT);
+ init_perf_counter(&(data->memInfo.availPhysKb),
+ &(data->memInfo.memObjDesc),
+ get_counter_id(data),
+ "Available Physical Kilobytes",
+ "Available Physical Kilobytes is the number of free kilobytes in physical memory",
+ PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX,
+ PERF_COUNTER);
+ init_perf_counter(&(data->memInfo.availSwapKb),
+ &(data->memInfo.memObjDesc),
+ get_counter_id(data),
+ "Available Swap Kilobytes",
+ "Available Swap Kilobytes is the number of free kilobytes in swap space",
+ PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX,
+ PERF_COUNTER);
+ init_perf_counter(&(data->memInfo.totalPhysKb),
+ &(data->memInfo.memObjDesc),
+ get_counter_id(data),
+ "Total Physical Kilobytes",
+ "Total Physical Kilobytes is a base counter",
+ PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_COUNTER_BASE | PERF_DISPLAY_NOSHOW,
+ PERF_COUNTER);
+ init_perf_counter(&(data->memInfo.totalSwapKb),
+ &(data->memInfo.memObjDesc),
+ get_counter_id(data),
+ "Total Swap Kilobytes",
+ "Total Swap Kilobytes is a base counter",
+ PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_COUNTER_BASE | PERF_DISPLAY_NOSHOW,
+ PERF_COUNTER);
+
+ return;
+}
+
+void init_mem_data(PERF_DATA_BLOCK *data)
+{
+ data->memInfo.data = calloc(1, sizeof(*data->memInfo.data));
+ if(!data->memInfo.data)
+ {
+ perror("init_memdata: out of memory");
+ exit(1);
+ }
+
+ init_memdata_desc(data);
+
+ get_meminfo(data);
+
+ return;
+}
+
+void output_mem_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt)
+{
+ output_perf_desc(data->memInfo.memObjDesc, rt);
+ output_perf_desc(data->memInfo.availPhysKb, rt);
+ output_perf_desc(data->memInfo.availSwapKb, rt);
+ output_perf_desc(data->memInfo.totalPhysKb, rt);
+ output_perf_desc(data->memInfo.totalSwapKb, rt);
+
+ return;
+}
+
+void output_meminfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags)
+{
+ output_perf_counter(data->memInfo.availPhysKb,
+ (unsigned long long)data->memInfo.data->availPhysKb,
+ rt, tdb_flags);
+ output_perf_counter(data->memInfo.availSwapKb,
+ (unsigned long long)data->memInfo.data->availSwapKb,
+ rt, tdb_flags);
+ output_perf_counter(data->memInfo.totalPhysKb,
+ (unsigned long long)data->memInfo.data->totalPhysKb,
+ rt, tdb_flags);
+ output_perf_counter(data->memInfo.totalSwapKb,
+ (unsigned long long)data->memInfo.data->totalSwapKb,
+ rt, tdb_flags);
+
+ return;
+}
diff --git a/examples/perfcounter/perf_writer_process.c b/examples/perfcounter/perf_writer_process.c
new file mode 100644
index 0000000..bddceea
--- /dev/null
+++ b/examples/perfcounter/perf_writer_process.c
@@ -0,0 +1,85 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Performance Counter Daemon
+ *
+ * Copyright (C) Marcin Krzysztof Porwit 2005
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "perf.h"
+
+void get_processinfo(PERF_DATA_BLOCK *data)
+{
+ int status;
+ struct sysinfo info;
+ status = sysinfo(&info);
+
+ data->processInfo.data->runningProcessCount = (unsigned int)info.procs;
+
+ return;
+}
+
+void init_processdata_desc(PERF_DATA_BLOCK *data)
+{
+ init_perf_counter(&(data->processInfo.processObjDesc),
+ &(data->processInfo.processObjDesc),
+ get_counter_id(data),
+ "Processes",
+ "%The Processes performance object displays aggregate information about processes on the machine.",
+ 0,
+ PERF_OBJECT);
+ init_perf_counter(&(data->processInfo.runningProcessCount),
+ &(data->processInfo.processObjDesc),
+ get_counter_id(data),
+ "Process Count",
+ "Process Count is the number of processes currently on the machine.",
+ PERF_SIZE_DWORD | PERF_TYPE_NUMBER | PERF_NUMBER_DECIMAL | PERF_DISPLAY_NO_SUFFIX,
+ PERF_COUNTER);
+
+ return;
+}
+
+void init_process_data(PERF_DATA_BLOCK *data)
+{
+ data->processInfo.data = calloc(1, sizeof(*data->processInfo.data));
+ if(!(data->processInfo.data))
+ {
+ perror("init_process_data: out of memory");
+ exit(1);
+ }
+
+ init_processdata_desc(data);
+
+ get_processinfo(data);
+
+ return;
+}
+
+void output_processinfo(PERF_DATA_BLOCK *data, RuntimeSettings rt, int tdb_flags)
+{
+ output_perf_counter(data->processInfo.runningProcessCount,
+ (unsigned long long)data->processInfo.data->runningProcessCount,
+ rt, tdb_flags);
+
+ return;
+}
+
+void output_process_desc(PERF_DATA_BLOCK *data, RuntimeSettings rt)
+{
+ output_perf_desc(data->processInfo.processObjDesc, rt);
+ output_perf_desc(data->processInfo.runningProcessCount, rt);
+
+ return;
+}
diff --git a/examples/perfcounter/perf_writer_util.c b/examples/perfcounter/perf_writer_util.c
new file mode 100644
index 0000000..6f1eb16
--- /dev/null
+++ b/examples/perfcounter/perf_writer_util.c
@@ -0,0 +1,235 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Performance Counter Daemon
+ *
+ * Copyright (C) Marcin Krzysztof Porwit 2005
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "perf.h"
+
+extern sig_atomic_t keep_running;
+
+void fatal(char *msg)
+{
+ perror(msg);
+ exit(1);
+}
+
+void add_key_raw(TDB_CONTEXT *db, char *keystring, void *databuf, size_t datasize, int flags)
+{
+ TDB_DATA key, data;
+
+ key.dptr = keystring;
+ key.dsize = strlen(keystring);
+ data.dptr = databuf;
+ data.dsize = datasize;
+
+ tdb_store(db, key, data, flags);
+}
+
+void add_key(TDB_CONTEXT *db, char *keystring, char *datastring, int flags)
+{
+ TDB_DATA key, data;
+
+ key.dptr = keystring;
+ key.dsize = strlen(keystring);
+ data.dptr = datastring;
+ data.dsize = strlen(datastring);
+
+ tdb_store(db, key, data, flags);
+}
+
+void make_key(char *buf, int buflen, int key_part1, char *key_part2)
+{
+ memset(buf, 0, buflen);
+ if(key_part2 != NULL)
+ sprintf(buf, "%d%s", key_part1, key_part2);
+ else
+ sprintf(buf, "%d", key_part1);
+
+ return;
+}
+
+void usage(char *progname)
+{
+ fprintf(stderr, "Usage: %s [-d] [-f <file_path>].\n", progname);
+ fprintf(stderr, "\t-d: run as a daemon.\n");
+ fprintf(stderr, "\t-f <file_path>: path where the TDB files reside.\n");
+ fprintf(stderr, "\t\tDEFAULT is /var/lib/samba/perfmon\n");
+ exit(1);
+}
+
+void parse_flags(RuntimeSettings *rt, int argc, char **argv)
+{
+ int flag;
+
+ while((flag = getopt(argc, argv, "df:")) != -1)
+ {
+ switch(flag)
+ {
+ case 'd':
+ {
+ rt->dflag = TRUE;
+ break;
+ }
+ case 'f':
+ {
+ memcpy(rt->dbDir, optarg, strlen(optarg));
+ break;
+ }
+ default:
+ {
+ usage(argv[0]);
+ }
+ }
+ }
+
+ return;
+}
+
+void setup_file_paths(RuntimeSettings *rt)
+{
+ int status;
+
+ if(strlen(rt->dbDir) == 0)
+ {
+ /* No file path was passed in, use default */
+ sprintf(rt->dbDir, "/var/lib/samba/perfmon");
+ }
+
+ sprintf(rt->nameFile, "%s/names.tdb", rt->dbDir);
+ sprintf(rt->counterFile, "%s/data.tdb", rt->dbDir);
+
+ mkdir(rt->dbDir, 0755);
+ rt->cnames = tdb_open(rt->nameFile, 0, TDB_CLEAR_IF_FIRST, O_RDWR | O_CREAT, 0644);
+ rt->cdata = tdb_open(rt->counterFile, 0, TDB_CLEAR_IF_FIRST, O_RDWR | O_CREAT, 0644);
+
+ if(rt->cnames == NULL || rt->cdata == NULL)
+ {
+ perror("setup_file_paths");
+ exit(1);
+ }
+
+ return;
+}
+
+void sigterm_handler()
+{
+ keep_running = FALSE;
+ return;
+}
+
+void daemonize(RuntimeSettings *rt)
+{
+ pid_t pid;
+ int i;
+ int fd;
+
+ /* Check if we're already a daemon */
+ if(getppid() == 1)
+ return;
+ pid = fork();
+ if(pid < 0)
+ /* can't fork */
+ exit(1);
+ else if(pid > 0)
+ {
+ /* we're the parent */
+ tdb_close(rt->cnames);
+ tdb_close(rt->cdata);
+ exit(0);
+ }
+
+ /* get a new session */
+ if(setsid() == -1)
+ exit(2);
+
+ /* Change CWD */
+ chdir("/");
+
+ /* close file descriptors */
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+
+ /* And reopen them as safe defaults */
+ fd = open("/dev/null", O_RDONLY);
+ if(fd != 0)
+ {
+ dup2(fd, 0);
+ close(fd);
+ }
+ fd = open("/dev/null", O_WRONLY);
+ if(fd != 1)
+ {
+ dup2(fd, 1);
+ close(fd);
+ }
+ fd = open("/dev/null", O_WRONLY);
+ if(fd != 2)
+ {
+ dup2(fd, 2);
+ close(fd);
+ }
+
+ /* handle signals */
+ signal(SIGINT, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGTERM, sigterm_handler);
+
+ return;
+}
+
+int get_counter_id(PERF_DATA_BLOCK *data)
+{
+ data->counter_id += 2;
+ data->num_counters++;
+
+ return data->counter_id;
+}
+
+void init_perf_counter(PerfCounter *counter,
+ PerfCounter *parent,
+ unsigned int index,
+ char *name,
+ char *help,
+ int counter_type,
+ int record_type)
+{
+ counter->index = index;
+ memcpy(counter->name, name, strlen(name));
+ memcpy(counter->help, help, strlen(help));
+ counter->counter_type = counter_type;
+ counter->record_type = record_type;
+
+ switch(record_type)
+ {
+ case PERF_OBJECT:
+ sprintf(counter->relationships, "p");
+ break;
+ case PERF_COUNTER:
+ sprintf(counter->relationships, "c[%d]", parent->index);
+ break;
+ case PERF_INSTANCE:
+ sprintf(counter->relationships, "i[%d]", parent->index);
+ break;
+ default:
+ perror("init_perf_counter: unknown record type");
+ exit(1);
+ }
+
+ return;
+}
diff --git a/examples/perfcounter/perfcountd.init b/examples/perfcounter/perfcountd.init
new file mode 100755
index 0000000..0beff96
--- /dev/null
+++ b/examples/perfcounter/perfcountd.init
@@ -0,0 +1,65 @@
+#!/bin/sh
+#
+# Copyright (C) Gerald Carter 2005
+#
+# 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 3 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, see <http://www.gnu.org/licenses/>.
+#
+####################################################################
+
+## This file should have uid root, gid sys and chmod 744
+
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+
+killproc()
+{
+ pid=`ps aux | grep $1 | egrep -v '(grep|perfcountd)' | awk '{print $2}'`
+ if [ x"$pid" != "x" ]; then
+ kill $pid
+ fi
+}
+
+# Start/stop processes
+
+case "$1"
+in
+start)
+ /opt/samba/bin/perfcount -d -f /var/lib/samba/perfmon 2> /dev/null
+ if [ $? -ne 0 ]; then
+ echo "Failed!"
+ exit 1
+ fi
+ echo "done!"
+ ;;
+stop)
+ killproc perfcount
+ ;;
+
+status)
+ pid=`ps aux | grep perfcount | egrep -v '(grep|perfcountd)' | awk '{print $2}'`
+ if [ x"$pid" = "x" ]; then
+ echo "Dead!"
+ exit 2;
+ fi
+ echo "OK!"
+ ;;
+restart)
+ $0 stop && $0 start
+ ;;
+
+*)
+ echo "Usage: $0 { start|stop|restart|status }"
+ ;;
+esac
+
+
diff --git a/examples/printer-accounting/README b/examples/printer-accounting/README
new file mode 100644
index 0000000..b7ab42a
--- /dev/null
+++ b/examples/printer-accounting/README
@@ -0,0 +1,63 @@
+These are just a few examples of what you can do for printer accounting;
+they are really just hacks to show a manager how may pages were being
+printed out on his new hp5n :)
+
+acct-all will run acct-sum and read the log files to generate some
+stats.
+
+Here is a sample output of the raw stats :
+
+1996-06-10.15:02:15 pkelly master.fcp.oypi.com 538 0
+1996-06-10.15:06:40 pkelly master.fcp.oypi.com 537 0
+1996-06-10.15:32:12 ted master.fcp.oypi.com 547 0
+1996-06-11.09:06:15 violet master.fcp.oypi.com 2667 0
+1996-06-11.09:48:02 violet master.fcp.oypi.com 66304 5
+1996-06-11.09:50:04 violet master.fcp.oypi.com 116975 9
+1996-06-11.09:57:20 violet master.fcp.oypi.com 3013 1
+1996-06-11.10:13:17 pkelly master.fcp.oypi.com 3407 1
+1996-06-11.12:37:06 craig master.fcp.oypi.com 13639 2
+1996-06-11.12:42:23 pkelly master.fcp.oypi.com 13639 2
+1996-06-11.12:45:11 marlene master.fcp.oypi.com 515 0
+1996-06-11.14:17:10 lucie master.fcp.oypi.com 1405 1
+1996-06-11.14:36:03 laura master.fcp.oypi.com 45486 5
+1996-06-11.15:08:21 violet master.fcp.oypi.com 1923 1
+1996-06-11.15:09:42 laura master.fcp.oypi.com 4821 1
+1996-06-11.15:12:28 laura master.fcp.oypi.com 46277 5
+1996-06-11.15:19:38 violet master.fcp.oypi.com 3503 1
+1996-06-11.15:21:49 lucie master.fcp.oypi.com 493 0
+1996-06-11.15:43:36 al master.fcp.oypi.com 3067 1
+
+And the output after the acct-sum is done on a full set of files
+in /var/log/lp/*
+
+master[1072] /var/log/lp$ /etc/conf/acct-all
+
+Sun Jul 21 23:03:16 EDT 1996
+
+Pages are approximate ...
+
+User Jobs Pages Size
+al 1 1 2 KB
+craig 1 2 13 KB
+jack 68 235 1995 KB
+laura 88 328 3050 KB
+lucie 221 379 3529 KB
+marlene 12 151 1539 KB
+melanie 83 365 3691 KB
+michelle 68 219 1987 KB
+mike 2 10 81 KB
+neil 111 225 2753 KB
+operator 44 137 1132 KB
+pkelly 368 984 11154 KB
+root 8 0 29 KB
+ted 158 257 2337 KB
+tony 244 368 2455 KB
+violet 419 1002 10072 KB
+
+
+Printer Jobs Pages
+hp2p 3 4
+hp5 915 2135
+lp 978 2524
+
+<pkelly@ets.net>
diff --git a/examples/printer-accounting/acct-all b/examples/printer-accounting/acct-all
new file mode 100644
index 0000000..dc8f175
--- /dev/null
+++ b/examples/printer-accounting/acct-all
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+echo ""
+date
+echo ""
+echo "Pages are approximate ..."
+echo ""
+/etc/conf/acct-sum /var/log/lp/*
+echo ""
diff --git a/examples/printer-accounting/acct-sum b/examples/printer-accounting/acct-sum
new file mode 100644
index 0000000..ffbfc8d
--- /dev/null
+++ b/examples/printer-accounting/acct-sum
@@ -0,0 +1,29 @@
+#!/usr/bin/perl
+
+while (<>) {
+ ($date, $user, $machine, $size, $pages) = split(' ');
+
+ $Printer{$ARGV}++;
+ $PrinterPages{$ARGV} += $pages;
+
+ $Jobs{$user}++;
+ $Size{$user}+= $size;
+ $Pages{$user}+= $pages;
+}
+
+printf "%-15s %5s %8s %8s\n", qw(User Jobs Pages Size);
+foreach $user (sort keys %Jobs) {
+ printf "%-15s %5d %8d %8d \KB\n",
+ $user, $Jobs{$user}, $Pages{$user}, $Size{$user}/1024;
+}
+
+
+print "\n\n";
+printf "%-15s %5s %8s %8s\n", qw(Printer Jobs Pages);
+foreach $prn (sort keys %Printer) {
+ ($name = $prn) =~ s=.*/==;
+ printf "%-15s %5d %8d\n",
+ $name, $Printer{$prn}, $PrinterPages{$prn};
+}
+
+
diff --git a/examples/printer-accounting/hp5-redir b/examples/printer-accounting/hp5-redir
new file mode 100644
index 0000000..e23f718
--- /dev/null
+++ b/examples/printer-accounting/hp5-redir
@@ -0,0 +1,40 @@
+#!/usr/bin/perl
+#
+# 0 == stdin == document
+# 1 == stdout == printer
+# 2 == stderr == logging
+#
+# With redirection to another valid /etc/printcap entry
+#
+
+umask(002);
+
+# -w132 -l66 -i0 -n pkelly -h master.fcp.oypi.com /var/log/lp-acct
+require "getopts.pl";
+&Getopts("w:l:i:n:h:");
+
+chomp($date = `date '+%Y-%m-%d.%T'`);
+
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+ $atime,$mtime,$ctime,$blksize,$blocks)
+ = stat(STDIN);
+
+# send to the real printer now.
+open(P, "|lpr -Pmgmt0") || die "Can't print to hp5-real ($!)\n";
+$cnt = 0;
+while (sysread(STDIN, $buf, 10240)) {
+ print P $buf;
+ # this is ugly, but it gives the approx in pages. We
+ # don't print graphics, so ... There must be a better way :)
+ $cnt += ($buf =~ /^L/g);
+}
+close(P);
+
+$acct = shift;
+if (open(ACCT, ">>$acct")) {
+ print ACCT "$date $opt_n $opt_h $size $cnt\n";
+ close(ACCT);
+} else {
+ warn "Err: Can't account for it ($!)\n";
+ warn "Log: $date $opt_n $opt_h $size $cnt\n";
+}
diff --git a/examples/printer-accounting/lp-acct b/examples/printer-accounting/lp-acct
new file mode 100644
index 0000000..3acdbb9
--- /dev/null
+++ b/examples/printer-accounting/lp-acct
@@ -0,0 +1,35 @@
+#!/usr/bin/perl
+#
+# 0 == stdin == document
+# 1 == stdout == printer
+# 2 == stderr == logging
+#
+# Regular, with no redirection
+#
+
+umask(002);
+
+# -w132 -l66 -i0 -n pkelly -h master.fcp.oypi.com /var/log/lp-acct
+require "getopts.pl";
+&Getopts("w:l:i:n:h:");
+
+chomp($date = `date '+%Y-%m-%d.%T'`);
+
+($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
+ $atime,$mtime,$ctime,$blksize,$blocks)
+ = stat(STDIN);
+
+$cnt = 0;
+while (sysread(STDIN, $buf, 10240)) {
+ print $buf;
+ $cnt += ($buf =~ /^L/g);
+}
+
+$acct = shift;
+if (open(ACCT, ">>$acct")) {
+ print ACCT "$date $opt_n $opt_h $size $cnt\n";
+ close(ACCT);
+} else {
+ warn "Err: Can't account for it ($!)\n";
+ warn "Log: $date $opt_n $opt_h $size $cnt\n";
+}
diff --git a/examples/printer-accounting/printcap b/examples/printer-accounting/printcap
new file mode 100644
index 0000000..976005a
--- /dev/null
+++ b/examples/printer-accounting/printcap
@@ -0,0 +1,22 @@
+# HP5N - Accounting entry
+#
+# This file calls the filter, hp5-redir to do the numbers and then
+# is redirected to the real entry, mgmt0, which is a remote HP5N
+# on the LAN with it's own IP number.
+#
+hp5:lp=/dev/lp1:\
+ :sd=/usr/spool/lpd/hp5-acct:\
+ :lf=/var/log/lp-err:\
+ :af=/var/log/lp/hp5:\
+ :if=/usr/local/bin/lp/hp5-redir:\
+ :sh:sf:\
+ :mx#0:
+
+# HP5N - Real printer location
+mgmt0:\
+ :rm=hp5.fcp.oypi.com:\
+ :rp=hp5.fcp.oypi.com:\
+ :sd=/usr/spool/lpd/mgmt0:\
+ :sh:sf:\
+ :mx#0:
+
diff --git a/examples/printing/VampireDriversFunctions b/examples/printing/VampireDriversFunctions
new file mode 100644
index 0000000..b06e365
--- /dev/null
+++ b/examples/printing/VampireDriversFunctions
@@ -0,0 +1,1656 @@
+#!/bin/bash
+
+#####################################################################
+##
+## smb.conf parser class
+##
+## Copyright (C) Kurt Pfeifle <kpfeifle@danka.de>, 2004.
+##
+## 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 3 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, see <http://www.gnu.org/licenses/>.
+##
+######################################################################
+
+######################################################################
+## Here an example calling sequence
+##!/bin/sh
+## set -x
+## source VampireDriversFunctions
+
+##
+## Start local variables
+##
+## You must define these variable (possibly in a source script)
+
+## nthost=192.168.17.1
+## printeradmin=Administrator
+## adminpasswd=not4you
+
+## smbhost=knoppix
+## smbprinteradmin=knoppix
+## smbadminpasswd=knoppix
+##
+## End of local variables
+##
+
+##
+## functions to call
+##
+
+## fetchenumdrivers3listfromNThost # repeat, if no success at first
+## createdrivernamelist
+## createprinterlistwithUNCnames # repeat, if no success at first
+## createmapofprinterstodriver
+## splitenumdrivers3list
+## makesubdirsforWIN40driverlist
+## splitWIN40fileintoindividualdriverfiles
+## fetchtheWIN40driverfiles
+## uploadallWIN40drivers
+## makesubdirsforW32X86driverlist
+## splitW32X86fileintoindividualdriverfiles
+## fetchtheW32X86driverfiles
+## uploadallW32X86drivers
+
+## End of example calling sequence
+######################################################################
+
+
+# -----------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
+function vampiredrivers_readme()
+{
+echo -e " \n\
+############################################################################
+#
+# About the \"Vampire Printer Drivers\" set of functions....
+# --------------------------------------------------------
+#
+# (C) Kurt Pfeifle <kpfeifle@danka.de>, 2004
+# License: GPL
+#
+# ------------------------------------------------------------
+#
+# Version: 0.8 (largely \"self-documented\" now, but not yet
+# completely -- if it ever will be....)
+#
+# Thanks a lot to Fabian Franz for helping me with some important
+# Bash-Scripting-Questions!
+#
+# This set of functions provides a framework to snatch all printer
+# driver info and related files from a Windows NT print server.
+# It then uploads and installs the drivers to a Samba server. (The
+# Samba server needs to be prepared for this: a valid [print$]
+# share, with write access set for a user with SePrintOperatorPrivilege.)
+#
+# The main commands used are \"smbclient\" and \"rpcclient\" combined
+# with \"grep\", \"sed\" and \"awk\". Probably a Perl or Python script
+# would be better suited to do this, mainly because we have to cope
+# with printer and driver names which are containing spaces in
+# them, so a lot of shell escaping is required to handle these.
+# Also, I am not very savvy in scripting, so I invented some very
+# obscure methods to work around my knowledge gaps. When I download
+# the driver files from the Windows NT box, I put all related driver
+# files into their own sub directory, using the same name as the
+# driver. Also, driver versions \"0\", \"2\" and \"3\" are placed in
+# further subdirectories.
+#
+#
+# Known problems:
+# ---------------
+#
+# 1) I found one printer driver containing a \"slash\" which is not
+# handled by this script: \"HP Color LaserJet 5/5M PS\". (There
+# are more of these in the wild, of course.) -- The reason: I
+# didn't find a way to create a Unix directory containing a \"slash\".
+# UPDATE: The script replaces the \"/\" with a \"_\" and also renames
+# the drivername accordingly, when it is uploaded to the Samba
+# [print$] share....
+#
+# 2) There is an unsolved problem in case a real file name deviates
+# in its case sensitive spelling from how it is displayed by the
+# \"rpcclient enumdrivers\" command. I encountered cases where
+# rpcclient displayed \"PS5UI.DLL\" as a file name, but \"smbclient
+# mget\" retrieved \"ps5ui.dll\" from the NT printserver, and the
+# driverinstallation failed because \"smbclient mput\" tried to put
+# \"PS5UI.DLL\" back onto the Samba server where UNIX only had
+# \"ps5ui.dll\" available (which of course failed). -- UPDATE: this
+# is now solved. All files are renamed now to the same
+# case-sensitive spelling as \"rpcclient ... enumdrivers 3\"
+# announces. This includes renaming into both, uppercase or
+# lowercase, as the case might be....
+#
+# 3) This script is probably not portable at all and relies on lots
+# of Bash-isms.
+#
+# 4) This script runs with rpcclient from Samba-3.0.2a (or later) only
+# (because it uses the \"Version\" parameter for \"adddriver\").
+#
+# The following functions use a few external variables to log
+# into the 2 hosts. We suggest that you create a file which
+# contains the variables and that you source that file at the
+# beginning of this script...
+#
+# #################################################################
+#
+# ntprinteradmin=Administrator # any account on the NT host
+# # with SePrintOperatorPrivilege privileges
+# ntadminpasswd=not4you # the printer admin password on
+# # the NT print server
+# nthost=windowsntprintserverbox # the netbios name of the NT print
+# # server
+#
+# smbprinteradmin=knoppix # an account on the Samba server
+# # with SePrintOperatorPrivilege privileges
+# smbadminpasswd=2secret4you # the printer admin password on
+# # the Samba server
+# smbhost=knoppix # the netbios name of the Samba
+# # print server
+#
+# #################################################################
+#
+#
+# NOTE: these functions also work for 2 NT print servers: snatch all
+# drivers from the first, and upload them to the second server (which
+# takes the role of the \"Samba\" server). Of course they also work
+# for 2 Samba servers: snatch all drivers from the first (which takes
+# the role of the NT print server) and upload them to the second....
+#
+#
+# ............PRESS \"q\" TO QUIT............" \
+|less
+}
+
+
+#set -x
+
+
+# -----------------------------------------------------------------------------
+# ----------- print a little help... ------------------------------------------
+# -----------------------------------------------------------------------------
+
+function helpwithvampiredrivers()
+{
+if stringinstring help "$@"; then
+helpwithvampiredrivers ;
+else
+ echo " ";
+ echo " 1. Run the functions of this script one by one.";
+ echo " ";
+ echo " 2. List all functions with the \"enumallfunctions\" call.";
+ echo " ";
+ echo " 3. After each functions' run, check if it completed successfully.";
+ echo " ";
+ echo " 4. For each function, you can ask for separate help by typing";
+ echo " \"<functionname> --help\"."
+ echo " ";
+ echo " 5. Often network conditions prevent the MS-RPC calls"
+ echo " implemented by Samba to succeed at the first attempt."
+ echo " You may have more joy if you try more than once or twice....";
+ echo " ";
+ echo " 6. I can not support end-users who have problems with this script."
+ echo " However, we are available for paid, professional consulting,"
+ echo " training and troubleshooting work.";
+ echo " ";
+ echo " ";
+fi
+}
+
+# -----------------------------------------------------------------------------
+# ----------- enumerate all builtin functions... ------------------------------
+# -----------------------------------------------------------------------------
+function enumallfunctions()
+{
+if stringinstring help "$@"; then
+helpwithvampiredrivers ;
+else
+ echo " "
+ echo " "
+ echo "--> Running now function enumallfunctions()..."
+ echo "=============================================="
+ echo -e " \n\
+
+ NOTE: run the listed functions in the same order as listed below.
+
+ EXAMPLE: \"knoppix@ttyp6[knoppix]$ helpwithvampiredrivers\"
+
+ HELP: the \"--help\" parameter prints usage hints regarding a function.
+
+ EXAMPLE: \"knoppix@ttyp6[knoppix]$ fetchenumdrivers3listfromNThost --help\"
+
+
+ function vampiredrivers_readme()
+ function enumallfunctions()
+ function helpwithvampiredrivers()
+ function fetchenumdrivers3listfromNThost() # repeat, if no success at first
+ function createdrivernamelist()
+ function createprinterlistwithUNCnames() # repeat, if no success at first
+ function createmapofprinterstodrivers()
+ function splitenumdrivers3list()
+ function makesubdirsforW32X86driverlist()
+ function splitW32X86fileintoindividualdriverfiles()
+ function fetchallW32X86driverfiles()
+ function uploadallW32X86drivers()
+ function makesubdirsforWIN40driverlist()
+ function splitWIN40fileintoindividualdriverfiles()
+ function fetchallWIN40driverfiles()
+ function uploadallWIN40drivers()"
+ echo " "
+fi
+}
+
+# this is a helperfunction (Thanks to Fabian Franz!)
+function stringinstring()
+{
+ case "$2" in *$1*)
+ return 0
+ ;;
+ esac
+ return 1
+}
+
+# -----------------------------------------------------------------------------
+# ----------- Create an "enumprinters 3" list --------------------- -----------
+# -----------------------------------------------------------------------------
+#
+
+function helpwithfetchenumdrivers3listfromNThost()
+{
+echo -e " \n\
+################################################################################
+#
+# About fetchenumdrivers3listfromNThost()....
+# -------------------------------------------
+#
+# PRECONDITIONS: 1) This function expects write access to the current directory.
+# 2) This function expects to have the '\$nthosts',
+# '\$ntprinteradmin' and '\$ntadminpasswd' variables set to
+# according values.
+#
+# WHAT IT DOES: This function connects to the '\$nthost' (using the credentials
+# '\$ntprinteradmin' with '\$ntadminpasswd', retrieves a list of
+# drivers (with related file names) from that host, and saves the
+# list under the name of '\${nthost}/enumdrivers3list.txt' (ie. it
+# also creates the '\$nthost' subdirectory in the current one). It
+# further prints some more info to stdout.
+#
+# IF IT DOESN'T WORK: It may happen that the function doesn't work at the first
+# time (there may be a connection problem). Just repeat a
+# few times. It may work then. You will recognize if it
+# does.
+#
+# HINT: The current values: 'nthost'=\"$nthost\"
+# 'ntprinteradmin'=\"$ntprinteradmin\"
+# 'ntadminpasswd'=<not shown here, check yourself!>
+#
+################################################################################"
+echo " "
+}
+
+# -----------------------------------------------------------------------------
+
+function fetchenumdrivers3listfromNThost()
+{
+if stringinstring help "$@"; then
+helpwithfetchenumdrivers3listfromNThost;
+else
+ echo " "
+ echo " "
+ echo "--> Running now function fetchenumdrivers3listfromNThost"
+ echo "========================================================"
+ [ -d ${nthost} ] || mkdir "${nthost}";
+ rpcclient -U${ntprinteradmin}%${ntadminpasswd} -c 'enumdrivers 3' ${nthost} \
+ | sed -e '/^.*Driver Name: \[.*\]/ y/\//_/' \
+ | tee \
+ ${nthost}/enumdrivers3list.txt;
+
+ NUMBEROFDIFFERENTDRIVERNAMES=$( grep "Driver Name:" ${nthost}/enumdrivers3list.txt \
+ | sort -f \
+ | uniq \
+ | wc -l );
+
+ echo " ";
+ echo "--> Finished in running function fetchenumdrivers3listfromNThost....";
+ echo "===================================================================="
+ echo "NUMBEROFDIFFERENTDRIVERNAMES retrieved from \"${nthost}\" is $NUMBEROFDIFFERENTDRIVERNAMES".;
+ echo " --> If you got \"0\" you may want to try again. <---";
+ echo "================================================================";
+ echo " ";
+ enumdrivers3list=`cat ${nthost}/enumdrivers3list.txt`;
+fi
+}
+
+
+# -----------------------------------------------------------------------------
+# ----------- Create a list of all available drivers installed ----------------
+# ------------------------on the NT print server-------------------------------
+# -----------------------------------------------------------------------------
+#
+
+function helpwithcreatedrivernamelist()
+{
+echo -e " \n\
+################################################################################
+#
+# About createdrivernamelist()...
+# -------------------------------
+#
+# PRECONDITIONS: 1) This function expects to find the subdirectory '\$nthost'
+# and the file '\${nthost}/enumdrivers3list.txt' to exist.
+# 2) This function expects to have the '\$nthosts' variable set
+# to an according value.
+#
+# WHAT IT DOES: This function dissects the '\${nthost}/enumdrivers3list.txt'
+# and creates other textfiles from its contents:
+# - '\${nthost}/drvrlst.txt'
+# - '\${nthost}/completedriverlist.txt'
+# and further prints some more info to stdout.
+#
+# HINT: The current value: 'nthost'=\"$nthost\"
+#
+################################################################################"
+}
+
+# -----------------------------------------------------------------------------
+
+function createdrivernamelist()
+{
+if stringinstring help "$@"; then
+helpwithcreatedrivernamelist;
+else
+ echo " ";
+ echo " ";
+ echo "--> Running now function createdrivernamelist....";
+ echo "=================================================";
+ cat ${nthost}/enumdrivers3list.txt \
+ | grep "Driver Name:" \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print $1 }' \
+ | sort -f \
+ | uniq \
+ | tr / _ \
+ | sed -e 's/$/\"/' -e 's/^ */\"/' \
+ | tee \
+ ${nthost}/drvrlst.txt;
+ drvrlst=$(echo ${nthost}/drvrlst.txt);
+
+ cat ${nthost}/enumdrivers3list.txt \
+ | grep "Driver Name:" \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print $1 }' \
+ | sort -f \
+ | uniq \
+ | sed -e 's/$/\"/' \
+ | cat -n \
+ | sed -e 's/^ */DRIVERNAME/' -e 's/\t/\="/' \
+ | tee \
+ ${nthost}/completedriverlist.txt;
+
+ NUMBEROFDRIVERS=`cat ${nthost}/completedriverlist.txt| wc -l`;
+ echo " ";
+ echo "--> Finished in running function createdrivernamelist....";
+ echo "==============================================================================="
+ echo "NUMBEROFDRIVERS retrieve-able from \"${nthost}\" is $NUMBEROFDRIVERS".;
+ echo " --> If you got \"0\" you may want to run \"fetchenumdrivers3listfromNThost\""
+ echo " again. <---";
+ echo "===============================================================================";
+ echo " ";
+ driverlist=`cat ${nthost}/completedriverlist.txt`;
+
+ # alternative method suggested by Fabian Franz:
+ # | awk 'BEGIN {n=1} { print "DRIVERNAME"n"=\""$0"\""; n=n+1 } '
+fi
+}
+
+
+
+# -----------------------------------------------------------------------------
+# ----------- Create a list of all available printers -------------------------
+# -----------------------------------------------------------------------------
+#
+
+function helpwithcreateprinterlistwithUNCnames()
+{
+echo -e " \n\
+################################################################################
+#
+# About createprinterlistwithUNCnames()...
+# ----------------------------------------
+#
+# PRECONDITIONS: 1) This function expects write access to the current directory.
+# 2) This function expects to have the '\$nthost',
+# '\$ntprinteradmin' and '\$ntadminpasswd' variables set to
+# according values.
+#
+# WHAT IT DOES: This function connects to the '\$nthost' (using the credentials
+# '\$ntprinteradmin' with '\$ntadminpasswd'), retrieves a list of
+# printqueues (with associated driver names) from that host (with
+# the help of the 'rpcclient ... enumprinters' utility, and saves
+# it under name and path '\${nthost}/printerlistwithUNCnames.txt'
+# (ie. it also creates the '\$nthost' subdirectory in the current
+# one). It further prints some more info to stdout.
+#
+# IF IT DOESN'T WORK: It may happen that the function doesn't work at the first
+# time (there may be a connection problem). Just repeat a
+# few times. It may work then. You will recognize if it does.
+#
+# HINT: The current values: 'nthost'=\"$nthost\"
+# 'ntprinteradmin'=\"$ntprinteradmin\"
+# 'ntadminpasswd'=<not shown here, check yourself!>
+#
+################################################################################"
+}
+
+# -----------------------------------------------------------------------------
+
+function createprinterlistwithUNCnames()
+{
+if stringinstring help "$@"; then
+helpwithcreateprinterlistwithUNCnames ;
+else
+ [ -d ${nthost} ] || mkdir -p ${nthost};
+ echo " "
+ echo " "
+ echo " "
+ echo "--> Running now function createprinterlistwithUNCnames()...."
+ echo "============================================================"
+ rpcclient -U"${ntprinteradmin}%${ntadminpasswd}" -c 'enumprinters' ${nthost} \
+ | grep "description:" \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print $1 }' \
+ | sort -f \
+ | uniq \
+ | tee \
+ ${nthost}/printerlistwithUNCnames.txt;
+
+ NUMBEROFPRINTERS=`cat ${nthost}/printerlistwithUNCnames.txt| wc -l`;
+ echo " ";
+ echo "--> Finished in running function createprinterlistwithUNCnames....";
+ echo "=========================================================================="
+ echo "NUMBEROFPRINTERS retrieved from \"${nthost}\" is $NUMBEROFPRINTERS".;
+ echo " --> If you got \"0\" you may want to try again. <---";
+ echo "==========================================================================";
+ echo " ";
+ printerlistwithUNCnames=`cat ${nthost}/printerlistwithUNCnames.txt`;
+fi
+}
+
+
+# -----------------------------------------------------------------------------
+# ----------- Create a list of all printers which have (no) drivers -----------
+# -----------------------------------------------------------------------------
+#
+
+function helpwithcreatemapofprinterstodrivers()
+{
+echo -e " \n\
+################################################################################
+#
+# About createmapofprinterdrivers()...
+# ------------------------------------
+#
+# PRECONDITIONS: 1) This function expects to find a subdirectory '\$nthost' and
+# the file '\${nthost}/printerlistwithUNCnames.txt' to exist.
+# 2) This functions expects to have the '\$nthosts' variable set
+# to an according value.
+#
+# WHAT IT DOES: This function dissects '\${nthost}/printerlistwithUNCnames.txt'
+# and creates some other textfiles from its contents:
+# - '\${nthost}/allprinternames.txt'
+# - '\${nthost}/alldrivernames.txt'
+# - '\${nthost}/allnonrawprinters.txt'
+# - '\${nthost}/allrawprinters.txt'
+# - '\${nthost}/printertodrivermap.txt'
+# and further prints some more info to stdout.
+#
+# HINT: You currently have defined: 'nthost'=\"$nthost\", which resolves above
+# mentioned paths to:
+# - '${nthost}/allprinternames.txt'
+# - '${nthost}/alldrivernames.txt'
+# - '${nthost}/allnonrawprinters.txt'
+# - '${nthost}/allrawprinters.txt'
+# - '${nthost}/printertodrivermap.txt'
+#
+################################################################################"
+}
+
+# -----------------------------------------------------------------------------
+
+function createmapofprinterstodrivers()
+{
+if stringinstring help "$@"; then
+helpwithcreatemapofprinterstodrivers ;
+else
+ echo " "
+ echo " "
+ echo "--> Running now function createmapofprinterstodrivers()...."
+ echo "==========================================================="
+ echo " "
+ echo " "
+ echo "ALL PRINTERNAMES:"
+ echo "================="
+ echo " "
+ cat ${nthost}/printerlistwithUNCnames.txt \
+ | awk -F "\\" '{ print $4 }' \
+ | awk -F "," '{print $1}' \
+ | sort -f \
+ | uniq \
+ | tee \
+ ${nthost}/allprinternames.txt;
+
+ echo " "
+ echo " "
+ echo "ALL non-RAW PRINTERS:"
+ echo "====================="
+ echo " "
+ cat ${nthost}/printerlistwithUNCnames.txt \
+ | grep -v ",," \
+ | awk -F "\\" '{ print $4 }' \
+ | awk -F "," '{print $1}' \
+ | sort -f \
+ | uniq \
+ | tee \
+ ${nthost}/allnonrawprinters.txt;
+
+ echo " "
+ echo " "
+ echo "ALL RAW PRINTERS:"
+ echo "================"
+ echo " "
+ cat ${nthost}/printerlistwithUNCnames.txt \
+ | grep ",," \
+ | awk -F "\\" '{ print $4 }' \
+ | awk -F "," '{print $1}' \
+ | sort -f \
+ | uniq \
+ | tee \
+ ${nthost}/allrawprinters.txt;
+
+ echo " "
+ echo " "
+ echo "THE DRIVERNAMES:"
+ echo "================"
+ cat ${nthost}/printerlistwithUNCnames.txt \
+ | awk -F "," '{print $2 }' \
+ | grep -v "^$" \
+ | tee \
+ ${nthost}/alldrivernames.txt;
+
+ echo " "
+ echo " "
+ echo "THE PRINTER-TO-DRIVER-MAP-FOR-non-RAW-PRINTERS:"
+ echo "==============================================="
+ cat ${nthost}/printerlistwithUNCnames.txt \
+ | awk -F "\\" '{ print $4 }' \
+ | awk -F "," '{ print "\"" $1 "\":\"" $2 "\"" }' \
+ | grep -v ":\"\"$" \
+ | tee \
+ ${nthost}/printertodrivermap.txt
+ echo -e "##########################\n# printer:driver #" >> ${nthost}/printertodrivermap.txt
+fi
+}
+
+
+# -----------------------------------------------------------------------------
+# ----------- Create a list of all printers which have drivers ----------------
+# -----------------------------------------------------------------------------
+#
+
+function helpwithgetdrivernamelist()
+{
+echo -e " \n\
+################################################################################
+#
+# About getdrivernamelist()...
+# ----------------------------
+#
+# PRECONDITIONS: 1) This function expects to find the subdirectory '\$nthost\'
+# otherwise it creates it...
+#
+# WHAT IT DOES: This function creates the '\${nthost}/printernamelist.txt'
+# and also prints it to <stdout>. To do so, it must contact the
+# '\$nthost' via rpcclient (which in turn needs '\$ntprinteradmin'
+# '\$ntadminpasswd' to log in....).
+#
+# HINT: The current values: 'nthost'=\"$nthost\"
+# 'ntprinteradmin'=\"$ntprinteradmin\"
+# 'ntadminpasswd'=<not shown here, check yourself!>
+# which resolves above mentioned path to:
+# - '${nthost}/printernamelist.txt'
+#
+################################################################################"
+}
+
+# -----------------------------------------------------------------------------
+
+function getdrivernamelist()
+{
+if stringinstring help "$@"; then
+helpwithgetdrivernamelist ;
+else
+ [ -d ${nthost} ] || mkdir -p ${nthost};
+ echo " "
+ echo " "
+ echo "--> Running now function getdrivernamelist()...."
+ echo "================================================"
+ rpcclient -U${ntprinteradmin}%${ntadminpasswd} -c 'enumprinters' ${nthost} \
+ | grep "description:" \
+ | grep -v ",," \
+ | awk -F "," '{ print $2 }' \
+ | sort -f \
+ | uniq \
+ | tee \
+ ${nthost}/drivernamelist.txt
+fi
+}
+
+
+# -----------------------------------------------------------------------------
+# ----------- Split the driverfile listing between the architectures ----------
+# -----------------------------------------------------------------------------
+#
+
+function helpwithsplitenumdrivers3list()
+{
+echo -e " \n\
+################################################################################
+#
+# About splitenumdrivers3list()...
+# --------------------------------
+#
+# PRECONDITIONS: 1) This function expects write access to the current directory
+# and its subdirs '\$nthost/*'.
+# 2) This function expects to have the '\$nthost' variable set to
+# the according value.
+#
+# WHAT IT DOES: This function dissects the '\$nthost/enumdrivers3list.txt'
+# (using "sed", "cat", "awk" and "grep"). It splits the list up
+# into two different files representing a complete list of drivers
+# and files for each of the 2 supported architectures. It creates
+# '\${nthost}/W32X86/${nthost}-enumdrivers3list-NTx86.txt'
+# and '\${nthost}/WIN40/${nthost}-enumdrivers3list-WIN40.txt'.
+#
+# IF IT DOESN'T WORK: The function "fetchenumdrivers3listfromNThost" may not
+# have been run successfully. This is a precondition for
+# the current function.
+#
+# HINT: You currently have defined: 'nthost'=\"$nthost\", which resolves above
+# mentioned paths to:
+# - '${nthost}/WIN40/${nthost}-enumdrivers3list-NTx86.txt'
+# - '${nthost}/W32X86/${nthost}-enumdrivers3list-NTx86.txt'
+#
+################################################################################"
+}
+
+# -----------------------------------------------------------------------------
+
+function splitenumdrivers3list()
+{
+if stringinstring help "$@"; then
+helpwithsplitenumdrivers3list ;
+else
+ echo " "
+ echo " "
+ echo "--> Running now function splitenumdrivers3list()...."
+ echo "===================================================="
+
+ [ -d ${nthost}/WIN40 ] || mkdir -p ${nthost}/WIN40;
+ [ -d ${nthost}/W32X86 ] || mkdir -p ${nthost}/W32X86;
+
+ cat ${nthost}/enumdrivers3list.txt \
+ | sed -e '/^\[Windows NT x86\]/,$ d' \
+ | tee \
+ ${nthost}/WIN40/${nthost}-enumdrivers3list-WIN40.txt ;
+
+ cat ${nthost}/WIN40/${nthost}-enumdrivers3list-WIN40.txt \
+ | grep Version \
+ | sort -f \
+ | uniq \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print $1 }' \
+ | tee ${nthost}/WIN40/availableversionsWIN40.txt ;
+
+# cd ${nthost}/WIN40/ ;
+# mkdir $( cat availableversionsWIN40.txt ) 2> /dev/null ;
+# cd - ;
+
+ cat ${nthost}/enumdrivers3list.txt \
+ | sed -e '/^\[Windows NT x86\]/,$! d' \
+ | tee \
+ ${nthost}/W32X86/${nthost}-enumdrivers3list-NTx86.txt ;
+
+ cat ${nthost}/W32X86/${nthost}-enumdrivers3list-NTx86.txt \
+ | grep Version \
+ | sort -f \
+ | uniq \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print $1 }' \
+ | tee ${nthost}/W32X86/availableversionsW32X86.txt ;
+
+# cd ${nthost}/W32X86/ ;
+# mkdir $( cat availableversionsW32X86.txt ) 2> /dev/null ;
+# cd - ;
+fi
+}
+
+
+# -----------------------------------------------------------------------------
+# ---------- Make subdirs in ./${sambahost}/WIN40/ for each driver.... -------
+# -----------------------------------------------------------------------------
+#
+
+function helpwithmakesubdirsforWIN40driverlist()
+{
+echo -e " \n\
+################################################################################
+#
+# About makesubdirsforWIN40driverlist() and makesubdirsforWIN40driverlist ()...
+# -----------------------------------------------------------------------------
+#
+# PRECONDITIONS: 1) These functions expect write access to the current directory
+# 2) These functions expect to have the '\$nthost' variable set
+# to the according value.
+# 3) These functions expect to find the two files
+# '\${nthost}/WIN40/\${nthost}-enumdrivers3list-WIN40.txt' and
+# '\${nthost}/W32X86/\${nthost}-enumdrivers3list-NTx86.txt' to
+# work on.
+#
+# WHAT IT DOES: These functions dissect the '$nthost/enumdrivers3list.txt'
+# (using "sed", "cat", "awk" and "grep"). They split the input
+# files up into individual files representing driver(version)s and
+# create appropriate subdirectories for each driver and version
+# underneath './\$nthost/<architecture>'. They use the drivernames
+# (including spaces) for the directory names. ("/" -- slashes --
+# in drivernames are converted to underscores).
+#
+# IF IT DOESN'T WORK: The function "fetchenumdrivers3listfromNThost" and
+# consecutive ones may not have been run successfully. This
+# is a precondition for the current function.
+#
+# HINT: You currently have defined: 'nthost'=\"$nthost\", which resolves above
+# mentioned paths to:
+# - '\${nthost}/WIN40/\${nthost}-enumdrivers3list-NTx86.txt'
+# - '\${nthost}/W32X86/\${nthost}-enumdrivers3list-NTx86.txt'
+#
+################################################################################
+# ............PRESS \"q\" TO QUIT............" \
+|less
+}
+
+# -----------------------------------------------------------------------------
+
+function makesubdirsforWIN40driverlist()
+{
+if stringinstring help "$@"; then
+helpwithmakesubdirsforWIN40driverlist ;
+else
+ cat ${nthost}/WIN40/${nthost}-enumdrivers3list-WIN40.txt \
+ | grep "Driver Name:" \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print $1 }' \
+ | sort -f \
+ | uniq \
+ | tr / _ \
+ | sed -e 's/$/\"/' \
+ | sed -e 's/^/mkdir -p '"\"${nthost}"'\/WIN40\//' \
+ | tee \
+ ${nthost}/makesubdirsforWIN40driverlist.txt;
+
+ sh -x ${nthost}/makesubdirsforWIN40driverlist.txt;
+
+# rm ${nthost}/makesubdirsforWIN40driverlist.txt;
+fi
+}
+
+
+# -----------------------------------------------------------------------------
+# ---------- Make subdirs in ./${sambahost}/W32X86/ for each driver.... -------
+# -----------------------------------------------------------------------------
+#
+
+function makesubdirsforW32X86driverlist()
+{
+if stringinstring help "$@"; then
+helpwithvampiredrivers ;
+else
+ cat ${nthost}/W32X86/${nthost}-enumdrivers3list-NTx86.txt \
+ | grep "Driver Name:" \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print $1 }' \
+ | sort -f \
+ | uniq \
+ | tr / _ \
+ | sed -e 's/$/\"/' \
+ | sed -e 's/^ */mkdir '\""${nthost}"'\/W32X86\//' \
+ | tee \
+ ${nthost}/makesubdirsforW32X86driverlist.txt;
+
+ sh -x ${nthost}/makesubdirsforW32X86driverlist.txt;
+
+# rm ${nthost}/makesubdirsforW32X86driverlist.txt;
+fi
+}
+
+
+
+
+# -----------------------------------------------------------------------------
+# ----------- Split the WIN40 driverfile listing of each architecture ---------
+# ------------------------ into individual drivers ----------------------------
+# -----------------------------------------------------------------------------
+#
+
+function helpwithmakesubdirsforWIN40driverlist()
+{
+echo -e " \n\
+################################################################################
+#
+# About splitWIN40fileintoindividualdriverfiles() and
+# splitW32X86fileintoindividualdriverfiles()...
+# ---------------------------------------------------
+#
+# PRECONDITIONS: 1) These functions expect write access to the current directory
+# and its subdirs '\$nthost/*/'.
+# 2) These functions expect to have the '\$nthost' variable set
+# to the according value.
+# 3) These functions expect to find the two files
+# '\${nthost}/WIN40/\${nthost}-enumdrivers3list-WIN40.txt' and
+# '\${nthost}/W32X86/\${nthost}-enumdrivers3list-NTx86.txt' to
+# work on.
+#
+# WHAT IT DOES: 1) These functions create a directory for each printer driver.
+# The directory name is identical to the driver name.
+# 2) For each supported driver version (\"0\", \"2\" and \"3\") it
+# creates a subdirectory as required underneath
+# './\$nthost/<architecture>'.
+# 3) The directories use the drivernames (including spaces) for
+# their names. ("/" - slashes - in drivernames are converted to
+# underscores).
+# 4) In each subdirectory they dissect the original
+# '\$nthost/enumdrivers3list.txt' (using "sed", "cat", "awk"
+# and "grep") and store that part describing the related driver
+# (under the name \"driverfilesversion.txt\".
+# 5) For each driver the files \"Drivername\", \"DriverPath\",
+# \"Drivername\", \"Configfile\", \"Helpfile\", \"AllFiles\" and
+# \"Dependentfilelist\" are stored in the according directory
+# which hold contend that is used by other (downstream)
+# functions.
+# 6) It creates a file named \"AllFilesIAskFor\" which holds the
+# case sensitive names of files it wanted to download. It also
+# creates a file named \"AllFilesIGot\" which holds the case
+# sensitive spelling of the downloaded files. (Due to
+# Microsoft's ingenious file naming tradition, you may have
+# asked for a \"PS5UI.DLL\" but gotten a \"ps5ui.dll\".
+# 7) The 2 files from 6) will be later compared with the help of
+# the \"sdiff\" utility to decide how to re-name the files so
+# that the subsequent driver upload command's spelling
+# convention is met.
+#
+# IF IT DOESN'T WORK: The function \"fetchenumdrivers3listfromNThost\" and
+# consecutive ones may not have been run successfully. This
+# is a precondition for the current function.
+#
+# HINT: You currently have defined: 'nthost'=\"$nthost\".
+#
+################################################################################
+# ............PRESS \"q\" TO QUIT............" \
+|less
+}
+
+# -----------------------------------------------------------------------------
+
+function splitWIN40fileintoindividualdriverfiles()
+{
+if stringinstring help "$@"; then
+helpwithmakesubdirsforWIN40driverlist ;
+else
+ echo " "
+ echo " "
+ echo "--> Running now function splitWIN40fileintoindividualdriverfiles()..."
+ echo "====================================================================="
+
+ for i in ${nthost}/WIN40/*/; do
+ CWD1="$( pwd )" ;
+ cd "${i}" ;
+ echo " "
+ echo " "
+ echo " ###########################################################################################"
+ echo " "
+ echo " Next driver is \"$( basename "$( pwd)" )\""
+ echo " "
+ echo " ###########################################################################################"
+
+##### echo "yes" | cp -f ../../../${nthost}/WIN40/${nthost}-enumdrivers3list-WIN40.txt . 2> /dev/null ;
+ ln -s -f ../${nthost}-enumdrivers3list-WIN40.txt ${nthost}-enumdrivers3list-WIN40.lnk ;
+
+ tac ${nthost}-enumdrivers3list-WIN40.lnk \
+ | sed -e '/'"$(basename "$(echo "$PWD")")"'/,/Version/ p' -n \
+ | grep Version \
+ | uniq \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print "mkdir \"" $1 "\"" }' \
+ | tee mkversiondir.txt ;
+
+ sh mkversiondir.txt 2> /dev/null ;
+
+ cat ${nthost}-enumdrivers3list-WIN40.lnk \
+ | sed -e '/\['"$(basename "$(echo "$PWD")")"'\]/,/Monitor/ w alldriverfiles.txt' -n ;
+
+ for i in */; do
+ CWD2="$( pwd )" ;
+ cd "${i}";
+ echo "yes" | cp ../alldriverfiles.txt . 2> /dev/null ;
+
+ cat alldriverfiles.txt \
+ | egrep '(\\'"$(basename "$( pwd )")"'\\|Driver Name)' \
+ | tee driverfilesversion.txt ;
+
+ Drivername=$( grep "Driver Name:" driverfilesversion.txt \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print $1 }' \
+ | sort -f \
+ | uniq \
+ | tee Drivername ) ;
+
+ DriverPath=$( grep "Driver Path:" driverfilesversion.txt \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print $1 }' \
+ | awk -F "WIN40" '{ print $2 }' \
+ | awk -F "\\" '{ print $3 }' \
+ | sort -f \
+ | uniq ) ;
+ echo "${DriverPath}" \
+ | tee DriverPath ;
+
+ Datafile=$( grep "Datafile:" driverfilesversion.txt \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print $1 }' \
+ | awk -F "WIN40" '{ print $2 }' \
+ | awk -F "\\" '{ print $3 }' \
+ | sort -f \
+ | uniq ) ;
+ echo "${Datafile}" \
+ | tee Datafile ;
+
+ Configfile=$( grep "Configfile:" driverfilesversion.txt \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print $1 }' \
+ | awk -F "WIN40" '{ print $2 }' \
+ | awk -F "\\" '{ print $3 }' \
+ | sort -f \
+ | uniq ) ;
+ echo "${Configfile}" \
+ | tee Configfile ;
+
+ Helpfile=$( grep "Helpfile:" driverfilesversion.txt \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print $1 }' \
+ | awk -F "WIN40" '{ print $2 }' \
+ | awk -F "\\" '{ print $3 }' \
+ | sort -f \
+ | uniq ) ;
+ echo "${Helpfile}" \
+ | tee Helpfile ;
+
+ Dependentfilelist=$( grep "Dependentfiles:" driverfilesversion.txt \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print $1 }' \
+ | awk -F "WIN40" '{ print $2 }' \
+ | awk -F "\\" '{ print $3 }' \
+ | sort -f \
+ | uniq ) ;
+
+ Dependentfiles=$( echo $Dependentfilelist \
+ | sed -e 's/ /,/g ' ) ;
+
+ echo "${Dependentfiles}" \
+ | tee Dependentfiles
+
+ AllFiles=$( echo ${Dependentfilelist}; echo ${Helpfile}; echo ${Configfile}; echo ${Datafile}; echo ${DriverPath} );
+
+ echo "${AllFiles}" \
+ | sort -f \
+ | uniq \
+ | tee AllFiles ;
+
+ for i in $( cat AllFiles ); do echo ${i}; done \
+ | sort -f \
+ | uniq \
+ | tee AllFilesIAskFor ;
+
+ cd "${CWD2}" 1> /dev/null ;
+ done
+
+# rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" \
+# -c "adddriver \"${Architecture}\" \"${DriverName}:${DriverPath}:${Datafile}:${Configfile}:${Helpfile}:NULL:RAW:${Dependentfiles}\" ${Version}" \ ${smbhost}
+
+# rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" \
+# -c "setdriver \"${printername}\" \"${DriverName}\"" \
+# ${smbhost}
+#
+# rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" \
+# -c "setprinter \"${printername}\" \"Driver was installed and set via MS-RPC (utilized by Kurt Pfeifle\'s set of \"Vampire Printerdrivers\" scripts from Linux)\"" \
+# ${smbhost}
+
+ cd "${CWD1}" 1> /dev/null ;
+ done;
+fi
+}
+
+
+
+
+# -----------------------------------------------------------------------------
+# ---------- Split the W32X86 driverfile listing of each architecture ---------
+# ------------------------ into individual drivers ----------------------------
+# -----------------------------------------------------------------------------
+#
+
+function splitW32X86fileintoindividualdriverfiles()
+{
+if stringinstring help "$@"; then
+helpwithmakesubdirsforWIN40driverlist ;
+else
+ echo " "
+ echo " "
+ echo "--> Running now function splitW32X86fileintoindividualdriverfiles()..."
+ echo "======================================================================"
+
+ for i in ${nthost}/W32X86/*/; do
+ CWD1="$( pwd )" ;
+ cd "${i}" ;
+ echo " "
+ echo " "
+ echo " ###########################################################################################"
+ echo " "
+ echo " Next driver is \"$( basename "$( pwd)" )\""
+ echo " "
+ echo " ###########################################################################################"
+
+###### echo "yes" | cp -f ../../../${nthost}/W32X86/${nthost}-enumdrivers3list-NTx86.txt . 2> /dev/null ;
+ ln -s -f ../${nthost}-enumdrivers3list-NTx86.txt ${nthost}-enumdrivers3list-NTx86.lnk ;
+
+ tac ${nthost}-enumdrivers3list-NTx86.lnk \
+ | sed -e '/'"$(basename "$(echo "$PWD")")"'/,/Version/ p' -n \
+ | grep Version \
+ | uniq \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print "mkdir \"" $1 "\"" }' \
+ | tee mkversiondir.txt ;
+
+ sh mkversiondir.txt 2> /dev/null ;
+
+ cat ${nthost}-enumdrivers3list-NTx86.lnk \
+ | sed -e '/\['"$(basename "$(echo "$PWD")")"'\]/,/Monitor/ w alldriverfiles.txt' -n ;
+
+ for i in */; do
+ CWD2="$( pwd )" ;
+ cd "${i}";
+ echo "yes" | cp ../alldriverfiles.txt . 2> /dev/null ;
+
+ cat alldriverfiles.txt \
+ | egrep '(\\'"$(basename "$( pwd )")"'\\|Driver Name)' \
+ | tee driverfilesversion.txt ;
+
+ Drivername=$( grep "Driver Name:" driverfilesversion.txt \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print $1 }' \
+ | sort -f \
+ | uniq \
+ | tee Drivername ) ;
+# echo "${Drivername}" \
+# | tee Drivername ;
+
+
+ DriverPath=$( grep "Driver Path:" driverfilesversion.txt \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print $1 }' \
+ | awk -F "W32X86" '{ print $2 }' \
+ | awk -F "\\" '{ print $3 }' \
+ | sort -f \
+ | uniq ) ;
+ echo "${DriverPath}" \
+ | tee DriverPath ;
+
+ Datafile=$( grep "Datafile:" driverfilesversion.txt \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print $1 }' \
+ | awk -F "W32X86" '{ print $2 }' \
+ | awk -F "\\" '{ print $3 }' \
+ | sort -f \
+ | uniq ) ;
+ echo "${Datafile}" \
+ | tee Datafile ;
+
+ Configfile=$( grep "Configfile:" driverfilesversion.txt \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print $1 }' \
+ | awk -F "W32X86" '{ print $2 }' \
+ | awk -F "\\" '{ print $3 }' \
+ | sort -f \
+ | uniq ) ;
+ echo "${Configfile}" \
+ | tee Configfile ;
+
+ Helpfile=$( grep "Helpfile:" driverfilesversion.txt \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print $1 }' \
+ | awk -F "W32X86" '{ print $2 }' \
+ | awk -F "\\" '{ print $3 }' \
+ | sort -f \
+ | uniq ) ;
+ echo "${Helpfile}" \
+ | tee Helpfile ;
+
+ Dependentfilelist=$( grep "Dependentfiles:" driverfilesversion.txt \
+ | awk -F "[" '{ print $2 }' \
+ | awk -F "]" '{ print $1 }' \
+ | awk -F "W32X86" '{ print $2 }' \
+ | awk -F "\\" '{ print $3 }' \
+ | sort -f \
+ | uniq ) ;
+
+ Dependentfiles=$( echo $Dependentfilelist \
+ | sed -e 's/ /,/g ' ) ;
+
+ echo "${Dependentfiles}" \
+ | tee Dependentfiles
+
+ AllFiles=$( echo ${Dependentfilelist}; echo ${Helpfile}; echo ${Configfile}; echo ${Datafile}; echo ${DriverPath} ) ;
+
+ echo "${AllFiles}" \
+ | sort -f \
+ | uniq \
+ | tee AllFiles ;
+
+ for i in $( cat AllFiles ); do echo ${i}; done \
+ | sort -f \
+ | uniq \
+ | tee AllFilesIAskFor ;
+
+ cd "${CWD2}" 1> /dev/null ;
+ done
+
+# rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" \
+# -c "adddriver \"${Architecture}\" \"${DriverName}:${DriverPath}:${Datafile}:${Configfile}:${Helpfile}:NULL:RAW:${Dependentfiles}\" ${Version}" \ ${smbhost}
+
+# rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" \
+# -c "setdriver \"${printername}\" \"${DriverName}\"" \
+# ${smbhost}
+#
+# rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" \
+# -c "setprinter \"${printername}\" \"Driver was installed and set via MS-RPC (utilized by Kurt Pfeifle\'s set of \"Vampire Printerdrivers\" scripts from Linux)\"" \
+# ${smbhost}
+
+ cd "${CWD1}" 1> /dev/null ;
+ done;
+fi
+}
+
+
+
+# -----------------------------------------------------------------------------
+# ------------------ First download the driverfiles........... ----------------
+# -----------------------------------------------------------------------------
+#
+
+function helpwithfetchallW32X86driverfiles()
+{
+echo -e " \n\
+################################################################################
+#
+# About fetchallW32X86driverfiles()...
+# ------------------------------------
+#
+# PRECONDITIONS: 1) This function expects to have the \'\$nthost\' variable set
+# to the according value.
+# 2) This function expects to find files \"AllFiles\",
+# \"AllFilesIAskFor\", and \"AllFilesIGot\" in the directories
+# \'\${nthost}/<architecture>/<drivername>/<version>/\'.
+#
+# WHAT IT DOES: These functions use \"smbclient\" to connect to the NT print
+# server \"\$nthost\" and download the printer driver files from
+# there. To achieve that in an orderly fashion, the previously
+# created subdirectories (named like the drivers to fetch) are
+# visited in turn and the related files are downloaded for each
+# driver/directory.
+#
+# IF IT DOESN'T WORK: The function \"fetchenumdrivers3listfromNThost\" and
+# consecutive ones may not have been run successfully. This
+# is a precondition for the current function.
+#
+# HINT: The current values: 'nthost'=\"$nthost\"
+# 'ntprinteradmin'=\"$ntprinteradmin\"
+# 'ntadminpasswd'=<not shown here, check yourself!>
+#
+################################################################################"
+}
+
+# -----------------------------------------------------------------------------
+
+function fetchallW32X86driverfiles()
+{
+if stringinstring help "$@"; then
+helpwithfetchallW32X86driverfiles ;
+else
+ echo " "
+ echo " "
+ echo "--> Running now function fetchallW32X86driverfiles()...."
+ echo "========================================================"
+
+ CURRENTWD=${PWD} ;
+ for i in ${nthost}/W32X86/*/*/ ; do \
+ cd "${i}";
+
+ driverversion="$(basename "$(echo "$PWD")")" ;
+ echo "$(basename "$(echo "$PWD")")" > driverversion ;
+
+ AllFiles=$( cat AllFiles ) ;
+
+ [ -d TheFiles ] || mkdir TheFiles;
+
+ cd TheFiles;
+
+ echo " "
+ echo "===================================================="
+ echo "Downloading files now to ${PWD}....";
+ echo "===================================================="
+ echo " "
+
+ # Fetch the Driver files from the Windoze box (printserver)
+ smbclient -U"${ntprinteradmin}%${ntadminpasswd}" -d 2 \
+ //${nthost}/print\$ -c \
+ "cd W32X86\\${driverversion};prompt;mget ${AllFiles}"
+
+ ls -1 \
+ | sort -f \
+ | uniq \
+ | tee ../AllFilesIGot ;
+
+ cd ${CURRENTWD} ;
+
+ done ;
+fi
+}
+
+
+# -----------------------------------------------------------------------------
+# -------------- Now upload the driverfiles and activate them! ----------------
+# Upload files into root "Architecture" directory of Samba'a [print$] share...
+# -----------------------------------------------------------------------------
+#
+
+function helpwithuploadallW32X86drivers()
+{
+echo -e " \n\
+################################################################################
+#
+# About uploadallW32X86drivers()...
+# ---------------------------------
+#
+# PRECONDITIONS: 1) This function expects to have the '\$nthost',
+# '\$ntprinteradmin' and '\$ntadminpasswd' variables set to
+# according values.
+# 2) This function expects to find the files \"AllFiles\",
+# \"AllFilesIGot\" and \"AllFilesIAskFor\" in the
+# \"\${nthost}/W32X86<drivername>/<driverversion>/TheFiles\"
+# subdirectory.
+#
+# WHAT IT DOES: This function uses "smbclient" to connect to the new Samba print
+# server "\$nthost" and upload the printer driver files into the
+# \"[print\$]\" share there. To achieve that in orderly fashion,
+# the previously created subdirectories (named like the drivers
+# fetched previously from \$smbhost) are visited in turn and the
+# related files are uploaded for each driver/directory. For this
+# to really succeed, the files \"AllFilesIGot\" and \"AllFilesIAskFor\"
+# are compared with the help of the \"sdiff\" utility to decide
+# how to re-name the mis-matching filenams, so that the used
+# driver upload command's spelling convention is met....
+#
+# IF IT DOESN'T WORK: The function "fetchenumdrivers3listfromNThost" and
+# consecutive ones may not have been run successfully. This
+# is a precondition for the current function.
+#
+# HINT: The current values: 'nthost'=\"$nthost\"
+# 'ntprinteradmin'=\"$ntprinteradmin\"
+# 'ntadminpasswd'=<not shown here, check yourself!>
+#
+################################################################################
+# ............PRESS \"q\" TO QUIT............" \
+|less
+}
+
+# -----------------------------------------------------------------------------
+
+function uploadallW32X86drivers()
+{
+if stringinstring help "$@"; then
+helpwithuploadallW32X86drivers ;
+else
+ echo " "
+ echo " "
+ echo "--> Running now function uploadallW32X86drivers()...."
+ echo "====================================================="
+
+ for i in ${nthost}/W32X86/*/*/; do \
+ CURRENTWD=${PWD} ;
+ cd "${i}" ;
+ # we are now in [..]/W32X86/[drvrname]/[2|3]/
+
+ driverversion="$(basename "$(echo "$PWD")")" ;
+
+ echo "$(basename "$(echo "$PWD")")" > driverversion ;
+
+ cd TheFiles ;
+ # we are now in [..]/W32X86/[drvrname]/[2|3]/TheFiles
+ echo " "
+ echo "===================================================="
+ echo "Uploading driverfiles now from ${PWD}....";
+ echo "===================================================="
+ echo " "
+ set -x ;
+
+ smbclient -U"${smbprinteradmin}%${smbadminpasswd}" -d 2 \
+ //${smbhost}/print\$ \
+ -c "mkdir W32X86;cd W32X86;prompt;mput $( cat ../AllFilesIGot )";
+
+ cd .. ;
+ # we are now in [..]/W32X86/[drvrname]/[2|3]/
+
+# Now tell Samba that those files are *printerdriver* files....
+# The "adddriver" command will move them to the "0" subdir and create or
+# update the associated *.tdb files (faking the MS Windows Registry on Samba)
+ Drivername="$( cat Drivername )"
+
+ set -x ;
+ [ x"$( cat Dependentfiles)" == x"" ] && echo NULL > Dependentfiles;
+
+ sdiff -s AllFilesIGot AllFilesIAskFor \
+ | tee sdiff-of-Requested-and-Received.txt ;
+
+ [ -s sdiff-of-Requested-and-Received.txt ] \
+ || rm -f sdiff-of-Requested-and-Received.txt \
+ && cat sdiff-of-Requested-and-Received.txt > ../sdiff-of-Requested-and-Received.txt ;
+
+ cat sdiff-of-Requested-and-Received.txt \
+ | sed -e 's/^/mv /' \
+ | sed -e 's/ *|/ /' \
+ | tee rename-Received-to-Requested-case.txt ;
+
+ sh -x rename-Received-to-Requested-case.txt ;
+
+ mv rename-Received-to-Requested-case.txt rename-Received-to-Requested-case.done ;
+
+ echo " ################ B E G I N DEBUGGING STATEMENT ############"
+ echo "rpcclient -U\"${smbprinteradmin}%${smbadminpasswd}\" -d 2 \
+ -c \'adddriver \"Windows NT x86\" \"$( cat Drivername ):$( cat DriverPath ):$( cat Datafile ):$( cat Configfile ):$( cat Helpfile ):NULL:RAW:$( cat Dependentfiles )\" $( cat driverversion )" \
+ ${smbhost} \' ;
+ echo " ################ E N D DEBUGGING STATEMENT ################"
+
+ rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" -d 2 \
+ -c "adddriver \"Windows NT x86\" \"$( cat Drivername ):$( cat DriverPath ):$( cat Datafile ):$( cat Configfile ):$( cat Helpfile ):NULL:RAW:$( cat Dependentfiles )\" $( cat driverversion )" \
+ ${smbhost} ;
+
+ set +x ;
+
+ cd ${CURRENTWD} ;
+ # we are now back to where we started
+ done;
+ set +x ;
+fi
+}
+
+# Now tell Samba which printqueue this driver is associated with....
+# The "setdriver" command will do just that and create or
+# update the associated *.tdb files (faking the MS Windows Registry on Samba)
+# rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" \
+# -c "setdriver \"${printername}\" \"${DriverName}\"" \
+# ${smbhost}
+# -- NOT YET IMPLEMENTED IN THIS SCRIPT ---
+#
+
+# Now set a nice printer comment and let the world know what we've done
+# (or not.... ;-)
+# rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" \
+# -c "setprinter \"${printername}\" \"Driver was installed and set via MS-RPC (rpcclient commandline from Linux)\"" \
+# ${smbhost}
+# -- NOT YET IMPLEMENTED IN THIS SCRIPT ---
+#
+
+
+# -----------------------------------------------------------------------------
+# ------------------ First download the driverfiles........... ----------------
+# -----------------------------------------------------------------------------
+#
+
+function helpwithfetchallWIN40driverfiles()
+{
+echo -e " \n\
+################################################################################
+#
+# About fetchallWIN40driverfiles()...
+# -----------------------------------
+#
+# PRECONDITIONS: 1) This function expects to have the \$nthost variable set to
+# the according value.
+# 2) This function expects to find the \"AllFiles\" file in
+# \"\${nthost}/WIN40<drivername>/<driverversion>/TheFiles\".
+#
+# WHAT IT DOES: These functions use "smbclient" to connect to the NT print server
+# "\$nthost" and download the printer driver files from there. To
+# achieve that in an orderly fashion, the previously created
+# subdirectories (named like the drivers to fetch) are visited in
+# turn and the related files are downloaded for each
+# driver/directory.
+#
+# IF IT DOESN'T WORK: The function "fetchenumdrivers3listfromNThost" and
+# consecutive ones may not have been run successfully. This
+# is a precondition for the current function.
+#
+# HINT: The current values: 'nthost'=\"$nthost\"
+# 'ntprinteradmin'=\"$ntprinteradmin\"
+# 'ntadminpasswd'=<not shown here, check yourself!>
+#
+################################################################################
+# ............PRESS \"q\" TO QUIT............" \
+|less
+}
+
+# -----------------------------------------------------------------------------
+
+function fetchallWIN40driverfiles()
+{
+if stringinstring help "$@"; then
+helpwithfetchallWIN40driverfiles ;
+else
+ echo " "
+ echo " "
+ echo "--> Running now function fetchallWIN40driverfiles()...."
+ echo "======================================================="
+
+ CURRENTWD=${PWD} ;
+
+ for i in ${nthost}/WIN40/*/*/; do \
+ cd "${i}";
+
+ driverversion="$(basename "$(echo "$PWD")")" ;
+ echo "$(basename "$(echo "$PWD")")" > driverversion ;
+
+ AllFiles=$( cat AllFiles ) ;
+
+ [ -d TheFiles ] || mkdir TheFiles;
+
+ cd TheFiles;
+
+ echo " "
+ echo "===================================================="
+ echo "Downloading files now to ${PWD}....";
+ echo "===================================================="
+ echo " "
+
+ # Fetch the Driver files from the Windoze box (printserver)
+ smbclient -U"${ntprinteradmin}%${ntadminpasswd}" -d 2 \
+ //${nthost}/print\$ -c \
+ "cd WIN40\\${driverversion};prompt;mget ${AllFiles}" ;
+
+ ls -1 \
+ | sort -f \
+ | uniq \
+ | tee ../AllFilesIGot ;
+
+ cd ${CURRENTWD} ;
+
+ done ;
+fi
+}
+
+
+# -----------------------------------------------------------------------------
+# -------------- Now upload the driverfiles and activate them! ----------------
+# Upload files into root "Architecture" directory of Samba'a [print$] share...
+# -----------------------------------------------------------------------------
+#
+
+function helpwithuploadallWIN40drivers()
+{
+echo -e " \n\
+################################################################################
+#
+# About uploadallWIN40drivers()...
+# --------------------------------
+#
+# PRECONDITIONS: 1) This function expects to have '\$smbhost', '\$smbprinteradmin'
+# and '\$smbadminpasswd' variables set to according values.
+# 2) This function expects to find \"AllFiles\", \"AllFilesIGot\"
+# and \"AllFilesIAskFor\" in the subdirectory
+# \"\${nthost}/WINI40/<drivername>/<driverversion>/TheFiles\".
+#
+# WHAT IT DOES: These function uses \"smbclient\" to connect to the new Samba
+# print server "\$nthost" and upload the printer driver files into
+# the \"[print\$]\" share there.
+# To achieve that in an orderly fashion, the previously created
+# subdirectories (named like the drivers fetched previously from
+# \$smbhost) are visited in turn and the related files are
+# uploaded for each driver/directory.
+# For this to really succeed, \"AllFilesIGot\" and \"AllFilesIAskFor\"
+# are compared with the help of the \"sdiff\" utility to decide
+# how to re-name the mis-matching filenams, so that the used
+# driver upload command's spelling convention is met....
+#
+# IF IT DOESN'T WORK: The function \"fetchenumdrivers3listfromNThost\" and
+# consecutive ones may not have been run successfully. This
+# is a precondition for the current function.
+#
+# HINT: The current values: 'nthost'=\"$nthost\"
+# 'ntprinteradmin'=\"$ntprinteradmin\"
+# 'ntadminpasswd'=<not shown here, check yourself!>
+#
+################################################################################
+# ............PRESS \"q\" TO QUIT............" \
+|less
+}
+function uploadallWIN40drivers()
+{
+if stringinstring help "$@"; then
+helpwithuploadallWIN40drivers ;
+else
+ echo " "
+ echo " "
+ echo "--> Running now function uploadallWIN40drivers()...."
+ echo "===================================================="
+
+ for i in ${nthost}/WIN40/*/*/; do \
+ CURRENTWD=${PWD} ;
+ cd "${i}" ;
+ # we are now in [..]/WIN40/[drvrname]/[0]/
+
+ driverversion="$(basename "$(echo "$PWD")")" ;
+
+ echo "$(basename "$(echo "$PWD")")" > driverversion ;
+
+ cd TheFiles ;
+ # we are now in [..]/WIN40/[drvrname]/[0]/TheFiles
+ echo " "
+ echo "===================================================="
+ echo "Uploading driverfiles now from ${PWD}....";
+ echo "===================================================="
+ echo " "
+ set -x ;
+
+ smbclient -U"${smbprinteradmin}%${smbadminpasswd}" -d 2 \
+ //${smbhost}/print\$ \
+ -c "mkdir WIN40;cd WIN40;prompt;mput $( cat ../AllFilesIGot )";
+
+ cd .. ;
+ # we are now in [..]/WIN40/[drvrname]/[0]/
+
+# Now tell Samba that those files are *printerdriver* files....
+# The "adddriver" command will move them to the "0" subdir and create or
+# update the associated *.tdb files (faking the MS Windows Registry on Samba)
+ Drivername="$( cat Drivername )"
+
+ set -x ;
+ [ x"$( cat Dependentfiles)" == x"" ] && echo NULL > Dependentfiles;
+
+ sdiff -s AllFilesIGot AllFilesIAskFor \
+ | tee sdiff-of-Requested-and-Received.txt ;
+
+ [ -s sdiff-of-Requested-and-Received.txt ] \
+ || rm -f sdiff-of-Requested-and-Received.txt \
+ && cat sdiff-of-Requested-and-Received.txt > ../sdiff-of-Requested-and-Received.txt ;
+
+ cat sdiff-of-Requested-and-Received.txt \
+ | sed -e 's/^/mv /' \
+ | sed -e 's/ *|/ /' \
+ | tee rename-Received-to-Requested-case.txt ;
+
+ sh -x rename-Received-to-Requested-case.txt ;
+
+ mv rename-Received-to-Requested-case.txt rename-Received-to-Requested-case.done ;
+
+ echo " ################ DEBUGGING STATEMENT "
+ echo "rpcclient -U\"${smbprinteradmin}%${smbadminpasswd}\" -d 2 \
+ -c \'adddriver \"Windows NT x86\" \"$( cat Drivername ):$( cat DriverPath ):$( cat Datafile ):$( cat Configfile ):$( cat Helpfile ):NULL:RAW:$( cat Dependentfiles )\" $( cat driverversion )" \
+ ${smbhost}\' ;
+ echo " ################ DEBUGGING STATEMENT "
+
+ rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" -d 2 \
+ -c "adddriver \"Windows 4.0\" \"$( cat Drivername ):$( cat DriverPath ):$( cat Datafile ):$( cat Configfile ):$( cat Helpfile ):NULL:RAW:$( cat Dependentfiles )\" $( cat driverversion )" \
+ ${smbhost} ;
+
+ set +x ;
+ cd ${CURRENTWD} ;
+ # we are now back to where we started
+ done;
+fi
+}
+
+# Now tell Samba which printqueue this driver is associated with....
+# The "setdriver" command will do just that and create or
+# update the associated *.tdb files (faking the MS Windows Registry on Samba)
+# rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" \
+# -c "setdriver \"${printername}\" \"${DriverName}\"" \
+# ${smbhost}
+# -- NOT YET IMPLEMENTED IN THIS SCRIPT ---
+#
+# Now set a nice printer comment and let the world know what we've done
+# (or not.... ;-)
+# rpcclient -U"${smbprinteradmin}%${smbadminpasswd}" \
+# -c "setprinter \"${printername}\" \"Driver was installed and set via MS-RPC (rpcclient commandline from Linux)\"" \
+# ${smbhost}
+# -- NOT YET IMPLEMENTED IN THIS SCRIPT ---
+#
+
+
+#source ${0} ;
+
+enumallfunctions;
diff --git a/examples/printing/prtpub.c b/examples/printing/prtpub.c
new file mode 100644
index 0000000..2839940
--- /dev/null
+++ b/examples/printing/prtpub.c
@@ -0,0 +1,237 @@
+/*
+ * Set printer capabilities in DsDriver Keys on remote printer
+ * Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2002.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This needs to be defined for certain compilers */
+#define WINVER 0x0500
+
+#include <tchar.h>
+#include <windows.h>
+#include <stdio.h>
+
+#define SAMBA_PORT _T("Samba")
+
+TCHAR *PrintLastError(void)
+{
+ static TCHAR msgtxt[1024*sizeof(TCHAR)];
+
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, GetLastError(),
+ 0, msgtxt, 0, NULL);
+
+ return msgtxt;
+}
+
+void map_orientation(HANDLE ph, TCHAR *printer, TCHAR *port)
+{
+ DWORD rot;
+ TCHAR portrait_only[] = _T("PORTRAIT\0");
+ TCHAR both[] = _T("LANDSCAPE\0PORTRAIT\0");
+
+ /* orentation of 90 or 270 indicates landscape supported, 0 means it isn't */
+ rot = DeviceCapabilities(printer, port, DC_BINNAMES, NULL, NULL);
+
+ printf("printOrientationsSupported:\n");
+
+ if (rot) {
+ printf("\tPORTRAIT\n\tLANDSCAPE\n");
+ SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printOrientationsSupported"), REG_MULTI_SZ,
+ both, sizeof(both));
+ } else {
+ printf("\tPORTRAIT\n");
+ SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printOrientationsSupported"), REG_MULTI_SZ,
+ portrait_only, sizeof(portrait_only));
+ }
+}
+
+void map_resolution(HANDLE ph, TCHAR *printer, TCHAR *port)
+{
+ DWORD num, *res, maxres = 0, i;
+
+ num = DeviceCapabilities(printer, port, DC_ENUMRESOLUTIONS, NULL, NULL);
+ if ((DWORD) -1 == num)
+ return;
+ res = malloc(num*2*sizeof(DWORD));
+ num = DeviceCapabilities(printer, port, DC_ENUMRESOLUTIONS, (BYTE *) res, NULL);
+ for (i=0; i < num*2; i++) {
+ maxres = (res[i] > maxres) ? res[i] : maxres;
+ }
+ printf("printMaxResolutionSupported: %d\n", maxres);
+ SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printMaxResolutionSupported"), REG_DWORD,
+ (BYTE *) &maxres, sizeof(maxres));
+}
+
+void map_extents(HANDLE ph, TCHAR *printer, TCHAR *port)
+{
+ DWORD extentval, xval, yval;
+
+ extentval = DeviceCapabilities(printer, port, DC_MINEXTENT, NULL, NULL);
+ xval = (DWORD) (LOWORD(extentval));
+ yval = (DWORD) (HIWORD(extentval));
+ printf("printMinXExtent: %d\n", xval);
+ printf("printMinYExtent: %d\n", yval);
+ SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printMinXExtent"), REG_DWORD, (BYTE *) &xval, sizeof(xval));
+ SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printMinYExtent"), REG_DWORD, (BYTE *) &yval, sizeof(yval));
+ extentval = DeviceCapabilities(printer, port, DC_MAXEXTENT, NULL, NULL);
+ xval = (DWORD) (LOWORD(extentval));
+ yval = (DWORD) (HIWORD(extentval));
+ printf("printMaxXExtent: %d\n", xval);
+ printf("printMaxYExtent: %d\n", yval);
+ SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printMaxXExtent"), REG_DWORD, (BYTE *) &xval, sizeof(xval));
+ SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printMaxYExtent"), REG_DWORD, (BYTE *) &yval, sizeof(yval));
+}
+
+void map_printrateunit(HANDLE ph, TCHAR *printer, TCHAR *port)
+{
+ DWORD unit;
+ TCHAR ppm[] = _T("PagesPerMinute");
+ TCHAR ipm[] = _T("InchesPerMinute");
+ TCHAR lpm[] = _T("LinesPerMinute");
+ TCHAR cps[] = _T("CharactersPerSecond");
+
+ unit = DeviceCapabilities(printer, port, DC_PRINTRATEUNIT, NULL, NULL);
+ switch(unit) {
+ case PRINTRATEUNIT_PPM:
+ printf("printRateUnit: %s\n", ppm);
+ SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printRateUnit"), REG_SZ, ppm, sizeof(ppm));
+ break;
+ case PRINTRATEUNIT_IPM:
+ printf("printRateUnit: %s\n", ipm);
+ SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printRateUnit"), REG_SZ, ipm, sizeof(ipm));
+ break;
+ case PRINTRATEUNIT_LPM:
+ printf("printRateUnit: %s\n", lpm);
+ SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printRateUnit"), REG_SZ, lpm, sizeof(lpm));
+ break;
+ case PRINTRATEUNIT_CPS:
+ printf("printRateUnit: %s\n", cps);
+ SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, _T("printRateUnit"), REG_SZ, cps, sizeof(cps));
+ break;
+ default:
+ printf("printRateUnit: unknown value %d\n", unit);
+ }
+}
+
+void map_generic_boolean(HANDLE ph, TCHAR *printer, TCHAR *port, WORD cap, TCHAR *key)
+{
+ BYTE boolval;
+ /* DeviceCapabilities doesn't always return 1 for true...just nonzero */
+ boolval = (BYTE) (DeviceCapabilities(printer, port, cap, NULL, NULL) ? 1 : 0);
+ printf("%s: %s\n", key, boolval ? "TRUE" : "FALSE");
+ SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, key, REG_BINARY, &boolval, sizeof(boolval));
+}
+
+void map_generic_dword(HANDLE ph, TCHAR *printer, TCHAR *port, WORD cap, TCHAR *key)
+{
+ DWORD dword;
+
+ dword = DeviceCapabilities(printer, port, cap, NULL, NULL);
+ if ((DWORD) -1 == dword)
+ return;
+
+ printf("%s: %d\n", key, dword);
+ SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, key, REG_DWORD, (BYTE *) &dword, sizeof(dword));
+}
+
+void map_generic_multi_sz(HANDLE ph, TCHAR *printer, TCHAR *port, WORD cap, TCHAR *key, int size)
+{
+ TCHAR *strings_in;
+ TCHAR *strings_out, *strings_cur;
+ DWORD num_items, i;
+
+ num_items = DeviceCapabilities(printer, port, cap, NULL, NULL);
+ if ((DWORD) -1 == num_items)
+ return;
+ strings_in = malloc(num_items * size);
+ strings_out = calloc(num_items, size);
+ num_items = DeviceCapabilities(printer, port, cap, strings_in, NULL);
+ printf("%s:\n", key);
+ for (i=0, strings_cur = strings_out; i < num_items; i++) {
+ _tcsncpy(strings_cur, &strings_in[i*size], size);
+ printf("\t%s\n", strings_cur);
+ strings_cur += _tcslen(strings_cur) + 1;
+ }
+
+ SetPrinterDataEx(ph, SPLDS_DRIVER_KEY, key, REG_MULTI_SZ, strings_out,
+ (strings_cur - strings_out + 1) * sizeof(TCHAR));
+
+ free(strings_in);
+ free(strings_out);
+}
+
+int main(int argc, char *argv[])
+{
+ HANDLE ph;
+ BYTE *driver_info;
+ DWORD needed;
+ TCHAR *printer;
+ TCHAR *port = SAMBA_PORT;
+ PRINTER_DEFAULTS admin_access = {NULL, NULL, PRINTER_ACCESS_ADMINISTER};
+ PRINTER_INFO_7 publish = {NULL, DSPRINT_PUBLISH};
+
+ if (argc < 2) {
+ printf("Usage: %s <printername>\n", argv[0]);
+ return -1;
+ }
+
+ printer = argv[1];
+
+ if (!(OpenPrinter(printer, &ph, &admin_access))) {
+ printf("OpenPrinter failed, error = %s\n", PrintLastError());
+ return -1;
+ }
+
+ GetPrinterDriver(ph, NULL, 1, NULL, 0, &needed);
+ if (!needed) {
+ printf("GetPrinterDriver failed, error = %s\n", PrintLastError());
+ ClosePrinter(ph);
+ return -1;
+ }
+ driver_info = malloc(needed);
+ if (!(GetPrinterDriver(ph, NULL, 1, driver_info, needed, &needed))) {
+ printf("GetPrinterDriver failed, error = %s\n", PrintLastError());
+ ClosePrinter(ph);
+ return -1;
+ }
+
+ map_generic_multi_sz(ph, printer, port, DC_BINNAMES, _T("printBinNames"), 24);
+ map_generic_boolean(ph, printer, port, DC_COLLATE, _T("printCollate"));
+ map_generic_dword(ph, printer, port, DC_COPIES, _T("printMaxCopies"));
+ map_generic_dword(ph, printer, port, DC_DRIVER, _T("driverVersion"));
+ map_generic_boolean(ph, printer, port, DC_DUPLEX, _T("printDuplexSupported"));
+ map_extents(ph, printer, port);
+ map_resolution(ph, printer, port);
+ map_orientation(ph, printer, port);
+ map_generic_multi_sz(ph, printer, port, DC_PAPERNAMES, _T("printMediaSupported"), 64);
+#if (WINVER >= 0x0500)
+ map_generic_boolean(ph, printer, port, DC_COLORDEVICE, _T("printColor"));
+ map_generic_multi_sz(ph, printer, port, DC_PERSONALITY, _T("printLanguage"), 64);
+ map_generic_multi_sz(ph, printer, port, DC_MEDIAREADY, _T("printMediaReady"),64);
+ map_generic_dword(ph, printer, port, DC_PRINTERMEM, _T("printMemory"));
+ map_generic_dword(ph, printer, port, DC_PRINTRATE, _T("printRate"));
+ map_printrateunit(ph, printer, port);
+#ifdef DC_STAPLE
+ map_generic_boolean(ph, printer, port, DC_STAPLE, _T("printStaplingSupported"));
+#endif
+#ifdef DC_PRINTRATEPPM
+ map_generic_dword(ph, printer, port, DC_PRINTRATEPPM, _T("printPagesPerMinute"));
+#endif
+#endif
+ SetPrinter(ph, 7, (BYTE *) &publish, 0);
+ ClosePrinter(ph);
+ return 0;
+}
diff --git a/examples/printing/readme.prtpub b/examples/printing/readme.prtpub
new file mode 100644
index 0000000..319ce60
--- /dev/null
+++ b/examples/printing/readme.prtpub
@@ -0,0 +1,12 @@
+prtpub.c contains a program which, when compiled with Visual C, can
+download a driver for a printer, query the capabilities of the driver,
+then write back the DsDriver keys necessary to publish all the fields
+of a printer in the directory. After writing back the fields, it issues
+a SetPrinter with info level 7, telling the server to publish the
+printer.
+
+It also writes the fields to stdout.
+
+In order to be distributed, it should be compiled using DLLs for C runtime.
+
+The program takes the UNC name of a printer as the only argument.
diff --git a/examples/printing/smbprint.sysv b/examples/printing/smbprint.sysv
new file mode 100644
index 0000000..11fea21
--- /dev/null
+++ b/examples/printing/smbprint.sysv
@@ -0,0 +1,52 @@
+#!/bin/sh
+#
+# @(#) smbprint.sysv version 1.0 Ross Wakelin <r.wakelin@march.co.uk>
+#
+# Version 1.0 13 January 1995
+# modified from the original smbprint (bsd) script
+#
+# this script is a System 5 printer interface script. It
+# uses the smbclient program to print the file to the specified smb-based
+# server and service.
+#
+# To add this to your lp system, copy this file into your samba directory
+# (the example here is /opt/samba), modify the server and service variables
+# and then execute the following command (as root)
+#
+# lpadmin -punixprintername -v/dev/null -i/opt/samba/smbprint
+#
+# where unixprintername is the name that the printer will be known as
+# on your unix box.
+#
+# the script smbprint will be copied into your printer administration
+# directory (/usr/lib/lp or /etc/lp) as a new interface
+# (interface/unixprintername)
+# Then you have to enable unixprintername and accept unixprintername
+#
+# This script will then be called by the lp service to print the files
+# This script will have 6 or more parameters passed to it by the lp service.
+# The first five will contain details of the print job, who queued it etc,
+# while parameters 6 onwards are a list of files to print. We just
+# cat these at the samba client.
+#
+# Set these to the server and service you wish to print to
+# In this example I have a WfWg PC called "lapland" that has a printer
+# exported called "printer" with no password.
+#
+# clear out the unwanted parameters
+shift;shift;shift;shift;shift
+# now the argument list is just the files to print
+
+server=admin
+service=hplj2
+password=""
+
+(
+# NOTE You may wish to add the line `echo translate' if you want automatic
+# CR/LF translation when printing.
+ echo translate
+ echo "print -"
+ cat $*
+) | /opt/samba/smbclient "\\\\$server\\$service" $password -N > /dev/null
+exit $?
+
diff --git a/examples/scripts/debugging/linux/backtrace b/examples/scripts/debugging/linux/backtrace
new file mode 100644
index 0000000..7d14ff8
--- /dev/null
+++ b/examples/scripts/debugging/linux/backtrace
@@ -0,0 +1,41 @@
+#! /bin/sh
+#
+# Author: Andrew Tridgell <tridge at samba dot org>
+
+# we want everything on stderr, so the program is not disturbed
+exec 1>&2
+
+BASENAME=$(basename $0)
+
+test -z ${GDB_BIN} && GDB_BIN=$(type -p gdb)
+if [ -z ${GDB_BIN} ]; then
+ echo "ERROR: ${BASENAME} needs an installed gdb. "
+ exit 1
+fi
+
+if [ -z $1 ]; then
+ echo "ERROR: ${BASENAME} needs a PID. "
+ exit 1
+fi
+PID=$1
+
+# use /dev/shm as default temp directory
+test -d /dev/shm &&
+ TMP_BASE_DIR=/dev/shm ||
+ TMP_BASE_DIR=/var/tmp
+TMPFILE=$(mktemp -p ${TMP_BASE_DIR} backtrace.XXXXXX)
+if [ $? -ne 0 ]; then
+ echo "ERROR: ${basename} can't create temp file in ${TMP_BASE_DIR}. "
+ exit 1
+fi
+
+cat <<EOF >"${TMPFILE}"
+set height 0
+up 8
+bt full
+quit
+EOF
+
+${GDB_BIN} -x "${TMPFILE}" "/proc/${PID}/exe" "${PID}"
+
+/bin/rm -f "${TMPFILE}"
diff --git a/examples/scripts/debugging/smbXsrvdump b/examples/scripts/debugging/smbXsrvdump
new file mode 100755
index 0000000..f5c3091
--- /dev/null
+++ b/examples/scripts/debugging/smbXsrvdump
@@ -0,0 +1,87 @@
+#!/usr/bin/env python3
+
+import sys
+
+sys.path.insert(0, "bin/python")
+
+import os
+import argparse
+import struct
+
+from samba.ndr import ndr_unpack, ndr_print
+from samba.dcerpc import smbXsrv
+from samba.dcerpc import server_id
+import tdb
+
+def print_watchers(num_watched, blob):
+ for i in range(0,num_watched):
+ id = ndr_unpack(server_id.server_id, blob[:24])
+ print(ndr_print(id))
+ blob = blob[24:]
+
+def print_record(data, ndr_type, watched, ctdb):
+ blob = data
+
+ if ctdb:
+ (rsn, dmaster, reserved1, flags) = struct.unpack('QIII', bytes(blob[:20]))
+ blob = blob[24:]
+ print(" ctdb record header: rsn=%lu, dmaster=%u, reserved1=0x%x, flags=0x%x len=%u" %
+ (rsn, dmaster, reserved1, flags, len(blob)))
+ if len(blob) == 0:
+ return
+
+ if watched:
+ (num_watched, ) = struct.unpack('I', bytes(blob[:4]))
+ blob = blob[4:]
+
+ deleted_bit = 1<<31
+ deleted = num_watched & deleted_bit
+
+ num_watched = num_watched & ~deleted_bit
+ if num_watched > 0:
+ if deleted:
+ deleted_str = "yes"
+ else:
+ deleted_str = "no"
+ print(" num_watched: %d, deleted: %s" % (num_watched, deleted_str))
+ print_watchers(num_watched, blob)
+ blob = blob[num_watched*4:]
+
+ unpacked = ndr_unpack(ndr_type, blob, allow_remaining=True)
+ print(ndr_print(unpacked))
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument('path', help='Path to the TDB file')
+ parser.add_argument('-c', '--ctdb',
+ default=False,
+ action="store_true",
+ help='The TDB database is from a ctdb cluster')
+ args = parser.parse_args()
+
+ watched = False
+ if 'smbXsrv_session' in args.path:
+ ndr_type = smbXsrv.session_globalB
+ watched = True
+ elif 'smbXsrv_open' in args.path:
+ ndr_type = smbXsrv.open_globalB
+ elif 'smbXsrv_client' in args.path:
+ ndr_type = smbXsrv.client_globalB
+ watched = True
+ elif 'smbXsrv_tcon' in args.path:
+ ndr_type = smbXsrv.tcon_globalB
+ elif 'smbXsrv_version' in args.path:
+ ndr_type = smbXsrv.version_globalB
+ else:
+ raise Exception("Failed to guess NDR type")
+
+ tdb = tdb.Tdb(args.path, 0, tdb.INCOMPATIBLE_HASH, os.O_RDONLY)
+
+ i = 1
+ for k in tdb.keys():
+ data = tdb.get(k)
+ print("Record: %d" % i)
+ print_record(data, ndr_type, watched, args.ctdb)
+ i = i + 1
+
+ tdb.close()
diff --git a/examples/scripts/debugging/solaris/README b/examples/scripts/debugging/solaris/README
new file mode 100644
index 0000000..9e33680
--- /dev/null
+++ b/examples/scripts/debugging/solaris/README
@@ -0,0 +1,28 @@
+Last update: John H Terpstra - June 27, 2005
+
+Subject: This directory will contain debugging tools and tips.
+
+Notes: Identification and confirmation of some bugs can be difficult.
+ When such bugs are encountered it is necessary to provide as
+ sufficient detailed debugging information to assist the developer
+ both by providing incontrivertable proof of the problem, but also
+ precise information regarding the values of variables being processed
+ at the time the problem strikes.
+
+ This directory is the ideal place to locate useful hints, tips and
+ methods that will help Samba users to provide the information that
+ developers need.
+
+============================ Solaris Method A ==============================
+File: solaris-oops.sh
+Contributor: David Collier-Brown
+Date: June 27, 2005
+Method and Use:
+To the global stanza of smb.conf add:
+ panic action = /usr/local/bin/solaris-oops.sh %d
+
+When the panic action is initiated a voluntary core dump file will be placed
+in /var/tmp. Use this method with "log level = 10" and an smbd binary that
+has been built with the '-g' option.
+============================================================================
+
diff --git a/examples/scripts/debugging/solaris/solaris-oops.sh b/examples/scripts/debugging/solaris/solaris-oops.sh
new file mode 100644
index 0000000..2d8587d
--- /dev/null
+++ b/examples/scripts/debugging/solaris/solaris-oops.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+#
+# solaris_panic_action -- capture supporting information after a failure
+#
+ProgName=$(basename $0)
+LOGDIR=/usr/local/samba/var
+
+main()
+{
+ pid=$1
+
+ if [ $# -lt 1 ]; then
+ say "$ProgName error: you must supply a pid"
+ say "Usage: $0 pid"
+ exit 1
+ fi
+ cat >>$LOGDIR/log.solaris_panic_action <<!
+
+$(date)
+State information and vountary core dump for process $pid
+
+Related processes were:
+$(/usr/bin/ptree $pid)
+
+Stack(s) were:
+$(/usr/bin/pstack $pid)
+
+Flags were:
+$(/usr/bin/pflags $pid)
+
+Credentials were:
+$(/usr/bin/pcred $pid)
+
+Libraries used were:
+$(/usr/bin/pldd $pid)
+
+Signal-handler settings were:
+$(/usr/bin/psig $pid)
+
+Files and devices in use were:
+$(/usr/bin/pfiles $pid)
+
+Directory in use was:
+$(/usr/bin/pwdx $pid)
+
+
+A voluntary core dump was placed in /var/tmp/samba_solaris_panic_action_gcore.$pid
+$(gcore -o /var/tmp/samba_solaris_panic_action_gcore $pid)
+!
+}
+
+say()
+{
+ echo "$@" 1>&2
+}
+
+main "$@"
diff --git a/examples/scripts/eventlog/parselog.pl b/examples/scripts/eventlog/parselog.pl
new file mode 100644
index 0000000..a2f9a27
--- /dev/null
+++ b/examples/scripts/eventlog/parselog.pl
@@ -0,0 +1,32 @@
+#!/usr/bin/perl
+######################################################################
+##
+## Simple parselog script for Samba
+##
+## Copyright (C) Brian Moran 2005.
+##
+## 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 3 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, see <http://www.gnu.org/licenses/>.
+##
+######################################################################
+
+## usage: tail -f /var/log/syslog | parselog.pl | eventlogadm -o write "Application"
+
+while(<>) {
+ chomp();
+ @le = split '\s+',$_,5;
+ $ln = $le[4];
+ $cname = $le[3];
+ $outstr = sprintf "TMG: %d\nTMW: %d\nEID: 1000\nETP: INFO\nECT: 0\nRS2: 0\nCRN: 0\nUSL: 0\nSRC: Syslog\nSRN: $cname\nSTR: $ln\nDAT:\n\n",time(),time();
+ print $outstr;
+}
diff --git a/examples/scripts/idmap/README b/examples/scripts/idmap/README
new file mode 100644
index 0000000..a8637bb
--- /dev/null
+++ b/examples/scripts/idmap/README
@@ -0,0 +1,168 @@
+idmap script option for flexible UID/GID handling
+-------------------------------------------------
+
+If you are using "idmap backend = tdb2" with winbind in Samba3, then
+you have the option of specifying an external script to perform
+uid/gid allocation. This can be useful in situations where you are
+using AD for authentication, but the AD server is not configured to
+supply uid/gid mappings via the services for unix extensions and you
+have a need to support a pre-existing system for uid/gid allocation.
+
+One common situation where this arises is where you have a mixture of
+NFS and CIFS clients, and the NFS clients are configured to use NIS
+for their id mapping. It is quite common to have an administrative
+mechanism in place to ensure that all of the NIS users have a
+corresponding AD user account, but there may be no direct mechanism to
+ensure that any unix uid/gid attributes in AD match those in NIS.
+
+In this situation it would normally not be possible to share files
+with correct ownership between the CIFS and NFS clients, as winbind
+would normally allocate its own set of UIDs from a reserved pool, and
+those uids won't match the existing ones in NIS.
+
+The idmap script option
+-----------------------
+
+To resolve this problem the idmap tdb2 module has the ability to call
+out to an external script whenever it needs an unknown SID or UID/GID
+for the first time. It is then the job of that script to provide a
+mapping consistent with whatever external system is in place (such as
+NIS), and return the mapped result to winbind.
+
+Winbind will then persistently store the result of the mapping, so
+that the script is not invoked more than once per user/group.
+
+To setup the idmap script you need to set the following options:
+
+ idmap backend = tdb2
+ idmap script = /usr/local/bin/idmap.sh
+
+where the location and name of the script is arbitrary. It just needs
+to be executable by winbind.
+
+You then need to stop Samba, delete the key idmap cache files, and
+restart Samba. The idmap files that need to be deleted are:
+
+ - gencache.tdb
+ - winbindd_cache.tdb
+ - idmap2.tdb
+
+
+Script operation
+----------------
+
+The script will be called by winbind in one of three ways.
+
+ 1) idmap.sh SIDTOID <SID>
+ 2) idmap.sh IDTOSID UID <UID>
+ 2) idmap.sh IDTOSID GID <GID>
+
+In the first form the script is being asked to map a windows SID (in
+the string form "S-*") to a UID or GID. In the second form the script
+is being asked to map a UID to a SID, and in the third form it is
+being asked to map a GID to a SID.
+
+SIDTOID
+-------
+
+In the first form the script is expected to output a UID or GID given
+a SID. The output format is expected to be like this:
+
+ UID:1234
+or
+ GID:1122
+
+If the SID cannot be found, then the script should output an error
+like this:
+
+ ERR:Some error message
+
+Note that it is common for the external mechanism to not know about
+windows SIDs, in which case the script may use the wbinfo command to
+ask winbind to change the SID into a username or group name. The
+"wbinfo -s" option is the one to use.
+
+
+IDTOSID UID
+-----------
+
+In this form the script is expected to turn a UID into a SID,
+returning a result like this:
+
+ SID:S-1-5-21-1110277820-2343689819-414998773-1124
+
+or an error like this:
+
+ ERR:Some error message
+
+If the external mechanism that the script wants to use cannot produce
+a SID, but can produce a username, then the script can convert the
+username to a SID using the "wbinfo -n" option.
+
+IDTOSID GID
+-----------
+
+In this form the script is expected to turn a GID into a SID,
+returning a result like this:
+
+ SID:S-1-5-21-1110277820-2343689819-414998773-1120
+
+or an error like this:
+
+ ERR:Some error message
+
+If the external mechanism that the script wants to use cannot produce
+a SID, but can produce a group name, then the script can convert the
+groupname to a SID using the "wbinfo -n" option.
+
+
+Testing the script
+------------------
+
+It is suggested that you test the script on the command line first,
+before using it in winbind. To do that first get a list of users you
+would like to test using the command "wbinfo -u". Let's assume one of
+those users is "DC01\tridge". You would then test the script as
+follows:
+
+ [root ~]# wbinfo -n 'DC01\tridge'
+ S-1-5-21-1110277820-2343689819-414998773-1124 User (1)
+
+ [root ~]# /usr/local/bin/idmap.sh SIDTOID S-1-5-21-1110277820-2343689819-414998773-1124
+ UID:1003
+
+ [root ~]# /usr/local/bin/idmap.sh IDTOSID UID 1003
+ SID:S-1-5-21-1110277820-2343689819-414998773-1124
+
+Once those steps pass, you can enable the script in winbind
+(remembering to clear the cache tdbs), and test using the id command:
+
+ [root ~]# id 'DC01\tridge'
+ uid=1003(DC01\tridge) gid=10000009(DC01\domain users)
+
+
+nsswitch.conf
+-------------
+
+When using the idmap script option you setup nsswitch.conf as usual
+for winbind, with one addition. If your external idmap mechanism
+support nsswitch then you may optionally choose to add it to
+nsswitch.conf, but you must add it after the winbind entry. So for
+example, if using NIS, you could have a nsswitch.conf entry like this:
+
+ passwd: files winbind nis
+ group: files winbind nis
+
+Adding this to nsswitch.conf is not essential, but may be useful for
+some local administration tools.
+
+Sample script
+-------------
+
+This directory contains a simple example script 'idmap_nis.sh' that
+provides idmap script support for NIS. To use it you first need to
+enable the NIS client on your Samba server, usually by configuring
+/etc/yp.conf. See the manual page for yp.conf for details.
+
+You should test the ypcat and ypmatch commands and make sure they work
+before enabling the idmap_nis.sh script.
diff --git a/examples/scripts/idmap/idmap_nis.sh b/examples/scripts/idmap/idmap_nis.sh
new file mode 100755
index 0000000..a5ea79d
--- /dev/null
+++ b/examples/scripts/idmap/idmap_nis.sh
@@ -0,0 +1,120 @@
+#!/bin/bash
+# idmap script to map SIDs to UIDs/GIDs using NIS
+# tridge@samba.org June 2009
+
+DOMAIN=$(ypdomainname)
+
+(
+ date
+ echo $*
+) >>/var/log/samba/idmap.log
+
+cmd=$1
+shift
+
+PATH=/usr/bin:bin:$PATH
+
+shopt -s nocasematch || {
+ echo "shell option nocasematch not supported"
+ exit 1
+}
+
+# map from a domain and name to a uid/gid
+map_name()
+{
+ domain="$1"
+ name="$2"
+ ntype="$3"
+ case $ntype in
+ 1)
+ rtype="UID"
+ map="passwd"
+ ;;
+ 2)
+ rtype="GID"
+ map="group"
+ ;;
+ *)
+ echo "ERR: bad name type $ntype"
+ exit 1
+ ;;
+ esac
+ id=$(ypmatch "$name" "$map".byname 2>/dev/null | cut -d: -f3)
+ [ -z "$id" ] && {
+ echo "ERR: bad match for $name in map $map"
+ exit 1
+ }
+ echo "$rtype":"$id"
+}
+
+# map from a unix id to a name
+map_id()
+{
+ ntype="$1"
+ id="$2"
+ case $ntype in
+ UID)
+ map="passwd.byuid"
+ ;;
+ GID)
+ map="group.bygid"
+ ;;
+ *)
+ echo "ERR: bad name type $ntype"
+ exit 1
+ ;;
+ esac
+ name="$(ypmatch "$id" "$map" 2>/dev/null | cut -d: -f1)"
+ [ -z "$name" ] && {
+ echo "ERR: bad match for $name in map $map"
+ exit 1
+ }
+ echo "$name"
+}
+
+case $cmd in
+SIDTOID)
+ sid=$1
+ rid=$(echo $sid | cut -d- -f8)
+ [ -z "$rid" ] && {
+ echo "ERR: bad rid in SID $sid"
+ exit 1
+ }
+
+ unset _NO_WINBINDD
+ # oh, this is ugly. Shell is just not meant for parsing text
+ fullname=$(wbinfo -s $sid 2>/dev/null)
+ domain=$(echo $fullname | cut -d'\' -f1)
+ [[ "$domain" = $DOMAIN ]] || {
+ echo "ERR: bad domain $domain"
+ exit 1
+ }
+ name=$(echo $fullname | cut -d'\' -f2)
+ nwords=$(echo $name | wc -w)
+ ntype=$(echo $name | cut -d' ' -f$nwords)
+ nminusone=$(expr $nwords - 1)
+ name=$(echo $name | cut -d' ' -f-$nminusone)
+ [ -z "$name" ] && {
+ echo "ERR: bad name $fullname for SID $sid"
+ exit 1
+ }
+ map_name "$domain" "$name" "$ntype"
+ ;;
+IDTOSID)
+ ntype=$1
+ id=$2
+ name="$(map_id "$ntype" "$id")"
+ sid="$(wbinfo -n "$name" 2>/dev/null | cut -d' ' -f1)"
+ [ -z "$sid" ] && {
+ echo "ERR: name $name not found in ADS"
+ exit 1
+ }
+ echo "SID:$sid"
+ ;;
+*)
+ echo "ERR: Unknown command $cmd"
+ exit 1
+ ;;
+esac
+
+exit 0
diff --git a/examples/scripts/mount/mount.smbfs b/examples/scripts/mount/mount.smbfs
new file mode 100644
index 0000000..3b57bc5
--- /dev/null
+++ b/examples/scripts/mount/mount.smbfs
@@ -0,0 +1,115 @@
+#!/bin/bash
+# Debian mount.smbfs compatibility wrapper
+# Copyright 2007, Steve Langasek <vorlon at debian.org>
+# Licensed under the GNU General Public License, version 2. See the
+# file /usr/share/common-licenses/GPL or <http://www.gnu.org/copyleft/gpl.txt>.
+
+# This script accepts all documented mount options for mount.smbfs,
+# passing through those that are also recognized by mount.cifs,
+# converting those that are not recognized but map to available cifs
+# options, and warning about the use of options for which no equivalent
+# exists.
+
+# known bugs: quoted spaces in arguments are not passed intact
+
+set -e
+
+# reverse the order of username and password in a "username" parameter,
+# taking care to leave any "%password" bit intact
+
+reverse_username_workgroup() {
+ local workgroup password username
+
+ username="$1"
+ case "$username" in
+ *%*) password="${username#*%}"
+ username="${username%%%*}"
+ ;;
+ *) ;;
+ esac
+ case "$username" in
+ */*) workgroup="${username#*/}"
+ username="${username%%/*}"
+ ;;
+ *) ;;
+ esac
+ if [ -n "$workgroup" ]; then
+ username="$workgroup\\$username"
+ fi
+ if [ -n "$password" ]; then
+ username="$username%$password"
+ fi
+ echo "$username"
+}
+
+
+# parse out the mount options that have been specified using -o, and if
+# necessary, convert them for use by mount.cifs
+
+parse_mount_options () {
+ local OLD_IFS IFS options option username
+ OLD_IFS="$IFS"
+ IFS=","
+ options=""
+ workgroup=""
+ password=""
+
+ for option in $@; do
+ case "$option" in
+ sockopt=* | scope=* | codepage=* | ttl=* | debug=*)
+ echo "Warning: ignoring deprecated smbfs option '$option'" >&2
+ ;;
+
+ krb)
+ options="$options${options:+,}sec=krb5"
+ ;;
+
+ guest)
+ echo "Warning: mapping 'guest' to 'guest,sec=none'" >&2
+ options="$options${options:+,}guest,sec=none"
+ ;;
+
+ # username and workgroup are reversed in username= arguments,
+ # so need to be parsed out
+ username=*/*)
+ IFS="$OLD_IFS"
+ username="${option#username=}"
+ username="$(reverse_username_workgroup "$username")"
+ IFS=","
+ options="$options${options:+,}username=$username"
+ ;;
+
+ *)
+ options="$options${options:+,}$option"
+ ;;
+ esac
+ done
+ IFS="$OLD_IFS"
+ echo $options
+}
+
+args=()
+while [ "$#" -gt 0 ]; do
+ case "$1" in
+ -o*)
+ arg=${1#-o}
+ shift
+ if [ -z "$arg" ]; then
+ arg=$1
+ shift
+ fi
+ arg="$(parse_mount_options "$arg")"
+ if [ -n "$arg" ]; then
+ args=("${args[@]}" "-o" "$arg")
+ fi
+ ;;
+ *)
+ args=("${args[@]}" "$1")
+ shift
+ ;;
+ esac
+done
+
+USER="$(reverse_username_workgroup "$USER")"
+
+exec /sbin/mount.cifs "${args[@]}"
diff --git a/examples/scripts/nmb/findsmb b/examples/scripts/nmb/findsmb
new file mode 100755
index 0000000..5c668f3
--- /dev/null
+++ b/examples/scripts/nmb/findsmb
@@ -0,0 +1,160 @@
+#!/usr/bin/env perl
+#
+# Prints info on all smb responding machines on a subnet.
+# This script needs to be run on a machine without nmbd running and be
+# run as root to get correct info from WIN95 clients.
+#
+# syntax:
+# findsmb [-d|-D] [-r] [subnet broadcast address]
+#
+# with no argument it will list machines on the current subnet
+#
+# There will be a "+" in front of the workgroup name for machines that are
+# local master browsers for that workgroup. There will be an "*" in front
+# of the workgroup name for machines that are the domain master browser for
+# that workgroup.
+#
+# Options:
+#
+# -d|-D enable debug
+# -r add -r option to nmblookup when finding netbios name
+#
+
+$SAMBABIN = "/usr/bin";
+
+for ($i = 0; $i < 2; $i++) { # test for -d and -r options
+ $_ = shift;
+ if (m/-d|-D/) {
+ $DEBUG = 1;
+ } elsif (m/-r/) {
+ $R_OPTION = "-r";
+ }
+}
+
+if ($_) { # set broadcast address if it was specified
+ $BCAST = "-B $_";
+}
+
+
+######################################################################
+# do numeric sort on last field of IP address
+sub ipsort
+{
+ @t1 = split(/\./,$a);
+ @t2 = split(/\./,$b);
+ @t1[3] <=> @t2[3];
+}
+######################################################################
+
+# look for all machines that respond to a name lookup
+
+open(NMBLOOKUP,"$SAMBABIN/nmblookup $BCAST '*' --debuglevel=0|") ||
+ die("Can't run nmblookup '*'.\n");
+
+# get rid of all lines that are not a response IP address,
+# strip everything but IP address and sort by last field in address
+
+@ipaddrs = sort ipsort grep(s/ \*<00>.*$//,<NMBLOOKUP>);
+
+# print header info
+print "\n *=DMB\n";
+print " +=LMB\n";
+print "IP ADDR NETBIOS NAME WORKGROUP/OS/VERSION $BCAST\n";
+print "---------------------------------------------------------------------\n";
+
+foreach $ip (@ipaddrs) # loop through each IP address found
+{
+ $ip =~ s/\n//; # strip newline from IP address
+
+ # find the netbios names registered by each machine
+
+ open(NMBLOOKUP,"$SAMBABIN/nmblookup $R_OPTION -A $ip --debuglevel=0|") ||
+ die("Can't get nmb name list.\n");
+ @nmblookup = <NMBLOOKUP>;
+ close NMBLOOKUP;
+
+ # get the first <00> name
+
+ @name = grep(/<00>/,@nmblookup);
+ $_ = @name[0];
+
+ if ($_) { # we have a netbios name
+ if (/GROUP/) { # is it a group name
+ ($name, $aliases, $type, $length, @addresses) =
+ gethostbyaddr(pack('C4',split('\.',$ip)),2);
+ if (! $name) { # could not get name
+ $name = "unknown nis name";
+ }
+ } else {
+ # The Netbios name can contain lot of characters also '<' '>'
+ # and spaces. The following cure inside name space but not
+ # names starting or ending with spaces
+ /(.{1,15})\s+<00>\s+/;
+ $name = $1;
+ $name =~ s/^\s+//g;
+ }
+
+ # do an smbclient command on the netbios name.
+
+ if ( "$name" ) {
+ open(SMB,"$SAMBABIN/smbclient -L $name -I $ip -N --debuglevel=1 2>&1 |") ||
+ die("Can't do smbclient command.\n");
+ @smb = <SMB>;
+ close SMB;
+
+ if ($DEBUG) { # if -d flag print results of nmblookup and smbclient
+ print "===============================================================\n";
+ print @nmblookup;
+ print @smb;
+ }
+
+ # look for the OS= string
+
+ @info = grep(/OS=/,@smb);
+ $_ = @info[0];
+ if ($_) { # we found response
+ s/Domain=|OS=|Server=|\n//g; # strip out descriptions to make line shorter
+
+ } else { # no OS= string in response (WIN95 client)
+
+ # for WIN95 clients get workgroup name from nmblookup response
+ @name = grep(/<00> - <GROUP>/,@nmblookup);
+ $_ = @name[0];
+ if ($_) {
+ # Same as before for space and characters
+ /(.{1,15})\s+<00>\s+/;
+ $_ = "[$1]";
+ } else {
+ $_ = "Unknown Workgroup";
+ }
+ }
+ }
+
+ # see if machine registered a local master browser name
+ if (grep(/<1d>/,@nmblookup)) {
+ $master = '+'; # indicate local master browser
+ if (grep(/<1b>/,@nmblookup)) { # how about domain master browser?
+ $master = '*'; # indicate domain master browser
+ }
+ } else {
+ $master = ' '; # not a browse master
+ }
+
+ # line up info in 3 columns
+
+ print "$ip".' 'x(16-length($ip))."$name".' 'x(14-length($name))."$master"."$_\n";
+
+ } else { # no netbios name found
+ # try getting the host name
+ ($name, $aliases, $type, $length, @addresses) =
+ gethostbyaddr(pack('C4',split('\.',$ip)),2);
+ if (! $name) { # could not get name
+ $name = "unknown nis name";
+ }
+ if ($DEBUG) { # if -d flag print results of nmblookup
+ print "===============================================================\n";
+ print @nmblookup;
+ }
+ print "$ip".' 'x(16-length($ip))."$name\n";
+ }
+}
diff --git a/examples/scripts/nmb/findsmb.1.xml b/examples/scripts/nmb/findsmb.1.xml
new file mode 100644
index 0000000..6b35410
--- /dev/null
+++ b/examples/scripts/nmb/findsmb.1.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
+<refentry id="findsmb.1">
+
+<refmeta>
+ <refentrytitle>findsmb</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo class="source">Samba</refmiscinfo>
+ <refmiscinfo class="manual">User Commands</refmiscinfo>
+ <refmiscinfo class="version">&doc.version;</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+ <refname>findsmb</refname>
+ <refpurpose>list info about machines that respond to SMB
+ name queries on a subnet</refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+ <cmdsynopsis>
+ <command>findsmb</command>
+ <arg choice="opt">subnet broadcast address</arg>
+ </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+ <title>DESCRIPTION</title>
+
+ <para>This perl script is part of the <citerefentry>
+ <refentrytitle>samba</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ suite.</para>
+
+ <para><command>findsmb</command> is a perl script that
+ prints out several pieces of information about machines
+ on a subnet that respond to SMB name query requests.
+ It uses <citerefentry><refentrytitle>nmblookup</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ and <citerefentry><refentrytitle>smbclient</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ to obtain this information.
+ </para>
+</refsect1>
+
+<refsect1>
+ <title>OPTIONS</title>
+
+ <variablelist>
+ <varlistentry>
+ <term>-r</term>
+ <listitem><para>Controls whether <command>findsmb</command> takes
+ bugs in Windows95 into account when trying to find a Netbios name
+ registered of the remote machine. This option is disabled by default
+ because it is specific to Windows 95 and Windows 95 machines only.
+ If set, <citerefentry><refentrytitle>nmblookup</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ will be called with <constant>-B</constant> option.</para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>subnet broadcast address</term>
+ <listitem><para>Without this option, <command>findsmb
+ </command> will probe the subnet of the machine where
+ <citerefentry><refentrytitle>findsmb</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ is run. This value is passed to
+ <citerefentry><refentrytitle>nmblookup</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ as part of the <constant>-B</constant> option.</para></listitem>
+ </varlistentry>
+ </variablelist>
+</refsect1>
+
+<refsect1>
+ <title>EXAMPLES</title>
+
+ <para>The output of <command>findsmb</command> lists the following
+ information for all machines that respond to the initial
+ <command>nmblookup</command> for any name: IP address, NetBIOS name,
+ Workgroup name, operating system, and SMB server version.</para>
+
+ <para>There will be a '+' in front of the workgroup name for
+ machines that are local master browsers for that workgroup. There
+ will be an '*' in front of the workgroup name for
+ machines that are the domain master browser for that workgroup.
+ Machines that are running Windows for Workgroups, Windows 95 or
+ Windows 98 will
+ not show any information about the operating system or server
+ version.</para>
+
+ <para>The command with <constant>-r</constant> option
+ must be run on a system without <citerefentry>
+ <refentrytitle>nmbd</refentrytitle><manvolnum>8</manvolnum>
+ </citerefentry> running.
+
+ If <command>nmbd</command> is running on the system, you will
+ only get the IP address and the DNS name of the machine. To
+ get proper responses from Windows 95 and Windows 98 machines,
+ the command must be run as root and with <constant>-r</constant>
+ option on a machine without <command>nmbd</command> running.</para>
+
+ <para>For example, running <command>findsmb</command>
+ without <constant>-r</constant> option set would yield output similar
+ to the following</para>
+
+<programlisting>
+IP ADDR NETBIOS NAME WORKGROUP/OS/VERSION
+---------------------------------------------------------------------
+192.168.35.10 MINESET-TEST1 [DMVENGR]
+192.168.35.55 LINUXBOX *[MYGROUP] [Unix] [Samba 2.0.6]
+192.168.35.56 HERBNT2 [HERB-NT]
+192.168.35.63 GANDALF [MVENGR] [Unix] [Samba 2.0.5a for IRIX]
+192.168.35.65 SAUNA [WORKGROUP] [Unix] [Samba 1.9.18p10]
+192.168.35.71 FROGSTAR [ENGR] [Unix] [Samba 2.0.0 for IRIX]
+192.168.35.78 HERBDHCP1 +[HERB]
+192.168.35.88 SCNT2 +[MVENGR] [Windows NT 4.0] [NT LAN Manager 4.0]
+192.168.35.93 FROGSTAR-PC [MVENGR] [Windows 5.0] [Windows 2000 LAN Manager]
+192.168.35.97 HERBNT1 *[HERB-NT] [Windows NT 4.0] [NT LAN Manager 4.0]
+</programlisting>
+
+</refsect1>
+
+
+<refsect1>
+ <title>VERSION</title>
+
+ <para>This man page is part of version &doc.version; of
+ the Samba suite.</para>
+</refsect1>
+
+<refsect1>
+ <title>SEE ALSO</title>
+ <para><citerefentry>
+ <refentrytitle>nmbd</refentrytitle><manvolnum>8</manvolnum>
+ </citerefentry>,
+ <citerefentry><refentrytitle>smbclient</refentrytitle><manvolnum>1</manvolnum>
+ </citerefentry>, and <citerefentry><refentrytitle>nmblookup</refentrytitle>
+ <manvolnum>1</manvolnum></citerefentry>
+ </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>
+</refsect1>
+
+</refentry>
diff --git a/examples/scripts/printing/cups/smbaddprinter.pl b/examples/scripts/printing/cups/smbaddprinter.pl
new file mode 100755
index 0000000..aee2020
--- /dev/null
+++ b/examples/scripts/printing/cups/smbaddprinter.pl
@@ -0,0 +1,39 @@
+#!/usr/bin/perl
+## Add printer script for samba, APW, and cups
+## Copyright (C) Jeff Hardy <hardyjm@potsdam.edu> 2004
+##
+## 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 3 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, see <http://www.gnu.org/licenses/>.
+
+@argv = @ARGV;
+
+# take in args
+my $lpname=shift(@argv); # printer name
+my $shname=shift(@argv); # share name -> used for CUPS queue name
+my $portname=shift(@argv); # port name
+my $drivername=shift(@argv); # driver name -> used for CUPS description
+my $location=shift(@argv); # location -> used for CUPS device URI
+my $win9x=shift(@argv); # win9x location
+
+#check for location syntax
+#if no protocol specified...
+if ($location !~ m#:/#){
+ #assume an lpd printer
+ $location = "lpd://".$location;
+}
+#else, simply pass the URI on to the lpadmin command
+
+#run the cups lpadmin command to add the printer
+system("/usr/sbin/lpadmin -p $shname -D \"$drivername\" -E -v $location");
+
diff --git a/examples/scripts/printing/cups/smbdelprinter.pl b/examples/scripts/printing/cups/smbdelprinter.pl
new file mode 100755
index 0000000..23adeb7
--- /dev/null
+++ b/examples/scripts/printing/cups/smbdelprinter.pl
@@ -0,0 +1,25 @@
+#!/usr/bin/perl
+## Delete printer script for samba, APW, and cups
+## Copyright (C) Gerald (Jerry) Carter <jerry@samba.rog> 2004
+##
+## 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 3 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, see <http://www.gnu.org/licenses/>.
+
+@argv = @ARGV;
+
+# take in args
+my $lpname=shift(@argv); # printer name
+
+system("/usr/sbin/lpadmin -x $lpname");
+
diff --git a/examples/scripts/users_and_groups/adduserstogroups.pl b/examples/scripts/users_and_groups/adduserstogroups.pl
new file mode 100755
index 0000000..99837f9
--- /dev/null
+++ b/examples/scripts/users_and_groups/adduserstogroups.pl
@@ -0,0 +1,166 @@
+#!/usr/bin/perl
+
+#
+# adduserstogroups.pl
+#
+# add single or continuously numbered domain users
+# to a given single group or list of groups
+#
+# Copyright (C) Michael Adam <obnox@samba.org> 2007
+#
+# 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 3 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, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# WARNING: This script is still rather crude.
+#
+
+use strict;
+use Getopt::Std;
+
+my $net_cmd = "net";
+
+# defaults:
+
+my $server;
+my $num_members = 1;
+my $startmem; # if empty, don't add numbers to member prefix
+my $member_prefix; # name prefix for member
+my $num_groups = 1;
+my $startgroup; # if empty, don't add numbers to group prefix
+my $group_prefix; # name prefix for group
+my $path; # path to rpcclient command
+my $net_path = $net_cmd;
+my $creds;
+
+sub usage {
+ print "USAGE: $0 [-h] -S server -U user\%pass \\\n"
+ . "\t-m member [-s startmem] [-n nummem] \\\n"
+ . "\t-g group [-G startgroup] [-N numgroups] \\\n"
+ . "\t[-P path]\n";
+}
+
+# parse commandline:
+
+my %options = ();
+getopts("U:S:m:s:n:g:G:N:P:h", \%options);
+
+if (exists($options{h})) {
+ usage();
+ exit 0;
+}
+
+if (exists($options{g})) {
+ $group_prefix = $options{g};
+}
+else {
+ print "ERROR: mandatory argument '-g' missing\n";
+ usage();
+ exit 1;
+}
+
+if (exists($options{U})) {
+ $creds = "-U $options{U}";
+ if ($creds !~ '%') {
+ print "ERROR: you need to specify credentials in the form -U user\%pass\n";
+ usage();
+ exit 1;
+ }
+}
+else {
+ print "ERROR: mandatory argument '-U' missing\n";
+ usage();
+ exit 1;
+}
+
+if (exists($options{S})) {
+ $server = $options{S};
+}
+else {
+ print "ERROR: mandatory argument '-S' missing\n";
+ usage();
+ exit 1;
+}
+
+if (exists($options{s})) {
+ $startmem = $options{s};
+}
+
+if (exists($options{n})) {
+ $num_members = $options{n};
+}
+
+if (exists($options{m})) {
+ $member_prefix = $options{m};
+}
+else {
+ print "ERROR: mandatory argument '-m' missing\n";
+ usage();
+ exit 1;
+}
+
+if (exists($options{G})) {
+ $startgroup = $options{G};
+}
+
+if (exists($options{N})) {
+ $num_groups = $options{N};
+}
+
+if (exists($options{P})) {
+ $path = $options{p};
+ $net_path = "$path/$net_cmd";
+}
+
+if (@ARGV) {
+ print "ERROR: junk on the command line ('" . join(" ", @ARGV) . "')...\n";
+ usage();
+ exit 1;
+}
+
+# utility functions:
+
+sub do_add {
+ my $member_name = shift;
+ my $group_name = shift;
+ print "adding member $member_name to group $group_name\n";
+ system("$net_path rpc -I $server ".$creds." group addmem $group_name $member_name");
+}
+
+sub add_group_loop {
+ my $member_name = shift;
+
+ if ("x$startgroup" eq "x") {
+ do_add($member_name, $group_prefix);
+ }
+ else {
+ for (my $groupnum = 1; $groupnum <= $num_groups; ++$groupnum) {
+ do_add($member_name,
+ sprintf("%s%.05d", $group_prefix, $startgroup + $groupnum - 1));
+ }
+ }
+}
+
+
+# main:
+
+if ("x$startmem" eq "x") {
+ add_group_loop($member_prefix);
+}
+else {
+ for (my $memnum = 1; $memnum <= $num_members; ++$memnum) {
+ add_group_loop(sprintf("%s%.05d", $member_prefix, $startmem + $memnum - 1));
+ }
+}
+
diff --git a/examples/scripts/users_and_groups/createdomobj.pl b/examples/scripts/users_and_groups/createdomobj.pl
new file mode 100755
index 0000000..d53aefe
--- /dev/null
+++ b/examples/scripts/users_and_groups/createdomobj.pl
@@ -0,0 +1,159 @@
+#!/usr/bin/perl
+
+#
+# createdomobj.pl
+#
+# create single or continuously numbered domain
+# users/groups/aliases via rpc
+#
+# Copyright (C) Michael Adam <obnox@samba.org> 2007
+#
+# 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 3 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, see <http://www.gnu.org/licenses/>.
+#
+
+#
+# WARNING: This script is still rather crude.
+#
+
+use strict;
+use Getopt::Std;
+
+
+my $target_type = "group"; # what type of object to create
+my $rpc_cmd = "createdom".$target_type;
+my $rpccli_cmd = "rpcclient";
+
+# defaults:
+
+my $server;
+my $num_targets = 1;
+my $startnum; # if empty, don't add numbers to prefix
+my $prefix; # name-prefix
+my $path; # path to rpcclient command
+my $rpccli_path = $rpccli_cmd;
+my $creds;
+
+sub usage {
+ print "USAGE: $0 [-h] -S server -U user\%pass [-p prefix] \\\n"
+ . "\t[-t {alias|group|user}] [-s startnum] [-n numobjs] [-P path] \n";
+}
+
+# parse commandline:
+
+my %options = ();
+getopts("U:t:S:s:n:p:P:h", \%options);
+
+if (exists($options{h})) {
+ usage();
+ exit 0;
+}
+
+if (exists($options{t})) {
+ $target_type = $options{t};
+ if ($target_type !~ /^(alias|user|group)$/) {
+ print "ERROR: invalid target type given\n";
+ usage();
+ exit 1;
+ }
+ $rpc_cmd = "createdom".$target_type;
+}
+
+if (exists($options{U})) {
+ $creds = "-U $options{U}";
+ if ($creds !~ '%') {
+ print "ERROR: you need to specify credentials in the form -U user\%pass\n";
+ usage();
+ exit 1;
+ }
+}
+else {
+ print "ERROR: mandatory argument '-U' missing\n";
+ usage();
+ exit 1;
+}
+
+if (exists($options{S})) {
+ $server = $options{S};
+}
+else {
+ print "ERROR: mandatory argument '-S' missing\n";
+ usage();
+ exit 1;
+}
+
+if (exists($options{s})) {
+ $startnum = $options{s};
+}
+
+if (exists($options{n})) {
+ $num_targets = $options{n};
+}
+
+if (exists($options{p})) {
+ $prefix = $options{p};
+} else {
+ $prefix = $target_type;
+}
+
+if (exists($options{P})) {
+ $path = $options{p};
+ $rpccli_path = "$path/$rpccli_cmd";
+}
+
+if (@ARGV) {
+ print "ERROR: junk on the command line ('" . join(" ", @ARGV) . "')...\n";
+ usage();
+ exit 1;
+}
+
+# utility functions:
+
+sub open_rpc_pipe {
+ print "opening rpc pipe\n";
+ open(IPC, "| $rpccli_cmd $server $creds -d0") or
+ die "error opening rpc pipe.";
+}
+
+sub close_rpc_pipe {
+ print "closing rpc pipe\n";
+ close(IPC);
+}
+
+sub do_create {
+ my $target_name = shift;
+ print "creating $target_type $target_name\n";
+ print IPC "$rpc_cmd $target_name\n";
+}
+
+# main:
+
+open_rpc_pipe();
+
+if ("x$startnum" eq "x") {
+ do_create($prefix);
+}
+else {
+ for (my $num = 1; $num <= $num_targets; ++$num) {
+ do_create(sprintf "%s%.05d", $prefix, $startnum + $num - 1);
+ if (($num) % 500 == 0) {
+ printf("500 ".$target_type."s created\n");
+ close_rpc_pipe();
+ sleep 2;
+ open_rpc_pipe();
+ }
+ }
+}
+
+close_rpc_pipe();
+
diff --git a/examples/scripts/vfs/media_harmony/trigger_avid_update.py b/examples/scripts/vfs/media_harmony/trigger_avid_update.py
new file mode 100755
index 0000000..7d724ef
--- /dev/null
+++ b/examples/scripts/vfs/media_harmony/trigger_avid_update.py
@@ -0,0 +1,106 @@
+#!/usr/bin/python
+import os
+import socket
+import sys
+import stat
+
+######################################################################
+##
+## trigger_avid_update.py for media_harmony VFS module.
+##
+## Copyright (C) Andrew Klaassen 2012.
+##
+## 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 3 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, see <http://www.gnu.org/licenses/>.
+##
+######################################################################
+
+
+#
+# Change avid_shares and ip_prefix as appropriate for your network.
+#
+
+avid_shares = (
+ '\\\\mediaharmony01\\project1\\',
+ '\\\\mediaharmony01\\project2\\',
+ '\\\\mediaharmony01\\project3\\',
+)
+
+ip_prefix = '192.168.1.'
+
+
+if __name__ == "__main__":
+ my_ips = [ip for ip in socket.gethostbyname_ex(socket.gethostname())[2] if ip[:len(ip_prefix)] == ip_prefix]
+ if not my_ips:
+ print 'No IP address found. Aborting.'
+ dummy = raw_input("\nPress Enter to finish: ")
+ sys.exit()
+
+ my_ip = my_ips[0]
+ my_name = os.environ.get('USERNAME')
+
+ for avid_share in avid_shares:
+ media_dirs = []
+ omfi_dir = os.path.join(avid_share, 'OMFI MediaFiles')
+ if os.path.exists(omfi_dir):
+ media_dirs.append(omfi_dir)
+ mxf_root = os.path.join(avid_share, 'Avid MediaFiles', 'MXF')
+ if os.path.exists(mxf_root):
+ mxf_children = os.listdir(mxf_root)
+ for child in mxf_children:
+ fullpath = os.path.join(mxf_root, child)
+ if os.path.isdir(fullpath):
+ media_dirs.append(fullpath)
+
+ for media_dir in media_dirs:
+
+ print '\nChecking %s...' % media_dir
+
+ fakepath = '%s_%s_%s' % (media_dir, my_ip, my_name)
+ print '...fakepath: %s' % fakepath
+
+ db = os.path.join(media_dir, 'msmMMOB.mdb')
+ print '...Checking for %s' % db
+ if os.path.exists(db):
+ print '......found %s.' % db
+ db_mtime = os.stat(db)[stat.ST_MTIME]
+ newer_file = False
+ for child in os.listdir(media_dir):
+ if child == 'msmMMOB.mdb' or child == 'msmFMID.pmr':
+ continue
+ child_mtime = os.stat(os.path.join(media_dir, child))[stat.ST_MTIME]
+ if child_mtime > db_mtime:
+ print '......found newer file %s' % child
+ newer_file = True
+ break
+ else:
+ print '......no %s.' % db
+ newer_file = True
+
+ if newer_file:
+ utime = None # Sets to current time.
+ print '...Setting fake mtime to NOW. Will trigger re-index.'
+ else:
+ mtime = os.stat(media_dir)[stat.ST_MTIME]
+ utime = (mtime, mtime)
+ print '...Setting fake mtime to media_dir mtime. No re-index.'
+
+ if not os.path.exists(fakepath):
+ tmp_fakepath = '%s.tmp' % fakepath
+ open(tmp_fakepath, 'a').close()
+ os.utime(tmp_fakepath, utime)
+ os.rename(tmp_fakepath, fakepath)
+ else:
+ os.utime(fakepath, utime)
+
+ dummy = raw_input("\nPress Enter to finish: ")
diff --git a/examples/scripts/vfs/virusfilter/virusfilter-notify.ksh b/examples/scripts/vfs/virusfilter/virusfilter-notify.ksh
new file mode 100644
index 0000000..a07b914
--- /dev/null
+++ b/examples/scripts/vfs/virusfilter/virusfilter-notify.ksh
@@ -0,0 +1,284 @@
+#!/bin/ksh
+##
+## Samba-VirusFilter VFS modules
+## Copyright (C) 2010-2016 SATOH Fumiyasu @ OSS Technology Corp., Japan
+##
+## 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 3 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, see <http://www.gnu.org/licenses/>.
+##
+
+set -u
+
+pdie() { echo "$0: ERROR: ${1-}" 1>&2; exit "${2-1}"; }
+
+## ======================================================================
+
+sendmail="${VIRUSFILTER_NOTIFY_SENDMAIL_COMMAND:-/usr/sbin/sendmail}"
+sendmail_opts="${VIRUSFILTER_NOTIFY_SENDMAIL_OPTIONS:-}"
+
+smbclient="${VIRUSFILTER_NOTIFY_SMBCLIENT_COMMAND:-@SAMBA_BINDIR@/smbclient}"
+smbclient_opts="${VIRUSFILTER_NOTIFY_SMBCLIENT_OPTIONS:-}"
+
+## ======================================================================
+
+if [ -n "${VIRUSFILTER_RESULT_IS_CACHE-}" ]; then
+ ## Result is cache. Ignore!
+ exit 0
+fi
+
+if [ ! -t 1 ] && [ -z "${VIRUSFILTER_NOTIFY_BG-}" ]; then
+ export VIRUSFILTER_NOTIFY_BG=1
+ "$0" ${1+"$@"} </dev/null >/dev/null &
+ exit 0
+fi
+
+## ----------------------------------------------------------------------
+
+if [ -n "${VIRUSFILTER_INFECTED_FILE_ACTION-}" ]; then
+ report="$VIRUSFILTER_INFECTED_FILE_REPORT"
+else
+ report="$VIRUSFILTER_SCAN_ERROR_REPORT"
+fi
+
+if [ X"$VIRUSFILTER_SERVER_NAME" != X"$VIRUSFILTER_SERVER_IP" ]; then
+ server_name="$VIRUSFILTER_SERVER_NAME"
+else
+ server_name="$VIRUSFILTER_SERVER_NETBIOS_NAME"
+fi
+
+if [ X"$VIRUSFILTER_CLIENT_NAME" != X"$VIRUSFILTER_CLIENT_IP" ]; then
+ client_name="$VIRUSFILTER_CLIENT_NAME"
+else
+ client_name="$VIRUSFILTER_CLIENT_NETBIOS_NAME"
+fi
+
+mail_to=""
+winpopup_to=""
+subject_prefix=""
+sender=""
+from=""
+cc=""
+bcc=""
+content_type="text/plain"
+content_encoding="UTF-8"
+
+cmd_usage="Usage: $0 [OPTIONS]
+
+Options:
+ --mail-to ADDRESS
+ Send a notice message to this e-mail address(es)
+ --winpopup-to NAME
+ Send a \"WinPopup\" message to this NetBIOS name
+ --sender ADDRESS
+ Envelope sender address for mail
+ --from ADDRESS
+ From: e-mail address for mail
+ --cc ADDRESS
+ Cc: e-mail address(es) for mail
+ --bcc ADDRESS
+ Bcc: e-mail address(es) for mail
+ --subject-prefix PREFIX
+ Subject: prefix string for mail
+ --content-type TYPE
+ --content-encoding ENCODING
+ Content-Type: TYPE; charset=\"ENCODING\" for mail [$content_type; charset=\"$content_encoding\"]
+ --header-file FILE
+ Prepend the content of FILE to the message
+ --footer-file FILE
+ Append the content of FILE to the message
+"
+
+## ----------------------------------------------------------------------
+
+getopts_want_arg()
+{
+ if [ "$#" -lt 2 ]; then
+ pdie "Option requires an argument: $1"
+ fi
+ if [ "$#" -ge 3 ]; then
+ if expr x"$2" : x"$3\$" >/dev/null; then
+ : OK
+ else
+ pdie "Invalid value for option: $1 $2"
+ fi
+ fi
+}
+
+while [ "$#" -gt 0 ]; do
+ OPT="$1"; shift
+ case "$OPT" in
+ --help)
+ echo "$cmd_usage"
+ exit 0
+ ;;
+ --mail-to)
+ getopts_want_arg "$OPT" ${1+"$1"}
+ mail_to="${mail_to:+$mail_to, }$1"; shift
+ ;;
+ --winpopup-to)
+ getopts_want_arg "$OPT" ${1+"$1"}
+ winpopup_to="$1"; shift
+ ;;
+ --sender)
+ getopts_want_arg "$OPT" ${1+"$1"}
+ sender="$1"; shift
+ ;;
+ --from)
+ getopts_want_arg "$OPT" ${1+"$1"}
+ from="$1"; shift
+ ;;
+ --cc)
+ getopts_want_arg "$OPT" ${1+"$1"}
+ cc="${cc:+$cc, }$1"; shift
+ ;;
+ --bcc)
+ getopts_want_arg "$OPT" ${1+"$1"}
+ bcc="${bcc:+$bcc, }$1"; shift
+ ;;
+ --subject-prefix)
+ getopts_want_arg "$OPT" ${1+"$1"}
+ subject_prefix="$1"; shift
+ ;;
+ --content-type)
+ getopts_want_arg "$OPT" ${1+"$1"}
+ content_type="$1"; shift
+ ;;
+ --content-encoding)
+ getopts_want_arg "$OPT" ${1+"$1"}
+ content_encoding="$1"; shift
+ ;;
+ --header-file)
+ getopts_want_arg "$OPT" ${1+"$1"}
+ header_file="$1"; shift
+ ;;
+ --footer-file)
+ getopts_want_arg "$OPT" ${1+"$1"}
+ footer_file="$1"; shift
+ ;;
+ --)
+ break
+ ;;
+ -*)
+ pdie "Invalid option: $OPT"
+ ;;
+ *)
+ set -- "$OPT" ${1+"$@"}
+ break
+ ;;
+ esac
+done
+
+[ -z "$sender" ] && sender="$from"
+subject="$subject_prefix$report"
+
+## ======================================================================
+
+msg_header="\
+Subject: $subject
+Content-Type: $content_type; charset=$content_encoding
+X-VIRUSFILTER-Version: $VIRUSFILTER_VERSION
+X-VIRUSFILTER-Module-Name: $VIRUSFILTER_MODULE_NAME
+"
+
+if [ -n "${VIRUSFILTER_MODULE_VERSION-}" ]; then
+ msg_header="${msg_header}\
+X-VIRUSFILTER-Module-Version: $VIRUSFILTER_MODULE_VERSION
+"
+fi
+
+if [ -n "${from-}" ]; then
+ msg_header="${msg_header}\
+From: $from
+"
+fi
+
+if [ -n "${mail_to-}" ]; then
+ msg_header="${msg_header}\
+To: $mail_to
+"
+fi
+
+if [ -n "${cc-}" ]; then
+ msg_header="${msg_header}\
+Cc: $cc
+"
+fi
+
+if [ -n "${bcc-}" ]; then
+ msg_header="${msg_header}\
+Bcc: $bcc
+"
+fi
+
+## ----------------------------------------------------------------------
+
+msg_body=""
+
+if [ -n "${header_file-}" ] && [ -f "$header_file" ]; then
+ msg_body="${msg_body}\
+`cat "$header_file"`
+"
+fi
+
+msg_body="${msg_body}\
+Server: $server_name ($VIRUSFILTER_SERVER_IP)
+Server PID: $VIRUSFILTER_SERVER_PID
+Service name: $VIRUSFILTER_SERVICE_NAME
+Service path: $VIRUSFILTER_SERVICE_PATH
+Client: $client_name ($VIRUSFILTER_CLIENT_IP)
+User: $VIRUSFILTER_USER_DOMAIN\\$VIRUSFILTER_USER_NAME
+"
+
+if [ -n "${VIRUSFILTER_INFECTED_FILE_ACTION-}" ]; then
+ msg_body="${msg_body}\
+Infected file report: $VIRUSFILTER_INFECTED_FILE_REPORT
+"
+ msg_body="${msg_body}\
+Infected file path: $VIRUSFILTER_SERVICE_PATH/$VIRUSFILTER_INFECTED_SERVICE_FILE_PATH
+"
+ msg_body="${msg_body}\
+Infected file action: $VIRUSFILTER_INFECTED_FILE_ACTION
+"
+else
+ msg_body="${msg_body}\
+Scan error report: $VIRUSFILTER_SCAN_ERROR_REPORT
+Scan error file path: $VIRUSFILTER_SERVICE_PATH/$VIRUSFILTER_SCAN_ERROR_SERVICE_FILE_PATH
+"
+fi
+
+if [ -n "${VIRUSFILTER_QUARANTINED_FILE_PATH-}" ]; then
+ msg_body="${msg_body}\
+Quarantined/Renamed file path: ${VIRUSFILTER_QUARANTINED_FILE_PATH-}
+"
+fi
+
+if [ -n "${footer_file-}" ] && [ -f "$footer_file" ]; then
+ msg_body="${msg_body}\
+`cat "$footer_file"`
+"
+fi
+
+## ======================================================================
+
+if [ -n "$mail_to" ]; then
+ (echo "$msg_header"; echo "$msg_body") \
+ |"$sendmail" -t -i ${sender:+-f "$sender"} $sendmail_opts
+fi
+
+if [ -n "$winpopup_to" ]; then
+ echo "$msg_body" \
+ |"$smbclient" -M "$winpopup_to" -U% $smbclient_opts \
+ >/dev/null
+fi
+
+exit 0
diff --git a/examples/scripts/wins_hook/README b/examples/scripts/wins_hook/README
new file mode 100644
index 0000000..1147f57
--- /dev/null
+++ b/examples/scripts/wins_hook/README
@@ -0,0 +1,8 @@
+This is an example script for doing dynamic DNS updates from the WINS
+database. You use this by putting the full path to the script in the
+"wins hook" option in smb.conf. Remember to mark the script executable
+and to set the right domain at the top of the script.
+
+See the BIND documentation for how to enable dynamic DNS
+updates. Remember to restrict the updates as far as you can to reduce
+the security risks inherent in dynamic DNS.
diff --git a/examples/scripts/wins_hook/dns_update b/examples/scripts/wins_hook/dns_update
new file mode 100644
index 0000000..14fc1fe
--- /dev/null
+++ b/examples/scripts/wins_hook/dns_update
@@ -0,0 +1,92 @@
+#!/bin/sh
+#
+# Example script for "wins hook". This attempts to update the DNS with
+# new A records for the NETBIOS name that Samba passes us. We do this
+# the simple way, by deleting all DNS records for the name and then
+# re-adding all the expected 'A' records.
+#
+# Written by Stephen Rothwell <sfr@linuxcare.com>
+#
+
+#
+# Configurable things
+#
+# The domain in which to create names
+# YOU MUST CHANGE THIS
+# N.B. include the trailing dot
+#
+# It is a good idea to use a subdomain of your primary domain to ensure
+# that rogue machines can't take over (or delete) important names on
+# your network.
+DOMAIN=wins.example.com.
+
+#
+# The DNS TTL to give the records (in seconds)
+#
+TTL=3600
+#
+# NETBIOS name types that we want to create DNS records for:
+# 20 is server
+# 00 is workstation
+# 03 is user
+#
+USEFUL_TYPES="20 00 03"
+#
+# The name of a cache file to use to avoid continual updates
+# of the same name and IP addresses. If you comment this out
+# then the cache is not kept at all.
+#
+#CACHE_FILE=/usr/local/samba/var/wins_update.cache
+
+if [ $# -lt 4 ]; then
+ echo "Usage: $0 op name type ttl [ip_addr ...]" 1>&2
+ echo " op is one of add, refresh, delete" 1>&2
+ echo " name is the NETBIOS name" 1>&2
+ echo " type is the NETBIOS name type" 1>&2
+ echo " ttl is the NETBIOS time to live" 1>&2
+ echo " ip_addr's are the remaining IP addresses for this name" 1>&2
+ exit 1
+fi
+
+NSUPDATE=$(which nsupdate)
+[ -x "$NSUPDATE" ] || NSUPDATE=/usr/bin/nsupdate
+[ -x "$NSUPDATE" ] || NSUPDATE=/sbin/nsupdate
+[ -x "$NSUPDATE" ] || NSUPDATE=/usr/sbin/nsupdate
+[ -x "$NSUPDATE" ] || {
+ echo "Cannot find nsupdate." 1>&2
+ exit 1
+}
+
+OP=$1
+NAME=$2
+TYPE=$3
+WINS_TTL=$4
+shift 4
+IP_ADDRS="$@"
+
+do_update=0
+for i in $USEFUL_TYPES; do
+ [ "$TYPE" = "$i" ] && do_update=1
+done
+[ $do_update = 1 ] || exit 0
+
+if [ -n "$CACHE_FILE" ]; then
+ if [ -r "$CACHE_FILE" ]; then
+ fgrep -q -x -i "$NAME $IP_ADDRS" "$CACHE_FILE" &&
+ exit 0
+ grep -v -i "^$NAME " "$CACHE_FILE" >"$CACHE_FILE".$$
+ fi
+ echo "$NAME $IP_ADDRS" >>"$CACHE_FILE".$$
+ mv "$CACHE_FILE" "$CACHE_FILE".old 2>/dev/null
+ mv "$CACHE_FILE".$$ "$CACHE_FILE"
+fi
+
+{
+ echo update delete $NAME.$DOMAIN
+ for i in $IP_ADDRS; do
+ echo update add $NAME.$DOMAIN $TTL A $i
+ done
+ echo
+} 2>/dev/null | $NSUPDATE >/dev/null 2>&1 &
+
+exit 0
diff --git a/examples/smb.conf.default b/examples/smb.conf.default
new file mode 100644
index 0000000..6210d69
--- /dev/null
+++ b/examples/smb.conf.default
@@ -0,0 +1,223 @@
+# 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
+#
+# For a step to step guide on installing, configuring and using samba,
+# read the Samba-HOWTO-Collection. This may be obtained from:
+# http://www.samba.org/samba/docs/Samba-HOWTO-Collection.pdf
+#
+# Many working examples of smb.conf files can be found in the
+# Samba-Guide which is generated daily and can be downloaded from:
+# http://www.samba.org/samba/docs/Samba-Guide.pdf
+#
+# 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, eg: MIDEARTH
+ workgroup = MYGROUP
+
+# server string is the equivalent of the NT Description field
+ server string = Samba Server
+
+# Server role. Defines in which mode Samba will operate. Possible
+# values are "standalone server", "member server", "classic primary
+# domain controller", "classic backup domain controller", "active
+# directory domain controller".
+#
+# Most people will want "standalone server" or "member server".
+# Running as "active directory domain controller" will require first
+# running "samba-tool domain provision" to wipe databases and create a
+# new domain.
+ server role = standalone 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.
+
+# 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 = /usr/local/samba/var/log.%m
+
+# Put a capping on the size of the log files (in Kb).
+ max log size = 50
+
+# Specifies the Kerberos or Active Directory realm the host is part of
+; realm = MY_REALM
+
+# Backend to store user information in. New installations should
+# use either tdbsam or ldapsam. smbpasswd is available for backwards
+# compatibility. tdbsam requires no further configuration.
+; passdb backend = tdbsam
+
+# 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.
+# Note: Consider carefully the location in the configuration file of
+# this line. The included file is read at that point.
+; include = /usr/local/samba/lib/smb.conf.%m
+
+# 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
+
+# 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
+
+# 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 default is NO.
+ dns proxy = no
+
+# These scripts are used on a domain controller or stand-alone
+# machine to add or delete corresponding unix accounts
+; add user script = /usr/sbin/useradd %u
+; add group script = /usr/sbin/groupadd %g
+; add machine script = /usr/sbin/adduser -n -g machines -c Machine -d /dev/null -s /bin/false %u
+; delete user script = /usr/sbin/userdel %u
+; delete user from group script = /usr/sbin/deluser %u %g
+; delete group script = /usr/sbin/groupdel %g
+
+
+#============================ Share Definitions ==============================
+[homes]
+ comment = Home Directories
+ browsable = no
+ writable = yes
+
+# Un-comment the following and create the netlogon directory for Domain Logons
+; [netlogon]
+; comment = Network Logon Service
+; path = /usr/local/samba/lib/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 = /usr/local/samba/profiles
+; browsable = 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 = /usr/spool/samba
+ browsable = no
+# Change 'guest ok' from 'no' to 'yes' to allow the 'guest account' user 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
+; writable = no
+; printable = no
+; 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/examples/systemtap/gencache.stp b/examples/systemtap/gencache.stp
new file mode 100755
index 0000000..95fcff3
--- /dev/null
+++ b/examples/systemtap/gencache.stp
@@ -0,0 +1,147 @@
+#!/usr/bin/stap
+#
+# Systemtap script to instrument the Samba gencache subsystem
+#
+# Usage:
+#
+# Instrument all smbd processes:
+# # stap gencache.stp smbd
+#
+# Instrument all winbindd processes:
+# # stap gencache.stp winbindd
+#
+# Instrument a specific smbd process:
+# # stap -x PID gencache.stp smbd
+#
+# Instrument a specific winbindd process:
+# # stap -x PID gencache.stp winbindd
+#
+
+global running, intervals
+global cache_misses, cache_hits, neg_cache_hits
+
+probe begin {
+ printf("Collecting data, press ctrl-C to stop... ")
+}
+
+probe process(@1).library("*").function("gencache_parse") {
+ running["gencache_parse", tid()] = gettimeofday_us()
+}
+
+probe process(@1).library("*").function("gencache_parse").return {
+ if (!(["gencache_parse", tid()] in running))
+ next
+
+ end = gettimeofday_us()
+ begin = running["gencache_parse", tid()]
+ delete running["gencache_parse", tid()]
+
+ duration = end - begin
+ intervals["gencache_parse"] <<< duration
+
+ if ($return == 0) {
+ cache_misses++
+ } else {
+ cache_hits++
+ }
+}
+
+probe process(@1).library("*").function("gencache_get_data_blob_parser") {
+ if ($timeout == 0) {
+ neg_cache_hits++
+ }
+}
+
+probe process(@1).library("*").function("gencache_get_data_blob") {
+ running["gencache_get_data_blob", tid()] = gettimeofday_us()
+}
+
+probe process(@1).library("*").function("gencache_get_data_blob").return {
+ if (!(["gencache_get_data_blob", tid()] in running))
+ next
+
+ end = gettimeofday_us()
+ begin = running["gencache_get_data_blob", tid()]
+ delete running["gencache_get_data_blob", tid()]
+
+ duration = end - begin
+ intervals["gencache_get_data_blob"] <<< duration
+}
+
+probe process(@1).library("*").function("gencache_set_data_blob") {
+ running["gencache_set_data_blob", tid()] = gettimeofday_us()
+}
+
+probe process(@1).library("*").function("gencache_set_data_blob").return {
+ if (!(["gencache_set_data_blob", tid()] in running))
+ next
+
+ end = gettimeofday_us()
+ begin = running["gencache_set_data_blob", tid()]
+ delete running["gencache_set_data_blob", tid()]
+
+ duration = end - begin
+ intervals["gencache_set_data_blob"] <<< duration
+}
+
+probe process(@1).library("*").function("gencache_del") {
+ running["gencache_del", tid()] = gettimeofday_us()
+}
+
+probe process(@1).library("*").function("gencache_del").return {
+ if (!(["gencache_del", tid()] in running))
+ next
+
+ end = gettimeofday_us()
+ begin = running["gencache_del", tid()]
+ delete running["gencache_del", tid()]
+
+ duration = end - begin
+ intervals["gencache_del"] <<< duration
+}
+
+probe process(@1).library("*").function("gencache_stabilize") {
+ running["gencache_stabilize", tid()] = gettimeofday_us()
+}
+
+probe process(@1).library("*").function("gencache_stabilize").return {
+ if (!(["gencache_stabilize", tid()] in running))
+ next
+
+ end = gettimeofday_us()
+ begin = running["gencache_stabilize", tid()]
+ delete running["gencache_stabilize", tid()]
+
+ duration = end - begin
+ intervals["gencache_stabilize"] <<< duration
+}
+
+probe end {
+ printf("\n\n")
+
+ printf("Summary of cache access stats\n")
+ printf("=============================\n\n")
+ printf("%-10s %-10s %-10s\n",
+ "Hits", "Misses", "Negative-Hits");
+ printf("--------------------------------------\n")
+ printf("%-10d %-10d %-10d\n",
+ cache_hits, cache_misses, neg_cache_hits);
+
+ printf("\n")
+
+ foreach ([name] in intervals) {
+ printf("%-30s count: %d sum: %d us (min: %d us avg: %d us max: %d us)\n",
+ name,
+ @count(intervals[name]),
+ @sum(intervals[name]),
+ @min(intervals[name]),
+ @avg(intervals[name]),
+ @max(intervals[name]))
+ }
+
+ printf("\n")
+ foreach ([name] in intervals) {
+ printf("%s time distribution histogram:\n", name)
+ println(@hist_log(intervals[name]))
+ }
+}
diff --git a/examples/systemtap/generate-winbindd.stp.sh b/examples/systemtap/generate-winbindd.stp.sh
new file mode 100755
index 0000000..3a4d2d8
--- /dev/null
+++ b/examples/systemtap/generate-winbindd.stp.sh
@@ -0,0 +1,310 @@
+#!/bin/sh
+
+outfile="$(dirname $0)/winbindd.stp"
+
+child_funcs="winbindd_dual_init_connection
+_wbint_InitConnection
+_wbint_Ping
+_wbint_PamAuth
+_wbint_PamAuthCrap
+_wbint_PamLogOff
+_wbint_PamAuthChangePassword
+_wbint_PamAuthCrapChangePassword
+_wbint_ListTrustedDomains
+_wbint_LookupSid
+_wbint_LookupSids
+_wbint_LookupName
+_wbint_Sids2UnixIDs
+_wbint_UnixIDs2Sids
+_wbint_AllocateUid
+_wbint_AllocateGid
+_wbint_GetNssInfo
+_wbint_LookupUserAliases
+_wbint_LookupUserGroups
+_wbint_QuerySequenceNumber
+_wbint_LookupGroupMembers
+_wbint_QueryGroupList
+_wbint_QueryUserRidList
+_wbint_DsGetDcName
+_wbint_LookupRids
+_wbint_CheckMachineAccount
+_wbint_ChangeMachineAccount
+_wbint_PingDc"
+
+async_funcs="wb_ping
+winbindd_lookupsid
+winbindd_lookupsids
+winbindd_lookupname
+winbindd_sids_to_xids
+winbindd_xids_to_sids
+winbindd_getpwsid
+winbindd_getpwnam
+winbindd_getpwuid
+winbindd_getsidaliases
+winbindd_getuserdomgroups
+winbindd_getgroups
+winbindd_show_sequence
+winbindd_getgrgid
+winbindd_getgrnam
+winbindd_getusersids
+winbindd_lookuprids
+winbindd_setpwent
+winbindd_getpwent
+winbindd_endpwent
+winbindd_dsgetdcname
+winbindd_getdcname
+winbindd_setgrent
+winbindd_getgrent
+winbindd_endgrent
+winbindd_list_users
+winbindd_list_groups
+winbindd_check_machine_acct
+winbindd_ping_dc
+winbindd_pam_auth
+winbindd_pam_logoff
+winbindd_pam_chauthtok
+winbindd_pam_chng_pswd_auth_crap
+winbindd_wins_byip
+winbindd_wins_byname
+winbindd_allocate_uid
+winbindd_allocate_gid
+winbindd_change_machine_acct
+winbindd_pam_auth_crap"
+
+backend_funcs="query_user_list
+enum_dom_groups
+enum_local_groups
+name_to_sid
+sid_to_name
+rids_to_names
+lookup_usergroups
+lookup_useraliases
+lookup_groupmem
+sequence_number
+lockout_policy
+password_policy
+trusted_domains"
+
+header='#!/usr/bin/stap
+#
+# Systemtap script to instrument winbindd
+#
+'"# Generated by examples/systemtap/$(basename $0) on $(date), do not edit
+#"'
+# Usage:
+#
+# Instrument all winbindd processes:
+# # stap winbindd.stp
+#
+# Instrument a specific winbindd process:
+# # stap -x PID winbindd.stp
+#
+
+global dc_running, dc_svctime
+global backend_running, backend_svctime
+global send_running, recv_running
+global start_time, idle_time
+global async_svctime, async_runtime
+
+probe begin {
+ printf("Collecting data, press ctrl-C to stop... ")
+}'
+
+domchild_req_template='
+#
+# winbind domain child function XXX
+#
+
+probe process("winbindd").function("XXX") {
+ dc_running[tid(), "XXX"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("XXX").return {
+ if (!([tid(), "XXX"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "XXX"]
+ delete dc_running[tid(), "XXX"]
+
+ duration = end - begin
+ dc_svctime["XXX"] <<< duration
+}'
+
+backend_req_template='
+#
+# winbind domain child backend function XXX
+#
+
+probe process("winbindd").function("XXX@../source3/winbindd/winbindd_ads.c") {
+ backend_running[tid(), "XXX"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("XXX@../source3/winbindd/winbindd_ads.c").return {
+ if (!([tid(), "XXX"] in backend_running))
+ next
+
+ end = gettimeofday_us()
+ begin = backend_running[tid(), "XXX"]
+ delete backend_running[tid(), "XXX"]
+
+ duration = end - begin
+ backend_svctime["XXX"] <<< duration
+}'
+
+async_req_template='
+#
+# winbind async function XXX
+#
+
+probe process("winbindd").function("XXX_send") {
+ send_running["XXX_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("XXX_send").return {
+ if (!(["XXX_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["XXX_send"]
+ delete send_running["XXX_send"]
+
+ start_time["XXX_send", $return] = start
+ idle_time["XXX_send", $return] = end
+}
+
+probe process("winbindd").function("XXX_recv") {
+ if (!(["XXX_send", $req] in start_time))
+ next
+
+ recv_running["XXX_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("XXX_recv").return {
+ if (!(["XXX_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["XXX_recv"]
+ delete recv_running["XXX_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["XXX_send", req]
+ delete start_time["XXX_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["XXX_send", req]
+ delete idle_time["XXX_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["XXX_send"] <<< svctime
+ async_runtime["XXX_send"] <<< runtime
+}'
+
+footer='
+probe end {
+ printf("\n\n")
+
+ printf("Winbind request service time\n")
+ printf("============================\n")
+ foreach ([name] in async_svctime) {
+ printf("%-40s count: %5d, sum: %6d ms (min: %6d us, avg: %6d us, max: %6d us)\n",
+ name,
+ @count(async_svctime[name]),
+ @sum(async_svctime[name]) / 1000,
+ @min(async_svctime[name]),
+ @avg(async_svctime[name]),
+ @max(async_svctime[name]))
+ }
+ printf("\n")
+
+ printf("Winbind request runtime\n")
+ printf("=======================\n")
+ foreach ([name] in async_runtime) {
+ printf("%-40s count: %5d, sum: %6d ms (min: %6d us, avg: %6d us, max: %6d us)\n",
+ name,
+ @count(async_runtime[name]),
+ @sum(async_runtime[name]) / 1000,
+ @min(async_runtime[name]),
+ @avg(async_runtime[name]),
+ @max(async_runtime[name]))
+ }
+ printf("\n")
+
+ printf("Winbind domain-child request service time\n")
+ printf("=========================================\n")
+ foreach ([name] in dc_svctime) {
+ printf("%-40s count: %5d, sum: %6d ms (min: %6d us, avg: %6d us, max: %6d us)\n",
+ name,
+ @count(dc_svctime[name]),
+ @sum(dc_svctime[name]) / 1000,
+ @min(dc_svctime[name]),
+ @avg(dc_svctime[name]),
+ @max(dc_svctime[name]))
+ }
+ printf("\n")
+
+ printf("Winbind domain-child AD-backend service time\n")
+ printf("============================================\n")
+ foreach ([name] in backend_svctime) {
+ printf("%-40s count: %5d, sum: %6d ms (min: %6d us, avg: %6d us, max: %6d us)\n",
+ name,
+ @count(backend_svctime[name]),
+ @sum(backend_svctime[name]) / 1000,
+ @min(backend_svctime[name]),
+ @avg(backend_svctime[name]),
+ @max(backend_svctime[name]))
+ }
+ printf("\n")
+
+ printf("Winbind request service time distributions (us)\n")
+ printf("===============================================\n")
+ foreach ([name] in async_svctime) {
+ printf("%s:\n", name);
+ println(@hist_log(async_svctime[name]))
+ }
+ printf("\n")
+
+ printf("Winbind request runtime distributions (us)\n")
+ printf("==========================================\n")
+ foreach ([name] in async_runtime) {
+ printf("%s:\n", name);
+ println(@hist_log(async_runtime[name]))
+ }
+
+ printf("Winbind domain-child request service time distributions (us)\n")
+ printf("============================================================\n")
+ foreach ([name] in dc_svctime) {
+ printf("%s:\n", name);
+ println(@hist_log(dc_svctime[name]))
+ }
+
+ printf("Winbind domain-child AD-backend service time distributions (us)\n")
+ printf("===============================================================\n")
+ foreach ([name] in backend_svctime) {
+ printf("%s:\n", name);
+ println(@hist_log(backend_svctime[name]))
+ }
+}'
+
+cat <<EOF >$outfile
+$header
+EOF
+
+printf "$child_funcs\n" | while read func; do
+ printf "$domchild_req_template\n" | sed -e s/XXX/$func/g >>$outfile
+done
+
+printf "$backend_funcs\n" | while read func; do
+ printf "$backend_req_template\n" | sed -e "s|XXX|$func|g" >>$outfile
+done
+
+printf "$async_funcs\n" | while read func; do
+ printf "$async_req_template\n" | sed -e s/XXX/$func/g >>$outfile
+done
+
+cat <<EOF >>$outfile
+$footer
+EOF
diff --git a/examples/systemtap/winbindd.stp b/examples/systemtap/winbindd.stp
new file mode 100644
index 0000000..635784a
--- /dev/null
+++ b/examples/systemtap/winbindd.stp
@@ -0,0 +1,2879 @@
+#!/usr/bin/stap
+#
+# Systemtap script to instrument winbindd
+#
+# Generated by examples/systemtap/generate-winbindd.stp.sh on lun 09 may 2022 17:31:44 CEST, do not edit
+#
+# Usage:
+#
+# Instrument all winbindd processes:
+# # stap winbindd.stp
+#
+# Instrument a specific winbindd process:
+# # stap -x PID winbindd.stp
+#
+
+global dc_running, dc_svctime
+global backend_running, backend_svctime
+global send_running, recv_running
+global start_time, idle_time
+global async_svctime, async_runtime
+
+probe begin {
+ printf("Collecting data, press ctrl-C to stop... ")
+}
+
+#
+# winbind domain child function winbindd_dual_init_connection
+#
+
+probe process("winbindd").function("winbindd_dual_init_connection") {
+ dc_running[tid(), "winbindd_dual_init_connection"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_dual_init_connection").return {
+ if (!([tid(), "winbindd_dual_init_connection"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "winbindd_dual_init_connection"]
+ delete dc_running[tid(), "winbindd_dual_init_connection"]
+
+ duration = end - begin
+ dc_svctime["winbindd_dual_init_connection"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_InitConnection
+#
+
+probe process("winbindd").function("_wbint_InitConnection") {
+ dc_running[tid(), "_wbint_InitConnection"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_InitConnection").return {
+ if (!([tid(), "_wbint_InitConnection"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_InitConnection"]
+ delete dc_running[tid(), "_wbint_InitConnection"]
+
+ duration = end - begin
+ dc_svctime["_wbint_InitConnection"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_Ping
+#
+
+probe process("winbindd").function("_wbint_Ping") {
+ dc_running[tid(), "_wbint_Ping"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_Ping").return {
+ if (!([tid(), "_wbint_Ping"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_Ping"]
+ delete dc_running[tid(), "_wbint_Ping"]
+
+ duration = end - begin
+ dc_svctime["_wbint_Ping"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_PamAuth
+#
+
+probe process("winbindd").function("_wbint_PamAuth") {
+ dc_running[tid(), "_wbint_PamAuth"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_PamAuth").return {
+ if (!([tid(), "_wbint_PamAuth"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_PamAuth"]
+ delete dc_running[tid(), "_wbint_PamAuth"]
+
+ duration = end - begin
+ dc_svctime["_wbint_PamAuth"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_PamAuthCrap
+#
+
+probe process("winbindd").function("_wbint_PamAuthCrap") {
+ dc_running[tid(), "_wbint_PamAuthCrap"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_PamAuthCrap").return {
+ if (!([tid(), "_wbint_PamAuthCrap"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_PamAuthCrap"]
+ delete dc_running[tid(), "_wbint_PamAuthCrap"]
+
+ duration = end - begin
+ dc_svctime["_wbint_PamAuthCrap"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_PamLogOff
+#
+
+probe process("winbindd").function("_wbint_PamLogOff") {
+ dc_running[tid(), "_wbint_PamLogOff"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_PamLogOff").return {
+ if (!([tid(), "_wbint_PamLogOff"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_PamLogOff"]
+ delete dc_running[tid(), "_wbint_PamLogOff"]
+
+ duration = end - begin
+ dc_svctime["_wbint_PamLogOff"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_PamAuthChangePassword
+#
+
+probe process("winbindd").function("_wbint_PamAuthChangePassword") {
+ dc_running[tid(), "_wbint_PamAuthChangePassword"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_PamAuthChangePassword").return {
+ if (!([tid(), "_wbint_PamAuthChangePassword"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_PamAuthChangePassword"]
+ delete dc_running[tid(), "_wbint_PamAuthChangePassword"]
+
+ duration = end - begin
+ dc_svctime["_wbint_PamAuthChangePassword"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_PamAuthCrapChangePassword
+#
+
+probe process("winbindd").function("_wbint_PamAuthCrapChangePassword") {
+ dc_running[tid(), "_wbint_PamAuthCrapChangePassword"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_PamAuthCrapChangePassword").return {
+ if (!([tid(), "_wbint_PamAuthCrapChangePassword"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_PamAuthCrapChangePassword"]
+ delete dc_running[tid(), "_wbint_PamAuthCrapChangePassword"]
+
+ duration = end - begin
+ dc_svctime["_wbint_PamAuthCrapChangePassword"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_ListTrustedDomains
+#
+
+probe process("winbindd").function("_wbint_ListTrustedDomains") {
+ dc_running[tid(), "_wbint_ListTrustedDomains"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_ListTrustedDomains").return {
+ if (!([tid(), "_wbint_ListTrustedDomains"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_ListTrustedDomains"]
+ delete dc_running[tid(), "_wbint_ListTrustedDomains"]
+
+ duration = end - begin
+ dc_svctime["_wbint_ListTrustedDomains"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_LookupSid
+#
+
+probe process("winbindd").function("_wbint_LookupSid") {
+ dc_running[tid(), "_wbint_LookupSid"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_LookupSid").return {
+ if (!([tid(), "_wbint_LookupSid"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_LookupSid"]
+ delete dc_running[tid(), "_wbint_LookupSid"]
+
+ duration = end - begin
+ dc_svctime["_wbint_LookupSid"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_LookupSids
+#
+
+probe process("winbindd").function("_wbint_LookupSids") {
+ dc_running[tid(), "_wbint_LookupSids"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_LookupSids").return {
+ if (!([tid(), "_wbint_LookupSids"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_LookupSids"]
+ delete dc_running[tid(), "_wbint_LookupSids"]
+
+ duration = end - begin
+ dc_svctime["_wbint_LookupSids"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_LookupName
+#
+
+probe process("winbindd").function("_wbint_LookupName") {
+ dc_running[tid(), "_wbint_LookupName"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_LookupName").return {
+ if (!([tid(), "_wbint_LookupName"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_LookupName"]
+ delete dc_running[tid(), "_wbint_LookupName"]
+
+ duration = end - begin
+ dc_svctime["_wbint_LookupName"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_Sids2UnixIDs
+#
+
+probe process("winbindd").function("_wbint_Sids2UnixIDs") {
+ dc_running[tid(), "_wbint_Sids2UnixIDs"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_Sids2UnixIDs").return {
+ if (!([tid(), "_wbint_Sids2UnixIDs"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_Sids2UnixIDs"]
+ delete dc_running[tid(), "_wbint_Sids2UnixIDs"]
+
+ duration = end - begin
+ dc_svctime["_wbint_Sids2UnixIDs"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_UnixIDs2Sids
+#
+
+probe process("winbindd").function("_wbint_UnixIDs2Sids") {
+ dc_running[tid(), "_wbint_UnixIDs2Sids"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_UnixIDs2Sids").return {
+ if (!([tid(), "_wbint_UnixIDs2Sids"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_UnixIDs2Sids"]
+ delete dc_running[tid(), "_wbint_UnixIDs2Sids"]
+
+ duration = end - begin
+ dc_svctime["_wbint_UnixIDs2Sids"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_AllocateUid
+#
+
+probe process("winbindd").function("_wbint_AllocateUid") {
+ dc_running[tid(), "_wbint_AllocateUid"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_AllocateUid").return {
+ if (!([tid(), "_wbint_AllocateUid"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_AllocateUid"]
+ delete dc_running[tid(), "_wbint_AllocateUid"]
+
+ duration = end - begin
+ dc_svctime["_wbint_AllocateUid"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_AllocateGid
+#
+
+probe process("winbindd").function("_wbint_AllocateGid") {
+ dc_running[tid(), "_wbint_AllocateGid"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_AllocateGid").return {
+ if (!([tid(), "_wbint_AllocateGid"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_AllocateGid"]
+ delete dc_running[tid(), "_wbint_AllocateGid"]
+
+ duration = end - begin
+ dc_svctime["_wbint_AllocateGid"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_GetNssInfo
+#
+
+probe process("winbindd").function("_wbint_GetNssInfo") {
+ dc_running[tid(), "_wbint_GetNssInfo"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_GetNssInfo").return {
+ if (!([tid(), "_wbint_GetNssInfo"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_GetNssInfo"]
+ delete dc_running[tid(), "_wbint_GetNssInfo"]
+
+ duration = end - begin
+ dc_svctime["_wbint_GetNssInfo"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_LookupUserAliases
+#
+
+probe process("winbindd").function("_wbint_LookupUserAliases") {
+ dc_running[tid(), "_wbint_LookupUserAliases"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_LookupUserAliases").return {
+ if (!([tid(), "_wbint_LookupUserAliases"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_LookupUserAliases"]
+ delete dc_running[tid(), "_wbint_LookupUserAliases"]
+
+ duration = end - begin
+ dc_svctime["_wbint_LookupUserAliases"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_LookupUserGroups
+#
+
+probe process("winbindd").function("_wbint_LookupUserGroups") {
+ dc_running[tid(), "_wbint_LookupUserGroups"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_LookupUserGroups").return {
+ if (!([tid(), "_wbint_LookupUserGroups"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_LookupUserGroups"]
+ delete dc_running[tid(), "_wbint_LookupUserGroups"]
+
+ duration = end - begin
+ dc_svctime["_wbint_LookupUserGroups"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_QuerySequenceNumber
+#
+
+probe process("winbindd").function("_wbint_QuerySequenceNumber") {
+ dc_running[tid(), "_wbint_QuerySequenceNumber"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_QuerySequenceNumber").return {
+ if (!([tid(), "_wbint_QuerySequenceNumber"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_QuerySequenceNumber"]
+ delete dc_running[tid(), "_wbint_QuerySequenceNumber"]
+
+ duration = end - begin
+ dc_svctime["_wbint_QuerySequenceNumber"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_LookupGroupMembers
+#
+
+probe process("winbindd").function("_wbint_LookupGroupMembers") {
+ dc_running[tid(), "_wbint_LookupGroupMembers"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_LookupGroupMembers").return {
+ if (!([tid(), "_wbint_LookupGroupMembers"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_LookupGroupMembers"]
+ delete dc_running[tid(), "_wbint_LookupGroupMembers"]
+
+ duration = end - begin
+ dc_svctime["_wbint_LookupGroupMembers"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_QueryGroupList
+#
+
+probe process("winbindd").function("_wbint_QueryGroupList") {
+ dc_running[tid(), "_wbint_QueryGroupList"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_QueryGroupList").return {
+ if (!([tid(), "_wbint_QueryGroupList"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_QueryGroupList"]
+ delete dc_running[tid(), "_wbint_QueryGroupList"]
+
+ duration = end - begin
+ dc_svctime["_wbint_QueryGroupList"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_QueryUserRidList
+#
+
+probe process("winbindd").function("_wbint_QueryUserRidList") {
+ dc_running[tid(), "_wbint_QueryUserRidList"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_QueryUserRidList").return {
+ if (!([tid(), "_wbint_QueryUserRidList"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_QueryUserRidList"]
+ delete dc_running[tid(), "_wbint_QueryUserRidList"]
+
+ duration = end - begin
+ dc_svctime["_wbint_QueryUserRidList"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_DsGetDcName
+#
+
+probe process("winbindd").function("_wbint_DsGetDcName") {
+ dc_running[tid(), "_wbint_DsGetDcName"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_DsGetDcName").return {
+ if (!([tid(), "_wbint_DsGetDcName"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_DsGetDcName"]
+ delete dc_running[tid(), "_wbint_DsGetDcName"]
+
+ duration = end - begin
+ dc_svctime["_wbint_DsGetDcName"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_LookupRids
+#
+
+probe process("winbindd").function("_wbint_LookupRids") {
+ dc_running[tid(), "_wbint_LookupRids"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_LookupRids").return {
+ if (!([tid(), "_wbint_LookupRids"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_LookupRids"]
+ delete dc_running[tid(), "_wbint_LookupRids"]
+
+ duration = end - begin
+ dc_svctime["_wbint_LookupRids"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_CheckMachineAccount
+#
+
+probe process("winbindd").function("_wbint_CheckMachineAccount") {
+ dc_running[tid(), "_wbint_CheckMachineAccount"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_CheckMachineAccount").return {
+ if (!([tid(), "_wbint_CheckMachineAccount"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_CheckMachineAccount"]
+ delete dc_running[tid(), "_wbint_CheckMachineAccount"]
+
+ duration = end - begin
+ dc_svctime["_wbint_CheckMachineAccount"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_ChangeMachineAccount
+#
+
+probe process("winbindd").function("_wbint_ChangeMachineAccount") {
+ dc_running[tid(), "_wbint_ChangeMachineAccount"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_ChangeMachineAccount").return {
+ if (!([tid(), "_wbint_ChangeMachineAccount"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_ChangeMachineAccount"]
+ delete dc_running[tid(), "_wbint_ChangeMachineAccount"]
+
+ duration = end - begin
+ dc_svctime["_wbint_ChangeMachineAccount"] <<< duration
+}
+
+#
+# winbind domain child function _wbint_PingDc
+#
+
+probe process("winbindd").function("_wbint_PingDc") {
+ dc_running[tid(), "_wbint_PingDc"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("_wbint_PingDc").return {
+ if (!([tid(), "_wbint_PingDc"] in dc_running))
+ next
+
+ end = gettimeofday_us()
+ begin = dc_running[tid(), "_wbint_PingDc"]
+ delete dc_running[tid(), "_wbint_PingDc"]
+
+ duration = end - begin
+ dc_svctime["_wbint_PingDc"] <<< duration
+}
+
+#
+# winbind domain child backend function query_user_list
+#
+
+probe process("winbindd").function("query_user_list@../source3/winbindd/winbindd_ads.c") {
+ backend_running[tid(), "query_user_list"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("query_user_list@../source3/winbindd/winbindd_ads.c").return {
+ if (!([tid(), "query_user_list"] in backend_running))
+ next
+
+ end = gettimeofday_us()
+ begin = backend_running[tid(), "query_user_list"]
+ delete backend_running[tid(), "query_user_list"]
+
+ duration = end - begin
+ backend_svctime["query_user_list"] <<< duration
+}
+
+#
+# winbind domain child backend function enum_dom_groups
+#
+
+probe process("winbindd").function("enum_dom_groups@../source3/winbindd/winbindd_ads.c") {
+ backend_running[tid(), "enum_dom_groups"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("enum_dom_groups@../source3/winbindd/winbindd_ads.c").return {
+ if (!([tid(), "enum_dom_groups"] in backend_running))
+ next
+
+ end = gettimeofday_us()
+ begin = backend_running[tid(), "enum_dom_groups"]
+ delete backend_running[tid(), "enum_dom_groups"]
+
+ duration = end - begin
+ backend_svctime["enum_dom_groups"] <<< duration
+}
+
+#
+# winbind domain child backend function enum_local_groups
+#
+
+probe process("winbindd").function("enum_local_groups@../source3/winbindd/winbindd_ads.c") {
+ backend_running[tid(), "enum_local_groups"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("enum_local_groups@../source3/winbindd/winbindd_ads.c").return {
+ if (!([tid(), "enum_local_groups"] in backend_running))
+ next
+
+ end = gettimeofday_us()
+ begin = backend_running[tid(), "enum_local_groups"]
+ delete backend_running[tid(), "enum_local_groups"]
+
+ duration = end - begin
+ backend_svctime["enum_local_groups"] <<< duration
+}
+
+#
+# winbind domain child backend function name_to_sid
+#
+
+probe process("winbindd").function("name_to_sid@../source3/winbindd/winbindd_ads.c") {
+ backend_running[tid(), "name_to_sid"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("name_to_sid@../source3/winbindd/winbindd_ads.c").return {
+ if (!([tid(), "name_to_sid"] in backend_running))
+ next
+
+ end = gettimeofday_us()
+ begin = backend_running[tid(), "name_to_sid"]
+ delete backend_running[tid(), "name_to_sid"]
+
+ duration = end - begin
+ backend_svctime["name_to_sid"] <<< duration
+}
+
+#
+# winbind domain child backend function sid_to_name
+#
+
+probe process("winbindd").function("sid_to_name@../source3/winbindd/winbindd_ads.c") {
+ backend_running[tid(), "sid_to_name"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("sid_to_name@../source3/winbindd/winbindd_ads.c").return {
+ if (!([tid(), "sid_to_name"] in backend_running))
+ next
+
+ end = gettimeofday_us()
+ begin = backend_running[tid(), "sid_to_name"]
+ delete backend_running[tid(), "sid_to_name"]
+
+ duration = end - begin
+ backend_svctime["sid_to_name"] <<< duration
+}
+
+#
+# winbind domain child backend function rids_to_names
+#
+
+probe process("winbindd").function("rids_to_names@../source3/winbindd/winbindd_ads.c") {
+ backend_running[tid(), "rids_to_names"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("rids_to_names@../source3/winbindd/winbindd_ads.c").return {
+ if (!([tid(), "rids_to_names"] in backend_running))
+ next
+
+ end = gettimeofday_us()
+ begin = backend_running[tid(), "rids_to_names"]
+ delete backend_running[tid(), "rids_to_names"]
+
+ duration = end - begin
+ backend_svctime["rids_to_names"] <<< duration
+}
+
+#
+# winbind domain child backend function lookup_usergroups
+#
+
+probe process("winbindd").function("lookup_usergroups@../source3/winbindd/winbindd_ads.c") {
+ backend_running[tid(), "lookup_usergroups"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("lookup_usergroups@../source3/winbindd/winbindd_ads.c").return {
+ if (!([tid(), "lookup_usergroups"] in backend_running))
+ next
+
+ end = gettimeofday_us()
+ begin = backend_running[tid(), "lookup_usergroups"]
+ delete backend_running[tid(), "lookup_usergroups"]
+
+ duration = end - begin
+ backend_svctime["lookup_usergroups"] <<< duration
+}
+
+#
+# winbind domain child backend function lookup_useraliases
+#
+
+probe process("winbindd").function("lookup_useraliases@../source3/winbindd/winbindd_ads.c") {
+ backend_running[tid(), "lookup_useraliases"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("lookup_useraliases@../source3/winbindd/winbindd_ads.c").return {
+ if (!([tid(), "lookup_useraliases"] in backend_running))
+ next
+
+ end = gettimeofday_us()
+ begin = backend_running[tid(), "lookup_useraliases"]
+ delete backend_running[tid(), "lookup_useraliases"]
+
+ duration = end - begin
+ backend_svctime["lookup_useraliases"] <<< duration
+}
+
+#
+# winbind domain child backend function lookup_groupmem
+#
+
+probe process("winbindd").function("lookup_groupmem@../source3/winbindd/winbindd_ads.c") {
+ backend_running[tid(), "lookup_groupmem"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("lookup_groupmem@../source3/winbindd/winbindd_ads.c").return {
+ if (!([tid(), "lookup_groupmem"] in backend_running))
+ next
+
+ end = gettimeofday_us()
+ begin = backend_running[tid(), "lookup_groupmem"]
+ delete backend_running[tid(), "lookup_groupmem"]
+
+ duration = end - begin
+ backend_svctime["lookup_groupmem"] <<< duration
+}
+
+#
+# winbind domain child backend function sequence_number
+#
+
+probe process("winbindd").function("sequence_number@../source3/winbindd/winbindd_ads.c") {
+ backend_running[tid(), "sequence_number"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("sequence_number@../source3/winbindd/winbindd_ads.c").return {
+ if (!([tid(), "sequence_number"] in backend_running))
+ next
+
+ end = gettimeofday_us()
+ begin = backend_running[tid(), "sequence_number"]
+ delete backend_running[tid(), "sequence_number"]
+
+ duration = end - begin
+ backend_svctime["sequence_number"] <<< duration
+}
+
+#
+# winbind domain child backend function lockout_policy
+#
+
+probe process("winbindd").function("lockout_policy@../source3/winbindd/winbindd_ads.c") {
+ backend_running[tid(), "lockout_policy"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("lockout_policy@../source3/winbindd/winbindd_ads.c").return {
+ if (!([tid(), "lockout_policy"] in backend_running))
+ next
+
+ end = gettimeofday_us()
+ begin = backend_running[tid(), "lockout_policy"]
+ delete backend_running[tid(), "lockout_policy"]
+
+ duration = end - begin
+ backend_svctime["lockout_policy"] <<< duration
+}
+
+#
+# winbind domain child backend function password_policy
+#
+
+probe process("winbindd").function("password_policy@../source3/winbindd/winbindd_ads.c") {
+ backend_running[tid(), "password_policy"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("password_policy@../source3/winbindd/winbindd_ads.c").return {
+ if (!([tid(), "password_policy"] in backend_running))
+ next
+
+ end = gettimeofday_us()
+ begin = backend_running[tid(), "password_policy"]
+ delete backend_running[tid(), "password_policy"]
+
+ duration = end - begin
+ backend_svctime["password_policy"] <<< duration
+}
+
+#
+# winbind domain child backend function trusted_domains
+#
+
+probe process("winbindd").function("trusted_domains@../source3/winbindd/winbindd_ads.c") {
+ backend_running[tid(), "trusted_domains"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("trusted_domains@../source3/winbindd/winbindd_ads.c").return {
+ if (!([tid(), "trusted_domains"] in backend_running))
+ next
+
+ end = gettimeofday_us()
+ begin = backend_running[tid(), "trusted_domains"]
+ delete backend_running[tid(), "trusted_domains"]
+
+ duration = end - begin
+ backend_svctime["trusted_domains"] <<< duration
+}
+
+#
+# winbind async function wb_ping
+#
+
+probe process("winbindd").function("wb_ping_send") {
+ send_running["wb_ping_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("wb_ping_send").return {
+ if (!(["wb_ping_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["wb_ping_send"]
+ delete send_running["wb_ping_send"]
+
+ start_time["wb_ping_send", $return] = start
+ idle_time["wb_ping_send", $return] = end
+}
+
+probe process("winbindd").function("wb_ping_recv") {
+ if (!(["wb_ping_send", $req] in start_time))
+ next
+
+ recv_running["wb_ping_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("wb_ping_recv").return {
+ if (!(["wb_ping_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["wb_ping_recv"]
+ delete recv_running["wb_ping_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["wb_ping_send", req]
+ delete start_time["wb_ping_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["wb_ping_send", req]
+ delete idle_time["wb_ping_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["wb_ping_send"] <<< svctime
+ async_runtime["wb_ping_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_lookupsid
+#
+
+probe process("winbindd").function("winbindd_lookupsid_send") {
+ send_running["winbindd_lookupsid_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_lookupsid_send").return {
+ if (!(["winbindd_lookupsid_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_lookupsid_send"]
+ delete send_running["winbindd_lookupsid_send"]
+
+ start_time["winbindd_lookupsid_send", $return] = start
+ idle_time["winbindd_lookupsid_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_lookupsid_recv") {
+ if (!(["winbindd_lookupsid_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_lookupsid_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_lookupsid_recv").return {
+ if (!(["winbindd_lookupsid_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_lookupsid_recv"]
+ delete recv_running["winbindd_lookupsid_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_lookupsid_send", req]
+ delete start_time["winbindd_lookupsid_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_lookupsid_send", req]
+ delete idle_time["winbindd_lookupsid_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_lookupsid_send"] <<< svctime
+ async_runtime["winbindd_lookupsid_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_lookupsids
+#
+
+probe process("winbindd").function("winbindd_lookupsids_send") {
+ send_running["winbindd_lookupsids_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_lookupsids_send").return {
+ if (!(["winbindd_lookupsids_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_lookupsids_send"]
+ delete send_running["winbindd_lookupsids_send"]
+
+ start_time["winbindd_lookupsids_send", $return] = start
+ idle_time["winbindd_lookupsids_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_lookupsids_recv") {
+ if (!(["winbindd_lookupsids_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_lookupsids_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_lookupsids_recv").return {
+ if (!(["winbindd_lookupsids_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_lookupsids_recv"]
+ delete recv_running["winbindd_lookupsids_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_lookupsids_send", req]
+ delete start_time["winbindd_lookupsids_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_lookupsids_send", req]
+ delete idle_time["winbindd_lookupsids_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_lookupsids_send"] <<< svctime
+ async_runtime["winbindd_lookupsids_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_lookupname
+#
+
+probe process("winbindd").function("winbindd_lookupname_send") {
+ send_running["winbindd_lookupname_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_lookupname_send").return {
+ if (!(["winbindd_lookupname_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_lookupname_send"]
+ delete send_running["winbindd_lookupname_send"]
+
+ start_time["winbindd_lookupname_send", $return] = start
+ idle_time["winbindd_lookupname_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_lookupname_recv") {
+ if (!(["winbindd_lookupname_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_lookupname_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_lookupname_recv").return {
+ if (!(["winbindd_lookupname_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_lookupname_recv"]
+ delete recv_running["winbindd_lookupname_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_lookupname_send", req]
+ delete start_time["winbindd_lookupname_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_lookupname_send", req]
+ delete idle_time["winbindd_lookupname_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_lookupname_send"] <<< svctime
+ async_runtime["winbindd_lookupname_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_sids_to_xids
+#
+
+probe process("winbindd").function("winbindd_sids_to_xids_send") {
+ send_running["winbindd_sids_to_xids_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_sids_to_xids_send").return {
+ if (!(["winbindd_sids_to_xids_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_sids_to_xids_send"]
+ delete send_running["winbindd_sids_to_xids_send"]
+
+ start_time["winbindd_sids_to_xids_send", $return] = start
+ idle_time["winbindd_sids_to_xids_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_sids_to_xids_recv") {
+ if (!(["winbindd_sids_to_xids_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_sids_to_xids_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_sids_to_xids_recv").return {
+ if (!(["winbindd_sids_to_xids_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_sids_to_xids_recv"]
+ delete recv_running["winbindd_sids_to_xids_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_sids_to_xids_send", req]
+ delete start_time["winbindd_sids_to_xids_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_sids_to_xids_send", req]
+ delete idle_time["winbindd_sids_to_xids_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_sids_to_xids_send"] <<< svctime
+ async_runtime["winbindd_sids_to_xids_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_xids_to_sids
+#
+
+probe process("winbindd").function("winbindd_xids_to_sids_send") {
+ send_running["winbindd_xids_to_sids_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_xids_to_sids_send").return {
+ if (!(["winbindd_xids_to_sids_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_xids_to_sids_send"]
+ delete send_running["winbindd_xids_to_sids_send"]
+
+ start_time["winbindd_xids_to_sids_send", $return] = start
+ idle_time["winbindd_xids_to_sids_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_xids_to_sids_recv") {
+ if (!(["winbindd_xids_to_sids_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_xids_to_sids_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_xids_to_sids_recv").return {
+ if (!(["winbindd_xids_to_sids_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_xids_to_sids_recv"]
+ delete recv_running["winbindd_xids_to_sids_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_xids_to_sids_send", req]
+ delete start_time["winbindd_xids_to_sids_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_xids_to_sids_send", req]
+ delete idle_time["winbindd_xids_to_sids_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_xids_to_sids_send"] <<< svctime
+ async_runtime["winbindd_xids_to_sids_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_getpwsid
+#
+
+probe process("winbindd").function("winbindd_getpwsid_send") {
+ send_running["winbindd_getpwsid_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getpwsid_send").return {
+ if (!(["winbindd_getpwsid_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_getpwsid_send"]
+ delete send_running["winbindd_getpwsid_send"]
+
+ start_time["winbindd_getpwsid_send", $return] = start
+ idle_time["winbindd_getpwsid_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_getpwsid_recv") {
+ if (!(["winbindd_getpwsid_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_getpwsid_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getpwsid_recv").return {
+ if (!(["winbindd_getpwsid_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_getpwsid_recv"]
+ delete recv_running["winbindd_getpwsid_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_getpwsid_send", req]
+ delete start_time["winbindd_getpwsid_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_getpwsid_send", req]
+ delete idle_time["winbindd_getpwsid_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_getpwsid_send"] <<< svctime
+ async_runtime["winbindd_getpwsid_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_getpwnam
+#
+
+probe process("winbindd").function("winbindd_getpwnam_send") {
+ send_running["winbindd_getpwnam_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getpwnam_send").return {
+ if (!(["winbindd_getpwnam_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_getpwnam_send"]
+ delete send_running["winbindd_getpwnam_send"]
+
+ start_time["winbindd_getpwnam_send", $return] = start
+ idle_time["winbindd_getpwnam_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_getpwnam_recv") {
+ if (!(["winbindd_getpwnam_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_getpwnam_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getpwnam_recv").return {
+ if (!(["winbindd_getpwnam_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_getpwnam_recv"]
+ delete recv_running["winbindd_getpwnam_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_getpwnam_send", req]
+ delete start_time["winbindd_getpwnam_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_getpwnam_send", req]
+ delete idle_time["winbindd_getpwnam_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_getpwnam_send"] <<< svctime
+ async_runtime["winbindd_getpwnam_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_getpwuid
+#
+
+probe process("winbindd").function("winbindd_getpwuid_send") {
+ send_running["winbindd_getpwuid_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getpwuid_send").return {
+ if (!(["winbindd_getpwuid_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_getpwuid_send"]
+ delete send_running["winbindd_getpwuid_send"]
+
+ start_time["winbindd_getpwuid_send", $return] = start
+ idle_time["winbindd_getpwuid_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_getpwuid_recv") {
+ if (!(["winbindd_getpwuid_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_getpwuid_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getpwuid_recv").return {
+ if (!(["winbindd_getpwuid_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_getpwuid_recv"]
+ delete recv_running["winbindd_getpwuid_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_getpwuid_send", req]
+ delete start_time["winbindd_getpwuid_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_getpwuid_send", req]
+ delete idle_time["winbindd_getpwuid_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_getpwuid_send"] <<< svctime
+ async_runtime["winbindd_getpwuid_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_getsidaliases
+#
+
+probe process("winbindd").function("winbindd_getsidaliases_send") {
+ send_running["winbindd_getsidaliases_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getsidaliases_send").return {
+ if (!(["winbindd_getsidaliases_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_getsidaliases_send"]
+ delete send_running["winbindd_getsidaliases_send"]
+
+ start_time["winbindd_getsidaliases_send", $return] = start
+ idle_time["winbindd_getsidaliases_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_getsidaliases_recv") {
+ if (!(["winbindd_getsidaliases_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_getsidaliases_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getsidaliases_recv").return {
+ if (!(["winbindd_getsidaliases_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_getsidaliases_recv"]
+ delete recv_running["winbindd_getsidaliases_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_getsidaliases_send", req]
+ delete start_time["winbindd_getsidaliases_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_getsidaliases_send", req]
+ delete idle_time["winbindd_getsidaliases_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_getsidaliases_send"] <<< svctime
+ async_runtime["winbindd_getsidaliases_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_getuserdomgroups
+#
+
+probe process("winbindd").function("winbindd_getuserdomgroups_send") {
+ send_running["winbindd_getuserdomgroups_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getuserdomgroups_send").return {
+ if (!(["winbindd_getuserdomgroups_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_getuserdomgroups_send"]
+ delete send_running["winbindd_getuserdomgroups_send"]
+
+ start_time["winbindd_getuserdomgroups_send", $return] = start
+ idle_time["winbindd_getuserdomgroups_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_getuserdomgroups_recv") {
+ if (!(["winbindd_getuserdomgroups_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_getuserdomgroups_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getuserdomgroups_recv").return {
+ if (!(["winbindd_getuserdomgroups_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_getuserdomgroups_recv"]
+ delete recv_running["winbindd_getuserdomgroups_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_getuserdomgroups_send", req]
+ delete start_time["winbindd_getuserdomgroups_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_getuserdomgroups_send", req]
+ delete idle_time["winbindd_getuserdomgroups_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_getuserdomgroups_send"] <<< svctime
+ async_runtime["winbindd_getuserdomgroups_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_getgroups
+#
+
+probe process("winbindd").function("winbindd_getgroups_send") {
+ send_running["winbindd_getgroups_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getgroups_send").return {
+ if (!(["winbindd_getgroups_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_getgroups_send"]
+ delete send_running["winbindd_getgroups_send"]
+
+ start_time["winbindd_getgroups_send", $return] = start
+ idle_time["winbindd_getgroups_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_getgroups_recv") {
+ if (!(["winbindd_getgroups_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_getgroups_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getgroups_recv").return {
+ if (!(["winbindd_getgroups_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_getgroups_recv"]
+ delete recv_running["winbindd_getgroups_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_getgroups_send", req]
+ delete start_time["winbindd_getgroups_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_getgroups_send", req]
+ delete idle_time["winbindd_getgroups_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_getgroups_send"] <<< svctime
+ async_runtime["winbindd_getgroups_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_show_sequence
+#
+
+probe process("winbindd").function("winbindd_show_sequence_send") {
+ send_running["winbindd_show_sequence_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_show_sequence_send").return {
+ if (!(["winbindd_show_sequence_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_show_sequence_send"]
+ delete send_running["winbindd_show_sequence_send"]
+
+ start_time["winbindd_show_sequence_send", $return] = start
+ idle_time["winbindd_show_sequence_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_show_sequence_recv") {
+ if (!(["winbindd_show_sequence_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_show_sequence_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_show_sequence_recv").return {
+ if (!(["winbindd_show_sequence_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_show_sequence_recv"]
+ delete recv_running["winbindd_show_sequence_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_show_sequence_send", req]
+ delete start_time["winbindd_show_sequence_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_show_sequence_send", req]
+ delete idle_time["winbindd_show_sequence_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_show_sequence_send"] <<< svctime
+ async_runtime["winbindd_show_sequence_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_getgrgid
+#
+
+probe process("winbindd").function("winbindd_getgrgid_send") {
+ send_running["winbindd_getgrgid_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getgrgid_send").return {
+ if (!(["winbindd_getgrgid_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_getgrgid_send"]
+ delete send_running["winbindd_getgrgid_send"]
+
+ start_time["winbindd_getgrgid_send", $return] = start
+ idle_time["winbindd_getgrgid_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_getgrgid_recv") {
+ if (!(["winbindd_getgrgid_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_getgrgid_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getgrgid_recv").return {
+ if (!(["winbindd_getgrgid_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_getgrgid_recv"]
+ delete recv_running["winbindd_getgrgid_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_getgrgid_send", req]
+ delete start_time["winbindd_getgrgid_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_getgrgid_send", req]
+ delete idle_time["winbindd_getgrgid_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_getgrgid_send"] <<< svctime
+ async_runtime["winbindd_getgrgid_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_getgrnam
+#
+
+probe process("winbindd").function("winbindd_getgrnam_send") {
+ send_running["winbindd_getgrnam_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getgrnam_send").return {
+ if (!(["winbindd_getgrnam_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_getgrnam_send"]
+ delete send_running["winbindd_getgrnam_send"]
+
+ start_time["winbindd_getgrnam_send", $return] = start
+ idle_time["winbindd_getgrnam_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_getgrnam_recv") {
+ if (!(["winbindd_getgrnam_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_getgrnam_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getgrnam_recv").return {
+ if (!(["winbindd_getgrnam_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_getgrnam_recv"]
+ delete recv_running["winbindd_getgrnam_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_getgrnam_send", req]
+ delete start_time["winbindd_getgrnam_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_getgrnam_send", req]
+ delete idle_time["winbindd_getgrnam_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_getgrnam_send"] <<< svctime
+ async_runtime["winbindd_getgrnam_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_getusersids
+#
+
+probe process("winbindd").function("winbindd_getusersids_send") {
+ send_running["winbindd_getusersids_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getusersids_send").return {
+ if (!(["winbindd_getusersids_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_getusersids_send"]
+ delete send_running["winbindd_getusersids_send"]
+
+ start_time["winbindd_getusersids_send", $return] = start
+ idle_time["winbindd_getusersids_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_getusersids_recv") {
+ if (!(["winbindd_getusersids_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_getusersids_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getusersids_recv").return {
+ if (!(["winbindd_getusersids_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_getusersids_recv"]
+ delete recv_running["winbindd_getusersids_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_getusersids_send", req]
+ delete start_time["winbindd_getusersids_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_getusersids_send", req]
+ delete idle_time["winbindd_getusersids_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_getusersids_send"] <<< svctime
+ async_runtime["winbindd_getusersids_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_lookuprids
+#
+
+probe process("winbindd").function("winbindd_lookuprids_send") {
+ send_running["winbindd_lookuprids_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_lookuprids_send").return {
+ if (!(["winbindd_lookuprids_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_lookuprids_send"]
+ delete send_running["winbindd_lookuprids_send"]
+
+ start_time["winbindd_lookuprids_send", $return] = start
+ idle_time["winbindd_lookuprids_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_lookuprids_recv") {
+ if (!(["winbindd_lookuprids_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_lookuprids_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_lookuprids_recv").return {
+ if (!(["winbindd_lookuprids_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_lookuprids_recv"]
+ delete recv_running["winbindd_lookuprids_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_lookuprids_send", req]
+ delete start_time["winbindd_lookuprids_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_lookuprids_send", req]
+ delete idle_time["winbindd_lookuprids_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_lookuprids_send"] <<< svctime
+ async_runtime["winbindd_lookuprids_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_setpwent
+#
+
+probe process("winbindd").function("winbindd_setpwent_send") {
+ send_running["winbindd_setpwent_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_setpwent_send").return {
+ if (!(["winbindd_setpwent_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_setpwent_send"]
+ delete send_running["winbindd_setpwent_send"]
+
+ start_time["winbindd_setpwent_send", $return] = start
+ idle_time["winbindd_setpwent_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_setpwent_recv") {
+ if (!(["winbindd_setpwent_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_setpwent_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_setpwent_recv").return {
+ if (!(["winbindd_setpwent_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_setpwent_recv"]
+ delete recv_running["winbindd_setpwent_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_setpwent_send", req]
+ delete start_time["winbindd_setpwent_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_setpwent_send", req]
+ delete idle_time["winbindd_setpwent_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_setpwent_send"] <<< svctime
+ async_runtime["winbindd_setpwent_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_getpwent
+#
+
+probe process("winbindd").function("winbindd_getpwent_send") {
+ send_running["winbindd_getpwent_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getpwent_send").return {
+ if (!(["winbindd_getpwent_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_getpwent_send"]
+ delete send_running["winbindd_getpwent_send"]
+
+ start_time["winbindd_getpwent_send", $return] = start
+ idle_time["winbindd_getpwent_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_getpwent_recv") {
+ if (!(["winbindd_getpwent_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_getpwent_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getpwent_recv").return {
+ if (!(["winbindd_getpwent_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_getpwent_recv"]
+ delete recv_running["winbindd_getpwent_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_getpwent_send", req]
+ delete start_time["winbindd_getpwent_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_getpwent_send", req]
+ delete idle_time["winbindd_getpwent_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_getpwent_send"] <<< svctime
+ async_runtime["winbindd_getpwent_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_endpwent
+#
+
+probe process("winbindd").function("winbindd_endpwent_send") {
+ send_running["winbindd_endpwent_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_endpwent_send").return {
+ if (!(["winbindd_endpwent_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_endpwent_send"]
+ delete send_running["winbindd_endpwent_send"]
+
+ start_time["winbindd_endpwent_send", $return] = start
+ idle_time["winbindd_endpwent_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_endpwent_recv") {
+ if (!(["winbindd_endpwent_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_endpwent_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_endpwent_recv").return {
+ if (!(["winbindd_endpwent_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_endpwent_recv"]
+ delete recv_running["winbindd_endpwent_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_endpwent_send", req]
+ delete start_time["winbindd_endpwent_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_endpwent_send", req]
+ delete idle_time["winbindd_endpwent_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_endpwent_send"] <<< svctime
+ async_runtime["winbindd_endpwent_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_dsgetdcname
+#
+
+probe process("winbindd").function("winbindd_dsgetdcname_send") {
+ send_running["winbindd_dsgetdcname_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_dsgetdcname_send").return {
+ if (!(["winbindd_dsgetdcname_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_dsgetdcname_send"]
+ delete send_running["winbindd_dsgetdcname_send"]
+
+ start_time["winbindd_dsgetdcname_send", $return] = start
+ idle_time["winbindd_dsgetdcname_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_dsgetdcname_recv") {
+ if (!(["winbindd_dsgetdcname_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_dsgetdcname_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_dsgetdcname_recv").return {
+ if (!(["winbindd_dsgetdcname_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_dsgetdcname_recv"]
+ delete recv_running["winbindd_dsgetdcname_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_dsgetdcname_send", req]
+ delete start_time["winbindd_dsgetdcname_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_dsgetdcname_send", req]
+ delete idle_time["winbindd_dsgetdcname_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_dsgetdcname_send"] <<< svctime
+ async_runtime["winbindd_dsgetdcname_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_getdcname
+#
+
+probe process("winbindd").function("winbindd_getdcname_send") {
+ send_running["winbindd_getdcname_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getdcname_send").return {
+ if (!(["winbindd_getdcname_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_getdcname_send"]
+ delete send_running["winbindd_getdcname_send"]
+
+ start_time["winbindd_getdcname_send", $return] = start
+ idle_time["winbindd_getdcname_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_getdcname_recv") {
+ if (!(["winbindd_getdcname_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_getdcname_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getdcname_recv").return {
+ if (!(["winbindd_getdcname_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_getdcname_recv"]
+ delete recv_running["winbindd_getdcname_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_getdcname_send", req]
+ delete start_time["winbindd_getdcname_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_getdcname_send", req]
+ delete idle_time["winbindd_getdcname_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_getdcname_send"] <<< svctime
+ async_runtime["winbindd_getdcname_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_setgrent
+#
+
+probe process("winbindd").function("winbindd_setgrent_send") {
+ send_running["winbindd_setgrent_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_setgrent_send").return {
+ if (!(["winbindd_setgrent_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_setgrent_send"]
+ delete send_running["winbindd_setgrent_send"]
+
+ start_time["winbindd_setgrent_send", $return] = start
+ idle_time["winbindd_setgrent_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_setgrent_recv") {
+ if (!(["winbindd_setgrent_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_setgrent_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_setgrent_recv").return {
+ if (!(["winbindd_setgrent_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_setgrent_recv"]
+ delete recv_running["winbindd_setgrent_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_setgrent_send", req]
+ delete start_time["winbindd_setgrent_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_setgrent_send", req]
+ delete idle_time["winbindd_setgrent_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_setgrent_send"] <<< svctime
+ async_runtime["winbindd_setgrent_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_getgrent
+#
+
+probe process("winbindd").function("winbindd_getgrent_send") {
+ send_running["winbindd_getgrent_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getgrent_send").return {
+ if (!(["winbindd_getgrent_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_getgrent_send"]
+ delete send_running["winbindd_getgrent_send"]
+
+ start_time["winbindd_getgrent_send", $return] = start
+ idle_time["winbindd_getgrent_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_getgrent_recv") {
+ if (!(["winbindd_getgrent_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_getgrent_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_getgrent_recv").return {
+ if (!(["winbindd_getgrent_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_getgrent_recv"]
+ delete recv_running["winbindd_getgrent_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_getgrent_send", req]
+ delete start_time["winbindd_getgrent_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_getgrent_send", req]
+ delete idle_time["winbindd_getgrent_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_getgrent_send"] <<< svctime
+ async_runtime["winbindd_getgrent_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_endgrent
+#
+
+probe process("winbindd").function("winbindd_endgrent_send") {
+ send_running["winbindd_endgrent_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_endgrent_send").return {
+ if (!(["winbindd_endgrent_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_endgrent_send"]
+ delete send_running["winbindd_endgrent_send"]
+
+ start_time["winbindd_endgrent_send", $return] = start
+ idle_time["winbindd_endgrent_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_endgrent_recv") {
+ if (!(["winbindd_endgrent_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_endgrent_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_endgrent_recv").return {
+ if (!(["winbindd_endgrent_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_endgrent_recv"]
+ delete recv_running["winbindd_endgrent_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_endgrent_send", req]
+ delete start_time["winbindd_endgrent_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_endgrent_send", req]
+ delete idle_time["winbindd_endgrent_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_endgrent_send"] <<< svctime
+ async_runtime["winbindd_endgrent_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_list_users
+#
+
+probe process("winbindd").function("winbindd_list_users_send") {
+ send_running["winbindd_list_users_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_list_users_send").return {
+ if (!(["winbindd_list_users_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_list_users_send"]
+ delete send_running["winbindd_list_users_send"]
+
+ start_time["winbindd_list_users_send", $return] = start
+ idle_time["winbindd_list_users_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_list_users_recv") {
+ if (!(["winbindd_list_users_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_list_users_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_list_users_recv").return {
+ if (!(["winbindd_list_users_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_list_users_recv"]
+ delete recv_running["winbindd_list_users_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_list_users_send", req]
+ delete start_time["winbindd_list_users_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_list_users_send", req]
+ delete idle_time["winbindd_list_users_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_list_users_send"] <<< svctime
+ async_runtime["winbindd_list_users_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_list_groups
+#
+
+probe process("winbindd").function("winbindd_list_groups_send") {
+ send_running["winbindd_list_groups_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_list_groups_send").return {
+ if (!(["winbindd_list_groups_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_list_groups_send"]
+ delete send_running["winbindd_list_groups_send"]
+
+ start_time["winbindd_list_groups_send", $return] = start
+ idle_time["winbindd_list_groups_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_list_groups_recv") {
+ if (!(["winbindd_list_groups_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_list_groups_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_list_groups_recv").return {
+ if (!(["winbindd_list_groups_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_list_groups_recv"]
+ delete recv_running["winbindd_list_groups_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_list_groups_send", req]
+ delete start_time["winbindd_list_groups_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_list_groups_send", req]
+ delete idle_time["winbindd_list_groups_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_list_groups_send"] <<< svctime
+ async_runtime["winbindd_list_groups_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_check_machine_acct
+#
+
+probe process("winbindd").function("winbindd_check_machine_acct_send") {
+ send_running["winbindd_check_machine_acct_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_check_machine_acct_send").return {
+ if (!(["winbindd_check_machine_acct_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_check_machine_acct_send"]
+ delete send_running["winbindd_check_machine_acct_send"]
+
+ start_time["winbindd_check_machine_acct_send", $return] = start
+ idle_time["winbindd_check_machine_acct_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_check_machine_acct_recv") {
+ if (!(["winbindd_check_machine_acct_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_check_machine_acct_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_check_machine_acct_recv").return {
+ if (!(["winbindd_check_machine_acct_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_check_machine_acct_recv"]
+ delete recv_running["winbindd_check_machine_acct_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_check_machine_acct_send", req]
+ delete start_time["winbindd_check_machine_acct_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_check_machine_acct_send", req]
+ delete idle_time["winbindd_check_machine_acct_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_check_machine_acct_send"] <<< svctime
+ async_runtime["winbindd_check_machine_acct_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_ping_dc
+#
+
+probe process("winbindd").function("winbindd_ping_dc_send") {
+ send_running["winbindd_ping_dc_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_ping_dc_send").return {
+ if (!(["winbindd_ping_dc_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_ping_dc_send"]
+ delete send_running["winbindd_ping_dc_send"]
+
+ start_time["winbindd_ping_dc_send", $return] = start
+ idle_time["winbindd_ping_dc_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_ping_dc_recv") {
+ if (!(["winbindd_ping_dc_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_ping_dc_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_ping_dc_recv").return {
+ if (!(["winbindd_ping_dc_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_ping_dc_recv"]
+ delete recv_running["winbindd_ping_dc_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_ping_dc_send", req]
+ delete start_time["winbindd_ping_dc_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_ping_dc_send", req]
+ delete idle_time["winbindd_ping_dc_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_ping_dc_send"] <<< svctime
+ async_runtime["winbindd_ping_dc_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_pam_auth
+#
+
+probe process("winbindd").function("winbindd_pam_auth_send") {
+ send_running["winbindd_pam_auth_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_pam_auth_send").return {
+ if (!(["winbindd_pam_auth_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_pam_auth_send"]
+ delete send_running["winbindd_pam_auth_send"]
+
+ start_time["winbindd_pam_auth_send", $return] = start
+ idle_time["winbindd_pam_auth_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_pam_auth_recv") {
+ if (!(["winbindd_pam_auth_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_pam_auth_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_pam_auth_recv").return {
+ if (!(["winbindd_pam_auth_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_pam_auth_recv"]
+ delete recv_running["winbindd_pam_auth_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_pam_auth_send", req]
+ delete start_time["winbindd_pam_auth_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_pam_auth_send", req]
+ delete idle_time["winbindd_pam_auth_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_pam_auth_send"] <<< svctime
+ async_runtime["winbindd_pam_auth_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_pam_logoff
+#
+
+probe process("winbindd").function("winbindd_pam_logoff_send") {
+ send_running["winbindd_pam_logoff_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_pam_logoff_send").return {
+ if (!(["winbindd_pam_logoff_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_pam_logoff_send"]
+ delete send_running["winbindd_pam_logoff_send"]
+
+ start_time["winbindd_pam_logoff_send", $return] = start
+ idle_time["winbindd_pam_logoff_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_pam_logoff_recv") {
+ if (!(["winbindd_pam_logoff_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_pam_logoff_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_pam_logoff_recv").return {
+ if (!(["winbindd_pam_logoff_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_pam_logoff_recv"]
+ delete recv_running["winbindd_pam_logoff_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_pam_logoff_send", req]
+ delete start_time["winbindd_pam_logoff_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_pam_logoff_send", req]
+ delete idle_time["winbindd_pam_logoff_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_pam_logoff_send"] <<< svctime
+ async_runtime["winbindd_pam_logoff_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_pam_chauthtok
+#
+
+probe process("winbindd").function("winbindd_pam_chauthtok_send") {
+ send_running["winbindd_pam_chauthtok_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_pam_chauthtok_send").return {
+ if (!(["winbindd_pam_chauthtok_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_pam_chauthtok_send"]
+ delete send_running["winbindd_pam_chauthtok_send"]
+
+ start_time["winbindd_pam_chauthtok_send", $return] = start
+ idle_time["winbindd_pam_chauthtok_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_pam_chauthtok_recv") {
+ if (!(["winbindd_pam_chauthtok_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_pam_chauthtok_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_pam_chauthtok_recv").return {
+ if (!(["winbindd_pam_chauthtok_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_pam_chauthtok_recv"]
+ delete recv_running["winbindd_pam_chauthtok_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_pam_chauthtok_send", req]
+ delete start_time["winbindd_pam_chauthtok_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_pam_chauthtok_send", req]
+ delete idle_time["winbindd_pam_chauthtok_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_pam_chauthtok_send"] <<< svctime
+ async_runtime["winbindd_pam_chauthtok_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_pam_chng_pswd_auth_crap
+#
+
+probe process("winbindd").function("winbindd_pam_chng_pswd_auth_crap_send") {
+ send_running["winbindd_pam_chng_pswd_auth_crap_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_pam_chng_pswd_auth_crap_send").return {
+ if (!(["winbindd_pam_chng_pswd_auth_crap_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_pam_chng_pswd_auth_crap_send"]
+ delete send_running["winbindd_pam_chng_pswd_auth_crap_send"]
+
+ start_time["winbindd_pam_chng_pswd_auth_crap_send", $return] = start
+ idle_time["winbindd_pam_chng_pswd_auth_crap_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_pam_chng_pswd_auth_crap_recv") {
+ if (!(["winbindd_pam_chng_pswd_auth_crap_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_pam_chng_pswd_auth_crap_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_pam_chng_pswd_auth_crap_recv").return {
+ if (!(["winbindd_pam_chng_pswd_auth_crap_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_pam_chng_pswd_auth_crap_recv"]
+ delete recv_running["winbindd_pam_chng_pswd_auth_crap_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_pam_chng_pswd_auth_crap_send", req]
+ delete start_time["winbindd_pam_chng_pswd_auth_crap_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_pam_chng_pswd_auth_crap_send", req]
+ delete idle_time["winbindd_pam_chng_pswd_auth_crap_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_pam_chng_pswd_auth_crap_send"] <<< svctime
+ async_runtime["winbindd_pam_chng_pswd_auth_crap_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_wins_byip
+#
+
+probe process("winbindd").function("winbindd_wins_byip_send") {
+ send_running["winbindd_wins_byip_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_wins_byip_send").return {
+ if (!(["winbindd_wins_byip_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_wins_byip_send"]
+ delete send_running["winbindd_wins_byip_send"]
+
+ start_time["winbindd_wins_byip_send", $return] = start
+ idle_time["winbindd_wins_byip_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_wins_byip_recv") {
+ if (!(["winbindd_wins_byip_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_wins_byip_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_wins_byip_recv").return {
+ if (!(["winbindd_wins_byip_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_wins_byip_recv"]
+ delete recv_running["winbindd_wins_byip_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_wins_byip_send", req]
+ delete start_time["winbindd_wins_byip_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_wins_byip_send", req]
+ delete idle_time["winbindd_wins_byip_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_wins_byip_send"] <<< svctime
+ async_runtime["winbindd_wins_byip_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_wins_byname
+#
+
+probe process("winbindd").function("winbindd_wins_byname_send") {
+ send_running["winbindd_wins_byname_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_wins_byname_send").return {
+ if (!(["winbindd_wins_byname_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_wins_byname_send"]
+ delete send_running["winbindd_wins_byname_send"]
+
+ start_time["winbindd_wins_byname_send", $return] = start
+ idle_time["winbindd_wins_byname_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_wins_byname_recv") {
+ if (!(["winbindd_wins_byname_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_wins_byname_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_wins_byname_recv").return {
+ if (!(["winbindd_wins_byname_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_wins_byname_recv"]
+ delete recv_running["winbindd_wins_byname_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_wins_byname_send", req]
+ delete start_time["winbindd_wins_byname_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_wins_byname_send", req]
+ delete idle_time["winbindd_wins_byname_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_wins_byname_send"] <<< svctime
+ async_runtime["winbindd_wins_byname_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_allocate_uid
+#
+
+probe process("winbindd").function("winbindd_allocate_uid_send") {
+ send_running["winbindd_allocate_uid_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_allocate_uid_send").return {
+ if (!(["winbindd_allocate_uid_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_allocate_uid_send"]
+ delete send_running["winbindd_allocate_uid_send"]
+
+ start_time["winbindd_allocate_uid_send", $return] = start
+ idle_time["winbindd_allocate_uid_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_allocate_uid_recv") {
+ if (!(["winbindd_allocate_uid_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_allocate_uid_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_allocate_uid_recv").return {
+ if (!(["winbindd_allocate_uid_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_allocate_uid_recv"]
+ delete recv_running["winbindd_allocate_uid_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_allocate_uid_send", req]
+ delete start_time["winbindd_allocate_uid_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_allocate_uid_send", req]
+ delete idle_time["winbindd_allocate_uid_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_allocate_uid_send"] <<< svctime
+ async_runtime["winbindd_allocate_uid_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_allocate_gid
+#
+
+probe process("winbindd").function("winbindd_allocate_gid_send") {
+ send_running["winbindd_allocate_gid_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_allocate_gid_send").return {
+ if (!(["winbindd_allocate_gid_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_allocate_gid_send"]
+ delete send_running["winbindd_allocate_gid_send"]
+
+ start_time["winbindd_allocate_gid_send", $return] = start
+ idle_time["winbindd_allocate_gid_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_allocate_gid_recv") {
+ if (!(["winbindd_allocate_gid_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_allocate_gid_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_allocate_gid_recv").return {
+ if (!(["winbindd_allocate_gid_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_allocate_gid_recv"]
+ delete recv_running["winbindd_allocate_gid_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_allocate_gid_send", req]
+ delete start_time["winbindd_allocate_gid_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_allocate_gid_send", req]
+ delete idle_time["winbindd_allocate_gid_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_allocate_gid_send"] <<< svctime
+ async_runtime["winbindd_allocate_gid_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_change_machine_acct
+#
+
+probe process("winbindd").function("winbindd_change_machine_acct_send") {
+ send_running["winbindd_change_machine_acct_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_change_machine_acct_send").return {
+ if (!(["winbindd_change_machine_acct_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_change_machine_acct_send"]
+ delete send_running["winbindd_change_machine_acct_send"]
+
+ start_time["winbindd_change_machine_acct_send", $return] = start
+ idle_time["winbindd_change_machine_acct_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_change_machine_acct_recv") {
+ if (!(["winbindd_change_machine_acct_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_change_machine_acct_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_change_machine_acct_recv").return {
+ if (!(["winbindd_change_machine_acct_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_change_machine_acct_recv"]
+ delete recv_running["winbindd_change_machine_acct_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_change_machine_acct_send", req]
+ delete start_time["winbindd_change_machine_acct_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_change_machine_acct_send", req]
+ delete idle_time["winbindd_change_machine_acct_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_change_machine_acct_send"] <<< svctime
+ async_runtime["winbindd_change_machine_acct_send"] <<< runtime
+}
+
+#
+# winbind async function winbindd_pam_auth_crap
+#
+
+probe process("winbindd").function("winbindd_pam_auth_crap_send") {
+ send_running["winbindd_pam_auth_crap_send"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_pam_auth_crap_send").return {
+ if (!(["winbindd_pam_auth_crap_send"] in send_running))
+ next
+
+ end = gettimeofday_us()
+ start = send_running["winbindd_pam_auth_crap_send"]
+ delete send_running["winbindd_pam_auth_crap_send"]
+
+ start_time["winbindd_pam_auth_crap_send", $return] = start
+ idle_time["winbindd_pam_auth_crap_send", $return] = end
+}
+
+probe process("winbindd").function("winbindd_pam_auth_crap_recv") {
+ if (!(["winbindd_pam_auth_crap_send", $req] in start_time))
+ next
+
+ recv_running["winbindd_pam_auth_crap_recv"] = gettimeofday_us()
+}
+
+probe process("winbindd").function("winbindd_pam_auth_crap_recv").return {
+ if (!(["winbindd_pam_auth_crap_recv"] in recv_running))
+ next
+
+ recv_end = gettimeofday_us()
+ recv_start = recv_running["winbindd_pam_auth_crap_recv"]
+ delete recv_running["winbindd_pam_auth_crap_recv"]
+ recv_runtime = recv_end - recv_start
+
+ req = @entry($req)
+
+ send_begin = start_time["winbindd_pam_auth_crap_send", req]
+ delete start_time["winbindd_pam_auth_crap_send", req]
+ svctime = recv_end - send_begin
+
+ idle = idle_time["winbindd_pam_auth_crap_send", req]
+ delete idle_time["winbindd_pam_auth_crap_send", req]
+ runtime = (idle - send_begin) + recv_runtime
+
+ async_svctime["winbindd_pam_auth_crap_send"] <<< svctime
+ async_runtime["winbindd_pam_auth_crap_send"] <<< runtime
+}
+
+probe end {
+ printf("\n\n")
+
+ printf("Winbind request service time\n")
+ printf("============================\n")
+ foreach ([name] in async_svctime) {
+ printf("%-40s count: %5d, sum: %6d ms (min: %6d us, avg: %6d us, max: %6d us)\n",
+ name,
+ @count(async_svctime[name]),
+ @sum(async_svctime[name]) / 1000,
+ @min(async_svctime[name]),
+ @avg(async_svctime[name]),
+ @max(async_svctime[name]))
+ }
+ printf("\n")
+
+ printf("Winbind request runtime\n")
+ printf("=======================\n")
+ foreach ([name] in async_runtime) {
+ printf("%-40s count: %5d, sum: %6d ms (min: %6d us, avg: %6d us, max: %6d us)\n",
+ name,
+ @count(async_runtime[name]),
+ @sum(async_runtime[name]) / 1000,
+ @min(async_runtime[name]),
+ @avg(async_runtime[name]),
+ @max(async_runtime[name]))
+ }
+ printf("\n")
+
+ printf("Winbind domain-child request service time\n")
+ printf("=========================================\n")
+ foreach ([name] in dc_svctime) {
+ printf("%-40s count: %5d, sum: %6d ms (min: %6d us, avg: %6d us, max: %6d us)\n",
+ name,
+ @count(dc_svctime[name]),
+ @sum(dc_svctime[name]) / 1000,
+ @min(dc_svctime[name]),
+ @avg(dc_svctime[name]),
+ @max(dc_svctime[name]))
+ }
+ printf("\n")
+
+ printf("Winbind domain-child AD-backend service time\n")
+ printf("============================================\n")
+ foreach ([name] in backend_svctime) {
+ printf("%-40s count: %5d, sum: %6d ms (min: %6d us, avg: %6d us, max: %6d us)\n",
+ name,
+ @count(backend_svctime[name]),
+ @sum(backend_svctime[name]) / 1000,
+ @min(backend_svctime[name]),
+ @avg(backend_svctime[name]),
+ @max(backend_svctime[name]))
+ }
+ printf("\n")
+
+ printf("Winbind request service time distributions (us)\n")
+ printf("===============================================\n")
+ foreach ([name] in async_svctime) {
+ printf("%s:\n", name);
+ println(@hist_log(async_svctime[name]))
+ }
+ printf("\n")
+
+ printf("Winbind request runtime distributions (us)\n")
+ printf("==========================================\n")
+ foreach ([name] in async_runtime) {
+ printf("%s:\n", name);
+ println(@hist_log(async_runtime[name]))
+ }
+
+ printf("Winbind domain-child request service time distributions (us)\n")
+ printf("============================================================\n")
+ foreach ([name] in dc_svctime) {
+ printf("%s:\n", name);
+ println(@hist_log(dc_svctime[name]))
+ }
+
+ printf("Winbind domain-child AD-backend service time distributions (us)\n")
+ printf("===============================================================\n")
+ foreach ([name] in backend_svctime) {
+ printf("%s:\n", name);
+ println(@hist_log(backend_svctime[name]))
+ }
+}
diff --git a/examples/winexe/README b/examples/winexe/README
new file mode 100644
index 0000000..c688e5d
--- /dev/null
+++ b/examples/winexe/README
@@ -0,0 +1,18 @@
+winexe from https://sourceforge.net/projects/winexe/ is a project
+based on Samba libraries from 2012. According to the winexe git
+repository the last Samba commit winexe was updated to is 47bbf9886f0c
+from November 6, 2012. As winexe uses unpublished Samba internal
+libraries, it broke over time.
+
+This is a port of the winexe functionality to more modern Samba
+versions. It still uses internal APIs, but it being part of the tree
+means that it is much easier to keep up to date.
+
+The Windows service files were taken literally from the original
+winexe from the sourceforge git. Andrzej Hajda chose GPLv3 only and
+not GPLv3+. As GPL evolves very slowly, this should not be a practical
+problem for quite some time.
+
+To build it under Linux, you need mingw binaries on your build
+system. Under Debian stretch, the package names are gcc-mingw-w64 and
+friends.
diff --git a/examples/winexe/winexe.c b/examples/winexe/winexe.c
new file mode 100644
index 0000000..5c2529c
--- /dev/null
+++ b/examples/winexe/winexe.c
@@ -0,0 +1,1918 @@
+/*
+ * Samba Unix/Linux CIFS implementation
+ *
+ * winexe
+ *
+ * Copyright (C) 2018 Volker Lendecke <vl@samba.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+#include "version.h"
+#include <popt.h>
+#include <tevent.h>
+#include "lib/param/param.h"
+#include "auth/credentials/credentials.h"
+#include "lib/util/talloc_stack.h"
+#include "lib/util/tevent_ntstatus.h"
+#include "lib/util/sys_rw.h"
+#include "libsmb/proto.h"
+#include "librpc/gen_ndr/ndr_svcctl_c.h"
+#include "rpc_client/cli_pipe.h"
+#include "libcli/smb/smbXcli_base.h"
+#include "libcli/util/werror.h"
+#include "lib/async_req/async_sock.h"
+#include "lib/cmdline/cmdline.h"
+#include "client.h"
+
+#define SVC_INTERACTIVE 1
+#define SVC_IGNORE_INTERACTIVE 2
+#define SVC_INTERACTIVE_MASK 3
+#define SVC_FORCE_UPLOAD 4
+#define SVC_OS64BIT 8
+#define SVC_OSCHOOSE 16
+#define SVC_UNINSTALL 32
+#define SVC_SYSTEM 64
+
+#define SERVICE_NAME "winexesvc"
+
+#define PIPE_NAME "ahexec"
+#define PIPE_NAME_IN "ahexec_stdin%08X"
+#define PIPE_NAME_OUT "ahexec_stdout%08X"
+#define PIPE_NAME_ERR "ahexec_stderr%08X"
+
+static const char version_message_fmt[] = "winexe version %d.%d\n"
+ "This program may be freely redistributed under the terms of the "
+ "GNU GPLv3\n";
+
+struct program_options {
+ char *hostname;
+ int port;
+ char *cmd;
+ struct cli_credentials *credentials;
+ char *runas;
+ char *runas_file;
+ int flags;
+};
+
+static void parse_args(int argc, const char *argv[],
+ TALLOC_CTX *mem_ctx,
+ struct program_options *options)
+{
+ poptContext pc;
+ int opt, i;
+
+ int argc_new;
+ char **argv_new;
+
+ int port = 445;
+ char *port_str = NULL;
+
+ int flag_interactive = SVC_IGNORE_INTERACTIVE;
+ int flag_ostype = 2;
+ int flag_reinstall = 0;
+ int flag_uninstall = 0;
+ int flag_help = 0;
+ int flag_version = 0;
+ bool ok;
+
+ struct poptOption long_options[] = {
+ POPT_AUTOHELP
+ {
+ .longName = "uninstall",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = &flag_uninstall,
+ .val = 0,
+ .descrip = "Uninstall winexe service after "
+ "remote execution",
+ .argDescrip = NULL,
+ },{
+ .longName = "reinstall",
+ .shortName = 0,
+ .argInfo = POPT_ARG_NONE,
+ .arg = &flag_reinstall,
+ .val = 0,
+ .descrip = "Reinstall winexe service before "
+ "remote execution",
+ .argDescrip = NULL,
+ },{
+ .longName = "runas",
+ .shortName = 0,
+ .argInfo = POPT_ARG_STRING,
+ .arg = &options->runas,
+ .val = 0,
+ .descrip = "Run as the given user (BEWARE: this "
+ "password is sent in cleartext over "
+ "the network!)",
+ .argDescrip = "[DOMAIN\\]USERNAME%PASSWORD",
+ },{
+ .longName = "runas-file",
+ .shortName = 0,
+ .argInfo = POPT_ARG_STRING,
+ .arg = &options->runas_file,
+ .val = 0,
+ .descrip = "Run as user options defined in a file",
+ .argDescrip = "FILE",
+ },{
+ .longName = "interactive",
+ .shortName = 0,
+ .argInfo = POPT_ARG_INT,
+ .arg = &flag_interactive,
+ .val = 0,
+ .descrip = "Desktop interaction: 0 - disallow, "
+ "1 - allow. If allow, also use the "
+ "--system switch (Windows requirement). "
+ "Vista does not support this option.",
+ .argDescrip = "0|1",
+ },{
+ .longName = "ostype",
+ .shortName = 0,
+ .argInfo = POPT_ARG_INT,
+ .arg = &flag_ostype,
+ .val = 0,
+ .descrip = "OS type: 0 - 32-bit, 1 - 64-bit, "
+ "2 - winexe will decide. "
+ "Determines which version (32-bit or 64-bit)"
+ " of service will be installed.",
+ .argDescrip = "0|1|2",
+ },
+ POPT_COMMON_SAMBA
+ POPT_COMMON_CREDENTIALS
+ POPT_COMMON_VERSION
+ POPT_TABLEEND
+ };
+
+ ZERO_STRUCTP(options);
+
+ ok = samba_cmdline_init(mem_ctx,
+ SAMBA_CMDLINE_CONFIG_CLIENT,
+ false /* require_smbconf */);
+ if (!ok) {
+ DBG_ERR("Failed to init cmdline parser!\n");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ pc = samba_popt_get_context(getprogname(),
+ argc,
+ argv,
+ long_options,
+ 0);
+ if (pc == NULL) {
+ DBG_ERR("Failed to setup popt context!\n");
+ TALLOC_FREE(mem_ctx);
+ exit(1);
+ }
+
+ poptSetOtherOptionHelp(pc, "[OPTION]... //HOST[:PORT] COMMAND\nOptions:");
+
+ if (((opt = poptGetNextOpt(pc)) != -1) || flag_help || flag_version) {
+ fprintf(stderr, version_message_fmt, SAMBA_VERSION_MAJOR,
+ SAMBA_VERSION_MINOR);
+ if (flag_version) {
+ exit(0);
+ }
+ poptPrintHelp(pc, stdout, 0);
+ if (flag_help) {
+ exit(0);
+ }
+ exit(1);
+ }
+
+ argv_new = discard_const_p(char *, poptGetArgs(pc));
+
+ argc_new = argc;
+ for (i = 0; i < argc; i++) {
+ if (!argv_new || argv_new[i] == NULL) {
+ argc_new = i;
+ break;
+ }
+ }
+
+ if (argc_new != 2 || argv_new[0][0] != '/' || argv_new[0][1] != '/') {
+ fprintf(stderr, version_message_fmt, SAMBA_VERSION_MAJOR,
+ SAMBA_VERSION_MINOR);
+ poptPrintHelp(pc, stdout, 0);
+ exit(1);
+ }
+
+ port_str = strchr(argv_new[0], ':');
+ if (port_str) {
+ if (sscanf(port_str + 1, "%d", &port) != 1 || port <= 0) {
+ fprintf(stderr, version_message_fmt,
+ SAMBA_VERSION_MAJOR, SAMBA_VERSION_MINOR);
+ poptPrintHelp(pc, stdout, 0);
+ exit(1);
+ }
+ *port_str = '\0';
+ }
+
+ if (options->runas == NULL && options->runas_file != NULL) {
+ struct cli_credentials *runas_cred;
+ const char *user;
+ const char *pass;
+
+ runas_cred = cli_credentials_init(mem_ctx);
+ cli_credentials_parse_file(runas_cred, options->runas_file,
+ CRED_SPECIFIED);
+
+ user = cli_credentials_get_username(runas_cred);
+ pass = cli_credentials_get_password(runas_cred);
+
+ if (user && pass) {
+ char buffer[1024];
+ const char *dom;
+
+ dom = cli_credentials_get_domain(runas_cred);
+ if (dom) {
+ snprintf(buffer, sizeof(buffer), "%s\\%s%%%s",
+ dom, user, pass);
+ } else {
+ snprintf(buffer, sizeof(buffer), "%s%%%s",
+ user, pass);
+ }
+ buffer[sizeof(buffer)-1] = '\0';
+ options->runas = talloc_strdup(mem_ctx, buffer);
+ }
+ }
+
+ options->credentials = samba_cmdline_get_creds();
+
+ options->hostname = talloc_strdup(mem_ctx, argv_new[0] + 2);
+ if (options->hostname == NULL) {
+ DBG_ERR("Out of memory\n");
+ exit(1);
+ }
+ options->port = port;
+ options->cmd = talloc_strdup(mem_ctx, argv_new[1]);
+ if (options->cmd == NULL) {
+ DBG_ERR("Out of memory\n");
+ exit(1);
+ }
+
+ poptFreeContext(pc);
+
+ options->flags = flag_interactive;
+ if (flag_reinstall) {
+ options->flags |= SVC_FORCE_UPLOAD;
+ }
+ if (flag_ostype == 1) {
+ options->flags |= SVC_OS64BIT;
+ }
+ if (flag_ostype == 2) {
+ options->flags |= SVC_OSCHOOSE;
+ }
+ if (flag_uninstall) {
+ options->flags |= SVC_UNINSTALL;
+ }
+}
+
+static NTSTATUS winexe_svc_upload(
+ const char *hostname,
+ int port,
+ const char *service_filename,
+ const DATA_BLOB *svc32_exe,
+ const DATA_BLOB *svc64_exe,
+ struct cli_credentials *credentials,
+ int flags)
+{
+ struct cli_state *cli;
+ uint16_t fnum = 0xffff;
+ NTSTATUS status;
+ const DATA_BLOB *binary = NULL;
+
+ status = cli_full_connection_creds(
+ &cli,
+ NULL,
+ hostname,
+ NULL,
+ port,
+ "ADMIN$",
+ "?????",
+ credentials,
+ 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("cli_full_connection_creds failed: %s\n",
+ nt_errstr(status));
+ return status;
+ }
+
+ if (flags & SVC_FORCE_UPLOAD) {
+ status = cli_unlink(cli, service_filename, 0);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("cli_unlink failed: %s\n",
+ nt_errstr(status));
+ }
+ }
+
+ if (flags & SVC_OSCHOOSE) {
+ status = cli_chkpath(cli, "SysWoW64");
+ if (NT_STATUS_IS_OK(status)) {
+ flags |= SVC_OS64BIT;
+ }
+ }
+
+ if (flags & SVC_OS64BIT) {
+ binary = svc64_exe;
+ } else {
+ binary = svc32_exe;
+ }
+
+ if (binary == NULL) {
+ goto done;
+ }
+
+ status = cli_ntcreate(
+ cli,
+ service_filename,
+ 0, /* CreatFlags */
+ SEC_FILE_WRITE_DATA, /* DesiredAccess */
+ FILE_ATTRIBUTE_NORMAL, /* FileAttributes */
+ FILE_SHARE_WRITE|FILE_SHARE_READ, /* ShareAccess */
+ FILE_OPEN_IF, /* CreateDisposition */
+ FILE_NON_DIRECTORY_FILE, /* CreateOptions */
+ 0, /* SecurityFlags */
+ &fnum,
+ NULL); /* CreateReturns */
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("Could not create %s: %s\n", service_filename,
+ nt_errstr(status));
+ goto done;
+ }
+
+ status = cli_writeall(
+ cli,
+ fnum,
+ 0,
+ binary->data,
+ 0,
+ binary->length,
+ NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("Could not write file: %s\n", nt_errstr(status));
+ goto done;
+ }
+
+done:
+ if (fnum != 0xffff) {
+ status = cli_close(cli, fnum);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("Close(%"PRIu16") failed for %s: %s\n",
+ fnum,
+ service_filename,
+ nt_errstr(status));
+ }
+ }
+
+ TALLOC_FREE(cli);
+ return status;
+}
+
+static NTSTATUS winexe_svc_install(
+ struct cli_state *cli,
+ const char *hostname,
+ int port,
+ const char *service_name,
+ const char *service_filename,
+ const DATA_BLOB *svc32_exe,
+ const DATA_BLOB *svc64_exe,
+ struct cli_credentials *credentials,
+ int flags)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct rpc_pipe_client *rpccli;
+ struct policy_handle scmanager_handle;
+ struct policy_handle service_handle;
+ struct SERVICE_STATUS service_status;
+ bool need_start = false;
+ bool need_conf = false;
+ NTSTATUS status;
+ WERROR werr;
+ const char *remote_name = smbXcli_conn_remote_name(cli->conn);
+ const struct sockaddr_storage *remote_sockaddr =
+ smbXcli_conn_remote_sockaddr(cli->conn);
+
+ status = cli_rpc_pipe_open_noauth_transport(
+ cli,
+ NCACN_NP,
+ &ndr_table_svcctl,
+ remote_name,
+ remote_sockaddr,
+ &rpccli);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+
+ status = dcerpc_svcctl_OpenSCManagerW(
+ rpccli->binding_handle,
+ frame,
+ remote_name,
+ NULL,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ &scmanager_handle,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+ if (!W_ERROR_IS_OK(werr)) {
+ DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
+ win_errstr(werr));
+ goto done;
+ }
+
+ status = dcerpc_svcctl_OpenServiceW(
+ rpccli->binding_handle,
+ frame,
+ &scmanager_handle,
+ service_name,
+ SERVICE_ALL_ACCESS,
+ &service_handle,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
+ nt_errstr(status));
+ goto close_scmanager;
+ }
+
+ if (W_ERROR_EQUAL(werr, WERR_SERVICE_DOES_NOT_EXIST)) {
+ status = dcerpc_svcctl_CreateServiceW(
+ rpccli->binding_handle,
+ frame,
+ &scmanager_handle,
+ service_name,
+ NULL,
+ SERVICE_ALL_ACCESS,
+ SERVICE_TYPE_WIN32_OWN_PROCESS |
+ ((flags & SVC_INTERACTIVE) ?
+ SERVICE_TYPE_INTERACTIVE_PROCESS : 0),
+ SVCCTL_DEMAND_START,
+ SVCCTL_SVC_ERROR_NORMAL,
+ service_filename,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ 0,
+ &service_handle,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("dcerpc_svcctl_CreateServiceW "
+ "failed: %s\n", nt_errstr(status));
+ goto close_scmanager;
+ }
+ if (!W_ERROR_IS_OK(werr)) {
+ DBG_WARNING("dcerpc_svcctl_CreateServiceW "
+ "failed: %s\n", win_errstr(werr));
+ status = werror_to_ntstatus(werr);
+ goto close_scmanager;
+ }
+ }
+
+ status = dcerpc_svcctl_QueryServiceStatus(
+ rpccli->binding_handle,
+ frame,
+ &service_handle,
+ &service_status,
+ &werr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
+ "failed: %s\n", nt_errstr(status));
+ goto close_service;
+ }
+ if (!W_ERROR_IS_OK(werr)) {
+ DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
+ "failed: %s\n", win_errstr(werr));
+ status = werror_to_ntstatus(werr);
+ goto close_service;
+ }
+
+ if (!(flags & SVC_IGNORE_INTERACTIVE)) {
+ need_conf =
+ !(service_status.type &
+ SERVICE_TYPE_INTERACTIVE_PROCESS) ^
+ !(flags & SVC_INTERACTIVE);
+ }
+
+ if (service_status.state == SVCCTL_STOPPED) {
+ need_start = true;
+ } else if (need_conf) {
+ status = dcerpc_svcctl_ControlService(
+ rpccli->binding_handle,
+ frame,
+ &service_handle,
+ SVCCTL_CONTROL_STOP,
+ &service_status,
+ &werr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
+ "failed: %s\n", nt_errstr(status));
+ goto close_service;
+ }
+ if (!W_ERROR_IS_OK(werr)) {
+ DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
+ "failed: %s\n", win_errstr(werr));
+ status = werror_to_ntstatus(werr);
+ goto close_service;
+ }
+
+ do {
+ smb_msleep(100);
+
+ status = dcerpc_svcctl_QueryServiceStatus(
+ rpccli->binding_handle,
+ frame,
+ &service_handle,
+ &service_status,
+ &werr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
+ "failed: %s\n", nt_errstr(status));
+ goto close_service;
+ }
+ if (!W_ERROR_IS_OK(werr)) {
+ DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
+ "failed: %s\n", win_errstr(werr));
+ status = werror_to_ntstatus(werr);
+ goto close_service;
+ }
+ } while (service_status.state == SVCCTL_STOP_PENDING);
+
+ need_start = 1;
+ }
+
+ if (need_conf) {
+ status = dcerpc_svcctl_ChangeServiceConfigW(
+ rpccli->binding_handle,
+ frame,
+ &service_handle,
+ SERVICE_TYPE_WIN32_OWN_PROCESS |
+ ((flags & SVC_INTERACTIVE) ?
+ SERVICE_TYPE_INTERACTIVE_PROCESS : 0), /* type */
+ UINT32_MAX, /* start_type, SERVICE_NO_CHANGE */
+ UINT32_MAX, /* error_control, SERVICE_NO_CHANGE */
+ NULL, /* binary_path */
+ NULL, /* load_order_group */
+ NULL, /* tag_id */
+ NULL, /* dependencies */
+ 0, /* dwDependSize */
+ NULL, /* service_start_name */
+ NULL, /* password */
+ 0, /* dwPwSize */
+ NULL, /* display_name */
+ &werr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
+ "failed: %s\n", nt_errstr(status));
+ goto close_service;
+ }
+ if (!W_ERROR_IS_OK(werr)) {
+ DBG_WARNING("dcerpc_svcctl_ChangeServiceConfigW "
+ "failed: %s\n", win_errstr(werr));
+ status = werror_to_ntstatus(werr);
+ goto close_service;
+ }
+ }
+
+ if (need_start) {
+ status = winexe_svc_upload(
+ hostname,
+ port,
+ service_filename,
+ svc32_exe,
+ svc64_exe,
+ credentials,
+ flags);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("winexe_svc_upload failed: %s\n",
+ nt_errstr(status));
+ goto close_service;
+ }
+
+ status = dcerpc_svcctl_StartServiceW(
+ rpccli->binding_handle,
+ frame,
+ &service_handle,
+ 0, /* num_args */
+ NULL, /* arguments */
+ &werr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("dcerpc_svcctl_StartServiceW "
+ "failed: %s\n", nt_errstr(status));
+ goto close_service;
+ }
+ if (!W_ERROR_IS_OK(werr)) {
+ DBG_WARNING("dcerpc_svcctl_StartServiceW "
+ "failed: %s\n", win_errstr(werr));
+ status = werror_to_ntstatus(werr);
+ goto close_service;
+ }
+
+ do {
+ smb_msleep(100);
+
+ status = dcerpc_svcctl_QueryServiceStatus(
+ rpccli->binding_handle,
+ frame,
+ &service_handle,
+ &service_status,
+ &werr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
+ "failed: %s\n", nt_errstr(status));
+ goto close_service;
+ }
+ if (!W_ERROR_IS_OK(werr)) {
+ DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
+ "failed: %s\n", win_errstr(werr));
+ status = werror_to_ntstatus(werr);
+ goto close_service;
+ }
+ } while (service_status.state == SVCCTL_START_PENDING);
+
+ if (service_status.state != SVCCTL_RUNNING) {
+ DBG_WARNING("Failed to start service\n");
+ status = NT_STATUS_UNSUCCESSFUL;
+ goto close_service;
+ }
+ }
+
+close_service:
+ {
+ NTSTATUS close_status;
+ WERROR close_werr;
+
+ close_status = dcerpc_svcctl_CloseServiceHandle(
+ rpccli->binding_handle,
+ frame,
+ &service_handle,
+ &close_werr);
+ if (!NT_STATUS_IS_OK(close_status)) {
+ DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
+ "failed: %s\n", nt_errstr(close_status));
+ goto done;
+ }
+ if (!W_ERROR_IS_OK(close_werr)) {
+ DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
+ " failed: %s\n", win_errstr(close_werr));
+ goto done;
+ }
+ }
+
+close_scmanager:
+ {
+ NTSTATUS close_status;
+ WERROR close_werr;
+
+ close_status = dcerpc_svcctl_CloseServiceHandle(
+ rpccli->binding_handle,
+ frame,
+ &scmanager_handle,
+ &close_werr);
+ if (!NT_STATUS_IS_OK(close_status)) {
+ DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
+ "failed: %s\n", nt_errstr(close_status));
+ goto done;
+ }
+ if (!W_ERROR_IS_OK(close_werr)) {
+ DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
+ " failed: %s\n", win_errstr(close_werr));
+ goto done;
+ }
+ }
+
+done:
+ TALLOC_FREE(rpccli);
+ TALLOC_FREE(frame);
+ return status;
+}
+
+static NTSTATUS winexe_svc_uninstall(
+ struct cli_state *cli,
+ const char *service_name)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct rpc_pipe_client *rpccli;
+ struct policy_handle scmanager_handle;
+ struct policy_handle service_handle;
+ struct SERVICE_STATUS service_status;
+ NTSTATUS status;
+ WERROR werr;
+ const char *remote_name = smbXcli_conn_remote_name(cli->conn);
+ const struct sockaddr_storage *remote_sockaddr =
+ smbXcli_conn_remote_sockaddr(cli->conn);
+
+ status = cli_rpc_pipe_open_noauth_transport(
+ cli,
+ NCACN_NP,
+ &ndr_table_svcctl,
+ remote_name,
+ remote_sockaddr,
+ &rpccli);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("cli_rpc_pipe_open_noauth_transport failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+
+ status = dcerpc_svcctl_OpenSCManagerW(
+ rpccli->binding_handle,
+ frame,
+ remote_name,
+ NULL,
+ SEC_FLAG_MAXIMUM_ALLOWED,
+ &scmanager_handle,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+ if (!W_ERROR_IS_OK(werr)) {
+ DBG_WARNING("dcerpc_svcctl_OpenSCManagerW failed: %s\n",
+ win_errstr(werr));
+ goto done;
+ }
+
+ status = dcerpc_svcctl_OpenServiceW(
+ rpccli->binding_handle,
+ frame,
+ &scmanager_handle,
+ service_name,
+ SERVICE_ALL_ACCESS,
+ &service_handle,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
+ nt_errstr(status));
+ goto close_scmanager;
+ }
+ if (!W_ERROR_IS_OK(werr)) {
+ DBG_WARNING("dcerpc_svcctl_OpenServiceW failed: %s\n",
+ win_errstr(werr));
+ status = werror_to_ntstatus(werr);
+ goto close_scmanager;
+ }
+
+ status = dcerpc_svcctl_ControlService(
+ rpccli->binding_handle,
+ frame,
+ &service_handle,
+ SVCCTL_CONTROL_STOP,
+ &service_status,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
+ "failed: %s\n", nt_errstr(status));
+ goto close_service;
+ }
+ if (!W_ERROR_IS_OK(werr)) {
+ DBG_WARNING("dcerpc_svcctl_ControlServiceStatus "
+ "failed: %s\n", win_errstr(werr));
+ status = werror_to_ntstatus(werr);
+ goto close_service;
+ }
+
+ do {
+ smb_msleep(100);
+
+ status = dcerpc_svcctl_QueryServiceStatus(
+ rpccli->binding_handle,
+ frame,
+ &service_handle,
+ &service_status,
+ &werr);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
+ "failed: %s\n", nt_errstr(status));
+ goto close_service;
+ }
+ if (!W_ERROR_IS_OK(werr)) {
+ DBG_WARNING("dcerpc_svcctl_QueryServiceStatus "
+ "failed: %s\n", win_errstr(werr));
+ status = werror_to_ntstatus(werr);
+ goto close_service;
+ }
+ } while (service_status.state != SVCCTL_STOPPED);
+
+ status = dcerpc_svcctl_DeleteService(
+ rpccli->binding_handle,
+ frame,
+ &service_handle,
+ &werr);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("dcerpc_svcctl_DeleteService "
+ "failed: %s\n", nt_errstr(status));
+ goto close_service;
+ }
+ if (!W_ERROR_IS_OK(werr)) {
+ DBG_WARNING("dcerpc_svcctl_DeleteService "
+ "failed: %s\n", win_errstr(werr));
+ status = werror_to_ntstatus(werr);
+ goto close_service;
+ }
+
+close_service:
+ {
+ NTSTATUS close_status;
+ WERROR close_werr;
+
+ close_status = dcerpc_svcctl_CloseServiceHandle(
+ rpccli->binding_handle,
+ frame,
+ &service_handle,
+ &close_werr);
+ if (!NT_STATUS_IS_OK(close_status)) {
+ DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
+ "failed: %s\n", nt_errstr(close_status));
+ goto done;
+ }
+ if (!W_ERROR_IS_OK(close_werr)) {
+ DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
+ " failed: %s\n", win_errstr(close_werr));
+ goto done;
+ }
+ }
+
+close_scmanager:
+ {
+ NTSTATUS close_status;
+ WERROR close_werr;
+
+ close_status = dcerpc_svcctl_CloseServiceHandle(
+ rpccli->binding_handle,
+ frame,
+ &scmanager_handle,
+ &close_werr);
+ if (!NT_STATUS_IS_OK(close_status)) {
+ DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
+ "failed: %s\n", nt_errstr(close_status));
+ goto done;
+ }
+ if (!W_ERROR_IS_OK(close_werr)) {
+ DBG_WARNING("dcerpc_svcctl_CloseServiceHandle "
+ " failed: %s\n", win_errstr(close_werr));
+ goto done;
+ }
+ }
+
+done:
+ TALLOC_FREE(rpccli);
+ TALLOC_FREE(frame);
+ return status;
+}
+
+struct winexe_out_pipe_state {
+ struct tevent_context *ev;
+ struct cli_state *cli;
+ uint16_t out_pipe;
+ int out_fd;
+ char out_inbuf[256];
+};
+
+static void winexe_out_pipe_opened(struct tevent_req *subreq);
+static void winexe_out_pipe_got_data(struct tevent_req *subreq);
+static void winexe_out_pipe_closed(struct tevent_req *subreq);
+
+static struct tevent_req *winexe_out_pipe_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ const char *pipe_name,
+ int out_fd)
+{
+ struct tevent_req *req, *subreq;
+ struct winexe_out_pipe_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct winexe_out_pipe_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->cli = cli;
+ state->out_fd = out_fd;
+
+ subreq = cli_ntcreate_send(
+ state,
+ state->ev,
+ state->cli,
+ pipe_name,
+ 0,
+ SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
+ SEC_RIGHTS_FILE_EXECUTE,
+ 0, /* FileAttributes */
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_OPEN, /* CreateDisposition */
+ 0, /* CreateOptions */
+ SMB2_IMPERSONATION_IMPERSONATION,
+ 0); /* SecurityFlags */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, winexe_out_pipe_opened, req);
+ return req;
+}
+
+static void winexe_out_pipe_opened(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct winexe_out_pipe_state *state = tevent_req_data(
+ req, struct winexe_out_pipe_state);
+ int timeout;
+ NTSTATUS status;
+
+ status = cli_ntcreate_recv(subreq, &state->out_pipe, NULL);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ timeout = state->cli->timeout;
+ state->cli->timeout = 0;
+
+ subreq = cli_read_send(
+ state,
+ state->ev,
+ state->cli,
+ state->out_pipe,
+ state->out_inbuf,
+ 0,
+ sizeof(state->out_inbuf));
+
+ state->cli->timeout = timeout;
+
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
+}
+
+static void winexe_out_pipe_got_data(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct winexe_out_pipe_state *state = tevent_req_data(
+ req, struct winexe_out_pipe_state);
+ NTSTATUS status;
+ int timeout;
+ size_t received;
+ ssize_t written;
+
+ status = cli_read_recv(subreq, &received);
+ TALLOC_FREE(subreq);
+
+ DBG_DEBUG("cli_read for %d gave %s\n",
+ state->out_fd,
+ nt_errstr(status));
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
+ subreq = cli_close_send(state,
+ state->ev,
+ state->cli,
+ state->out_pipe,
+ 0);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, winexe_out_pipe_closed, req);
+ return;
+ }
+
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (received > 0) {
+ written = sys_write(state->out_fd, state->out_inbuf, received);
+ if (written == -1) {
+ tevent_req_nterror(req, map_nt_error_from_unix(errno));
+ return;
+ }
+ }
+
+ timeout = state->cli->timeout;
+ state->cli->timeout = 0;
+
+ subreq = cli_read_send(
+ state,
+ state->ev,
+ state->cli,
+ state->out_pipe,
+ state->out_inbuf,
+ 0,
+ sizeof(state->out_inbuf));
+
+ state->cli->timeout = timeout;
+
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, winexe_out_pipe_got_data, req);
+}
+
+static void winexe_out_pipe_closed(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ NTSTATUS status;
+
+ status = cli_close_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static NTSTATUS winexe_out_pipe_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+struct winexe_in_pipe_state {
+ struct tevent_context *ev;
+ struct cli_state *cli;
+ struct tevent_req *fd_read_req;
+ bool close_requested;
+ bool closing;
+ uint16_t in_pipe;
+ int in_fd;
+ char inbuf[256];
+};
+
+static void winexe_in_pipe_opened(struct tevent_req *subreq);
+static void winexe_in_pipe_got_data(struct tevent_req *subreq);
+static void winexe_in_pipe_written(struct tevent_req *subreq);
+static void winexe_in_pipe_closed(struct tevent_req *subreq);
+
+static struct tevent_req *winexe_in_pipe_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ const char *pipe_name,
+ int in_fd)
+{
+ struct tevent_req *req, *subreq;
+ struct winexe_in_pipe_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct winexe_in_pipe_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->cli = cli;
+ state->in_fd = in_fd;
+
+ subreq = cli_ntcreate_send(
+ state,
+ state->ev,
+ state->cli,
+ pipe_name,
+ 0,
+ SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
+ SEC_RIGHTS_FILE_EXECUTE,
+ 0, /* FileAttributes */
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_OPEN, /* CreateDisposition */
+ 0, /* CreateOptions */
+ SMB2_IMPERSONATION_IMPERSONATION,
+ 0); /* SecurityFlags */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, winexe_in_pipe_opened, req);
+ return req;
+}
+
+static void winexe_in_pipe_opened(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct winexe_in_pipe_state *state = tevent_req_data(
+ req, struct winexe_in_pipe_state);
+ NTSTATUS status;
+
+ status = cli_ntcreate_recv(subreq, &state->in_pipe, NULL);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ subreq = wait_for_read_send(
+ state,
+ state->ev,
+ state->in_fd,
+ true);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
+
+ state->fd_read_req = subreq;
+}
+
+static void winexe_in_pipe_got_data(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct winexe_in_pipe_state *state = tevent_req_data(
+ req, struct winexe_in_pipe_state);
+ int err;
+ bool ok;
+ int timeout;
+ ssize_t nread;
+
+ ok = wait_for_read_recv(subreq, &err);
+ TALLOC_FREE(subreq);
+ if (!ok) {
+ tevent_req_nterror(req, map_nt_error_from_unix(err));
+ return;
+ }
+ state->fd_read_req = NULL;
+
+ nread = sys_read(state->in_fd, &state->inbuf, sizeof(state->inbuf));
+ if (nread == -1) {
+ tevent_req_nterror(req, map_nt_error_from_unix(errno));
+ return;
+ }
+ if (nread == 0) {
+ tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
+ return;
+ }
+
+ timeout = state->cli->timeout;
+ state->cli->timeout = 0;
+
+ subreq = cli_writeall_send(
+ state,
+ state->ev,
+ state->cli,
+ state->in_pipe,
+ 0,
+ (uint8_t *)state->inbuf,
+ 0,
+ nread);
+
+ state->cli->timeout = timeout;
+
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, winexe_in_pipe_written, req);
+}
+
+static void winexe_in_pipe_written(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct winexe_in_pipe_state *state = tevent_req_data(
+ req, struct winexe_in_pipe_state);
+ NTSTATUS status;
+
+ status = cli_writeall_recv(subreq, NULL);
+ TALLOC_FREE(subreq);
+
+ DBG_DEBUG("cli_writeall for %d gave %s\n",
+ state->in_fd,
+ nt_errstr(status));
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED) ||
+ state->close_requested) {
+ subreq = cli_close_send(state,
+ state->ev,
+ state->cli,
+ state->in_pipe,
+ 0);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
+ state->closing = true;
+ return;
+ }
+
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ subreq = wait_for_read_send(
+ state,
+ state->ev,
+ state->in_fd,
+ true);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, winexe_in_pipe_got_data, req);
+
+ state->fd_read_req = subreq;
+}
+
+static void winexe_in_pipe_closed(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ NTSTATUS status;
+
+ status = cli_close_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ return tevent_req_done(req);
+}
+
+static NTSTATUS winexe_in_pipe_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+static bool winexe_in_pipe_close(struct tevent_req *req)
+{
+ struct winexe_in_pipe_state *state = tevent_req_data(
+ req, struct winexe_in_pipe_state);
+ struct tevent_req *subreq;
+
+ if (state->closing) {
+ return true;
+ }
+
+ if (state->fd_read_req == NULL) {
+ /*
+ * cli_writeall active, wait for it to return
+ */
+ state->close_requested = true;
+ return true;
+ }
+
+ TALLOC_FREE(state->fd_read_req);
+
+ subreq =
+ cli_close_send(state, state->ev, state->cli, state->in_pipe, 0);
+ if (subreq == NULL) {
+ return false;
+ }
+ tevent_req_set_callback(subreq, winexe_in_pipe_closed, req);
+ state->closing = true;
+
+ return true;
+}
+
+struct winexe_pipes_state {
+ struct tevent_req *pipes[3];
+};
+
+static void winexe_pipes_stdin_done(struct tevent_req *subreq);
+static void winexe_pipes_stdout_done(struct tevent_req *subreq);
+static void winexe_pipes_stderr_done(struct tevent_req *subreq);
+
+static struct tevent_req *winexe_pipes_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ const char *pipe_postfix)
+{
+ struct tevent_req *req;
+ struct winexe_pipes_state *state;
+ char *pipe_name;
+
+ req = tevent_req_create(mem_ctx, &state, struct winexe_pipes_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ pipe_name = talloc_asprintf(state, "\\ahexec_stdin%s", pipe_postfix);
+ if (tevent_req_nomem(pipe_name, req)) {
+ return tevent_req_post(req, ev);
+ }
+ state->pipes[0] = winexe_in_pipe_send(
+ state,
+ ev,
+ cli,
+ pipe_name,
+ 0);
+ if (tevent_req_nomem(state->pipes[0], req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(state->pipes[0], winexe_pipes_stdin_done, req);
+
+ pipe_name = talloc_asprintf(state, "\\ahexec_stdout%s", pipe_postfix);
+ if (tevent_req_nomem(pipe_name, req)) {
+ return tevent_req_post(req, ev);
+ }
+ state->pipes[1] = winexe_out_pipe_send(
+ state,
+ ev,
+ cli,
+ pipe_name,
+ 1);
+ if (tevent_req_nomem(state->pipes[1], req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(state->pipes[1], winexe_pipes_stdout_done,
+ req);
+
+ pipe_name = talloc_asprintf(state, "\\ahexec_stderr%s", pipe_postfix);
+ if (tevent_req_nomem(pipe_name, req)) {
+ return tevent_req_post(req, ev);
+ }
+ state->pipes[2] = winexe_out_pipe_send(
+ state,
+ ev,
+ cli,
+ pipe_name,
+ 2);
+ if (tevent_req_nomem(state->pipes[2], req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(state->pipes[2], winexe_pipes_stderr_done,
+ req);
+
+ DBG_DEBUG("pipes = %p %p %p\n",
+ state->pipes[0],
+ state->pipes[1],
+ state->pipes[2]);
+
+ return req;
+}
+
+static void winexe_pipes_stdin_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct winexe_pipes_state *state = tevent_req_data(
+ req, struct winexe_pipes_state);
+ NTSTATUS status;
+
+ status = winexe_in_pipe_recv(subreq);
+ TALLOC_FREE(subreq);
+
+ DBG_DEBUG("stdin returned %s\n", nt_errstr(status));
+
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ state->pipes[0] = NULL;
+
+ DBG_DEBUG("pipes = %p %p %p\n",
+ state->pipes[0],
+ state->pipes[1],
+ state->pipes[2]);
+
+ if ((state->pipes[1] == NULL) && (state->pipes[2] == NULL)) {
+ tevent_req_done(req);
+ }
+}
+
+static void winexe_pipes_stdout_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct winexe_pipes_state *state = tevent_req_data(
+ req, struct winexe_pipes_state);
+ NTSTATUS status;
+
+ status = winexe_out_pipe_recv(subreq);
+ TALLOC_FREE(subreq);
+
+ DBG_DEBUG("stdout returned %s\n", nt_errstr(status));
+
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (state->pipes[0] != NULL) {
+ winexe_in_pipe_close(state->pipes[0]);
+ }
+
+ state->pipes[1] = NULL;
+
+ DBG_DEBUG("pipes = %p %p %p\n",
+ state->pipes[0],
+ state->pipes[1],
+ state->pipes[2]);
+
+ if ((state->pipes[0] == NULL) && (state->pipes[2] == NULL)) {
+ tevent_req_done(req);
+ }
+}
+
+static void winexe_pipes_stderr_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct winexe_pipes_state *state = tevent_req_data(
+ req, struct winexe_pipes_state);
+ NTSTATUS status;
+
+ status = winexe_out_pipe_recv(subreq);
+ TALLOC_FREE(subreq);
+
+ DBG_DEBUG("stderr returned %s\n", nt_errstr(status));
+
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ if (state->pipes[0] != NULL) {
+ winexe_in_pipe_close(state->pipes[0]);
+ }
+
+ state->pipes[2] = NULL;
+
+ DBG_DEBUG("pipes = %p %p %p\n",
+ state->pipes[0],
+ state->pipes[1],
+ state->pipes[2]);
+
+ if ((state->pipes[0] == NULL) && (state->pipes[1] == NULL)) {
+ tevent_req_done(req);
+ }
+}
+
+static NTSTATUS winexe_pipes_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+struct winexe_ctrl_state {
+ struct tevent_context *ev;
+ struct cli_state *cli;
+
+ uint16_t ctrl_pipe;
+ bool ctrl_pipe_done;
+
+ char ctrl_inbuf[256];
+ char *cmd;
+ int return_code;
+
+ struct tevent_req *pipes_req;
+};
+
+static void winexe_ctrl_opened(struct tevent_req *subreq);
+static void winexe_ctrl_got_read(struct tevent_req *subreq);
+static void winexe_ctrl_wrote_version(struct tevent_req *subreq);
+static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq);
+static void winexe_ctrl_pipes_done(struct tevent_req *subreq);
+static void winexe_ctrl_pipe_closed(struct tevent_req *subreq);
+
+static struct tevent_req *winexe_ctrl_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ const char *cmd)
+{
+ struct tevent_req *req, *subreq;
+ struct winexe_ctrl_state *state;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct winexe_ctrl_state);
+ if (req == NULL) {
+ return NULL;
+ }
+ state->ev = ev;
+ state->cli = cli;
+
+ state->cmd = talloc_asprintf(state, "run %s\n", cmd);
+ if (tevent_req_nomem(state->cmd, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ subreq = cli_ntcreate_send(
+ state,
+ state->ev,
+ state->cli,
+ "\\" PIPE_NAME,
+ 0,
+ SEC_RIGHTS_FILE_READ|SEC_RIGHTS_FILE_WRITE|
+ SEC_RIGHTS_FILE_EXECUTE,
+ 0, /* FileAttributes */
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ FILE_OPEN, /* CreateDisposition */
+ 0, /* CreateOptions */
+ SMB2_IMPERSONATION_IMPERSONATION,
+ 0); /* SecurityFlags */
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, winexe_ctrl_opened, req);
+ return req;
+}
+
+static void winexe_ctrl_opened(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct winexe_ctrl_state *state = tevent_req_data(
+ req, struct winexe_ctrl_state);
+ int timeout;
+ NTSTATUS status;
+ static const char cmd[] = "get codepage\nget version\n";
+
+ status = cli_ntcreate_recv(subreq, &state->ctrl_pipe, NULL);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ timeout = state->cli->timeout;
+ state->cli->timeout = 0;
+
+ subreq = cli_read_send(
+ state,
+ state->ev,
+ state->cli,
+ state->ctrl_pipe,
+ state->ctrl_inbuf,
+ 0,
+ sizeof(state->ctrl_inbuf)-1);
+
+ state->cli->timeout = timeout;
+
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
+
+ subreq = cli_writeall_send(
+ state,
+ state->ev,
+ state->cli,
+ state->ctrl_pipe,
+ 0,
+ (const uint8_t *)cmd,
+ 0,
+ strlen(cmd));
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, winexe_ctrl_wrote_version, req);
+}
+
+static void winexe_ctrl_got_read(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct winexe_ctrl_state *state = tevent_req_data(
+ req, struct winexe_ctrl_state);
+ NTSTATUS status;
+ int timeout;
+ size_t received;
+ unsigned int version, return_code;
+ int ret;
+
+ status = cli_read_recv(subreq, &received);
+ TALLOC_FREE(subreq);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
+ subreq = cli_close_send(state,
+ state->ev,
+ state->cli,
+ state->ctrl_pipe,
+ 0);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, winexe_ctrl_pipe_closed, req);
+ return;
+ }
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ DBG_DEBUG("Got %zu bytes\n", received);
+
+ timeout = state->cli->timeout;
+ state->cli->timeout = 0;
+
+ subreq = cli_read_send(
+ state,
+ state->ev,
+ state->cli,
+ state->ctrl_pipe,
+ state->ctrl_inbuf,
+ 0,
+ sizeof(state->ctrl_inbuf)-1);
+
+ state->cli->timeout = timeout;
+
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, winexe_ctrl_got_read, req);
+
+ ret = sscanf(state->ctrl_inbuf, "version 0x%x\n", &version);
+ if (ret == 1) {
+ DBG_DEBUG("Got version %x\n", version);
+
+ subreq = cli_writeall_send(
+ state,
+ state->ev,
+ state->cli,
+ state->ctrl_pipe,
+ 0,
+ (const uint8_t *)state->cmd,
+ 0,
+ strlen(state->cmd));
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, winexe_ctrl_wrote_cmd, req);
+ return;
+ }
+
+ ret = strncmp(state->ctrl_inbuf, "std_io_err ", strlen("std_io_err "));
+ if (ret == 0) {
+ char *p = state->ctrl_inbuf + 11;
+ char *q = strchr(state->ctrl_inbuf, '\n');
+ char *postfix;
+ size_t postfix_len;
+
+ if (q == NULL) {
+ DBG_DEBUG("Got invalid pipe postfix\n");
+ return;
+ }
+
+ postfix_len = q - p;
+
+ postfix = talloc_strndup(state, p, postfix_len);
+ if (tevent_req_nomem(postfix, req)) {
+ return;
+ }
+
+ DBG_DEBUG("Got pipe postfix %s\n", postfix);
+
+ subreq = winexe_pipes_send(
+ state,
+ state->ev,
+ state->cli,
+ postfix);
+ if (tevent_req_nomem(subreq, req)) {
+ return;
+ }
+ tevent_req_set_callback(subreq, winexe_ctrl_pipes_done, req);
+
+ state->pipes_req = subreq;
+
+ return;
+ }
+
+ ret = strncmp(state->ctrl_inbuf, "error ", strlen("error "));
+ if (ret == 0) {
+ printf("Error: %s", state->ctrl_inbuf);
+ return;
+ }
+
+ ret = sscanf(state->ctrl_inbuf, "return_code %x\n", &return_code);
+ if (ret == 1) {
+ state->return_code = return_code;
+ return;
+ }
+}
+
+static void winexe_ctrl_wrote_version(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ NTSTATUS status;
+
+ status = cli_writeall_recv(subreq, NULL);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+}
+
+static void winexe_ctrl_wrote_cmd(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ NTSTATUS status;
+
+ status = cli_writeall_recv(subreq, NULL);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+}
+
+static void winexe_ctrl_pipe_closed(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct winexe_ctrl_state *state = tevent_req_data(
+ req, struct winexe_ctrl_state);
+ NTSTATUS status;
+
+ status = cli_close_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ state->ctrl_pipe_done = true;
+ if (state->pipes_req == NULL) {
+ tevent_req_done(req);
+ }
+}
+
+static void winexe_ctrl_pipes_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct winexe_ctrl_state *state = tevent_req_data(
+ req, struct winexe_ctrl_state);
+ NTSTATUS status;
+
+ status = winexe_pipes_recv(subreq);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+
+ state->pipes_req = NULL;
+ if (state->ctrl_pipe_done) {
+ tevent_req_done(req);
+ }
+}
+
+static NTSTATUS winexe_ctrl_recv(struct tevent_req *req,
+ int *preturn_code)
+{
+ struct winexe_ctrl_state *state = tevent_req_data(
+ req, struct winexe_ctrl_state);
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+ if (preturn_code != NULL) {
+ *preturn_code = state->return_code;
+ }
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS winexe_ctrl(struct cli_state *cli,
+ const char *cmd,
+ int *preturn_code)
+{
+ struct tevent_context *ev = NULL;
+ struct tevent_req *req = NULL;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+ bool ok;
+
+ ev = samba_tevent_context_init(cli);
+ if (ev == NULL) {
+ goto done;
+ }
+ req = winexe_ctrl_send(ev, ev, cli, cmd);
+ if (req == NULL) {
+ goto done;
+ }
+ ok = tevent_req_poll_ntstatus(req, ev, &status);
+ if (!ok) {
+ goto done;
+ }
+ status = winexe_ctrl_recv(req, preturn_code);
+done:
+ TALLOC_FREE(req);
+ TALLOC_FREE(ev);
+ return status;
+}
+
+#ifdef HAVE_WINEXE_CC_WIN32
+const DATA_BLOB *winexesvc32_exe_binary(void);
+#endif
+
+#ifdef HAVE_WINEXE_CC_WIN64
+const DATA_BLOB *winexesvc64_exe_binary(void);
+#endif
+
+int main(int argc, char *argv[])
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ const char **const_argv = discard_const_p(const char *, argv);
+ struct program_options options = {0};
+ struct cli_state *cli = NULL;
+ const char *service_name = SERVICE_NAME;
+ char *service_filename = NULL;
+#ifdef HAVE_WINEXE_CC_WIN32
+ const DATA_BLOB *winexesvc32_exe = winexesvc32_exe_binary();
+#else
+ const DATA_BLOB *winexesvc32_exe = NULL;
+#endif
+#ifdef HAVE_WINEXE_CC_WIN64
+ const DATA_BLOB *winexesvc64_exe = winexesvc64_exe_binary();
+#else
+ const DATA_BLOB *winexesvc64_exe = NULL;
+#endif
+ NTSTATUS status;
+ int ret = 1;
+ int return_code = 0;
+
+ smb_init_locale();
+
+ parse_args(argc, const_argv, frame, &options);
+
+ samba_cmdline_burn(argc, argv);
+
+ if (options.cmd == NULL) {
+ fprintf(stderr, "no cmd given\n");
+ goto done;
+ }
+
+ service_filename = talloc_asprintf(frame, "%s.exe", service_name);
+ if (service_filename == NULL) {
+ DBG_WARNING("talloc_asprintf failed\n");
+ goto done;
+ }
+
+ status = cli_full_connection_creds(
+ &cli,
+ lp_netbios_name(),
+ options.hostname,
+ NULL,
+ options.port,
+ "IPC$",
+ "IPC",
+ options.credentials,
+ CLI_FULL_CONNECTION_IPC);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("cli_full_connection_creds failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+
+ status = winexe_svc_install(
+ cli,
+ options.hostname,
+ options.port,
+ service_name,
+ service_filename,
+ winexesvc32_exe,
+ winexesvc64_exe,
+ options.credentials,
+ options.flags);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("winexe_svc_install failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+
+ status = winexe_ctrl(cli, options.cmd, &return_code);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_PIPE_DISCONNECTED)) {
+ /* Normal finish */
+ status = NT_STATUS_OK;
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("cli_ctrl failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+
+ if (options.flags & SVC_UNINSTALL) {
+ status = winexe_svc_uninstall(
+ cli,
+ service_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ DBG_WARNING("winexe_svc_uninstall failed: %s\n",
+ nt_errstr(status));
+ goto done;
+ }
+ }
+
+ ret = return_code;
+done:
+ TALLOC_FREE(frame);
+ return ret;
+}
diff --git a/examples/winexe/winexesvc.c b/examples/winexe/winexesvc.c
new file mode 100644
index 0000000..3d2ebcc
--- /dev/null
+++ b/examples/winexe/winexesvc.c
@@ -0,0 +1,745 @@
+/*
+ * Copyright (C) Andrzej Hajda 2009-2013
+ * Contact: andrzej.hajda@wp.pl
+ *
+ * Source of this file: https://git.code.sf.net/p/winexe/winexe-waf
+ * commit b787d2a2c4b1abc3653bad10aec943b8efcd7aab.
+ *
+ * ** NOTE! The following "GPLv3 only" license applies to the winexe
+ * ** service files. This does NOT imply that all of Samba is released
+ * ** under the "GPLv3 only" license.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 3 as published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <windows.h>
+#include <aclapi.h>
+#include <userenv.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "winexesvc.h"
+
+#define BUFSIZE 256
+
+#if 0
+#define dbg(arg...) \
+({\
+ FILE *f = fopen("C:\\" SERVICE_NAME ".log", "at");\
+ if (f) {\
+ fprintf(f, arg);\
+ fclose(f);\
+ }\
+})
+#else
+#define dbg(arg...)
+#endif
+
+static SECURITY_ATTRIBUTES sa;
+
+/* Creates SECURITY_ATTRIBUTES sa with full access for BUILTIN\Administrators */
+static int CreatePipesSA()
+{
+ DWORD dwRes;
+ PSID pAdminSID = NULL;
+ PACL pACL = NULL;
+ PSECURITY_DESCRIPTOR pSD = NULL;
+ EXPLICIT_ACCESS ea;
+ SID_IDENTIFIER_AUTHORITY SIDAuthNT = {SECURITY_NT_AUTHORITY};
+
+ /* Create a SID for the BUILTIN\Administrators group. */
+ if (
+ !AllocateAndInitializeSid(
+ &SIDAuthNT, 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0, &pAdminSID
+ )
+ ) {
+ dbg("AllocateAndInitializeSid Error %lu\n", GetLastError());
+ return 0;
+ }
+ /* Initialize an EXPLICIT_ACCESS structure for an ACE.
+ The ACE will allow the Administrators group full access to the key.
+ */
+ ea.grfAccessPermissions = FILE_ALL_ACCESS;
+ ea.grfAccessMode = SET_ACCESS;
+ ea.grfInheritance = NO_INHERITANCE;
+ ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
+ ea.Trustee.ptstrName = (LPTSTR) pAdminSID;
+
+ /* Create a new ACL that contains the new ACEs */
+ dwRes = SetEntriesInAcl(1, &ea, NULL, &pACL);
+ if (ERROR_SUCCESS != dwRes) {
+ dbg("SetEntriesInAcl Error %lu\n", GetLastError());
+ return 0;
+ }
+ /* Initialize a security descriptor */
+ pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
+ if (NULL == pSD) {
+ dbg("LocalAlloc Error %lu\n", GetLastError());
+ return 0;
+ }
+
+ if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
+ {
+ dbg("InitializeSecurityDescriptor Error %lu\n", GetLastError());
+ return 0;
+ }
+ /* Add the ACL to the security descriptor */
+ if (
+ !SetSecurityDescriptorDacl(
+ pSD, TRUE, /* bDaclPresent flag */
+ pACL, FALSE /* not a default DACL */
+ )
+ ) {
+ dbg("SetSecurityDescriptorDacl Error %lu\n", GetLastError());
+ return 0;
+ }
+ /* Initialize a security attributes structure */
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.lpSecurityDescriptor = pSD;
+ sa.bInheritHandle = FALSE;
+ return 1;
+}
+
+typedef struct {
+ HANDLE h;
+ OVERLAPPED o;
+} OV_HANDLE;
+
+static int hgets(char *str, int n, OV_HANDLE *pipe)
+{
+ DWORD res;
+ DWORD count = 0;
+ --n;
+ while (--n >= 0) {
+ if (!ReadFile(pipe->h, str, 1, NULL, &pipe->o) && GetLastError() != ERROR_IO_PENDING)
+ goto finish;
+ if (!GetOverlappedResult(pipe->h, &pipe->o, &res, TRUE) || !res)
+ goto finish;
+ if (*str == '\n')
+ goto finish;
+ ++count;
+ ++str;
+ }
+finish:
+ *str = 0;
+ return count;
+}
+
+static int hprintf(OV_HANDLE *pipe, const char *fmt, ...)
+{
+ int res;
+ char buf[1024];
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ if (!WriteFile(pipe->h, buf, strlen(buf), NULL, &pipe->o) && GetLastError() == ERROR_IO_PENDING)
+ GetOverlappedResult(pipe->h, &pipe->o, (LPDWORD)&res, TRUE);
+ FlushFileBuffers(pipe->h);
+ return res;
+}
+
+typedef struct {
+ OV_HANDLE *pipe;
+ const char *cmd;
+ HANDLE pin;
+ HANDLE pout;
+ HANDLE perr;
+ HANDLE token;
+ int implevel;
+ int system;
+ int profile;
+ char *runas;
+ int conn_number;
+} connection_context;
+
+typedef int CMD_FUNC(connection_context *);
+
+typedef struct {
+ const char *name;
+ CMD_FUNC *func;
+} CMD_ITEM;
+
+static int cmd_set(connection_context *c)
+{
+ static const char* var_system = "system";
+ static const char* var_implevel = "implevel";
+ static const char* var_runas = "runas";
+ static const char* var_profile = "profile";
+ char *cmdline;
+ int res = 0;
+
+ cmdline = strchr(c->cmd, ' ');
+ if (!cmdline) {
+ goto finish;
+ }
+ ++cmdline;
+ int l;
+ if ((strstr(cmdline, var_system) == cmdline) && (cmdline[l = strlen(var_system)] == ' ')) {
+ c->system = atoi(cmdline + l + 1);
+ } else if ((strstr(cmdline, var_implevel) == cmdline) && (cmdline[l = strlen(var_implevel)] == ' ')) {
+ c->implevel = atoi(cmdline + l + 1);
+ } else if ((strstr(cmdline, var_profile) == cmdline) && (cmdline[l = strlen(var_profile)] == ' ')) {
+ c->profile = atoi(cmdline + l + 1);
+ } else if ((strstr(cmdline, var_runas) == cmdline) && (cmdline[l = strlen(var_runas)] == ' ')) {
+ c->runas = strdup(cmdline + l + 1);
+ } else {
+ hprintf(c->pipe, "error Unknown command (%s)\n", c->cmd);
+ goto finish;
+ }
+ res = 1;
+finish:
+ return res;
+}
+
+static int cmd_get(connection_context *c)
+{
+ static const char* var_version = "version";
+ static const char* var_codepage = "codepage";
+ char *cmdline;
+ int res = 0;
+
+ cmdline = strchr(c->cmd, ' ');
+ if (!cmdline) {
+ goto finish;
+ }
+ ++cmdline;
+ int l;
+ if ((strstr(cmdline, var_version) == cmdline)
+ && (cmdline[l = strlen(var_version)] == 0)) {
+ hprintf(c->pipe, "version 0x%04X\n", VERSION);
+ } else if ((strstr(cmdline, var_codepage) == cmdline)
+ && (cmdline[l = strlen(var_codepage)] == 0)) {
+ hprintf(c->pipe, "codepage %d\n", GetOEMCP());
+ } else {
+ hprintf(c->pipe, "error Unknown argument (%s)\n", c->cmd);
+ goto finish;
+ }
+ res = 1;
+finish:
+ return res;
+}
+
+typedef struct {
+ char *user;
+ char *domain;
+ char *password;
+} credentials;
+
+static int prepare_credentials(char *str, credentials *crd)
+{
+ char *p;
+ p = strchr(str, '/');
+ if (!p) p = strchr(str, '\\');
+ if (p) {
+ *p++ = 0;
+ crd->domain = str;
+ } else {
+ p = str;
+ crd->domain = ".";
+ }
+ crd->user = p;
+ p = strchr(p, '%');
+ if (p)
+ *p++ = 0;
+ crd->password = p;
+ return 1;
+}
+
+static int get_token(connection_context *c)
+{
+ int res = 0;
+ int wres;
+ HANDLE token;
+
+ if (c->runas) {
+ credentials crd;
+ if (!prepare_credentials(c->runas, &crd)) {
+ hprintf(c->pipe, "error Incorrect runas credentials\n");
+ goto finish;
+ }
+ wres = LogonUser(crd.user, crd.domain, crd.password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &c->token);
+ if (!wres) {
+ hprintf(c->pipe, "error Cannot LogonUser(%s,%s,%s) %d\n",
+ crd.user, crd.domain, crd.password, GetLastError());
+ goto finish;
+ }
+ res = 1;
+ goto finish;
+ } else if (c->system) {
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)) {
+ hprintf(c->pipe, "error Cannot OpenProcessToken %d\n", GetLastError());
+ goto finish;
+ }
+ } else {
+ if (!ImpersonateNamedPipeClient(c->pipe->h)) {
+ hprintf(c->pipe, "error Cannot ImpersonateNamedPipeClient %d\n", GetLastError());
+ goto finish;
+ }
+ if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &token)) {
+ hprintf(c->pipe, "error Cannot OpenThreadToken %d\n", GetLastError());
+ goto finishRevertToSelf;
+ }
+ }
+ if (!DuplicateTokenEx(token, MAXIMUM_ALLOWED, 0, c->implevel, TokenPrimary, &c->token)) {
+ hprintf(c->pipe, "error Cannot Duplicate Token %d\n", GetLastError());
+ goto finishCloseToken;
+ }
+ res = 1;
+finishCloseToken:
+ CloseHandle(token);
+finishRevertToSelf:
+ if (!c->system) {
+ if (!RevertToSelf()) {
+ hprintf(c->pipe, "error Cannot RevertToSelf %d\n", GetLastError());
+ res = 0;
+ }
+ }
+finish:
+ return res;
+}
+
+static int load_user_profile(connection_context *c)
+{
+ PROFILEINFO pi = { .dwSize = sizeof(PROFILEINFO) };
+ DWORD ulen = 256;
+ TCHAR username[ulen];
+
+ GetUserName(username, &ulen);
+ pi.lpUserName = username;
+
+ return LoadUserProfile(c->token, &pi);
+}
+
+static int cmd_run(connection_context *c)
+{
+ char buf[256];
+ int res = 0;
+ char *cmdline;
+ DWORD pipe_nr;
+
+ cmdline = strchr(c->cmd, ' ');
+ if (!cmdline) {
+ goto finish;
+ }
+ ++cmdline;
+
+ if (!get_token(c))
+ return 0;
+
+ pipe_nr = (GetCurrentProcessId() << 16) + (DWORD) c->conn_number;
+
+ sprintf(buf, "\\\\.\\pipe\\" PIPE_NAME_IN, (unsigned int) pipe_nr);
+ c->pin = CreateNamedPipe(buf,
+ PIPE_ACCESS_DUPLEX,
+ PIPE_WAIT,
+ 1,
+ BUFSIZE,
+ BUFSIZE,
+ NMPWAIT_USE_DEFAULT_WAIT,
+ &sa);
+ if (c->pin == INVALID_HANDLE_VALUE) {
+ hprintf(c->pipe, "error Cannot create in pipe(%s), error 0x%08X\n", buf, GetLastError());
+ goto finishCloseToken;
+ }
+
+ sprintf(buf, "\\\\.\\pipe\\" PIPE_NAME_OUT, (unsigned int) pipe_nr);
+ c->pout = CreateNamedPipe(buf,
+ PIPE_ACCESS_DUPLEX,
+ PIPE_WAIT,
+ 1,
+ BUFSIZE,
+ BUFSIZE,
+ NMPWAIT_USE_DEFAULT_WAIT,
+ &sa);
+ if (c->pout == INVALID_HANDLE_VALUE) {
+ hprintf(c->pipe, "error Cannot create out pipe(%s), error 0x%08X\n", buf, GetLastError());
+ goto finishClosePin;
+ }
+
+ sprintf(buf, "\\\\.\\pipe\\" PIPE_NAME_ERR, (unsigned int) pipe_nr);
+ c->perr = CreateNamedPipe(buf,
+ PIPE_ACCESS_DUPLEX,
+ PIPE_WAIT,
+ 1,
+ BUFSIZE,
+ BUFSIZE,
+ NMPWAIT_USE_DEFAULT_WAIT,
+ &sa);
+ if (c->perr == INVALID_HANDLE_VALUE) {
+ hprintf(c->pipe, "error Cannot create err pipe(%s), error 0x%08x\n", buf, GetLastError());
+ goto finishClosePout;
+ }
+
+ /* Send handle to client (it will use it to connect pipes) */
+ hprintf(c->pipe, CMD_STD_IO_ERR " %08X\n", pipe_nr);
+
+ HANDLE ph[] = { c->pin, c->pout, c->perr };
+ int i;
+
+ for (i = 0; i < 3; ++i) {
+ if (ConnectNamedPipe(ph[i], NULL))
+ continue;
+ int err = GetLastError();
+ if (err != ERROR_PIPE_CONNECTED) {
+ hprintf(c->pipe, "error ConnectNamedPipe(pin) %d\n", err);
+ while (--i >= 0)
+ DisconnectNamedPipe(ph[i]);
+ goto finishClosePerr;
+ }
+ }
+
+ SetHandleInformation(c->pin, HANDLE_FLAG_INHERIT, 1);
+ SetHandleInformation(c->pout, HANDLE_FLAG_INHERIT, 1);
+ SetHandleInformation(c->perr, HANDLE_FLAG_INHERIT, 1);
+
+ if (c->profile)
+ load_user_profile(c);
+
+ PROCESS_INFORMATION pi;
+ ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
+
+ STARTUPINFO si;
+ ZeroMemory(&si, sizeof(STARTUPINFO));
+ si.cb = sizeof(STARTUPINFO);
+ si.hStdInput = c->pin;
+ si.hStdOutput = c->pout;
+ si.hStdError = c->perr;
+ si.dwFlags |= STARTF_USESTDHANDLES;
+
+ if (CreateProcessAsUser(
+ c->token,
+ NULL,
+ cmdline, /* command line */
+ NULL, /* process security attributes */
+ NULL, /* primary thread security attributes */
+ TRUE, /* handles are inherited */
+ 0, /* creation flags */
+ NULL, /* use parent's environment */
+ NULL, /* use parent's current directory */
+ &si, /* STARTUPINFO pointer */
+ &pi) /* receives PROCESS_INFORMATION */
+ ) {
+ HANDLE hlist[2] = {c->pipe->o.hEvent, pi.hProcess};
+ DWORD ec;
+ char str[1];
+
+ if (!ResetEvent(c->pipe->o.hEvent))
+ dbg("ResetEvent error - %lu\n", GetLastError());
+ if (!ReadFile(c->pipe->h, str, 1, NULL, &c->pipe->o) && GetLastError() != ERROR_IO_PENDING)
+ dbg("ReadFile(control_pipe) error - %lu\n", GetLastError());
+ ec = WaitForMultipleObjects(2, hlist, FALSE, INFINITE);
+ dbg("WaitForMultipleObjects=%lu\n", ec - WAIT_OBJECT_0);
+ if (ec != WAIT_OBJECT_0)
+ GetExitCodeProcess(pi.hProcess, &ec);
+ else
+ TerminateProcess(pi.hProcess, ec = 0x1234);
+ FlushFileBuffers(c->pout);
+ FlushFileBuffers(c->perr);
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ hprintf(c->pipe, CMD_RETURN_CODE " %08X\n", ec);
+ } else {
+ hprintf(c->pipe, "error Creating process(%s) %d\n", cmdline, GetLastError());
+ }
+
+ DisconnectNamedPipe(c->perr);
+ DisconnectNamedPipe(c->pout);
+ DisconnectNamedPipe(c->pin);
+finishClosePerr:
+ CloseHandle(c->perr);
+finishClosePout:
+ CloseHandle(c->pout);
+finishClosePin:
+ CloseHandle(c->pin);
+finishCloseToken:
+ CloseHandle(c->token);
+finish:
+ return res;
+}
+
+static CMD_ITEM cmd_table[] = {
+ {"run", cmd_run},
+ {"set", cmd_set},
+ {"get", cmd_get},
+ {NULL, NULL}
+};
+
+typedef struct {
+ OV_HANDLE *pipe;
+ int conn_number;
+} connection_data;
+
+#define MAX_COMMAND_LENGTH (32768)
+
+static VOID handle_connection(connection_data *data)
+{
+ char *cmd = 0;
+ int res;
+ connection_context _c, *c = &_c;
+ cmd = malloc(MAX_COMMAND_LENGTH);
+ if (!cmd) {
+ hprintf(data->pipe,
+ "error: unable to allocate buffer for command\n");
+ return;
+ }
+ ZeroMemory(cmd, MAX_COMMAND_LENGTH);
+ ZeroMemory(c, sizeof(connection_context));
+ c->pipe = data->pipe;
+ c->cmd = cmd;
+ c->conn_number = data->conn_number;
+ free(data);
+ /* FIXME make wait for end of process or ctrl_pipe input */
+ while (1) {
+ res = hgets(cmd, MAX_COMMAND_LENGTH, c->pipe);
+ if (res <= 0) {
+ dbg("Error reading from pipe(%p)\n", c->pipe->h);
+ goto finish;
+ }
+ dbg("Retrieved line: \"%s\"\n", cmd);
+ CMD_ITEM *ci;
+ for (ci = cmd_table; ci->name; ++ci) {
+ if (strstr(cmd, ci->name) != cmd)
+ continue;
+ char c = cmd[strlen(ci->name)];
+ if (!c || (c == ' '))
+ break;
+ }
+ if (ci->name) {
+ if (!ci->func(c))
+ goto finish;
+ } else {
+ hprintf(c->pipe, "error Ignoring unknown command (%s)\n", cmd);
+ }
+ }
+finish:
+ FlushFileBuffers(c->pipe->h);
+ DisconnectNamedPipe(c->pipe->h);
+ CloseHandle(c->pipe->h);
+ CloseHandle(c->pipe->o.hEvent);
+ free(c->pipe);
+ free(cmd);
+}
+
+static int conn_number = 0;
+
+DWORD WINAPI winexesvc_loop(LPVOID lpParameter)
+{
+ BOOL res;
+
+ dbg("server_loop: alive\n");
+ if (!CreatePipesSA()) {
+ dbg("CreatePipesSA failed (%08lX)\n", GetLastError());
+ return -1;
+ }
+ dbg("server_loop: CreatePipesSA done\n");
+ for (;;) {
+ dbg("server_loop: Create Pipe\n");
+ OV_HANDLE *pipe;
+ pipe = (OV_HANDLE *)malloc(sizeof(OV_HANDLE));
+ ZeroMemory(&pipe->o, sizeof(OVERLAPPED));
+ pipe->o.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ pipe->h = CreateNamedPipe("\\\\.\\pipe\\" PIPE_NAME,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES,
+ BUFSIZE,
+ BUFSIZE,
+ NMPWAIT_USE_DEFAULT_WAIT,
+ &sa);
+ if (pipe->h == INVALID_HANDLE_VALUE) {
+ dbg("CreatePipe failed(%08lX)\n",
+ GetLastError());
+ CloseHandle(pipe->o.hEvent);
+ free(pipe);
+ return 0;
+ }
+
+ dbg("server_loop: Connect Pipe\n");
+ if (ConnectNamedPipe(pipe->h, &pipe->o)) {
+ dbg("server_loop: Connect Pipe err %08lX\n", GetLastError());
+ res = FALSE;
+ } else {
+ switch (GetLastError()) {
+ case ERROR_IO_PENDING:
+ dbg("server_loop: Connect Pipe(0) pending\n");
+ DWORD t;
+ res = GetOverlappedResult(pipe->h, &pipe->o, &t, TRUE);
+ break;
+ case ERROR_PIPE_CONNECTED:
+ dbg("server_loop: Connect Pipe(0) connected\n");
+ res = TRUE;
+ break;
+ default:
+ dbg("server_loop: Connect Pipe(0) err %08lX\n", GetLastError());
+ res = FALSE;
+ }
+ }
+
+ if (res) {
+ connection_data *cd = malloc(sizeof(connection_data));
+ cd->pipe = pipe;
+ cd->conn_number = ++conn_number;
+ dbg("server_loop: CreateThread\n");
+ HANDLE th = CreateThread(NULL, /* no security attribute */
+ 0, /* default stack size */
+ (LPTHREAD_START_ROUTINE)
+ handle_connection,
+ (LPVOID) cd, /* thread parameter */
+ 0, /* not suspended */
+ NULL); /* returns thread ID */
+ if (!th) {
+ dbg("Cannot create thread\n");
+ CloseHandle(pipe->h);
+ CloseHandle(pipe->o.hEvent);
+ free(pipe);
+ } else {
+ CloseHandle(th);
+ dbg("server_loop: Thread created\n");
+ }
+ } else {
+ dbg("server_loop: Pipe not connected\n");
+ CloseHandle(pipe->h);
+ CloseHandle(pipe->o.hEvent);
+ free(pipe);
+ }
+ }
+ dbg("server_loop: STH wrong\n");
+ return 0;
+}
+
+static SERVICE_STATUS winexesvcStatus;
+static SERVICE_STATUS_HANDLE winexesvcStatusHandle;
+
+static VOID WINAPI winexesvcCtrlHandler(DWORD Opcode)
+{
+ switch (Opcode) {
+ case SERVICE_CONTROL_PAUSE:
+ dbg(SERVICE_NAME ": winexesvcCtrlHandler: pause\n", 0);
+ winexesvcStatus.dwCurrentState = SERVICE_PAUSED;
+ break;
+
+ case SERVICE_CONTROL_CONTINUE:
+ dbg(SERVICE_NAME ": winexesvcCtrlHandler: continue\n", 0);
+ winexesvcStatus.dwCurrentState = SERVICE_RUNNING;
+ break;
+
+ case SERVICE_CONTROL_STOP:
+ dbg(SERVICE_NAME ": winexesvcCtrlHandler: stop\n", 0);
+ winexesvcStatus.dwWin32ExitCode = 0;
+ winexesvcStatus.dwCurrentState = SERVICE_STOPPED;
+ winexesvcStatus.dwCheckPoint = 0;
+ winexesvcStatus.dwWaitHint = 0;
+
+ if (!SetServiceStatus (winexesvcStatusHandle, &winexesvcStatus))
+ dbg(SERVICE_NAME ": SetServiceStatus error %ld\n", GetLastError());
+
+ dbg(SERVICE_NAME ": Leaving winexesvc\n", 0);
+ return;
+
+ case SERVICE_CONTROL_INTERROGATE:
+ dbg(SERVICE_NAME ": winexesvcCtrlHandler: interrogate\n", 0);
+ break;
+
+ default:
+ dbg(SERVICE_NAME ": Unrecognized opcode %ld\n", Opcode);
+ }
+
+ if (!SetServiceStatus(winexesvcStatusHandle, &winexesvcStatus))
+ dbg(SERVICE_NAME ": SetServiceStatus error 0x%08X\n", GetLastError());
+
+ return;
+}
+
+static DWORD winexesvcInitialization(DWORD argc, LPTSTR * argv, DWORD * specificError)
+{
+ HANDLE th = CreateThread(NULL, 0, winexesvc_loop, NULL, 0, NULL);
+ if (th) {
+ CloseHandle(th);
+ return NO_ERROR;
+ }
+ return !NO_ERROR;
+}
+
+static void WINAPI winexesvcStart(DWORD argc, LPTSTR * argv)
+{
+ DWORD status;
+ DWORD specificError;
+
+ winexesvcStatus.dwServiceType = SERVICE_WIN32;
+ winexesvcStatus.dwCurrentState = SERVICE_START_PENDING;
+ winexesvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
+ winexesvcStatus.dwWin32ExitCode = 0;
+ winexesvcStatus.dwServiceSpecificExitCode = 0;
+ winexesvcStatus.dwCheckPoint = 0;
+ winexesvcStatus.dwWaitHint = 0;
+
+ dbg(SERVICE_NAME ": RegisterServiceCtrlHandler\n", 0);
+
+ winexesvcStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, winexesvcCtrlHandler);
+
+ if (winexesvcStatusHandle == (SERVICE_STATUS_HANDLE) 0) {
+ dbg(SERVICE_NAME
+ ": RegisterServiceCtrlHandler failed %d\n",
+ GetLastError());
+ return;
+ }
+ status = winexesvcInitialization(argc, argv, &specificError);
+
+ if (status != NO_ERROR) {
+ winexesvcStatus.dwCurrentState = SERVICE_STOPPED;
+ winexesvcStatus.dwCheckPoint = 0;
+ winexesvcStatus.dwWaitHint = 0;
+ winexesvcStatus.dwWin32ExitCode = status;
+ winexesvcStatus.dwServiceSpecificExitCode = specificError;
+
+ SetServiceStatus(winexesvcStatusHandle, &winexesvcStatus);
+ return;
+ }
+
+ winexesvcStatus.dwCurrentState = SERVICE_RUNNING;
+ winexesvcStatus.dwCheckPoint = 0;
+ winexesvcStatus.dwWaitHint = 0;
+
+ if (!SetServiceStatus(winexesvcStatusHandle, &winexesvcStatus)) {
+ status = GetLastError();
+ dbg(SERVICE_NAME ": SetServiceStatus error %ld\n", status);
+ }
+
+ dbg(SERVICE_NAME ": Returning the Main Thread \n", 0);
+
+ return;
+}
+
+int main(int argc, char *argv[])
+{
+ SERVICE_TABLE_ENTRY DispatchTable[] = {
+ {SERVICE_NAME, winexesvcStart},
+ {NULL, NULL}
+ };
+
+ dbg(SERVICE_NAME ": StartServiceCtrlDispatcher %d\n", GetLastError());
+ if (!StartServiceCtrlDispatcher(DispatchTable)) {
+ dbg(SERVICE_NAME
+ ": StartServiceCtrlDispatcher (%d)\n",
+ GetLastError());
+ }
+ return 0;
+}
diff --git a/examples/winexe/winexesvc.h b/examples/winexe/winexesvc.h
new file mode 100644
index 0000000..92b8375
--- /dev/null
+++ b/examples/winexe/winexesvc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) Andrzej Hajda 2009-2013
+ * Contact: andrzej.hajda@wp.pl
+ *
+ * Source of this file: https://git.code.sf.net/p/winexe/winexe-waf
+ * commit b787d2a2c4b1abc3653bad10aec943b8efcd7aab.
+ *
+ * ** NOTE! The following "GPLv3 only" license applies to the winexe
+ * ** service files. This does NOT imply that all of Samba is released
+ * ** under the "GPLv3 only" license.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 3 as published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Shared by winexe and winexesvc
+ */
+
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 1
+
+#define VERSION ((VERSION_MAJOR * 100) + VERSION_MINOR)
+
+#define SERVICE_NAME "winexesvc"
+
+#define PIPE_NAME "ahexec"
+#define PIPE_NAME_IN "ahexec_stdin%08X"
+#define PIPE_NAME_OUT "ahexec_stdout%08X"
+#define PIPE_NAME_ERR "ahexec_stderr%08X"
+
+#define CMD_STD_IO_ERR "std_io_err"
+#define CMD_RETURN_CODE "return_code"
diff --git a/examples/winexe/wscript b/examples/winexe/wscript
new file mode 100644
index 0000000..6b311b1
--- /dev/null
+++ b/examples/winexe/wscript
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+def configure(conf):
+ AR32 = ['i386', 'i586', 'i686']
+ AR64 = ['x86_64', 'amd64']
+ TC = ['mingw32', 'mingw32msvc', 'w64-mingw32']
+
+ found = False
+
+ for a in AR32:
+ for t in TC:
+ if conf.find_program(a + '-' + t + '-gcc', var='WINEXE_CC_WIN32'):
+ found = True
+ break
+ if found:
+ conf.DEFINE('HAVE_WINEXE_CC_WIN32', 1);
+ break
+
+ found = False
+
+ for a in AR64:
+ for t in TC:
+ if conf.find_program(a + '-' + t + '-gcc', var='WINEXE_CC_WIN64'):
+ found = True
+ break
+ if found:
+ conf.DEFINE('HAVE_WINEXE_CC_WIN64', 1);
+ break
+
+ conf.DEFINE("WINEXE_LDFLAGS",
+ "-s -Wall -Wl,-Bstatic -Wl,-Bdynamic -luserenv")
diff --git a/examples/winexe/wscript_build b/examples/winexe/wscript_build
new file mode 100644
index 0000000..3646834
--- /dev/null
+++ b/examples/winexe/wscript_build
@@ -0,0 +1,118 @@
+#!/usr/bin/env python
+
+import samba_utils
+
+def generate_winexesvc_c_from_exe(t):
+ '''generate a C source file with the contents of the given binary'''
+ src = t.inputs[0].bldpath(t.env)
+ tgt = t.outputs[0].bldpath(t.env)
+ fn = t.env.SAMBA_GENERATOR_VARS['WINEXE_FN']
+
+ try:
+ with open(src, 'rb') as f:
+ src_blob = f.read()
+ f.close()
+ except:
+ print('Failed to read %s to convert to C array' % (src))
+ return -1
+
+ def c_array(src):
+ N = 0
+ result = ''
+ while src:
+ l = src[:8]
+ src = src[8:]
+ # Even files opened in binary mode are read as type "str" in
+ # Python 2, so we need to get the integer ordinal of each
+ # character in the string before we try to convert it to hex.
+ if isinstance(l, str):
+ h = ' '.join(["0x%02X," % ord(x) for x in l])
+ # Files opened in binary mode are read as type "bytes" in
+ # Python 3, so we can convert each individual integer in the
+ # array of bytes to hex directly.
+ else:
+ h = ' '.join(["0x%02X," % x for x in l])
+ result += "\t\t%s\n" % (h)
+ return result
+
+ src_array = c_array(src_blob)
+ if len(src_array) <= 0:
+ print('Failed to convert %s to C array' % (src))
+ return -1
+
+ contents = '''
+#include "replace.h"
+#include "lib/util/data_blob.h"
+
+const DATA_BLOB *%s(void);
+const DATA_BLOB *%s(void)
+{
+\tstatic const uint8_t array[] = {
+%s
+\t};
+\tstatic const DATA_BLOB blob = {
+\t\t.data = discard_const_p(uint8_t, array),
+\t\t.length = ARRAY_SIZE(array),
+\t};
+\treturn &blob;
+}
+''' % (fn, fn, src_array)
+
+ if not samba_utils.save_file(tgt, contents):
+ print('Failed to write C source file %s' % (tgt))
+ return -1
+ return 0
+
+winexesvc_binaries = ''
+
+bld.SAMBA_GENERATOR(
+ 'winexesvc32_exe',
+ source='winexesvc.c',
+ target='winexesvc32.exe',
+ rule='${WINEXE_CC_WIN32} ${SRC} -o ${TGT} ${WINEXE_LDFLAGS}',
+ enabled=bld.env.build_winexe and bld.env.WINEXE_CC_WIN32)
+
+vars = {"WINEXE_FN": "winexesvc32_exe_binary"}
+bld.SAMBA_GENERATOR(
+ 'winexesvc32_exe_binary',
+ source='winexesvc32.exe',
+ target='winexesvc32_exe_binary.c',
+ group='build_source',
+ vars=vars,
+ rule=generate_winexesvc_c_from_exe,
+ enabled=bld.env.build_winexe and bld.env.WINEXE_CC_WIN32)
+
+if bld.env.WINEXE_CC_WIN32:
+ winexesvc_binaries += ' winexesvc32_exe_binary.c'
+
+bld.SAMBA_GENERATOR(
+ 'winexesvc64_exe',
+ source='winexesvc.c',
+ target='winexesvc64.exe',
+ rule='${WINEXE_CC_WIN64} ${SRC} -o ${TGT} ${WINEXE_LDFLAGS}',
+ enabled=bld.env.build_winexe and bld.env.WINEXE_CC_WIN64)
+
+vars = {"WINEXE_FN": "winexesvc64_exe_binary"}
+bld.SAMBA_GENERATOR(
+ 'winexesvc64_exe_binary',
+ source='winexesvc64.exe',
+ target='winexesvc64_exe_binary.c',
+ group='build_source',
+ vars=vars,
+ rule=generate_winexesvc_c_from_exe,
+ enabled=bld.env.build_winexe and bld.env.WINEXE_CC_WIN64)
+
+if bld.env.WINEXE_CC_WIN64:
+ winexesvc_binaries += ' winexesvc64_exe_binary.c'
+
+if winexesvc_binaries != '':
+ bld.SAMBA3_BINARY('winexe',
+ source='winexe.c ' + winexesvc_binaries,
+ deps='''
+ CMDLINE_S3
+ samba-credentials
+ LOADPARM_CTX
+ libsmb
+ msrpc3
+ ''',
+ enabled=bld.env.build_winexe)