summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
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.c1110
-rw-r--r--examples/VFS/skel_transparent.c1422
-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.c1556
-rw-r--r--examples/fuse/clifuse.h27
-rw-r--r--examples/fuse/smb2mount.c157
-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.c282
-rw-r--r--examples/libsmbclient/testbrowse2.c170
-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.c70
-rw-r--r--examples/libsmbclient/teststat2.c70
-rw-r--r--examples/libsmbclient/teststat3.c75
-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.c814
-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
-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/tridge/README8
-rw-r--r--examples/tridge/smb.conf92
-rw-r--r--examples/tridge/smb.conf.WinNT14
-rw-r--r--examples/tridge/smb.conf.fjall20
-rw-r--r--examples/tridge/smb.conf.lapland14
-rw-r--r--examples/tridge/smb.conf.vittjokk14
-rw-r--r--examples/validchars/msdos70.out257
-rw-r--r--examples/validchars/nwdos70.out257
-rw-r--r--examples/validchars/readme101
-rw-r--r--examples/validchars/validchr.c123
-rw-r--r--examples/validchars/validchr.com77
-rw-r--r--examples/winexe/README18
-rw-r--r--examples/winexe/winexe.c1921
-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_build110
161 files changed, 30854 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..f268b47
--- /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)
+
+( (nextattrib += 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 += 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..12392cb
--- /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 "### Unknow 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 "### Unknow 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 methode 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..1fca4a7
--- /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 directoy 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..48bf9d5
--- /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 this 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..a72ba57
--- /dev/null
+++ b/examples/VFS/skel_opaque.c
@@ -0,0 +1,1110 @@
+/*
+ * 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,
+ SMB_STRUCT_STAT *sbuf)
+{
+ return NULL;
+}
+
+static void skel_seekdir(vfs_handle_struct *handle, DIR *dirp, long offset)
+{
+ ;
+}
+
+static long skel_telldir(vfs_handle_struct *handle, DIR *dirp)
+{
+ return (long)-1;
+}
+
+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 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,
+ .seekdir_fn = skel_seekdir,
+ .telldir_fn = skel_telldir,
+ .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..8fb8644
--- /dev/null
+++ b/examples/VFS/skel_transparent.c
@@ -0,0 +1,1422 @@
+/*
+ * 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,
+ SMB_STRUCT_STAT *sbuf)
+{
+ return SMB_VFS_NEXT_READDIR(handle, dirfsp, dirp, sbuf);
+}
+
+static void skel_seekdir(vfs_handle_struct *handle, DIR *dirp, long offset)
+{
+ SMB_VFS_NEXT_SEEKDIR(handle, dirp, offset);
+}
+
+static long skel_telldir(vfs_handle_struct *handle, DIR *dirp)
+{
+ return SMB_VFS_NEXT_TELLDIR(handle, 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 smb_filename *smb_fname)
+{
+ return SMB_VFS_NEXT_CONNECTPATH(handle, 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,
+ .seekdir_fn = skel_seekdir,
+ .telldir_fn = skel_telldir,
+ .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..1f06028
--- /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
+ browseable = no
+ read only = no
+ create mode = 0750
+
+[test]
+ comment = test stuff
+ path = /dept/mis/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
+ browseable = no
+ read only = no
+ create mode = 0750
+
+[develdfs]
+ comment = Technology Development Cell
+ path = /.../devel.boston.oec.com/fs
+ browseable = 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..f75a9f5
--- /dev/null
+++ b/examples/fuse/clifuse.c
@@ -0,0 +1,1556 @@
+/*
+ * 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"
+
+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[1];
+};
+
+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,
+ 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);
+ 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);
+ 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 */
+ (SMB_FILE_ALL_INFORMATION - 1000), /* 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((char *)outbuf.data + 0x0);
+ state->access_time = interpret_long_date((char *)outbuf.data + 0x8);
+ state->write_time = interpret_long_date((char *)outbuf.data + 0x10);
+ state->change_time = interpret_long_date((char *)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 (IS_DOS_DIR(state->mode)) {
+ 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((const char *)dir_data + 8);
+ finfo->atime_ts = interpret_long_date((const char *)dir_data + 16);
+ finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24);
+ finfo->ctime_ts = interpret_long_date((const char *)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);
+}
+
+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,
+ 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);
+ 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);
+ 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);
+ 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,
+ .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..7133927
--- /dev/null
+++ b/examples/fuse/smb2mount.c
@@ -0,0 +1,157 @@
+/*
+ * 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 "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();
+ 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_set_cmdline("client min protocol", "SMB2");
+ lp_set_cmdline("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..5f2be72
--- /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..0f6e0ac
--- /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..a74a72d
--- /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..59d9994
--- /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..1609e2f
--- /dev/null
+++ b/examples/libsmbclient/testbrowse.c
@@ -0,0 +1,282 @@
+#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..ac2063d
--- /dev/null
+++ b/examples/libsmbclient/testbrowse2.c
@@ -0,0 +1,170 @@
+/*
+ * 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("Cant 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..b285a81
--- /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..7f27fbd
--- /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..b2396e3
--- /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..e6d9bf8
--- /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..3c9aa56
--- /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..4084fd0
--- /dev/null
+++ b/examples/libsmbclient/teststat.c
@@ -0,0 +1,70 @@
+#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;
+ const char * pLocalPath = NULL;
+ struct stat st;
+
+ 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;
+ }
+
+ smbc_init(get_auth_data_fn, debug);
+
+ if (smbc_stat(pSmbPath, &st) < 0)
+ {
+ perror("smbc_stat");
+ return 1;
+ }
+
+ printf("\nSAMBA\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));
+
+ if (pLocalPath != NULL)
+ {
+ 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/teststat2.c b/examples/libsmbclient/teststat2.c
new file mode 100644
index 0000000..963cd27
--- /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..3efe51d
--- /dev/null
+++ b/examples/libsmbclient/teststat3.c
@@ -0,0 +1,75 @@
+#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..9a8e539
--- /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..1b4298d
--- /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..662bd86
--- /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..1837839
--- /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..6e34cd0
--- /dev/null
+++ b/examples/libsmbclient/tree.c
@@ -0,0 +1,814 @@
+/*
+ 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..b047089
--- /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 ocassionally
+# 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..e33c565
--- /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 useage section
+
+removed the large docstring from the file and moved the information to
+the USEAGE 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
+
+======
+USEAGE
+======
+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 curently 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..4e278f8
--- /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 = '\[ *' + s + ' *\]'
+ elif s == 'Group':
+ hdrstring = '\[ *' + s + ' *- *' + group + ' *\]'
+ elif s == 'User':
+ hdrstring = '\[ *' + s + ' *- *' + user + ' *\]'
+ elif s == 'OS':
+ hdrstring = '\[ *' + s + ' *- *' + ostype + ' *\]'
+ elif s == 'Machine':
+ hdrstring = '\[ *' + s + ' *- *' + machine + ' *\]'
+
+ #
+ # 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 substition name specified line: %d" % idx
+ sys.exit(1)
+
+ if varsub == '':
+ print "Error: No substitution text provided line: %d" % idx
+ sys.exit(1)
+
+ if macros.has_key(varname):
+ 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..87bc388
--- /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 dependend 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..46f8514
--- /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 it -i which supresses 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..ea12990
--- /dev/null
+++ b/examples/printer-accounting/hp5-redir
@@ -0,0 +1,40 @@
+#!/usr/bin/perl
+#
+# 0 == stdin == docuement
+# 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..91a3def
--- /dev/null
+++ b/examples/printer-accounting/lp-acct
@@ -0,0 +1,35 @@
+#!/usr/bin/perl
+#
+# 0 == stdin == docuement
+# 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..f245c31
--- /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 $@ ; 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/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..3032493
--- /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 meeds 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..7c58917
--- /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 agrument 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..6759428
--- /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: madatory 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..919f75a
--- /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: madatory 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..2e8b717
--- /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
+# readding 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..2f20720
--- /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
+ browseable = 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
+; browseable = no
+; guest ok = yes
+
+
+# NOTE: If you have a BSD-style print system there is no need to
+# specifically define each individual printer
+[printers]
+ comment = All Printers
+ path = /usr/spool/samba
+ browseable = no
+# Set public = yes to allow user 'guest account' to print
+ guest ok = no
+ writable = no
+ printable = yes
+
+# This one is useful for people to share files
+;[tmp]
+; comment = Temporary file space
+; path = /tmp
+; read only = no
+; public = yes
+
+# A publicly accessible directory, but read only, except for people in
+# the "staff" group
+;[public]
+; comment = Public Stuff
+; path = /home/samba
+; public = yes
+; 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/tridge/README b/examples/tridge/README
new file mode 100644
index 0000000..11c72f2
--- /dev/null
+++ b/examples/tridge/README
@@ -0,0 +1,8 @@
+This is the configuration I use at home. I have 2 client PCs, one
+running Win95, one running alternately WfWg and NTAS3.5. My server is
+a 486dx2-66 Linux box.
+
+Note that I use the %a and %m macros to load smb.conf extensions
+particular to machines and architectures. This gives me a lot of
+flexibility in how I handle each of the machines.
+
diff --git a/examples/tridge/smb.conf b/examples/tridge/smb.conf
new file mode 100644
index 0000000..d1d18db
--- /dev/null
+++ b/examples/tridge/smb.conf
@@ -0,0 +1,92 @@
+[global]
+ config file = /usr/local/samba/smb.conf.%m
+ status = yes
+ security = user
+ encrypt passwords = yes
+ server string = Tridge (%v,%h)
+ load printers = yes
+ log level = 1
+ log file = /usr/local/samba/var/log.%m
+ guest account = pcguest
+ hosts allow = 192.0.2. localhost
+ auto services = tridge susan
+ message command = csh -c '/usr/bin/X11/xedit -display :0 %s;rm %s' &
+ read prediction = yes
+ socket options = TCP_NODELAY
+ valid chars = ö:Ö å:Å ä:Ä
+ share modes = yes
+ locking = yes
+ strict locking = yes
+ keepalive = 30
+ include = /usr/local/samba/lib/smb.conf.%m
+ include = /usr/local/samba/lib/smb.conf.%a
+
+
+[uniprint]
+ comment = University Printing
+ path = /home/susan/print
+ user = susan
+ postscript = yes
+ print ok = yes
+ print command = xmenu -heading "%s" OK&
+
+[amd]
+ comment = amd area
+ path = /mount
+ force user = tridge
+ read only = no
+
+[homes]
+ browseable = no
+ guest ok = no
+ read only = no
+ create mask = 0755
+
+[printers]
+ browseable = no
+ comment = Printer in Printcap
+ guest ok = no
+ path = /tmp
+ read only = no
+ print ok = yes
+
+[dos]
+ browseable = yes
+ comment = Dos Files
+ force group = samba
+ create mode = 0775
+ path = /home/tridge/dos
+ copy = homes
+
+[msoffice]
+ browseable = yes
+ comment = Microsoft Office
+ force group = samba
+ create mode = 0775
+ path = /data/msoffice
+ read only = yes
+
+[root]
+ comment = Root Dir
+ copy = dos
+ path = /
+ dont descend = /proc ./proc /etc
+
+[tmp]
+ comment = tmp files
+ copy = dos
+ path = /tmp
+ read only = no
+
+
+[cdrom]
+ comment = Tridge's CdRom
+ path = /mount/cdrom
+ read only = yes
+ locking = no
+
+[data]
+ comment = Data Partition
+ path = /data
+ read only = yes
+ guest ok = yes
diff --git a/examples/tridge/smb.conf.WinNT b/examples/tridge/smb.conf.WinNT
new file mode 100644
index 0000000..f490f83
--- /dev/null
+++ b/examples/tridge/smb.conf.WinNT
@@ -0,0 +1,14 @@
+#log level = 4
+#readraw = no
+#writeraw = no
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/tridge/smb.conf.fjall b/examples/tridge/smb.conf.fjall
new file mode 100644
index 0000000..8406596
--- /dev/null
+++ b/examples/tridge/smb.conf.fjall
@@ -0,0 +1,20 @@
+;log level = 4
+;readraw = no
+;writeraw = no
+;mangled map = (;1 )
+;protocol = lanman1
+;user = susan
+;getwd cache = no
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/tridge/smb.conf.lapland b/examples/tridge/smb.conf.lapland
new file mode 100644
index 0000000..f490f83
--- /dev/null
+++ b/examples/tridge/smb.conf.lapland
@@ -0,0 +1,14 @@
+#log level = 4
+#readraw = no
+#writeraw = no
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/tridge/smb.conf.vittjokk b/examples/tridge/smb.conf.vittjokk
new file mode 100644
index 0000000..919ecd1
--- /dev/null
+++ b/examples/tridge/smb.conf.vittjokk
@@ -0,0 +1,14 @@
+;protocol = LANMAN2
+log level = 2
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/validchars/msdos70.out b/examples/validchars/msdos70.out
new file mode 100644
index 0000000..a722b83
--- /dev/null
+++ b/examples/validchars/msdos70.out
@@ -0,0 +1,257 @@
+255: ok
+254: ok
+253: ok
+252: ok
+251: ok
+250: ok
+249: ok
+248: ok
+247: ok
+246: ok
+245: ok
+244: ok
+243: ok
+242: ok
+241: ok
+240: ok
+239: ok
+238: ok
+237: ok
+236: 237
+235: ok
+234: ok
+233: ok
+232: ok
+231: 232
+230: ok
+229: ok
+228: 229
+227: ok
+226: ok
+225: ok
+224: ok
+223: ok
+222: ok
+221: ok
+220: ok
+219: ok
+218: ok
+217: ok
+216: ok
+215: ok
+214: ok
+213: 73
+212: ok
+211: ok
+210: ok
+209: ok
+208: 209
+207: ok
+206: ok
+205: ok
+204: ok
+203: ok
+202: ok
+201: ok
+200: ok
+199: ok
+198: 199
+197: ok
+196: ok
+195: ok
+194: ok
+193: ok
+192: ok
+191: ok
+190: ok
+189: ok
+188: ok
+187: ok
+186: ok
+185: ok
+184: ok
+183: ok
+182: ok
+181: ok
+180: ok
+179: ok
+178: ok
+177: ok
+176: ok
+175: ok
+174: ok
+173: ok
+172: ok
+171: ok
+170: ok
+169: ok
+168: ok
+167: ok
+166: ok
+165: ok
+164: 165
+163: 233
+162: 224
+161: 214
+160: 181
+159: ok
+158: ok
+157: ok
+156: ok
+155: 157
+154: ok
+153: ok
+152: length 0
+151: 235
+150: 234
+149: 227
+148: 153
+147: 226
+146: ok
+145: 146
+144: ok
+143: ok
+142: ok
+141: 222
+140: 215
+139: 216
+138: 212
+137: 211
+136: 210
+135: 128
+134: 143
+133: 183
+132: 142
+131: 182
+130: 144
+129: 154
+128: ok
+127: ok
+126: ok
+125: ok
+124: open unlink 0
+123: ok
+122: 90
+121: 89
+120: 88
+119: 87
+118: 86
+117: 85
+116: 84
+115: 83
+114: 82
+113: 81
+112: 80
+111: 79
+110: 78
+109: 77
+108: 76
+107: 75
+106: 74
+105: 73
+104: 72
+103: 71
+102: 70
+101: 69
+100: 68
+99: 67
+98: 66
+97: 65
+96: ok
+95: ok
+94: ok
+93: open unlink 0
+92: open unlink 0
+91: open unlink 0
+90: ok
+89: ok
+88: ok
+87: ok
+86: ok
+85: ok
+84: ok
+83: ok
+82: ok
+81: ok
+80: ok
+79: ok
+78: ok
+77: ok
+76: ok
+75: ok
+74: ok
+73: ok
+72: ok
+71: ok
+70: ok
+69: ok
+68: ok
+67: ok
+66: ok
+65: ok
+64: ok
+63: open unlink 0
+62: open unlink 0
+61: open unlink 0
+60: open unlink 0
+59: open unlink 0
+58: open unlink 0
+57: ok
+56: ok
+55: ok
+54: ok
+53: ok
+52: ok
+51: ok
+50: ok
+49: ok
+48: ok
+47: open unlink 0
+46: open unlink 0
+45: ok
+44: open unlink 0
+43: open unlink 0
+42: open unlink 0
+41: ok
+40: ok
+39: ok
+38: ok
+37: ok
+36: ok
+35: ok
+34: open unlink 0
+33: ok
+32: open unlink 0
+31: open unlink 0
+30: open unlink 0
+29: open unlink 0
+28: open unlink 0
+27: open unlink 0
+26: open unlink 0
+25: open unlink 0
+24: open unlink 0
+23: open unlink 0
+22: open unlink 0
+21: open unlink 0
+20: open unlink 0
+19: open unlink 0
+18: open unlink 0
+17: open unlink 0
+16: open unlink 0
+15: open unlink 0
+14: open unlink 0
+13: open unlink 0
+12: open unlink 0
+11: open unlink 0
+10: open unlink 0
+9: open unlink 0
+8: open unlink 0
+7: open unlink 0
+6: open unlink 0
+5: open unlink 0
+4: open unlink 0
+3: open unlink 0
+2: open unlink 0
+1: open unlink 0
+
+ valid chars = 73:213 213:73 73:73 33 35 36 37 38 39 40 41 45 48 49 50 51 52 53 54 55 56 57 64 97:65 98:66 99:67 100:68 101:69 102:70 103:71 104:72 105:73 106:74 107:75 108:76 109:77 110:78 111:79 112:80 113:81 114:82 115:83 116:84 117:85 118:86 119:87 120:88 121:89 122:90 94 95 96 123 125 126 127 135:128 132:142 134:143 130:144 145:146 148:153 129:154 156 155:157 158 159 164:165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 160:181 131:182 133:183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198:199 200 201 202 203 204 205 206 207 208:209 136:210 137:211 138:212 161:214 140:215 139:216 217 218 219 220 221 141:222 223 162:224 225 147:226 149:227 228:229 230 231:232 163:233 150:234 151:235 236:237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
diff --git a/examples/validchars/nwdos70.out b/examples/validchars/nwdos70.out
new file mode 100644
index 0000000..b0dbf62
--- /dev/null
+++ b/examples/validchars/nwdos70.out
@@ -0,0 +1,257 @@
+255: ok
+254: ok
+253: ok
+252: ok
+251: ok
+250: ok
+249: ok
+248: ok
+247: ok
+246: ok
+245: ok
+244: ok
+243: ok
+242: ok
+241: ok
+240: ok
+239: ok
+238: ok
+237: ok
+236: ok
+235: ok
+234: ok
+233: ok
+232: ok
+231: ok
+230: ok
+229: ok
+228: ok
+227: ok
+226: ok
+225: ok
+224: ok
+223: ok
+222: ok
+221: ok
+220: ok
+219: ok
+218: ok
+217: ok
+216: ok
+215: ok
+214: ok
+213: ok
+212: ok
+211: ok
+210: ok
+209: ok
+208: ok
+207: ok
+206: ok
+205: ok
+204: ok
+203: ok
+202: ok
+201: ok
+200: ok
+199: ok
+198: ok
+197: ok
+196: ok
+195: ok
+194: ok
+193: ok
+192: ok
+191: ok
+190: ok
+189: ok
+188: ok
+187: ok
+186: ok
+185: ok
+184: ok
+183: ok
+182: ok
+181: ok
+180: ok
+179: ok
+178: ok
+177: ok
+176: ok
+175: ok
+174: ok
+173: ok
+172: ok
+171: ok
+170: ok
+169: ok
+168: ok
+167: ok
+166: ok
+165: ok
+164: 165
+163: 85
+162: 79
+161: 73
+160: 65
+159: ok
+158: ok
+157: ok
+156: ok
+155: ok
+154: ok
+153: ok
+152: 89
+151: 85
+150: 85
+149: 79
+148: 153
+147: 79
+146: ok
+145: 146
+144: ok
+143: ok
+142: ok
+141: 73
+140: 73
+139: 73
+138: 69
+137: 69
+136: 69
+135: 128
+134: 143
+133: 65
+132: 142
+131: 65
+130: 69
+129: 154
+128: ok
+127: ok
+126: ok
+125: ok
+124: open unlink 0
+123: ok
+122: 90
+121: 89
+120: 88
+119: 87
+118: 86
+117: 85
+116: 84
+115: 83
+114: 82
+113: 81
+112: 80
+111: 79
+110: 78
+109: 77
+108: 76
+107: 75
+106: 74
+105: 73
+104: 72
+103: 71
+102: 70
+101: 69
+100: 68
+99: 67
+98: 66
+97: 65
+96: ok
+95: ok
+94: ok
+93: open unlink 0
+92: open unlink 0
+91: open unlink 0
+90: ok
+89: ok
+88: ok
+87: ok
+86: ok
+85: ok
+84: ok
+83: ok
+82: ok
+81: ok
+80: ok
+79: ok
+78: ok
+77: ok
+76: ok
+75: ok
+74: ok
+73: ok
+72: ok
+71: ok
+70: ok
+69: ok
+68: ok
+67: ok
+66: ok
+65: ok
+64: ok
+63: open unlink 0
+62: open unlink 0
+61: open unlink 0
+60: open unlink 0
+59: open unlink 0
+58: open unlink 0
+57: ok
+56: ok
+55: ok
+54: ok
+53: ok
+52: ok
+51: ok
+50: ok
+49: ok
+48: ok
+47: open unlink 0
+46: open unlink 0
+45: ok
+44: open unlink 0
+43: open unlink 0
+42: open unlink 0
+41: ok
+40: ok
+39: ok
+38: ok
+37: ok
+36: ok
+35: ok
+34: open unlink 0
+33: ok
+32: length 0
+31: open unlink 0
+30: open unlink 0
+29: open unlink 0
+28: open unlink 0
+27: open unlink 0
+26: open unlink 0
+25: open unlink 0
+24: open unlink 0
+23: open unlink 0
+22: open unlink 0
+21: open unlink 0
+20: open unlink 0
+19: open unlink 0
+18: open unlink 0
+17: open unlink 0
+16: open unlink 0
+15: open unlink 0
+14: open unlink 0
+13: open unlink 0
+12: open unlink 0
+11: open unlink 0
+10: open unlink 0
+9: open unlink 0
+8: open unlink 0
+7: open unlink 0
+6: open unlink 0
+5: open unlink 0
+4: open unlink 0
+3: open unlink 0
+2: open unlink 0
+1: open unlink 0
+
+ valid chars = 69:130 130:69 69:69 65:131 131:65 65:65 65:133 133:65 65:65 69:136 136:69 69:69 69:137 137:69 69:69 69:138 138:69 69:69 73:139 139:73 73:73 73:140 140:73 73:73 73:141 141:73 73:73 79:147 147:79 79:79 79:149 149:79 79:79 85:150 150:85 85:85 85:151 151:85 85:85 89:152 152:89 89:89 65:160 160:65 65:65 73:161 161:73 73:73 79:162 162:79 79:79 85:163 163:85 85:85 33 35 36 37 38 39 40 41 45 48 49 50 51 52 53 54 55 56 57 64 97:65 98:66 99:67 100:68 101:69 102:70 103:71 104:72 105:73 106:74 107:75 108:76 109:77 110:78 111:79 112:80 113:81 114:82 115:83 116:84 117:85 118:86 119:87 120:88 121:89 122:90 94 95 96 123 125 126 127 135:128 132:142 134:143 144 145:146 148:153 129:154 155 156 157 158 159 164:165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
diff --git a/examples/validchars/readme b/examples/validchars/readme
new file mode 100644
index 0000000..6487fbd
--- /dev/null
+++ b/examples/validchars/readme
@@ -0,0 +1,101 @@
+Note: All files in this directory are DOS formatted (CRLF line terminator).
+
+!!! VIRUS WARNING !!! I do not know if VALIDCHR.COM is virus free !!!
+I think that my system is virus free here because I do not run any games
+or other copied software. I only run Shareware/Freeware etc. from CD-ROMs
+or from registered disks, however I do not use viral scanners because
+I have not registered any (I consider `having no sex' is better than
+`testing for AIDS on a regular basis', if you know what I mean).
+
+This is VALIDCHR, a little DOS program I wrote to create
+an apropriate `valid chars =' config parameter.
+It is freeware and is thought to be distributed freely with Samba.
+
+WARNING:
+ Your SMB driver may use another character map as the one VALIDCHR
+ sees. The only way you can tell this is that some file names fail.
+ Under Win95 everything is fine, though.
+
+Usage:
+ c:
+ mkdir junk_dir
+ cd junk_dir
+ a:validchr > a:output.log
+ cd ..
+ rmdir junk_dir
+
+Siedeffects:
+ Files named *.TST may be deleted.
+
+Verification:
+ For diagnostic purpose you can run VALIDCHR on a Samba mounted drive.
+ Then you can use unix diff to compare the output of the network and
+ the hard drive. These two outputs usually differ! However there
+ should be few differences. I get following on Win95 (c: visa e:)
+ 104c104
+ < 152: length 0
+ ---
+ > 152: 95
+ (diff line for `valid chars =' deleted because it's uninteresting)
+ You can see, `y diaresis' can be mapped on the network drive while
+ it cannot be mapped on the hard drive. Everything else is identical.
+ However this gives a hint that one can improve the mapping.
+
+Bugs:
+ Yes, probably some.
+
+
+VALIDCHR must be run on the system which character mapping should be probed.
+It must be run on the hard drive for this. VALIDCHR ALTERS THE CURRENT
+DIRECTORY AND REMOVES SOME FILES, SO ALWAYS RUN IT IN A junk DIRECTORY !!!
+You should redirect the output of VALIDCHR. At the end of the output is a
+line like
+ valid chars = x:y y:x x:x ... a:b c ...
+which is suitable for your smb.conf file. (you should remove the DOS CR
+character, because DOS uses CRLF while Unix uses LF only.)
+
+Note that some mappings at the beginning of the `valid chars =' line like
+A:B B:A B:B
+might look a little bit strange to you, however sometimes character A
+has to be mapped to character B independently of a default mapping
+to uppercase or lowercase while character B must not be touched. I found
+this out the hard way ... Consider it a crude workaround, because Samba
+lacks the possibility to map characters in one direction only!
+
+VALIDCHR usually issues one warning for character 32.
+You may ignore these and any other warnings.
+
+VALIDCHR does not test for character NUL (this is the directory end marker).
+
+validchr.c is the source code to validchr.com
+ You may do anything with the source code (copy, change, sell, burn)
+validchr.com is a Borland C compiled binary.
+ Beware, it may contain a virus (if my system contains one).
+nwdos70.out is the output of an VALIDCHR-run under Novell DOS 7.0
+ while no codepage (no display.sys) was active.
+msdos70.out is the output of an VALIDCHR-run under MS-DOS 7.0 (Win95 DOS)
+ while codepage 850 was active.
+
+I have no other MS-DOS systems at home currently.
+(I have access to MS-DOS 3.0, 3.2, 3.3, 5.0 and 6.22, however I have no time
+ to run VALIDCHR there)
+
+Some words to the output
+(for people not fammiliar with programming language C):
+
+probed_char: [text] mapped_char
+
+probed_char is the character probed to be written to disk
+text may be empty or contain:
+ open File could not be opened.
+ close File could not be closed (should not happen)
+ length File name was shortened (usually occurs on SPC)
+ unlink File cannot be unlinked (usually when open fails)
+mapped_char is the character which is used by MS-DOS in the directory
+ This is usually the uppercase character.
+ The mapped character is 0 if something failed (you may say
+ that the character is not supported)
+
+The last line in the output is documented in the smb.conf manual page ;)
+
+tino@augsburg.net
diff --git a/examples/validchars/validchr.c b/examples/validchars/validchr.c
new file mode 100644
index 0000000..415546c
--- /dev/null
+++ b/examples/validchars/validchr.c
@@ -0,0 +1,123 @@
+/* by tino@augsburg.net
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <dirent.h>
+
+unsigned char
+test(void)
+{
+ DIR *dir;
+ struct dirent *dp;
+ unsigned char c;
+
+ if ((dir=opendir("."))==0)
+ {
+ perror("open .");
+ return 0;
+ }
+ c = 0;
+ while ((dp=readdir(dir))!=0)
+ {
+ size_t len;
+
+ len = strlen(dp->d_name);
+ if (len<4)
+ continue;
+ if (strcmp(dp->d_name+len-4, ".TST"))
+ continue;
+ if (len!=5)
+ {
+ fprintf(stderr, "warning: %s\n", dp->d_name);
+ printf(" length");
+ continue;
+ }
+ if (c)
+ printf(" double%d\n", c);
+ c = dp->d_name[0];
+ }
+ if (closedir(dir))
+ perror("close .");
+ return c;
+}
+
+int
+main(void)
+{
+ char name[256];
+ unsigned char map[256], upper[256], lower[256];
+ int i, j, c;
+ FILE *fd;
+
+ if (test())
+ {
+ printf("There are *.TST files, please remove\n");
+ return 0;
+ }
+ for (i=0; ++i<256; )
+ {
+ lower[i] = i;
+ upper[i] = 0;
+ }
+ for (i=256; --i; )
+ {
+ map[i] = i;
+ strcpy(name, "..TST");
+ name[0] = i;
+ printf("%d:", i);
+ if ((fd=fopen(name, "w"))==0)
+ printf(" open");
+ else
+ fclose(fd);
+ c = test();
+ if (unlink(name))
+ printf(" unlink");
+ if (c==i)
+ printf(" ok");
+ else
+ printf(" %d", c);
+ printf("\n");
+ if (c!=i)
+ {
+ upper[c]++;
+ lower[c] = i;
+ }
+ map[i] = c;
+ }
+
+ /* Uppercase characters are detected above on:
+ * The character is mapped to itself and there is a
+ * character which maps to it.
+ * Lowercase characters are the lowest character pointing to another one.
+ * Else it is a one way character.
+ *
+ * For this reason we have to process the list
+ * 1) for 'one way' characters
+ * 'one way' is something which is no upper and no lower character.
+ * This is an awful, crude and ugly hack due to missing Samba support.
+ * 2) for true uppercase/lowercase characters
+ * 3) for standalone characters
+ * Note that there might be characters which do not fall into 1 to 3.
+ */
+ printf("\n valid chars =");
+ for (i=0; ++i<256; )
+ if (map[i] && map[i]!=i && lower[map[i]]!=i)
+ {
+ if (!upper[i])
+ printf(" %d:%d %d:%d %d:%d", /*1*/
+ map[i], i, i, map[i], map[i], map[i]);
+ else
+ fprintf(stderr, "ignoring map %d->%d because of %d->%d\n",
+ lower[i], i, i, map[i]);
+ }
+ for (i=0; ++i<256; )
+ if (map[i] && map[i]==i)
+ if (upper[i])
+ printf(" %d:%d", lower[i], i); /*2*/
+ else
+ printf(" %d", i); /*3*/
+ printf("\n");
+ return 0;
+}
diff --git a/examples/validchars/validchr.com b/examples/validchars/validchr.com
new file mode 100644
index 0000000..a5dbb39
--- /dev/null
+++ b/examples/validchars/validchr.com
@@ -0,0 +1,77 @@
+ŒÊ.‰–´0Í!‹.‹,ŽÚ£é Œç ‰ã ‰.ÿ è]¡ã ŽÀ3À‹Ø‹ø¹ÿüò®ãaC&8uö€Í€÷Ù‰á ¹ÓãƒÃƒãø‰å ŒÚ+ê‹>º#ÿs¿‰>º#Ç>'r(>R#r"±ÓïG;ïrƒ>º#tƒ>R#u¿;ïw‹ýëéã‹ßÚ‰÷ ‰û ¡ç +ØŽÀ´JWÍ!_ÓçúŽÒ‹çû3À.Ž–¿î&¹>'+Ïüóªƒ>$#vG€>é r@w€>ê r7¸X»Í!r*´g‹$#Í!r ´H»Í!r@£ÿ HŽÀ´IÍ!r
+¸X»Í!séb´Í‰í ‰ï
+Àt ¸@ŽÀ»p&Æ3í.Ž–¾è&¿î&è©ÿ6ß ÿ6Ý ÿ6Û èóPèy.Ž–VW¾î&¿î&èÊ_^ÃËì´LŠFÍ!¹ºŸ é¸5Í!‰Ë ŒÍ ¸5Í!‰Ï ŒÑ ¸5Í!‰Ó ŒÕ ¸5Í!‰× ŒÙ ¸%ŒÊŽÚº{Í!ø%ÅË Í!¸%ÅÏ Í!¸%ÅÓ Í!¸%Å× Í!ø‹×‹Þ;ßt&€?ÿt&ŠO2í;Ès‹Á‹ÓƒÃëã;×t‹Ú&€?&Æÿt&ÿ_ëÄ&ÿWë½Ã´‹×‹Þ;ßt&€?ÿt &8gr&Šg‹ÓƒÃëå;×t‹Ú&€?&Æÿt&ÿ_ëÇ&ÿWëÀô@»Í!ùº­ .Ž–èêÿ¸PèPU‹ìƒìVW¸!Pè6Y‰Fþ Àu ¸!PèƒY°é‰ÆFýë]VèúY‹øƒÿsëO¸ !P‹ÆÇüÿPèYY Àtë8ƒÿtV¸!P¸"Pèƃĸ!PèmYë€~ýtŠFý´P¸%!PèWYYŠˆFýÿvþètY‹ð Àu–ÿvþè›Y Àt¸0!PèûYŠFýétÿ_^‹å]ÃU‹ììèCÿ
+Àt ¸8!PèY3ÀéaÇFþë†úû‹^þØŠFþˆ†úü‹^þØÆÿFþ‹Fþ=|ÛÇFþéƆúý‹^þØŠFþˆ¸^!P†úþPèêYYŠFþˆ†úþÿvþ¸d!Pè¨YY¸h!P†úþPèÊYY‰Fú Àu ¸j!PèŠëÿvúèYè§þ´‰Fü†úþPèJY Àt¸p!PèeY‹Fü;Fþu
+¸x!PèUYë ÿvü¸|!PèHYY¸€!Pè?Y‹Fü;Fþt†úü‹^üØþ†úû‹^üØŠFþˆ†úý‹^þØŠFüˆÿNþté2ÿ¸‚!PèYÇFþéÒ†úý‹^þØ€?uéÁ†úý‹^þØŠ´;Fþu鬆úý‹^þØŠ´–úû‹؊´;Fþu鋆úü‹^þØŠ´ ÀuJ†úý‹^þØŠ´P†úý‹^þØŠ´P†úý‹^þØŠ´Pÿvþÿvþ†úý‹^þØŠ´P¸”!PèZƒÄë0†úý‹^þØŠ´Pÿvþÿvþ†úû‹^þØŠ´P¸§!P¸"PèwƒÄ ÿFþ‹Fþ=}é ÿÇFþëW†úý‹^þØ€?tI†úý‹^þØŠ´;Fþu7†úü‹^þØ€?tÿvþ†úû‹^þØŠ´P¸Î!PèʃÄë ÿvþ¸Õ!Pè»YYÿFþ‹Fþ=|ž¸Ù!é•ý‹å]ÃU‹ìƒ>Ü! u¸ë‹Ü!Ñã‹F‰‡î&ÿÜ!3À]ÃU‹ì´C2À‹VÍ!r ‹^‰3ÀëPè?]ÃU‹ì´C°‹V‹NÍ!r3ÀëPè$]ÃU‹ì´/Í!S´‹VÍ!´N‹N‹VÍ!œY“´ZÍ!Qr3ÀëSèñ]ÃU‹ì´/Í!S´‹VÍ!´OÍ!œY“´ZÍ!Qr3ÀëSèÄ]ÃÃU‹ìV‹v öuëÿÜ!‹Ü!Ñãÿ—î&ƒ>Ü!uëè¯úÿÞ!èûè¸úƒ~u öuÿà!ÿâ!ÿvè¡úY^]ÂU‹ì3ÀPPÿvè¦ÿ]ÃU‹ì¸P3ÀPÿvè”ÿ]Ã3ÀP¸P3ÀPè…ÿøPP3ÀPèyÿÃU‹ìV‹v ö|ƒþX~¾W‰6T#Š„V#˜‹ðë ÷Þƒþ0éÇT#ÿÿ‰6ë ¸ÿÿ^]ÂU‹ìV‹vVè¼ÿ‹Æ^]ÂU‹ì¸D‹^Í!’%€]ÃU‹ìƒì"VW‹~
+‹^ƒû$wX€ûrS‹F ‹N É}€~t Æ-G÷Ù÷؃ÙvÞã‘+Ò÷ó‘÷óˆFã ëñ+Ò÷óˆF ÀuõNÞ÷ÙÎüNŠ,
+s:ëFªâï°ª‹F
+_^‹å]Â U‹ì3ÀPÿvÿv¸
+P°P°aPèjÿ]ÂU‹ì‹^Ñã§&#ÿý´BŠF
+‹^‹N‹VÍ!rëPèäþ™]ÃU‹ìV‹v‹V öu¾.'ÿv Òu¸°#ë‹ÂPVèÖYYPèÿ¸´#PVèÕYY‹Æ^]ÂU‹ìƒìVW‹v‹~V3ÀPƒ=ÿu¸ë¸‹Pèžÿ‹ðFþPVèTýYY Àt׋Æ_^‹å]º;$#s+‹ÚÑãLJ&#‹Ú±ÓãƇè!ÿ‹ÂÓàä!‹ÚÓ㉇ò!B;$#rÕ è!˜PètþY Àu&æ!ÿý¸P÷æ!t¸ë3ÀP3ÀP¸ä!PèZƒÄ ø!˜Pè@þY Àu&ö!ÿý¸P÷ö!t¸ë3ÀP3ÀP¸ô!Pè&ƒÄÃU‹ì´A‹VÍ!r3ÀëPè´ý]ÊÆèŠÂÔ†àè†à'@'ªÃU‹ìì–VWÇFîÇFìPÇFêëFW¹ÿÿ2Àò®÷ÑI_Ã6ˆGþNìu/SQR†jÿ+ø†jÿPWÿvÿV
+ ÀuÇFêÇFìP~î¾jÿZY[Ãü¾jÿ‰~ü‹~ü‹v¬
+Àt<%t6ˆGþNìîè¬ÿëééÚ‰vð¬<%tç‰~ü3ɉNò‰NþˆNõÇFøÿÿÇFöÿÿë¬2ä‹Ð‹Ø€ë €û`sŠŸÃ#ƒûvéÑã.ÿ§û郀ýwøƒNþëЀýwíƒNþëÅ€ýwâ€~õ+tˆVõ뵃fþßëƒNþ µ맀ýwM÷Fþu)ƒNþµë“é8‹~6‹ƒF€ýs Ày÷؃Nþ‰Føµéoÿ€ýu׉FöþÅébÿ€ýsʵÿFöéUÿ’,0˜€ýwµ‡Fø À|ÑÑà‹ÐÑàÑàÂFøé3ÿ€ýu›‡Fö ÀtµÑà‹ÐÑàÑàÂFöéÿƒNþéeÿNþƒfþïéYÿ·ë
+·³éÚÆFõˆVû3ÒˆVú‹~6‹ë·
+ÆFúˆVû‹~6‹™GG‰v÷Fþt6‹GG‰~~» Àu Òuƒ~öu 6Æ‹ÇëƒNþRPWŠÇ˜PŠFúPSèÝû‹Vö Ò}éòéýˆVû‰v~º‹^6ÿ7CC‰^÷Fþ t6‹CC‰^è˜ý°:ªZèý6ÆÆFúƒfþûNº+ù‡Ï‹Vö;Ñ‹Ñ韉vˆVû‹~6‹ƒF~»2ä6‰¹é‰vˆVû‹~÷Fþ u 6‹=ƒF ÿë 6Ä=ƒFŒÀ Çu¿¼#èPý;Növ‹Nöé…‰vˆVû‹~‹Nö É}¹WQ^»SR¸#FþP‹Fþ©t ¸ƒF
+ëƒF¸Pèò~»÷Fþt‹Vø Ò~èòü&€=-uI+Ñ~‰Vò&€=-t ŠFõ
+ÀtO&ˆƒ~ò~
+‹Nö É}ÿNòèÀü‹÷‹~ü‹^ø¸#Fþ=uŠfû€üou ƒ~òÇFòë€üxt€üXuƒNþ@KKƒnò}ÇFòNò÷Fþu ë° èyüK;Ùö÷Fþ@t °0èhüŠFûèbü‹Vò Ò~'+Ê+Ú&Š<-t< t<+u&¬èCüIK‡Êã°0è8üâù‡Êã+Ù&¬6ˆGþNìè+üâð Û~ ‹Ë° èüâùéUü‰v‹~÷Fþ u 6‹=ƒFë6Ä=ƒF¸P*FìFî&‰÷FþtGG&Çéü‹vð‹~ü°%èÉû¬
+Àuø€~ìP}èÄûƒ~êt¸ÿÿë‹Fî_^‹å]Â^ H “ S Á Î   | A  # '   M ð  ËËËn t U‹ìVW‹~ÿvè‰Y‹ð@PÿvWè ƒÄ‹ÇÆ_^]ÃU‹ì‹F‹Ôê;Âs£ó 3Àë Çë ¸ÿÿ]ÃU‹ì‹F‹Vó ƒÒ‹È ÒuÁr
+;Ìs‡ó ë Çë ¸ÿÿ]ÃU‹ìÿvè¤ÿY]ÃU‹ì‹F™RPè·ÿYY]ú$$ëº)$¹´@»Í!¹'º.$´@Í!é£óU‹ì‹V´DŠF‹^‹N
+Í!r ƒ~u‹ÂëëPèø]ÃVW‹ô‹\ƒër;X$tèBëè_^Ã9V$t#‹wöt‰6X$ë ;6V$t ‹ÞèT‹G£X$ë ‹Þ3À£V$£X$£Z$Sèöþ[Ãÿ;V$t‹w‹¨u‰‹?û‰u‹Þëè2‹?û‹¨tË÷ð‰\‹ß‹;ßt‰>Z$‹w‰u‰|ÃÇZ$Ë6Z$ öt‹|‰\‰]‰‰wÉZ$‰_‰_ÃVW‹ô‹D ÀtRr6%þÿ=s¸ƒ>V$t‹Z$ Ût ‹Ó9s‹_;Úuõèfë!èŠëèë3Àë‹ðƒÆ97séèkÿÿ‹Ã_^ÃP3ÀPPè6þ[[%t 3ÒRPè(þ[[XP3ÛSPèþ[[=ÿÿt‹Ø‰V$‰X$X@‰ƒÃ‹ÃÃ[3ÀÃP3ÛSPèöý[[=ÿÿt‹Ø¡X$‰G‰X$X@‰ƒÃ‹ÃÃX3ÀÃ)‹ó7‹þø@‰‰\‰uƒÆ‹ÆËìSPQPèÿ[‹Ø Àtü‹ø‹vþ‹ ƒÆVƒéÑéó¥‰Fþè$þ[‹^þƒÄ˃Â;Ñw5‹Ñ;X$u‰ÿÃSPèKý[[ë‹ûø‰]+Ð)‹÷ò‰|B‰‹Ë‹ßè7þ‹ÙƒÃÃVWU‹ì‹^‹F
+ Àt7 Ût-ƒë‹I‹ÐƒÂƒâþƒúsº;Êr wƒÃëè‡ÿëèOÿ‹Ãë PèeþëSèý3À[]_^Ãÿ&à&U‹ì‹N´CŠF‹VÍ!r‘ëPèyõ]ÃU‹ì‹V;$#r ¸Pèdõë‹ÚÑãLJ&#RèY]ÃU‹ì´>‹^Í!r ÑãLJ&#3ÀëPè5õ]ÃU‹ìVWÿvèØ Y‹øPèàýY‹ð Àu
+Çë 3ÀëpÿvVè” YY‹ÇO Àt‹ß€8:t€8\t
+€8/t¸\$ë¸a$PVè YY¸/Pè˜ýY‹ø Àu Çë VëW¸PVèÔóƒÄ Àt Vè¥üYWè üY뙉u+ÆE-ÆE.Ý‹Ç_^]ÃU‹ìV‹v€|.ÝuV¸Pÿt+è˜óƒÄÆD-^]ÃU‹ìV‹v€|.Ýt
+Çë 3ÀëŠD-˜ Àu VèžóY ÀuëÆD-‹Æ^]ÃU‹ìV‹v öt€|.Ýt Çë ¸ÿÿëÆD.ÿt+èüYVè üY3À^]ÃU‹ìVW‹~¾ÿÿ ÿtd9}u_ƒ}tƒ=} WèVY ÀuK÷EtÿuèÐûY€}| ŠE˜PèWþY‹ðÇEÇEÇÆEÿƒ} t3ÀPPÿu èÈôPèÝõYÇE ‹Æ_^]ÃU‹ìVW‹~ ÿuènëf9}t¸ÿÿë^ƒ=|)÷Eu
+‹Ç9E
+uFÇ‹Ç9E
+u8‹E‰E
+ë0ë.‹E@‹ð)5P‹E‰E
+PŠE˜Pè
+ƒÄ;Æt ÷EuƒMëŸ3À_^]ÃU‹ìƒìVWÇFþ‹>$#¾ä!ë÷DtVèbÿYÿFþƒÆ‹ÇO Àuç‹Fþ_^‹å]ÃU‹ìƒìVW‹vÇFþ‹ÞFŠŠÁ<ruº¿ë €ùwuºë€ùau º ÇFþ€¿ë3ÀëiŠ F€ù+t€<+u€ùtt€ùbu€ù+uŠ ƒâüƒÊÇFþ€¿€ùtuÊ@ë€ùbuÊ€ë¡N#%À Ћ©€tƒÏ@Çà! ‹^‰‹^‹Fþ‰‹Ç_^‹å]ÂU‹ìƒìV‹v
+ÿvFþPFüPè4ÿ‰D Àt €|}'ÿvü‹Fþ FPÿv苃ĈD
+À} ÆDÿÇD3ÀëAŠD˜Pè'òY ÀtL¸P÷Dt¸ë3ÀP3ÀPVèƒÄ ÀtVè›ýYëÂÇD ‹Æ^‹å]ÂV¾ä!€||¡$#±Óàä!‹ÖƒÆ;Âwç€||3Àë‹Æ^ÃU‹ìèÏÿ‹Ð Àu3Àë Rÿvÿv3ÀPè$ÿ]ÃU‹ì¸×PÿvÿvFPè¤ó]ÃU‹ìVW‹vƒ<}
+‹TB‹úë ‹™3Â+‹Ћø÷D@u,‹L
+ƒ<}ë I‹Ù€?
+uG‹ÂJ Àuðë‹ÙA€?
+uG‹ÂJ Àuð‹Ç_^]ÂU‹ìVW‹v‹~
+Vè7ýY Àt¸ÿÿëGƒÿuƒ<~ Vè|ÿ™)FVd_þÇ‹D‰D
+WÿvÿvŠD˜Pè‰ñƒÄƒúÿu
+=ÿÿu¸ÿÿë3À_^]ÃU‹ìƒìV‹v¸P3À3ÒPRŠD˜PèUñƒÄ‰Vþ‰Füƒúÿu=ÿÿu鄃<}tŠD˜Ñà‹Ø÷‡&#tW¸P3À3ÒPRŠD˜PèñƒÄ‰Vú‰Føƒúÿu=ÿÿtP3ÀPÿvþÿvüŠD˜PèôðƒÄƒúÿu =ÿÿuºÿÿ¸ÿÿë*‹Fú‹Vø‰Fþ‰VüVèþ™FüVþë Vèþ™)FüVþ‹Vþ‹Fü^‹å]ÃU‹ìVW‹~‹v‹NÑéüó¥s¤‹F_^]ÃU‹ì‹N´<‹VÍ!rëPè†ï]ÂU‹ì‹^+É+Ò´@Í!]ÂU‹ìƒìVW‹v‹~÷ÆÀu¡N#%À ð3ÀPÿvè¹ùYY‰Fþ÷Ætx#>P#‹Ç©€u¸Pè.ïƒ~þÿu#ƒ>T#t
+ÿ6T#èïéí÷Ç€t3À븉Fþë ÷Æt7¸PPëÜ÷Æðtÿv3ÀPèOÿ‹ø À}éµWèŒùYëÿvÿvþè6ÿ‹ø À}léœVÿvèYY‹ø À|Z3ÀPWè~öYY‰Fü©€tÎ ÷Æ€t%ÿ P¸PWè[öƒÄë
+÷ÆtWèþþ÷Fþt÷Æt÷Æðt¸PPÿvèÐøƒÄ ÿ|/÷Æt¸ë3À‹Öâÿø ÐR÷Fþt3Àë¸Z ЋßÑ㉗&#‹Ç_^‹å]ÃU‹ìƒì°‹N÷Áu
+°÷Áu°‹V±ð"N
+Á´=Í!r‰Fþ‹F%ÿ¸ €‹^þÑ㉇&#‹FþëPèÛí‹å]ÃU‹ì¡ë ;Æ$}ƒ>ë | ‹ë Ñã‹—f$ëºÃ&Rÿv¸Ñ&P¸"PèTüƒÄ]ÃU‹ì¸×P¸ô!PÿvFPèòï]ÃU‹ìV‹vÿ VŠF˜PèYY^]ÃU‹ìVW‹~ŠF¢<'ƒ=ÿ}:ÿ‹]
+ÿE
+ˆ÷Eué÷€><'
+t
+€><' téæWèžùY ÀuéÚ¸ÿÿéÙéÑ÷Eu÷EuƒMëãMƒ}tEƒ=t WèeùY ÀuÊ‹E÷؉‹]
+ÿE
+ <'ˆ÷Eu鈀><'
+t€><' uzWè2ùY Àtqë•ëmŠE˜Ñà‹Ø÷‡&#t¸P3À3ÒPRŠE˜Pè–íƒÄ€><'
+u÷E@u¸P¸Ú&PŠE˜PèOƒÄ=u¸P¸<'PŠE˜Pè7ƒÄ=t
+÷Eué=ÿ <'´_^]ÃU‹ì¸ô!PÿvèÌþYY]ÃU‹ìƒìVW‹~‹F‰Fþ÷Et)ëW‹^ÿFŠ˜Pè þYY=ÿÿu3ÀéY‹FÿN ÀuÜéI÷E@uéãƒ}uéš‹E;FsQƒ=t Wè=øY ÀuÅŠE˜Ñà‹Ø÷‡&#t¸P3À3ÒPRŠE˜Pè¥ìƒÄÿvÿvŠE˜PènƒÄ;Fuéâë…éÝ‹F|ƒ=u
+¸ÿÿ+E‰ë WèÛ÷Y Àté`ÿÿvÿvÿu
+è¦ûƒÄ‹F‰‹FE
+霊E˜Ñà‹Ø÷‡&#t¸P3À3ÒPRŠE˜Pè!ìƒÄÿvÿvŠE˜PèêƒÄ;Ftaéÿë\ƒ}t=ë/ÿ}‹]
+ÿE
+‹vÿFŠˆ´ëW‹^ÿFŠPèVýYY=ÿÿuéÊþ‹FÿN ÀuÇëÿvÿvŠE˜P膃Ä;Fté¥þ‹Fþ_^‹å]ÂU‹ìVW‹v‹~
+9tu ƒ~ÿÿv¸ÿÿ馃>Þ&uþô!uÇÞ&ëƒ>Ü&u þä!uÇÜ&ƒ<t¸P3À3ÒPRVèjùƒÄ÷Dtÿtè,òYƒdóÇD‹Æ‰D‰D
+ƒ~t> ÿv:ÇÞ!B ƒ~uWèÌòY‰F ÀuéuÿƒLëélÿ‹F‰D
+‰D‰|ƒ~uƒL3À_^]ÃU‹ìVWü‹~‹×2À¹ÿÿò®uÿ‹~¹ÿÿò®÷Ñ+ù‡÷÷Æt¤IÑéó¥s¤’_^]ÃU‹ìVWŒØŽÀü3À‹Ø‹~‹÷2À¹ÿÿò®÷Ñ‹þ‹vó¦ŠDÿŠ]ÿ+Ã_^]ÃU‹ìVWü‹~‹÷2À¹ÿÿò®÷Ñ‹~ó¤‹F_^]ÃU‹ìWŒØŽÀ‹~3Àü¹ÿÿò®‘÷ÐH_]ÃU‹ììˆVW‹~‹v;>$#r
+¸Pèééá‹F@=s3ÀéÓ‹ßÑã÷‡&#t¸P3À3ÒPRWèåéƒÄ‹ßÑã÷‡&#@uÿvVW訃Ä霋ßÑã§&#ÿý‰vú‹F‰FþëMÿNþ‹^úÿFúŠˆFý<
+uÆ FŠFýˆF†xÿ‹Ö+Ðú€|'+ðVPWè[ƒÄ‹Ð;Ætƒúÿu¸ÿÿë=‹F+Fþë1¶xÿƒ~þu©†xÿ+ð‹Æ Àv!V†xÿPWè ƒÄ‹Ð;ÆtƒúÿtÅ‹FÂ+Æë‹F_^‹å]ÃU‹ì‹^Ñã÷‡&#t¸Pë´@‹^‹N‹VÍ!rP‹^Ñã&#XëPèøç]ÃVW3ÿ¾ä!;>$#s÷DtVèÌóYƒÆG;>$#rê_^ÃVW¿¾ä!ë÷DtVè"ôYOƒÆ ÿuì_^ÃBorland C++ - Copyright 1991 Borland Intl.Divide error
+Abnormal program termination
+>'>'.open ..TSTwarning: %s
+ length double%d
+close .There are *.TST files, please remove
+..TST%d:w open unlink ok %d
+
+ valid chars = %d:%d %d:%d %d:%dignoring map %d->%d because of %d->%d
+ %d:%d %d
+‰‰‰ ä!
+ô!"C"B$"```  @ÿÿ),(((((),(((),#,*((((**#(#%(TMP.$$$(null)  
+
+   print scanf : floating point formats not linked
+\*.**.*È$Ð$è$%%%%7%G%\%n%‹%Ÿ%®%Â%Ï%Ð%ß%&&#&4&E&W&i&j&k&l&m&n&o&p&q&r&s&&’&¦&¸&¹&º&»&¼&½&¾&¿&À&Á&Â&0Error 0Invalid function numberNo such file or directoryPath not foundToo many open filesPermission deniedBad file numberMemory arena trashedNot enough memoryInvalid memory block addressInvalid environmentInvalid formatInvalid access codeInvalid dataNo such deviceAttempted to remove current directoryNot same deviceNo more filesInvalid argumentArg list too bigExec format errorCross-device linkMath argumentResult too largeFile already existsPossible deadlockUnknown error%s: %s
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..29e1fe2
--- /dev/null
+++ b/examples/winexe/winexe.c
@@ -0,0 +1,1921 @@
+/*
+ * 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);
+ 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);
+ 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);
+ 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);
+ 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..02aa9df
--- /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 commad (%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..143739f
--- /dev/null
+++ b/examples/winexe/wscript_build
@@ -0,0 +1,110 @@
+#!/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 = ''
+
+if bld.env.WINEXE_CC_WIN32:
+ bld.SAMBA_GENERATOR(
+ 'winexesvc32_exe',
+ source='winexesvc.c',
+ target='winexesvc32.exe',
+ rule='${WINEXE_CC_WIN32} ${SRC} -o ${TGT} ${WINEXE_LDFLAGS}')
+ 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)
+ winexesvc_binaries += ' winexesvc32_exe_binary.c'
+
+if bld.env.WINEXE_CC_WIN64:
+ bld.SAMBA_GENERATOR(
+ 'winexesvc64_exe',
+ source='winexesvc.c',
+ target='winexesvc64.exe',
+ rule='${WINEXE_CC_WIN64} ${SRC} -o ${TGT} ${WINEXE_LDFLAGS}')
+ 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)
+ 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)